pantheon-opencode 1.5.0-beta.9 → 1.5.0

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.
Files changed (82) hide show
  1. package/AGENTS.md +14 -63
  2. package/CHANGELOG.md +304 -0
  3. package/README.md +14 -27
  4. package/README.pt-BR.md +5 -6
  5. package/commands/pantheon.md +1 -35
  6. package/package.json +1 -2
  7. package/plugin.json +1 -1
  8. package/pyproject.toml +2 -5
  9. package/scripts/doctor.mjs +32 -3
  10. package/scripts/install/plugin.mjs +9 -12
  11. package/scripts/mcp_persistence_server.py +1 -1
  12. package/scripts/sync-tui.mjs +8 -11
  13. package/src/agents/apollo.md +1 -0
  14. package/src/agents/gaia.md +1 -0
  15. package/src/agents/zeus.md +9 -52
  16. package/src/instructions/memory-protocol.instructions.md +6 -3
  17. package/src/instructions/zeus-anti-stall.instructions.md +2 -4
  18. package/src/instructions/zeus-council-synthesis.instructions.md +3 -28
  19. package/src/instructions/zeus-timeout-retry.instructions.md +3 -28
  20. package/src/mcp/mcp_persistence_server.py +1 -1
  21. package/src/mcp/toon_codec.py +2 -4
  22. package/src/pantheon/background-job-board.ts +4 -4
  23. package/src/pantheon/{delegation-compaction.ts → compaction-context.ts} +10 -100
  24. package/src/pantheon/cost-command.ts +1 -2
  25. package/src/pantheon/delegation-enforce.ts +59 -14
  26. package/src/pantheon/goal-loop.ts +1 -1
  27. package/src/pantheon/goal-store.ts +1 -1
  28. package/src/pantheon/idle-continuation.ts +4 -6
  29. package/src/pantheon/model-command.ts +1 -2
  30. package/src/pantheon/native-task-status.ts +2 -2
  31. package/src/pantheon/presets.d.mts +0 -20
  32. package/src/pantheon/presets.mjs +0 -64
  33. package/src/pantheon/session-guard.ts +2 -2
  34. package/src/pantheon/session-id.ts +30 -0
  35. package/src/pantheon/task-result-guard.ts +2 -3
  36. package/src/pantheon/todo-enforcer.ts +3 -3
  37. package/src/pantheon/tool-context.ts +23 -0
  38. package/src/pantheon/v2-bridge.ts +1 -4
  39. package/src/plugin-v2.ts +8 -21
  40. package/src/plugin.ts +61 -245
  41. package/src/plugins/pantheon-hooks.ts +1 -1
  42. package/src/plugins/tui/dist/tui.d.ts +212 -81
  43. package/src/plugins/tui/dist/tui.d.ts.map +1 -1
  44. package/src/plugins/tui/dist/tui.js +475 -254
  45. package/src/plugins/tui/package-lock.json +2 -2
  46. package/src/plugins/tui/package.json +2 -2
  47. package/src/plugins/tui/src/index.tsx +667 -269
  48. package/src/routing.yml +0 -16
  49. package/src/skills/context-compression/SKILL.md +1 -1
  50. package/scripts/generate-preset-docs.mjs +0 -300
  51. package/scripts/generate-prompts.sh +0 -222
  52. package/scripts/hash_verify.py +0 -192
  53. package/scripts/install/component.mjs +0 -24
  54. package/scripts/install/migrate-config.mjs +0 -302
  55. package/scripts/test-context-compression.sh +0 -169
  56. package/src/pantheon/auto-wake.ts +0 -85
  57. package/src/pantheon/chat-reminders.ts +0 -9
  58. package/src/pantheon/comment-checker.ts +0 -48
  59. package/src/pantheon/compaction-assert.ts +0 -160
  60. package/src/pantheon/compaction-handoff.ts +0 -304
  61. package/src/pantheon/cost-tracker.ts +0 -108
  62. package/src/pantheon/delegate-manager.ts +0 -766
  63. package/src/pantheon/delegation-classifier.ts +0 -307
  64. package/src/pantheon/delegation-finalize.ts +0 -406
  65. package/src/pantheon/delegation-notify.ts +0 -212
  66. package/src/pantheon/delegation-toast.ts +0 -73
  67. package/src/pantheon/delegation.ts +0 -1337
  68. package/src/pantheon/dispatch-guard.ts +0 -109
  69. package/src/pantheon/native-probe.ts +0 -234
  70. package/src/pantheon/permission-eval.ts +0 -284
  71. package/src/pantheon/preemptive-compact.ts +0 -76
  72. package/src/pantheon/provider-capabilities.ts +0 -221
  73. package/src/pantheon/provider-stream-tracker.ts +0 -182
  74. package/src/pantheon/retry-policy.ts +0 -212
  75. package/src/pantheon/step-cap.ts +0 -110
  76. package/src/pantheon/token-opt.ts +0 -689
  77. package/src/pantheon/toon-codec.ts +0 -481
  78. package/src/pantheon/v2-events.ts +0 -148
  79. package/src/pantheon/v2-hooks.ts +0 -287
  80. package/src/pantheon/v2-tool-definitions.ts +0 -331
  81. package/src/pantheon/zeus-delegate-with-retry.ts +0 -406
  82. package/src/plugins/tui/dist/tui.tsx +0 -2853
