pantheon-opencode 1.6.0-beta.10 → 1.6.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/AGENTS.global.md +42 -18
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +46 -0
- package/README.md +122 -38
- package/README.pt-BR.md +5 -4
- package/bin/pantheon-init.mjs +322 -101
- package/package.json +7 -6
- package/plugin.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/build-agents-md.mjs +128 -10
- package/scripts/check-plugin-v2-coverage.mjs +7 -7
- package/scripts/doctor.mjs +242 -19
- package/scripts/install/backup.mjs +648 -0
- package/scripts/install/cli-ui.mjs +79 -1
- package/scripts/install/exit-codes.mjs +26 -0
- package/scripts/install/file-inventory.mjs +555 -0
- package/scripts/install/interactive.mjs +15 -1
- package/scripts/install/migrate.mjs +32 -6
- package/scripts/install/model-picker.mjs +63 -22
- package/scripts/install/opencode-version.mjs +9 -1
- package/scripts/install/opencode.mjs +761 -63
- package/scripts/install/plan-artifact.mjs +517 -0
- package/scripts/install/plan.mjs +449 -0
- package/scripts/install/plugin.mjs +136 -18
- package/scripts/install/shared.mjs +249 -94
- package/scripts/install/state.mjs +63 -8
- package/scripts/install/strings.mjs +20 -0
- package/scripts/install/venv.mjs +25 -6
- package/scripts/install/verify.mjs +128 -0
- package/scripts/install/vision-prompt.mjs +13 -1
- package/scripts/install-mcp.mjs +1 -1
- package/scripts/manifest-inventory.mjs +49 -3
- package/scripts/mcp_persistence.py +50 -15
- package/scripts/node-engine-policy.mjs +74 -0
- package/scripts/package-evidence.mjs +6 -0
- package/scripts/postinstall.mjs +3 -4
- package/scripts/prune.mjs +9 -3
- package/scripts/reconcile.mjs +325 -0
- package/scripts/restore.mjs +222 -0
- package/scripts/uninstall.mjs +258 -34
- package/scripts/update.mjs +164 -0
- package/scripts/validate-node-engine-policy.mjs +13 -0
- package/scripts/version-check.mjs +34 -1
- package/scripts/versioning.mjs +9 -1
- package/skills-lock.json +4 -4
- package/src/agents/iris.md +6 -0
- package/src/agents/mnemosyne.md +7 -2
- package/src/agents/zeus.md +19 -62
- package/src/instructions/agent-return-format.instructions.md +17 -15
- package/src/instructions/memory-protocol.instructions.md +3 -2
- package/src/instructions/test-economy.instructions.md +21 -0
- package/src/instructions/zeus-anti-stall.instructions.md +6 -6
- package/src/instructions/zeus-council-synthesis.instructions.md +10 -11
- package/src/instructions/zeus-memory-operations.instructions.md +11 -6
- package/src/instructions/zeus-timeout-retry.instructions.md +28 -9
- package/src/mcp/mcp_persistence.py +50 -15
- package/src/pantheon/cost-command.ts +5 -2
- package/src/pantheon/model-agents.ts +19 -0
- package/src/pantheon/model-command.ts +218 -56
- package/src/pantheon/v2-model-overrides.ts +275 -0
- package/src/pantheon/v2-tools.ts +18 -29
- package/src/pantheon/v2-unsupported.mjs +2 -3
- package/src/plugin-v2.ts +13 -0
- package/src/plugins/tui/dist/tui-v2.js +2 -2
- package/src/plugins/tui/dist/tui.js +1 -1
- package/src/plugins/tui/package-lock.json +3 -3
- package/src/plugins/tui/package.json +2 -2
- package/src/skills/artifact-management/SKILL.md +5 -1
- package/src/skills/auto-continue/SKILL.md +14 -6
- package/src/skills/memory-bank/SKILL.md +5 -1
- package/src/skills/worktrees/SKILL.md +30 -11
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { closeSync, constants, fstatSync, openSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { KNOWN_AGENTS } from './model-agents.ts'
|
|
4
|
+
import { capabilityEntry, normalizeCapability } from './presets.mjs'
|
|
5
|
+
|
|
6
|
+
export interface V2ModelOverride {
|
|
7
|
+
model: string
|
|
8
|
+
variant?: 'low' | 'medium' | 'high'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface V2ModelConfiguration {
|
|
12
|
+
overrides: Record<string, V2ModelOverride>
|
|
13
|
+
legacyPresetMarker: { source: 'env' | 'file' } | null
|
|
14
|
+
warnings: string[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface V2AgentDraftLike {
|
|
18
|
+
list(): readonly { id: string }[]
|
|
19
|
+
update(id: string, update: (agent: { id: string; model?: unknown }) => void): void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface AgentModelLike {
|
|
23
|
+
id: string
|
|
24
|
+
model?: unknown
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const MODEL_REF_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._:+-]*$/
|
|
28
|
+
const VARIANTS = new Set(['low', 'medium', 'high'])
|
|
29
|
+
const KNOWN_AGENTS_SET = new Set<string>(KNOWN_AGENTS)
|
|
30
|
+
|
|
31
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
32
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isVariant(value: unknown): value is NonNullable<V2ModelOverride['variant']> {
|
|
36
|
+
return typeof value === 'string' && VARIANTS.has(value)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isSupportedModelChoice(model: unknown, variant: unknown): model is string {
|
|
40
|
+
if (typeof model !== 'string' || !MODEL_REF_PATTERN.test(model)) return false
|
|
41
|
+
if (variant !== undefined && !isVariant(variant)) return false
|
|
42
|
+
try {
|
|
43
|
+
capabilityEntry(model)
|
|
44
|
+
if (variant === undefined) return true
|
|
45
|
+
const normalized = normalizeCapability(model, variant)
|
|
46
|
+
return !normalized.clamped && normalized.variant === variant
|
|
47
|
+
} catch {
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface PresetFileSystem {
|
|
53
|
+
openSync(path: string, flags: number): number
|
|
54
|
+
fstatSync(fileDescriptor: number): { isFile(): boolean }
|
|
55
|
+
readFileSync(fileDescriptor: number, encoding: 'utf8'): string
|
|
56
|
+
closeSync(fileDescriptor: number): void
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
class SecurePresetReadUnavailableError extends Error {
|
|
60
|
+
constructor() {
|
|
61
|
+
super('Secure preset-file opening is unavailable')
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class NonRegularPresetFileError extends Error {
|
|
66
|
+
constructor() {
|
|
67
|
+
super('Preset file is not a regular file')
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Open and read a regular preset file without following links or blocking on special files. */
|
|
72
|
+
export function readV2PresetFile(
|
|
73
|
+
candidate: string,
|
|
74
|
+
fileSystem: PresetFileSystem = { openSync, fstatSync, readFileSync, closeSync },
|
|
75
|
+
): string {
|
|
76
|
+
const noFollowFlag = constants.O_NOFOLLOW
|
|
77
|
+
const nonBlockFlag = constants.O_NONBLOCK
|
|
78
|
+
if (
|
|
79
|
+
noFollowFlag === undefined ||
|
|
80
|
+
noFollowFlag === 0 ||
|
|
81
|
+
nonBlockFlag === undefined ||
|
|
82
|
+
nonBlockFlag === 0
|
|
83
|
+
) {
|
|
84
|
+
throw new SecurePresetReadUnavailableError()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let fileDescriptor: number | undefined
|
|
88
|
+
try {
|
|
89
|
+
fileDescriptor = fileSystem.openSync(
|
|
90
|
+
candidate,
|
|
91
|
+
constants.O_RDONLY | noFollowFlag | nonBlockFlag,
|
|
92
|
+
)
|
|
93
|
+
if (!fileSystem.fstatSync(fileDescriptor).isFile()) {
|
|
94
|
+
throw new NonRegularPresetFileError()
|
|
95
|
+
}
|
|
96
|
+
return fileSystem.readFileSync(fileDescriptor, 'utf8')
|
|
97
|
+
} finally {
|
|
98
|
+
if (fileDescriptor !== undefined) fileSystem.closeSync(fileDescriptor)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function parseOverrides(
|
|
103
|
+
value: Record<string, unknown>,
|
|
104
|
+
warnings: string[],
|
|
105
|
+
): Record<string, V2ModelOverride> {
|
|
106
|
+
const parsed: Record<string, V2ModelOverride> = {}
|
|
107
|
+
for (const [agent, raw] of Object.entries(value)) {
|
|
108
|
+
if (!KNOWN_AGENTS_SET.has(agent)) {
|
|
109
|
+
warnings.push(
|
|
110
|
+
'Override entry ignored for an unsupported agent; use one of the canonical Pantheon agent IDs.',
|
|
111
|
+
)
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
const entry = isRecord(raw) ? raw : undefined
|
|
115
|
+
const hasVariant = entry !== undefined && Object.hasOwn(entry, 'variant')
|
|
116
|
+
const variant = hasVariant ? entry?.variant : entry?.reasoning_effort
|
|
117
|
+
const model = entry?.model
|
|
118
|
+
if (!entry || (hasVariant && !isVariant(variant)) || !isSupportedModelChoice(model, variant)) {
|
|
119
|
+
warnings.push(
|
|
120
|
+
'Override entry ignored because its model or variant is unsupported; choose a supported model and reasoning variant.',
|
|
121
|
+
)
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
const override: V2ModelOverride = { model }
|
|
125
|
+
if (isVariant(variant)) override.variant = variant
|
|
126
|
+
parsed[agent] = override
|
|
127
|
+
}
|
|
128
|
+
return parsed
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function defaultCandidates(): string[] {
|
|
132
|
+
return [join(process.cwd(), '.pantheon', 'active-preset.json')]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Read explicit per-agent project overrides only; global files are ignored in V2. */
|
|
136
|
+
export function readV2ModelConfiguration(
|
|
137
|
+
options: { candidates?: string[]; env?: NodeJS.ProcessEnv } = {},
|
|
138
|
+
): V2ModelConfiguration {
|
|
139
|
+
const env = options.env ?? process.env
|
|
140
|
+
const envName = env.PANTHEON_MODEL_PRESET?.trim()
|
|
141
|
+
let fileMarkerPresent = false
|
|
142
|
+
const configurations: Array<Record<string, V2ModelOverride>> = []
|
|
143
|
+
const warnings: string[] = []
|
|
144
|
+
let readFailure = false
|
|
145
|
+
|
|
146
|
+
// `model-command` passes project before global candidates. Keep this reader
|
|
147
|
+
// project-only even if a caller supplies the legacy candidate list.
|
|
148
|
+
const candidates = options.candidates ?? defaultCandidates()
|
|
149
|
+
for (const candidate of candidates.slice(0, 1)) {
|
|
150
|
+
let rawContent: string
|
|
151
|
+
try {
|
|
152
|
+
rawContent = readV2PresetFile(candidate)
|
|
153
|
+
} catch (error: unknown) {
|
|
154
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') continue
|
|
155
|
+
if (error instanceof SecurePresetReadUnavailableError) {
|
|
156
|
+
warnings.push(
|
|
157
|
+
'V2 project model configuration cannot be read securely on this platform; manual overrides were not applied.',
|
|
158
|
+
)
|
|
159
|
+
readFailure = true
|
|
160
|
+
break
|
|
161
|
+
}
|
|
162
|
+
if (
|
|
163
|
+
error instanceof NonRegularPresetFileError ||
|
|
164
|
+
(error instanceof Error && 'code' in error && error.code === 'ELOOP')
|
|
165
|
+
) {
|
|
166
|
+
warnings.push(
|
|
167
|
+
'V2 project model configuration is not a regular file or is a symlink; check active-preset.json. Manual overrides were not applied.',
|
|
168
|
+
)
|
|
169
|
+
readFailure = true
|
|
170
|
+
break
|
|
171
|
+
}
|
|
172
|
+
warnings.push(
|
|
173
|
+
'V2 project model configuration could not be read; check active-preset.json file access. Manual overrides were not applied.',
|
|
174
|
+
)
|
|
175
|
+
readFailure = true
|
|
176
|
+
break
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let raw: unknown
|
|
180
|
+
try {
|
|
181
|
+
raw = JSON.parse(rawContent)
|
|
182
|
+
} catch {
|
|
183
|
+
warnings.push(
|
|
184
|
+
'V2 project model configuration contains invalid JSON; correct active-preset.json. Manual overrides were not applied.',
|
|
185
|
+
)
|
|
186
|
+
readFailure = true
|
|
187
|
+
break
|
|
188
|
+
}
|
|
189
|
+
if (!isRecord(raw)) {
|
|
190
|
+
warnings.push(
|
|
191
|
+
'V2 project model configuration has an invalid shape; correct active-preset.json. Manual overrides were not applied.',
|
|
192
|
+
)
|
|
193
|
+
readFailure = true
|
|
194
|
+
break
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (Object.hasOwn(raw, 'preset')) fileMarkerPresent = true
|
|
198
|
+
let parsedOverrides: Record<string, V2ModelOverride> = {}
|
|
199
|
+
if (Object.hasOwn(raw, 'overrides')) {
|
|
200
|
+
if (!isRecord(raw.overrides)) {
|
|
201
|
+
warnings.push(
|
|
202
|
+
'V2 project model configuration has an invalid `overrides` object; expected an object in active-preset.json. The project file contributed no manual overrides.',
|
|
203
|
+
)
|
|
204
|
+
} else if (Object.hasOwn(raw.overrides, 'agents')) {
|
|
205
|
+
if (!isRecord(raw.overrides.agents)) {
|
|
206
|
+
warnings.push(
|
|
207
|
+
'V2 project model configuration has invalid `overrides.agents`; expected an object in active-preset.json. The project file contributed no manual overrides.',
|
|
208
|
+
)
|
|
209
|
+
} else {
|
|
210
|
+
parsedOverrides = parseOverrides(raw.overrides.agents, warnings)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
configurations.push(parsedOverrides)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const envMarkerPresent = typeof envName === 'string' && envName.length > 0
|
|
218
|
+
const markerSource: 'env' | 'file' | null = envMarkerPresent
|
|
219
|
+
? 'env'
|
|
220
|
+
: fileMarkerPresent
|
|
221
|
+
? 'file'
|
|
222
|
+
: null
|
|
223
|
+
|
|
224
|
+
// A project-file read/parse failure fails closed. Malformed entries warn but
|
|
225
|
+
// leave other valid project entries available.
|
|
226
|
+
const overrides: Record<string, V2ModelOverride> = {}
|
|
227
|
+
if (!readFailure) {
|
|
228
|
+
Object.assign(overrides, configurations[0] ?? {})
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
overrides,
|
|
232
|
+
legacyPresetMarker: markerSource === null ? null : { source: markerSource },
|
|
233
|
+
warnings,
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Apply one explicit model override while leaving all other agent settings intact. */
|
|
238
|
+
export function applyV2ModelOverride(
|
|
239
|
+
agent: AgentModelLike,
|
|
240
|
+
override: V2ModelOverride | undefined,
|
|
241
|
+
): void {
|
|
242
|
+
if (
|
|
243
|
+
!KNOWN_AGENTS_SET.has(agent.id) ||
|
|
244
|
+
!override ||
|
|
245
|
+
!isSupportedModelChoice(override.model, override.variant)
|
|
246
|
+
) {
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
const separator = override.model.indexOf('/')
|
|
250
|
+
const previous = isRecord(agent.model) ? agent.model : {}
|
|
251
|
+
const model: Record<string, unknown> = {
|
|
252
|
+
...previous,
|
|
253
|
+
providerID: override.model.slice(0, separator),
|
|
254
|
+
id: override.model.slice(separator + 1),
|
|
255
|
+
}
|
|
256
|
+
if (override.variant !== undefined) {
|
|
257
|
+
model.variant = override.variant
|
|
258
|
+
} else {
|
|
259
|
+
delete model.variant
|
|
260
|
+
}
|
|
261
|
+
agent.model = model
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Apply explicit overrides to matching agents and leave unmatched host defaults untouched. */
|
|
265
|
+
export function applyV2ModelOverrides(
|
|
266
|
+
draft: V2AgentDraftLike,
|
|
267
|
+
overrides: Record<string, V2ModelOverride>,
|
|
268
|
+
): void {
|
|
269
|
+
for (const agent of draft.list()) {
|
|
270
|
+
if (!KNOWN_AGENTS_SET.has(agent.id)) continue
|
|
271
|
+
const override = overrides[agent.id]
|
|
272
|
+
if (!override) continue
|
|
273
|
+
draft.update(agent.id, (current) => applyV2ModelOverride(current, override))
|
|
274
|
+
}
|
|
275
|
+
}
|
package/src/pantheon/v2-tools.ts
CHANGED
|
@@ -311,7 +311,7 @@ async function executeCost(
|
|
|
311
311
|
|
|
312
312
|
// ─── pantheon_model ─────────────────────────────────────────────────────
|
|
313
313
|
|
|
314
|
-
/** JSON Schema for `pantheon_model
|
|
314
|
+
/** JSON Schema for V2 `pantheon_model`; global scope is intentionally absent. */
|
|
315
315
|
const MODEL_INPUT: Record<string, unknown> = {
|
|
316
316
|
type: 'object',
|
|
317
317
|
additionalProperties: false,
|
|
@@ -330,39 +330,27 @@ const MODEL_INPUT: Record<string, unknown> = {
|
|
|
330
330
|
},
|
|
331
331
|
scope: {
|
|
332
332
|
type: 'string',
|
|
333
|
-
enum: ['project'
|
|
334
|
-
description: '
|
|
335
|
-
},
|
|
336
|
-
confirm: {
|
|
337
|
-
type: 'boolean',
|
|
338
|
-
description: 'Explicit confirmation for a mutating operation; required for global changes.',
|
|
339
|
-
},
|
|
340
|
-
authorize_global: {
|
|
341
|
-
type: 'boolean',
|
|
342
|
-
description: 'Separate authorization for global configuration; not implied by confirm.',
|
|
333
|
+
enum: ['project'],
|
|
334
|
+
description: 'Project scope only; global overrides are not supported in V2.',
|
|
343
335
|
},
|
|
344
336
|
},
|
|
345
337
|
}
|
|
346
338
|
|
|
347
|
-
const
|
|
348
|
-
'the interactive wizard has no user in the V2 tool surface — pass action="status" to read ' +
|
|
349
|
-
'the current overrides, or pass agent and model explicitly for action="set"'
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* The V1 command falls back to an interactive readline prompt when invoked
|
|
353
|
-
* with no arguments. A tool call has no user at the terminal, so that fallback
|
|
354
|
-
* would block the call until it timed out. `ask` is injected to refuse
|
|
355
|
-
* deterministically instead, which routes through the command's own
|
|
356
|
-
* `wizard canceled` error path rather than forking its logic.
|
|
357
|
-
*/
|
|
358
|
-
const modelCommand = createModelCommand({
|
|
359
|
-
ask: () => Promise.reject(new Error(WIZARD_UNAVAILABLE)),
|
|
360
|
-
})
|
|
339
|
+
const modelCommand = createModelCommand({ v2Mode: true })
|
|
361
340
|
|
|
362
341
|
async function executeModel(
|
|
363
342
|
input: Record<string, unknown>,
|
|
364
343
|
context: unknown,
|
|
365
344
|
): Promise<V2ToolResult> {
|
|
345
|
+
if (input.scope !== undefined && input.scope !== 'project') {
|
|
346
|
+
return { output: 'Error: V2 pantheon_model is project-only; global scope is not supported.' }
|
|
347
|
+
}
|
|
348
|
+
if (Object.hasOwn(input, 'confirm') || Object.hasOwn(input, 'authorize_global')) {
|
|
349
|
+
return {
|
|
350
|
+
output:
|
|
351
|
+
'Error: V2 pantheon_model does not accept authorization flags; global authorization is not supported by this tool.',
|
|
352
|
+
}
|
|
353
|
+
}
|
|
366
354
|
// The V1 tool validates its own args (zod) and reports failures as text.
|
|
367
355
|
const output = await modelCommand.pantheon_model.execute(
|
|
368
356
|
input as Parameters<typeof modelCommand.pantheon_model.execute>[0],
|
|
@@ -415,10 +403,11 @@ export function createV2ToolDefinitions(visionRuntime?: V2VisionRuntime): V2Tool
|
|
|
415
403
|
{
|
|
416
404
|
name: 'pantheon_model',
|
|
417
405
|
description:
|
|
418
|
-
'Show, set, or reset per-agent model overrides in active-preset.json
|
|
419
|
-
'
|
|
420
|
-
'
|
|
421
|
-
'
|
|
406
|
+
'Show, set, or reset explicit per-agent project-scoped model overrides in active-preset.json. ' +
|
|
407
|
+
'V2 ignores static preset names and PANTHEON_MODEL_PRESET; no wizard or implicit model ' +
|
|
408
|
+
'selection. Global overrides are not read or written in V2; future global support requires ' +
|
|
409
|
+
'separate explicit authorization. Pass action="status" to read project-scoped overrides. ' +
|
|
410
|
+
'Never writes .env or top-level model/small_model.',
|
|
422
411
|
input: MODEL_INPUT,
|
|
423
412
|
output: {},
|
|
424
413
|
execute: executeModel,
|
|
@@ -21,9 +21,8 @@
|
|
|
21
21
|
* So a `.mjs` import is the only form all three consumers can share, and it
|
|
22
22
|
* matches the existing `src/pantheon/presets.mjs` + `.d.mts` precedent.
|
|
23
23
|
*
|
|
24
|
-
* NOT the reason: type-stripping. `package.json#engines` admits
|
|
25
|
-
*
|
|
26
|
-
* unflagged type-stripping (it landed in 22.18.0), so that argument would not
|
|
24
|
+
* NOT the reason: type-stripping. `package.json#engines` admits Node >=26.4.0,
|
|
25
|
+
* which defaults to unflagged type-stripping (it landed in 22.18.0), so that argument would not
|
|
27
26
|
* have held on any admitted version. The live hazard is that `engines` is not
|
|
28
27
|
* ENFORCED: a Node 20 user can run `doctor` and would get no type-stripping,
|
|
29
28
|
* which is an argument for a runtime version check, not for this file's shape.
|
package/src/plugin-v2.ts
CHANGED
|
@@ -110,6 +110,7 @@ import {
|
|
|
110
110
|
v2ResourceTarget,
|
|
111
111
|
} from './pantheon/v2-delegation-enforce.ts'
|
|
112
112
|
import { createV2ExecuteAfter, resolveV2SandboxConfig } from './pantheon/v2-execute-after.ts'
|
|
113
|
+
import { applyV2ModelOverrides, readV2ModelConfiguration } from './pantheon/v2-model-overrides.ts'
|
|
113
114
|
import { createV2ToolDefinitions, type V2ToolResult } from './pantheon/v2-tools.ts'
|
|
114
115
|
import { V2_UNSUPPORTED_FEATURE_SEED } from './pantheon/v2-unsupported.mjs'
|
|
115
116
|
import { buildV2VisionPromptContext, type V2VisionRuntime } from './pantheon/v2-vision.ts'
|
|
@@ -351,6 +352,18 @@ function transformAgents(draft: AgentDraft): void {
|
|
|
351
352
|
markUnsupported('agent-transform-list')
|
|
352
353
|
return
|
|
353
354
|
}
|
|
355
|
+
try {
|
|
356
|
+
const modelConfiguration = readV2ModelConfiguration()
|
|
357
|
+
if (modelConfiguration.warnings.length > 0) {
|
|
358
|
+
// The V2 server PluginContext has no documented user-visible notification
|
|
359
|
+
// or logging channel; preserve the degradation for status diagnostics.
|
|
360
|
+
markUnsupported('agent-model-overrides')
|
|
361
|
+
}
|
|
362
|
+
applyV2ModelOverrides(draft, modelConfiguration.overrides)
|
|
363
|
+
} catch {
|
|
364
|
+
// Model configuration is optional. Preserve host models if it cannot be read.
|
|
365
|
+
markUnsupported('agent-model-overrides')
|
|
366
|
+
}
|
|
354
367
|
try {
|
|
355
368
|
for (const agent of agents) {
|
|
356
369
|
draft.update(agent.id, (current) => {
|
|
@@ -477,7 +477,7 @@ function Sidebar(props) {
|
|
|
477
477
|
setProp(_el$, "width", "100%");
|
|
478
478
|
setProp(_el$, "padding", 1);
|
|
479
479
|
setProp(_el$2, "attributes", 1);
|
|
480
|
-
insert(_el$2, `Pantheon v1.6.0-beta.
|
|
480
|
+
insert(_el$2, `Pantheon v1.6.0-beta.12`);
|
|
481
481
|
insertNode(_el$3, createTextNode(`OpenCode V2 · plugin TUI ativo`));
|
|
482
482
|
insert(_el$, createComponent(Show, {
|
|
483
483
|
get when() {
|
|
@@ -623,7 +623,7 @@ function HomeStatus(props) {
|
|
|
623
623
|
const muted = () => props.context.theme?.text?.muted ?? props.context.theme?.text?.base;
|
|
624
624
|
return (() => {
|
|
625
625
|
var _el$20 = createElement("text");
|
|
626
|
-
insert(_el$20, () => `Pantheon v1.6.0-beta.
|
|
626
|
+
insert(_el$20, () => `Pantheon v1.6.0-beta.12${preset().name ? ` ⚡ ${preset().name}` : ""}`);
|
|
627
627
|
effect((_$p) => setProp(_el$20, "fg", muted(), _$p));
|
|
628
628
|
return _el$20;
|
|
629
629
|
})();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-tui",
|
|
3
|
-
"version": "1.6.0-beta.
|
|
3
|
+
"version": "1.6.0-beta.12",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pantheon-tui",
|
|
9
|
-
"version": "1.6.0-beta.
|
|
9
|
+
"version": "1.6.0-beta.12",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@opencode-ai/plugin": "1.18.33",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"tsdown": "0.23.0"
|
|
21
21
|
},
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": "
|
|
23
|
+
"node": ">=26.4.0"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"@opencode-ai/plugin": "1.18.33",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-tui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.6.0-beta.
|
|
4
|
+
"version": "1.6.0-beta.12",
|
|
5
5
|
"description": "Pantheon TUI plugin — V1 rich sidebar and usage gauges; native V2 status, session and delegation sidebar",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"engines": {
|
|
8
|
-
"node": "
|
|
8
|
+
"node": ">=26.4.0"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
"./tui": "./dist/tui.js",
|
|
@@ -23,12 +23,16 @@ All ephemeral artifacts live in `.pantheon/memory-bank/.tmp/` — gitignored and
|
|
|
23
23
|
│ ├── IMPL-phase1-hermes.md
|
|
24
24
|
│ ├── IMPL-phase1-aphrodite.md
|
|
25
25
|
│ └── REVIEW-<feature>.md
|
|
26
|
-
├── _notes/ ←
|
|
26
|
+
├── _notes/ ← permanent ADRs; Git tracking follows repository policy
|
|
27
27
|
│ └── ADR-<topic>.md
|
|
28
28
|
├── 01-active-context.md
|
|
29
29
|
└── 02-progress-log.md
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
Memory Bank files are not automatically versioned or shared across clones.
|
|
33
|
+
Check the repository's ignore/commit policy before relying on `_tasks/` records
|
|
34
|
+
or other files being tracked; `_tasks/` may be Git-ignored.
|
|
35
|
+
|
|
32
36
|
---
|
|
33
37
|
|
|
34
38
|
## Artifact Types
|
|
@@ -55,16 +55,16 @@ Full-auto may continue only within a task and scope the user explicitly authoriz
|
|
|
55
55
|
## Implementation Pattern
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
1. Create
|
|
59
|
-
2.
|
|
60
|
-
3.
|
|
61
|
-
4.
|
|
58
|
+
1. Create a checklist only for multi-step work; a one-step fix needs no todo ceremony
|
|
59
|
+
2. Use native todo operations only when a todo-write tool is visible in the active session; otherwise keep the checklist explicit in the conversation
|
|
60
|
+
3. Mark work complete in the available checklist as soon as it is done
|
|
61
|
+
4. Do not claim that the native todo list was updated when no todo-write tool is exposed
|
|
62
62
|
5. Do NOT ask "should I continue?" between clear steps
|
|
63
63
|
6. Stop at any applicable risk gate; do not require a plan/review gate for a low-risk edit
|
|
64
64
|
7. After gate approval, resume with next todo
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
**Never batch-complete
|
|
67
|
+
**Never batch-complete checklist items.** Mark each completed as soon as done; do not imply a tool call occurred unless it did.
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
@@ -107,6 +107,14 @@ Only expand to full cooldown when hitting a mandatory gate.
|
|
|
107
107
|
|
|
108
108
|
## Timeout & Retry Enforcement
|
|
109
109
|
|
|
110
|
+
Delegate through the root `subagent` tool observed in the Beta 10 runtime. `task()` is
|
|
111
|
+
host/API terminology, not an assumed root tool; call shape and background support are
|
|
112
|
+
runtime-dependent. Prefer synchronous dispatch unless the active schema exposes background
|
|
113
|
+
and the host provides an observable completion notification. Do not assume `task_status`,
|
|
114
|
+
`cancel_task`, or board-based tracking/recovery tools are available. When no completion
|
|
115
|
+
mechanism is observable, use synchronous dispatch or state the limitation; do not claim
|
|
116
|
+
that jobs are being tracked or recovered.
|
|
117
|
+
|
|
110
118
|
When a delegated agent does not respond in time, enforce the timeout policy defined in
|
|
111
119
|
`src/instructions/zeus-timeout-retry.instructions.md`.
|
|
112
120
|
|
|
@@ -128,7 +136,7 @@ When dispatching, set the expectation explicitly:
|
|
|
128
136
|
|
|
129
137
|
### Timeout Tracking Table
|
|
130
138
|
|
|
131
|
-
Maintain
|
|
139
|
+
Maintain an in-context (not persistent/native) checklist of delegations when needed:
|
|
132
140
|
|
|
133
141
|
| Agent | Started | Timeout | Status | Partial OK? |
|
|
134
142
|
|-------|---------|---------|--------|-------------|
|
|
@@ -16,7 +16,7 @@ Complete guide to Pantheon memory bank — structure, rules, optimization, and m
|
|
|
16
16
|
|
|
17
17
|
| System | Where | Owner | Lifetime | Purpose |
|
|
18
18
|
|--------|-------|-------|----------|---------|
|
|
19
|
-
| **Memory Bank** | `.pantheon/memory-bank/` | Team |
|
|
19
|
+
| **Memory Bank** | `.pantheon/memory-bank/` | Team | Files persist in the working tree; Git tracking depends on repository ignore/commit policy | Project context: architecture, patterns, progress |
|
|
20
20
|
| **VS Code `/memories/`** | `.vscode/` or workspace | Agent | Session/repo scoped | Atomic facts, conversation plans |
|
|
21
21
|
|
|
22
22
|
---
|
|
@@ -39,6 +39,10 @@ Complete guide to Pantheon memory bank — structure, rules, optimization, and m
|
|
|
39
39
|
└── NOTE0001-topic.md ← Architectural decisions, findings
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
Memory Bank files are not automatically synchronized across clones. In
|
|
43
|
+
particular, `_tasks/` records may be Git-ignored; only files tracked and
|
|
44
|
+
committed under the repository's policy are shared through Git.
|
|
45
|
+
|
|
42
46
|
### File Update Frequency
|
|
43
47
|
|
|
44
48
|
| File | Fill when | Update frequency |
|
|
@@ -16,28 +16,47 @@ Use git worktrees to create isolated working directories for parallel or experim
|
|
|
16
16
|
|
|
17
17
|
## Setup
|
|
18
18
|
|
|
19
|
+
Use this persistent external default for new worktrees:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
<project-parent>/.pantheon-worktrees/<exact-repository-directory-basename>/<task>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Resolve the project directory to an absolute path, then use its exact final
|
|
26
|
+
directory basename as the repository component; spaces are valid and must not
|
|
27
|
+
be normalized into a potentially colliding slug. For example, a project at
|
|
28
|
+
`/home/user/My Project` uses
|
|
29
|
+
`/home/user/.pantheon-worktrees/My Project/feature-name`. Replace
|
|
30
|
+
`<task>` with a short descriptive task name. This keeps worktrees outside
|
|
31
|
+
the project and reuses the same location across agent sessions.
|
|
32
|
+
|
|
19
33
|
```bash
|
|
20
|
-
# Create a worktree
|
|
21
|
-
git worktree add
|
|
34
|
+
# Create a worktree at the recommended external location
|
|
35
|
+
git worktree add "/home/user/.pantheon-worktrees/My Project/feature-name" task-branch
|
|
36
|
+
|
|
37
|
+
# List worktrees and their absolute paths
|
|
38
|
+
git worktree list --porcelain
|
|
22
39
|
|
|
23
|
-
#
|
|
24
|
-
git worktree
|
|
40
|
+
# Only after the user explicitly authorizes removal, remove that exact worktree
|
|
41
|
+
git worktree remove "/home/user/.pantheon-worktrees/My Project/feature-name"
|
|
25
42
|
|
|
26
|
-
#
|
|
27
|
-
git
|
|
43
|
+
# Only after the user explicitly authorizes branch deletion
|
|
44
|
+
git branch -d task-branch
|
|
28
45
|
```
|
|
29
46
|
|
|
30
47
|
## Workflow
|
|
31
48
|
|
|
32
|
-
1.
|
|
49
|
+
1. Resolve the project directory to an absolute path and create the worktree at `<project-parent>/.pantheon-worktrees/<exact-repository-directory-basename>/<task>`.
|
|
33
50
|
2. Work in the worktree directory
|
|
34
51
|
3. Commit and push from within the worktree
|
|
35
|
-
4.
|
|
36
|
-
5.
|
|
52
|
+
4. Leave the worktree and branch in place when the task is done unless the user explicitly authorizes removal or deletion.
|
|
53
|
+
5. If authorized, remove only the exact worktree path above; delete its branch only with separate explicit user authorization.
|
|
37
54
|
|
|
38
55
|
## Rules
|
|
39
56
|
- Never create worktrees inside the main project directory
|
|
40
|
-
-
|
|
41
|
-
-
|
|
57
|
+
- Use the persistent external default `<project-parent>/.pantheon-worktrees/<exact-repository-directory-basename>/<task>`
|
|
58
|
+
- Use the exact repository directory basename (spaces included); do not normalize it into a lossy slug
|
|
59
|
+
- Name worktrees descriptively, for example `feature-name` or `auth-refactor`
|
|
60
|
+
- Never remove a worktree or delete a branch unless the user explicitly authorizes that action
|
|
42
61
|
- Worktrees share the same git history — pushing from a worktree is the same as pushing from main
|
|
43
62
|
- Escalate to @iris for branch management if unsure
|