feat(chat): terminal chat parity for every tool; Desktop-like artifacts
- The chat over a terminal pane now covers Claude, Codex, omp, Cursor and Antigravity: Cursor's agent transcript and agy's step log (brain/<id>/.system_generated/logs/transcript_full.jsonl) are read as conversations; Cursor sessions are claimed by their workspace - Replies appear as soon as they are written: the projects-tree watcher broadcasts `transcript_changed` (at most every 250 ms per session) and the chat re-reads the transcript while the terminal underneath draws - Stop shows from the pane's own busy line (Claude/Codex `esc to interrupt`, agy `… esc to cancel`), or fresh output for omp/Cursor — no hooks needed - Permission prompts read off the terminal become a card with the tool, its command and "Deny with a note"; Codex gets Permission mode / Model buttons that open its own numbered pickers, answered from the menu card - Artifacts: cards for pages/documents/diagrams/tables/React components, a Preview | Code panel with versions, copy, download, save to the Artifacts Hub, full screen; sandboxed iframes without allow-same-origin - Claude panes get CLAUDE_CODE_ENABLE_TODO_TOOLS=1 so the Progress panel has a plan; multi-question pane menus read their Next row and question tabs - The realtime chat bridge (structured stdio, /api/chat-bridge, /ws-chat) from the unreleased ad9d475 is not kept
This commit is contained in:
+33
-5
@@ -1032,7 +1032,9 @@ function startWorkflowPoll(broadcast) {
|
||||
* sessions show up immediately rather than on the next poll. Events for
|
||||
* files already in `mtimeCache` (active transcripts being appended to) are
|
||||
* ignored, so a busy session never thrashes the importer — the poll picks
|
||||
* up its growth. Recursive watching is used only on macOS/Windows (native,
|
||||
* up its growth; such an append only broadcasts `transcript_changed`
|
||||
* `{session_id}` (at most every 250 ms per session), so an open chat reads
|
||||
* the new lines at once. Recursive watching is used only on macOS/Windows (native,
|
||||
* stable); on Linux, where Node's userland recursive watcher trips on the
|
||||
* high-churn projects tree (see lib/cc-watcher.js), we watch the root plus
|
||||
* each immediate child folder non-recursively instead.
|
||||
@@ -1148,11 +1150,37 @@ function startSessionSync(broadcast) {
|
||||
}, DEBOUNCE_MS);
|
||||
if (debounce.unref) debounce.unref();
|
||||
}
|
||||
// Only a path we don't already track is interesting (a new session file or a
|
||||
// new project folder). Appends to a known active transcript are left to the
|
||||
// poll, so the watcher never re-parses a busy session every write.
|
||||
// An append to a session's own transcript: a chat showing that session reads
|
||||
// it now instead of at its next poll. One `transcript_changed` per session
|
||||
// per PUSH_MS — a notice only, nothing is parsed here.
|
||||
const PUSH_MS = 250;
|
||||
const pushing = new Map(); // session id → pending timer
|
||||
function pushTranscript(fullPath) {
|
||||
const m =
|
||||
/(?:^|[\\/])([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i.exec(
|
||||
fullPath
|
||||
);
|
||||
if (!m || pushing.has(m[1])) return;
|
||||
const sessionId = m[1];
|
||||
const timer = setTimeout(() => {
|
||||
pushing.delete(sessionId);
|
||||
try {
|
||||
broadcast("transcript_changed", { session_id: sessionId });
|
||||
} catch {
|
||||
/* best-effort — the chat's poll still catches up */
|
||||
}
|
||||
}, PUSH_MS);
|
||||
if (timer.unref) timer.unref();
|
||||
pushing.set(sessionId, timer);
|
||||
}
|
||||
|
||||
// Only a path we don't already track is interesting to the importer (a new
|
||||
// session file or a new project folder). Appends to a known active
|
||||
// transcript are left to the poll, so the watcher never re-parses a busy
|
||||
// session every write — it only tells the chats (`pushTranscript`).
|
||||
function onFsEvent(fullPath) {
|
||||
if (fullPath && mtimeCache.has(fullPath)) return;
|
||||
if (fullPath && mtimeCache.has(fullPath)) return void pushTranscript(fullPath);
|
||||
if (fullPath) pushTranscript(fullPath);
|
||||
scheduleSweep();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user