@@ -5,7 +5,7 @@ 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 (= board task id, from the `Task ID` header). The
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;
@@ -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 board report
25
- * (rendered with the distinct `[native]` tag); 'md' = board report wins. */
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,19 +45,26 @@ 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
- * HISTORY channel. Unlike the children/live channels it does NOT depend on a
47
- * resolved sessionID: with no focused session (null/placeholder), the panel
48
- * still shows the reports from all past sessions (running first, Finalized
49
- * desc — the sort applied by readDelegationEntries). Fail-open: a
50
- * missing/unreadable directory yields []. */
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 directory where the job board writes delegation md reports.
53
- * The board writes `.pantheon/delegations` RELATIVE to the server cwd,
54
- * which the TUI exposes as `TuiState.path.directory`. `project` does NOT
55
- * exist on `TuiState.path` (the old `state?.project ?? state?.worktree`
56
- * resolution was always undefined for the first term) and `worktree` is
57
- * `/` when there is no git (e.g. the sandbox test project) — a root of
58
- * `''` or `'/'` must fall back to `process.cwd()`. */
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;
@@ -74,17 +83,16 @@ declare function tuiLogPath(projectRoot: string): string;
74
83
  * mergeDelegationSources. */
75
84
  declare function compareDelegationEntries(a: DelegationEntry, b: DelegationEntry): number;
76
85
  /** Split the panel list: active jobs (running/retry, stale-marked) first,
77
- * then the most recent terminal reports, then the archived tail (paginated
78
- * in the View). Pure — so the history-only panel (no sessionID) is testable
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
79
88
  * without the TUI runtime. */
80
89
  declare function splitDelegationList(all: readonly DelegationEntry[], maxRecent?: number, now?: number, staleThresholdMs?: number): {
81
90
  active: DelegationEntry[];
82
91
  recent: DelegationEntry[];
83
- archived: DelegationEntry[];
84
92
  };
85
- /** The list the panel actually renders (kept for the header count and
86
- * existing tests): active jobs first, then the most recent terminal
87
- * reports (capped) — the archived tail is rendered separately. Pure. */
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. */
88
96
  declare function visibleDelegationList(all: readonly DelegationEntry[], maxTerminal?: number, now?: number, staleThresholdMs?: number): DelegationEntry[];
89
97
  /** Default stale-running threshold: 30 minutes. */
90
98
  declare const STALE_RUNNING_THRESHOLD_MS: number;
