one-code-extension 0.1.4 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +222 -177
- package/agents/explore.md +9 -6
- package/agents/general-purpose.md +1 -1
- package/agents/plan.md +6 -4
- package/docs/guide/README.md +52 -0
- package/docs/guide/bring-your-claude-code-setup.md +128 -0
- package/docs/guide/configuration.md +173 -0
- package/docs/guide/differences-from-claude-code.md +152 -0
- package/docs/guide/doctor.md +88 -0
- package/docs/guide/hooks.md +111 -0
- package/docs/guide/installation.md +126 -0
- package/docs/guide/permissions-modes-and-auto-mode.md +452 -0
- package/docs/guide/providers-and-models.md +196 -0
- package/docs/guide/reference.md +226 -0
- package/docs/guide/sessions-and-context.md +192 -0
- package/docs/guide/skills-plugins-and-mcp.md +178 -0
- package/docs/guide/subagents-and-workflows.md +195 -0
- package/docs/guide/tasks-and-background-work.md +113 -0
- package/docs/guide/terminal-interface.md +157 -0
- package/docs/guide/tools.md +177 -0
- package/docs/guide/troubleshooting.md +177 -0
- package/extensions/ask-user/index.ts +65 -71
- package/extensions/ask-user/questions.ts +15 -28
- package/extensions/ask-user/widget.ts +533 -0
- package/extensions/auto-mode/actions.ts +9 -26
- package/extensions/auto-mode/classifier-prompt.ts +127 -0
- package/extensions/auto-mode/classifier.ts +305 -227
- package/extensions/auto-mode/config.ts +279 -77
- package/extensions/auto-mode/defaults.ts +17 -60
- package/extensions/auto-mode/instructions.ts +2 -1
- package/extensions/auto-mode/model-picker.ts +53 -31
- package/extensions/auto-mode/model-select.ts +153 -82
- package/extensions/auto-mode/paths.ts +13 -1
- package/extensions/auto-mode/pause.ts +8 -0
- package/extensions/auto-mode/prompt.ts +205 -238
- package/extensions/auto-mode/recoverability.ts +229 -0
- package/extensions/auto-mode/rules.ts +92 -75
- package/extensions/auto-mode/safety-floor.ts +43 -12
- package/extensions/auto-mode/sensitive.ts +11 -0
- package/extensions/auto-mode/setup-run.ts +245 -0
- package/extensions/auto-mode/setup.ts +235 -0
- package/extensions/auto-mode/shell-analysis.ts +332 -26
- package/extensions/auto-mode/transcript.ts +102 -0
- package/extensions/background/index.ts +256 -43
- package/extensions/background/monitor-batch.ts +58 -0
- package/extensions/background/registry.ts +9 -0
- package/extensions/background/wakeup.ts +45 -0
- package/extensions/bash/background.ts +47 -22
- package/extensions/bash/guards.ts +229 -0
- package/extensions/bash/index.ts +81 -19
- package/extensions/branding/index.ts +44 -18
- package/extensions/branding/startup.ts +23 -8
- package/extensions/claude-compat/index.ts +17 -2
- package/extensions/claude-context/index.ts +41 -12
- package/extensions/clear/index.ts +27 -0
- package/extensions/compaction/fit.ts +121 -0
- package/extensions/compaction/index.ts +176 -71
- package/extensions/compaction/prompt.ts +21 -1
- package/extensions/context-budget/budget.ts +61 -0
- package/extensions/context-budget/index.ts +66 -0
- package/extensions/context-management/index.ts +40 -16
- package/extensions/doctor/build.ts +226 -0
- package/extensions/doctor/cli.ts +99 -0
- package/extensions/doctor/compat.ts +532 -0
- package/extensions/doctor/dependencies.ts +186 -0
- package/extensions/doctor/fix-prompt.ts +125 -0
- package/extensions/doctor/index.ts +308 -0
- package/extensions/doctor/models.ts +231 -0
- package/extensions/doctor/presets.ts +208 -0
- package/extensions/doctor/report.ts +189 -0
- package/extensions/doctor/update-lookup.ts +46 -0
- package/extensions/doctor/viewer.ts +124 -0
- package/extensions/effort/index.ts +41 -4
- package/extensions/effort/slider.ts +33 -2
- package/extensions/file-tracker/index.ts +143 -20
- package/extensions/file-tracker/replay.ts +46 -0
- package/extensions/file-tracker/tracker.ts +51 -4
- package/extensions/footer/footer-line.ts +207 -0
- package/extensions/footer/index.ts +152 -0
- package/extensions/footer/pr.ts +53 -0
- package/extensions/hooks/executor.ts +57 -20
- package/extensions/hooks/formatter-notice.ts +76 -0
- package/extensions/hooks/index.ts +314 -73
- package/extensions/hooks/matcher.ts +35 -1
- package/extensions/hooks/plugin-hooks.ts +3 -3
- package/extensions/hooks/protocol.ts +58 -0
- package/extensions/hooks/subagent-bridge.ts +77 -0
- package/extensions/hooks/trust.ts +15 -4
- package/extensions/init/index.ts +26 -0
- package/extensions/init/prompt.ts +40 -0
- package/extensions/interrupted/index.ts +35 -0
- package/extensions/interrupted/line.ts +9 -0
- package/extensions/lib/abort.ts +15 -0
- package/extensions/lib/agent-loader.ts +183 -0
- package/extensions/lib/anthropic-payload.ts +15 -0
- package/extensions/lib/atomic-write.ts +56 -0
- package/extensions/lib/bridge-watch.ts +20 -0
- package/extensions/lib/cache-retention.ts +60 -0
- package/extensions/lib/capability-index.ts +466 -0
- package/extensions/lib/claude-context.ts +318 -27
- package/extensions/lib/claude-settings.ts +64 -0
- package/extensions/lib/consent-preview.ts +30 -0
- package/extensions/lib/deferred.ts +144 -13
- package/extensions/lib/favorites.ts +43 -0
- package/extensions/lib/fetch-timeout.ts +15 -0
- package/extensions/lib/frontmatter.ts +31 -0
- package/extensions/lib/git.ts +44 -2
- package/extensions/lib/hook-gate.ts +90 -0
- package/extensions/lib/interrupt.ts +94 -0
- package/extensions/lib/mcp-overrides.ts +61 -0
- package/extensions/lib/mcp-share.ts +25 -0
- package/extensions/lib/mcp-status.ts +34 -0
- package/extensions/lib/memory.ts +41 -6
- package/extensions/lib/model-facts.generated.json +2480 -0
- package/extensions/lib/model-facts.ts +162 -0
- package/extensions/lib/model-policy.ts +145 -189
- package/extensions/lib/model-tier.ts +480 -64
- package/extensions/lib/model-unusable.ts +37 -0
- package/extensions/lib/notifications.ts +320 -1
- package/extensions/lib/one-code-settings.ts +63 -0
- package/extensions/lib/original-command.ts +71 -0
- package/extensions/lib/package-version.ts +31 -0
- package/extensions/lib/paths.ts +39 -4
- package/extensions/lib/permission-gate.ts +192 -0
- package/extensions/lib/persisted-output.ts +18 -0
- package/extensions/lib/pi-ai-estimate.ts +160 -0
- package/extensions/lib/pi-version.ts +1 -1
- package/extensions/lib/plan-mode-channels.ts +11 -0
- package/extensions/lib/plugin-overrides.ts +24 -0
- package/extensions/lib/plugin-root.ts +44 -0
- package/extensions/lib/plugins.ts +233 -54
- package/extensions/lib/prefix-warm-gate.ts +157 -0
- package/extensions/lib/process-tree.ts +56 -0
- package/extensions/lib/reminders.ts +321 -68
- package/extensions/lib/scratchpad.ts +11 -8
- package/extensions/lib/session-lifecycle.ts +28 -0
- package/extensions/lib/settings-channels.ts +14 -0
- package/extensions/lib/shell-tasks.ts +54 -0
- package/extensions/lib/skill-overrides.ts +86 -0
- package/extensions/lib/skill-scan.ts +110 -0
- package/extensions/lib/text-width.ts +267 -0
- package/extensions/lib/tui-render.ts +281 -54
- package/extensions/lib/usage-bus.ts +75 -0
- package/extensions/lib/usage-tracker.ts +67 -0
- package/extensions/lib/worktree-isolation.ts +170 -0
- package/extensions/lsp/client.ts +69 -12
- package/extensions/lsp/format.ts +12 -2
- package/extensions/lsp/index.ts +273 -84
- package/extensions/lsp/install-hints.ts +43 -0
- package/extensions/lsp/keep-alive.ts +19 -0
- package/extensions/lsp/plugin-servers.ts +331 -0
- package/extensions/lsp/watcher.ts +157 -0
- package/extensions/mcp/announce.ts +99 -0
- package/extensions/mcp/client.ts +181 -22
- package/extensions/mcp/config.ts +55 -24
- package/extensions/mcp/index.ts +586 -86
- package/extensions/mcp/oauth/browser.ts +26 -0
- package/extensions/mcp/oauth/callback.ts +104 -0
- package/extensions/mcp/oauth/flow.ts +68 -0
- package/extensions/mcp/oauth/provider.ts +147 -0
- package/extensions/mcp/oauth/store.ts +86 -0
- package/extensions/mcp/panel/keys.ts +34 -0
- package/extensions/mcp/panel/model.ts +62 -0
- package/extensions/mcp/panel/render.ts +141 -0
- package/extensions/mcp/panel/state.ts +108 -0
- package/extensions/mcp/schema.ts +83 -6
- package/extensions/mcp/trust.ts +340 -0
- package/extensions/memory/entries.ts +163 -0
- package/extensions/memory/index.ts +119 -2
- package/extensions/memory/open-external.ts +97 -0
- package/extensions/memory/panel.ts +124 -0
- package/extensions/model-default/index.ts +74 -0
- package/extensions/notebook/index.ts +36 -18
- package/extensions/notebook/notebook.ts +110 -17
- package/extensions/permissions/index.ts +1012 -247
- package/extensions/permissions/matcher.ts +488 -57
- package/extensions/permissions/modes.ts +55 -7
- package/extensions/permissions/project-trust.ts +81 -0
- package/extensions/permissions/protected-paths.ts +16 -3
- package/extensions/permissions/rule-prose.ts +79 -0
- package/extensions/permissions/session-grant.ts +91 -0
- package/extensions/permissions/settings.ts +112 -33
- package/extensions/permissions/subagent-gate.ts +57 -0
- package/extensions/plan-mode/index.ts +143 -33
- package/extensions/plan-mode/reminder.ts +16 -19
- package/extensions/plan-mode/viewer.ts +40 -31
- package/extensions/plugins/counts.ts +68 -0
- package/extensions/plugins/index.ts +496 -32
- package/extensions/plugins/install/install.ts +167 -0
- package/extensions/plugins/install/paths.ts +23 -0
- package/extensions/plugins/install/registry.ts +72 -0
- package/extensions/plugins/marketplace/git.ts +103 -0
- package/extensions/plugins/marketplace/official.ts +36 -0
- package/extensions/plugins/marketplace/parse.ts +94 -0
- package/extensions/plugins/marketplace/registry.ts +60 -0
- package/extensions/plugins/marketplace/sync.ts +146 -0
- package/extensions/plugins/marketplace/types.ts +128 -0
- package/extensions/plugins/panel/keys.ts +52 -0
- package/extensions/plugins/panel/render.ts +315 -0
- package/extensions/plugins/panel/rows.ts +230 -0
- package/extensions/plugins/panel/state.ts +333 -0
- package/extensions/recap/index.ts +215 -0
- package/extensions/recap/prompt.ts +44 -0
- package/extensions/recap/scheduler.ts +87 -0
- package/extensions/search-tools/index.ts +0 -0
- package/extensions/search-tools/tools.ts +7 -5
- package/extensions/skill/index.ts +360 -34
- package/extensions/skill/invoke.ts +185 -0
- package/extensions/skill/listing.ts +21 -0
- package/extensions/skill/panel/keys.ts +41 -0
- package/extensions/skill/panel/render.ts +91 -0
- package/extensions/skill/panel/state.ts +115 -0
- package/extensions/spinner/index.ts +110 -0
- package/extensions/spinner/line.ts +51 -0
- package/extensions/spinner/verbs.ts +201 -0
- package/extensions/subagents/agents.ts +88 -44
- package/extensions/subagents/default-model.ts +62 -32
- package/extensions/subagents/delegation-steer.ts +23 -0
- package/extensions/subagents/hand-back-review.ts +67 -0
- package/extensions/subagents/index.ts +1545 -346
- package/extensions/subagents/live-runs.ts +293 -0
- package/extensions/subagents/model-select.ts +252 -82
- package/extensions/subagents/outcome.ts +90 -0
- package/extensions/subagents/panel-keys.ts +41 -0
- package/extensions/subagents/panel-render.ts +357 -0
- package/extensions/subagents/panel-widget.ts +330 -0
- package/extensions/subagents/pending-claim.ts +45 -0
- package/extensions/subagents/prose.ts +105 -0
- package/extensions/subagents/runner.ts +674 -0
- package/extensions/subagents/runs.ts +68 -1
- package/extensions/subagents/send-to-main-tool.ts +55 -0
- package/extensions/subagents/session-turns.ts +138 -0
- package/extensions/subagents/shell-panel.ts +198 -0
- package/extensions/subagents/usage.ts +16 -4
- package/extensions/subagents/worktree.ts +13 -0
- package/extensions/system-prompt/environment.ts +5 -3
- package/extensions/system-prompt/git-status.ts +93 -0
- package/extensions/system-prompt/index.ts +23 -1
- package/extensions/system-prompt/template.ts +34 -4
- package/extensions/system-prompt/tiers/common.ts +31 -6
- package/extensions/system-prompt/tiers/low.ts +13 -3
- package/extensions/system-prompt/tiers/mid.ts +21 -8
- package/extensions/system-reminder/index.ts +53 -9
- package/extensions/tasks/index.ts +65 -16
- package/extensions/tasks/store.ts +76 -3
- package/extensions/tool-search/announce.ts +42 -0
- package/extensions/tool-search/index.ts +136 -13
- package/extensions/turn-duration/index.ts +60 -0
- package/extensions/turn-duration/line.ts +22 -0
- package/extensions/turn-duration/span.ts +41 -0
- package/extensions/turn-duration/verbs.ts +24 -0
- package/extensions/web/backends.ts +421 -0
- package/extensions/web/index.ts +178 -21
- package/extensions/web-fetch/index.ts +74 -18
- package/extensions/web-fetch/summarize.ts +1 -1
- package/extensions/workflow/agent-session.ts +182 -112
- package/extensions/workflow/globals.ts +129 -106
- package/extensions/workflow/index.ts +343 -28
- package/extensions/workflow/records.ts +118 -0
- package/extensions/workflow/run-manager.ts +80 -31
- package/extensions/workflow/saved-workflows.ts +2 -1
- package/extensions/workflow/script-worker.mjs +110 -0
- package/extensions/workflow/types.ts +74 -8
- package/extensions/workflow/viewer.ts +562 -0
- package/extensions/workflow/vm-runtime.ts +118 -22
- package/extensions/workflow/widget.ts +126 -18
- package/extensions/worktree/guards.ts +240 -0
- package/extensions/worktree/index.ts +30 -5
- package/extensions/worktree/rewrite.ts +32 -16
- package/package.json +20 -10
- package/skills/code-review/SKILL.md +165 -0
- package/skills/fewer-permission-prompts/SKILL.md +61 -0
- package/skills/security-review/SKILL.md +178 -0
- package/skills/simplify/SKILL.md +70 -0
- package/themes/{one-code-light.json → onecode-light.json} +6 -1
- package/themes/{one-code.json → onecode.json} +6 -1
- package/types/app.d.ts +8 -1
- package/types/community-packages.d.ts +45 -2
- package/docs/decisions/auto-mode.md +0 -526
- package/docs/decisions/branding.md +0 -127
- package/docs/decisions/code-review-remediation.md +0 -106
- package/docs/decisions/compaction.md +0 -140
- package/docs/decisions/distribution.md +0 -168
- package/docs/decisions/hooks.md +0 -64
- package/docs/decisions/lsp.md +0 -58
- package/docs/decisions/mcp.md +0 -104
- package/docs/decisions/memory-state.md +0 -170
- package/docs/decisions/model-policy.md +0 -126
- package/docs/decisions/modes.md +0 -178
- package/docs/decisions/skills-plugins.md +0 -56
- package/docs/decisions/subagents-workflows.md +0 -225
- package/docs/decisions/system-prompt.md +0 -98
- package/docs/decisions/tools.md +0 -407
- package/docs/decisions/tui.md +0 -217
- package/docs/decisions.md +0 -148
- package/extensions/subagents/child.ts +0 -414
- package/extensions/subagents/rpc-turns.ts +0 -123
- package/extensions/todo/index.ts +0 -133
- package/extensions/workflow/permission-gate.ts +0 -71
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live-run registry for the subagent panel (Claude Code's below-editor agent
|
|
3
|
+
* tree). One record per in-process child — foreground-parallel, background, or
|
|
4
|
+
* resident — kept for the life of the session so the strip and the transcript
|
|
5
|
+
* viewer render from a single source. The runner feeds it three signals:
|
|
6
|
+
* `start` (register), progress events (activity/tokens/tool blocks), and the
|
|
7
|
+
* final outcome (mark done/failed).
|
|
8
|
+
*
|
|
9
|
+
* Pure except for the change-callback fan-out; the row/transcript rendering
|
|
10
|
+
* lives in panel-render.ts and reads snapshots from here.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { basename } from "node:path";
|
|
14
|
+
import { cutPlainText, firstNonEmptyLine } from "../lib/tui-render.ts";
|
|
15
|
+
import { normalizeToolName } from "../permissions/matcher.ts";
|
|
16
|
+
import { emptyUsage, sumUsage, type UsageTotals } from "./usage.ts";
|
|
17
|
+
|
|
18
|
+
export type LiveStatus = "running" | "idle" | "done" | "failed" | "stopped";
|
|
19
|
+
|
|
20
|
+
/** Terminal outcome for `finish`: false = completed, true = failed, "stopped" = stopped by the user. */
|
|
21
|
+
export type FinishOutcome = boolean | "stopped";
|
|
22
|
+
|
|
23
|
+
/** One rendered block of a child's transcript, mirroring the main-session marks. */
|
|
24
|
+
export interface TranscriptBlock {
|
|
25
|
+
kind: "task" | "text" | "call" | "result";
|
|
26
|
+
/** For a call: the tool name; for a result: the tool it belongs to. */
|
|
27
|
+
tool?: string;
|
|
28
|
+
/** Rendered short content (args summary, result summary, or assistant text). */
|
|
29
|
+
text: string;
|
|
30
|
+
isError?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The shape of a streaming assistant message (pi's message_update payload). */
|
|
34
|
+
export interface StreamingMessage {
|
|
35
|
+
content?: unknown;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Assistant text of an in-flight message. Extraction is deliberately lazy —
|
|
40
|
+
* message_update fires per token carrying the whole message-so-far, so the
|
|
41
|
+
* registry stores only the reference and the viewer extracts at paint time.
|
|
42
|
+
*/
|
|
43
|
+
export function streamingText(message: StreamingMessage | undefined): string {
|
|
44
|
+
const blocks = Array.isArray(message?.content) ? message.content : [];
|
|
45
|
+
return blocks
|
|
46
|
+
.filter((b): b is { type: string; text: string } => (b as { type?: string }).type === "text" && typeof (b as { text?: unknown }).text === "string")
|
|
47
|
+
.map((b) => b.text)
|
|
48
|
+
.join("");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface LiveRun {
|
|
52
|
+
taskId: string;
|
|
53
|
+
/** Registry name (`general-purpose-1`), also the SendMessage handle. */
|
|
54
|
+
name: string;
|
|
55
|
+
agentType: string;
|
|
56
|
+
model?: string;
|
|
57
|
+
thinking?: string;
|
|
58
|
+
/** Short human label shown in the row and the viewer chip (CC: "Efficiency review of diff"). */
|
|
59
|
+
label: string;
|
|
60
|
+
status: LiveStatus;
|
|
61
|
+
startedAt: number;
|
|
62
|
+
finishedAt?: number;
|
|
63
|
+
toolCalls: number;
|
|
64
|
+
tokens: UsageTotals;
|
|
65
|
+
/** Live one-line activity ("Reading tui-render.ts"), derived from the latest tool call/text. */
|
|
66
|
+
activity: string;
|
|
67
|
+
/** Full transcript blocks, appended as events arrive (bounded by MAX_BLOCKS). */
|
|
68
|
+
blocks: TranscriptBlock[];
|
|
69
|
+
/** The in-flight assistant message (whole-so-far), cleared at message_end. */
|
|
70
|
+
streaming?: StreamingMessage;
|
|
71
|
+
/**
|
|
72
|
+
* Lifetime totals carried over from before a resume — a resumed run's fresh
|
|
73
|
+
* tracker restarts at 0, so stats() adds the current turn on top of these
|
|
74
|
+
* instead of visibly regressing the run's cost.
|
|
75
|
+
*/
|
|
76
|
+
baseToolCalls: number;
|
|
77
|
+
baseTokens: UsageTotals;
|
|
78
|
+
/** Spawning run for a nested agent (a child's own Agent call); undefined for main's children. */
|
|
79
|
+
parentTaskId?: string;
|
|
80
|
+
/** Nesting level: 0 = spawned by main, 1 = spawned by a child (CC's `└` rows). */
|
|
81
|
+
depth: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Keep memory bounded for long/chatty children; the viewer scrolls the tail. */
|
|
85
|
+
export const MAX_BLOCKS = 400;
|
|
86
|
+
|
|
87
|
+
/** First non-empty line of the task, trimmed — the chip/row label. */
|
|
88
|
+
export function deriveLabel(task: string, fallback: string): string {
|
|
89
|
+
const line = firstNonEmptyLine(task);
|
|
90
|
+
return line ? cutPlainText(line, 60) : fallback;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* A short present-tense activity from the latest tool call, Claude Code style
|
|
95
|
+
* ("Reading tui-render.ts", "Running tests", "Searching todo"). Tool names go
|
|
96
|
+
* through the canonical CC↔pi alias table (permissions/matcher.ts), so both
|
|
97
|
+
* spellings resolve without a second table here. Falls back to the first line
|
|
98
|
+
* of the latest assistant text, then a generic "Working…".
|
|
99
|
+
*/
|
|
100
|
+
export function deriveActivity(toolName: string | undefined, args: unknown, lastText: string): string {
|
|
101
|
+
if (toolName) {
|
|
102
|
+
const a = (args ?? {}) as Record<string, unknown>;
|
|
103
|
+
const path = typeof a.file_path === "string" ? basename(a.file_path) : undefined;
|
|
104
|
+
switch (normalizeToolName(toolName)) {
|
|
105
|
+
case "read":
|
|
106
|
+
return path ? `Reading ${path}` : "Reading a file";
|
|
107
|
+
case "edit":
|
|
108
|
+
case "write":
|
|
109
|
+
return path ? `Editing ${path}` : "Editing a file";
|
|
110
|
+
case "bash":
|
|
111
|
+
return "Running a command";
|
|
112
|
+
case "grep":
|
|
113
|
+
return typeof a.pattern === "string" ? `Searching ${cutPlainText(a.pattern, 24)}` : "Searching";
|
|
114
|
+
case "find":
|
|
115
|
+
case "ls":
|
|
116
|
+
return "Listing files";
|
|
117
|
+
case "web_search":
|
|
118
|
+
return "Searching the web";
|
|
119
|
+
case "web_fetch":
|
|
120
|
+
return "Fetching a page";
|
|
121
|
+
default:
|
|
122
|
+
return `Running ${toolName}`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const line = firstNonEmptyLine(lastText);
|
|
126
|
+
return line ? cutPlainText(line, 48) : "Working…";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface RegisterInput {
|
|
130
|
+
taskId: string;
|
|
131
|
+
name: string;
|
|
132
|
+
agentType: string;
|
|
133
|
+
model?: string;
|
|
134
|
+
thinking?: string;
|
|
135
|
+
task: string;
|
|
136
|
+
startedAt: number;
|
|
137
|
+
parentTaskId?: string;
|
|
138
|
+
depth?: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The registry. Emits `onChange` on every mutation (debounced by the widget,
|
|
143
|
+
* not here). Records are never removed — a finished agent stays inspectable,
|
|
144
|
+
* like Claude Code (and matches SendMessage's resume model).
|
|
145
|
+
*/
|
|
146
|
+
export class LiveRunRegistry {
|
|
147
|
+
private readonly runs: LiveRun[] = [];
|
|
148
|
+
private readonly byId = new Map<string, LiveRun>();
|
|
149
|
+
private readonly listeners = new Set<(taskId?: string) => void>();
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Add a change listener (widget, view). Each event carries the mutated
|
|
153
|
+
* run's taskId so a single-run consumer (the transcript view) can ignore
|
|
154
|
+
* unrelated children's streaming deltas. Returns the unsubscribe.
|
|
155
|
+
*/
|
|
156
|
+
subscribe(cb: (taskId?: string) => void): () => void {
|
|
157
|
+
this.listeners.add(cb);
|
|
158
|
+
return () => this.listeners.delete(cb);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private changed(taskId?: string): void {
|
|
162
|
+
for (const cb of this.listeners) cb(taskId);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
register(input: RegisterInput): void {
|
|
166
|
+
const run: LiveRun = {
|
|
167
|
+
taskId: input.taskId,
|
|
168
|
+
name: input.name,
|
|
169
|
+
agentType: input.agentType,
|
|
170
|
+
model: input.model,
|
|
171
|
+
thinking: input.thinking,
|
|
172
|
+
label: deriveLabel(input.task, input.name),
|
|
173
|
+
status: "running",
|
|
174
|
+
startedAt: input.startedAt,
|
|
175
|
+
toolCalls: 0,
|
|
176
|
+
tokens: emptyUsage(),
|
|
177
|
+
activity: "Starting…",
|
|
178
|
+
// The child's prompt opens the transcript, like Claude Code's viewer.
|
|
179
|
+
blocks: input.task.trim() ? [{ kind: "task", text: input.task }] : [],
|
|
180
|
+
baseToolCalls: 0,
|
|
181
|
+
baseTokens: emptyUsage(),
|
|
182
|
+
parentTaskId: input.parentTaskId,
|
|
183
|
+
depth: input.depth ?? 0,
|
|
184
|
+
};
|
|
185
|
+
this.runs.push(run);
|
|
186
|
+
this.byId.set(run.taskId, run);
|
|
187
|
+
this.changed(run.taskId);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A finished run is being resumed (SendMessage to a done agent): flip it back
|
|
192
|
+
* to running, restart the clock, and append the new prompt to its transcript.
|
|
193
|
+
* Returns false when the taskId was never registered (caller registers fresh).
|
|
194
|
+
*/
|
|
195
|
+
reactivate(taskId: string, task: string, startedAt: number): boolean {
|
|
196
|
+
const run = this.byId.get(taskId);
|
|
197
|
+
if (!run) return false;
|
|
198
|
+
run.status = "running";
|
|
199
|
+
run.startedAt = startedAt;
|
|
200
|
+
run.finishedAt = undefined;
|
|
201
|
+
run.activity = "Resuming…";
|
|
202
|
+
// The resumed run's tracker restarts at 0 — bank the lifetime totals so
|
|
203
|
+
// stats() keeps them instead of regressing the displayed cost.
|
|
204
|
+
run.baseToolCalls = run.toolCalls;
|
|
205
|
+
run.baseTokens = { ...run.tokens };
|
|
206
|
+
if (task.trim()) this.block(taskId, { kind: "task", text: task });
|
|
207
|
+
this.changed(taskId);
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** An idle resident got new work — back to running, the turn clock restarts. */
|
|
212
|
+
private wake(run: LiveRun): void {
|
|
213
|
+
if (run.status !== "idle") return;
|
|
214
|
+
run.status = "running";
|
|
215
|
+
run.finishedAt = undefined;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** A progress tick from the tracker: refresh tokens/toolCalls (on top of any pre-resume baseline). */
|
|
219
|
+
stats(taskId: string, toolCalls: number, tokens: UsageTotals): void {
|
|
220
|
+
const run = this.byId.get(taskId);
|
|
221
|
+
if (!run) return;
|
|
222
|
+
run.toolCalls = run.baseToolCalls + toolCalls;
|
|
223
|
+
run.tokens = sumUsage(run.baseTokens, tokens);
|
|
224
|
+
this.wake(run);
|
|
225
|
+
this.changed(taskId);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Update the one-line activity string (already derived). */
|
|
229
|
+
setActivity(taskId: string, activity: string): void {
|
|
230
|
+
const run = this.byId.get(taskId);
|
|
231
|
+
if (!run) return;
|
|
232
|
+
run.activity = activity;
|
|
233
|
+
this.wake(run);
|
|
234
|
+
this.changed(taskId);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Append a transcript block (bounded). */
|
|
238
|
+
block(taskId: string, block: TranscriptBlock): void {
|
|
239
|
+
const run = this.byId.get(taskId);
|
|
240
|
+
if (!run) return;
|
|
241
|
+
run.blocks.push(block);
|
|
242
|
+
if (run.blocks.length > MAX_BLOCKS) run.blocks.splice(0, run.blocks.length - MAX_BLOCKS);
|
|
243
|
+
this.changed(taskId);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** The in-flight assistant message (or undefined at message_end). O(1) per delta. */
|
|
247
|
+
setStreaming(taskId: string, message: StreamingMessage | undefined): void {
|
|
248
|
+
const run = this.byId.get(taskId);
|
|
249
|
+
if (!run) return;
|
|
250
|
+
run.streaming = message;
|
|
251
|
+
this.wake(run);
|
|
252
|
+
this.changed(taskId);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** A resident agent settled a turn but stays alive — mark idle, keep its totals. */
|
|
256
|
+
settle(taskId: string): void {
|
|
257
|
+
const run = this.byId.get(taskId);
|
|
258
|
+
if (!run || run.status === "done" || run.status === "failed") return;
|
|
259
|
+
run.status = "idle";
|
|
260
|
+
run.activity = "Idle — waiting";
|
|
261
|
+
run.streaming = undefined;
|
|
262
|
+
// The turn is over: freeze the clock and start the strip's linger window
|
|
263
|
+
// (an idle resident leaves the strip like a finished run — it stays
|
|
264
|
+
// reachable via /agents and SendMessage).
|
|
265
|
+
run.finishedAt = Date.now();
|
|
266
|
+
this.changed(taskId);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** Terminal: the run finished, failed, or was stopped by the user. */
|
|
270
|
+
finish(taskId: string, outcome: FinishOutcome): void {
|
|
271
|
+
const run = this.byId.get(taskId);
|
|
272
|
+
if (!run) return;
|
|
273
|
+
if (outcome === "stopped") {
|
|
274
|
+
run.status = "stopped";
|
|
275
|
+
run.activity = "Stopped";
|
|
276
|
+
} else {
|
|
277
|
+
run.status = outcome ? "failed" : "done";
|
|
278
|
+
run.activity = outcome ? "Failed" : "Completed";
|
|
279
|
+
}
|
|
280
|
+
run.finishedAt = Date.now();
|
|
281
|
+
run.streaming = undefined;
|
|
282
|
+
this.changed(taskId);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
get(taskId: string): LiveRun | undefined {
|
|
286
|
+
return this.byId.get(taskId);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Newest-first, for the strip and viewer (main is prepended by the caller). */
|
|
290
|
+
list(): LiveRun[] {
|
|
291
|
+
return [...this.runs].reverse();
|
|
292
|
+
}
|
|
293
|
+
}
|