pantheon-opencode 1.5.0-beta.16 → 1.5.0-beta.18

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 (41) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +13 -25
  3. package/README.pt-BR.md +4 -5
  4. package/package.json +1 -1
  5. package/plugin.json +1 -1
  6. package/pyproject.toml +1 -1
  7. package/scripts/mcp_persistence_server.py +1 -1
  8. package/src/agents/apollo.md +1 -0
  9. package/src/agents/gaia.md +1 -0
  10. package/src/agents/zeus.md +8 -29
  11. package/src/mcp/mcp_persistence_server.py +1 -1
  12. package/src/pantheon/{delegation-compaction.ts → compaction-context.ts} +10 -100
  13. package/src/pantheon/cost-command.ts +1 -2
  14. package/src/pantheon/delegation-enforce.ts +59 -14
  15. package/src/pantheon/goal-loop.ts +1 -1
  16. package/src/pantheon/goal-store.ts +1 -1
  17. package/src/pantheon/idle-continuation.ts +4 -6
  18. package/src/pantheon/model-command.ts +1 -2
  19. package/src/pantheon/native-task-status.ts +2 -2
  20. package/src/pantheon/session-id.ts +30 -0
  21. package/src/pantheon/task-result-guard.ts +2 -3
  22. package/src/pantheon/todo-enforcer.ts +3 -3
  23. package/src/pantheon/tool-context.ts +23 -0
  24. package/src/pantheon/v2-bridge.ts +1 -4
  25. package/src/plugin-v2.ts +4 -15
  26. package/src/plugin.ts +61 -245
  27. package/src/plugins/tui/dist/tui.d.ts +49 -79
  28. package/src/plugins/tui/dist/tui.d.ts.map +1 -1
  29. package/src/plugins/tui/dist/tui.js +48 -189
  30. package/src/plugins/tui/package-lock.json +2 -2
  31. package/src/plugins/tui/package.json +1 -1
  32. package/src/plugins/tui/src/index.tsx +97 -295
  33. package/src/skills/context-compression/SKILL.md +1 -1
  34. package/src/pantheon/delegate-manager.ts +0 -851
  35. package/src/pantheon/delegation-classifier.ts +0 -306
  36. package/src/pantheon/delegation-finalize.ts +0 -468
  37. package/src/pantheon/delegation-notify.ts +0 -212
  38. package/src/pantheon/delegation-toast.ts +0 -73
  39. package/src/pantheon/delegation.ts +0 -1349
  40. package/src/pantheon/native-probe.ts +0 -234
  41. package/src/pantheon/step-cap.ts +0 -110
@@ -165,7 +165,7 @@ async function detectVersion(api) {
165
165
  if (ver) return ver;
166
166
  }
167
167
  } catch {}
168
- return "1.5.0-beta.16";
168
+ return "1.5.0-beta.18";
169
169
  }
