pantheon-opencode 1.5.0-beta.2 → 1.5.0-beta.20
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/.pantheon/code-mode/manifest.json +21 -0
- package/AGENTS.md +14 -63
- package/CHANGELOG.md +1260 -0
- package/README.md +162 -23
- package/README.pt-BR.md +104 -19
- package/bin/pantheon-init.mjs +178 -21
- package/commands/pantheon.md +1 -35
- package/package.json +23 -15
- package/plugin.json +1 -1
- package/pyproject.toml +62 -0
- package/scripts/code_mode_server.py +431 -55
- package/scripts/doctor.mjs +207 -9
- package/scripts/install/cli-ui.mjs +17 -11
- package/scripts/install/config-migration.mjs +4 -6
- package/scripts/install/opencode.mjs +137 -35
- package/scripts/install/plugin.mjs +12 -45
- package/scripts/install/shared.mjs +43 -2
- package/scripts/install/strings.mjs +129 -0
- package/scripts/install-mcp.mjs +1 -0
- package/scripts/manifest-inventory.mjs +410 -0
- package/scripts/mcp_persistence_server.py +536 -164
- package/scripts/package-evidence.mjs +242 -0
- package/scripts/probe-pantheon-cost.mjs +10 -1
- package/scripts/release-beta-version.mjs +56 -60
- package/scripts/sync-artifacts.mjs +169 -0
- package/scripts/sync-tui.mjs +129 -64
- package/scripts/test-opencode-v1-v2-sandbox.sh +79 -161
- package/scripts/validation-policy.mjs +7 -7
- package/scripts/version-check.mjs +113 -108
- package/scripts/versioning.mjs +230 -86
- package/src/agents/apollo.md +1 -0
- package/src/agents/gaia.md +1 -0
- package/src/agents/mnemosyne.md +1 -1
- package/src/agents/zeus.md +11 -54
- package/src/instructions/memory-protocol.instructions.md +6 -3
- package/src/instructions/zeus-anti-stall.instructions.md +2 -4
- package/src/instructions/zeus-council-synthesis.instructions.md +3 -28
- package/src/instructions/zeus-timeout-retry.instructions.md +3 -28
- package/src/mcp/code_mode_server.py +431 -55
- package/src/mcp/mcp_persistence_server.py +536 -164
- package/src/mcp/toon_codec.py +2 -4
- package/src/pantheon/background-job-board.ts +47 -5
- package/src/pantheon/{delegation-compaction.ts → compaction-context.ts} +10 -100
- package/src/pantheon/cost-command.ts +309 -44
- package/src/pantheon/delegation-enforce.ts +59 -14
- package/src/pantheon/file-persistence-salvage.ts +64 -0
- package/src/pantheon/file-persistence.ts +194 -45
- package/src/pantheon/goal-loop.ts +1 -1
- package/src/pantheon/goal-store.ts +1 -1
- package/src/pantheon/idle-continuation.ts +4 -6
- package/src/pantheon/model-command.ts +1 -2
- package/src/pantheon/native-task-status.ts +139 -0
- package/src/pantheon/presets.d.mts +0 -20
- package/src/pantheon/presets.mjs +0 -64
- package/src/pantheon/session-guard.ts +2 -2
- package/src/pantheon/session-id.ts +30 -0
- package/src/pantheon/shared-board.ts +37 -0
- package/src/pantheon/task-result-guard.ts +106 -0
- package/src/pantheon/todo-enforcer.ts +3 -3
- package/src/pantheon/tool-ceiling.ts +159 -0
- package/src/pantheon/tool-context.ts +23 -0
- package/src/pantheon/v2-bridge.ts +1 -4
- package/src/plugin-v2.ts +8 -21
- package/src/plugin.ts +83 -251
- package/src/plugins/pantheon-hooks.ts +51 -0
- package/src/plugins/tui/dist/server.d.ts +1 -1
- package/src/plugins/tui/dist/server.d.ts.map +1 -1
- package/src/plugins/tui/dist/server.js +1 -1
- package/src/plugins/tui/dist/server.js.map +1 -1
- package/src/plugins/tui/dist/tui.d.ts +261 -77
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +640 -234
- package/src/plugins/tui/dist/tui.js.map +1 -1
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +2 -2
- package/src/plugins/tui/src/index.tsx +872 -226
- package/src/routing.yml +0 -16
- package/src/skills/context-compression/SKILL.md +1 -1
- package/scripts/generate-preset-docs.mjs +0 -300
- package/scripts/generate-prompts.sh +0 -222
- package/scripts/hash_verify.py +0 -192
- package/scripts/install/component.mjs +0 -24
- package/scripts/install/migrate-config.mjs +0 -302
- package/scripts/test-context-compression.sh +0 -169
- package/src/pantheon/auto-wake.ts +0 -89
- package/src/pantheon/chat-reminders.ts +0 -9
- package/src/pantheon/comment-checker.ts +0 -48
- package/src/pantheon/compaction-assert.ts +0 -160
- package/src/pantheon/cost-tracker.ts +0 -108
- package/src/pantheon/delegate-manager.ts +0 -669
- package/src/pantheon/delegation-classifier.ts +0 -307
- package/src/pantheon/delegation-finalize.ts +0 -374
- package/src/pantheon/delegation-notify.ts +0 -212
- package/src/pantheon/delegation-toast.ts +0 -73
- package/src/pantheon/delegation.ts +0 -1120
- package/src/pantheon/dispatch-guard.ts +0 -109
- package/src/pantheon/permission-eval.ts +0 -284
- package/src/pantheon/preemptive-compact.ts +0 -76
- package/src/pantheon/retry-policy.ts +0 -212
- package/src/pantheon/step-cap.ts +0 -110
- package/src/pantheon/token-opt.ts +0 -781
- package/src/pantheon/toon-codec.ts +0 -481
- package/src/pantheon/v2-events.ts +0 -131
- package/src/pantheon/v2-hooks.ts +0 -287
- package/src/pantheon/v2-tool-definitions.ts +0 -331
- package/src/pantheon/zeus-delegate-with-retry.ts +0 -406
- package/src/plugins/tui/dist/tui.tsx +0 -2605
|
@@ -5,13 +5,13 @@ type DelegationEntry = {
|
|
|
5
5
|
alias: string;
|
|
6
6
|
/** Parent session the job was launched from (dir name under .pantheon/delegations). */
|
|
7
7
|
sessionID: string;
|
|
8
|
-
/** Child session id (=
|
|
8
|
+
/** Child session id (= task id, from the `Task ID` header). The
|
|
9
9
|
* children channel always sets it from the child session itself; the md
|
|
10
10
|
* channel parses it so child↔md matching works by taskID. */
|
|
11
11
|
taskID?: string;
|
|
12
12
|
/** Agent name, e.g. "apollo". */
|
|
13
13
|
agent: string;
|
|
14
|
-
state: 'running' | 'completed' | 'error' | 'startup_failed' | 'startup_unknown' | 'cancelled' | 'stale-running';
|
|
14
|
+
state: 'running' | 'retry' | 'completed' | 'error' | 'startup_failed' | 'startup_unknown' | 'cancelled' | 'stale-running';
|
|
15
15
|
/** Epoch ms of the `Started` header. */
|
|
16
16
|
startedAt: number;
|
|
17
17
|
/** Epoch ms of the `Finalized` header — null while still running. */
|
|
@@ -21,8 +21,10 @@ type DelegationEntry = {
|
|
|
21
21
|
/** True while the panel is waiting for pantheon_delegation_read. */
|
|
22
22
|
read?: boolean;
|
|
23
23
|
/** Internal provenance used to keep a finalized md report authoritative.
|
|
24
|
-
* 'children-only' = a native task() child session with NO
|
|
25
|
-
* (
|
|
24
|
+
* 'children-only' = a native task() child session with NO delegate report
|
|
25
|
+
* (a native child row); 'md' = the child has a matching report;
|
|
26
|
+
* 'child' = the plain children channel; 'live' = the optimistic tool-event
|
|
27
|
+
* channel. */
|
|
26
28
|
source?: 'child' | 'live' | 'md' | 'children-only';
|
|
27
29
|
};
|
|
28
30
|
/** Parse one delegation report md header into a structured entry.
|
|
@@ -43,23 +45,30 @@ declare function parseDelegationMarkdown(raw: string, fileAlias?: string, sessio
|
|
|
43
45
|
declare function readDelegationEntries(dir: string): Promise<DelegationEntry[]>;
|
|
44
46
|
/** Read delegation reports from EVERY session under
|
|
45
47
|
* `<root>/.pantheon/delegations/<sessionID>/<alias>.md` — the panel's
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* ENRICHMENT source. The read is deliberately unfiltered (each entry carries
|
|
49
|
+
* its directory's sessionID, so a taskID match can enrich any channel);
|
|
50
|
+
* callers MUST scope the merged result with {@link filterDelegationsToSession}
|
|
51
|
+
* before rendering — only the active session's reports are shown. Entries are
|
|
52
|
+
* running first, Finalized desc (the sort applied by readDelegationEntries).
|
|
53
|
+
* Fail-open: a missing/unreadable directory yields []. */
|
|
51
54
|
declare function readAllDelegationEntries(root: string): Promise<DelegationEntry[]>;
|
|
52
|
-
/** Resolve the
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
|
|
55
|
+
/** Resolve the PROJECT ROOT used by every pantheon file channel. `directory`
|
|
56
|
+
* wins over `worktree` (the old `resolveDelegationsDir` already did this);
|
|
57
|
+
* an absent/empty root or `/` (no git — e.g. the sandbox test project) falls
|
|
58
|
+
* back to cwd. Standardised here so the delegations md and the panel logger
|
|
59
|
+
* all read the SAME root (audit finding: the channels
|
|
60
|
+
* resolved the root independently). Pure — no I/O. */
|
|
61
|
+
declare function resolvePantheonRoot(state: {
|
|
62
|
+
directory?: string;
|
|
63
|
+
worktree?: string;
|
|
64
|
+
} | undefined, cwd?: string): string;
|
|
65
|
+
/** Resolve the directory where delegation md reports are written.
|
|
66
|
+
* The finalizer writes `.pantheon/delegations` RELATIVE to the server cwd,
|
|
67
|
+
* which the TUI exposes as `TuiState.path.directory`. */
|
|
59
68
|
declare function resolveDelegationsDir(state: {
|
|
60
69
|
directory?: string;
|
|
61
70
|
worktree?: string;
|
|
62
|
-
} | undefined, cwd?:
|
|
71
|
+
} | undefined, cwd?: string): string;
|
|
63
72
|
/** Project root derived from the delegations dir: `<root>/.pantheon/delegations`
|
|
64
73
|
* → `<root>`. Used to point the panel logger at the REAL hooks.log — passing
|
|
65
74
|
* the delegations dir (or its dirname) directly made createTuiLogger append
|
|
@@ -73,10 +82,17 @@ declare function tuiLogPath(projectRoot: string): string;
|
|
|
73
82
|
* falling back to startedAt, descending). Shared by the md reader and
|
|
74
83
|
* mergeDelegationSources. */
|
|
75
84
|
declare function compareDelegationEntries(a: DelegationEntry, b: DelegationEntry): number;
|
|
76
|
-
/**
|
|
77
|
-
* recent terminal reports
|
|
78
|
-
*
|
|
79
|
-
*
|
|
85
|
+
/** Split the panel list: active jobs (running/retry, stale-marked) first,
|
|
86
|
+
* then the most recent terminal reports; the remaining tail is collapsed
|
|
87
|
+
* by the View into a single "… +N more" line. Pure — so the history-only panel (no sessionID) is testable
|
|
88
|
+
* without the TUI runtime. */
|
|
89
|
+
declare function splitDelegationList(all: readonly DelegationEntry[], maxRecent?: number, now?: number, staleThresholdMs?: number): {
|
|
90
|
+
active: DelegationEntry[];
|
|
91
|
+
recent: DelegationEntry[];
|
|
92
|
+
};
|
|
93
|
+
/** Live-first window used by {@link ceilingDelegationList} (kept for the
|
|
94
|
+
* ceiling helper and existing tests): active jobs first, then the most
|
|
95
|
+
* recent terminal reports (capped). Pure. */
|
|
80
96
|
declare function visibleDelegationList(all: readonly DelegationEntry[], maxTerminal?: number, now?: number, staleThresholdMs?: number): DelegationEntry[];
|
|
81
97
|
/** Default stale-running threshold: 30 minutes. */
|
|
82
98
|
declare const STALE_RUNNING_THRESHOLD_MS: number;
|
|
@@ -84,28 +100,98 @@ declare const STALE_RUNNING_THRESHOLD_MS: number;
|
|
|
84
100
|
* considered stale. Combined with the stale-running threshold to produce the
|
|
85
101
|
* display-only `stale-running` state. */
|
|
86
102
|
declare const IDLE_SILENCE_MS: number;
|
|
103
|
+
/** Visual-only terminal retention windows. Reports remain on disk; these
|
|
104
|
+
* constants only control which rows enter the TUI window. */
|
|
105
|
+
declare const DELEGATION_DONE_RETENTION_MS: number;
|
|
106
|
+
declare const DELEGATION_FAILED_RETENTION_MS: number;
|
|
107
|
+
/** Grace window for an ABSENT child status. `api.state.session.status()` only
|
|
108
|
+
* carries the sessions that are currently ALIVE; every finished child of a
|
|
109
|
+
* long-lived session is missing from that map. A child with no status is
|
|
110
|
+
* therefore treated as terminal (done) — treating it as running made every
|
|
111
|
+
* historical child of the session show up as "active" (the "197 children,
|
|
112
|
+
* all active" regression). The one exception is a freshly-spawned child that
|
|
113
|
+
* has not been registered by the status API yet: within this window of its
|
|
114
|
+
* last activity (`time.updated`, falling back to `time.created`) it still
|
|
115
|
+
* reads as running. */
|
|
116
|
+
declare const DELEGATION_CHILD_STATUS_GRACE_MS: number;
|
|
117
|
+
/** Recency window for the children channel. `session.children` returns EVERY
|
|
118
|
+
* child the focused session ever spawned, so a long session accumulates
|
|
119
|
+
* hundreds of historical rows that would inflate the panel. A child whose
|
|
120
|
+
* last activity (its own time, or its matched report's Finalized timestamp)
|
|
121
|
+
* is older than this window is dropped BEFORE it can enter the list. 24h
|
|
122
|
+
* keeps the sidebar scoped to current work while still covering long
|
|
123
|
+
* delegations. A child with no timestamp at all is kept (fail-open). */
|
|
124
|
+
declare const DELEGATION_CHILDREN_RECENCY_MS: number;
|
|
125
|
+
/** Alias-less NATIVE task() live entries never receive a report alias (the
|
|
126
|
+
* task tool output carries none), so the 30s alias-less prune in
|
|
127
|
+
* mergeChildDelegationSources must not apply to them — 5 minutes covers a
|
|
128
|
+
* slow child listing while still bounding the live map. */
|
|
129
|
+
declare const NATIVE_LIVE_ALIASLESS_TTL_MS: number;
|
|
87
130
|
/**
|
|
88
131
|
* Mark a running entry as `stale-running` if it has been running longer than
|
|
89
132
|
* the threshold AND has no recent activity (no `updatedAt` change in the last
|
|
90
|
-
* `IDLE_SILENCE_MS`). This is DISPLAY-ONLY — the
|
|
133
|
+
* `IDLE_SILENCE_MS`). This is DISPLAY-ONLY — the persisted state is unchanged.
|
|
91
134
|
*
|
|
92
135
|
* A `stale-running` entry renders with a warning indicator but the underlying
|
|
93
136
|
* delegation is still treated as running by the backend.
|
|
94
137
|
*/
|
|
95
138
|
declare function markStaleIfRunning(entry: DelegationEntry, now: number, thresholdMs?: number): DelegationEntry;
|
|
96
|
-
/** Compact elapsed-time label: "
|
|
139
|
+
/** Compact elapsed-time label, single unit only: "12s"/"3m"/"1h"/"2d" — ticks every
|
|
97
140
|
* second for running jobs. */
|
|
98
141
|
declare function fmtElapsed(ms: number): string;
|
|
99
|
-
/** Elapsed label for one entry:
|
|
100
|
-
*
|
|
142
|
+
/** Elapsed label for one entry: an ACTIVE entry (running/retry/stale-running)
|
|
143
|
+
* ticks `now - startedAt`; a terminal one is fixed at
|
|
144
|
+
* `updatedAt - startedAt` (em dash when no finalized timestamp). */
|
|
101
145
|
declare function delegationElapsed(entry: DelegationEntry, now: number): string;
|
|
102
146
|
/** The activity labels shown by the animated row. Keeping this pure makes the
|
|
103
147
|
* state machine testable without booting OpenCode's renderer. */
|
|
104
148
|
type DelegationActivity = 'delegating' | 'working' | 'reading' | 'completed' | 'error' | 'cancelled';
|
|
105
149
|
declare function delegationActivity(entry: DelegationEntry): DelegationActivity;
|
|
106
150
|
declare function delegationActivityLabel(entry: DelegationEntry): string;
|
|
107
|
-
/** Return
|
|
108
|
-
|
|
151
|
+
/** Return the spinner glyph for the given frame counter. The frame counter
|
|
152
|
+
* is incremented every ~80ms by a dedicated animation timer, decoupled from
|
|
153
|
+
* the data poll cycle. Pure — no side effects. */
|
|
154
|
+
declare function delegationSpinnerFrame(frame: number): string;
|
|
155
|
+
/** Every state the row knows how to draw: the delegation lifecycle states
|
|
156
|
+
* derived from the children status + md reports (`completed`, `error`,
|
|
157
|
+
* `cancelled`, `startup_failed`, `startup_unknown`) plus the TUI-only
|
|
158
|
+
* states (`retry`, `stale-running`). Fase 1 deliberately omits speculative
|
|
159
|
+
* blocked/paused/scheduled/skipped. There is no `pending` display state: a
|
|
160
|
+
* pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
|
|
161
|
+
type DelegationDisplayState = DelegationEntry['state'];
|
|
162
|
+
/** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
|
|
163
|
+
* Kept separate + pure so the color channel is testable without booting the
|
|
164
|
+
* renderer. Every display state resolves to one of the three status colors;
|
|
165
|
+
* the row paints its whole content with it (see {@link DelegationRow}). */
|
|
166
|
+
type DelegationStateTone = 'warning' | 'error' | 'success';
|
|
167
|
+
/** Status → color mapping for the whole-row tone. Red = failure, green =
|
|
168
|
+
* terminal, yellow = in flight. The glyph remains a redundant channel so the
|
|
169
|
+
* state stays legible in monochrome. Display-only; no behavior change. */
|
|
170
|
+
declare function delegationStateTone(state: DelegationDisplayState): DelegationStateTone;
|
|
171
|
+
type ToolActivity = {
|
|
172
|
+
tool: string;
|
|
173
|
+
summary: string;
|
|
174
|
+
at: number;
|
|
175
|
+
};
|
|
176
|
+
/** Reduce one message.part.updated tool part to displayable activity.
|
|
177
|
+
* Returns null for non-tool parts, completed/error parts (no live activity)
|
|
178
|
+
* or parts without a session id. Pure. */
|
|
179
|
+
declare function extractToolActivity(part: {
|
|
180
|
+
type?: string;
|
|
181
|
+
tool?: string;
|
|
182
|
+
sessionID?: string;
|
|
183
|
+
state?: {
|
|
184
|
+
status?: string;
|
|
185
|
+
input?: Record<string, unknown>;
|
|
186
|
+
};
|
|
187
|
+
}, now?: number): {
|
|
188
|
+
sessionID: string;
|
|
189
|
+
activity: ToolActivity;
|
|
190
|
+
} | null;
|
|
191
|
+
/** Record an activity sample (bounded map, oldest dropped). */
|
|
192
|
+
declare function trackToolActivity(map: Map<string, ToolActivity>, sessionID: string, activity: ToolActivity): void;
|
|
193
|
+
/** Latest live activity for a child session, or null when absent/stale. */
|
|
194
|
+
declare function latestToolActivityFor(map: Map<string, ToolActivity>, sessionID: string | undefined, now?: number, ttlMs?: number): ToolActivity | null;
|
|
109
195
|
/** Merge the immediate tool-event channel into the child-session channel.
|
|
110
196
|
*
|
|
111
197
|
* Children remain the durable source, while live entries make a delegation
|
|
@@ -139,7 +225,7 @@ type LiveDelegationEntry = {
|
|
|
139
225
|
partID: string;
|
|
140
226
|
/** Parent session the delegation was launched from. */
|
|
141
227
|
sessionID: string;
|
|
142
|
-
tool: 'pantheon_delegate' | 'pantheon_delegation_read';
|
|
228
|
+
tool: 'pantheon_delegate' | 'pantheon_delegation_read' | 'task';
|
|
143
229
|
/** Agent name (from the delegate input args). */
|
|
144
230
|
agent: string;
|
|
145
231
|
description: string;
|
|
@@ -158,7 +244,7 @@ type ParsedDelegationToolPart = {
|
|
|
158
244
|
callID: string;
|
|
159
245
|
partID: string;
|
|
160
246
|
sessionID: string;
|
|
161
|
-
tool: 'pantheon_delegate' | 'pantheon_delegation_read';
|
|
247
|
+
tool: 'pantheon_delegate' | 'pantheon_delegation_read' | 'task';
|
|
162
248
|
/** null for read parts (no agent arg — the id targets an existing job). */
|
|
163
249
|
agent: string | null;
|
|
164
250
|
description: string;
|
|
@@ -170,7 +256,9 @@ type ParsedDelegationToolPart = {
|
|
|
170
256
|
};
|
|
171
257
|
/** Extract the tool name + args from a `message.part.updated` part and
|
|
172
258
|
* reduce it to what the panel needs. Returns null for anything that is
|
|
173
|
-
* not a pantheon delegation tool part
|
|
259
|
+
* not a pantheon delegation tool part, the native `task` subagent tool
|
|
260
|
+
* (same parentID === caller mechanism — its children render `nat:`),
|
|
261
|
+
* or is missing its callID. */
|
|
174
262
|
declare function parseDelegationToolPart(part: DelegationToolPart, now?: number): ParsedDelegationToolPart | null;
|
|
175
263
|
/** Apply one tool part to the live map. Returns true when the map changed.
|
|
176
264
|
* Pure w.r.t. I/O — only mutates `map`. */
|
|
@@ -178,11 +266,14 @@ declare function reduceDelegationToolPart(map: Map<string, LiveDelegationEntry>,
|
|
|
178
266
|
/** Remove a live entry by part id (message.part.removed) or call id.
|
|
179
267
|
* Returns true when something was removed. */
|
|
180
268
|
declare function removeDelegationEntry(map: Map<string, LiveDelegationEntry>, partIDOrCallID: string): boolean;
|
|
181
|
-
/** Collect pantheon delegation tool parts from a session's messages.
|
|
269
|
+
/** Collect pantheon delegation + native task tool parts from a session's messages.
|
|
182
270
|
* Messages may carry their parts inline (duck-typed `msg.parts`); when
|
|
183
271
|
* they don't, the optional `getParts(messageID)` callback is used (the TUI
|
|
184
|
-
* SDK exposes `api.state.part(messageID)`).
|
|
185
|
-
*
|
|
272
|
+
* SDK exposes `api.state.part(messageID)`). The native `task` tool spawns a
|
|
273
|
+
* child session with parentID = caller — the same mechanism as
|
|
274
|
+
* pantheon_delegate — so its parts feed the live-map as the native signal
|
|
275
|
+
* (rows come from the children channel). Pure w.r.t. I/O — used
|
|
276
|
+
* by the mount re-scan to re-seed the live map after compaction/attach. */
|
|
186
277
|
declare function collectDelegationToolParts(messages: readonly {
|
|
187
278
|
id?: string;
|
|
188
279
|
parts?: unknown[];
|
|
@@ -201,6 +292,23 @@ declare function toDelegationEntry(live: LiveDelegationEntry): DelegationEntry;
|
|
|
201
292
|
* terminal md entry is authoritative over a live running entry for the
|
|
202
293
|
* same job (it carries Finalized/timedOut/cancelled from finalize). */
|
|
203
294
|
declare function mergeDelegationSources(live: readonly LiveDelegationEntry[], md: readonly DelegationEntry[]): DelegationEntry[];
|
|
295
|
+
/** Scope a fully-merged display list to the ACTIVE session only.
|
|
296
|
+
*
|
|
297
|
+
* The panel is session-scoped: rows from other sessions (md history under
|
|
298
|
+
* `.pantheon/delegations/<other-session>/`) and rows with no
|
|
299
|
+
* attributable session (empty sessionID) are DROPPED. The previous
|
|
300
|
+
* cross-session behavior rendered those rows and clicking them led to
|
|
301
|
+
* "Session not found" — there is no cross-session channel anymore.
|
|
302
|
+
*
|
|
303
|
+
* The md channel still feeds the merge UNFILTERED so it can ENRICH an
|
|
304
|
+
* active-session row with state/alias/agent (dedup by taskID), but it can
|
|
305
|
+
* never introduce a row for another session: this filter is applied
|
|
306
|
+
* ONCE, after every merge (children + live + md).
|
|
307
|
+
*
|
|
308
|
+
* Returns [] when no active session resolves (null/placeholder) — there is no
|
|
309
|
+
* scope to show. Native children always carry the active session id (stamped
|
|
310
|
+
* by `childrenToDelegationEntries`), so they survive the filter. Pure. */
|
|
311
|
+
declare function filterDelegationsToSession(entries: readonly DelegationEntry[], activeSessionID: string | null | undefined): DelegationEntry[];
|
|
204
312
|
/** Server-aligned session id validity: opencode rejects anything not starting
|
|
205
313
|
* with "ses" (SchemaError). This deliberately mirrors that exact contract —
|
|
206
314
|
* nothing stricter, nothing looser — so a template placeholder ("{sessionID}"),
|
|
@@ -237,34 +345,35 @@ type TuiSessionSources = {
|
|
|
237
345
|
* fetch (empty panel, zero errors). Pure — no I/O, no runtime required. */
|
|
238
346
|
declare function resolveCurrentSessionID(sources: TuiSessionSources): string | null;
|
|
239
347
|
/** THE single choke point for every `session.children` / session-API path.
|
|
240
|
-
* Returns
|
|
241
|
-
* null for anything else (placeholder,
|
|
242
|
-
* skips the call entirely instead of
|
|
243
|
-
* (the "%7BsessionID%7D" regression).
|
|
244
|
-
*
|
|
245
|
-
*
|
|
348
|
+
* Returns the v2 SDK parameter shape `{ sessionID }` ONLY for a
|
|
349
|
+
* server-valid session id; returns null for anything else (placeholder,
|
|
350
|
+
* empty, foreign id) so the caller skips the call entirely instead of
|
|
351
|
+
* sending an unsubstituted placeholder (the "%7BsessionID%7D" regression).
|
|
352
|
+
* The TUI client is `@opencode-ai/sdk/v2`, whose session methods take a
|
|
353
|
+
* FLAT parameter object (`{ sessionID }`), NOT the v1 `{ path: { id } }`
|
|
354
|
+
* envelope — passing the v1 shape left the v2 `{sessionID}` URL template
|
|
355
|
+
* unsubstituted (`/session/%7BsessionID%7D/children`). Every session-API
|
|
356
|
+
* call site MUST go through this function (enforced by the source-scan
|
|
357
|
+
* test in tests/pantheon/tui-delegations.test.ts). */
|
|
246
358
|
declare function safeSessionPath(id: unknown): {
|
|
247
|
-
|
|
248
|
-
id: string;
|
|
249
|
-
};
|
|
359
|
+
sessionID: string;
|
|
250
360
|
} | null;
|
|
251
|
-
/** Build the `session.children`
|
|
361
|
+
/** Build the `session.children` parameters ONLY from a validated session id.
|
|
252
362
|
* Delegates to {@link safeSessionPath} — the single choke point. Returns
|
|
253
|
-
* null for null/invalid ids so the caller
|
|
254
|
-
* sending an unsubstituted placeholder (the
|
|
363
|
+
* the v2 SDK shape `{ sessionID }`; null for null/invalid ids so the caller
|
|
364
|
+
* skips the fetch instead of sending an unsubstituted placeholder (the
|
|
365
|
+
* "%7BsessionID%7D" regression). */
|
|
255
366
|
declare function buildChildrenPath(id: string | null | undefined): {
|
|
256
|
-
|
|
257
|
-
id: string;
|
|
258
|
-
};
|
|
367
|
+
sessionID: string;
|
|
259
368
|
} | null;
|
|
260
369
|
/** Duck-typed subset of a child Session (+ its live status type). */
|
|
261
370
|
type ChildDelegationLike = {
|
|
262
|
-
/** Child session id (=
|
|
371
|
+
/** Child session id (= task id). */
|
|
263
372
|
id: string;
|
|
264
373
|
/** Session title — the delegate's description or prompt prefix. */
|
|
265
374
|
title?: string;
|
|
266
375
|
/** Agent name when the child session carries one (duck-typed; native
|
|
267
|
-
* task() children may expose it,
|
|
376
|
+
* task() children may expose it, md reports always do). */
|
|
268
377
|
agent?: string;
|
|
269
378
|
/** Status type from api.state.session.status: 'busy' | 'retry' | 'idle',
|
|
270
379
|
* or undefined when the status API is unavailable. */
|
|
@@ -274,40 +383,115 @@ type ChildDelegationLike = {
|
|
|
274
383
|
updated?: number;
|
|
275
384
|
};
|
|
276
385
|
};
|
|
277
|
-
/** Map a child status type to a display state.
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
* report still renders: description from its title, agent from the child
|
|
294
|
-
* itself (fallback 'agent'), state derived from its status, startedAt from
|
|
295
|
-
* time.created. A report-less child is a NATIVE task() child (every
|
|
296
|
-
* child of the current session — pantheon_delegate OR the native `task()`
|
|
297
|
-
* tool — carries parentID = caller), so it gets source 'children-only'
|
|
298
|
-
* and the `[native]` tag instead of a board alias.
|
|
299
|
-
* Terminal md state wins over the derived state; a running md defers to
|
|
300
|
-
* the child's live status. Sorted running-first (compareDelegationEntries).
|
|
386
|
+
/** Map a child status type to a display state.
|
|
387
|
+
*
|
|
388
|
+
* Only `busy`/`retry` are EXPLICIT live states. `idle` is terminal and so is
|
|
389
|
+
* any other/unknown status — a status the panel does not recognise is not
|
|
390
|
+
* evidence of activity. An ABSENT status is the historical case: the status
|
|
391
|
+
* map (`api.state.session.status`) contains only currently-alive sessions, so
|
|
392
|
+
* every finished child of a long session is missing from it. Defaulting that
|
|
393
|
+
* to running made the whole session history render as "active" (the
|
|
394
|
+
* "197 children, all active" regression), so an absent status is terminal
|
|
395
|
+
* (done) UNLESS the child was active within `graceMs` — a just-spawned child
|
|
396
|
+
* that the status API has not registered yet must still render as running.
|
|
397
|
+
*
|
|
398
|
+
* @param status the `api.state.session.status(id)?.type`, or undefined
|
|
399
|
+
* @param time the child session time fields (`created`/`updated`)
|
|
400
|
+
* @param now current wall-clock ms (injectable for tests)
|
|
401
|
+
* @param graceMs recency window for the absent-status running assumption
|
|
301
402
|
* Pure — no I/O. */
|
|
302
|
-
declare function
|
|
403
|
+
declare function childStatusToState(status: string | undefined, time?: {
|
|
404
|
+
created?: number;
|
|
405
|
+
updated?: number;
|
|
406
|
+
}, now?: number, graceMs?: number): 'running' | 'completed' | 'retry';
|
|
407
|
+
/** Status-only row model: ONE glyph + ONE identity per row.
|
|
408
|
+
*
|
|
409
|
+
* A row is
|
|
410
|
+
* `{glyph} {alias:7} {elapsed:>5}` plus a muted description line. The short
|
|
411
|
+
* alias (`apo-1`) is the single identity; rows without a report alias show
|
|
412
|
+
* the agent instead (never both). */
|
|
413
|
+
type DelegationRowStatus = 'active' | 'done' | 'failed' | 'retry';
|
|
414
|
+
/** Map every FSM/display state to one of the 4 row kinds. reconciled never
|
|
415
|
+
* reaches the panel (the md parser drops it) but reads as done;
|
|
416
|
+
* cancelled reads as done; startup_failed reads as failed while
|
|
417
|
+
* startup_unknown (no error known) reads as retry. Pure. */
|
|
418
|
+
declare function delegationRowStatus(state: DelegationDisplayState): DelegationRowStatus;
|
|
419
|
+
/** The only 4 glyphs a row may show: animated active, done, failed, retry.
|
|
420
|
+
* Shape is redundant with color (never the only signal). Pure. */
|
|
421
|
+
declare const DELEGATION_ROW_GLYPHS: Readonly<Record<DelegationRowStatus, string>>;
|
|
422
|
+
declare function delegationRowGlyph(status: DelegationRowStatus): string;
|
|
423
|
+
/** Row marker (`<glyph> `) — the single state channel. `active` animates
|
|
424
|
+
* through the spinner for the given frame counter (incremented every ~80ms);
|
|
425
|
+
* every other kind is static. Pure. */
|
|
426
|
+
declare function delegationRowMarker(state: DelegationDisplayState, frame?: number): string;
|
|
427
|
+
/** ONE identity per row: the short report alias (`apo-1`); a row without a
|
|
428
|
+
* report alias (native task() child `native-task` / `native-<id>`, or an
|
|
429
|
+
* alias-less native live row `live-<callID>` kept as children-only) shows
|
|
430
|
+
* the agent instead — never alias + agent stacked. Pure. */
|
|
431
|
+
declare function delegationRowIdentity(entry: DelegationEntry): string;
|
|
432
|
+
/** Fixed alias cell, pad-right + hard-truncate to `width` (default 7) so
|
|
433
|
+
* identities line up across rows. Pure. */
|
|
434
|
+
declare const DELEGATION_ALIAS_WIDTH = 7;
|
|
435
|
+
declare function formatDelegationAlias(identity: string, width?: number): string;
|
|
436
|
+
/** Max description width on the row detail line — the old 180-char slice
|
|
437
|
+
* wrapped the sidebar; 44 keeps one readable line. */
|
|
438
|
+
declare const DELEGATION_DESCRIPTION_MAX = 44;
|
|
439
|
+
/** Truncate a description to `max` graphemes appending `…` when cut. Exact
|
|
440
|
+
* `max`-length text is left untouched. Grapheme-granular, so an emoji made of
|
|
441
|
+
* several code points is never split into mojibake at the boundary. Pure. */
|
|
442
|
+
declare function truncateDelegationDescription(text: string, max?: number): string;
|
|
443
|
+
/** Fixed elapsed-time box: right-aligned to `width` (default 5) so elapsed
|
|
444
|
+
* values line up across rows, e.g. ` 12s`. A label that already fills
|
|
445
|
+
* the box is returned untouched. Pure. */
|
|
446
|
+
declare const DELEGATION_ELAPSED_WIDTH = 5;
|
|
447
|
+
declare function formatDelegationElapsed(entry: DelegationEntry, now: number, width?: number): string;
|
|
448
|
+
/** Colored left half of a row line: `<marker><alias:7> ` — the state glyph
|
|
449
|
+
* plus the single identity, padded so the muted elapsed column aligns. The
|
|
450
|
+
* row renders this colored lead separately from the muted elapsed tail. Pure. */
|
|
451
|
+
declare function formatDelegationRowLead(entry: DelegationEntry, marker: string): string;
|
|
452
|
+
/** Visible-row ceiling for the panel: the remainder collapses into a single
|
|
453
|
+
* "… +N more" line. Live rows render first, so a running job is never hidden
|
|
454
|
+
* by the cap. */
|
|
455
|
+
declare const DELEGATION_VISIBLE_CEILING = 8;
|
|
456
|
+
/** Header summary: `(N active · M done)` plus `· K failed` only when K > 0.
|
|
457
|
+
* Active counts running/retry AND display-only stale-running (a stale row is
|
|
458
|
+
* still a live job — it must never read as done); failed counts
|
|
459
|
+
* error/startup_failed; cancelled reads as done. Pure. */
|
|
460
|
+
declare function formatDelegationHeader(entries: readonly DelegationEntry[]): string;
|
|
461
|
+
/** Cap the panel: live rows first, then most-recent retained terminal rows, at
|
|
462
|
+
* most `maxVisible` total. Hidden counts describe the retained render list,
|
|
463
|
+
* not expired history. */
|
|
464
|
+
declare function ceilingDelegationList(all: readonly DelegationEntry[], maxVisible?: number, now?: number): {
|
|
465
|
+
visible: DelegationEntry[];
|
|
466
|
+
hidden: number;
|
|
467
|
+
hiddenActive: number;
|
|
468
|
+
hiddenTerminal: number;
|
|
469
|
+
};
|
|
470
|
+
/** Split a display list into native task() rows vs pantheon_delegate rows.
|
|
471
|
+
* Native = source 'children-only' (no delegate report); everything else counts
|
|
472
|
+
* as pantheon. Pure — powers the hooks.log line. */
|
|
473
|
+
declare function countDelegationSources(entries: readonly DelegationEntry[]): {
|
|
474
|
+
native: number;
|
|
475
|
+
pantheon: number;
|
|
476
|
+
total: number;
|
|
477
|
+
};
|
|
478
|
+
/** Diagnostic hooks.log line for a panel re-fetch, with the children
|
|
479
|
+
* breakdown (pantheon = children WITH a delegate report, native = children
|
|
480
|
+
* WITHOUT one). Pure — the View logs the returned string verbatim. */
|
|
481
|
+
declare function formatPanelLogLine(children: number, pantheon: number, native: number, md: number, events: number): string;
|
|
482
|
+
declare function childrenToDelegationEntries(children: readonly ChildDelegationLike[] | undefined, md: readonly DelegationEntry[], now?: number, parentSessionID?: string): DelegationEntry[];
|
|
303
483
|
/** Navigate the TUI to a child session (click/Enter on a delegation row).
|
|
304
484
|
* Returns false when the route API is unavailable or the target id is
|
|
305
485
|
* missing/placeholder — the row stays inert instead of crashing. Only a
|
|
306
486
|
* server-valid session id ("ses...") ever reaches the router, so an
|
|
307
487
|
* unsubstituted "{sessionID}" placeholder can never be routed. */
|
|
308
488
|
declare function navigateToDelegationSession(route: {
|
|
309
|
-
navigate?: (name: string, params?: Record<string, unknown>) => void
|
|
489
|
+
navigate?: (name: string, params?: Record<string, unknown>) => void | PromiseLike<void>;
|
|
310
490
|
} | undefined, taskID: string | undefined): boolean;
|
|
491
|
+
/** Build the mouse handler used by each delegation row. */
|
|
492
|
+
declare function createDelegationRowOpenHandler(route: {
|
|
493
|
+
navigate?: (name: string, params?: Record<string, unknown>) => void | PromiseLike<void>;
|
|
494
|
+
} | undefined, taskID: string | undefined): () => void;
|
|
311
495
|
/** Plugin-level live delegation store shared with the event subscriptions
|
|
312
496
|
* in `tui()`: the map of live entries + a version signal bumped on every
|
|
313
497
|
* mutation. The View subscribes to the version (in an effect) to refresh the
|
|
@@ -324,5 +508,5 @@ declare const plugin: TuiPluginModule & {
|
|
|
324
508
|
setup: () => Promise<void>;
|
|
325
509
|
};
|
|
326
510
|
//#endregion
|
|
327
|
-
export { ChildDelegationLike, DelegationActivity, DelegationEntry, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, TuiSessionSources, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationSpinnerFrame,
|
|
511
|
+
export { ChildDelegationLike, DELEGATION_ALIAS_WIDTH, DELEGATION_CHILDREN_RECENCY_MS, DELEGATION_CHILD_STATUS_GRACE_MS, DELEGATION_DESCRIPTION_MAX, DELEGATION_DONE_RETENTION_MS, DELEGATION_ELAPSED_WIDTH, DELEGATION_FAILED_RETENTION_MS, DELEGATION_ROW_GLYPHS, DELEGATION_VISIBLE_CEILING, DelegationActivity, DelegationDisplayState, DelegationEntry, DelegationRowStatus, DelegationStateTone, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, NATIVE_LIVE_ALIASLESS_TTL_MS, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, ToolActivity, TuiSessionSources, buildChildrenPath, ceilingDelegationList, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, countDelegationSources, createDelegationRowOpenHandler, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationRowGlyph, delegationRowIdentity, delegationRowMarker, delegationRowStatus, delegationSpinnerFrame, delegationStateTone, extractToolActivity, filterDelegationsToSession, fmtElapsed, formatDelegationAlias, formatDelegationElapsed, formatDelegationHeader, formatDelegationRowLead, formatPanelLogLine, isValidSessionId, latestToolActivityFor, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, resolvePantheonRoot, safeSessionPath, seedLiveDelegationMap, splitDelegationList, toDelegationEntry, trackToolActivity, truncateDelegationDescription, tuiLogPath, visibleDelegationList };
|
|
328
512
|
//# sourceMappingURL=tui.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":"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"}
|