@@ -92,28 +100,74 @@ declare const STALE_RUNNING_THRESHOLD_MS: number;
92
100
  * considered stale. Combined with the stale-running threshold to produce the
93
101
  * display-only `stale-running` state. */
94
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;
95
130
  /**
96
131
  * Mark a running entry as `stale-running` if it has been running longer than
97
132
  * the threshold AND has no recent activity (no `updatedAt` change in the last
98
- * `IDLE_SILENCE_MS`). This is DISPLAY-ONLY — the board state is unchanged.
133
+ * `IDLE_SILENCE_MS`). This is DISPLAY-ONLY — the persisted state is unchanged.
99
134
  *
100
135
  * A `stale-running` entry renders with a warning indicator but the underlying
101
136
  * delegation is still treated as running by the backend.
102
137
  */
103
138
  declare function markStaleIfRunning(entry: DelegationEntry, now: number, thresholdMs?: number): DelegationEntry;
104
- /** Compact elapsed-time label: "5m 12s", "1h 30m", "2d 4h" — ticks every
139
+ /** Compact elapsed-time label, single unit only: "12s"/"3m"/"1h"/"2d" — ticks every
105
140
  * second for running jobs. */
106
141
  declare function fmtElapsed(ms: number): string;
107
- /** Elapsed label for one entry: running → ticks `now - startedAt`, terminal
108
- * → fixed `updatedAt - startedAt` (em dash when no finalized timestamp). */
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). */
109
145
  declare function delegationElapsed(entry: DelegationEntry, now: number): string;
110
146
  /** The activity labels shown by the animated row. Keeping this pure makes the
111
147
  * state machine testable without booting OpenCode's renderer. */
112
148
  type DelegationActivity = 'delegating' | 'working' | 'reading' | 'completed' | 'error' | 'cancelled';
113
149
  declare function delegationActivity(entry: DelegationEntry): DelegationActivity;
114
150
  declare function delegationActivityLabel(entry: DelegationEntry): string;
