pantheon-opencode 1.5.0-beta.11 → 1.5.0-beta.13

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/CHANGELOG.md CHANGED
@@ -18,6 +18,53 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
18
18
 
19
19
  ## ✅ Closed Issues
20
20
 
21
+ ## [v1.5.0-beta.13] - 2026-09-14
22
+
23
+ <!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
24
+ move this section to a versioned entry and reset the template below. -->
25
+
26
+ ## 🆕 What's New
27
+
28
+ - **TUI status-only — rows simplificadas:** cada linha do painel Delegations passa
29
+ a ser `{glyph} {alias} {elapsed}` + `desc` muted — um glyph de status, uma única
30
+ identidade e o tempo decorrido, com a descrição em tom muted. São 4 glyphs
31
+ (running animado, completed, error, cancelled/retry), sem toggle
32
+ `[Sessão]`/`[Tudo]`, sem prefixos `nat:`/`pan:` e sem losango ◇/◆.
33
+ - **Header `active`/`done`/`failed`:** o cabeçalho do painel resume apenas esses
34
+ três contadores sobre a lista completa (todas as sessões), sem `nat:`/`pan:`.
35
+ - **Ceiling 8:** no máximo 8 linhas visíveis (live-first); o excedente colapsa em
36
+ uma única linha `… +N more`.
37
+ - **Board read (jobs de todas as sessões):** o painel lê o BackgroundJobBoard
38
+ (`.pantheon/board/state.json`), então jobs `pantheon_delegate` de qualquer
39
+ sessão aparecem — não só os filhos nativos da sessão focada.
40
+ - **118 testes TUI delegations:** `tests/pantheon/tui-delegations.test.ts` com
41
+ 118/118 passando, cobrindo rows status-only, header active/done/failed, ceiling
42
+ e board read cross-session.
43
+
44
+ ## 🐞 Fixed
45
+
46
+ - **Sanitização de dead code:** removidos helpers, tipos e estado órfãos do
47
+ painel Delegations (toggle de escopo `[Sessão]`/`[Tudo]`, prefixos curtos
48
+ `nat:`/`pan:`, glyphs por estado e paginação de arquivo morto) que sobraram do
49
+ refactor status-only.
50
+ - **Board merge preserva sessão conhecida:** um record do board com
51
+ `parentSessionID` vazio não sobrescreve mais a sessão já atribuída à linha.
52
+ ## [v1.5.0-beta.12] - 2026-09-14
53
+
54
+ <!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
55
+ move this section to a versioned entry and reset the template below. -->
56
+
57
+ ## 🆕 What's New
58
+
59
+ - **TUI lê o board (4º canal):** o painel Delegations passa a ler o
60
+ BackgroundJobBoard via `readBoardState()` — jobs `pantheon_delegate` de todas
61
+ as sessões aparecem, não só os filhos nativos da sessão focada.
62
+ - **Toggle [Sessão]/[Tudo] + chips:** `[Sessão]` (default) mostra só a sessão
63
+ focada, `[Tudo]` mostra jobs de todas as sessões; chips clicáveis no header.
64
+ - **Raw `dist/tui.tsx` removido (bundle-only):** o dist passa a carregar só o
65
+ bundle compilado (`tui.js`); o fonte raw sai do pacote publicado.
66
+ - **117 testes TUI delegations:** `tests/pantheon/tui-delegations.test.ts` com
67
+ 117/117 passando, cobrindo board-read, split ativo/recente e toggle de escopo.
21
68
  ## [v1.5.0-beta.11] - 2026-09-14
22
69
 
23
70
  <!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pantheon-opencode",
3
- "version": "1.5.0-beta.11",
3
+ "version": "1.5.0-beta.13",
4
4
  "description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
5
5
  "type": "module",
