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 +47 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/dev-tui.sh +1 -1
- package/scripts/install/plugin.mjs +9 -12
- package/scripts/sync-tui.mjs +8 -11
- package/src/pantheon/session-guard.ts +2 -2
- package/src/plugins/tui/dist/tui.d.ts +111 -59
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +353 -239
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +2 -2
- package/src/plugins/tui/src/index.tsx +415 -201
- package/src/plugins/tui/dist/tui.tsx +0 -3008
|
@@ -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
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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.
|
|
168
|
+
return "1.5.0-beta.13";
|
|
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`.
|
|
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
|
-
|
|
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
|
|
@@ -875,22 +933,19 @@ function compareDelegationEntries(a, b) {
|
|
|
875
933
|
return (b.updatedAt ?? b.startedAt) - (a.updatedAt ?? a.startedAt);
|
|
876
934
|
}
|
|
877
935
|
/** Split the panel list: active jobs (running/retry, stale-marked) first,
|
|
878
|
-
* then the most recent terminal reports
|
|
879
|
-
*
|
|
936
|
+
* then the most recent terminal reports; the remaining tail is collapsed
|
|
937
|
+
* by the View into a single "… +N more" line. Pure — so the history-only panel (no sessionID) is testable
|
|
880
938
|
* without the TUI runtime. */
|
|
881
939
|
function splitDelegationList(all, maxRecent = 8, now = Date.now(), staleThresholdMs = 1800 * 1e3) {
|
|
882
940
|
const isActiveState = (st) => st === "running" || st === "retry" || st === "stale-running";
|
|
883
|
-
const active = all.filter((d) => isActiveState(d.state)).map((d) => markStaleIfRunning(d, now, staleThresholdMs));
|
|
884
|
-
const terminal = all.filter((d) => !isActiveState(d.state));
|
|
885
941
|
return {
|
|
886
|
-
active,
|
|
887
|
-
recent:
|
|
888
|
-
archived: terminal.slice(maxRecent)
|
|
942
|
+
active: all.filter((d) => isActiveState(d.state)).map((d) => markStaleIfRunning(d, now, staleThresholdMs)),
|
|
943
|
+
recent: all.filter((d) => !isActiveState(d.state)).slice(0, maxRecent)
|
|
889
944
|
};
|
|
890
945
|
}
|
|
891
|
-
/**
|
|
892
|
-
* existing tests): active jobs first, then the most
|
|
893
|
-
* reports (capped)
|
|
946
|
+
/** Live-first window used by {@link ceilingDelegationList} (kept for the
|
|
947
|
+
* ceiling helper and existing tests): active jobs first, then the most
|
|
948
|
+
* recent terminal reports (capped). Pure. */
|
|
894
949
|
function visibleDelegationList(all, maxTerminal = 8, now = Date.now(), staleThresholdMs = 1800 * 1e3) {
|
|
895
950
|
const { active, recent } = splitDelegationList(all, maxTerminal, now, staleThresholdMs);
|
|
896
951
|
return [...active, ...recent];
|
|
@@ -918,7 +973,7 @@ function markStaleIfRunning(entry, now, thresholdMs = STALE_RUNNING_THRESHOLD_MS
|
|
|
918
973
|
state: "stale-running"
|
|
919
974
|
};
|
|
920
975
|
}
|
|
921
|
-
/** Compact elapsed-time label: "
|
|
976
|
+
/** Compact elapsed-time label, single unit only: "12s"/"3m"/"1h"/"2d" — ticks every
|
|
922
977
|
* second for running jobs. */
|
|
923
978
|
function fmtElapsed(ms) {
|
|
924
979
|
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
@@ -926,9 +981,9 @@ function fmtElapsed(ms) {
|
|
|
926
981
|
const hours = Math.floor(total % 86400 / 3600);
|
|
927
982
|
const minutes = Math.floor(total % 3600 / 60);
|
|
928
983
|
const seconds = total % 60;
|
|
929
|
-
if (days > 0) return `${days}d
|
|
930
|
-
if (hours > 0) return `${hours}h
|
|
931
|
-
if (minutes > 0) return `${minutes}m
|
|
984
|
+
if (days > 0) return `${days}d`;
|
|
985
|
+
if (hours > 0) return `${hours}h`;
|
|
986
|
+
if (minutes > 0) return `${minutes}m`;
|
|
932
987
|
return `${seconds}s`;
|
|
933
988
|
}
|
|
934
989
|
/** Elapsed label for one entry: an ACTIVE entry (running/retry/stale-running)
|
|
@@ -982,32 +1037,12 @@ function delegationSpinnerFrame(now) {
|
|
|
982
1037
|
* (`retry`, `stale-running`). Fase 1 deliberately omits speculative
|
|
983
1038
|
* blocked/paused/scheduled/skipped. There is no `pending` display state: a
|
|
984
1039
|
* pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
|
|
985
|
-
/** Static glyph per display state. `running` shows its base spinner frame;
|
|
986
|
-
* callers that animate must prefer {@link delegationStateMarker}. Unicode
|
|
987
|
-
* geometric shapes only (no Nerd Font) — shape is an independent channel
|
|
988
|
-
* from color, so rows stay legible without color. */
|
|
989
|
-
const DELEGATION_STATE_GLYPHS = {
|
|
990
|
-
running: "⠋",
|
|
991
|
-
retry: "⟳",
|
|
992
|
-
"stale-running": "⚠",
|
|
993
|
-
completed: "✓",
|
|
994
|
-
error: "✕",
|
|
995
|
-
cancelled: "−",
|
|
996
|
-
startup_failed: "⚠",
|
|
997
|
-
startup_unknown: "⚠"
|
|
998
|
-
};
|
|
999
|
-
function delegationStateGlyph(state) {
|
|
1000
|
-
return DELEGATION_STATE_GLYPHS[state];
|
|
1001
|
-
}
|
|
1002
|
-
/** Row marker (`<glyph> `) — the state channel. `running` animates through
|
|
1003
|
-
* {@link delegationSpinnerFrame} for the given tick; every other state is
|
|
1004
|
-
* static. Pure. */
|
|
1005
|
-
function delegationStateMarker(state, now = Date.now()) {
|
|
1006
|
-
return `${state === "running" ? delegationSpinnerFrame(now) : delegationStateGlyph(state)} `;
|
|
1007
|
-
}
|
|
1008
1040
|
/** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
|
|
1009
1041
|
* Kept separate + pure so the color channel is testable without booting the
|
|
1010
1042
|
* renderer. */
|
|
1043
|
+
/** Color is the ONLY channel separating `stale-running` from a live `running`
|
|
1044
|
+
* row — the 4-glyph row design has no dedicated stale shape. Display-only;
|
|
1045
|
+
* no behavior change. */
|
|
1011
1046
|
function delegationStateTone(state) {
|
|
1012
1047
|
switch (state) {
|
|
1013
1048
|
case "running":
|
|
@@ -1024,9 +1059,6 @@ function delegationStateTone(state) {
|
|
|
1024
1059
|
const latestToolActivity = /* @__PURE__ */ new Map();
|
|
1025
1060
|
const MAX_TOOL_ACTIVITY_ENTRIES = 200;
|
|
1026
1061
|
const TOOL_ACTIVITY_TTL_MS = 300 * 1e3;
|
|
1027
|
-
/** Archived-section pagination state — module-level so it survives sidebar
|
|
1028
|
-
* remounts (route changes) without leaking into the component tree. */
|
|
1029
|
-
const archivedUiState = { page: 0 };
|
|
1030
1062
|
/** First usable summary string from common tool input fields. */
|
|
1031
1063
|
function summarizeToolInput(input) {
|
|
1032
1064
|
if (!input) return "";
|
|
@@ -1097,6 +1129,11 @@ function mergeChildDelegationSources(children, live) {
|
|
|
1097
1129
|
for (const liveEntry of live) {
|
|
1098
1130
|
if (liveEntry.alias === null && liveEntry.taskID === null && Date.now() - liveEntry.startedAt > 3e4) continue;
|
|
1099
1131
|
const incoming = toDelegationEntry(liveEntry);
|
|
1132
|
+
const isNativeLive = liveEntry.tool === "task" && liveEntry.alias === null;
|
|
1133
|
+
if (isNativeLive) {
|
|
1134
|
+
incoming.source = "children-only";
|
|
1135
|
+
incoming.alias = "native-task";
|
|
1136
|
+
}
|
|
1100
1137
|
const index = (incoming.taskID !== void 0 ? byTask.get(incoming.taskID) : void 0) ?? (incoming.alias !== "" ? bySessionAlias.get(key(incoming.sessionID, incoming.alias)) : void 0);
|
|
1101
1138
|
if (index === void 0) {
|
|
1102
1139
|
result.push(incoming);
|
|
@@ -1124,7 +1161,7 @@ function mergeChildDelegationSources(children, live) {
|
|
|
1124
1161
|
startedAt: Math.min(existing.startedAt, incoming.startedAt),
|
|
1125
1162
|
updatedAt: incoming.updatedAt,
|
|
1126
1163
|
read: incoming.read,
|
|
1127
|
-
source: "live"
|
|
1164
|
+
source: isNativeLive ? existing.source : "live"
|
|
1128
1165
|
};
|
|
1129
1166
|
}
|
|
1130
1167
|
result.sort(compareDelegationEntries);
|
|
@@ -1308,7 +1345,7 @@ function removeDelegationEntry(map, partIDOrCallID) {
|
|
|
1308
1345
|
* SDK exposes `api.state.part(messageID)`). The native `task` tool spawns a
|
|
1309
1346
|
* child session with parentID = caller — the same mechanism as
|
|
1310
1347
|
* pantheon_delegate — so its parts feed the live-map as the native signal
|
|
1311
|
-
* (rows
|
|
1348
|
+
* (rows come from the children channel). Pure w.r.t. I/O — used
|
|
1312
1349
|
* by the mount re-scan to re-seed the live map after compaction/attach. */
|
|
1313
1350
|
function collectDelegationToolParts(messages, getParts) {
|
|
1314
1351
|
const out = [];
|
|
@@ -1379,6 +1416,76 @@ function mergeDelegationSources(live, md) {
|
|
|
1379
1416
|
all.sort(compareDelegationEntries);
|
|
1380
1417
|
return all;
|
|
1381
1418
|
}
|
|
1419
|
+
/** Job-board FSM → panel display state. `reconciled` is intentionally absent:
|
|
1420
|
+
* the panel parser rejects it (a reconciled job is done and folded away). */
|
|
1421
|
+
const BOARD_STATE_TO_DISPLAY = {
|
|
1422
|
+
running: "running",
|
|
1423
|
+
completed: "completed",
|
|
1424
|
+
error: "error",
|
|
1425
|
+
startup_failed: "startup_failed",
|
|
1426
|
+
startup_unknown: "startup_unknown",
|
|
1427
|
+
cancelled: "cancelled"
|
|
1428
|
+
};
|
|
1429
|
+
/** Map one persisted board record into the display shape. Returns null for
|
|
1430
|
+
* states the panel does not render (reconciled / unknown). Pure. */
|
|
1431
|
+
function boardRecordToDelegationEntry(record) {
|
|
1432
|
+
const state = BOARD_STATE_TO_DISPLAY[record.state];
|
|
1433
|
+
if (state === void 0) return null;
|
|
1434
|
+
const running = state === "running";
|
|
1435
|
+
return {
|
|
1436
|
+
alias: record.alias !== "" ? record.alias : `job-${record.taskID.slice(0, 8)}`,
|
|
1437
|
+
sessionID: record.parentSessionID,
|
|
1438
|
+
taskID: record.taskID,
|
|
1439
|
+
agent: record.agent,
|
|
1440
|
+
state,
|
|
1441
|
+
startedAt: record.launchedAt ?? record.updatedAt ?? 0,
|
|
1442
|
+
updatedAt: running ? null : record.completedAt ?? record.updatedAt ?? null,
|
|
1443
|
+
timedOut: record.timedOut === true,
|
|
1444
|
+
description: record.description ?? "",
|
|
1445
|
+
source: "board"
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
/** Map a whole board snapshot, dropping unrenderable states. Sorted like every
|
|
1449
|
+
* other channel (running first, then most recent). Pure. */
|
|
1450
|
+
function boardRecordsToDelegationEntries(records) {
|
|
1451
|
+
const out = [];
|
|
1452
|
+
for (const record of records) {
|
|
1453
|
+
const entry = boardRecordToDelegationEntry(record);
|
|
1454
|
+
if (entry !== null) out.push(entry);
|
|
1455
|
+
}
|
|
1456
|
+
out.sort(compareDelegationEntries);
|
|
1457
|
+
return out;
|
|
1458
|
+
}
|
|
1459
|
+
/** Merge the board over any other channel. The board is AUTHORITATIVE for
|
|
1460
|
+
* state/alias/agent (it is the persisted FSM) and it is the only channel
|
|
1461
|
+
* that carries jobs from OTHER sessions. Dedup by taskID first, then by
|
|
1462
|
+
* (sessionID, alias) — aliases are per parent session. Pure. */
|
|
1463
|
+
function mergeBoardDelegationSources(base, board) {
|
|
1464
|
+
const key = (sessionID, alias) => `${sessionID}\u0000${alias}`;
|
|
1465
|
+
const byTaskID = /* @__PURE__ */ new Map();
|
|
1466
|
+
const bySessionAlias = /* @__PURE__ */ new Map();
|
|
1467
|
+
const out = [...base];
|
|
1468
|
+
out.forEach((entry, index) => {
|
|
1469
|
+
if (entry.taskID !== void 0) byTaskID.set(entry.taskID, index);
|
|
1470
|
+
bySessionAlias.set(key(entry.sessionID, entry.alias), index);
|
|
1471
|
+
});
|
|
1472
|
+
for (const incoming of board) {
|
|
1473
|
+
const index = (incoming.taskID !== void 0 ? byTaskID.get(incoming.taskID) : void 0) ?? bySessionAlias.get(key(incoming.sessionID, incoming.alias));
|
|
1474
|
+
if (index === void 0) {
|
|
1475
|
+
out.push(incoming);
|
|
1476
|
+
const next = out.length - 1;
|
|
1477
|
+
if (incoming.taskID !== void 0) byTaskID.set(incoming.taskID, next);
|
|
1478
|
+
bySessionAlias.set(key(incoming.sessionID, incoming.alias), next);
|
|
1479
|
+
continue;
|
|
1480
|
+
}
|
|
1481
|
+
out[index] = {
|
|
1482
|
+
...incoming,
|
|
1483
|
+
sessionID: incoming.sessionID !== "" ? incoming.sessionID : out[index]?.sessionID ?? ""
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
out.sort(compareDelegationEntries);
|
|
1487
|
+
return out;
|
|
1488
|
+
}
|
|
1382
1489
|
/** Server-aligned session id validity: opencode rejects anything not starting
|
|
1383
1490
|
* with "ses" (SchemaError). This deliberately mirrors that exact contract —
|
|
1384
1491
|
* nothing stricter, nothing looser — so a template placeholder ("{sessionID}"),
|
|
@@ -1435,33 +1542,59 @@ function childStatusToState(status) {
|
|
|
1435
1542
|
if (status === "retry") return "retry";
|
|
1436
1543
|
return "running";
|
|
1437
1544
|
}
|
|
1438
|
-
/**
|
|
1439
|
-
* that split native task() work from pantheon_delegate jobs — the other is
|
|
1440
|
-
* {@link delegationIcon}):
|
|
1441
|
-
*
|
|
1442
|
-
* - `nat:<agent>` — a native task() child (source 'children-only', no board
|
|
1443
|
-
* report). The child session carries no board alias, so the agent IS the
|
|
1444
|
-
* identity.
|
|
1445
|
-
* - `pan:<alias>` — a pantheon_delegate board row (`pan:apo-1`), the same
|
|
1446
|
-
* alias the manager prints in pantheon_delegation_list.
|
|
1545
|
+
/** Status-only row model: ONE glyph + ONE identity per row.
|
|
1447
1546
|
*
|
|
1448
|
-
*
|
|
1449
|
-
* `
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1547
|
+
* A row is
|
|
1548
|
+
* `{glyph} {alias:7} {elapsed:>5}` plus a muted description line. The short
|
|
1549
|
+
* alias (`apo-1`) is the single identity; rows without a board alias show
|
|
1550
|
+
* the agent instead (never both). */
|
|
1551
|
+
/** Map every FSM/display state to one of the 4 row kinds. reconciled never
|
|
1552
|
+
* reaches the panel (the board parser drops it) but reads as done;
|
|
1553
|
+
* cancelled reads as done; startup_failed reads as failed while
|
|
1554
|
+
* startup_unknown (no error known) reads as retry. Pure. */
|
|
1555
|
+
function delegationRowStatus(state) {
|
|
1556
|
+
switch (state) {
|
|
1557
|
+
case "running":
|
|
1558
|
+
case "stale-running": return "active";
|
|
1559
|
+
case "retry":
|
|
1560
|
+
case "startup_unknown": return "retry";
|
|
1561
|
+
case "completed":
|
|
1562
|
+
case "cancelled": return "done";
|
|
1563
|
+
case "error":
|
|
1564
|
+
case "startup_failed": return "failed";
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
/** The only 4 glyphs a row may show: animated active, done, failed, retry.
|
|
1568
|
+
* Shape is redundant with color (never the only signal). Pure. */
|
|
1569
|
+
const DELEGATION_ROW_GLYPHS = {
|
|
1570
|
+
active: "⠋",
|
|
1571
|
+
done: "✓",
|
|
1572
|
+
failed: "✕",
|
|
1573
|
+
retry: "⟳"
|
|
1574
|
+
};
|
|
1575
|
+
function delegationRowGlyph(status) {
|
|
1576
|
+
return DELEGATION_ROW_GLYPHS[status];
|
|
1577
|
+
}
|
|
1578
|
+
/** Row marker (`<glyph> `) — the single state channel. `active` animates
|
|
1579
|
+
* through the 1s spinner for the given tick; every other kind is static.
|
|
1580
|
+
* Pure. */
|
|
1581
|
+
function delegationRowMarker(state, now = Date.now()) {
|
|
1582
|
+
const status = delegationRowStatus(state);
|
|
1583
|
+
return `${status === "active" ? delegationSpinnerFrame(now) : delegationRowGlyph(status)} `;
|
|
1584
|
+
}
|
|
1585
|
+
/** ONE identity per row: the short board alias (`apo-1`); a row without a
|
|
1586
|
+
* board alias (native task() child, alias `native-task`) shows the agent
|
|
1587
|
+
* instead — never alias + agent stacked. Pure. */
|
|
1588
|
+
function delegationRowIdentity(entry) {
|
|
1589
|
+
if (entry.alias === "native-task" && entry.agent !== "") return entry.agent;
|
|
1590
|
+
return entry.alias;
|
|
1591
|
+
}
|
|
1592
|
+
/** Fixed alias cell, pad-right + hard-truncate to `width` (default 7) so
|
|
1593
|
+
* identities line up across rows. Pure. */
|
|
1594
|
+
const DELEGATION_ALIAS_WIDTH = 7;
|
|
1595
|
+
function formatDelegationAlias(identity, width = 7) {
|
|
1596
|
+
if (identity.length >= width) return identity.slice(0, width);
|
|
1597
|
+
return `${identity}${" ".repeat(width - identity.length)}`;
|
|
1465
1598
|
}
|
|
1466
1599
|
/** Max description width on the row detail line — the old 180-char slice
|
|
1467
1600
|
* wrapped the sidebar; 44 keeps one readable line. */
|
|
@@ -1487,33 +1620,61 @@ function truncateDelegationDescription(text, max = 44) {
|
|
|
1487
1620
|
if (graphemes.length <= max) return text;
|
|
1488
1621
|
return `${graphemes.slice(0, Math.max(0, max - 1)).join("")}\u2026`;
|
|
1489
1622
|
}
|
|
1490
|
-
/** Fixed elapsed-time box: right-aligned to `width` (default
|
|
1491
|
-
* values line up across rows, e.g. `
|
|
1623
|
+
/** Fixed elapsed-time box: right-aligned to `width` (default 5) so elapsed
|
|
1624
|
+
* values line up across rows, e.g. ` 12s`. A label that already fills
|
|
1492
1625
|
* the box is returned untouched. Pure. */
|
|
1493
|
-
const DELEGATION_ELAPSED_WIDTH =
|
|
1494
|
-
function formatDelegationElapsed(entry, now, width =
|
|
1626
|
+
const DELEGATION_ELAPSED_WIDTH = 5;
|
|
1627
|
+
function formatDelegationElapsed(entry, now, width = 5) {
|
|
1495
1628
|
const label = delegationElapsed(entry, now);
|
|
1496
1629
|
if (label.length >= width) return label;
|
|
1497
1630
|
return `${" ".repeat(width - label.length)}${label}`;
|
|
1498
1631
|
}
|
|
1499
|
-
/**
|
|
1500
|
-
*
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
*
|
|
1632
|
+
/** Colored left half of a row line: `<marker><alias:7> ` — the state glyph
|
|
1633
|
+
* plus the single identity, padded so the muted elapsed column aligns. The
|
|
1634
|
+
* row renders this colored lead separately from the muted elapsed tail. Pure. */
|
|
1635
|
+
function formatDelegationRowLead(entry, marker) {
|
|
1636
|
+
return `${marker}${formatDelegationAlias(delegationRowIdentity(entry))} `;
|
|
1637
|
+
}
|
|
1638
|
+
/** Visible-row ceiling for the panel: the remainder collapses into a single
|
|
1639
|
+
* "… +N more" line. Live rows render first, so a running job is never hidden
|
|
1640
|
+
* by the cap. */
|
|
1641
|
+
const DELEGATION_VISIBLE_CEILING = 8;
|
|
1642
|
+
/** Header summary: `(N active · M done)` plus `· K failed` only when K > 0.
|
|
1643
|
+
* Active counts running/retry AND display-only stale-running (a stale row is
|
|
1644
|
+
* still a live job — it must never read as done); failed counts
|
|
1645
|
+
* error/startup_failed; cancelled reads as done. Pure. */
|
|
1507
1646
|
function formatDelegationHeader(entries) {
|
|
1508
1647
|
let active = 0;
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
const
|
|
1512
|
-
|
|
1648
|
+
let done = 0;
|
|
1649
|
+
let failed = 0;
|
|
1650
|
+
for (const e of entries) switch (delegationRowStatus(e.state)) {
|
|
1651
|
+
case "active":
|
|
1652
|
+
case "retry":
|
|
1653
|
+
active++;
|
|
1654
|
+
break;
|
|
1655
|
+
case "failed":
|
|
1656
|
+
failed++;
|
|
1657
|
+
break;
|
|
1658
|
+
case "done":
|
|
1659
|
+
done++;
|
|
1660
|
+
break;
|
|
1661
|
+
}
|
|
1662
|
+
const tail = failed > 0 ? ` · ${failed} failed` : "";
|
|
1663
|
+
return `(${active} active · ${done} done${tail})`;
|
|
1664
|
+
}
|
|
1665
|
+
/** Cap the panel: live rows first, then most-recent terminal rows, at most
|
|
1666
|
+
* `maxVisible` total. `hidden` is how many were dropped (rendered as
|
|
1667
|
+
* "… +N more"). Pure. */
|
|
1668
|
+
function ceilingDelegationList(all, maxVisible = 8, now = Date.now()) {
|
|
1669
|
+
const visible = visibleDelegationList(all, maxVisible, now).slice(0, maxVisible);
|
|
1670
|
+
return {
|
|
1671
|
+
visible,
|
|
1672
|
+
hidden: Math.max(0, all.length - visible.length)
|
|
1673
|
+
};
|
|
1513
1674
|
}
|
|
1514
1675
|
/** Split a display list into native task() rows vs pantheon_delegate rows.
|
|
1515
1676
|
* Native = source 'children-only' (no board report); everything else counts
|
|
1516
|
-
* as pantheon. Pure — powers the
|
|
1677
|
+
* as pantheon. Pure — powers the hooks.log line. */
|
|
1517
1678
|
function countDelegationSources(entries) {
|
|
1518
1679
|
let native = 0;
|
|
1519
1680
|
for (const e of entries) if (e.source === "children-only") native++;
|
|
@@ -1538,15 +1699,18 @@ function formatPanelLogLine(children, pantheon, native, md, events) {
|
|
|
1538
1699
|
* time.created. A report-less child is a NATIVE task() child (every
|
|
1539
1700
|
* child of the current session — pantheon_delegate OR the native `task()`
|
|
1540
1701
|
* tool — carries parentID = caller), so it gets source 'children-only',
|
|
1541
|
-
* the internal alias 'native-task'
|
|
1702
|
+
* the internal alias 'native-task' instead of a
|
|
1542
1703
|
* board alias. The 'task nativa' description fallback keeps the row
|
|
1543
1704
|
* non-empty when the child carries no title.
|
|
1544
1705
|
* Terminal md state wins over the derived state; a running md defers to
|
|
1545
1706
|
* the child's live status. A running child is NEVER archived — it always
|
|
1546
1707
|
* lands in the active split (splitDelegationList active = running/retry).
|
|
1708
|
+
* `parentSessionID` (the focused session id) is stamped on report-less
|
|
1709
|
+
* children so the row carries its origin session; omit it and they stay
|
|
1710
|
+
* unscoped ('').
|
|
1547
1711
|
* Sorted running-first (compareDelegationEntries).
|
|
1548
1712
|
* Pure — no I/O. */
|
|
1549
|
-
function childrenToDelegationEntries(children, md, now = Date.now()) {
|
|
1713
|
+
function childrenToDelegationEntries(children, md, now = Date.now(), parentSessionID = "") {
|
|
1550
1714
|
const byTaskID = /* @__PURE__ */ new Map();
|
|
1551
1715
|
for (const m of md) if (m.taskID !== void 0 && !byTaskID.has(m.taskID)) byTaskID.set(m.taskID, m);
|
|
1552
1716
|
const out = [];
|
|
@@ -1558,7 +1722,7 @@ function childrenToDelegationEntries(children, md, now = Date.now()) {
|
|
|
1558
1722
|
const state = mdEntry !== void 0 && mdEntry.state !== "running" ? mdEntry.state : childStatusToState(child.status);
|
|
1559
1723
|
out.push({
|
|
1560
1724
|
alias: mdEntry?.alias ?? "native-task",
|
|
1561
|
-
sessionID: mdEntry?.sessionID ??
|
|
1725
|
+
sessionID: mdEntry?.sessionID ?? parentSessionID,
|
|
1562
1726
|
taskID: child.id,
|
|
1563
1727
|
agent: mdEntry?.agent ?? child.agent ?? "agent",
|
|
1564
1728
|
state,
|
|
@@ -1644,7 +1808,7 @@ function SessionRow(props) {
|
|
|
1644
1808
|
}
|
|
1645
1809
|
function DelegationRow(props) {
|
|
1646
1810
|
const theme = () => props.api.theme.current;
|
|
1647
|
-
const
|
|
1811
|
+
const tone = createMemo(() => {
|
|
1648
1812
|
const t = theme();
|
|
1649
1813
|
switch (delegationStateTone(props.job.state)) {
|
|
1650
1814
|
case "warning": return t.warning;
|
|
@@ -1653,57 +1817,54 @@ function DelegationRow(props) {
|
|
|
1653
1817
|
default: return t.textMuted;
|
|
1654
1818
|
}
|
|
1655
1819
|
});
|
|
1656
|
-
const marker = createMemo(() =>
|
|
1657
|
-
const
|
|
1658
|
-
const description = createMemo(() => truncateDelegationDescription(props.job.description));
|
|
1820
|
+
const marker = createMemo(() => delegationRowMarker(props.job.state, props.animationNow));
|
|
1821
|
+
const lead = createMemo(() => formatDelegationRowLead(props.job, marker()));
|
|
1659
1822
|
const elapsed = createMemo(() => formatDelegationElapsed(props.job, props.now));
|
|
1823
|
+
const description = createMemo(() => truncateDelegationDescription(props.job.description));
|
|
1660
1824
|
const activity = createMemo(() => latestToolActivityFor(latestToolActivity, props.job.taskID, props.now));
|
|
1661
1825
|
const open = () => {
|
|
1662
1826
|
navigateToDelegationSession(props.api.route, props.job.taskID);
|
|
1663
1827
|
};
|
|
1664
1828
|
return (() => {
|
|
1665
|
-
var _el$13 = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("text"), _el$16 = createElement("
|
|
1829
|
+
var _el$13 = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("text"), _el$16 = createElement("span"), _el$17 = createElement("span");
|
|
1666
1830
|
insertNode(_el$13, _el$14);
|
|
1667
|
-
insertNode(_el$13, _el$16);
|
|
1668
1831
|
setProp(_el$13, "onMouseDown", open);
|
|
1669
1832
|
insertNode(_el$14, _el$15);
|
|
1670
1833
|
setProp(_el$14, "flexDirection", "row");
|
|
1671
|
-
|
|
1672
|
-
insertNode(_el$
|
|
1673
|
-
|
|
1674
|
-
insert(_el$
|
|
1834
|
+
insertNode(_el$15, _el$16);
|
|
1835
|
+
insertNode(_el$15, _el$17);
|
|
1836
|
+
insert(_el$16, lead);
|
|
1837
|
+
insert(_el$17, elapsed);
|
|
1838
|
+
insert(_el$13, createComponent(Show, {
|
|
1675
1839
|
get when() {
|
|
1676
1840
|
return description() !== "";
|
|
1677
1841
|
},
|
|
1678
1842
|
get children() {
|
|
1679
|
-
var _el$
|
|
1680
|
-
insert(_el$
|
|
1681
|
-
effect((_$p) => setProp(_el$
|
|
1682
|
-
return _el$
|
|
1843
|
+
var _el$18 = createElement("text");
|
|
1844
|
+
insert(_el$18, () => ` ${description()}`);
|
|
1845
|
+
effect((_$p) => setProp(_el$18, "fg", theme().textMuted, _$p));
|
|
1846
|
+
return _el$18;
|
|
1683
1847
|
}
|
|
1684
|
-
}),
|
|
1685
|
-
insert(_el$18, elapsed);
|
|
1848
|
+
}), null);
|
|
1686
1849
|
insert(_el$13, createComponent(Show, {
|
|
1687
1850
|
get when() {
|
|
1688
1851
|
return activity();
|
|
1689
1852
|
},
|
|
1690
1853
|
children: (a) => (() => {
|
|
1691
1854
|
var _el$19 = createElement("text");
|
|
1692
|
-
insert(_el$19, () => `
|
|
1855
|
+
insert(_el$19, () => ` ↳ ${truncateDelegationDescription(`${a().tool}${a().summary !== "" ? ` ${a().summary}` : ""}`)}`);
|
|
1693
1856
|
effect((_$p) => setProp(_el$19, "fg", theme().textMuted, _$p));
|
|
1694
1857
|
return _el$19;
|
|
1695
1858
|
})()
|
|
1696
1859
|
}), null);
|
|
1697
1860
|
effect((_p$) => {
|
|
1698
|
-
var _v$5 =
|
|
1699
|
-
_v$5 !== _p$.e && (_p$.e = setProp(_el$
|
|
1700
|
-
_v$6 !== _p$.t && (_p$.t = setProp(_el$
|
|
1701
|
-
_v$7 !== _p$.a && (_p$.a = setProp(_el$18, "fg", _v$7, _p$.a));
|
|
1861
|
+
var _v$5 = tone(), _v$6 = theme().textMuted;
|
|
1862
|
+
_v$5 !== _p$.e && (_p$.e = setProp(_el$16, "fg", _v$5, _p$.e));
|
|
1863
|
+
_v$6 !== _p$.t && (_p$.t = setProp(_el$17, "fg", _v$6, _p$.t));
|
|
1702
1864
|
return _p$;
|
|
1703
1865
|
}, {
|
|
1704
1866
|
e: void 0,
|
|
1705
|
-
t: void 0
|
|
1706
|
-
a: void 0
|
|
1867
|
+
t: void 0
|
|
1707
1868
|
});
|
|
1708
1869
|
return _el$13;
|
|
1709
1870
|
})();
|
|
@@ -1761,8 +1922,8 @@ function View(props) {
|
|
|
1761
1922
|
return (b.time?.updated ?? b.updated ?? 0) - ta;
|
|
1762
1923
|
}).slice(0, 8);
|
|
1763
1924
|
});
|
|
1764
|
-
const
|
|
1765
|
-
const panelLog = createTuiLogger(
|
|
1925
|
+
const projectRoot = createMemo(() => resolvePantheonRoot(props.api.state.path));
|
|
1926
|
+
const panelLog = createTuiLogger(projectRoot());
|
|
1766
1927
|
const [childDelegations, setChildDelegations] = createSignal([]);
|
|
1767
1928
|
const [now, setNow] = createSignal(Date.now());
|
|
1768
1929
|
const [animationNow, setAnimationNow] = createSignal(Date.now());
|
|
@@ -1775,17 +1936,23 @@ function View(props) {
|
|
|
1775
1936
|
const state = props.api.state;
|
|
1776
1937
|
let md = [];
|
|
1777
1938
|
try {
|
|
1778
|
-
md = await readAllDelegationEntries(
|
|
1939
|
+
md = await readAllDelegationEntries(projectRoot());
|
|
1779
1940
|
} catch {
|
|
1780
1941
|
md = [];
|
|
1781
1942
|
}
|
|
1943
|
+
let board = [];
|
|
1944
|
+
try {
|
|
1945
|
+
board = boardRecordsToDelegationEntries(await readBoardState(projectRoot()));
|
|
1946
|
+
} catch {
|
|
1947
|
+
board = [];
|
|
1948
|
+
}
|
|
1782
1949
|
const sessionID = resolveCurrentSessionID({
|
|
1783
1950
|
sessionID: props.sessionID,
|
|
1784
1951
|
api: props.api
|
|
1785
1952
|
});
|
|
1786
1953
|
if (sessionID === null) {
|
|
1787
|
-
setChildDelegations(md);
|
|
1788
|
-
panelLog.info(`${formatPanelLogLine(0, 0, 0, md.length, eventRefreshCount)} (no sessionID — history shown)`);
|
|
1954
|
+
setChildDelegations(mergeBoardDelegationSources(md, board));
|
|
1955
|
+
panelLog.info(`${formatPanelLogLine(0, 0, 0, md.length, eventRefreshCount)} (no sessionID — history+board shown)`);
|
|
1789
1956
|
return;
|
|
1790
1957
|
}
|
|
1791
1958
|
let children = [];
|
|
@@ -1808,10 +1975,10 @@ function View(props) {
|
|
|
1808
1975
|
const childEntries = childrenToDelegationEntries(children.map((c) => ({
|
|
1809
1976
|
...c,
|
|
1810
1977
|
status: resolveStatus(c.id)
|
|
1811
|
-
})), md, now());
|
|
1978
|
+
})), md, now(), sessionID);
|
|
1812
1979
|
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
1980
|
const liveEntries = [...props.liveStore.map.values()].filter((entry) => entry.sessionID === sessionID);
|
|
1814
|
-
setChildDelegations(mergeChildDelegationSources(childEntries, liveEntries));
|
|
1981
|
+
setChildDelegations(mergeBoardDelegationSources(mergeChildDelegationSources(childEntries, liveEntries), board));
|
|
1815
1982
|
const counts = countDelegationSources(childEntries);
|
|
1816
1983
|
panelLog.info(formatPanelLogLine(children.length, counts.pantheon, counts.native, md.length, eventRefreshCount));
|
|
1817
1984
|
} finally {
|
|
@@ -1820,15 +1987,8 @@ function View(props) {
|
|
|
1820
1987
|
})();
|
|
1821
1988
|
return delegationsInflight;
|
|
1822
1989
|
};
|
|
1823
|
-
const
|
|
1824
|
-
const visibleDelegations = createMemo(() => [...delegationSplit().active, ...delegationSplit().recent]);
|
|
1990
|
+
const delegationCeiling = createMemo(() => ceilingDelegationList(childDelegations(), 8, now()));
|
|
1825
1991
|
const delegationHeader = createMemo(() => formatDelegationHeader(childDelegations()));
|
|
1826
|
-
const [archivedPage, setArchivedPage] = createSignal(archivedUiState.page);
|
|
1827
|
-
const clampArchivedPage = (page, pages) => {
|
|
1828
|
-
const clamped = Math.max(0, Math.min(page, Math.max(0, pages - 1)));
|
|
1829
|
-
archivedUiState.page = clamped;
|
|
1830
|
-
setArchivedPage(clamped);
|
|
1831
|
-
};
|
|
1832
1992
|
onMount(() => {
|
|
1833
1993
|
const cleanup = [];
|
|
1834
1994
|
try {
|
|
@@ -1896,10 +2056,10 @@ function View(props) {
|
|
|
1896
2056
|
return branch();
|
|
1897
2057
|
},
|
|
1898
2058
|
children: (b) => (() => {
|
|
1899
|
-
var _el$
|
|
1900
|
-
insert(_el$
|
|
1901
|
-
effect((_$p) => setProp(_el$
|
|
1902
|
-
return _el$
|
|
2059
|
+
var _el$33 = createElement("text");
|
|
2060
|
+
insert(_el$33, b);
|
|
2061
|
+
effect((_$p) => setProp(_el$33, "fg", theme().textMuted, _$p));
|
|
2062
|
+
return _el$33;
|
|
1903
2063
|
})()
|
|
1904
2064
|
}), _el$24);
|
|
1905
2065
|
insert(_el$22, createComponent(Show, {
|
|
@@ -1908,37 +2068,37 @@ function View(props) {
|
|
|
1908
2068
|
},
|
|
1909
2069
|
get fallback() {
|
|
1910
2070
|
return (() => {
|
|
1911
|
-
var _el$
|
|
1912
|
-
insertNode(_el$
|
|
1913
|
-
setProp(_el$
|
|
1914
|
-
setProp(_el$
|
|
1915
|
-
insertNode(_el$
|
|
1916
|
-
effect((_$p) => setProp(_el$
|
|
1917
|
-
return _el$
|
|
2071
|
+
var _el$34 = createElement("box"), _el$35 = createElement("text");
|
|
2072
|
+
insertNode(_el$34, _el$35);
|
|
2073
|
+
setProp(_el$34, "flexDirection", "row");
|
|
2074
|
+
setProp(_el$34, "gap", 1);
|
|
2075
|
+
insertNode(_el$35, createTextNode(`Preset: default`));
|
|
2076
|
+
effect((_$p) => setProp(_el$35, "fg", theme().textMuted, _$p));
|
|
2077
|
+
return _el$34;
|
|
1918
2078
|
})();
|
|
1919
2079
|
},
|
|
1920
2080
|
children: (name) => (() => {
|
|
1921
|
-
var _el$
|
|
1922
|
-
insertNode(_el$
|
|
1923
|
-
insertNode(_el$
|
|
1924
|
-
insertNode(_el$
|
|
1925
|
-
setProp(_el$
|
|
1926
|
-
setProp(_el$
|
|
1927
|
-
insertNode(_el$
|
|
1928
|
-
insert(_el$
|
|
1929
|
-
insert(_el$
|
|
2081
|
+
var _el$37 = createElement("box"), _el$38 = createElement("text"), _el$40 = createElement("text"), _el$41 = createElement("text");
|
|
2082
|
+
insertNode(_el$37, _el$38);
|
|
2083
|
+
insertNode(_el$37, _el$40);
|
|
2084
|
+
insertNode(_el$37, _el$41);
|
|
2085
|
+
setProp(_el$37, "flexDirection", "row");
|
|
2086
|
+
setProp(_el$37, "gap", 1);
|
|
2087
|
+
insertNode(_el$38, createTextNode(`⚡ Preset:`));
|
|
2088
|
+
insert(_el$40, name);
|
|
2089
|
+
insert(_el$41, () => `(${preset().source ?? ""})`);
|
|
1930
2090
|
effect((_p$) => {
|
|
1931
|
-
var _v$
|
|
1932
|
-
_v$
|
|
1933
|
-
_v$
|
|
1934
|
-
_v$
|
|
2091
|
+
var _v$10 = theme().textMuted, _v$11 = theme().accent, _v$12 = theme().textMuted;
|
|
2092
|
+
_v$10 !== _p$.e && (_p$.e = setProp(_el$38, "fg", _v$10, _p$.e));
|
|
2093
|
+
_v$11 !== _p$.t && (_p$.t = setProp(_el$40, "fg", _v$11, _p$.t));
|
|
2094
|
+
_v$12 !== _p$.a && (_p$.a = setProp(_el$41, "fg", _v$12, _p$.a));
|
|
1935
2095
|
return _p$;
|
|
1936
2096
|
}, {
|
|
1937
2097
|
e: void 0,
|
|
1938
2098
|
t: void 0,
|
|
1939
2099
|
a: void 0
|
|
1940
2100
|
});
|
|
1941
|
-
return _el$
|
|
2101
|
+
return _el$37;
|
|
1942
2102
|
})()
|
|
1943
2103
|
}), _el$24);
|
|
1944
2104
|
insert(_el$22, createComponent(HR, {}), _el$24);
|
|
@@ -1959,12 +2119,12 @@ function View(props) {
|
|
|
1959
2119
|
},
|
|
1960
2120
|
get fallback() {
|
|
1961
2121
|
return (() => {
|
|
1962
|
-
var _el$
|
|
1963
|
-
insertNode(_el$
|
|
1964
|
-
setProp(_el$
|
|
1965
|
-
insertNode(_el$
|
|
1966
|
-
effect((_$p) => setProp(_el$
|
|
1967
|
-
return _el$
|
|
2122
|
+
var _el$42 = createElement("box"), _el$43 = createElement("text");
|
|
2123
|
+
insertNode(_el$42, _el$43);
|
|
2124
|
+
setProp(_el$42, "marginLeft", 1);
|
|
2125
|
+
insertNode(_el$43, createTextNode(`No recent sessions`));
|
|
2126
|
+
effect((_$p) => setProp(_el$43, "fg", theme().textMuted, _$p));
|
|
2127
|
+
return _el$42;
|
|
1968
2128
|
})();
|
|
1969
2129
|
},
|
|
1970
2130
|
get children() {
|
|
@@ -1992,7 +2152,10 @@ function View(props) {
|
|
|
1992
2152
|
setProp(_el$28, "onMouseDown", () => setShowDelegations((x) => !x));
|
|
1993
2153
|
setProp(_el$29, "attributes", 1);
|
|
1994
2154
|
insert(_el$29, () => `${showDelegations() ? "▼" : "▶"} Delegations`);
|
|
1995
|
-
insert(_el$30, () =>
|
|
2155
|
+
insert(_el$30, (() => {
|
|
2156
|
+
var _c$ = memo(() => childDelegations().length > 0);
|
|
2157
|
+
return () => _c$() ? ` ${delegationHeader()}` : " — idle";
|
|
2158
|
+
})());
|
|
1996
2159
|
insert(_el$22, createComponent(Show, {
|
|
1997
2160
|
get when() {
|
|
1998
2161
|
return showDelegations();
|
|
@@ -2000,16 +2163,16 @@ function View(props) {
|
|
|
2000
2163
|
get children() {
|
|
2001
2164
|
return createComponent(Show, {
|
|
2002
2165
|
get when() {
|
|
2003
|
-
return
|
|
2166
|
+
return delegationCeiling().visible.length > 0;
|
|
2004
2167
|
},
|
|
2005
2168
|
get fallback() {
|
|
2006
2169
|
return (() => {
|
|
2007
|
-
var _el$
|
|
2008
|
-
insertNode(_el$
|
|
2009
|
-
setProp(_el$
|
|
2010
|
-
insertNode(_el$
|
|
2011
|
-
effect((_$p) => setProp(_el$
|
|
2012
|
-
return _el$
|
|
2170
|
+
var _el$45 = createElement("box"), _el$46 = createElement("text");
|
|
2171
|
+
insertNode(_el$45, _el$46);
|
|
2172
|
+
setProp(_el$45, "marginLeft", 1);
|
|
2173
|
+
insertNode(_el$46, createTextNode(`No delegations`));
|
|
2174
|
+
effect((_$p) => setProp(_el$46, "fg", theme().textMuted, _$p));
|
|
2175
|
+
return _el$45;
|
|
2013
2176
|
})();
|
|
2014
2177
|
},
|
|
2015
2178
|
get children() {
|
|
@@ -2018,7 +2181,7 @@ function View(props) {
|
|
|
2018
2181
|
setProp(_el$31, "flexDirection", "column");
|
|
2019
2182
|
insert(_el$31, createComponent(For, {
|
|
2020
2183
|
get each() {
|
|
2021
|
-
return
|
|
2184
|
+
return delegationCeiling().visible;
|
|
2022
2185
|
},
|
|
2023
2186
|
children: (job) => createComponent(DelegationRow, {
|
|
2024
2187
|
get api() {
|
|
@@ -2035,62 +2198,13 @@ function View(props) {
|
|
|
2035
2198
|
}), null);
|
|
2036
2199
|
insert(_el$31, createComponent(Show, {
|
|
2037
2200
|
get when() {
|
|
2038
|
-
return
|
|
2201
|
+
return delegationCeiling().hidden > 0;
|
|
2039
2202
|
},
|
|
2040
2203
|
get children() {
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
const page = Math.min(archivedPage(), pages - 1);
|
|
2046
|
-
const slice = archived.slice(page * pageSize, page * pageSize + pageSize);
|
|
2047
|
-
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, {
|
|
2064
|
-
each: slice,
|
|
2065
|
-
children: (job) => createComponent(DelegationRow, {
|
|
2066
|
-
get api() {
|
|
2067
|
-
return props.api;
|
|
2068
|
-
},
|
|
2069
|
-
job,
|
|
2070
|
-
get now() {
|
|
2071
|
-
return now();
|
|
2072
|
-
},
|
|
2073
|
-
get animationNow() {
|
|
2074
|
-
return animationNow();
|
|
2075
|
-
}
|
|
2076
|
-
})
|
|
2077
|
-
}), null);
|
|
2078
|
-
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));
|
|
2084
|
-
return _p$;
|
|
2085
|
-
}, {
|
|
2086
|
-
e: void 0,
|
|
2087
|
-
t: void 0,
|
|
2088
|
-
a: void 0,
|
|
2089
|
-
o: void 0
|
|
2090
|
-
});
|
|
2091
|
-
return _el$47;
|
|
2092
|
-
})();
|
|
2093
|
-
})();
|
|
2204
|
+
var _el$32 = createElement("text");
|
|
2205
|
+
insert(_el$32, () => `… +${delegationCeiling().hidden} more`);
|
|
2206
|
+
effect((_$p) => setProp(_el$32, "fg", theme().textMuted, _$p));
|
|
2207
|
+
return _el$32;
|
|
2094
2208
|
}
|
|
2095
2209
|
}), null);
|
|
2096
2210
|
return _el$31;
|
|
@@ -2099,12 +2213,12 @@ function View(props) {
|
|
|
2099
2213
|
}
|
|
2100
2214
|
}), null);
|
|
2101
2215
|
effect((_p$) => {
|
|
2102
|
-
var _v$
|
|
2103
|
-
_v$
|
|
2104
|
-
_v$
|
|
2105
|
-
_v$
|
|
2106
|
-
_v$
|
|
2107
|
-
_v$
|
|
2216
|
+
var _v$7 = theme().accent, _v$8 = theme().text, _v$9 = theme().textMuted, _v$0 = theme().text, _v$1 = theme().textMuted;
|
|
2217
|
+
_v$7 !== _p$.e && (_p$.e = setProp(_el$23, "fg", _v$7, _p$.e));
|
|
2218
|
+
_v$8 !== _p$.t && (_p$.t = setProp(_el$25, "fg", _v$8, _p$.t));
|
|
2219
|
+
_v$9 !== _p$.a && (_p$.a = setProp(_el$26, "fg", _v$9, _p$.a));
|
|
2220
|
+
_v$0 !== _p$.o && (_p$.o = setProp(_el$29, "fg", _v$0, _p$.o));
|
|
2221
|
+
_v$1 !== _p$.i && (_p$.i = setProp(_el$30, "fg", _v$1, _p$.i));
|
|
2108
2222
|
return _p$;
|
|
2109
2223
|
}, {
|
|
2110
2224
|
e: void 0,
|
|
@@ -2173,6 +2287,6 @@ const plugin = {
|
|
|
2173
2287
|
setup: async () => {}
|
|
2174
2288
|
};
|
|
2175
2289
|
//#endregion
|
|
2176
|
-
export { DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH,
|
|
2290
|
+
export { DELEGATION_ALIAS_WIDTH, DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DELEGATION_ROW_GLYPHS, DELEGATION_VISIBLE_CEILING, IDLE_SILENCE_MS, STALE_RUNNING_THRESHOLD_MS, 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 };
|
|
2177
2291
|
|
|
2178
2292
|
//# sourceMappingURL=tui.js.map
|