The activity panel, and continuing an agent chat in a terminal
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:
10 files changed
+1072
-40
No files matched your search
@@ -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()
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user