Add crimata-agent and redesign agentic OS UI
- crimata-agent (TypeScript, port 7702): WebSocket server + HTTP /events
endpoint, Claude tool-use loop (render/remove/call_api/show_cursor_response),
session.start fires on first browser connection to seed the canvas
- OS UI redesigned: light grey canvas (#e8e8e8), no dock bar, cursor dot,
Cmd+Space input bubble above cursor, elements placed by agent
- Canvas elements: app_icon (floating icons with running dot), window (no-chrome
content cards), cursor_response (text + action pills)
- Component system: HTML fragments fetched from /components/{app}/{name}.html,
inline scripts re-executed after injection
- contacts/crimata.json: added icon, defaultComponent, components[], api[]
- dock: apps.h/c/main.c extended to parse and serve components + api from
crimata.json; BUF_SIZE increased for richer JSON output
- ui/components/contacts/list.html + card.html: first component pair
- provision.sh: installs crimata-agent, adds WebSocket + /events + /components
nginx locations, fixes /auth/ prefix stripping
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
44f3192b78
commit
31b5e321a1
19 changed files with 1030 additions and 305 deletions
47
ui/components/contacts/list.html
Normal file
47
ui/components/contacts/list.html
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<div class="contacts-list">
|
||||
<div class="cl-header">
|
||||
<h2>Contacts</h2>
|
||||
<button data-event="new_contact">+ New</button>
|
||||
</div>
|
||||
<div class="cl-items" id="cl-items">
|
||||
<div class="cl-empty">Loading…</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.contacts-list { padding: 20px 24px; font-family: -apple-system, sans-serif; width: 360px; }
|
||||
.cl-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
|
||||
.cl-header h2 { font-size: 17px; font-weight: 600; color: #1a1a1a; }
|
||||
.cl-header button { background: #1a1a1a; color: white; border: none; border-radius: 8px; padding: 6px 14px; font-size: 12px; font-weight: 500; cursor: pointer; }
|
||||
.cl-header button:hover { background: #333; }
|
||||
.contact-row { display: flex; align-items: center; gap: 12px; padding: 9px 10px; border-radius: 10px; cursor: pointer; transition: background 0.1s; }
|
||||
.contact-row:hover { background: #f5f5f5; }
|
||||
.contact-avatar { width: 34px; height: 34px; background: #e8e8e8; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 600; color: #666; flex-shrink: 0; }
|
||||
.contact-name { font-size: 14px; font-weight: 500; color: #1a1a1a; }
|
||||
.contact-domain { font-size: 12px; color: #999; }
|
||||
.cl-empty { color: #aaa; font-size: 13px; padding: 12px 0; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const list = document.getElementById('cl-items')
|
||||
fetch('/apps/contacts/')
|
||||
.then(r => r.json())
|
||||
.then(contacts => {
|
||||
if (!contacts.length) {
|
||||
list.innerHTML = '<div class="cl-empty">No contacts yet.</div>'
|
||||
return
|
||||
}
|
||||
list.innerHTML = contacts.map(c => `
|
||||
<div class="contact-row" data-id="${c.id}">
|
||||
<div class="contact-avatar">${(c.name || '?')[0].toUpperCase()}</div>
|
||||
<div>
|
||||
<div class="contact-name">${c.name || '—'}</div>
|
||||
<div class="contact-domain">${c.domain || ''}</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')
|
||||
})
|
||||
.catch(() => { list.innerHTML = '<div class="cl-empty">Could not load contacts.</div>' })
|
||||
})()
|
||||
</script>
|
||||
Loading…
Reference in a new issue