6
6
  "publishConfig": {
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pantheon",
3
3
  "publisher": "ils15",
4
- "version": "1.5.0-beta.11",
4
+ "version": "1.5.0-beta.13",
5
5
  "displayName": "Pantheon",
6
6
  "description": "Conductor-Delegate orchestration platform with 14 specialized agents, 21 skills, and OpenCode support.",
7
7
  "agents": "./src/agents",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
4
4
 
5
5
  [project]
6
6
  name = "pantheon"
7
- version = "1.5.0-beta.11"
7
+ version = "1.5.0-beta.13"
8
8
  description = "Multi-agent orchestration framework"
9
9
  requires-python = ">=3.11"
10
10
  dependencies = []
@@ -20,7 +20,7 @@ command -v npm >/dev/null 2>&1 || { echo "error: npm not found in PATH" >&2; exi
20
20
 
21
21
  echo "==> TUI dev source: $TUI_DIR"
22
22
 
23
- # 1. Install pinned deps + build dist/tui.js (dist/tui.tsx is copied by build).
23
+ # 1. Install pinned deps + build dist/tui.js (the bundle is the only load path).
24
24
  echo "==> Installing TUI dev dependencies (npm ci)"
25
25
  npm ci --prefix "$TUI_DIR" --ignore-scripts --no-audit --no-fund
26
26
 
@@ -8,8 +8,10 @@ import { isAbsolute, join, resolve } from 'node:path'
8
8
  import { ROOT, writeIfChanged } from './shared.mjs'
9
9
 
10
10
  /**
11
- * Copy a plugin's runtime payload (src/index.tsx → index.tsx, dist/*,
12
- * package.json and package-lock.json) from source to destination.
11
+ * Copy a plugin's runtime payload (the bundled dist/*, package.json and
12
+ * package-lock.json) from source to destination. Only the bundle is copied —
13
+ * the raw TSX source is never shipped to the destination, so the plugin can
14
+ * be modularized without the loader needing relative imports.
13
15
  * @param {string} srcDir - Source plugin directory (e.g. ROOT/src/plugins/tui)
14
16
  * @param {string} dstDir - Destination plugin directory
15
17
  * @param {object} [options]
@@ -22,16 +24,11 @@ export function copyPluginFiles(srcDir, dstDir, { dryRun = false } = {}) {
22
24
  if (!dryRun) mkdirSync(dstDir, { recursive: true })
23
25
  if (!dryRun) mkdirSync(join(dstDir, 'dist'), { recursive: true })
24
26
 
25
- // Copy src/index.tsx -> index.tsx
26
- const srcIdx = join(srcDir, 'src', 'index.tsx')
27
- if (existsSync(srcIdx)) {
28
- const idxStatus = writeIfChanged(
29
- join(dstDir, 'index.tsx'),
30
- readFileSync(srcIdx, 'utf8'),
31
- dryRun,
32
- )
33
- if (idxStatus === 'created') result.created++
34
- else result.skipped++
27
+ // Drop legacy raw copies from previous installs (root index.tsx + dist/tui.tsx).
28
+ // The loader consumes only the bundle, so stale raws must not linger.
29
+ if (!dryRun) {
30
+ rmSync(join(dstDir, 'index.tsx'), { force: true })
31
+ rmSync(join(dstDir, 'dist', 'tui.tsx'), { force: true })
35
32
  }
36
33
 
37
34
  // Copy dist/* files
@@ -10,7 +10,7 @@
10
10
  * If the user hasn't initialized yet → do nothing (silent exit).
11
11
  */
12
12
  import { execSync } from 'node:child_process'
13
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
13
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
14
14
  import { homedir } from 'node:os'
15
15
  import { join } from 'node:path'
16
16
  import { fileURLToPath, pathToFileURL } from 'node:url'
@@ -58,9 +58,9 @@ function resolveConfigDir() {
58
58
  }
59
59
 
60
60
  /**
61
- * Copy plugin runtime files (dist/*, package.json, package-lock.json,
62
- * src/index.tsx) from srcDir
63
- * to dstDir. Skips files that are byte-identical.
61
+ * Copy plugin runtime files (the bundled dist/*, package.json,
62
+ * package-lock.json) from srcDir to dstDir. Skips files that are byte-identical.
63
+ * The raw TSX source is never copied — the loader consumes only the bundle.
64
64
  * @returns {{ created: number, skipped: number }}
65
65
  */
66
66
  function copyPluginFiles(srcDir, dstDir) {
@@ -69,13 +69,10 @@ function copyPluginFiles(srcDir, dstDir) {
69
69
  mkdirSync(dstDir, { recursive: true })
70
70
  mkdirSync(join(dstDir, 'dist'), { recursive: true })
71
71
 
72
- // src/index.tsx → index.tsx
73
- const srcIdx = join(srcDir, 'src', 'index.tsx')
74
- if (existsSync(srcIdx)) {
75
- const content = readFileSync(srcIdx, 'utf8')
76
- if (writeIfChanged(join(dstDir, 'index.tsx'), content)) result.created++
77
- else result.skipped++
78
- }
72
+ // Drop legacy raw copies from previous installs (root index.tsx + dist/tui.tsx).
73
+ // The loader consumes only the bundle, so stale raws must not linger.
74
+ rmSync(join(dstDir, 'index.tsx'), { force: true })
75
+ rmSync(join(dstDir, 'dist', 'tui.tsx'), { force: true })
79
76
 
80
77
  // dist/*
81
78
  const distSrc = join(srcDir, 'dist')
@@ -10,8 +10,8 @@
10
10
  * never throw, never send the placeholder).
11
11
  *
12
12
  * Mirrors the TUI's `src/plugins/tui/src/index.tsx` contract verbatim so both
13
- * sides agree on what "valid" means. The TUI file remains self-contained
14
- * (dist/tui.tsx is a raw copy, no relative imports), so its local copy is kept
13
+ * sides agree on what "valid" means. The TUI plugin ships as a bundle
14
+ * (dist/tui.js) without the src/pantheon tree, so its local copy is kept
15
15
  * in sync — this module is the shared source for `src/pantheon/*` and
16
16
  * `src/plugin.ts`.
17
17
  *
@@ -22,8 +22,9 @@ type DelegationEntry = {
22
22
  read?: boolean;
23
23
  /** Internal provenance used to keep a finalized md report authoritative.
24
24
  * 'children-only' = a native task() child session with NO board report
25
- * (rendered with the distinct `nat:` prefix); 'md' = board report wins. */
26
- source?: 'child' | 'live' | 'md' | 'children-only';
25
+ * (a native child row); 'md' = board report wins;
26
+ * 'board' = read from .pantheon/board/state.json (cross-session FSM). */
27
+ source?: 'child' | 'live' | 'md' | 'children-only' | 'board';
27
28
  };
28
29
  /** Parse one delegation report md header into a structured entry.
29
30
  * Returns null (skip) when the file is not a recognizable report:
@@ -49,13 +50,39 @@ declare function readDelegationEntries(dir: string): Promise<DelegationEntry[]>;
49
50
  * desc — the sort applied by readDelegationEntries). Fail-open: a
50
51
  * missing/unreadable directory yields []. */
51
52
  declare function readAllDelegationEntries(root: string): Promise<DelegationEntry[]>;
53
+ /** The persisted subset of BackgroundJobRecord the panel consumes. Duck-typed
54
+ * so a corrupt/older record never breaks parsing. */
55
+ type BoardJobRecord = {
56
+ taskID: string;
57
+ parentSessionID: string;
58
+ agent: string;
59
+ description?: string;
60
+ state: string;
61
+ alias: string;
62
+ launchedAt?: number;
63
+ completedAt?: number;
64
+ updatedAt?: number;
65
+ timedOut?: boolean;
66
+ };
67
+ /** The FilePersistence state path: `<root>/.pantheon/board/state.json`. */
68
+ declare function boardStatePath(root: string): string;
69
+ /** Read `.pantheon/board/state.json` (the cross-session job board snapshot).
70
+ * Fail-open: missing file, corrupt JSON, non-array payload or an unreadable
71
+ * path all yield [] — the panel keeps rendering from the other channels. */
72
+ declare function readBoardState(root: string): Promise<BoardJobRecord[]>;
73
+ /** Resolve the PROJECT ROOT used by every pantheon file channel. `directory`
74
+ * wins over `worktree` (the old `resolveDelegationsDir` already did this);
75
+ * an absent/empty root or `/` (no git — e.g. the sandbox test project) falls
76
+ * back to cwd. Standardised here so the delegations md, the board state file
77
+ * and the panel logger all read the SAME root (audit finding: the channels
78
+ * resolved the root independently). Pure — no I/O. */
79
+ declare function resolvePantheonRoot(state: {
80
+ directory?: string;
81
+ worktree?: string;
82
+ } | undefined, cwd?: string): string;
52
83
  /** Resolve the directory where the job board writes delegation md reports.
53
84
  * 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()`. */
85
+ * which the TUI exposes as `TuiState.path.directory`. */
59
86
  declare function resolveDelegationsDir(state: {
60
87
  directory?: string;
61
88
  worktree?: string;
@@ -74,17 +101,16 @@ declare function tuiLogPath(projectRoot: string): string;
74
101
  * mergeDelegationSources. */
75
102
  declare function compareDelegationEntries(a: DelegationEntry, b: DelegationEntry): number;
76
103
  /** 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
104
+ * then the most recent terminal reports; the remaining tail is collapsed
105
+ * by the View into a single "… +N more" line. Pure — so the history-only panel (no sessionID) is testable
79
106
  * without the TUI runtime. */
80
107
  declare function splitDelegationList(all: readonly DelegationEntry[], maxRecent?: number, now?: number, staleThresholdMs?: number): {
81
108
  active: DelegationEntry[];
82
109
  recent: DelegationEntry[];
83
- archived: DelegationEntry[];
84
110
  };
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. */
111
+ /** Live-first window used by {@link ceilingDelegationList} (kept for the
112
+ * ceiling helper and existing tests): active jobs first, then the most
113
+ * recent terminal reports (capped). Pure. */
88
114
  declare function visibleDelegationList(all: readonly DelegationEntry[], maxTerminal?: number, now?: number, staleThresholdMs?: number): DelegationEntry[];
89
115
  /** Default stale-running threshold: 30 minutes. */
90
116
  declare const STALE_RUNNING_THRESHOLD_MS: number;
@@ -101,7 +127,7 @@ declare const IDLE_SILENCE_MS: number;
101
127
  * delegation is still treated as running by the backend.
102
128
  */
103
129
  declare function markStaleIfRunning(entry: DelegationEntry, now: number, thresholdMs?: number): DelegationEntry;
104
- /** Compact elapsed-time label: "5m 12s", "1h 30m", "2d 4h" — ticks every
130
+ /** Compact elapsed-time label, single unit only: "12s"/"3m"/"1h"/"2d" — ticks every
105
131
  * second for running jobs. */
106
132
  declare function fmtElapsed(ms: number): string;
107
133
  /** Elapsed label for one entry: an ACTIVE entry (running/retry/stale-running)
@@ -122,20 +148,13 @@ declare function delegationSpinnerFrame(now: number): string;
122
148
  * blocked/paused/scheduled/skipped. There is no `pending` display state: a
123
149
  * pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
124
150
  type DelegationDisplayState = DelegationEntry['state'];
125
- /** Static glyph per display state. `running` shows its base spinner frame;
126
- * callers that animate must prefer {@link delegationStateMarker}. Unicode
127
- * geometric shapes only (no Nerd Font) — shape is an independent channel
128
- * from color, so rows stay legible without color. */
129
- declare const DELEGATION_STATE_GLYPHS: Readonly<Record<DelegationDisplayState, string>>;
130
- declare function delegationStateGlyph(state: DelegationDisplayState): string;
131
- /** Row marker (`<glyph> `) — the state channel. `running` animates through
132
- * {@link delegationSpinnerFrame} for the given tick; every other state is
133
- * static. Pure. */
134
- declare function delegationStateMarker(state: DelegationDisplayState, now?: number): string;
135
151
  /** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
136
152
  * Kept separate + pure so the color channel is testable without booting the
137
153
  * renderer. */
138
154
  type DelegationStateTone = 'warning' | 'error' | 'success' | 'muted';
155
+ /** Color is the ONLY channel separating `stale-running` from a live `running`
156
+ * row — the 4-glyph row design has no dedicated stale shape. Display-only;
157
+ * no behavior change. */
139
158
  declare function delegationStateTone(state: DelegationDisplayState): DelegationStateTone;
140
159
  type ToolActivity = {
141
160
  tool: string;
@@ -241,7 +260,7 @@ declare function removeDelegationEntry(map: Map<string, LiveDelegationEntry>, pa
241
260
  * SDK exposes `api.state.part(messageID)`). The native `task` tool spawns a
242
261
  * child session with parentID = caller — the same mechanism as
243
262
  * pantheon_delegate — so its parts feed the live-map as the native signal
244
- * (rows render `nat:` via the children channel). Pure w.r.t. I/O — used
263
+ * (rows come from the children channel). Pure w.r.t. I/O — used
245
264
  * by the mount re-scan to re-seed the live map after compaction/attach. */
246
265
  declare function collectDelegationToolParts(messages: readonly {
247
266
  id?: string;
@@ -261,6 +280,17 @@ declare function toDelegationEntry(live: LiveDelegationEntry): DelegationEntry;
261
280
  * terminal md entry is authoritative over a live running entry for the
262
281
  * same job (it carries Finalized/timedOut/cancelled from finalize). */
263
282
  declare function mergeDelegationSources(live: readonly LiveDelegationEntry[], md: readonly DelegationEntry[]): DelegationEntry[];
283
+ /** Map one persisted board record into the display shape. Returns null for
284
+ * states the panel does not render (reconciled / unknown). Pure. */
285
+ declare function boardRecordToDelegationEntry(record: BoardJobRecord): DelegationEntry | null;
286
+ /** Map a whole board snapshot, dropping unrenderable states. Sorted like every
287
+ * other channel (running first, then most recent). Pure. */
288
+ declare function boardRecordsToDelegationEntries(records: readonly BoardJobRecord[]): DelegationEntry[];
289
+ /** Merge the board over any other channel. The board is AUTHORITATIVE for
290
+ * state/alias/agent (it is the persisted FSM) and it is the only channel
291
+ * that carries jobs from OTHER sessions. Dedup by taskID first, then by
292
+ * (sessionID, alias) — aliases are per parent session. Pure. */
293
+ declare function mergeBoardDelegationSources(base: readonly DelegationEntry[], board: readonly DelegationEntry[]): DelegationEntry[];
264
294
  /** Server-aligned session id validity: opencode rejects anything not starting
265
295
  * with "ses" (SchemaError). This deliberately mirrors that exact contract —
266
296
  * nothing stricter, nothing looser — so a template placeholder ("{sessionID}"),
@@ -339,28 +369,34 @@ type ChildDelegationLike = {
339
369
  * (fail-open: a freshly-seen child is assumed active; the 1s poll + md
340
370
  * correct it as soon as terminal data exists). */
341
371
  declare function childStatusToState(status: string | undefined): 'running' | 'completed' | 'retry';
342
- /** Short row prefix for a delegation entry (one of the two visual channels
343
- * that split native task() work from pantheon_delegate jobs — the other is
344
- * {@link delegationIcon}):
372
+ /** Status-only row model: ONE glyph + ONE identity per row.
345
373
  *
346
- * - `nat:<agent>` — a native task() child (source 'children-only', no board
347
- * report). The child session carries no board alias, so the agent IS the
348
- * identity.
349
- * - `pan:<alias>` — a pantheon_delegate board row (`pan:apo-1`), the same
350
- * alias the manager prints in pantheon_delegation_list.
351
- *
352
- * Short prefixes keep the narrow sidebar readable (the old
353
- * `pan:apo-1`/`nat:` tags ate the row width). */
354
- declare function delegationTag(entry: DelegationEntry): string;
355
- /** Row glyph: hollow diamond `◇` for native task() children (info color,
356
- * outline) vs filled diamond `◆` for pantheon_delegate rows (state color).
357
- * Shape + color are independent channels, so the split stays legible even
358
- * without color. */
359
- declare function delegationIcon(entry: DelegationEntry): string;
360
- /** Row identity after the status marker + glyph. Pantheon rows append the
361
- * agent (`pan:apo-1 apollo`); native rows already carry it inside the tag
362
- * (`nat:apollo`) and must not duplicate it. */
363
- declare function formatDelegationIdentity(entry: DelegationEntry): string;
374
+ * A row is
375
+ * `{glyph} {alias:7} {elapsed:>5}` plus a muted description line. The short
376
+ * alias (`apo-1`) is the single identity; rows without a board alias show
377
+ * the agent instead (never both). */
378
+ type DelegationRowStatus = 'active' | 'done' | 'failed' | 'retry';
379
+ /** Map every FSM/display state to one of the 4 row kinds. reconciled never
380
+ * reaches the panel (the board parser drops it) but reads as done;
381
+ * cancelled reads as done; startup_failed reads as failed while
382
+ * startup_unknown (no error known) reads as retry. Pure. */
383
+ declare function delegationRowStatus(state: DelegationDisplayState): DelegationRowStatus;
384
+ /** The only 4 glyphs a row may show: animated active, done, failed, retry.
385
+ * Shape is redundant with color (never the only signal). Pure. */
386
+ declare const DELEGATION_ROW_GLYPHS: Readonly<Record<DelegationRowStatus, string>>;
387
+ declare function delegationRowGlyph(status: DelegationRowStatus): string;
388
+ /** Row marker (`<glyph> `) — the single state channel. `active` animates
389
+ * through the 1s spinner for the given tick; every other kind is static.
390
+ * Pure. */
391
+ declare function delegationRowMarker(state: DelegationDisplayState, now?: number): string;
392
+ /** ONE identity per row: the short board alias (`apo-1`); a row without a
393
+ * board alias (native task() child, alias `native-task`) shows the agent
394
+ * instead — never alias + agent stacked. Pure. */
395
+ declare function delegationRowIdentity(entry: DelegationEntry): string;
396
+ /** Fixed alias cell, pad-right + hard-truncate to `width` (default 7) so
397
+ * identities line up across rows. Pure. */
398
+ declare const DELEGATION_ALIAS_WIDTH = 7;
399
+ declare function formatDelegationAlias(identity: string, width?: number): string;
364
400
  /** Max description width on the row detail line — the old 180-char slice
365
401
  * wrapped the sidebar; 44 keeps one readable line. */
366
402
  declare const DELEGATION_DESCRIPTION_MAX = 44;
@@ -368,21 +404,34 @@ declare const DELEGATION_DESCRIPTION_MAX = 44;
368
404
  * `max`-length text is left untouched. Grapheme-granular, so an emoji made of
369
405
  * several code points is never split into mojibake at the boundary. Pure. */
370
406
  declare function truncateDelegationDescription(text: string, max?: number): string;
371
- /** Fixed elapsed-time box: right-aligned to `width` (default 8) so elapsed
372
- * values line up across rows, e.g. ` 12s`. A label that already fills
407
+ /** Fixed elapsed-time box: right-aligned to `width` (default 5) so elapsed
408
+ * values line up across rows, e.g. ` 12s`. A label that already fills
373
409
  * the box is returned untouched. Pure. */
374
- declare const DELEGATION_ELAPSED_WIDTH = 8;
410
+ declare const DELEGATION_ELAPSED_WIDTH = 5;
375
411
  declare function formatDelegationElapsed(entry: DelegationEntry, now: number, width?: number): string;
376
- /** First row line: `<marker><glyph> <identity>`. The marker already carries
377
- * its trailing space. Pure — the row renders the returned string verbatim. */
378
- declare function formatDelegationRow(entry: DelegationEntry, marker: string): string;
379
- /** Header summary: `(N active · M done · nat:K pan:M)`. Active counts
380
- * running/retry AND display-only stale-running (a stale row is still a live
381
- * job — it must never read as done). Pure. */
412
+ /** Colored left half of a row line: `<marker><alias:7> ` — the state glyph
413
+ * plus the single identity, padded so the muted elapsed column aligns. The
414
+ * row renders this colored lead separately from the muted elapsed tail. Pure. */
415
+ declare function formatDelegationRowLead(entry: DelegationEntry, marker: string): string;
416
+ /** Visible-row ceiling for the panel: the remainder collapses into a single
417
+ * "… +N more" line. Live rows render first, so a running job is never hidden
418
+ * by the cap. */
419
+ declare const DELEGATION_VISIBLE_CEILING = 8;
420
+ /** Header summary: `(N active · M done)` plus `· K failed` only when K > 0.
421
+ * Active counts running/retry AND display-only stale-running (a stale row is
422
+ * still a live job — it must never read as done); failed counts
423
+ * error/startup_failed; cancelled reads as done. Pure. */
382
424
  declare function formatDelegationHeader(entries: readonly DelegationEntry[]): string;
425
+ /** Cap the panel: live rows first, then most-recent terminal rows, at most
426
+ * `maxVisible` total. `hidden` is how many were dropped (rendered as
427
+ * "… +N more"). Pure. */
428
+ declare function ceilingDelegationList(all: readonly DelegationEntry[], maxVisible?: number, now?: number): {
429
+ visible: DelegationEntry[];
430
+ hidden: number;
431
+ };
383
432
  /** Split a display list into native task() rows vs pantheon_delegate rows.
384
433
  * Native = source 'children-only' (no board report); everything else counts
385
- * as pantheon. Pure — powers the header breakdown + the hooks.log line. */
434
+ * as pantheon. Pure — powers the hooks.log line. */
386
435
  declare function countDelegationSources(entries: readonly DelegationEntry[]): {
387
436
  native: number;
388
437
  pantheon: number;
@@ -401,15 +450,18 @@ declare function formatPanelLogLine(children: number, pantheon: number, native:
401
450
  * time.created. A report-less child is a NATIVE task() child (every
402
451
  * child of the current session — pantheon_delegate OR the native `task()`
403
452
  * tool — carries parentID = caller), so it gets source 'children-only',
404
- * the internal alias 'native-task' and the `nat:` tag instead of a
453
+ * the internal alias 'native-task' instead of a
405
454
  * board alias. The 'task nativa' description fallback keeps the row
406
455
  * non-empty when the child carries no title.
407
456
  * Terminal md state wins over the derived state; a running md defers to
408
457
  * the child's live status. A running child is NEVER archived — it always
409
458
  * lands in the active split (splitDelegationList active = running/retry).
459
+ * `parentSessionID` (the focused session id) is stamped on report-less
460
+ * children so the row carries its origin session; omit it and they stay
461
+ * unscoped ('').
410
462
  * Sorted running-first (compareDelegationEntries).
411
463
  * Pure — no I/O. */
412
- declare function childrenToDelegationEntries(children: readonly ChildDelegationLike[] | undefined, md: readonly DelegationEntry[], now?: number): DelegationEntry[];
464
+ declare function childrenToDelegationEntries(children: readonly ChildDelegationLike[] | undefined, md: readonly DelegationEntry[], now?: number, parentSessionID?: string): DelegationEntry[];
413
465
  /** Navigate the TUI to a child session (click/Enter on a delegation row).
414
466
  * Returns false when the route API is unavailable or the target id is
415
467
  * missing/placeholder — the row stays inert instead of crashing. Only a
@@ -434,5 +486,5 @@ declare const plugin: TuiPluginModule & {
434
486
  setup: () => Promise<void>;
435
487
  };
436
488
  //#endregion
437
- export { ChildDelegationLike, DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DELEGATION_STATE_GLYPHS, DelegationActivity, DelegationDisplayState, DelegationEntry, DelegationStateTone, 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, delegationIcon, delegationSpinnerFrame, delegationStateGlyph, delegationStateMarker, delegationStateTone, delegationTag, extractToolActivity, fmtElapsed, formatDelegationElapsed, formatDelegationHeader, formatDelegationIdentity, formatDelegationRow, formatPanelLogLine, isValidSessionId, latestToolActivityFor, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, safeSessionPath, seedLiveDelegationMap, splitDelegationList, toDelegationEntry, trackToolActivity, truncateDelegationDescription, tuiLogPath, visibleDelegationList };
489
+ export { BoardJobRecord, ChildDelegationLike, DELEGATION_ALIAS_WIDTH, DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DELEGATION_ROW_GLYPHS, DELEGATION_VISIBLE_CEILING, DelegationActivity, DelegationDisplayState, DelegationEntry, DelegationRowStatus, DelegationStateTone, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, ToolActivity, TuiSessionSources, boardRecordToDelegationEntry, boardRecordsToDelegationEntries, boardStatePath, buildChildrenPath, ceilingDelegationList, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, countDelegationSources, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationRowGlyph, delegationRowIdentity, delegationRowMarker, delegationRowStatus, delegationSpinnerFrame, delegationStateTone, extractToolActivity, fmtElapsed, formatDelegationAlias, formatDelegationElapsed, formatDelegationHeader, formatDelegationRowLead, formatPanelLogLine, isValidSessionId, latestToolActivityFor, markStaleIfRunning, mergeBoardDelegationSources, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readBoardState, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, resolvePantheonRoot, safeSessionPath, seedLiveDelegationMap, splitDelegationList, toDelegationEntry, trackToolActivity, truncateDelegationDescription, tuiLogPath, visibleDelegationList };
438
490
  //# sourceMappingURL=tui.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":"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"}
1
+ {"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":"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"}