pantheon-opencode 1.5.0-beta.10 → 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.
- package/CHANGELOG.md +44 -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/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 +90 -8
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +355 -104
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +2 -2
- package/src/plugins/tui/src/index.tsx +410 -59
- package/src/plugins/tui/dist/tui.tsx +0 -2968
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,50 @@ 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.12] - 2026-09-14
|
|
22
|
+
|
|
23
|
+
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
|
24
|
+
move this section to a versioned entry and reset the template below. -->
|
|
25
|
+
|
|
26
|
+
## 🆕 What's New
|
|
27
|
+
|
|
28
|
+
- **TUI lê o board (4º canal):** o painel Delegations passa a ler o
|
|
29
|
+
BackgroundJobBoard via `readBoardState()` — jobs `pantheon_delegate` de todas
|
|
30
|
+
as sessões aparecem, não só os filhos nativos da sessão focada.
|
|
31
|
+
- **Toggle [Sessão]/[Tudo] + chips:** `[Sessão]` (default) mostra só a sessão
|
|
32
|
+
focada, `[Tudo]` mostra jobs de todas as sessões; chips clicáveis no header.
|
|
33
|
+
- **Raw `dist/tui.tsx` removido (bundle-only):** o dist passa a carregar só o
|
|
34
|
+
bundle compilado (`tui.js`); o fonte raw sai do pacote publicado.
|
|
35
|
+
- **117 testes TUI delegations:** `tests/pantheon/tui-delegations.test.ts` com
|
|
36
|
+
117/117 passando, cobrindo board-read, split ativo/recente e toggle de escopo.
|
|
37
|
+
## [v1.5.0-beta.11] - 2026-09-14
|
|
38
|
+
|
|
39
|
+
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
|
40
|
+
move this section to a versioned entry and reset the template below. -->
|
|
41
|
+
|
|
42
|
+
## 🆕 What's New
|
|
43
|
+
|
|
44
|
+
- **Glyphs da FSM real no painel Delegations:** cada estado do BackgroundJobBoard
|
|
45
|
+
tem agora um glifo Unicode geométrico próprio — `⠋` running (spinner 1s),
|
|
46
|
+
`⟳` retry, `⚠` stale/startup, `✓` completed, `✕` error, `−` cancelled. Forma e
|
|
47
|
+
cor são canais independentes: as linhas seguem legíveis sem cor e sem Nerd Font.
|
|
48
|
+
- **Prefixo `nat:` / `pan:` documentado:** `docs/INSTALLATION.md` passa a
|
|
49
|
+
descrever os prefixos curtos das linhas nativas (`nat:<agent>`) e do board
|
|
50
|
+
(`pan:<alias>`) e o par de glyphs ◇/◆.
|
|
51
|
+
- **`scripts/dev-tui.sh` (dev local sem publish):** instala, builda e registra o
|
|
52
|
+
caminho absoluto do repo em `.opencode/tui.json` (gitignored) com hint de
|
|
53
|
+
restart — sem tocar `opencode.json` e sem publicar.
|
|
54
|
+
- **104 testes TUI delegations:** `tests/pantheon/tui-delegations.test.ts` com
|
|
55
|
+
104/104 passando, cobrindo glifos/marker/tone dos estados reais da FSM.
|
|
56
|
+
|
|
57
|
+
## 🐞 Fixed
|
|
58
|
+
|
|
59
|
+
- **Doctor F.2 (`hasUsableScripts`):** a resolução do diretório code-mode agora
|
|
60
|
+
exige um `.py`/`.sh` regular (paridade com `_has_usable_scripts` do MCP), então
|
|
61
|
+
um overlay de projeto vazio não mascara mais uma instalação que traz scripts.
|
|
62
|
+
- **`publish:next` órfão removido:** nenhum workflow usava o script (o release
|
|
63
|
+
publica via `--tag beta`); removido do `package.json` para eliminar o dist-tag
|
|
64
|
+
`next` obsoleto da linha de publicação.
|
|
21
65
|
## [v1.5.0-beta.10] - 2026-09-14
|
|
22
66
|
|
|
23
67
|
<!-- 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.12",
|
|
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.12",
|
|
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 (the bundle is the only load path).
|
|
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
|
}
|
|
@@ -8,8 +8,10 @@ import { isAbsolute, join, resolve } from 'node:path'
|
|
|
8
8
|
import { ROOT, writeIfChanged } from './shared.mjs'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Copy a plugin's runtime payload (
|
|
12
|
-
* package
|
|
11
|
+
* Copy a plugin's runtime payload (the bundled dist/*, package.json and
|
|
12
|
+
* package-lock.json) from source to destination. Only the bundle is copied —
|
|
13
|
+
* the raw TSX source is never shipped to the destination, so the plugin can
|
|
14
|
+
* be modularized without the loader needing relative imports.
|
|
13
15
|
* @param {string} srcDir - Source plugin directory (e.g. ROOT/src/plugins/tui)
|
|
14
16
|
* @param {string} dstDir - Destination plugin directory
|
|
15
17
|
* @param {object} [options]
|
|
@@ -22,16 +24,11 @@ export function copyPluginFiles(srcDir, dstDir, { dryRun = false } = {}) {
|
|
|
22
24
|
if (!dryRun) mkdirSync(dstDir, { recursive: true })
|
|
23
25
|
if (!dryRun) mkdirSync(join(dstDir, 'dist'), { recursive: true })
|
|
24
26
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
readFileSync(srcIdx, 'utf8'),
|
|
31
|
-
dryRun,
|
|
32
|
-
)
|
|
33
|
-
if (idxStatus === 'created') result.created++
|
|
34
|
-
else result.skipped++
|
|
27
|
+
// Drop legacy raw copies from previous installs (root index.tsx + dist/tui.tsx).
|
|
28
|
+
// The loader consumes only the bundle, so stale raws must not linger.
|
|
29
|
+
if (!dryRun) {
|
|
30
|
+
rmSync(join(dstDir, 'index.tsx'), { force: true })
|
|
31
|
+
rmSync(join(dstDir, 'dist', 'tui.tsx'), { force: true })
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
// Copy dist/* files
|
package/scripts/sync-tui.mjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* If the user hasn't initialized yet → do nothing (silent exit).
|
|
11
11
|
*/
|
|
12
12
|
import { execSync } from 'node:child_process'
|
|
13
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
13
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
14
14
|
import { homedir } from 'node:os'
|
|
15
15
|
import { join } from 'node:path'
|
|
16
16
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
@@ -58,9 +58,9 @@ function resolveConfigDir() {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* Copy plugin runtime files (dist/*, package.json,
|
|
62
|
-
*
|
|
63
|
-
*
|
|
61
|
+
* Copy plugin runtime files (the bundled dist/*, package.json,
|
|
62
|
+
* package-lock.json) from srcDir to dstDir. Skips files that are byte-identical.
|
|
63
|
+
* The raw TSX source is never copied — the loader consumes only the bundle.
|
|
64
64
|
* @returns {{ created: number, skipped: number }}
|
|
65
65
|
*/
|
|
66
66
|
function copyPluginFiles(srcDir, dstDir) {
|
|
@@ -69,13 +69,10 @@ function copyPluginFiles(srcDir, dstDir) {
|
|
|
69
69
|
mkdirSync(dstDir, { recursive: true })
|
|
70
70
|
mkdirSync(join(dstDir, 'dist'), { recursive: true })
|
|
71
71
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (writeIfChanged(join(dstDir, 'index.tsx'), content)) result.created++
|
|
77
|
-
else result.skipped++
|
|
78
|
-
}
|
|
72
|
+
// Drop legacy raw copies from previous installs (root index.tsx + dist/tui.tsx).
|
|
73
|
+
// The loader consumes only the bundle, so stale raws must not linger.
|
|
74
|
+
rmSync(join(dstDir, 'index.tsx'), { force: true })
|
|
75
|
+
rmSync(join(dstDir, 'dist', 'tui.tsx'), { force: true })
|
|
79
76
|
|
|
80
77
|
// dist/*
|
|
81
78
|
const distSrc = join(srcDir, 'dist')
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* never throw, never send the placeholder).
|
|
11
11
|
*
|
|
12
12
|
* Mirrors the TUI's `src/plugins/tui/src/index.tsx` contract verbatim so both
|
|
13
|
-
* sides agree on what "valid" means. The TUI
|
|
14
|
-
* (dist/tui.
|
|
13
|
+
* sides agree on what "valid" means. The TUI plugin ships as a bundle
|
|
14
|
+
* (dist/tui.js) without the src/pantheon tree, so its local copy is kept
|
|
15
15
|
* in sync — this module is the shared source for `src/pantheon/*` and
|
|
16
16
|
* `src/plugin.ts`.
|
|
17
17
|
*
|
|
@@ -22,8 +22,9 @@ type DelegationEntry = {
|
|
|
22
22
|
read?: boolean;
|
|
23
23
|
/** Internal provenance used to keep a finalized md report authoritative.
|
|
24
24
|
* 'children-only' = a native task() child session with NO board report
|
|
25
|
-
* (rendered with the distinct `nat:` prefix); 'md' = board report wins
|
|
26
|
-
|
|
25
|
+
* (rendered with the distinct `nat:` prefix); 'md' = board report wins;
|
|
26
|
+
* 'board' = read from .pantheon/board/state.json (cross-session FSM). */
|
|
27
|
+
source?: 'child' | 'live' | 'md' | 'children-only' | 'board';
|
|
27
28
|
};
|
|
28
29
|
/** Parse one delegation report md header into a structured entry.
|
|
29
30
|
* Returns null (skip) when the file is not a recognizable report:
|
|
@@ -49,13 +50,39 @@ declare function readDelegationEntries(dir: string): Promise<DelegationEntry[]>;
|
|
|
49
50
|
* desc — the sort applied by readDelegationEntries). Fail-open: a
|
|
50
51
|
* missing/unreadable directory yields []. */
|
|
51
52
|
declare function readAllDelegationEntries(root: string): Promise<DelegationEntry[]>;
|
|
53
|
+
/** The persisted subset of BackgroundJobRecord the panel consumes. Duck-typed
|
|
54
|
+
* so a corrupt/older record never breaks parsing. */
|
|
55
|
+
type BoardJobRecord = {
|
|
56
|
+
taskID: string;
|
|
57
|
+
parentSessionID: string;
|
|
58
|
+
agent: string;
|
|
59
|
+
description?: string;
|
|
60
|
+
state: string;
|
|
61
|
+
alias: string;
|
|
62
|
+
launchedAt?: number;
|
|
63
|
+
completedAt?: number;
|
|
64
|
+
updatedAt?: number;
|
|
65
|
+
timedOut?: boolean;
|
|
66
|
+
};
|
|
67
|
+
/** The FilePersistence state path: `<root>/.pantheon/board/state.json`. */
|
|
68
|
+
declare function boardStatePath(root: string): string;
|
|
69
|
+
/** Read `.pantheon/board/state.json` (the cross-session job board snapshot).
|
|
70
|
+
* Fail-open: missing file, corrupt JSON, non-array payload or an unreadable
|
|
71
|
+
* path all yield [] — the panel keeps rendering from the other channels. */
|
|
72
|
+
declare function readBoardState(root: string): Promise<BoardJobRecord[]>;
|
|
73
|
+
/** Resolve the PROJECT ROOT used by every pantheon file channel. `directory`
|
|
74
|
+
* wins over `worktree` (the old `resolveDelegationsDir` already did this);
|
|
75
|
+
* an absent/empty root or `/` (no git — e.g. the sandbox test project) falls
|
|
76
|
+
* back to cwd. Standardised here so the delegations md, the board state file
|
|
77
|
+
* and the panel logger all read the SAME root (audit finding: the channels
|
|
78
|
+
* resolved the root independently). Pure — no I/O. */
|
|
79
|
+
declare function resolvePantheonRoot(state: {
|
|
80
|
+
directory?: string;
|
|
81
|
+
worktree?: string;
|
|
82
|
+
} | undefined, cwd?: string): string;
|
|
52
83
|
/** Resolve the directory where the job board writes delegation md reports.
|
|
53
84
|
* The board writes `.pantheon/delegations` RELATIVE to the server cwd,
|
|
54
|
-
* which the TUI exposes as `TuiState.path.directory`.
|
|
55
|
-
* exist on `TuiState.path` (the old `state?.project ?? state?.worktree`
|
|
56
|
-
* resolution was always undefined for the first term) and `worktree` is
|
|
57
|
-
* `/` when there is no git (e.g. the sandbox test project) — a root of
|
|
58
|
-
* `''` or `'/'` must fall back to `process.cwd()`. */
|
|
85
|
+
* which the TUI exposes as `TuiState.path.directory`. */
|
|
59
86
|
declare function resolveDelegationsDir(state: {
|
|
60
87
|
directory?: string;
|
|
61
88
|
worktree?: string;
|
|
@@ -116,6 +143,27 @@ declare function delegationActivityLabel(entry: DelegationEntry): string;
|
|
|
116
143
|
/** Return a deterministic spinner frame. The View ticks this every 1000ms
|
|
117
144
|
* (not 140ms — the fast tick flickered without adding information). */
|
|
118
145
|
declare function delegationSpinnerFrame(now: number): string;
|
|
146
|
+
/** Every state the row knows how to draw: the real BackgroundJobBoard FSM
|
|
147
|
+
* (src/pantheon/background-job-board.ts) plus the TUI display-only states
|
|
148
|
+
* (`retry`, `stale-running`). Fase 1 deliberately omits speculative
|
|
149
|
+
* blocked/paused/scheduled/skipped. There is no `pending` display state: a
|
|
150
|
+
* pre-dispatch tool part maps to `running` in {@link reduceDelegationToolPart}. */
|
|
151
|
+
type DelegationDisplayState = DelegationEntry['state'];
|
|
152
|
+
/** Static glyph per display state. `running` shows its base spinner frame;
|
|
153
|
+
* callers that animate must prefer {@link delegationStateMarker}. Unicode
|
|
154
|
+
* geometric shapes only (no Nerd Font) — shape is an independent channel
|
|
155
|
+
* from color, so rows stay legible without color. */
|
|
156
|
+
declare const DELEGATION_STATE_GLYPHS: Readonly<Record<DelegationDisplayState, string>>;
|
|
157
|
+
declare function delegationStateGlyph(state: DelegationDisplayState): string;
|
|
158
|
+
/** Row marker (`<glyph> `) — the state channel. `running` animates through
|
|
159
|
+
* {@link delegationSpinnerFrame} for the given tick; every other state is
|
|
160
|
+
* static. Pure. */
|
|
161
|
+
declare function delegationStateMarker(state: DelegationDisplayState, now?: number): string;
|
|
162
|
+
/** Semantic tone mapped to the TUI theme at the row ({@link DelegationRow}).
|
|
163
|
+
* Kept separate + pure so the color channel is testable without booting the
|
|
164
|
+
* renderer. */
|
|
165
|
+
type DelegationStateTone = 'warning' | 'error' | 'success' | 'muted';
|
|
166
|
+
declare function delegationStateTone(state: DelegationDisplayState): DelegationStateTone;
|
|
119
167
|
type ToolActivity = {
|
|
120
168
|
tool: string;
|
|
121
169
|
summary: string;
|
|
@@ -240,6 +288,40 @@ declare function toDelegationEntry(live: LiveDelegationEntry): DelegationEntry;
|
|
|
240
288
|
* terminal md entry is authoritative over a live running entry for the
|
|
241
289
|
* same job (it carries Finalized/timedOut/cancelled from finalize). */
|
|
242
290
|
declare function mergeDelegationSources(live: readonly LiveDelegationEntry[], md: readonly DelegationEntry[]): DelegationEntry[];
|
|
291
|
+
/** Map one persisted board record into the display shape. Returns null for
|
|
292
|
+
* states the panel does not render (reconciled / unknown). Pure. */
|
|
293
|
+
declare function boardRecordToDelegationEntry(record: BoardJobRecord): DelegationEntry | null;
|
|
294
|
+
/** Map a whole board snapshot, dropping unrenderable states. Sorted like every
|
|
295
|
+
* other channel (running first, then most recent). Pure. */
|
|
296
|
+
declare function boardRecordsToDelegationEntries(records: readonly BoardJobRecord[]): DelegationEntry[];
|
|
297
|
+
/** Merge the board over any other channel. The board is AUTHORITATIVE for
|
|
298
|
+
* state/alias/agent (it is the persisted FSM) and it is the only channel
|
|
299
|
+
* that carries jobs from OTHER sessions. Dedup by taskID first, then by
|
|
300
|
+
* (sessionID, alias) — aliases are per parent session. Pure. */
|
|
301
|
+
declare function mergeBoardDelegationSources(base: readonly DelegationEntry[], board: readonly DelegationEntry[]): DelegationEntry[];
|
|
302
|
+
/** 'session' = focused session only (default); 'all' = every session the
|
|
303
|
+
* board knows about. */
|
|
304
|
+
type DelegationScope = 'session' | 'all';
|
|
305
|
+
/** api.kv key holding the persisted scope (defaults to 'session'). */
|
|
306
|
+
declare const DELEGATION_SCOPE_KV_KEY = "delegations.scope";
|
|
307
|
+
/** Structural subset of TuiKV — kept local so the pure helpers are testable
|
|
308
|
+
* without the TUI runtime. */
|
|
309
|
+
type DelegationScopeKv = {
|
|
310
|
+
get: (key: string, fallback?: unknown) => unknown;
|
|
311
|
+
set: (key: string, value: unknown) => void;
|
|
312
|
+
};
|
|
313
|
+
/** Read the persisted scope; anything malformed/absent → 'session'. */
|
|
314
|
+
declare function readDelegationScope(kv: DelegationScopeKv | undefined): DelegationScope;
|
|
315
|
+
/** Persist the scope. Failure is non-fatal — the signal keeps it in memory. */
|
|
316
|
+
declare function writeDelegationScope(kv: DelegationScopeKv | undefined, scope: DelegationScope): void;
|
|
317
|
+
/** Keyboard/click toggle target. Pure. */
|
|
318
|
+
declare function nextDelegationScope(scope: DelegationScope): DelegationScope;
|
|
319
|
+
/** Keep only the focused session's jobs ('session') or all of them ('all').
|
|
320
|
+
* An empty sessionID marks a current-session child (the children channel is
|
|
321
|
+
* session-scoped and only fills sessionID from a matching md report), so it
|
|
322
|
+
* counts as the current session. With no resolved session there is nothing
|
|
323
|
+
* to scope against — fail-open to the full list. Pure. */
|
|
324
|
+
declare function filterDelegationsByScope(entries: readonly DelegationEntry[], scope: DelegationScope, sessionID: string | null): DelegationEntry[];
|
|
243
325
|
/** Server-aligned session id validity: opencode rejects anything not starting
|
|
244
326
|
* with "ses" (SchemaError). This deliberately mirrors that exact contract —
|
|
245
327
|
* nothing stricter, nothing looser — so a template placeholder ("{sessionID}"),
|
|
@@ -413,5 +495,5 @@ declare const plugin: TuiPluginModule & {
|
|
|
413
495
|
setup: () => Promise<void>;
|
|
414
496
|
};
|
|
415
497
|
//#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 };
|
|
498
|
+
export { BoardJobRecord, ChildDelegationLike, DELEGATION_DESCRIPTION_MAX, DELEGATION_ELAPSED_WIDTH, DELEGATION_SCOPE_KV_KEY, DELEGATION_STATE_GLYPHS, DelegationActivity, DelegationDisplayState, DelegationEntry, DelegationScope, DelegationScopeKv, DelegationStateTone, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, ToolActivity, TuiSessionSources, 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 };
|
|
417
499
|
//# sourceMappingURL=tui.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":"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"}
|