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

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.
@@ -10,9 +10,10 @@ import { For, Show, createEffect, createMemo, createResource, createSignal, onCl
10
10
  /**
11
11
  * pantheon-tui — Pantheon TUI plugin for opencode.
12
12
  *
13
- * Single self-contained entry file: `tsdown && cp src/index.tsx dist/tui.tsx`
14
- * keeps the no-build load path working (dist/tui.tsx is raw source, transpiled
15
- * on the fly by opencode). All feature code lives in this one file.
13
+ * Bundled entry: `tsdown` emits `dist/tui.js`, and the package `exports`
14
+ * (`./tui` → ./dist/tui.js, `./server` → ./dist/server.js) is the ONLY load
15
+ * path — no raw TSX copy is shipped. Because the bundle inlines relative
16
+ * imports, this entry may be split into modules without breaking the loader.
16
17
  *
17
18
  * Slots:
18
19
  * - sidebar_content (order 900) — Pantheon sidebar (header/version/
@@ -164,7 +165,7 @@ async function detectVersion(api) {
164
165
  if (ver) return ver;
165
166
  }
166
167
  } catch {}
167
- return "1.5.0-beta.11";
168
+ return "1.5.0-beta.12";
168
169
  }
169
170
  /**
170
171
  * usage-bar — AI subscription usage gauge for the opencode TUI.
@@ -839,17 +840,74 @@ async function readDelegationEntries(dir) {
839
840
  async function readAllDelegationEntries(root) {
840
841
  return readDelegationEntries(join(root, ".pantheon", "delegations"));
841
842
  }
843
+ /** The persisted subset of BackgroundJobRecord the panel consumes. Duck-typed
844
+ * so a corrupt/older record never breaks parsing. */
845
+ /** The FilePersistence state path: `<root>/.pantheon/board/state.json`. */
846
+ function boardStatePath(root) {
847
+ return join(root, ".pantheon", "board", "state.json");
848
+ }
849
+ /** Validate one parsed record, keeping only the fields the panel uses.
850
+ * Returns null for anything without a taskID/state (a corrupt entry is
851
+ * skipped individually — the rest of the snapshot still loads). */
852
+ function normalizeBoardRecord(item) {
853
+ if (typeof item !== "object" || item === null) return null;
854
+ const rec = item;
855
+ if (typeof rec.taskID !== "string" || rec.taskID === "") return null;
856
+ if (typeof rec.state !== "string" || rec.state === "") return null;
857
+ const record = {
858
+ taskID: rec.taskID,
859
+ parentSessionID: typeof rec.parentSessionID === "string" ? rec.parentSessionID : "",
860
+ agent: typeof rec.agent === "string" && rec.agent !== "" ? rec.agent : "agent",
861
+ state: rec.state,
862
+ alias: typeof rec.alias === "string" ? rec.alias : ""
863
+ };
864
+ if (typeof rec.description === "string") record.description = rec.description;
865
+ if (typeof rec.launchedAt === "number" && Number.isFinite(rec.launchedAt)) record.launchedAt = rec.launchedAt;
866
+ if (typeof rec.completedAt === "number" && Number.isFinite(rec.completedAt)) record.completedAt = rec.completedAt;
867
+ if (typeof rec.updatedAt === "number" && Number.isFinite(rec.updatedAt)) record.updatedAt = rec.updatedAt;
868
+ if (typeof rec.timedOut === "boolean") record.timedOut = rec.timedOut;
869
+ return record;
870
+ }
871
+ /** Read `.pantheon/board/state.json` (the cross-session job board snapshot).
872
+ * Fail-open: missing file, corrupt JSON, non-array payload or an unreadable
873
+ * path all yield [] — the panel keeps rendering from the other channels. */
874
+ async function readBoardState(root) {
875
+ let raw;
876
+ try {
877
+ raw = await readFile(boardStatePath(root), "utf8");
878
+ } catch {
879
+ return [];
880
+ }
881
+ let parsed;
882
+ try {
883
+ parsed = JSON.parse(raw);
884
+ } catch {
885
+ return [];
886
+ }
887
+ if (!Array.isArray(parsed)) return [];
888
+ const records = [];
889
+ for (const item of parsed) {
890
+ const record = normalizeBoardRecord(item);
891
+ if (record !== null) records.push(record);
892
+ }
893
+ return records;
894
+ }
895
+ /** Resolve the PROJECT ROOT used by every pantheon file channel. `directory`
896
+ * wins over `worktree` (the old `resolveDelegationsDir` already did this);
897
+ * an absent/empty root or `/` (no git — e.g. the sandbox test project) falls
898
+ * back to cwd. Standardised here so the delegations md, the board state file
899
+ * and the panel logger all read the SAME root (audit finding: the channels
900
+ * resolved the root independently). Pure — no I/O. */
901
+ function resolvePantheonRoot(state, cwd = process.cwd()) {
902
+ const root = state?.directory ?? state?.worktree ?? "";
903
+ if (root === "" || root === "/") return cwd;
904
+ return root;
905
+ }
842
906
  /** Resolve the directory where the job board writes delegation md reports.
843
907
  * The board writes `.pantheon/delegations` RELATIVE to the server cwd,
844
- * which the TUI exposes as `TuiState.path.directory`. `project` does NOT
845
- * exist on `TuiState.path` (the old `state?.project ?? state?.worktree`
846
- * resolution was always undefined for the first term) and `worktree` is
847
- * `/` when there is no git (e.g. the sandbox test project) — a root of
848
- * `''` or `'/'` must fall back to `process.cwd()`. */
908
+ * which the TUI exposes as `TuiState.path.directory`. */
849
909
  function resolveDelegationsDir(state, cwd = process.cwd()) {
850
- const root = state?.directory ?? state?.worktree ?? "";
851
- if (root === "" || root === "/") return join(cwd, ".pantheon", "delegations");
852
- return join(root, ".pantheon", "delegations");
910
+ return join(resolvePantheonRoot(state, cwd), ".pantheon", "delegations");
853
911
  }
854
912
  /** Project root derived from the delegations dir: `<root>/.pantheon/delegations`
855
913
  * → `<root>`. Used to point the panel logger at the REAL hooks.log — passing
@@ -1379,6 +1437,106 @@ function mergeDelegationSources(live, md) {
1379
1437
  all.sort(compareDelegationEntries);
1380
1438
  return all;
1381
1439
  }
1440
+ /** Job-board FSM → panel display state. `reconciled` is intentionally absent:
1441
+ * the panel parser rejects it (a reconciled job is done and folded away). */
1442
+ const BOARD_STATE_TO_DISPLAY = {
1443
+ running: "running",
1444
+ completed: "completed",
1445
+ error: "error",
1446
+ startup_failed: "startup_failed",
1447
+ startup_unknown: "startup_unknown",
1448
+ cancelled: "cancelled"
1449
+ };
1450
+ /** Map one persisted board record into the display shape. Returns null for
1451
+ * states the panel does not render (reconciled / unknown). Pure. */
1452
+ function boardRecordToDelegationEntry(record) {
1453
+ const state = BOARD_STATE_TO_DISPLAY[record.state];
1454
+ if (state === void 0) return null;
1455
+ const running = state === "running";
1456
+ return {
1457
+ alias: record.alias !== "" ? record.alias : `job-${record.taskID.slice(0, 8)}`,
1458
+ sessionID: record.parentSessionID,
1459
+ taskID: record.taskID,
1460
+ agent: record.agent,
1461
+ state,
1462
+ startedAt: record.launchedAt ?? record.updatedAt ?? 0,
1463
+ updatedAt: running ? null : record.completedAt ?? record.updatedAt ?? null,
1464
+ timedOut: record.timedOut === true,
1465
+ description: record.description ?? "",
1466
+ source: "board"
1467
+ };
1468
+ }
1469
+ /** Map a whole board snapshot, dropping unrenderable states. Sorted like every
1470
+ * other channel (running first, then most recent). Pure. */
1471
+ function boardRecordsToDelegationEntries(records) {
1472
+ const out = [];
1473
+ for (const record of records) {
1474
+ const entry = boardRecordToDelegationEntry(record);
1475
+ if (entry !== null) out.push(entry);
1476
+ }
1477
+ out.sort(compareDelegationEntries);
1478
+ return out;
1479
+ }
1480
+ /** Merge the board over any other channel. The board is AUTHORITATIVE for
1481
+ * state/alias/agent (it is the persisted FSM) and it is the only channel
1482
+ * that carries jobs from OTHER sessions. Dedup by taskID first, then by
1483
+ * (sessionID, alias) — aliases are per parent session. Pure. */
1484
+ function mergeBoardDelegationSources(base, board) {
1485
+ const key = (sessionID, alias) => `${sessionID}\u0000${alias}`;
1486
+ const byTaskID = /* @__PURE__ */ new Map();
1487
+ const bySessionAlias = /* @__PURE__ */ new Map();
1488
+ const out = [...base];
1489
+ out.forEach((entry, index) => {
1490
+ if (entry.taskID !== void 0) byTaskID.set(entry.taskID, index);
1491
+ bySessionAlias.set(key(entry.sessionID, entry.alias), index);
1492
+ });
1493
+ for (const incoming of board) {
1494
+ const index = (incoming.taskID !== void 0 ? byTaskID.get(incoming.taskID) : void 0) ?? bySessionAlias.get(key(incoming.sessionID, incoming.alias));
1495
+ if (index === void 0) {
1496
+ out.push(incoming);
1497
+ const next = out.length - 1;
1498
+ if (incoming.taskID !== void 0) byTaskID.set(incoming.taskID, next);
1499
+ bySessionAlias.set(key(incoming.sessionID, incoming.alias), next);
1500
+ continue;
1501
+ }
1502
+ out[index] = incoming;
1503
+ }
1504
+ out.sort(compareDelegationEntries);
1505
+ return out;
1506
+ }
1507
+ /** 'session' = focused session only (default); 'all' = every session the
1508
+ * board knows about. */
1509
+ /** api.kv key holding the persisted scope (defaults to 'session'). */
1510
+ const DELEGATION_SCOPE_KV_KEY = "delegations.scope";
1511
+ /** Structural subset of TuiKV — kept local so the pure helpers are testable
1512
+ * without the TUI runtime. */
1513
+ /** Read the persisted scope; anything malformed/absent → 'session'. */
1514
+ function readDelegationScope(kv) {
1515
+ try {
1516
+ return kv?.get?.("delegations.scope", "session") === "all" ? "all" : "session";
1517
+ } catch {
1518
+ return "session";
1519
+ }
1520
+ }
1521
+ /** Persist the scope. Failure is non-fatal — the signal keeps it in memory. */
1522
+ function writeDelegationScope(kv, scope) {
1523
+ try {
1524
+ kv?.set?.(DELEGATION_SCOPE_KV_KEY, scope);
1525
+ } catch {}
1526
+ }
1527
+ /** Keyboard/click toggle target. Pure. */
1528
+ function nextDelegationScope(scope) {
1529
+ return scope === "session" ? "all" : "session";
1530
+ }
1531
+ /** Keep only the focused session's jobs ('session') or all of them ('all').
1532
+ * An empty sessionID marks a current-session child (the children channel is
1533
+ * session-scoped and only fills sessionID from a matching md report), so it
1534
+ * counts as the current session. With no resolved session there is nothing
1535
+ * to scope against — fail-open to the full list. Pure. */
1536
+ function filterDelegationsByScope(entries, scope, sessionID) {
1537
+ if (scope === "all" || sessionID === null) return [...entries];
1538
+ return entries.filter((entry) => entry.sessionID === sessionID || entry.sessionID === "");
1539
+ }
1382
1540
  /** Server-aligned session id validity: opencode rejects anything not starting
1383
1541
  * with "ses" (SchemaError). This deliberately mirrors that exact contract —
1384
1542
  * nothing stricter, nothing looser — so a template placeholder ("{sessionID}"),
@@ -1761,8 +1919,13 @@ function View(props) {
1761
1919
  return (b.time?.updated ?? b.updated ?? 0) - ta;
1762
1920
  }).slice(0, 8);
1763
1921
  });
1764
- const delegationsDir = createMemo(() => resolveDelegationsDir(props.api.state.path));
1765
- const panelLog = createTuiLogger(panelLogDir(delegationsDir()));
1922
+ const projectRoot = createMemo(() => resolvePantheonRoot(props.api.state.path));
1923
+ const panelLog = createTuiLogger(projectRoot());
1924
+ const [delegationScope, setDelegationScope] = createSignal(readDelegationScope(props.api.kv));
1925
+ const applyDelegationScope = (scope) => {
1926
+ setDelegationScope(scope);
1927
+ writeDelegationScope(props.api.kv, scope);
1928
+ };
1766
1929
  const [childDelegations, setChildDelegations] = createSignal([]);
1767
1930
  const [now, setNow] = createSignal(Date.now());
1768
1931
  const [animationNow, setAnimationNow] = createSignal(Date.now());
@@ -1775,17 +1938,23 @@ function View(props) {
1775
1938
  const state = props.api.state;
1776
1939
  let md = [];
1777
1940
  try {
1778
- md = await readAllDelegationEntries(panelLogDir(delegationsDir()));
1941
+ md = await readAllDelegationEntries(projectRoot());
1779
1942
  } catch {
1780
1943
  md = [];
1781
1944
  }
1945
+ let board = [];
1946
+ try {
1947
+ board = boardRecordsToDelegationEntries(await readBoardState(projectRoot()));
1948
+ } catch {
1949
+ board = [];
1950
+ }
1782
1951
  const sessionID = resolveCurrentSessionID({
1783
1952
  sessionID: props.sessionID,
1784
1953
  api: props.api
1785
1954
  });
1786
1955
  if (sessionID === null) {
1787
- setChildDelegations(md);
1788
- panelLog.info(`${formatPanelLogLine(0, 0, 0, md.length, eventRefreshCount)} (no sessionID — history shown)`);
1956
+ setChildDelegations(mergeBoardDelegationSources(md, board));
1957
+ panelLog.info(`${formatPanelLogLine(0, 0, 0, md.length, eventRefreshCount)} (no sessionID — history+board shown)`);
1789
1958
  return;
1790
1959
  }
1791
1960
  let children = [];
@@ -1809,9 +1978,10 @@ function View(props) {
1809
1978
  ...c,
1810
1979
  status: resolveStatus(c.id)
1811
1980
  })), md, now());
1981
+ for (const entry of childEntries) if (entry.sessionID === "") entry.sessionID = sessionID;
1812
1982
  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);
1813
1983
  const liveEntries = [...props.liveStore.map.values()].filter((entry) => entry.sessionID === sessionID);
1814
- setChildDelegations(mergeChildDelegationSources(childEntries, liveEntries));
1984
+ setChildDelegations(mergeBoardDelegationSources(mergeChildDelegationSources(childEntries, liveEntries), board));
1815
1985
  const counts = countDelegationSources(childEntries);
1816
1986
  panelLog.info(formatPanelLogLine(children.length, counts.pantheon, counts.native, md.length, eventRefreshCount));
1817
1987
  } finally {
@@ -1820,9 +1990,13 @@ function View(props) {
1820
1990
  })();
1821
1991
  return delegationsInflight;
1822
1992
  };
1823
- const delegationSplit = createMemo(() => splitDelegationList(childDelegations()));
1993
+ const scopedDelegations = createMemo(() => filterDelegationsByScope(childDelegations(), delegationScope(), resolveCurrentSessionID({
1994
+ sessionID: props.sessionID,
1995
+ api: props.api
1996
+ })));
1997
+ const delegationSplit = createMemo(() => splitDelegationList(scopedDelegations()));
1824
1998
  const visibleDelegations = createMemo(() => [...delegationSplit().active, ...delegationSplit().recent]);
1825
- const delegationHeader = createMemo(() => formatDelegationHeader(childDelegations()));
1999
+ const delegationHeader = createMemo(() => formatDelegationHeader(scopedDelegations()));
1826
2000
  const [archivedPage, setArchivedPage] = createSignal(archivedUiState.page);
1827
2001
  const clampArchivedPage = (page, pages) => {
1828
2002
  const clamped = Math.max(0, Math.min(page, Math.max(0, pages - 1)));
@@ -1872,6 +2046,23 @@ function View(props) {
1872
2046
  if (parts.length > 0 && seedLiveDelegationMap(props.liveStore.map, parts) > 0) props.liveStore.bump();
1873
2047
  }
1874
2048
  } catch {}
2049
+ try {
2050
+ const keymap = props.api?.keymap;
2051
+ if (typeof keymap?.registerLayer === "function") {
2052
+ const off = keymap.registerLayer({
2053
+ priority: 1e3,
2054
+ commands: [{
2055
+ name: "pantheon.delegations.toggleScope",
2056
+ run: () => applyDelegationScope(nextDelegationScope(delegationScope()))
2057
+ }],
2058
+ bindings: [{
2059
+ key: "ctrl+shift+d",
2060
+ cmd: "pantheon.delegations.toggleScope"
2061
+ }]
2062
+ });
2063
+ if (typeof off === "function") cleanup.push(off);
2064
+ }
2065
+ } catch {}
1875
2066
  onCleanup(() => cleanup.forEach((fn) => {
1876
2067
  fn();
1877
2068
  }));
@@ -1883,7 +2074,7 @@ function View(props) {
1883
2074
  return _el$20;
1884
2075
  })();
1885
2076
  return (() => {
1886
- var _el$22 = createElement("box"), _el$23 = createElement("text"), _el$24 = createElement("box"), _el$25 = createElement("text"), _el$26 = createElement("text"), _el$28 = createElement("box"), _el$29 = createElement("text"), _el$30 = createElement("text");
2077
+ var _el$22 = createElement("box"), _el$23 = createElement("text"), _el$24 = createElement("box"), _el$25 = createElement("text"), _el$26 = createElement("text"), _el$28 = createElement("box"), _el$29 = createElement("text"), _el$30 = createElement("text"), _el$31 = createElement("text"), _el$33 = createElement("text"), _el$35 = createElement("text"), _el$37 = createElement("text");
1887
2078
  insertNode(_el$22, _el$23);
1888
2079
  insertNode(_el$22, _el$24);
1889
2080
  insertNode(_el$22, _el$28);
@@ -1896,10 +2087,10 @@ function View(props) {
1896
2087
  return branch();
1897
2088
  },
1898
2089
  children: (b) => (() => {
1899
- var _el$32 = createElement("text");
1900
- insert(_el$32, b);
1901
- effect((_$p) => setProp(_el$32, "fg", theme().textMuted, _$p));
1902
- return _el$32;
2090
+ var _el$40 = createElement("text");
2091
+ insert(_el$40, b);
2092
+ effect((_$p) => setProp(_el$40, "fg", theme().textMuted, _$p));
2093
+ return _el$40;
1903
2094
  })()
1904
2095
  }), _el$24);
1905
2096
  insert(_el$22, createComponent(Show, {
@@ -1908,37 +2099,37 @@ function View(props) {
1908
2099
  },
1909
2100
  get fallback() {
1910
2101
  return (() => {
1911
- var _el$33 = createElement("box"), _el$34 = createElement("text");
1912
- insertNode(_el$33, _el$34);
1913
- setProp(_el$33, "flexDirection", "row");
1914
- setProp(_el$33, "gap", 1);
1915
- insertNode(_el$34, createTextNode(`Preset: default`));
1916
- effect((_$p) => setProp(_el$34, "fg", theme().textMuted, _$p));
1917
- return _el$33;
2102
+ var _el$41 = createElement("box"), _el$42 = createElement("text");
2103
+ insertNode(_el$41, _el$42);
2104
+ setProp(_el$41, "flexDirection", "row");
2105
+ setProp(_el$41, "gap", 1);
2106
+ insertNode(_el$42, createTextNode(`Preset: default`));
2107
+ effect((_$p) => setProp(_el$42, "fg", theme().textMuted, _$p));
2108
+ return _el$41;
1918
2109
  })();
1919
2110
  },
1920
2111
  children: (name) => (() => {
1921
- var _el$36 = createElement("box"), _el$37 = createElement("text"), _el$39 = createElement("text"), _el$40 = createElement("text");
1922
- insertNode(_el$36, _el$37);
1923
- insertNode(_el$36, _el$39);
1924
- insertNode(_el$36, _el$40);
1925
- setProp(_el$36, "flexDirection", "row");
1926
- setProp(_el$36, "gap", 1);
1927
- insertNode(_el$37, createTextNode(`⚡ Preset:`));
1928
- insert(_el$39, name);
1929
- insert(_el$40, () => `(${preset().source ?? ""})`);
2112
+ var _el$44 = createElement("box"), _el$45 = createElement("text"), _el$47 = createElement("text"), _el$48 = createElement("text");
2113
+ insertNode(_el$44, _el$45);
2114
+ insertNode(_el$44, _el$47);
2115
+ insertNode(_el$44, _el$48);
2116
+ setProp(_el$44, "flexDirection", "row");
2117
+ setProp(_el$44, "gap", 1);
2118
+ insertNode(_el$45, createTextNode(`⚡ Preset:`));
2119
+ insert(_el$47, name);
2120
+ insert(_el$48, () => `(${preset().source ?? ""})`);
1930
2121
  effect((_p$) => {
1931
- var _v$11 = theme().textMuted, _v$12 = theme().accent, _v$13 = theme().textMuted;
1932
- _v$11 !== _p$.e && (_p$.e = setProp(_el$37, "fg", _v$11, _p$.e));
1933
- _v$12 !== _p$.t && (_p$.t = setProp(_el$39, "fg", _v$12, _p$.t));
1934
- _v$13 !== _p$.a && (_p$.a = setProp(_el$40, "fg", _v$13, _p$.a));
2122
+ var _v$17 = theme().textMuted, _v$18 = theme().accent, _v$19 = theme().textMuted;
2123
+ _v$17 !== _p$.e && (_p$.e = setProp(_el$45, "fg", _v$17, _p$.e));
2124
+ _v$18 !== _p$.t && (_p$.t = setProp(_el$47, "fg", _v$18, _p$.t));
2125
+ _v$19 !== _p$.a && (_p$.a = setProp(_el$48, "fg", _v$19, _p$.a));
1935
2126
  return _p$;
1936
2127
  }, {
1937
2128
  e: void 0,
1938
2129
  t: void 0,
1939
2130
  a: void 0
1940
2131
  });
1941
- return _el$36;
2132
+ return _el$44;
1942
2133
  })()
1943
2134
  }), _el$24);
1944
2135
  insert(_el$22, createComponent(HR, {}), _el$24);
@@ -1959,12 +2150,12 @@ function View(props) {
1959
2150
  },
1960
2151
  get fallback() {
1961
2152
  return (() => {
1962
- var _el$41 = createElement("box"), _el$42 = createElement("text");
1963
- insertNode(_el$41, _el$42);
1964
- setProp(_el$41, "marginLeft", 1);
1965
- insertNode(_el$42, createTextNode(`No recent sessions`));
1966
- effect((_$p) => setProp(_el$42, "fg", theme().textMuted, _$p));
1967
- return _el$41;
2153
+ var _el$49 = createElement("box"), _el$50 = createElement("text");
2154
+ insertNode(_el$49, _el$50);
2155
+ setProp(_el$49, "marginLeft", 1);
2156
+ insertNode(_el$50, createTextNode(`No recent sessions`));
2157
+ effect((_$p) => setProp(_el$50, "fg", theme().textMuted, _$p));
2158
+ return _el$49;
1968
2159
  })();
1969
2160
  },
1970
2161
  get children() {
@@ -1989,10 +2180,26 @@ function View(props) {
1989
2180
  }), _el$28);
1990
2181
  insertNode(_el$28, _el$29);
1991
2182
  insertNode(_el$28, _el$30);
2183
+ insertNode(_el$28, _el$31);
2184
+ insertNode(_el$28, _el$33);
2185
+ insertNode(_el$28, _el$35);
2186
+ insertNode(_el$28, _el$37);
1992
2187
  setProp(_el$28, "onMouseDown", () => setShowDelegations((x) => !x));
1993
2188
  setProp(_el$29, "attributes", 1);
1994
2189
  insert(_el$29, () => `${showDelegations() ? "▼" : "▶"} Delegations`);
1995
2190
  insert(_el$30, () => ` ${delegationHeader()}`);
2191
+ insertNode(_el$31, createTextNode(` `));
2192
+ insertNode(_el$33, createTextNode(`[Sessão]`));
2193
+ setProp(_el$33, "onMouseDown", (e) => {
2194
+ if (typeof e === "object" && e !== null && "stopPropagation" in e) e.stopPropagation();
2195
+ applyDelegationScope("session");
2196
+ });
2197
+ insertNode(_el$35, createTextNode(`/`));
2198
+ insertNode(_el$37, createTextNode(`[Tudo]`));
2199
+ setProp(_el$37, "onMouseDown", (e) => {
2200
+ if (typeof e === "object" && e !== null && "stopPropagation" in e) e.stopPropagation();
2201
+ applyDelegationScope("all");
2202
+ });
1996
2203
  insert(_el$22, createComponent(Show, {
1997
2204
  get when() {
1998
2205
  return showDelegations();
@@ -2004,19 +2211,19 @@ function View(props) {
2004
2211
  },
2005
2212
  get fallback() {
2006
2213
  return (() => {
2007
- var _el$44 = createElement("box"), _el$45 = createElement("text");
2008
- insertNode(_el$44, _el$45);
2009
- setProp(_el$44, "marginLeft", 1);
2010
- insertNode(_el$45, createTextNode(`No delegations`));
2011
- effect((_$p) => setProp(_el$45, "fg", theme().textMuted, _$p));
2012
- return _el$44;
2214
+ var _el$52 = createElement("box"), _el$53 = createElement("text");
2215
+ insertNode(_el$52, _el$53);
2216
+ setProp(_el$52, "marginLeft", 1);
2217
+ insertNode(_el$53, createTextNode(`No delegations`));
2218
+ effect((_$p) => setProp(_el$53, "fg", theme().textMuted, _$p));
2219
+ return _el$52;
2013
2220
  })();
2014
2221
  },
2015
2222
  get children() {
2016
- var _el$31 = createElement("box");
2017
- setProp(_el$31, "marginLeft", 1);
2018
- setProp(_el$31, "flexDirection", "column");
2019
- insert(_el$31, createComponent(For, {
2223
+ var _el$39 = createElement("box");
2224
+ setProp(_el$39, "marginLeft", 1);
2225
+ setProp(_el$39, "flexDirection", "column");
2226
+ insert(_el$39, createComponent(For, {
2020
2227
  get each() {
2021
2228
  return visibleDelegations();
2022
2229
  },
@@ -2033,7 +2240,7 @@ function View(props) {
2033
2240
  }
2034
2241
  })
2035
2242
  }), null);
2036
- insert(_el$31, createComponent(Show, {
2243
+ insert(_el$39, createComponent(Show, {
2037
2244
  get when() {
2038
2245
  return delegationSplit().archived.length > 0;
2039
2246
  },
@@ -2045,22 +2252,22 @@ function View(props) {
2045
2252
  const page = Math.min(archivedPage(), pages - 1);
2046
2253
  const slice = archived.slice(page * pageSize, page * pageSize + pageSize);
2047
2254
  return (() => {
2048
- var _el$47 = createElement("box"), _el$48 = createElement("box"), _el$49 = createElement("text"), _el$51 = createElement("text"), _el$52 = createElement("text"), _el$53 = createElement("text");
2049
- insertNode(_el$47, _el$48);
2050
- setProp(_el$47, "flexDirection", "column");
2051
- insertNode(_el$48, _el$49);
2052
- insertNode(_el$48, _el$51);
2053
- insertNode(_el$48, _el$52);
2054
- insertNode(_el$48, _el$53);
2055
- setProp(_el$48, "flexDirection", "row");
2056
- setProp(_el$48, "marginLeft", 0);
2057
- insertNode(_el$49, createTextNode(`‹ `));
2058
- setProp(_el$49, "onMouseDown", () => clampArchivedPage(page - 1, pages));
2059
- insert(_el$51, () => `Archived (${archived.length}) `);
2060
- insert(_el$52, `${page + 1}/${pages}`);
2061
- insertNode(_el$53, createTextNode(` ›`));
2062
- setProp(_el$53, "onMouseDown", () => clampArchivedPage(page + 1, pages));
2063
- insert(_el$47, createComponent(For, {
2255
+ var _el$55 = createElement("box"), _el$56 = createElement("box"), _el$57 = createElement("text"), _el$59 = createElement("text"), _el$60 = createElement("text"), _el$61 = createElement("text");
2256
+ insertNode(_el$55, _el$56);
2257
+ setProp(_el$55, "flexDirection", "column");
2258
+ insertNode(_el$56, _el$57);
2259
+ insertNode(_el$56, _el$59);
2260
+ insertNode(_el$56, _el$60);
2261
+ insertNode(_el$56, _el$61);
2262
+ setProp(_el$56, "flexDirection", "row");
2263
+ setProp(_el$56, "marginLeft", 0);
2264
+ insertNode(_el$57, createTextNode(`‹ `));
2265
+ setProp(_el$57, "onMouseDown", () => clampArchivedPage(page - 1, pages));
2266
+ insert(_el$59, () => `Archived (${archived.length}) `);
2267
+ insert(_el$60, `${page + 1}/${pages}`);
2268
+ insertNode(_el$61, createTextNode(` ›`));
2269
+ setProp(_el$61, "onMouseDown", () => clampArchivedPage(page + 1, pages));
2270
+ insert(_el$55, createComponent(For, {
2064
2271
  each: slice,
2065
2272
  children: (job) => createComponent(DelegationRow, {
2066
2273
  get api() {
@@ -2076,11 +2283,11 @@ function View(props) {
2076
2283
  })
2077
2284
  }), null);
2078
2285
  effect((_p$) => {
2079
- var _v$14 = theme().textMuted, _v$15 = theme().textMuted, _v$16 = theme().textMuted, _v$17 = theme().textMuted;
2080
- _v$14 !== _p$.e && (_p$.e = setProp(_el$49, "fg", _v$14, _p$.e));
2081
- _v$15 !== _p$.t && (_p$.t = setProp(_el$51, "fg", _v$15, _p$.t));
2082
- _v$16 !== _p$.a && (_p$.a = setProp(_el$52, "fg", _v$16, _p$.a));
2083
- _v$17 !== _p$.o && (_p$.o = setProp(_el$53, "fg", _v$17, _p$.o));
2286
+ var _v$20 = theme().textMuted, _v$21 = theme().textMuted, _v$22 = theme().textMuted, _v$23 = theme().textMuted;
2287
+ _v$20 !== _p$.e && (_p$.e = setProp(_el$57, "fg", _v$20, _p$.e));
2288
+ _v$21 !== _p$.t && (_p$.t = setProp(_el$59, "fg", _v$21, _p$.t));
2289
+ _v$22 !== _p$.a && (_p$.a = setProp(_el$60, "fg", _v$22, _p$.a));
2290
+ _v$23 !== _p$.o && (_p$.o = setProp(_el$61, "fg", _v$23, _p$.o));
2084
2291
  return _p$;
2085
2292
  }, {
2086
2293
  e: void 0,
@@ -2088,30 +2295,42 @@ function View(props) {
2088
2295
  a: void 0,
2089
2296
  o: void 0
2090
2297
  });
2091
- return _el$47;
2298
+ return _el$55;
2092
2299
  })();
2093
2300
  })();
2094
2301
  }
2095
2302
  }), null);
2096
- return _el$31;
2303
+ return _el$39;
2097
2304
  }
2098
2305
  });
2099
2306
  }
2100
2307
  }), null);
2101
2308
  effect((_p$) => {
2102
- var _v$8 = theme().accent, _v$9 = theme().text, _v$0 = theme().textMuted, _v$1 = theme().text, _v$10 = theme().textMuted;
2309
+ var _v$8 = theme().accent, _v$9 = theme().text, _v$0 = theme().textMuted, _v$1 = theme().text, _v$10 = theme().textMuted, _v$11 = theme().textMuted, _v$12 = delegationScope() === "session" ? theme().accent : theme().textMuted, _v$13 = delegationScope() === "session" ? 1 : void 0, _v$14 = theme().textMuted, _v$15 = delegationScope() === "all" ? theme().accent : theme().textMuted, _v$16 = delegationScope() === "all" ? 1 : void 0;
2103
2310
  _v$8 !== _p$.e && (_p$.e = setProp(_el$23, "fg", _v$8, _p$.e));
2104
2311
  _v$9 !== _p$.t && (_p$.t = setProp(_el$25, "fg", _v$9, _p$.t));
2105
2312
  _v$0 !== _p$.a && (_p$.a = setProp(_el$26, "fg", _v$0, _p$.a));
2106
2313
  _v$1 !== _p$.o && (_p$.o = setProp(_el$29, "fg", _v$1, _p$.o));
2107
2314
  _v$10 !== _p$.i && (_p$.i = setProp(_el$30, "fg", _v$10, _p$.i));
2315
+ _v$11 !== _p$.n && (_p$.n = setProp(_el$31, "fg", _v$11, _p$.n));
2316
+ _v$12 !== _p$.s && (_p$.s = setProp(_el$33, "fg", _v$12, _p$.s));
2317
+ _v$13 !== _p$.h && (_p$.h = setProp(_el$33, "attributes", _v$13, _p$.h));
2318
+ _v$14 !== _p$.r && (_p$.r = setProp(_el$35, "fg", _v$14, _p$.r));
2319
+ _v$15 !== _p$.d && (_p$.d = setProp(_el$37, "fg", _v$15, _p$.d));
2320
+ _v$16 !== _p$.l && (_p$.l = setProp(_el$37, "attributes", _v$16, _p$.l));
2108
2321
  return _p$;
2109
2322
  }, {
2110
2323
  e: void 0,
2111
2324
  t: void 0,
2112
2325
  a: void 0,
2113
2326
  o: void 0,
2114
- i: void 0
2327
+ i: void 0,
2328
+ n: void 0,
2329
+ s: void 0,
2330
+ h: void 0,
2331
+ r: void 0,
2332
+ d: void 0,
2333
+ l: void 0
2115
2334
  });
2116
2335
  return _el$22;
2117
2336
  })();
@@ -2173,6 +2392,6 @@ const plugin = {
2173
2392
  setup: async () => {}
2174
2393
  };
2175
2394
  //#endregion
2176
- export { DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DELEGATION_STATE_GLYPHS, IDLE_SILENCE_MS, STALE_RUNNING_THRESHOLD_MS, 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 };
2395
+ export { DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DELEGATION_SCOPE_KV_KEY, DELEGATION_STATE_GLYPHS, IDLE_SILENCE_MS, STALE_RUNNING_THRESHOLD_MS, boardRecordToDelegationEntry, boardRecordsToDelegationEntries, boardStatePath, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, countDelegationSources, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationIcon, delegationSpinnerFrame, delegationStateGlyph, delegationStateMarker, delegationStateTone, delegationTag, extractToolActivity, filterDelegationsByScope, fmtElapsed, formatDelegationElapsed, formatDelegationHeader, formatDelegationIdentity, formatDelegationRow, formatPanelLogLine, isValidSessionId, latestToolActivityFor, markStaleIfRunning, mergeBoardDelegationSources, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, nextDelegationScope, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readBoardState, readDelegationEntries, readDelegationScope, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, resolvePantheonRoot, safeSessionPath, seedLiveDelegationMap, splitDelegationList, toDelegationEntry, trackToolActivity, truncateDelegationDescription, tuiLogPath, visibleDelegationList, writeDelegationScope };
2177
2396
 
2178
2397
  //# sourceMappingURL=tui.js.map
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pantheon-tui",
3
- "version": "1.5.0-beta.11",
3
+ "version": "1.5.0-beta.12",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pantheon-tui",
9
- "version": "1.5.0-beta.11",
9
+ "version": "1.5.0-beta.12",
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.11",
4
+ "version": "1.5.0-beta.12",
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": {
@@ -13,7 +13,7 @@
13
13
  "src"
14
14
  ],
15
15
  "scripts": {
16
- "build": "tsdown && cp src/index.tsx dist/tui.tsx",
16
+ "build": "tsdown",
17
17
  "typecheck": "tsc --noEmit"
18
18
  },
19
19
  "peerDependencies": {