115
- /** Return a deterministic spinner frame. The View ticks this every 140ms. */
116
- declare function delegationSpinnerFrame(now: number): string;
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;
117
171
  type ToolActivity = {
118
172
  tool: string;
119
173
  summary: string;
@@ -203,7 +257,7 @@ type ParsedDelegationToolPart = {
203
257
  /** Extract the tool name + args from a `message.part.updated` part and
204
258
  * reduce it to what the panel needs. Returns null for anything that is
205
259
  * not a pantheon delegation tool part, the native `task` subagent tool
206
- * (same parentID === caller mechanism — its children render `[native]`),
260
+ * (same parentID === caller mechanism — its children render `nat:`),
207
261
  * or is missing its callID. */
208
262
  declare function parseDelegationToolPart(part: DelegationToolPart, now?: number): ParsedDelegationToolPart | null;
209
263
  /** Apply one tool part to the live map. Returns true when the map changed.
@@ -218,7 +272,7 @@ declare function removeDelegationEntry(map: Map<string, LiveDelegationEntry>, pa
218
272
  * SDK exposes `api.state.part(messageID)`). The native `task` tool spawns a
219
273
  * child session with parentID = caller — the same mechanism as
220
274
  * pantheon_delegate — so its parts feed the live-map as the native signal
221
- * (rows render `[native]` via the children channel). Pure w.r.t. I/O — used
275
+ * (rows come from the children channel). Pure w.r.t. I/O — used
222
276
  * by the mount re-scan to re-seed the live map after compaction/attach. */
223
277
  declare function collectDelegationToolParts(messages: readonly {
224
278
  id?: string;
@@ -238,6 +292,23 @@ declare function toDelegationEntry(live: LiveDelegationEntry): DelegationEntry;
238
292
  * terminal md entry is authoritative over a live running entry for the
239
293
  * same job (it carries Finalized/timedOut/cancelled from finalize). */
240
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[];
241
312
  /** Server-aligned session id validity: opencode rejects anything not starting
242
313
  * with "ses" (SchemaError). This deliberately mirrors that exact contract —
243
314
  * nothing stricter, nothing looser — so a template placeholder ("{sessionID}"),
@@ -274,34 +345,35 @@ type TuiSessionSources = {
274
345
  * fetch (empty panel, zero errors). Pure — no I/O, no runtime required. */
275
346
  declare function resolveCurrentSessionID(sources: TuiSessionSources): string | null;
276
347
  /** THE single choke point for every `session.children` / session-API path.
277
- * Returns `{ path: { id } }` ONLY for a server-valid session id; returns
278
- * null for anything else (placeholder, empty, foreign id) so the caller
279
- * skips the call entirely instead of sending an unsubstituted placeholder
280
- * (the "%7BsessionID%7D" regression). Every session-API call site MUST go
281
- * through this function (enforced by the source-scan test in
282
- * tests/pantheon/tui-delegations.test.ts). */
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). */
283
358
  declare function safeSessionPath(id: unknown): {
284
- path: {
285
- id: string;
286
- };
359
+ sessionID: string;
287
360
  } | null;
288
- /** Build the `session.children` path ONLY from a validated session id.
361
+ /** Build the `session.children` parameters ONLY from a validated session id.
289
362
  * Delegates to {@link safeSessionPath} — the single choke point. Returns
290
- * null for null/invalid ids so the caller skips the fetch instead of
291
- * sending an unsubstituted placeholder (the "%7BsessionID%7D" regression). */
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). */
292
366
  declare function buildChildrenPath(id: string | null | undefined): {
293
- path: {
294
- id: string;
295
- };
367
+ sessionID: string;
296
368
  } | null;
297
369
  /** Duck-typed subset of a child Session (+ its live status type). */
298
370
  type ChildDelegationLike = {
299
- /** Child session id (= board task id). */
371
+ /** Child session id (= task id). */
300
372
  id: string;
301
373
  /** Session title — the delegate's description or prompt prefix. */
302
374
  title?: string;
303
375
  /** Agent name when the child session carries one (duck-typed; native
304
- * task() children may expose it, board reports always do). */
376
+ * task() children may expose it, md reports always do). */
305
377
  agent?: string;
306
378
  /** Status type from api.state.session.status: 'busy' | 'retry' | 'idle',
307
379
  * or undefined when the status API is unavailable. */
@@ -311,56 +383,115 @@ type ChildDelegationLike = {
311
383
  updated?: number;
312
384
  };
313
385
  };
314
- /** Map a child status type to a display state. busy/retry → running
315
- * (the child is actively working), idle → completed, unknown → running
316
- * (fail-open: a freshly-seen child is assumed active; the 1s poll + md
317
- * correct it as soon as terminal data exists). */
318
- declare function childStatusToState(status: string | undefined): 'running' | 'completed' | 'retry';
319
- /** Row tag for a delegation entry: `[native]` for native task() children
320
- * (source 'children-only' — no board report), `[pantheon:<alias>]` for board
321
- * rows ([pantheon:apo-1]) — the same tags the manager prints in
322
- * pantheon_delegation_list, so panel rows and CLI list lines match. The
323
- * panel renders the tag with a distinct style so native task() children are
324
- * visually separable from pantheon_delegate jobs. */
325
- declare function delegationTag(entry: DelegationEntry): string;
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
402
+ * Pure — no I/O. */
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
+ };
326
470
  /** Split a display list into native task() rows vs pantheon_delegate rows.
327
- * Native = source 'children-only' (no board report); everything else counts
328
- * as pantheon. Pure — powers the header breakdown + the hooks.log line. */
471
+ * Native = source 'children-only' (no delegate report); everything else counts
472
+ * as pantheon. Pure — powers the hooks.log line. */
329
473
  declare function countDelegationSources(entries: readonly DelegationEntry[]): {
330
474
  native: number;
331
475
  pantheon: number;
332
476
  total: number;
333
477
  };