170
170
  /**
171
171
  * usage-bar — AI subscription usage gauge for the opencode TUI.
@@ -841,71 +841,19 @@ async function readDelegationEntries(dir) {
841
841
  async function readAllDelegationEntries(root) {
842
842
  return readDelegationEntries(join(root, ".pantheon", "delegations"));
843
843
  }
844
- /** The persisted subset of BackgroundJobRecord the panel consumes. Duck-typed
845
- * so a corrupt/older record never breaks parsing. */
846
- /** The FilePersistence state path: `<root>/.pantheon/board/state.json`. */
847
- function boardStatePath(root) {
848
- return join(root, ".pantheon", "board", "state.json");
849
- }
850
- /** Validate one parsed record, keeping only the fields the panel uses.
851
- * Returns null for anything without a taskID/state (a corrupt entry is
852
- * skipped individually — the rest of the snapshot still loads). */
853
- function normalizeBoardRecord(item) {
854
- if (typeof item !== "object" || item === null) return null;
855
- const rec = item;
856
- if (typeof rec.taskID !== "string" || rec.taskID === "") return null;
857
- if (typeof rec.state !== "string" || rec.state === "") return null;
858
- const record = {
859
- taskID: rec.taskID,
860
- parentSessionID: typeof rec.parentSessionID === "string" ? rec.parentSessionID : "",
861
- agent: typeof rec.agent === "string" && rec.agent !== "" ? rec.agent : "agent",
862
- state: rec.state,
863
- alias: typeof rec.alias === "string" ? rec.alias : ""
864
- };
865
- if (typeof rec.description === "string") record.description = rec.description;
866
- if (typeof rec.launchedAt === "number" && Number.isFinite(rec.launchedAt)) record.launchedAt = rec.launchedAt;
867
- if (typeof rec.completedAt === "number" && Number.isFinite(rec.completedAt)) record.completedAt = rec.completedAt;
868
- if (typeof rec.updatedAt === "number" && Number.isFinite(rec.updatedAt)) record.updatedAt = rec.updatedAt;
869
- if (typeof rec.timedOut === "boolean") record.timedOut = rec.timedOut;
870
- return record;
871
- }
872
- /** Read `.pantheon/board/state.json` (the cross-session job board snapshot).
873
- * Fail-open: missing file, corrupt JSON, non-array payload or an unreadable
874
- * path all yield [] — the panel keeps rendering from the other channels. */
875
- async function readBoardState(root) {
876
- let raw;
877
- try {
878
- raw = await readFile(boardStatePath(root), "utf8");
879
- } catch {
880
- return [];
881
- }
882
- let parsed;
883
- try {
884
- parsed = JSON.parse(raw);
885
- } catch {
886
- return [];
887
- }
888
- if (!Array.isArray(parsed)) return [];
889
- const records = [];
890
- for (const item of parsed) {
891
- const record = normalizeBoardRecord(item);
892
- if (record !== null) records.push(record);
893
- }
894
- return records;
895
- }
896
844
  /** Resolve the PROJECT ROOT used by every pantheon file channel. `directory`
897
845
  * wins over `worktree` (the old `resolveDelegationsDir` already did this);
898
846
  * an absent/empty root or `/` (no git — e.g. the sandbox test project) falls
899
- * back to cwd. Standardised here so the delegations md, the board state file
900
- * and the panel logger all read the SAME root (audit finding: the channels
847
+ * back to cwd. Standardised here so the delegations md and the panel logger
848
+ * all read the SAME root (audit finding: the channels
901
849
  * resolved the root independently). Pure — no I/O. */
902
850
  function resolvePantheonRoot(state, cwd = process.cwd()) {
903
851
  const root = state?.directory ?? state?.worktree ?? "";
904
852
  if (root === "" || root === "/") return cwd;
905
853
  return root;
906
854
  }
907
- /** Resolve the directory where the job board writes delegation md reports.
908
- * The board writes `.pantheon/delegations` RELATIVE to the server cwd,
855
+ /** Resolve the directory where delegation md reports are written.
856
+ * The finalizer writes `.pantheon/delegations` RELATIVE to the server cwd,
909
857
  * which the TUI exposes as `TuiState.path.directory`. */
