pantheon-opencode 1.4.3 → 1.5.0-beta.1
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/.pantheon/code-mode/.gitkeep +0 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-1.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-10.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-11.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-2.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-3.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-4.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-5.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-6.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-7.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-8.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-9.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/heartbeat.json +8 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/session.json +11 -0
- package/.pantheon/code-mode/README.md +93 -0
- package/.pantheon/code-mode/checkpoint-session.py +7 -0
- package/.pantheon/code-mode/checkpoint-session.sh +11 -0
- package/.pantheon/code-mode/checkpoint_session.py +481 -0
- package/.pantheon/code-mode/compress-inline.py +450 -0
- package/.pantheon/code-mode/eval-llm-judge.py +255 -0
- package/.pantheon/code-mode/eval-monte-carlo.py +368 -0
- package/.pantheon/code-mode/eval-run.py +197 -0
- package/.pantheon/code-mode/eval-static.py +321 -0
- package/.pantheon/code-mode/example-sync.sh +5 -0
- package/.pantheon/code-mode/session-end-save.py +186 -0
- package/.pantheon/code-mode/session-end-save.sh +18 -0
- package/.pantheon/code-mode/test-allowed.sh +5 -0
- package/.pantheon/code-mode/test-auto-continue-checkpoint.sh +179 -0
- package/.pantheon/code-mode/test-env.sh +7 -0
- package/.pantheon/code-mode/test-prlimit.sh +9 -0
- package/.pantheon/code-mode/test-timeout.sh +6 -0
- package/README.md +158 -1101
- package/README.pt-BR.md +222 -0
- package/bin/pantheon-init.mjs +30 -11
- package/opencode.json +1 -0
- package/package.json +14 -3
- package/plugin.json +15 -0
- package/scripts/_pantheon_paths.py +48 -7
- package/scripts/ci-validate-yaml.py +7 -2
- package/scripts/code_mode_server.py +33 -2
- package/scripts/doctor.mjs +135 -127
- package/scripts/generate-preset-docs.mjs +127 -66
- package/scripts/generate-prompts.sh +2 -2
- package/scripts/install/cli-ui.mjs +8 -1
- package/scripts/install/config-migration.mjs +401 -0
- package/scripts/install/health-check.mjs +3 -3
- package/scripts/install/model-picker.mjs +72 -23
- package/scripts/install/opencode-version.mjs +47 -0
- package/scripts/install/opencode.mjs +261 -88
- package/scripts/install/plugin.mjs +112 -42
- package/scripts/install/shared.mjs +13 -158
- package/scripts/install-mcp.mjs +44 -232
- package/scripts/mcp_persistence_server.py +344 -15
- package/scripts/mcp_resources_server.py +144 -40
- package/scripts/memory_mcp_server.py +2 -2
- package/scripts/recover-zenodo-deposition.mjs +146 -0
- package/scripts/sync-tui.mjs +32 -7
- package/scripts/test-opencode-v1-v2-sandbox.sh +591 -0
- package/scripts/uninstall.mjs +298 -954
- package/scripts/validate-zenodo-release.mjs +154 -0
- package/scripts/zenodo-artifact.mjs +21 -0
- package/scripts/zenodo-release-state.mjs +53 -0
- package/src/agents/zeus.md +25 -14
- package/src/mcp/_pantheon_paths.py +48 -7
- package/src/mcp/code_mode_server.py +33 -2
- package/src/mcp/eval_store.py +1 -1
- package/src/mcp/mcp_persistence_server.py +344 -15
- package/src/mcp/mcp_resources_server.py +144 -40
- package/src/mcp/pantheon_vision_server.py +1 -1
- package/src/mcp/toon_codec.py +491 -0
- package/src/pantheon/background-job-board.ts +67 -1
- package/src/pantheon/cost-command.ts +13 -9
- package/src/pantheon/delegate-manager.ts +384 -0
- package/src/pantheon/delegate-task-adapter.ts +444 -0
- package/src/pantheon/delegation-classifier.ts +307 -0
- package/src/pantheon/delegation-enforce.ts +13 -12
- package/src/pantheon/delegation-finalize.ts +374 -0
- package/src/pantheon/delegation-notify.ts +212 -0
- package/src/pantheon/delegation-toast.ts +73 -0
- package/src/pantheon/delegation.ts +1120 -0
- package/src/pantheon/goal-loop.ts +2 -2
- package/src/pantheon/goal-store.ts +1 -1
- package/src/pantheon/hashline/tool.ts +2 -2
- package/src/pantheon/model-command.ts +2 -1
- package/src/pantheon/permission-eval.ts +284 -0
- package/src/pantheon/step-cap.ts +110 -0
- package/src/pantheon/token-opt.ts +555 -0
- package/src/pantheon/toon-codec.ts +481 -0
- package/src/pantheon/tui-version-check.ts +1 -3
- package/src/pantheon/v2-bridge.ts +129 -0
- package/src/pantheon/v2-events.ts +131 -0
- package/src/pantheon/v2-hooks.ts +287 -0
- package/src/pantheon/v2-tool-definitions.ts +331 -0
- package/src/pantheon/zeus-delegate-with-retry.ts +406 -0
- package/src/plugin-v2/index.ts +21 -0
- package/src/plugin-v2.ts +836 -0
- package/src/plugin.ts +241 -42
- package/src/plugins/tui/dist/server.d.ts +1 -1
- package/src/plugins/tui/dist/server.d.ts.map +1 -1
- package/src/plugins/tui/dist/server.js +1 -1
- package/src/plugins/tui/dist/server.js.map +1 -1
- package/src/plugins/tui/dist/tui.d.ts +10 -7
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +11 -8
- package/src/plugins/tui/dist/tui.js.map +1 -1
- package/src/plugins/tui/dist/tui.tsx +22 -16
- package/src/plugins/tui/package-lock.json +51 -51
- package/src/plugins/tui/package.json +7 -7
- package/src/plugins/tui/src/index.tsx +28 -24
- package/src/skills/README.md +0 -2
- package/src/pantheon/tool-context.ts +0 -41
package/src/plugin.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
1
3
|
import type { Plugin, PluginInput } from '@opencode-ai/plugin'
|
|
2
4
|
import type { PluginConfig } from 'opencode'
|
|
3
5
|
import { BackgroundJobBoard } from './pantheon/background-job-board.ts'
|
|
@@ -10,6 +12,19 @@ import {
|
|
|
10
12
|
DEFAULT_LIMITS as SANDBOX_DEFAULT_LIMITS,
|
|
11
13
|
} from './pantheon/context-sandbox.ts'
|
|
12
14
|
import { createCostCommand } from './pantheon/cost-command.ts'
|
|
15
|
+
import {
|
|
16
|
+
buildPluginNativeDelegation,
|
|
17
|
+
resolveDelegateMode,
|
|
18
|
+
withDelegationKillSwitch,
|
|
19
|
+
} from './pantheon/delegate-task-adapter.ts'
|
|
20
|
+
import {
|
|
21
|
+
collectRootSessionIDs,
|
|
22
|
+
createDelegationTools,
|
|
23
|
+
type DelegationClient,
|
|
24
|
+
resolveDelegationBudgets,
|
|
25
|
+
resolveDelegationTimeoutMs,
|
|
26
|
+
startIdleChildScan,
|
|
27
|
+
} from './pantheon/delegation.ts'
|
|
13
28
|
import { buildCompactionContext } from './pantheon/delegation-compaction.ts'
|
|
14
29
|
import {
|
|
15
30
|
createEnforcementGuard,
|
|
@@ -17,6 +32,8 @@ import {
|
|
|
17
32
|
SessionHierarchyRegistry,
|
|
18
33
|
zeusReadGuard,
|
|
19
34
|
} from './pantheon/delegation-enforce.ts'
|
|
35
|
+
import { handleDelegationEvent } from './pantheon/delegation-notify.ts'
|
|
36
|
+
import { showDelegationTerminalToast, type ToastClient } from './pantheon/delegation-toast.ts'
|
|
20
37
|
import { FilePersistenceAdapter } from './pantheon/file-persistence.ts'
|
|
21
38
|
import { GOAL_LOOP_DEFAULTS, GoalLoop, GoalStore } from './pantheon/goal-loop.ts'
|
|
22
39
|
import { createReadEnhancer } from './pantheon/hashline/read-enhancer.ts'
|
|
@@ -25,8 +42,14 @@ import { createIdleDispatcher } from './pantheon/idle-continuation.ts'
|
|
|
25
42
|
import { createPantheonLogger } from './pantheon/logger.ts'
|
|
26
43
|
import { createModelCommand } from './pantheon/model-command.ts'
|
|
27
44
|
import { pantheonPluginOnce } from './pantheon/plugin-once.ts'
|
|
28
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
applyActivePresetToConfig,
|
|
47
|
+
loadRoutingAgentModels,
|
|
48
|
+
loadRoutingMaxSteps,
|
|
49
|
+
loadRoutingPermissionTask,
|
|
50
|
+
} from './pantheon/presets.mjs'
|
|
29
51
|
import { safeSessionPath } from './pantheon/session-guard.ts'
|
|
52
|
+
import { StepCapTracker } from './pantheon/step-cap.ts'
|
|
30
53
|
import {
|
|
31
54
|
TODO_ENFORCER_DEFAULTS,
|
|
32
55
|
TodoEnforcer,
|
|
@@ -45,12 +68,24 @@ import { activePresetCandidates, createVisionHandler } from './pantheon/vision.t
|
|
|
45
68
|
// .pantheon/logs/hooks.log; the console echo is opt-in via PANTHEON_HOOKS_LOG=1.
|
|
46
69
|
const log = createPantheonLogger({ module: 'pantheon-plugin' })
|
|
47
70
|
|
|
71
|
+
// R4: per-agent step caps from routing.yml `agents.<name>.max_steps`
|
|
72
|
+
// (fail-open → {} = no agent capped). R1 retry_policy/cooldown are NOT
|
|
73
|
+
// wired here — the plugin has no retry path (opencode cannot intercept task
|
|
74
|
+
// completion); zeus waves load them via presets.mjs loaders and pass them
|
|
75
|
+
// to zeusDelegateWithRetry explicitly.
|
|
76
|
+
const stepCapTracker = new StepCapTracker(loadRoutingMaxSteps({ logger: log }))
|
|
77
|
+
|
|
78
|
+
// O5: permission.task glob rules from routing.yml `permission.task`
|
|
79
|
+
// (fail-open → undefined = existing runtime matrix only).
|
|
80
|
+
const routingPermissionTask = loadRoutingPermissionTask({ logger: log })
|
|
81
|
+
|
|
48
82
|
const board = new BackgroundJobBoard({
|
|
49
83
|
maxConcurrentPerAgent: 3,
|
|
50
84
|
signalDir: '.pantheon/deepwork/board-signals',
|
|
51
85
|
})
|
|
52
86
|
const persistence = new FilePersistenceAdapter('.pantheon/board/state.json')
|
|
53
87
|
board.setPersistence(persistence)
|
|
88
|
+
let terminalToastClient: ToastClient = {}
|
|
54
89
|
board
|
|
55
90
|
.recoverRunningJobs()
|
|
56
91
|
.catch((err) => log.error('[Pantheon Plugin] Failed to recover running jobs:', err))
|
|
@@ -60,13 +95,17 @@ board
|
|
|
60
95
|
// file-only log line (console echo opt-in via PANTHEON_HOOKS_LOG). There is
|
|
61
96
|
// deliberately NO chat delivery — the user policy is zero delegation
|
|
62
97
|
// notifications in the transcript. Completion visibility lives in the board
|
|
63
|
-
// `[unread]` marker
|
|
98
|
+
// `[unread]` marker (pantheon_delegation_list), pantheon_delegation_read,
|
|
99
|
+
// TUI toasts (pantheon-hooks, PANTHEON_TOASTS gate) and compaction
|
|
100
|
+
// carry-forward.
|
|
64
101
|
board.onTerminal((taskID: string) => {
|
|
65
102
|
const job = board.get(taskID)
|
|
66
103
|
if (!job) return
|
|
67
104
|
log.info(
|
|
68
105
|
`[Pantheon Plugin] Board terminal: [${job.alias}] ${job.description} → ${job.state}${job.resultSummary ? ` — ${job.resultSummary}` : ''}`,
|
|
69
106
|
)
|
|
107
|
+
// Deliberately direct-to-TUI: onTerminal must not inject chat/transcript text.
|
|
108
|
+
void showDelegationTerminalToast(terminalToastClient, job)
|
|
70
109
|
})
|
|
71
110
|
|
|
72
111
|
// Periodically prune terminal/reconciled jobs (24h TTL, every 30 min).
|
|
@@ -84,15 +123,23 @@ setInterval(
|
|
|
84
123
|
|
|
85
124
|
// ─── Phase 4: Read-Only Enforcement + Compaction Context ───────────────
|
|
86
125
|
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
126
|
+
// WS1 (PR #94): root-session predicate shared by the Phase 4 enforcement
|
|
127
|
+
// guard and the native delegate toolset — both must agree on what a root is.
|
|
128
|
+
// (Hoisted function: `rootSessions`/`sessionHierarchy` below are resolved at
|
|
129
|
+
// call time, after module init.)
|
|
130
|
+
function isRootSession(sessionID: string): boolean {
|
|
131
|
+
return rootSessions.has(sessionID) || sessionHierarchy.isRoot(sessionID)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// The read-only registry is populated by createDelegationTools (delegation.ts)
|
|
135
|
+
// when a delegate is read-only (explicit flag or agent ∈ readOnlyAgents).
|
|
136
|
+
// The guard denies edit/write/bash/task inside those sessions by throwing
|
|
137
|
+
// from tool.execute.before; unknown sessions are allowed (safe default).
|
|
91
138
|
const enforcementGuard = createEnforcementGuard({
|
|
92
139
|
getReadOnlySessions: () => readOnlyRegistry.sessionIDs(),
|
|
93
140
|
options: {
|
|
94
141
|
getSessionAgent: (sessionID) => sessionAgents.get(sessionID),
|
|
95
|
-
isRootSession
|
|
142
|
+
isRootSession,
|
|
96
143
|
isChildSession: (sessionID) => sessionHierarchy.isChild(sessionID),
|
|
97
144
|
logger: log,
|
|
98
145
|
},
|
|
@@ -108,7 +155,7 @@ const commandNormalizer = createCommandNormalizer({ logger: log })
|
|
|
108
155
|
// Mirrors routing.yml background_delegation.max_compaction_items.
|
|
109
156
|
const COMPACTION_MAX_ITEMS = 10
|
|
110
157
|
|
|
111
|
-
// Root-session registry for the
|
|
158
|
+
// Root-session registry for the delegation depth guard: sessions created
|
|
112
159
|
// without a parentID are roots. Populated from TWO sources:
|
|
113
160
|
// 1. the `session.created` event hook (live roots — fires for sessions
|
|
114
161
|
// created while the plugin runs);
|
|
@@ -116,9 +163,9 @@ const COMPACTION_MAX_ITEMS = 10
|
|
|
116
163
|
// hook (compaction-134) — opencode does NOT replay session.created
|
|
117
164
|
// events for sessions that exist before plugin load, so without the
|
|
118
165
|
// seed a resumed root would never enter this set after a restart.
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
166
|
+
// delegation.ts additionally falls back to knownChildren ("any session WE
|
|
167
|
+
// created is a sub-session; unknown sessions are roots") so the depth guard
|
|
168
|
+
// works even when this set is incomplete.
|
|
122
169
|
const rootSessions = new Set<string>()
|
|
123
170
|
const sessionHierarchy = new SessionHierarchyRegistry()
|
|
124
171
|
const sessionAgents = new Map<string, string>()
|
|
@@ -127,14 +174,14 @@ const sessionAgents = new Map<string, string>()
|
|
|
127
174
|
* Seed resumed root sessions without making OpenCode startup depend on the
|
|
128
175
|
* session API responding. Some OpenCode environments do not have the API
|
|
129
176
|
* ready while plugin config hooks run; awaiting session.list() there leaves
|
|
130
|
-
* the TUI stuck before it can open. The
|
|
177
|
+
* the TUI stuck before it can open. The delegation layer already treats an
|
|
131
178
|
* unknown session as a root, so this enrichment is deliberately best-effort.
|
|
132
179
|
*/
|
|
133
180
|
function seedRootSessionsInBackground(input: PluginInput): void {
|
|
134
181
|
// Fail-open: environments without the session API (client.session absent or
|
|
135
182
|
// not yet wired while config hooks run) must NOT break startup. `session`
|
|
136
183
|
// is captured and the method invoked on it so `this` stays bound; the
|
|
137
|
-
//
|
|
184
|
+
// delegation layer already treats unknown sessions as roots, so skipping
|
|
138
185
|
// the seed is always safe.
|
|
139
186
|
const session = input.client.session
|
|
140
187
|
if (typeof session?.list !== 'function') return
|
|
@@ -144,15 +191,10 @@ function seedRootSessionsInBackground(input: PluginInput): void {
|
|
|
144
191
|
.then((result) => {
|
|
145
192
|
if (!result.error && Array.isArray(result.data)) {
|
|
146
193
|
sessionHierarchy.completeSeed(result.data)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
seeded += 1
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (seeded > 0) {
|
|
155
|
-
log.info(`[Pantheon Plugin] Seeded ${seeded} root session(s) from session.list`)
|
|
194
|
+
const seeded = collectRootSessionIDs(result.data)
|
|
195
|
+
if (seeded.size > 0) {
|
|
196
|
+
for (const id of seeded) rootSessions.add(id)
|
|
197
|
+
log.info(`[Pantheon Plugin] Seeded ${seeded.size} root session(s) from session.list`)
|
|
156
198
|
}
|
|
157
199
|
} else {
|
|
158
200
|
sessionHierarchy.failSeed()
|
|
@@ -170,6 +212,62 @@ function sdkErrorMessage(error: { data?: { message?: string } } | null | undefin
|
|
|
170
212
|
return typeof message === 'string' && message.trim() !== '' ? message : 'request failed'
|
|
171
213
|
}
|
|
172
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Adapt the opencode SDK client to the structural DelegationClient the
|
|
217
|
+
* delegation toolset expects: the SDK wraps every call in a
|
|
218
|
+
* `{data, error, request, response}` result while delegation.ts uses direct
|
|
219
|
+
* returns. Errors surface as throws so the toolset's own error handling
|
|
220
|
+
* (tool errors returned as TEXT) keeps working.
|
|
221
|
+
*/
|
|
222
|
+
function adaptDelegationClient(client: PluginInput['client']): DelegationClient {
|
|
223
|
+
return {
|
|
224
|
+
session: {
|
|
225
|
+
create: async (input) => {
|
|
226
|
+
const body: {
|
|
227
|
+
parentID?: string
|
|
228
|
+
title?: string
|
|
229
|
+
model?: { id: string; providerID: string }
|
|
230
|
+
} = { parentID: input.body.parentID }
|
|
231
|
+
if (input.body.title !== undefined) body.title = input.body.title
|
|
232
|
+
// Forward a model only when the active routing profile supplied one.
|
|
233
|
+
if (input.body.model !== undefined) body.model = input.body.model
|
|
234
|
+
const result = await client.session.create({ body })
|
|
235
|
+
if (result.error) throw new Error(sdkErrorMessage(result.error))
|
|
236
|
+
return { id: result.data.id }
|
|
237
|
+
},
|
|
238
|
+
promptAsync: async (input) => {
|
|
239
|
+
const path = safeSessionPath(input.path.id)
|
|
240
|
+
if (!path) {
|
|
241
|
+
log.warn(`[Pantheon Plugin] promptAsync skipped: invalid sessionID "${input.path.id}"`)
|
|
242
|
+
throw new Error(`invalid sessionID: ${input.path.id}`)
|
|
243
|
+
}
|
|
244
|
+
const result = await client.session.promptAsync({
|
|
245
|
+
path: path.path,
|
|
246
|
+
body: {
|
|
247
|
+
agent: input.body.agent,
|
|
248
|
+
...(input.body.model !== undefined
|
|
249
|
+
? { model: { providerID: input.body.model.providerID, modelID: input.body.model.id } }
|
|
250
|
+
: {}),
|
|
251
|
+
parts: input.body.parts,
|
|
252
|
+
},
|
|
253
|
+
})
|
|
254
|
+
if (result.error) throw new Error(sdkErrorMessage(result.error))
|
|
255
|
+
return result.data
|
|
256
|
+
},
|
|
257
|
+
messages: async (input) => {
|
|
258
|
+
const path = safeSessionPath(input.path.id)
|
|
259
|
+
if (!path) {
|
|
260
|
+
log.warn(`[Pantheon Plugin] messages skipped: invalid sessionID "${input.path.id}"`)
|
|
261
|
+
return []
|
|
262
|
+
}
|
|
263
|
+
const result = await client.session.messages({ path: path.path })
|
|
264
|
+
if (result.error) throw new Error(sdkErrorMessage(result.error))
|
|
265
|
+
return result.data
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
173
271
|
/**
|
|
174
272
|
* Adapt the opencode SDK client to the structural TodoEnforcerClient the
|
|
175
273
|
* todo enforcer expects: unwraps the SDK `{data, error, request, response}`
|
|
@@ -250,6 +348,7 @@ function adaptTodoEnforcerClient(client: PluginInput['client']): TodoEnforcerCli
|
|
|
250
348
|
* Helpers live in src/pantheon/vision.ts and are imported from there directly.
|
|
251
349
|
*/
|
|
252
350
|
const plugin: Plugin = async (input: PluginInput) => {
|
|
351
|
+
terminalToastClient = input.client as unknown as ToastClient
|
|
253
352
|
// release-134: runtime guard against DOUBLE registration (duplicate toasts +
|
|
254
353
|
// duplicate task_ids in one process — 2026-08-12 live logs). opencode
|
|
255
354
|
// merges the global config (npm-package plugin paths) with the project
|
|
@@ -264,12 +363,101 @@ const plugin: Plugin = async (input: PluginInput) => {
|
|
|
264
363
|
// is older than the installed package. Runs once, fail-open, no auto-sync.
|
|
265
364
|
checkTuiVersionStaleness((msg) => log.warn(msg))
|
|
266
365
|
const vision = createVisionHandler(input)
|
|
366
|
+
// Phase 2/3: background delegation toolset + the bound finalize lifecycle
|
|
367
|
+
// hook. Completion is observed through the event hook below
|
|
368
|
+
// (session.idle / session.error on a child) → finalizeDelegation.
|
|
369
|
+
// Fase B3: runtime controls for the two read-only exceptions and the real
|
|
370
|
+
// per-child wall-clock timer. No task_budget field is injected into the
|
|
371
|
+
// plugin/frontmatter; these are enforced by delegation.ts itself.
|
|
372
|
+
const delegationBudgets = resolveDelegationBudgets()
|
|
373
|
+
const wallClockTimeoutMs = resolveDelegationTimeoutMs()
|
|
374
|
+
|
|
375
|
+
// WS1 (PR #94): delegation backend gate. Default = legacy (the V1
|
|
376
|
+
// fire-and-forget toolset, intact); PANTHEON_DELEGATE_MODE=native selects
|
|
377
|
+
// the thin manager over native task() semantics. Kill-switch
|
|
378
|
+
// PANTHEON_DELEGATION=off covers BOTH modes (native guards internally;
|
|
379
|
+
// legacy via withDelegationKillSwitch). finalizeDelegation always stays on
|
|
380
|
+
// the legacy observer: it works on the shared board in both modes and must
|
|
381
|
+
// never be kill-switched, so children never orphan. The idle hook below is
|
|
382
|
+
// untouched.
|
|
383
|
+
const delegationClient = adaptDelegationClient(input.client)
|
|
384
|
+
// Only an explicitly active routing profile may provide child models.
|
|
385
|
+
// An empty map deliberately lets OpenCode inherit the parent model.
|
|
386
|
+
const routingAgentModels = loadRoutingAgentModels({
|
|
387
|
+
candidates: activePresetCandidates(),
|
|
388
|
+
logger: log,
|
|
389
|
+
})
|
|
390
|
+
const readOnlyAgents = new Set(['apollo', 'gaia'])
|
|
391
|
+
const legacyDelegation = createDelegationTools({
|
|
392
|
+
board,
|
|
393
|
+
client: delegationClient,
|
|
394
|
+
options: {
|
|
395
|
+
rootSessions,
|
|
396
|
+
isChildSession: (sessionID) => sessionHierarchy.isChild(sessionID),
|
|
397
|
+
registerChildSession: (sessionID, parentID) => {
|
|
398
|
+
sessionHierarchy.register({ id: sessionID, parentID })
|
|
399
|
+
},
|
|
400
|
+
enforceRuntimeMatrix: true,
|
|
401
|
+
readOnlyAgents,
|
|
402
|
+
agentModels: routingAgentModels,
|
|
403
|
+
delegationBudgets,
|
|
404
|
+
stepCapTracker,
|
|
405
|
+
...(routingPermissionTask != null ? { permissionTask: routingPermissionTask } : {}),
|
|
406
|
+
...(wallClockTimeoutMs !== undefined ? { wallClockTimeoutMs } : {}),
|
|
407
|
+
},
|
|
408
|
+
})
|
|
409
|
+
const delegateMode = resolveDelegateMode()
|
|
410
|
+
if (delegateMode === 'native') {
|
|
411
|
+
log.info('[Pantheon Plugin] Delegation mode: native (PANTHEON_DELEGATE_MODE=native)')
|
|
412
|
+
}
|
|
413
|
+
const delegation =
|
|
414
|
+
delegateMode === 'native'
|
|
415
|
+
? buildPluginNativeDelegation({
|
|
416
|
+
board,
|
|
417
|
+
client: delegationClient,
|
|
418
|
+
isRootSession,
|
|
419
|
+
registerChildSession: (sessionID, parentID) => {
|
|
420
|
+
sessionHierarchy.register({ id: sessionID, parentID })
|
|
421
|
+
},
|
|
422
|
+
registerReadOnlySession: (sessionID, info) => {
|
|
423
|
+
readOnlyRegistry.register(sessionID, info)
|
|
424
|
+
},
|
|
425
|
+
readOnlyAgents,
|
|
426
|
+
agentModels: routingAgentModels,
|
|
427
|
+
stepCap: stepCapTracker,
|
|
428
|
+
...(wallClockTimeoutMs !== undefined ? { wallClockTimeoutMs } : {}),
|
|
429
|
+
finalizeDelegation: legacyDelegation.finalizeDelegation,
|
|
430
|
+
})
|
|
431
|
+
: withDelegationKillSwitch(legacyDelegation)
|
|
432
|
+
|
|
433
|
+
// Proactive idle-child scan (Fix 2): finalize children that are idle on the
|
|
434
|
+
// board but have no MD report on disk — eliminates the phantom "running"
|
|
435
|
+
// window. Runs every 30s (configurable via PANTHEON_IDLE_SCAN_INTERVAL_MS),
|
|
436
|
+
// unref'd so it never holds the process open. Fail-open by design.
|
|
437
|
+
const idleScanIntervalMs = Number(process.env.PANTHEON_IDLE_SCAN_INTERVAL_MS) || undefined
|
|
438
|
+
startIdleChildScan(
|
|
439
|
+
{
|
|
440
|
+
board,
|
|
441
|
+
finalize: (childSessionID, opts) => delegation.finalizeDelegation(childSessionID, opts),
|
|
442
|
+
hasReport: (job) => {
|
|
443
|
+
try {
|
|
444
|
+
const filePath = join('.pantheon/delegations', job.parentSessionID, `${job.alias}.md`)
|
|
445
|
+
return existsSync(filePath)
|
|
446
|
+
} catch {
|
|
447
|
+
return false
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
logger: log,
|
|
451
|
+
},
|
|
452
|
+
idleScanIntervalMs,
|
|
453
|
+
)
|
|
454
|
+
|
|
267
455
|
// Wave 1 (PR #46): TODO continuation enforcer for root/non-board sessions.
|
|
268
456
|
// Mirrors routing.yml `todo_enforcer` (plugin scope has no routing.yml
|
|
269
|
-
// access — COMPACTION_MAX_ITEMS pattern). The event hook routes
|
|
270
|
-
// session.idle events here
|
|
271
|
-
// (routing.yml is a doc
|
|
272
|
-
// PANTHEON_TOASTS pattern).
|
|
457
|
+
// access — COMPACTION_MAX_ITEMS pattern). The event hook routes non-board
|
|
458
|
+
// session.idle events here; board-child idles go to finalizeDelegation.
|
|
459
|
+
// Runtime kill-switch: PANTHEON_TODO_ENFORCER=off (routing.yml is a doc
|
|
460
|
+
// mirror only — the env var is the real switch, PANTHEON_TOASTS pattern).
|
|
273
461
|
const todoEnforcer = new TodoEnforcer({
|
|
274
462
|
client: adaptTodoEnforcerClient(input.client),
|
|
275
463
|
board,
|
|
@@ -326,7 +514,7 @@ const plugin: Plugin = async (input: PluginInput) => {
|
|
|
326
514
|
await readEnhancer(input, output)
|
|
327
515
|
}
|
|
328
516
|
|
|
329
|
-
// Wave 4 (PR #46): /cost — cost + token visibility
|
|
517
|
+
// Wave 4 (PR #46): /cost — delegation cost + token visibility. Reads
|
|
330
518
|
// opencode.db read-only (node:sqlite, falls back to scripts/cost.mjs).
|
|
331
519
|
// Fully wired (unlike dispatch-guard, which is manual-orchestration-only
|
|
332
520
|
// because opencode 1.18.x cannot intercept task completion via hooks).
|
|
@@ -338,11 +526,11 @@ const plugin: Plugin = async (input: PluginInput) => {
|
|
|
338
526
|
// compaction-134 seed: opencode does NOT replay `session.created`
|
|
339
527
|
// events for sessions that exist before plugin load, so after a
|
|
340
528
|
// restart the resumed ROOT session never enters rootSessions and the
|
|
341
|
-
// depth guard would
|
|
342
|
-
// session.list() in the background — every session
|
|
343
|
-
// is a root. Fail-open: a failed/throttled list
|
|
344
|
-
//
|
|
345
|
-
// and config setup must never wait for the session API.
|
|
529
|
+
// depth guard would reject its pantheon_delegate calls. Seed the
|
|
530
|
+
// registry from session.list() in the background — every session
|
|
531
|
+
// WITHOUT a parentID is a root. Fail-open: a failed/throttled list
|
|
532
|
+
// leaves the set untouched (delegation.ts treats unknown sessions as
|
|
533
|
+
// roots), and config setup must never wait for the session API.
|
|
346
534
|
// Context sandbox config — opencode.json → context_sandbox: {enabled, limits}
|
|
347
535
|
try {
|
|
348
536
|
const raw = (config as unknown as Record<string, unknown>).context_sandbox
|
|
@@ -387,16 +575,18 @@ const plugin: Plugin = async (input: PluginInput) => {
|
|
|
387
575
|
log.warn('[plugin] preset application failed (see logs for details)')
|
|
388
576
|
}
|
|
389
577
|
},
|
|
390
|
-
// Phase 2:
|
|
391
|
-
// shape
|
|
392
|
-
// deterministic /pantheon-model, /cost and full-auto goal tools.
|
|
578
|
+
// Phase 2: background delegation tools (structural — matches the `tool`
|
|
579
|
+
// hook field shape; read_only sessions feed the Phase 4 registry).
|
|
393
580
|
tool: {
|
|
581
|
+
pantheon_delegate: delegation.pantheon_delegate,
|
|
582
|
+
pantheon_delegation_read: delegation.pantheon_delegation_read,
|
|
583
|
+
pantheon_delegation_list: delegation.pantheon_delegation_list,
|
|
394
584
|
hashline_edit: hashlineEdit,
|
|
395
585
|
// Wave 3 (PR #46): full-auto goal tools (single active goal/session).
|
|
396
586
|
pantheon_goal_create: goalTools.pantheon_goal_create,
|
|
397
587
|
pantheon_goal_update: goalTools.pantheon_goal_update,
|
|
398
588
|
pantheon_goal_get: goalTools.pantheon_goal_get,
|
|
399
|
-
// Wave 4 (PR #46): /cost — cost report
|
|
589
|
+
// Wave 4 (PR #46): /cost — delegation cost report from opencode.db.
|
|
400
590
|
pantheon_cost: costCommand.pantheon_cost,
|
|
401
591
|
// Deterministic /pantheon-model management of top-level model fields.
|
|
402
592
|
pantheon_model: modelCommand.pantheon_model,
|
|
@@ -430,13 +620,22 @@ const plugin: Plugin = async (input: PluginInput) => {
|
|
|
430
620
|
if (ev.type === 'session.compacted') {
|
|
431
621
|
await todoPreserver.onCompacted(ev.properties.sessionID)
|
|
432
622
|
}
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
//
|
|
437
|
-
// + swallowed), so the session is safe.
|
|
623
|
+
// Phase 3: observe completion on child sessions → finalizeDelegation.
|
|
624
|
+
// The board transition fires onTerminal → the file-only audit log (no
|
|
625
|
+
// chat delivery — see the onTerminal listener above). Unknown sessions
|
|
626
|
+
// are a no-op.
|
|
438
627
|
try {
|
|
439
|
-
|
|
628
|
+
const delegated = await handleDelegationEvent(ev, {
|
|
629
|
+
board,
|
|
630
|
+
finalize: (childSessionID, opts) => delegation.finalizeDelegation(childSessionID, opts),
|
|
631
|
+
})
|
|
632
|
+
// Wave 1/3: non-board idle → idle dispatcher. Board children are
|
|
633
|
+
// handled by handleDelegationEvent above; everything else (roots,
|
|
634
|
+
// non-board sessions) is routed by priority: an active goal owns the
|
|
635
|
+
// idle (goal loop), otherwise the todo enforcer re-injects. Neither
|
|
636
|
+
// onIdle ever throws (internal failures are logged + swallowed), so
|
|
637
|
+
// the session is safe.
|
|
638
|
+
if (!delegated && ev.type === 'session.idle') {
|
|
440
639
|
await idleDispatcher.onIdle(ev.properties.sessionID)
|
|
441
640
|
}
|
|
442
641
|
} catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;;;;;;;iBAYwB"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;;;;;;;iBAYwB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["/**\n * No-op server stub for the opencode plugin loader.\n *\n * The opencode plugin host requires every plugin (TUI included) to expose a\n * `server()` entry via `exports[\"./server\"]` (or package.json `main`). When\n * that entry is missing the host fails to attach the plugin's server half and\n * the TUI runtime never wires the reactive channel — the initial JSX mounts\n * but effects/refresh/events stay dead (the \"mudo panel\" symptom).\n *\n * This stub satisfies the loader contract; pantheon-tui is TUI-only and has\n * no background server work of its own.\n */\nexport default function server() {\n return {}\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAwB,SAAS;CAC/B,OAAO,CAAC;AACV"}
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["/**\n * No-op server stub for the opencode plugin loader.\n *\n * The opencode plugin host requires every plugin (TUI included) to expose a\n * `server()` entry via `exports[\"./server\"]` (or package.json `main`). When\n * that entry is missing the host fails to attach the plugin's server half and\n * the TUI runtime never wires the reactive channel — the initial JSX mounts\n * but effects/refresh/events stay dead (the \"mudo panel\" symptom).\n *\n * This stub satisfies the loader contract; pantheon-tui is TUI-only and has\n * no background server work of its own.\n */\nexport default function server() {\n return {}\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAwB,SAAS;CAC/B,OAAO,CAAC;AACV"}
|
|
@@ -22,7 +22,7 @@ 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 `[
|
|
25
|
+
* (rendered with the distinct `[native]` tag); 'md' = board report wins. */
|
|
26
26
|
source?: 'child' | 'live' | 'md' | 'children-only';
|
|
27
27
|
};
|
|
28
28
|
/** Parse one delegation report md header into a structured entry.
|
|
@@ -59,7 +59,7 @@ declare function readAllDelegationEntries(root: string): Promise<DelegationEntry
|
|
|
59
59
|
declare function resolveDelegationsDir(state: {
|
|
60
60
|
directory?: string;
|
|
61
61
|
worktree?: string;
|
|
62
|
-
} | undefined, cwd?:
|
|
62
|
+
} | undefined, cwd?: any): string;
|
|
63
63
|
/** Project root derived from the delegations dir: `<root>/.pantheon/delegations`
|
|
64
64
|
* → `<root>`. Used to point the panel logger at the REAL hooks.log — passing
|
|
65
65
|
* the delegations dir (or its dirname) directly made createTuiLogger append
|
|
@@ -279,10 +279,12 @@ type ChildDelegationLike = {
|
|
|
279
279
|
* (fail-open: a freshly-seen child is assumed active; the 1s poll + md
|
|
280
280
|
* correct it as soon as terminal data exists). */
|
|
281
281
|
declare function childStatusToState(status: string | undefined): 'running' | 'completed';
|
|
282
|
-
/** Row tag for a delegation entry: `[
|
|
283
|
-
* (source 'children-only' — no board report), `[
|
|
284
|
-
* ([apo-1])
|
|
285
|
-
*
|
|
282
|
+
/** Row tag for a delegation entry: `[native]` for native task() children
|
|
283
|
+
* (source 'children-only' — no board report), `[pantheon:<alias>]` for board
|
|
284
|
+
* rows ([pantheon:apo-1]) — the same tags the manager prints in
|
|
285
|
+
* pantheon_delegation_list, so panel rows and CLI list lines match. The
|
|
286
|
+
* panel renders the tag with a distinct style so native task() children are
|
|
287
|
+
* visually separable from pantheon_delegate jobs. */
|
|
286
288
|
declare function delegationTag(entry: DelegationEntry): string;
|
|
287
289
|
/** Turn child sessions (PRIMARY) enriched with md reports into the display
|
|
288
290
|
* list. One entry per child id (duplicates across re-fetches collapse).
|
|
@@ -293,7 +295,7 @@ declare function delegationTag(entry: DelegationEntry): string;
|
|
|
293
295
|
* time.created. A report-less child is a NATIVE task() child (every
|
|
294
296
|
* child of the current session — pantheon_delegate OR the native `task()`
|
|
295
297
|
* tool — carries parentID = caller), so it gets source 'children-only'
|
|
296
|
-
* and the `[
|
|
298
|
+
* and the `[native]` tag instead of a board alias.
|
|
297
299
|
* Terminal md state wins over the derived state; a running md defers to
|
|
298
300
|
* the child's live status. Sorted running-first (compareDelegationEntries).
|
|
299
301
|
* Pure — no I/O. */
|
|
@@ -319,6 +321,7 @@ type LiveDelegationStore = {
|
|
|
319
321
|
};
|
|
320
322
|
declare const plugin: TuiPluginModule & {
|
|
321
323
|
id: string;
|
|
324
|
+
setup: () => Promise<void>;
|
|
322
325
|
};
|
|
323
326
|
//#endregion
|
|
324
327
|
export { ChildDelegationLike, DelegationActivity, DelegationEntry, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, TuiSessionSources, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationSpinnerFrame, delegationTag, fmtElapsed, isValidSessionId, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, safeSessionPath, seedLiveDelegationMap, toDelegationEntry, tuiLogPath, visibleDelegationList };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;KAo7BY;;EAEV;;EAEA;;;;EAIA;;EAEA;EACA;;EASA;;EAEA;EACA;EACA;;EAEA;;;;EAIA;;;;;;;;;;;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;;;;;iBAWhD,sBACd,cAAc,mBACd,sBACA,cACA,4BACC;;cASU;;;;cAKA;;;;;;;;;iBAUG,mBACd,OAAO,iBACP,aACA,uBACC;;;iBAWa,WAAW;;;iBAcX,kBAAkB,OAAO,iBAAiB;;;KAQ9C;iBAQI,mBAAmB,OAAO,kBAAkB;iBAc5C,wBAAwB,OAAO;;iBAoB/B,uBAAuB;;;;;;;iBAWvB,4BACd,mBAAmB,mBACnB,eAAe,wBACd;;KAmFS;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA,QAAQ;IACR;IACA;IACA;MAAS;MAAgB;;;;;KAKjB;;EAEV;;EAEA;;EAEA;EACA;;EAEA;EACA;;EAEA;;EAEA;EACA;EACA;EACA;;EAEA;;;KAIU;EACV;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBAac,wBACd,MAAM,oBACN,eACC;;;iBA+Ea,yBACd,KAAK,YAAY,sBACjB,MAAM,oBACN;;;iBA+Fc,sBACd,KAAK,YAAY,sBACjB;;;;;;iBAiBc,2BACd;EAAqB;EAAa;iBAClC,YAAY,uDACX;;;;;iBA2Ba,sBACd,KAAK,YAAY,sBACjB,gBAAgB,sBAChB;;;iBAWc,kBAAkB,MAAM,sBAAsB;;;;;;iBAqB9C,uBACd,eAAe,uBACf,aAAa,oBACZ;;;;;;;;;iBA8Da,iBAAiB,cAAc;;;;KAOnC;;EAEV;EACA;;IAEE;MAAU;;;IAEV;MAAU;QAAY;QAAe,SAAS;;;;;;;;;;iBASlC,wBAAwB,SAAS;;;;;;;;iBAmBjC,gBAAgB;EAAgB;IAAQ;;;;;;;iBASxC,kBAAkB;EAAkC;IAAQ;;;;KAKhE;;EAEV;;EAEA;;;EAGA;;;EAGA;EACA;IACE;IACA;;;;;;;iBAQY,mBAAmB
|
|
1
|
+
{"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;KAo7BY;;EAEV;;EAEA;;;;EAIA;;EAEA;EACA;;EASA;;EAEA;EACA;EACA;;EAEA;;;;EAIA;;;;;;;;;;;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;;;;;iBAWhD,sBACd,cAAc,mBACd,sBACA,cACA,4BACC;;cASU;;;;cAKA;;;;;;;;;iBAUG,mBACd,OAAO,iBACP,aACA,uBACC;;;iBAWa,WAAW;;;iBAcX,kBAAkB,OAAO,iBAAiB;;;KAQ9C;iBAQI,mBAAmB,OAAO,kBAAkB;iBAc5C,wBAAwB,OAAO;;iBAoB/B,uBAAuB;;;;;;;iBAWvB,4BACd,mBAAmB,mBACnB,eAAe,wBACd;;KAmFS;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA,QAAQ;IACR;IACA;IACA;MAAS;MAAgB;;;;;KAKjB;;EAEV;;EAEA;;EAEA;EACA;;EAEA;EACA;;EAEA;;EAEA;EACA;EACA;EACA;;EAEA;;;KAIU;EACV;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBAac,wBACd,MAAM,oBACN,eACC;;;iBA+Ea,yBACd,KAAK,YAAY,sBACjB,MAAM,oBACN;;;iBA+Fc,sBACd,KAAK,YAAY,sBACjB;;;;;;iBAiBc,2BACd;EAAqB;EAAa;iBAClC,YAAY,uDACX;;;;;iBA2Ba,sBACd,KAAK,YAAY,sBACjB,gBAAgB,sBAChB;;;iBAWc,kBAAkB,MAAM,sBAAsB;;;;;;iBAqB9C,uBACd,eAAe,uBACf,aAAa,oBACZ;;;;;;;;;iBA8Da,iBAAiB,cAAc;;;;KAOnC;;EAEV;EACA;;IAEE;MAAU;;;IAEV;MAAU;QAAY;QAAe,SAAS;;;;;;;;;;iBASlC,wBAAwB,SAAS;;;;;;;;iBAmBjC,gBAAgB;EAAgB;IAAQ;;;;;;;iBASxC,kBAAkB;EAAkC;IAAQ;;;;KAKhE;;EAEV;;EAEA;;;EAGA;;;EAGA;EACA;IACE;IACA;;;;;;;iBAQY,mBAAmB;;;;;;;iBAWnB,cAAc,OAAO;;;;;;;;;;;;;;iBAiBrB,4BACd,mBAAmB,mCACnB,aAAa,mBACb,eACC;;;;;;iBA0Ca,4BACd;EAAS,YAAY,cAAc,SAAS;eAC5C;;;;;KAiLU;EACV,KAAK,YAAY;;EAEjB;;EAEA;;cAucI,QAAQ;EAAoB;EAAY,aAAa"}
|
|
@@ -164,7 +164,7 @@ async function detectVersion(api) {
|
|
|
164
164
|
if (ver) return ver;
|
|
165
165
|
}
|
|
166
166
|
} catch {}
|
|
167
|
-
return "1.
|
|
167
|
+
return "1.5.0";
|
|
168
168
|
}
|
|
169
169
|
/**
|
|
170
170
|
* usage-bar — AI subscription usage gauge for the opencode TUI.
|
|
@@ -1311,12 +1311,14 @@ function childStatusToState(status) {
|
|
|
1311
1311
|
if (status === "idle") return "completed";
|
|
1312
1312
|
return "running";
|
|
1313
1313
|
}
|
|
1314
|
-
/** Row tag for a delegation entry: `[
|
|
1315
|
-
* (source 'children-only' — no board report), `[
|
|
1316
|
-
* ([apo-1])
|
|
1317
|
-
*
|
|
1314
|
+
/** Row tag for a delegation entry: `[native]` for native task() children
|
|
1315
|
+
* (source 'children-only' — no board report), `[pantheon:<alias>]` for board
|
|
1316
|
+
* rows ([pantheon:apo-1]) — the same tags the manager prints in
|
|
1317
|
+
* pantheon_delegation_list, so panel rows and CLI list lines match. The
|
|
1318
|
+
* panel renders the tag with a distinct style so native task() children are
|
|
1319
|
+
* visually separable from pantheon_delegate jobs. */
|
|
1318
1320
|
function delegationTag(entry) {
|
|
1319
|
-
return entry.source === "children-only" ? "[
|
|
1321
|
+
return entry.source === "children-only" ? "[native]" : `[pantheon:${entry.alias}]`;
|
|
1320
1322
|
}
|
|
1321
1323
|
/** Turn child sessions (PRIMARY) enriched with md reports into the display
|
|
1322
1324
|
* list. One entry per child id (duplicates across re-fetches collapse).
|
|
@@ -1327,7 +1329,7 @@ function delegationTag(entry) {
|
|
|
1327
1329
|
* time.created. A report-less child is a NATIVE task() child (every
|
|
1328
1330
|
* child of the current session — pantheon_delegate OR the native `task()`
|
|
1329
1331
|
* tool — carries parentID = caller), so it gets source 'children-only'
|
|
1330
|
-
* and the `[
|
|
1332
|
+
* and the `[native]` tag instead of a board alias.
|
|
1331
1333
|
* Terminal md state wins over the derived state; a running md defers to
|
|
1332
1334
|
* the child's live status. Sorted running-first (compareDelegationEntries).
|
|
1333
1335
|
* Pure — no I/O. */
|
|
@@ -1871,7 +1873,8 @@ const tui = (api, _options, _meta) => {
|
|
|
1871
1873
|
};
|
|
1872
1874
|
const plugin = {
|
|
1873
1875
|
id: "pantheon.tui",
|
|
1874
|
-
tui
|
|
1876
|
+
tui,
|
|
1877
|
+
setup: async () => {}
|
|
1875
1878
|
};
|
|
1876
1879
|
//#endregion
|
|
1877
1880
|
export { IDLE_SILENCE_MS, STALE_RUNNING_THRESHOLD_MS, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationSpinnerFrame, delegationTag, fmtElapsed, isValidSessionId, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, safeSessionPath, seedLiveDelegationMap, toDelegationEntry, tuiLogPath, visibleDelegationList };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.js","names":[],"sources":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"tui.js","names":[],"sources":[],"mappings":""}
|