334
478
  /** Diagnostic hooks.log line for a panel re-fetch, with the children
335
- * breakdown (pantheon = children WITH a board report, native = children
479
+ * breakdown (pantheon = children WITH a delegate report, native = children
336
480
  * WITHOUT one). Pure — the View logs the returned string verbatim. */
337
481
  declare function formatPanelLogLine(children: number, pantheon: number, native: number, md: number, events: number): string;
338
- /** Turn child sessions (PRIMARY) enriched with md reports into the display
339
- * list. One entry per child id (duplicates across re-fetches collapse).
340
- * The md report is matched by `Task ID` (== child.id) and supplies alias,
341
- * agent, description, terminal state and duration. A child without a
342
- * report still renders: description from its title, agent from the child
343
- * itself (fallback 'agent'), state derived from its status, startedAt from
344
- * time.created. A report-less child is a NATIVE task() child (every
345
- * child of the current session — pantheon_delegate OR the native `task()`
346
- * tool — carries parentID = caller), so it gets source 'children-only',
347
- * the internal alias 'native-task' and the `[native]` tag instead of a
348
- * board alias. The 'task nativa' description fallback keeps the row
349
- * non-empty when the child carries no title.
350
- * Terminal md state wins over the derived state; a running md defers to
351
- * the child's live status. A running child is NEVER archived — it always
352
- * lands in the active split (splitDelegationList active = running/retry).
353
- * Sorted running-first (compareDelegationEntries).
354
- * Pure — no I/O. */
355
- declare function childrenToDelegationEntries(children: readonly ChildDelegationLike[] | undefined, md: readonly DelegationEntry[], now?: number): DelegationEntry[];
482
+ declare function childrenToDelegationEntries(children: readonly ChildDelegationLike[] | undefined, md: readonly DelegationEntry[], now?: number, parentSessionID?: string): DelegationEntry[];
356
483
  /** Navigate the TUI to a child session (click/Enter on a delegation row).
357
484
  * Returns false when the route API is unavailable or the target id is
358
485
  * missing/placeholder — the row stays inert instead of crashing. Only a
359
486
  * server-valid session id ("ses...") ever reaches the router, so an
360
487
  * unsubstituted "{sessionID}" placeholder can never be routed. */
