The activity panel, and continuing an agent chat in a terminal
ci / check (push) Failing after 3s
ci / start (push) Failing after 3s

The activity panel beside a chat, from /api/v2's activity routes: Context
(used share, tokens against the window, a segmented bar and a row per
category), Outputs (the files written, lines added and removed, each opening
in the viewer), Background tasks (a team's members as a tree, helpers and
commands: state, elapsed time counting on between reads, model, latest step,
what it is writing, its whole conversation read-only, Stop -- a member after
a confirmation, as it takes those under it), the team's room (who to whom,
reports marked, the words through the page's own markdown) and the plan.

The chat follows GET /chats/{chat}/activity/events while it is open: the strip
above the message box sums the agents up and opens the panel; a new version
reads the panel again while it is open, the costly context part on opening,
after a reply and at most every 15 s. The stream is reopened when the server
closes it, and more slowly while it fails. Beside the chat on a wide window
(the viewer then goes over the chat), over it below --bp-wide, a full-height
sheet at --bp-narrow. The header's Activity button, the palette and Escape
open and close it.

An agent chat with a device session (device_session_id) can be continued in a
terminal: the chat's menu and a header button show 'cd <folder> && lembas -s
<id>' to copy, with lembas the CLI as it starts here (on PATH, else the app's
own copy by its path). Shown rather than run: no terminal opens the same way
on every desktop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-09 10:50:46 +00:00
1 parent 844684a152
commit d04bc4b6bd
10 files changed
+1072 -40

No files matched your search

+42
View File
@@ -124,3 +124,45 @@ export function ask({ title, text, value, ok, cancel, danger }) {
} else okBtn.focus()
})
}
/**
* A modal dialog that shows a line to copy: `title`, `text`, the line itself (`code`, shown as
* it is and selectable), and Copy beside Close. Resolves when it is closed.
*/
export function showLine({ title, text, code, copy, copied, close }) {
return new Promise((resolve) => {
const line = h("pre", { class: "dialog__code", tabindex: "0", text: code })
const copyBtn = h("button", { type: "button", class: "btn btn--primary", text: copy })
const closeBtn = h("button", { type: "button", class: "btn", text: close })
const dlg = h(
"dialog",
{ class: "dialog" },
h("div", { class: "dialog__body" }, h("h2", { class: "dialog__title", text: title }), text ? h("p", { class: "muted", text }) : null, line, h("div", { class: "dialog__actions" }, closeBtn, copyBtn)),
)
const done = () => {
dlg.close()
dlg.remove()
resolve()
}
copyBtn.addEventListener("click", () => {
navigator.clipboard
?.writeText(code)
.then(() => (copyBtn.textContent = copied))
.catch(() => {
// No clipboard: the line is selected, for Ctrl+C.
const range = document.createRange()
range.selectNodeContents(line)
getSelection()?.removeAllRanges()
getSelection()?.addRange(range)
})
})
closeBtn.addEventListener("click", done)
dlg.addEventListener("cancel", (e) => {
e.preventDefault()
done()
})
document.body.append(dlg)
dlg.showModal()
copyBtn.focus()
})
}