pantheon-opencode 1.5.0-beta.10 → 1.5.0-beta.11
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 +28 -0
- package/package.json +1 -2
- package/plugin.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/dev-tui.sh +48 -0
- package/scripts/doctor.mjs +32 -3
- package/src/plugins/tui/dist/tui.d.ts +22 -1
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +49 -17
- package/src/plugins/tui/dist/tui.tsx +62 -22
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +1 -1
- package/src/plugins/tui/src/index.tsx +62 -22
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,34 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
18
18
|
|
|
19
19
|
## ✅ Closed Issues
|
|
20
20
|
|
|
21
|
+
## [v1.5.0-beta.11] - 2026-09-14
|
|
22
|
+
|
|
23
|
+
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
|
24
|
+
move this section to a versioned entry and reset the template below. -->
|
|
25
|
+
|
|
26
|
+
## 🆕 What's New
|
|
27
|
+
|
|
28
|
+
- **Glyphs da FSM real no painel Delegations:** cada estado do BackgroundJobBoard
|
|
29
|
+
tem agora um glifo Unicode geométrico próprio — `⠋` running (spinner 1s),
|
|
30
|
+
`⟳` retry, `⚠` stale/startup, `✓` completed, `✕` error, `−` cancelled. Forma e
|
|
31
|
+
cor são canais independentes: as linhas seguem legíveis sem cor e sem Nerd Font.
|
|
32
|
+
- **Prefixo `nat:` / `pan:` documentado:** `docs/INSTALLATION.md` passa a
|
|
33
|
+
descrever os prefixos curtos das linhas nativas (`nat:<agent>`) e do board
|
|
34
|
+
(`pan:<alias>`) e o par de glyphs ◇/◆.
|
|
35
|
+
- **`scripts/dev-tui.sh` (dev local sem publish):** instala, builda e registra o
|
|
36
|
+
caminho absoluto do repo em `.opencode/tui.json` (gitignored) com hint de
|
|
37
|
+
restart — sem tocar `opencode.json` e sem publicar.
|
|
38
|
+
- **104 testes TUI delegations:** `tests/pantheon/tui-delegations.test.ts` com
|
|
39
|
+
104/104 passando, cobrindo glifos/marker/tone dos estados reais da FSM.
|
|
40
|
+
|
|
41
|
+
## 🐞 Fixed
|
|
42
|
+
|
|
43
|
+
- **Doctor F.2 (`hasUsableScripts`):** a resolução do diretório code-mode agora
|
|
44
|
+
exige um `.py`/`.sh` regular (paridade com `_has_usable_scripts` do MCP), então
|
|
45
|
+
um overlay de projeto vazio não mascara mais uma instalação que traz scripts.
|
|
46
|
+
- **`publish:next` órfão removido:** nenhum workflow usava o script (o release
|
|
47
|
+
publica via `--tag beta`); removido do `package.json` para eliminar o dist-tag
|
|
48
|
+
`next` obsoleto da linha de publicação.
|
|
21
49
|
## [v1.5.0-beta.10] - 2026-09-14
|
|
22
50
|
|
|
23
51
|
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-opencode",
|
|
3
|
-
"version": "1.5.0-beta.
|
|
3
|
+
"version": "1.5.0-beta.11",
|
|
4
4
|
"description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
"release:dry-run": "node scripts/versioning.mjs status && node scripts/release-notes.mjs && node scripts/package-evidence.mjs",
|
|
32
32
|
"package:evidence": "node scripts/package-evidence.mjs",
|
|
33
33
|
"package:validate": "node scripts/validate-package.mjs",
|
|
34
|
-
"publish:next": "npm publish --tag next --access public",
|
|
35
34
|
"lint": "biome ci .",
|
|
36
35
|
"typecheck": "tsc --noEmit",
|
|
37
36
|
"audit": "npm audit --audit-level=high",
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon",
|
|
3
3
|
"publisher": "ils15",
|
|
4
|
-
"version": "1.5.0-beta.
|
|
4
|
+
"version": "1.5.0-beta.11",
|
|
5
5
|
"displayName": "Pantheon",
|
|
6
6
|
"description": "Conductor-Delegate orchestration platform with 14 specialized agents, 21 skills, and OpenCode support.",
|
|
7
7
|
"agents": "./src/agents",
|
package/pyproject.toml
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# dev-tui.sh — load the Pantheon TUI from the repo (src/plugins/tui) WITHOUT publishing.
|
|
3
|
+
#
|
|
4
|
+
# Flow: build the bundle → register the repo's absolute path in
|
|
5
|
+
# .opencode/tui.json (read by the OpenCode TUI loader) → restart hint.
|
|
6
|
+
# It deliberately does NOT touch opencode.json: that file is packaged and
|
|
7
|
+
# merged into user configs by the installer, so a repo-relative path would
|
|
8
|
+
# leak into third-party installs and break the CI package gates.
|
|
9
|
+
#
|
|
10
|
+
# Usage: scripts/dev-tui.sh [--test]
|
|
11
|
+
# --test also run the full repo test suite (npm run test:all) after build.
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
15
|
+
TUI_DIR="$ROOT/src/plugins/tui"
|
|
16
|
+
TUI_JSON="$ROOT/.opencode/tui.json"
|
|
17
|
+
|
|
18
|
+
command -v npm >/dev/null 2>&1 || { echo "error: npm not found in PATH" >&2; exit 1; }
|
|
19
|
+
[ -d "$TUI_DIR" ] || { echo "error: TUI source not found: $TUI_DIR" >&2; exit 1; }
|
|
20
|
+
|
|
21
|
+
echo "==> TUI dev source: $TUI_DIR"
|
|
22
|
+
|
|
23
|
+
# 1. Install pinned deps + build dist/tui.js (dist/tui.tsx is copied by build).
|
|
24
|
+
echo "==> Installing TUI dev dependencies (npm ci)"
|
|
25
|
+
npm ci --prefix "$TUI_DIR" --ignore-scripts --no-audit --no-fund
|
|
26
|
+
|
|
27
|
+
echo "==> Building TUI plugin"
|
|
28
|
+
npm run build --prefix "$TUI_DIR"
|
|
29
|
+
|
|
30
|
+
# 2. Optional: full suite to match the CI gate before opening a PR.
|
|
31
|
+
if [[ "${1:-}" == "--test" ]]; then
|
|
32
|
+
echo "==> Running full test suite (npm run test:all)"
|
|
33
|
+
npm run test:all
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# 3. Register the repo path in the project tui.json (absolute, gitignored).
|
|
37
|
+
# Reuses the installer's registerPlugin so the array is merged, not clobbered.
|
|
38
|
+
echo "==> Registering repo TUI path in $TUI_JSON"
|
|
39
|
+
ROOT="$ROOT" TUI_JSON="$TUI_JSON" TUI_DIR="$TUI_DIR" node --input-type=module <<'NODE'
|
|
40
|
+
const { registerPlugin } = await import(`${process.env.ROOT}/scripts/install/plugin.mjs`)
|
|
41
|
+
const result = registerPlugin(process.env.TUI_JSON, process.env.TUI_DIR)
|
|
42
|
+
console.log(`${result}: ${process.env.TUI_DIR}`)
|
|
43
|
+
NODE
|
|
44
|
+
|
|
45
|
+
# 4. Restart hint + dev-mode caveat.
|
|
46
|
+
echo "==> Done. Restart OpenCode to load the rebuilt TUI plugin."
|
|
47
|
+
echo " Dev mode caveat: do NOT run 'init' in this repo while iterating — it"
|
|
48
|
+
echo " removes repo path refs as stale. If you do, re-run scripts/dev-tui.sh."
|
package/scripts/doctor.mjs
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import { spawn as spawnAsync, spawnSync } from 'node:child_process'
|
|
25
25
|
import { createHash } from 'node:crypto'
|
|
26
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs'
|
|
26
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs'
|
|
27
27
|
import { homedir } from 'node:os'
|
|
28
28
|
import { basename, dirname, join, resolve } from 'node:path'
|
|
29
29
|
import { fileURLToPath } from 'node:url'
|
|
@@ -959,6 +959,35 @@ function checkVenvLayer(args) {
|
|
|
959
959
|
// Check F.2: Code-Mode Scripts Directory
|
|
960
960
|
// ---------------------------------------------------------------------------
|
|
961
961
|
|
|
962
|
+
/**
|
|
963
|
+
* Return whether *dir* contains an executable code-mode target.
|
|
964
|
+
*
|
|
965
|
+
* Mirrors `_has_usable_scripts` in `scripts/code_mode_server.py`: a directory
|
|
966
|
+
* is only a valid resolver candidate when it is a real (non-symlink) directory
|
|
967
|
+
* containing a regular `.py`/`.sh` direct child. This prevents an empty project
|
|
968
|
+
* overlay from masking a lower-priority installation that actually ships
|
|
969
|
+
* scripts. Keep both implementations in sync (see tests/test_doctor_layers.mjs).
|
|
970
|
+
*/
|
|
971
|
+
function hasUsableScripts(dir) {
|
|
972
|
+
try {
|
|
973
|
+
if (!existsSync(dir)) return false
|
|
974
|
+
const stat = lstatSync(dir)
|
|
975
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) return false
|
|
976
|
+
return readdirSync(dir).some((name) => {
|
|
977
|
+
if (name.startsWith('.')) return false
|
|
978
|
+
const lower = name.toLowerCase()
|
|
979
|
+
if (!lower.endsWith('.py') && !lower.endsWith('.sh')) return false
|
|
980
|
+
try {
|
|
981
|
+
return statSync(join(dir, name)).isFile()
|
|
982
|
+
} catch {
|
|
983
|
+
return false
|
|
984
|
+
}
|
|
985
|
+
})
|
|
986
|
+
} catch {
|
|
987
|
+
return false
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
962
991
|
/**
|
|
963
992
|
* Verify the code-mode scripts directory exists for the resolved runtime
|
|
964
993
|
* root (project → <target>/.opencode, otherwise the global config dir).
|
|
@@ -977,7 +1006,7 @@ export function checkCodeModeDir(args) {
|
|
|
977
1006
|
// install (.opencode present) gets its runtime dir created when missing.
|
|
978
1007
|
// Only targets with no project layout fall back to the global config dir.
|
|
979
1008
|
const codeModeDir =
|
|
980
|
-
projectCandidates.find(
|
|
1009
|
+
projectCandidates.find(hasUsableScripts) ??
|
|
981
1010
|
(existsSync(join(target, '.opencode'))
|
|
982
1011
|
? projectCandidates[0]
|
|
983
1012
|
: join(resolveOpenCodeConfigDir(env), '.pantheon', 'code-mode'))
|
|
@@ -1003,7 +1032,7 @@ export function resolveCodeModeDir(args) {
|
|
|
1003
1032
|
join(target, '.opencode', '.pantheon', 'code-mode'),
|
|
1004
1033
|
join(target, '.pantheon', 'code-mode'),
|
|
1005
1034
|
]
|
|
1006
|
-
const projectDir = projectCandidates.find(
|
|
1035
|
+
const projectDir = projectCandidates.find(hasUsableScripts)
|
|
1007
1036
|
if (projectDir) return projectDir
|
|
1008
1037
|
return join(resolveOpenCodeConfigDir(env), '.pantheon', 'code-mode')
|
|
1009
1038
|
}
|
|
@@ -116,6 +116,27 @@ declare function delegationActivityLabel(entry: DelegationEntry): string;
|
|
|
116
116
|
/** Return a deterministic spinner frame. The View ticks this every 1000ms
|
|
117
117
|
* (not 140ms — the fast tick flickered without adding information). */
|
|
118
118
|
declare function delegationSpinnerFrame(now: number): string;
|
|
119
|
+
/** Every state the row knows how to draw: the real BackgroundJobBoard FSM
|
|
120
|
+
* (src/pantheon/background-job-board.ts) plus the TUI display-only states
|
|
121
|
+
* (`retry`, `stale-running`). Fase 1 deliberately omits speculative
|
|
122
|
+
* blocked/paused/scheduled/skipped. There is no `pending` display state: a
|
|
123
|
+
* pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
|
|
124
|
+
type DelegationDisplayState = DelegationEntry['state'];
|
|
125
|
+
/** Static glyph per display state. `running` shows its base spinner frame;
|
|
126
|
+
* callers that animate must prefer {@link delegationStateMarker}. Unicode
|
|
127
|
+
* geometric shapes only (no Nerd Font) — shape is an independent channel
|
|
128
|
+
* from color, so rows stay legible without color. */
|
|
129
|
+
declare const DELEGATION_STATE_GLYPHS: Readonly<Record<DelegationDisplayState, string>>;
|
|
130
|
+
declare function delegationStateGlyph(state: DelegationDisplayState): string;
|
|
131
|
+
/** Row marker (`<glyph> `) — the state channel. `running` animates through
|
|
132
|
+
* {@link delegationSpinnerFrame} for the given tick; every other state is
|
|
133
|
+
* static. Pure. */
|
|
134
|
+
declare function delegationStateMarker(state: DelegationDisplayState, now?: number): string;
|
|
135
|
+
/** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
|
|
136
|
+
* Kept separate + pure so the color channel is testable without booting the
|
|
137
|
+
* renderer. */
|
|
138
|
+
type DelegationStateTone = 'warning' | 'error' | 'success' | 'muted';
|
|
139
|
+
declare function delegationStateTone(state: DelegationDisplayState): DelegationStateTone;
|
|
119
140
|
type ToolActivity = {
|
|
120
141
|
tool: string;
|
|
121
142
|
summary: string;
|
|
@@ -413,5 +434,5 @@ declare const plugin: TuiPluginModule & {
|
|
|
413
434
|
setup: () => Promise<void>;
|
|
414
435
|
};
|
|
415
436
|
//#endregion
|
|
416
|
-
export { ChildDelegationLike, DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DelegationActivity, DelegationEntry, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, ToolActivity, TuiSessionSources, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, countDelegationSources, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationIcon, delegationSpinnerFrame, 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 };
|
|
437
|
+
export { ChildDelegationLike, DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DELEGATION_STATE_GLYPHS, DelegationActivity, DelegationDisplayState, DelegationEntry, DelegationStateTone, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, ToolActivity, TuiSessionSources, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, countDelegationSources, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationIcon, delegationSpinnerFrame, delegationStateGlyph, delegationStateMarker, delegationStateTone, delegationTag, extractToolActivity, fmtElapsed, formatDelegationElapsed, formatDelegationHeader, formatDelegationIdentity, formatDelegationRow, formatPanelLogLine, isValidSessionId, latestToolActivityFor, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, safeSessionPath, seedLiveDelegationMap, splitDelegationList, toDelegationEntry, trackToolActivity, truncateDelegationDescription, tuiLogPath, visibleDelegationList };
|
|
417
438
|
//# sourceMappingURL=tui.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;KAu7BY;;EAEV;;EAEA;;;;EAIA;;EAEA;EACA;;EAUA;;EAEA;EACA;EACA;;EAEA;;;;EAQA;;;;;;;;;;;iBAsBc,wBACd,aACA,oBACA,qBACC;;;;;;iBAkHmB,sBAAsB,cAAc,QAAQ;;;;;;;;iBAwC5C,yBAAyB,eAAe,QAAQ;;;;;;;;iBAWtD,sBACd;EAAS;EAAoB;eAC7B;;;;;;iBAYc,YAAY;;;iBAMZ,WAAW;;;;iBAOX,yBAAyB,GAAG,iBAAiB,GAAG;;;;;iBAahD,oBACd,cAAc,mBACd,oBACA,cACA;EACG,QAAQ;EAAmB,QAAQ;EAAmB,UAAU;;;;;iBAqBrD,sBACd,cAAc,mBACd,sBACA,cACA,4BACC;;cAMU;;;;cAKA;;;;;;;;;iBAUG,mBACd,OAAO,iBACP,aACA,uBACC;;;iBAWa,WAAW;;;;iBAeX,kBAAkB,OAAO,iBAAiB;;;KAQ9C;iBAQI,mBAAmB,OAAO,kBAAkB;iBAc5C,wBAAwB,OAAO;;;iBAsB/B,uBAAuB;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":"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"}
|
|
@@ -164,7 +164,7 @@ async function detectVersion(api) {
|
|
|
164
164
|
if (ver) return ver;
|
|
165
165
|
}
|
|
166
166
|
} catch {}
|
|
167
|
-
return "1.5.0-beta.
|
|
167
|
+
return "1.5.0-beta.11";
|
|
168
168
|
}
|
|
169
169
|
/**
|
|
170
170
|
* usage-bar — AI subscription usage gauge for the opencode TUI.
|
|
@@ -977,6 +977,49 @@ function delegationSpinnerFrame(now) {
|
|
|
977
977
|
const index = Math.floor(Math.max(0, now) / 1e3) % DELEGATION_SPINNER_FRAMES.length;
|
|
978
978
|
return DELEGATION_SPINNER_FRAMES[index] ?? DELEGATION_SPINNER_FRAMES[0];
|
|
979
979
|
}
|
|
980
|
+
/** Every state the row knows how to draw: the real BackgroundJobBoard FSM
|
|
981
|
+
* (src/pantheon/background-job-board.ts) plus the TUI display-only states
|
|
982
|
+
* (`retry`, `stale-running`). Fase 1 deliberately omits speculative
|
|
983
|
+
* blocked/paused/scheduled/skipped. There is no `pending` display state: a
|
|
984
|
+
* 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
|
+
/** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
|
|
1009
|
+
* Kept separate + pure so the color channel is testable without booting the
|
|
1010
|
+
* renderer. */
|
|
1011
|
+
function delegationStateTone(state) {
|
|
1012
|
+
switch (state) {
|
|
1013
|
+
case "running":
|
|
1014
|
+
case "retry":
|
|
1015
|
+
case "startup_unknown": return "warning";
|
|
1016
|
+
case "stale-running":
|
|
1017
|
+
case "error":
|
|
1018
|
+
case "startup_failed": return "error";
|
|
1019
|
+
case "completed": return "success";
|
|
1020
|
+
case "cancelled": return "muted";
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
980
1023
|
/** Bounded tracker: child session id → latest running tool call. */
|
|
981
1024
|
const latestToolActivity = /* @__PURE__ */ new Map();
|
|
982
1025
|
const MAX_TOOL_ACTIVITY_ENTRIES = 200;
|
|
@@ -1603,25 +1646,14 @@ function DelegationRow(props) {
|
|
|
1603
1646
|
const theme = () => props.api.theme.current;
|
|
1604
1647
|
const color = createMemo(() => {
|
|
1605
1648
|
const t = theme();
|
|
1606
|
-
switch (props.job.state) {
|
|
1607
|
-
case "
|
|
1608
|
-
case "retry": return t.warning;
|
|
1609
|
-
case "stale-running": return t.error;
|
|
1610
|
-
case "completed": return t.success;
|
|
1649
|
+
switch (delegationStateTone(props.job.state)) {
|
|
1650
|
+
case "warning": return t.warning;
|
|
1611
1651
|
case "error": return t.error;
|
|
1652
|
+
case "success": return t.success;
|
|
1612
1653
|
default: return t.textMuted;
|
|
1613
1654
|
}
|
|
1614
1655
|
});
|
|
1615
|
-
const marker = createMemo(() =>
|
|
1616
|
-
if (props.job.state === "running") return `${delegationSpinnerFrame(props.animationNow)} `;
|
|
1617
|
-
if (props.job.state === "retry") return "⟳ ";
|
|
1618
|
-
if (props.job.state === "stale-running") return "⚠ ";
|
|
1619
|
-
switch (props.job.state) {
|
|
1620
|
-
case "completed": return "✓ ";
|
|
1621
|
-
case "error": return "✕ ";
|
|
1622
|
-
default: return "○ ";
|
|
1623
|
-
}
|
|
1624
|
-
});
|
|
1656
|
+
const marker = createMemo(() => delegationStateMarker(props.job.state, props.animationNow));
|
|
1625
1657
|
const tagColor = createMemo(() => props.job.source === "children-only" ? theme().info : color());
|
|
1626
1658
|
const description = createMemo(() => truncateDelegationDescription(props.job.description));
|
|
1627
1659
|
const elapsed = createMemo(() => formatDelegationElapsed(props.job, props.now));
|
|
@@ -2141,6 +2173,6 @@ const plugin = {
|
|
|
2141
2173
|
setup: async () => {}
|
|
2142
2174
|
};
|
|
2143
2175
|
//#endregion
|
|
2144
|
-
export { DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, IDLE_SILENCE_MS, STALE_RUNNING_THRESHOLD_MS, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, countDelegationSources, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationIcon, delegationSpinnerFrame, 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 };
|
|
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 };
|
|
2145
2177
|
|
|
2146
2178
|
//# sourceMappingURL=tui.js.map
|
|
@@ -1354,6 +1354,62 @@ export function delegationSpinnerFrame(now: number): string {
|
|
|
1354
1354
|
return DELEGATION_SPINNER_FRAMES[index] ?? DELEGATION_SPINNER_FRAMES[0]
|
|
1355
1355
|
}
|
|
1356
1356
|
|
|
1357
|
+
/** Every state the row knows how to draw: the real BackgroundJobBoard FSM
|
|
1358
|
+
* (src/pantheon/background-job-board.ts) plus the TUI display-only states
|
|
1359
|
+
* (`retry`, `stale-running`). Fase 1 deliberately omits speculative
|
|
1360
|
+
* blocked/paused/scheduled/skipped. There is no `pending` display state: a
|
|
1361
|
+
* pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
|
|
1362
|
+
export type DelegationDisplayState = DelegationEntry['state']
|
|
1363
|
+
|
|
1364
|
+
/** Static glyph per display state. `running` shows its base spinner frame;
|
|
1365
|
+
* callers that animate must prefer {@link delegationStateMarker}. Unicode
|
|
1366
|
+
* geometric shapes only (no Nerd Font) — shape is an independent channel
|
|
1367
|
+
* from color, so rows stay legible without color. */
|
|
1368
|
+
export const DELEGATION_STATE_GLYPHS: Readonly<Record<DelegationDisplayState, string>> = {
|
|
1369
|
+
running: '\u280b', // ⠋ base frame of the animated spinner
|
|
1370
|
+
retry: '\u27f3', // ⟳ retrying
|
|
1371
|
+
'stale-running': '\u26a0', // ⚠ stale (display-only alert)
|
|
1372
|
+
completed: '\u2713', // ✓
|
|
1373
|
+
error: '\u2715', // ✕
|
|
1374
|
+
cancelled: '\u2212', // − minus: stopped, distinct from error's ✕
|
|
1375
|
+
startup_failed: '\u26a0', // ⚠ boot failed
|
|
1376
|
+
startup_unknown: '\u26a0', // ⚠ boot outcome unknown
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
export function delegationStateGlyph(state: DelegationDisplayState): string {
|
|
1380
|
+
return DELEGATION_STATE_GLYPHS[state]
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/** Row marker (`<glyph> `) — the state channel. `running` animates through
|
|
1384
|
+
* {@link delegationSpinnerFrame} for the given tick; every other state is
|
|
1385
|
+
* static. Pure. */
|
|
1386
|
+
export function delegationStateMarker(state: DelegationDisplayState, now = Date.now()): string {
|
|
1387
|
+
const glyph = state === 'running' ? delegationSpinnerFrame(now) : delegationStateGlyph(state)
|
|
1388
|
+
return `${glyph} `
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
/** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
|
|
1392
|
+
* Kept separate + pure so the color channel is testable without booting the
|
|
1393
|
+
* renderer. */
|
|
1394
|
+
export type DelegationStateTone = 'warning' | 'error' | 'success' | 'muted'
|
|
1395
|
+
|
|
1396
|
+
export function delegationStateTone(state: DelegationDisplayState): DelegationStateTone {
|
|
1397
|
+
switch (state) {
|
|
1398
|
+
case 'running':
|
|
1399
|
+
case 'retry':
|
|
1400
|
+
case 'startup_unknown':
|
|
1401
|
+
return 'warning'
|
|
1402
|
+
case 'stale-running':
|
|
1403
|
+
case 'error':
|
|
1404
|
+
case 'startup_failed':
|
|
1405
|
+
return 'error'
|
|
1406
|
+
case 'completed':
|
|
1407
|
+
return 'success'
|
|
1408
|
+
case 'cancelled':
|
|
1409
|
+
return 'muted'
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1357
1413
|
/* ─── Live tool activity per child session (beta.6) ────────────────────────
|
|
1358
1414
|
* The delegation panel's activity line ("↳ bash npm test") — what the agent
|
|
1359
1415
|
* is doing RIGHT NOW. Sourced from message.part.updated tool parts: every
|
|
@@ -2351,35 +2407,19 @@ function DelegationRow(props: {
|
|
|
2351
2407
|
|
|
2352
2408
|
const color = createMemo(() => {
|
|
2353
2409
|
const t = theme()
|
|
2354
|
-
switch (props.job.state) {
|
|
2355
|
-
case '
|
|
2356
|
-
return t.warning
|
|
2357
|
-
case 'retry':
|
|
2410
|
+
switch (delegationStateTone(props.job.state)) {
|
|
2411
|
+
case 'warning':
|
|
2358
2412
|
return t.warning
|
|
2359
|
-
case 'stale-running':
|
|
2360
|
-
return t.error // warning color for stale delegations
|
|
2361
|
-
case 'completed':
|
|
2362
|
-
return t.success
|
|
2363
2413
|
case 'error':
|
|
2364
2414
|
return t.error
|
|
2415
|
+
case 'success':
|
|
2416
|
+
return t.success
|
|
2365
2417
|
default:
|
|
2366
|
-
return t.textMuted // cancelled
|
|
2418
|
+
return t.textMuted // muted (cancelled)
|
|
2367
2419
|
}
|
|
2368
2420
|
})
|
|
2369
2421
|
|
|
2370
|
-
const marker = createMemo(() =>
|
|
2371
|
-
if (props.job.state === 'running') return `${delegationSpinnerFrame(props.animationNow)} `
|
|
2372
|
-
if (props.job.state === 'retry') return '\u27f3 ' // ⟳ retrying
|
|
2373
|
-
if (props.job.state === 'stale-running') return '\u26a0 ' // warning triangle
|
|
2374
|
-
switch (props.job.state) {
|
|
2375
|
-
case 'completed':
|
|
2376
|
-
return '\u2713 '
|
|
2377
|
-
case 'error':
|
|
2378
|
-
return '\u2715 '
|
|
2379
|
-
default:
|
|
2380
|
-
return '\u25cb '
|
|
2381
|
-
}
|
|
2382
|
-
})
|
|
2422
|
+
const marker = createMemo(() => delegationStateMarker(props.job.state, props.animationNow))
|
|
2383
2423
|
|
|
2384
2424
|
// Two visual channels split native task() from pantheon_delegate: the tag
|
|
2385
2425
|
// prefix (`nat:`/`pan:`, via delegationTag) and the glyph color — info
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-tui",
|
|
3
|
-
"version": "1.5.0-beta.
|
|
3
|
+
"version": "1.5.0-beta.11",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pantheon-tui",
|
|
9
|
-
"version": "1.5.0-beta.
|
|
9
|
+
"version": "1.5.0-beta.11",
|
|
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.
|
|
4
|
+
"version": "1.5.0-beta.11",
|
|
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": {
|
|
@@ -1354,6 +1354,62 @@ export function delegationSpinnerFrame(now: number): string {
|
|
|
1354
1354
|
return DELEGATION_SPINNER_FRAMES[index] ?? DELEGATION_SPINNER_FRAMES[0]
|
|
1355
1355
|
}
|
|
1356
1356
|
|
|
1357
|
+
/** Every state the row knows how to draw: the real BackgroundJobBoard FSM
|
|
1358
|
+
* (src/pantheon/background-job-board.ts) plus the TUI display-only states
|
|
1359
|
+
* (`retry`, `stale-running`). Fase 1 deliberately omits speculative
|
|
1360
|
+
* blocked/paused/scheduled/skipped. There is no `pending` display state: a
|
|
1361
|
+
* pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
|
|
1362
|
+
export type DelegationDisplayState = DelegationEntry['state']
|
|
1363
|
+
|
|
1364
|
+
/** Static glyph per display state. `running` shows its base spinner frame;
|
|
1365
|
+
* callers that animate must prefer {@link delegationStateMarker}. Unicode
|
|
1366
|
+
* geometric shapes only (no Nerd Font) — shape is an independent channel
|
|
1367
|
+
* from color, so rows stay legible without color. */
|
|
1368
|
+
export const DELEGATION_STATE_GLYPHS: Readonly<Record<DelegationDisplayState, string>> = {
|
|
1369
|
+
running: '\u280b', // ⠋ base frame of the animated spinner
|
|
1370
|
+
retry: '\u27f3', // ⟳ retrying
|
|
1371
|
+
'stale-running': '\u26a0', // ⚠ stale (display-only alert)
|
|
1372
|
+
completed: '\u2713', // ✓
|
|
1373
|
+
error: '\u2715', // ✕
|
|
1374
|
+
cancelled: '\u2212', // − minus: stopped, distinct from error's ✕
|
|
1375
|
+
startup_failed: '\u26a0', // ⚠ boot failed
|
|
1376
|
+
startup_unknown: '\u26a0', // ⚠ boot outcome unknown
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
export function delegationStateGlyph(state: DelegationDisplayState): string {
|
|
1380
|
+
return DELEGATION_STATE_GLYPHS[state]
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/** Row marker (`<glyph> `) — the state channel. `running` animates through
|
|
1384
|
+
* {@link delegationSpinnerFrame} for the given tick; every other state is
|
|
1385
|
+
* static. Pure. */
|
|
1386
|
+
export function delegationStateMarker(state: DelegationDisplayState, now = Date.now()): string {
|
|
1387
|
+
const glyph = state === 'running' ? delegationSpinnerFrame(now) : delegationStateGlyph(state)
|
|
1388
|
+
return `${glyph} `
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
/** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
|
|
1392
|
+
* Kept separate + pure so the color channel is testable without booting the
|
|
1393
|
+
* renderer. */
|
|
1394
|
+
export type DelegationStateTone = 'warning' | 'error' | 'success' | 'muted'
|
|
1395
|
+
|
|
1396
|
+
export function delegationStateTone(state: DelegationDisplayState): DelegationStateTone {
|
|
1397
|
+
switch (state) {
|
|
1398
|
+
case 'running':
|
|
1399
|
+
case 'retry':
|
|
1400
|
+
case 'startup_unknown':
|
|
1401
|
+
return 'warning'
|
|
1402
|
+
case 'stale-running':
|
|
1403
|
+
case 'error':
|
|
1404
|
+
case 'startup_failed':
|
|
1405
|
+
return 'error'
|
|
1406
|
+
case 'completed':
|
|
1407
|
+
return 'success'
|
|
1408
|
+
case 'cancelled':
|
|
1409
|
+
return 'muted'
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1357
1413
|
/* ─── Live tool activity per child session (beta.6) ────────────────────────
|
|
1358
1414
|
* The delegation panel's activity line ("↳ bash npm test") — what the agent
|
|
1359
1415
|
* is doing RIGHT NOW. Sourced from message.part.updated tool parts: every
|
|
@@ -2351,35 +2407,19 @@ function DelegationRow(props: {
|
|
|
2351
2407
|
|
|
2352
2408
|
const color = createMemo(() => {
|
|
2353
2409
|
const t = theme()
|
|
2354
|
-
switch (props.job.state) {
|
|
2355
|
-
case '
|
|
2356
|
-
return t.warning
|
|
2357
|
-
case 'retry':
|
|
2410
|
+
switch (delegationStateTone(props.job.state)) {
|
|
2411
|
+
case 'warning':
|
|
2358
2412
|
return t.warning
|
|
2359
|
-
case 'stale-running':
|
|
2360
|
-
return t.error // warning color for stale delegations
|
|
2361
|
-
case 'completed':
|
|
2362
|
-
return t.success
|
|
2363
2413
|
case 'error':
|
|
2364
2414
|
return t.error
|
|
2415
|
+
case 'success':
|
|
2416
|
+
return t.success
|
|
2365
2417
|
default:
|
|
2366
|
-
return t.textMuted // cancelled
|
|
2418
|
+
return t.textMuted // muted (cancelled)
|
|
2367
2419
|
}
|
|
2368
2420
|
})
|
|
2369
2421
|
|
|
2370
|
-
const marker = createMemo(() =>
|
|
2371
|
-
if (props.job.state === 'running') return `${delegationSpinnerFrame(props.animationNow)} `
|
|
2372
|
-
if (props.job.state === 'retry') return '\u27f3 ' // ⟳ retrying
|
|
2373
|
-
if (props.job.state === 'stale-running') return '\u26a0 ' // warning triangle
|
|
2374
|
-
switch (props.job.state) {
|
|
2375
|
-
case 'completed':
|
|
2376
|
-
return '\u2713 '
|
|
2377
|
-
case 'error':
|
|
2378
|
-
return '\u2715 '
|
|
2379
|
-
default:
|
|
2380
|
-
return '\u25cb '
|
|
2381
|
-
}
|
|
2382
|
-
})
|
|
2422
|
+
const marker = createMemo(() => delegationStateMarker(props.job.state, props.animationNow))
|
|
2383
2423
|
|
|
2384
2424
|
// Two visual channels split native task() from pantheon_delegate: the tag
|
|
2385
2425
|
// prefix (`nat:`/`pan:`, via delegationTag) and the glyph color — info
|