361
488
  declare function navigateToDelegationSession(route: {
362
- navigate?: (name: string, params?: Record<string, unknown>) => void;
489
+ navigate?: (name: string, params?: Record<string, unknown>) => void | PromiseLike<void>;
363
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;
364
495
  /** Plugin-level live delegation store shared with the event subscriptions
365
496
  * in `tui()`: the map of live entries + a version signal bumped on every
366
497
  * mutation. The View subscribes to the version (in an effect) to refresh the
@@ -377,5 +508,5 @@ declare const plugin: TuiPluginModule & {
377
508
  setup: () => Promise<void>;
378
509
  };
379
510
  //#endregion
380
- export { ChildDelegationLike, DelegationActivity, DelegationEntry, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, ToolActivity, TuiSessionSources, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, countDelegationSources, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationSpinnerFrame, delegationTag, extractToolActivity, fmtElapsed, formatPanelLogLine, isValidSessionId, latestToolActivityFor, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, safeSessionPath, seedLiveDelegationMap, splitDelegationList, toDelegationEntry, trackToolActivity, tuiLogPath, visibleDelegationList };
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 };
381
512
  //# sourceMappingURL=tui.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;KAu7BY;;EAEV;;EAEA;;;;EAIA;;EAEA;EACA;;EAUA;;EAEA;EACA;EACA;;EAEA;;;;EAIA;;;;;;;;;;;iBAsBc,wBACd,aACA,oBACA,qBACC;;;;;;iBAkHmB,sBAAsB,cAAc,QAAQ;;;;;;;;iBAwC5C,yBAAyB,eAAe,QAAQ;;;;;;;;iBAWtD,sBACd;EAAS;EAAoB;eAC7B;;;;;;iBAYc,YAAY;;;iBAMZ,WAAW;;;;iBAOX,yBAAyB,GAAG,iBAAiB,GAAG;;;;;iBAahD,oBACd,cAAc,mBACd,oBACA,cACA;EACG,QAAQ;EAAmB,QAAQ;EAAmB,UAAU;;;;;iBAerD,sBACd,cAAc,mBACd,sBACA,cACA,4BACC;;cAMU;;;;cAKA;;;;;;;;;iBAUG,mBACd,OAAO,iBACP,aACA,uBACC;;;iBAWa,WAAW;;;iBAcX,kBAAkB,OAAO,iBAAiB;;;KAQ9C;iBAQI,mBAAmB,OAAO,kBAAkB;iBAc5C,wBAAwB,OAAO;;iBAqB/B,uBAAuB;KAY3B;EACV;EACA;EACA;;;;;iBA0Bc,oBACd;EACE;EACA;EACA;EACA;IAAU;IAAiB,QAAQ;;GAErC;EACG;EAAmB,UAAU;;;iBAYlB,kBACd,KAAK,YAAY,eACjB,mBACA,UAAU;;iBAWI,sBACd,KAAK,YAAY,eACjB,+BACA,cACA,iBACC;;;;;;;iBAca,4BACd,mBAAmB,mBACnB,eAAe,wBACd;;KAqFS;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA,QAAQ;IACR;IACA;IACA;MAAS;MAAgB;;;;;KAKjB;;EAEV;;EAEA;;EAEA;EACA;;EAEA;EACA;;EAEA;;EAEA;EACA;EACA;EACA;;EAEA;;;KAIU;EACV;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;iBAec,wBACd,MAAM,oBACN,eACC;;;iBAgGa,yBACd,KAAK,YAAY,sBACjB,MAAM,oBACN;;;iBAiGc,sBACd,KAAK,YAAY,sBACjB;;;;;;;;;iBAoBc,2BACd;EAAqB;EAAa;iBAClC,YAAY,uDACX;;;;;iBA6Ba,sBACd,KAAK,YAAY,sBACjB,gBAAgB,sBAChB;;;iBAWc,kBAAkB,MAAM,sBAAsB;;;;;;iBAqB9C,uBACd,eAAe,uBACf,aAAa,oBACZ;;;;;;;;;iBA8Da,iBAAiB,cAAc;;;;KAOnC;;EAEV;EACA;;IAEE;MAAU;;;IAEV;MAAU;QAAY;QAAe,SAAS;;;;;;;;;;iBASlC,wBAAwB,SAAS;;;;;;;;iBAmBjC,gBAAgB;EAAgB;IAAQ;;;;;;;iBASxC,kBAAkB;EAAkC;IAAQ;;;;KAKhE;;EAEV;;EAEA;;;EAGA;;;EAGA;EACA;IACE;IACA;;;;;;;iBAQY,mBAAmB;;;;;;;iBAYnB,cAAc,OAAO;;;;iBAOrB,uBAAuB,kBAAkB;EACvD;EACA;EACA;;;;;iBAUc,mBACd,kBACA,kBACA,gBACA,YACA;;;;;;;;;;;;;;;;;;iBAsBc,4BACd,mBAAmB,mCACnB,aAAa,mBACb,eACC;;;;;;iBA4Ca,4BACd;EAAS,YAAY,cAAc,SAAS;eAC5C;;;;;KAiMU;EACV,KAAK,YAAY;;EAEjB;;EAEA;;cAugBI,QAAQ;EAAoB;EAAY,aAAa"}
1
+ {"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":"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"}