910
858
  function resolveDelegationsDir(state, cwd = process.cwd()) {
911
859
  return join(resolvePantheonRoot(state, cwd), ".pantheon", "delegations");
@@ -962,11 +910,11 @@ const STALE_RUNNING_THRESHOLD_MS = 1800 * 1e3;
962
910
  * considered stale. Combined with the stale-running threshold to produce the
963
911
  * display-only `stale-running` state. */
964
912
  const IDLE_SILENCE_MS = 60 * 1e3;
965
- /** Visual-only terminal retention windows. Reports remain on disk and in the
966
- * board; these constants only control which rows enter the TUI window. */
913
+ /** Visual-only terminal retention windows. Reports remain on disk; these
914
+ * constants only control which rows enter the TUI window. */
967
915
  const DELEGATION_DONE_RETENTION_MS = 120 * 1e3;
968
916
  const DELEGATION_FAILED_RETENTION_MS = 600 * 1e3;
969
- /** Alias-less NATIVE task() live entries never receive a board alias (the
917
+ /** Alias-less NATIVE task() live entries never receive a report alias (the
970
918
  * task tool output carries none), so the 30s alias-less prune in
971
919
  * mergeChildDelegationSources must not apply to them — 5 minutes covers a
972
920
  * slow child listing while still bounding the live map. */
@@ -974,7 +922,7 @@ const NATIVE_LIVE_ALIASLESS_TTL_MS = 300 * 1e3;
974
922
  /**
975
923
  * Mark a running entry as `stale-running` if it has been running longer than
976
924
  * the threshold AND has no recent activity (no `updatedAt` change in the last
977
- * `IDLE_SILENCE_MS`). This is DISPLAY-ONLY — the board state is unchanged.
925
+ * `IDLE_SILENCE_MS`). This is DISPLAY-ONLY — the persisted state is unchanged.
978
926
  *
979
927
  * A `stale-running` entry renders with a warning indicator but the underlying
980
928
  * delegation is still treated as running by the backend.
@@ -1047,9 +995,10 @@ function delegationSpinnerFrame(now) {
1047
995
  const index = Math.floor(Math.max(0, now) / 1e3) % DELEGATION_SPINNER_FRAMES.length;
1048
996
  return DELEGATION_SPINNER_FRAMES[index] ?? DELEGATION_SPINNER_FRAMES[0];
1049
997
  }
1050
- /** Every state the row knows how to draw: the real BackgroundJobBoard FSM
1051
- * (src/pantheon/background-job-board.ts) plus the TUI display-only states
1052
- * (`retry`, `stale-running`). Fase 1 deliberately omits speculative
998
+ /** Every state the row knows how to draw: the delegation lifecycle states
999
+ * derived from the children status + md reports (`completed`, `error`,
1000
+ * `cancelled`, `startup_failed`, `startup_unknown`) plus the TUI-only
1001
+ * states (`retry`, `stale-running`). Fase 1 deliberately omits speculative
1053
1002
  * blocked/paused/scheduled/skipped. There is no `pending` display state: a
1054
1003
  * pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
1055
1004
  /** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
@@ -1430,108 +1379,18 @@ function mergeDelegationSources(live, md) {
1430
1379
  all.sort(compareDelegationEntries);
1431
1380
  return all;
1432
1381
  }
1433
- /** Job-board FSM → panel display state. `reconciled` is intentionally absent:
1434
- * the panel parser rejects it (a reconciled job is done and folded away). */
1435
- const BOARD_STATE_TO_DISPLAY = {
1436
- running: "running",
1437
- completed: "completed",
1438
- error: "error",
1439
- startup_failed: "startup_failed",
1440
- startup_unknown: "startup_unknown",
1441
- cancelled: "cancelled"
1442
- };
1443
- /** Map one persisted board record into the display shape. Returns null for
1444
- * states the panel does not render (reconciled / unknown). Pure. */
1445
- function boardRecordToDelegationEntry(record) {
1446
- const state = BOARD_STATE_TO_DISPLAY[record.state];
1447
- if (state === void 0) return null;
1448
- const running = state === "running";
1449
- return {
1450
- alias: record.alias !== "" ? record.alias : `job-${record.taskID.slice(0, 8)}`,
1451
- sessionID: record.parentSessionID,
1452
- taskID: record.taskID,
1453
- agent: record.agent,
1454
- state,
1455
- startedAt: record.launchedAt ?? record.updatedAt ?? 0,
1456
- updatedAt: running ? null : record.completedAt ?? record.updatedAt ?? null,
1457
- timedOut: record.timedOut === true,
1458
- description: record.description ?? "",
1459
- source: "board"
1460
- };
1461
- }
1462
- /** Map a whole board snapshot, dropping unrenderable states. Sorted like every
1463
- * other channel (running first, then most recent). Pure. */
1464
- function boardRecordsToDelegationEntries(records) {
1465
- const out = [];
1466
- for (const record of records) {
1467
- const entry = boardRecordToDelegationEntry(record);
1468
- if (entry !== null) out.push(entry);
1469
- }
1470
- out.sort(compareDelegationEntries);
1471
- return out;
1472
- }
1473
- /** Active (non-terminal) display states — a job in one of these is still live. */
1474
- function isActiveDelegationState(state) {
1475
- return state === "running" || state === "retry" || state === "stale-running";
1476
- }
1477
- /** Temporal guard for the board merge (recycled-alias regression): board
1478
- * aliases recycle across jobs (apo-1 of a previous job), so a board
1479
- * terminal record only closes a running entry when its Finalized timestamp
1480
- * is STRICTLY NEWER than the entry it would close. Older/equal/missing
1481
- * keeps the live entry — when in doubt the live job wins. Pure. */
1482
- function shouldKeepRunningOverBoardTerminal(existing, incoming) {
1483
- if (existing === void 0) return false;
1484
- if (!isActiveDelegationState(existing.state)) return false;
1485
- if (isActiveDelegationState(incoming.state)) return false;
1486
- const incomingTs = incoming.updatedAt;
1487
- if (incomingTs === null) return true;
1488
- return incomingTs <= (existing.updatedAt ?? existing.startedAt);
1489
- }
1490
- /** Merge the board over any other channel. The board is AUTHORITATIVE for
1491
- * state/alias/agent (it is the persisted FSM). This merge is intentionally
1492
- * UNSCOPED so the board can enrich an active-session row (dedup by taskID);
1493
- * the caller scopes the merged list with {@link filterDelegationsToSession},
1494
- * which is what keeps other-session board jobs out of the panel. Dedup by
1495
- * taskID first, then by (sessionID, alias) — aliases are per parent session. Pure. */
1496
- function mergeBoardDelegationSources(base, board) {
1497
- const key = (sessionID, alias) => `${sessionID}\u0000${alias}`;
1498
- const byTaskID = /* @__PURE__ */ new Map();
1499
- const bySessionAlias = /* @__PURE__ */ new Map();
1500
- const out = [...base];
1501
- out.forEach((entry, index) => {
1502
- if (entry.taskID !== void 0) byTaskID.set(entry.taskID, index);
1503
- bySessionAlias.set(key(entry.sessionID, entry.alias), index);
1504
- });
1505
- for (const incoming of board) {
1506
- const index = (incoming.taskID !== void 0 ? byTaskID.get(incoming.taskID) : void 0) ?? bySessionAlias.get(key(incoming.sessionID, incoming.alias));
1507
- if (index === void 0) {
1508
- out.push(incoming);
1509
- const next = out.length - 1;
1510
- if (incoming.taskID !== void 0) byTaskID.set(incoming.taskID, next);
1511
- bySessionAlias.set(key(incoming.sessionID, incoming.alias), next);
1512
- continue;
1513
- }
1514
- if (shouldKeepRunningOverBoardTerminal(out[index], incoming)) continue;
1515
- out[index] = {
1516
- ...incoming,
1517
- sessionID: incoming.sessionID !== "" ? incoming.sessionID : out[index]?.sessionID ?? ""
1518
- };
1519
- }
1520
- out.sort(compareDelegationEntries);
1521
- return out;
1522
- }
1523
1382
  /** Scope a fully-merged display list to the ACTIVE session only.
1524
1383
  *
1525
- * The panel is session-scoped: rows from other sessions (board snapshot, md
1526
- * history under `.pantheon/delegations/<other-session>/`) and rows with no
1384
+ * The panel is session-scoped: rows from other sessions (md history under
1385
+ * `.pantheon/delegations/<other-session>/`) and rows with no
1527
1386
  * attributable session (empty sessionID) are DROPPED. The previous
1528
1387
  * cross-session behavior rendered those rows and clicking them led to
1529
1388
  * "Session not found" — there is no cross-session channel anymore.
1530
1389
  *
1531
- * The board/md channels still feed the merge UNFILTERED so the board can
1532
- * ENRICH an active-session row with state/alias/agent (dedup by taskID), but
1533
- * they can never introduce a row for another session: this filter is applied
1534
- * ONCE, after every merge (children + live + md + board).
1390
+ * The md channel still feeds the merge UNFILTERED so it can ENRICH an
1391
+ * active-session row with state/alias/agent (dedup by taskID), but it can
1392
+ * never introduce a row for another session: this filter is applied
1393
+ * ONCE, after every merge (children + live + md).
1535
1394
  *
1536
1395
  * Returns [] when no active session resolves (null/placeholder) — there is no
1537
1396
  * scope to show. Native children always carry the active session id (stamped
@@ -1569,20 +1428,25 @@ function resolveCurrentSessionID(sources) {
1569
1428
  return null;
1570
1429
  }
1571
1430
  /** THE single choke point for every `session.children` / session-API path.
1572
- * Returns `{ path: { id } }` ONLY for a server-valid session id; returns
1573
- * null for anything else (placeholder, empty, foreign id) so the caller
1574
- * skips the call entirely instead of sending an unsubstituted placeholder
1575
- * (the "%7BsessionID%7D" regression). Every session-API call site MUST go
1576
- * through this function (enforced by the source-scan test in
1577
- * tests/pantheon/tui-delegations.test.ts). */
1431
+ * Returns the v2 SDK parameter shape `{ sessionID }` ONLY for a
1432
+ * server-valid session id; returns null for anything else (placeholder,
1433
+ * empty, foreign id) so the caller skips the call entirely instead of
1434
+ * sending an unsubstituted placeholder (the "%7BsessionID%7D" regression).
1435
+ * The TUI client is `@opencode-ai/sdk/v2`, whose session methods take a
1436
+ * FLAT parameter object (`{ sessionID }`), NOT the v1 `{ path: { id } }`
1437
+ * envelope — passing the v1 shape left the v2 `{sessionID}` URL template
1438
+ * unsubstituted (`/session/%7BsessionID%7D/children`). Every session-API
1439
+ * call site MUST go through this function (enforced by the source-scan
1440
+ * test in tests/pantheon/tui-delegations.test.ts). */
1578
1441
  function safeSessionPath(id) {
1579
1442
  if (!isValidSessionId(id)) return null;
1580
- return { path: { id } };
1443
+ return { sessionID: id };
1581
1444
  }
1582
- /** Build the `session.children` path ONLY from a validated session id.
1445
+ /** Build the `session.children` parameters ONLY from a validated session id.
1583
1446
  * Delegates to {@link safeSessionPath} — the single choke point. Returns
1584
- * null for null/invalid ids so the caller skips the fetch instead of
1585
- * sending an unsubstituted placeholder (the "%7BsessionID%7D" regression). */
1447
+ * the v2 SDK shape `{ sessionID }`; null for null/invalid ids so the caller
1448
+ * skips the fetch instead of sending an unsubstituted placeholder (the
1449
+ * "%7BsessionID%7D" regression). */
1586
1450
  function buildChildrenPath(id) {
1587
1451
  return safeSessionPath(id);
1588
1452
  }
@@ -1600,10 +1464,10 @@ function childStatusToState(status) {
1600
1464
  *
1601
1465
  * A row is
1602
1466
  * `{glyph} {alias:7} {elapsed:>5}` plus a muted description line. The short
1603
- * alias (`apo-1`) is the single identity; rows without a board alias show
1467
+ * alias (`apo-1`) is the single identity; rows without a report alias show
1604
1468
  * the agent instead (never both). */
1605
1469
  /** Map every FSM/display state to one of the 4 row kinds. reconciled never
1606
- * reaches the panel (the board parser drops it) but reads as done;
1470
+ * reaches the panel (the md parser drops it) but reads as done;
1607
1471
  * cancelled reads as done; startup_failed reads as failed while
1608
1472
  * startup_unknown (no error known) reads as retry. Pure. */
1609
1473
  function delegationRowStatus(state) {
@@ -1636,8 +1500,8 @@ function delegationRowMarker(state, now = Date.now()) {
1636
1500
  const status = delegationRowStatus(state);
1637
1501
  return `${status === "active" ? delegationSpinnerFrame(now) : delegationRowGlyph(status)} `;
1638
1502
  }
1639
- /** ONE identity per row: the short board alias (`apo-1`); a row without a
1640
- * board alias (native task() child `native-task` / `native-<id>`, or an
1503
+ /** ONE identity per row: the short report alias (`apo-1`); a row without a
1504
+ * report alias (native task() child `native-task` / `native-<id>`, or an
1641
1505
  * alias-less native live row `live-<callID>` kept as children-only) shows
1642
1506
  * the agent instead — never alias + agent stacked. Pure. */
1643
1507
  function delegationRowIdentity(entry) {
@@ -1736,7 +1600,7 @@ function ceilingDelegationList(all, maxVisible = 8, now = Date.now()) {
1736
1600
  };
1737
1601
  }
1738
1602
  /** Split a display list into native task() rows vs pantheon_delegate rows.
1739
- * Native = source 'children-only' (no board report); everything else counts
1603
+ * Native = source 'children-only' (no delegate report); everything else counts
1740
1604
  * as pantheon. Pure — powers the hooks.log line. */
1741
1605
  function countDelegationSources(entries) {
1742
1606
  let native = 0;
@@ -1748,7 +1612,7 @@ function countDelegationSources(entries) {
1748
1612
  };
1749
1613
  }
1750
1614
  /** Diagnostic hooks.log line for a panel re-fetch, with the children
1751
- * breakdown (pantheon = children WITH a board report, native = children
1615
+ * breakdown (pantheon = children WITH a delegate report, native = children
1752
1616
  * WITHOUT one). Pure — the View logs the returned string verbatim. */
1753
1617
  function formatPanelLogLine(children, pantheon, native, md, events) {
1754
1618
  return `panel: children=${children}(pantheon=${pantheon} native=${native}) md=${md} events=${events}`;
@@ -1763,7 +1627,7 @@ function formatPanelLogLine(children, pantheon, native, md, events) {
1763
1627
  * child of the current session — pantheon_delegate OR the native `task()`
1764
1628
  * tool — carries parentID = caller), so it gets source 'children-only', a
1765
1629
  * per-child alias 'native-<last4 of the child id>' (one identity per native
1766
- * row) instead of a board alias. The 'task nativa' description fallback
1630
+ * row) instead of a report alias. The 'task nativa' description fallback
1767
1631
  * keeps the row non-empty when the child carries no title.
1768
1632
  * A FRESH terminal md state wins over the derived state (a stale md report
1769
1633
  * from a previous incarnation never flips a live child — see
@@ -1776,7 +1640,7 @@ function formatPanelLogLine(children, pantheon, native, md, events) {
1776
1640
  * Sorted running-first (compareDelegationEntries).
1777
1641
  * Pure — no I/O. */
1778
1642
  /** Temporal guard for the children channel (same recycled-alias class as the
1779
- * board merge): an md terminal report matched by taskID may still belong to
1643
+ * md merge): an md terminal report matched by taskID may still belong to
1780
1644
  * a PREVIOUS job incarnation. Accept it only when its Finalized timestamp
1781
1645
  * covers the child's latest activity, when either side has no timestamp to
1782
1646
  * compare, or when both startedAt agree on a single job incarnation.
@@ -2028,24 +1892,19 @@ function View(props) {
2028
1892
  } catch {
2029
1893
  md = [];
2030
1894
  }
2031
- let board = [];
2032
- try {
2033
- board = boardRecordsToDelegationEntries(await readBoardState(projectRoot()));
2034
- } catch {
2035
- board = [];
2036
- }
2037
1895
  const sessionID = resolveCurrentSessionID({
2038
1896
  sessionID: props.sessionID,
2039
1897
  api: props.api
2040
1898
  });
2041
1899
  if (sessionID === null) {
2042
- setChildDelegations(filterDelegationsToSession(mergeBoardDelegationSources(md, board), sessionID));
1900
+ setChildDelegations([]);
2043
1901
  panelLog.info(`${formatPanelLogLine(0, 0, 0, md.length, eventRefreshCount)} (no sessionID — inactive panel)`);
2044
1902
  return;
2045
1903
  }
2046
1904
  let children = [];
2047
1905
  try {
2048
- const result = await props.api.client?.session?.children?.(buildChildrenPath(sessionID));
1906
+ const childrenPath = buildChildrenPath(sessionID);
1907
+ const result = childrenPath ? await props.api.client.session.children(childrenPath) : void 0;
2049
1908
  const data = result?.data ?? result;
2050
1909
  children = Array.isArray(data) ? data : [];
2051
1910
  } catch (err) {
@@ -2055,7 +1914,7 @@ function View(props) {
2055
1914
  const resolveStatus = (childID) => {
2056
1915
  if (!isValidSessionId(childID)) return void 0;
2057
1916
  try {
2058
- return state?.session?.status?.(childID)?.type;
1917
+ return state.session.status(childID)?.type;
2059
1918
  } catch {
2060
1919
  return;
2061
1920
  }
@@ -2066,7 +1925,7 @@ function View(props) {
2066
1925
  })), md, now(), sessionID);
2067
1926
  for (const [k, v] of props.liveStore.map) if (v.alias === null && v.taskID === null && Date.now() - v.startedAt > 3e4) props.liveStore.map.delete(k);
2068
1927
  const liveEntries = [...props.liveStore.map.values()].filter((entry) => entry.sessionID === sessionID);
2069
- setChildDelegations(filterDelegationsToSession(mergeBoardDelegationSources(mergeChildDelegationSources(childEntries, liveEntries), board), sessionID));
1928
+ setChildDelegations(filterDelegationsToSession(mergeChildDelegationSources(childEntries, liveEntries), sessionID));
2070
1929
  const counts = countDelegationSources(childEntries);
2071
1930
  panelLog.info(formatPanelLogLine(children.length, counts.pantheon, counts.native, md.length, eventRefreshCount));
2072
1931
  } finally {
@@ -2378,6 +2237,6 @@ const plugin = {
2378
2237
  setup: async () => {}
2379
2238
  };
2380
2239
  //#endregion
2381
- export { DELEGATION_ALIAS_WIDTH, DELEGATION_DESCRIPTION_MAX, DELEGATION_DONE_RETENTION_MS, DELEGATION_ELAPSED_WIDTH, DELEGATION_FAILED_RETENTION_MS, DELEGATION_ROW_GLYPHS, DELEGATION_VISIBLE_CEILING, IDLE_SILENCE_MS, NATIVE_LIVE_ALIASLESS_TTL_MS, STALE_RUNNING_THRESHOLD_MS, boardRecordToDelegationEntry, boardRecordsToDelegationEntries, boardStatePath, 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, mergeBoardDelegationSources, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readBoardState, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, resolvePantheonRoot, safeSessionPath, seedLiveDelegationMap, splitDelegationList, toDelegationEntry, trackToolActivity, truncateDelegationDescription, tuiLogPath, visibleDelegationList };
2240
+ export { DELEGATION_ALIAS_WIDTH, DELEGATION_DESCRIPTION_MAX, DELEGATION_DONE_RETENTION_MS, DELEGATION_ELAPSED_WIDTH, DELEGATION_FAILED_RETENTION_MS, DELEGATION_ROW_GLYPHS, DELEGATION_VISIBLE_CEILING, IDLE_SILENCE_MS, NATIVE_LIVE_ALIASLESS_TTL_MS, STALE_RUNNING_THRESHOLD_MS, 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 };
2382
2241
 
2383
2242
  //# sourceMappingURL=tui.js.map
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pantheon-tui",
3
- "version": "1.5.0-beta.16",
3
+ "version": "1.5.0-beta.18",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pantheon-tui",
9
- "version": "1.5.0-beta.16",
9
+ "version": "1.5.0-beta.18",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@opencode-ai/plugin": ">=1.14.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pantheon-tui",
3
3
  "type": "module",
4
- "version": "1.5.0-beta.16",
4
+ "version": "1.5.0-beta.18",
5
5
  "description": "Pantheon TUI plugin — sidebar (version, preset, sessions, real-time delegations) + AI subscription usage gauges incl. OpenCode Go/Zen dollar limits (vendored, MIT)",
6
6
  "license": "MIT",
7
7
  "exports": {