pantheon-opencode 1.4.3 → 1.5.0-beta.2
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/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 +161 -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/cost.mjs +30 -14
- 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 +382 -16
- package/scripts/mcp_resources_server.py +144 -40
- package/scripts/memory_mcp_server.py +2 -2
- package/scripts/probe-context-rehydrate.mjs +240 -0
- package/scripts/probe-pantheon-cost.mjs +304 -0
- package/scripts/recover-zenodo-deposition.mjs +146 -0
- package/scripts/sync-tui.mjs +32 -7
- package/scripts/test-opencode-v1-v2-sandbox.sh +944 -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 +382 -16
- 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 +60 -39
- package/src/pantheon/delegate-manager.ts +669 -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 +781 -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 +824 -0
- package/src/plugin.ts +236 -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
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Token Command — `pantheon_cost` structural tool: token visibility for
|
|
3
|
+
* delegation traffic, straight from opencode.db.
|
|
4
4
|
*
|
|
5
|
-
* Reads the opencode session database READ-ONLY (sum
|
|
6
|
-
*
|
|
5
|
+
* Reads the opencode session database READ-ONLY (sum tokens by agent and
|
|
6
|
+
* phase over the last N days → markdown table). Zero new dependencies:
|
|
7
7
|
* - primary path: node:sqlite (DatabaseSync, readOnly) — node ≥ 22.5;
|
|
8
|
-
* - fallback: spawn scripts/cost.mjs
|
|
9
|
-
* direct import is unavailable;
|
|
8
|
+
* - CLI fallback: spawn scripts/cost.mjs with its explicit flag-based
|
|
9
|
+
* interface when the direct import is unavailable;
|
|
10
10
|
* - missing/unreadable db → FRIENDLY error string, never a crash (tools
|
|
11
11
|
* return errors as TEXT).
|
|
12
12
|
*
|
|
13
13
|
* dbPath resolution: explicit option > env PANTHEON_COST_DB > the version-aware
|
|
14
14
|
* default selected by PANTHEON_OPENCODE_VERSION (v1 or v2). An unset version
|
|
15
15
|
* deliberately preserves V1 behavior. The tool is wired in
|
|
16
|
-
* plugin.ts (usable by zeus and any agent
|
|
17
|
-
* needed).
|
|
16
|
+
* plugin.ts alongside the delegation toolset (usable by zeus and any agent
|
|
17
|
+
* with tool access — no routing change needed).
|
|
18
18
|
*
|
|
19
19
|
* @module cost-command
|
|
20
20
|
*/
|
|
@@ -25,16 +25,17 @@ import { join } from 'node:path'
|
|
|
25
25
|
import { promisify } from 'node:util'
|
|
26
26
|
import { z } from 'zod'
|
|
27
27
|
|
|
28
|
-
import type { ToolContextLike } from './
|
|
28
|
+
import type { ToolContextLike } from './delegation.ts'
|
|
29
29
|
|
|
30
30
|
const execFileAsync = promisify(execFile)
|
|
31
31
|
|
|
32
|
-
/** One aggregated
|
|
32
|
+
/** One aggregated token row (per agent and phase). */
|
|
33
33
|
export interface CostRow {
|
|
34
34
|
agent: string
|
|
35
|
-
|
|
35
|
+
phase: string
|
|
36
36
|
tokensInput: number
|
|
37
37
|
tokensOutput: number
|
|
38
|
+
tokensTotal: number
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export interface CostCommandOptions {
|
|
@@ -44,7 +45,7 @@ export interface CostCommandOptions {
|
|
|
44
45
|
|
|
45
46
|
export type OpenCodeVersion = 'v1' | 'v2'
|
|
46
47
|
|
|
47
|
-
/** One cost tool: description + zod args shape + execute. */
|
|
48
|
+
/** One cost tool: description + zod args shape + execute (delegation.ts shape). */
|
|
48
49
|
export interface CostTool<Args extends z.ZodRawShape = typeof costArgs> {
|
|
49
50
|
description: string
|
|
50
51
|
args: Args
|
|
@@ -62,7 +63,7 @@ const costArgs = {
|
|
|
62
63
|
.min(1)
|
|
63
64
|
.max(365)
|
|
64
65
|
.optional()
|
|
65
|
-
.describe('Number of days of
|
|
66
|
+
.describe('Number of days of delegation history to include (default 7).'),
|
|
66
67
|
} satisfies z.ZodRawShape
|
|
67
68
|
|
|
68
69
|
/** Return the safe, isolated state DB name for an OpenCode version. */
|
|
@@ -123,38 +124,46 @@ function assertCompatibleSchema(db: {
|
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
126
|
|
|
126
|
-
/** Aggregate
|
|
127
|
+
/** Aggregate tokens by agent and phase via node:sqlite (read-only). */
|
|
127
128
|
async function queryWithNodeSqlite(dbPath: string, days: number): Promise<CostRow[]> {
|
|
128
129
|
const sqlite = await import('node:sqlite')
|
|
129
130
|
const db = new sqlite.DatabaseSync(dbPath, { readOnly: true })
|
|
130
131
|
try {
|
|
131
132
|
assertCompatibleSchema(db)
|
|
132
133
|
const since = Date.now() - days * 86_400_000
|
|
133
|
-
const rows = db
|
|
134
|
-
|
|
134
|
+
const rows = db
|
|
135
|
+
.prepare('SELECT data FROM message WHERE time_created >= ?')
|
|
136
|
+
.all(since) as Array<{ data?: unknown }>
|
|
137
|
+
// Rows without a data payload carry no cost info — skip them instead of
|
|
138
|
+
// coercing null/undefined into "null"/"undefined" strings.
|
|
139
|
+
return aggregateMessages(rows.flatMap((row) => (row?.data == null ? [] : [String(row.data)])))
|
|
135
140
|
} finally {
|
|
136
141
|
db.close()
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
144
|
|
|
140
|
-
/**
|
|
145
|
+
/** CLI fallback: delegate the same aggregation to scripts/cost.mjs. */
|
|
141
146
|
async function queryWithScript(
|
|
142
147
|
scriptPath: string,
|
|
143
148
|
dbPath: string,
|
|
144
149
|
days: number,
|
|
145
150
|
): Promise<CostRow[]> {
|
|
146
|
-
const { stdout } = await execFileAsync(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
const { stdout } = await execFileAsync(
|
|
152
|
+
process.execPath,
|
|
153
|
+
[scriptPath, '--db-path', dbPath, '--days', String(days)],
|
|
154
|
+
{
|
|
155
|
+
timeout: 15_000,
|
|
156
|
+
encoding: 'utf8',
|
|
157
|
+
},
|
|
158
|
+
)
|
|
150
159
|
const parsed = JSON.parse(stdout) as { ok: boolean; rows?: CostRow[]; error?: string }
|
|
151
160
|
if (!parsed.ok) throw new Error(parsed.error ?? 'cost.mjs failed')
|
|
152
161
|
return parsed.rows ?? []
|
|
153
162
|
}
|
|
154
163
|
|
|
155
|
-
/** Parse message.data JSON rows and aggregate
|
|
164
|
+
/** Parse message.data JSON rows and aggregate tokens by assistant agent/phase. */
|
|
156
165
|
function aggregateMessages(dataValues: readonly string[]): CostRow[] {
|
|
157
|
-
const
|
|
166
|
+
const byAgentAndPhase = new Map<string, CostRow>()
|
|
158
167
|
for (const value of dataValues) {
|
|
159
168
|
try {
|
|
160
169
|
const outer = JSON.parse(value) as Record<string, unknown>
|
|
@@ -165,45 +174,57 @@ function aggregateMessages(dataValues: readonly string[]): CostRow[] {
|
|
|
165
174
|
if (info.role !== 'assistant') continue
|
|
166
175
|
const agent = typeof info.agent === 'string' && info.agent !== '' ? info.agent : null
|
|
167
176
|
if (agent === null) continue
|
|
168
|
-
const
|
|
177
|
+
const metadata = info.metadata as Record<string, unknown> | undefined
|
|
178
|
+
const phase =
|
|
179
|
+
(typeof info.phase === 'string' && info.phase) ||
|
|
180
|
+
(typeof metadata?.phase === 'string' && metadata.phase) ||
|
|
181
|
+
'unknown'
|
|
169
182
|
const tokens = (info.tokens ?? {}) as Record<string, unknown>
|
|
170
183
|
const tokensInput = Number(tokens.input) || 0
|
|
171
184
|
const tokensOutput = Number(tokens.output) || 0
|
|
172
|
-
const
|
|
173
|
-
acc.
|
|
185
|
+
const key = `${agent}\u0000${phase}`
|
|
186
|
+
const acc = byAgentAndPhase.get(key) ?? {
|
|
187
|
+
agent,
|
|
188
|
+
phase,
|
|
189
|
+
tokensInput: 0,
|
|
190
|
+
tokensOutput: 0,
|
|
191
|
+
tokensTotal: 0,
|
|
192
|
+
}
|
|
174
193
|
acc.tokensInput += tokensInput
|
|
175
194
|
acc.tokensOutput += tokensOutput
|
|
176
|
-
|
|
195
|
+
acc.tokensTotal += tokensInput + tokensOutput
|
|
196
|
+
byAgentAndPhase.set(key, acc)
|
|
177
197
|
} catch {
|
|
178
198
|
// Skip malformed rows — a partial ledger never breaks the report.
|
|
179
199
|
}
|
|
180
200
|
}
|
|
181
|
-
return [...
|
|
201
|
+
return [...byAgentAndPhase.values()].sort((a, b) => b.tokensTotal - a.tokensTotal)
|
|
182
202
|
}
|
|
183
203
|
|
|
184
204
|
/** Render the aggregate as a markdown table with a total row. */
|
|
185
205
|
function renderMarkdown(rows: readonly CostRow[], days: number): string {
|
|
186
206
|
if (rows.length === 0) {
|
|
187
|
-
return `##
|
|
207
|
+
return `## Token usage by agent and phase (last ${days} days)\n\nNo token records in the last ${days} days.`
|
|
188
208
|
}
|
|
189
209
|
const total = rows.reduce(
|
|
190
210
|
(acc, r) => {
|
|
191
|
-
acc.costUsd += r.costUsd
|
|
192
211
|
acc.tokensInput += r.tokensInput
|
|
193
212
|
acc.tokensOutput += r.tokensOutput
|
|
213
|
+
acc.tokensTotal += r.tokensTotal
|
|
194
214
|
return acc
|
|
195
215
|
},
|
|
196
|
-
{
|
|
216
|
+
{ tokensInput: 0, tokensOutput: 0, tokensTotal: 0 },
|
|
197
217
|
)
|
|
198
218
|
const lines = [
|
|
199
|
-
`##
|
|
219
|
+
`## Token usage by agent and phase (last ${days} days)`,
|
|
200
220
|
'',
|
|
201
|
-
'| Agent |
|
|
202
|
-
'
|
|
221
|
+
'| Agent | Phase | Tokens In | Tokens Out | Tokens Total |',
|
|
222
|
+
'|-------|-------|----------:|-----------:|-------------:|',
|
|
203
223
|
...rows.map(
|
|
204
|
-
(r) =>
|
|
224
|
+
(r) =>
|
|
225
|
+
`| ${r.agent} | ${r.phase} | ${r.tokensInput} | ${r.tokensOutput} | ${r.tokensTotal} |`,
|
|
205
226
|
),
|
|
206
|
-
`| **Total** |
|
|
227
|
+
`| **Total** | — | **${total.tokensInput}** | **${total.tokensOutput}** | **${total.tokensTotal}** |`,
|
|
207
228
|
'',
|
|
208
229
|
`Source: opencode.db (read-only)`,
|
|
209
230
|
]
|
|
@@ -214,14 +235,14 @@ export function createCostCommand(options?: CostCommandOptions): CostCommand {
|
|
|
214
235
|
const scriptPath = new URL('../../scripts/cost.mjs', import.meta.url).pathname
|
|
215
236
|
|
|
216
237
|
const execute = async (args: { days?: number }, _ctx: ToolContextLike): Promise<string> => {
|
|
217
|
-
const days = args
|
|
238
|
+
const days = args?.days ?? 7
|
|
218
239
|
try {
|
|
219
240
|
const dbPath = findExistingDb(options?.dbPath)
|
|
220
241
|
if (dbPath === undefined) {
|
|
221
242
|
const expected = resolveCostDbPath(options)
|
|
222
243
|
return (
|
|
223
244
|
`pantheon_cost failed: opencode.db not found (expected at ${expected}). ` +
|
|
224
|
-
`No
|
|
245
|
+
`No token history is available until opencode has stored session data.`
|
|
225
246
|
)
|
|
226
247
|
}
|
|
227
248
|
const rows = await queryWithNodeSqlite(dbPath, days).catch(async (err: unknown) => {
|
|
@@ -239,7 +260,7 @@ export function createCostCommand(options?: CostCommandOptions): CostCommand {
|
|
|
239
260
|
return {
|
|
240
261
|
pantheon_cost: {
|
|
241
262
|
description:
|
|
242
|
-
'Report
|
|
263
|
+
'Report input, output, and total token usage by agent and phase over the last N days, read from opencode.db (read-only, no monetary values).',
|
|
243
264
|
args: costArgs,
|
|
244
265
|
execute,
|
|
245
266
|
},
|