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.
Files changed (71) hide show
  1. package/AGENTS.global.md +42 -18
  2. package/AGENTS.md +1 -1
  3. package/CHANGELOG.md +46 -0
  4. package/README.md +122 -38
  5. package/README.pt-BR.md +5 -4
  6. package/bin/pantheon-init.mjs +322 -101
  7. package/package.json +7 -6
  8. package/plugin.json +1 -1
  9. package/pyproject.toml +1 -1
  10. package/scripts/build-agents-md.mjs +128 -10
  11. package/scripts/check-plugin-v2-coverage.mjs +7 -7
  12. package/scripts/doctor.mjs +242 -19
  13. package/scripts/install/backup.mjs +648 -0
  14. package/scripts/install/cli-ui.mjs +79 -1
  15. package/scripts/install/exit-codes.mjs +26 -0
  16. package/scripts/install/file-inventory.mjs +555 -0
  17. package/scripts/install/interactive.mjs +15 -1
  18. package/scripts/install/migrate.mjs +32 -6
  19. package/scripts/install/model-picker.mjs +63 -22
  20. package/scripts/install/opencode-version.mjs +9 -1
  21. package/scripts/install/opencode.mjs +761 -63
  22. package/scripts/install/plan-artifact.mjs +517 -0
  23. package/scripts/install/plan.mjs +449 -0
  24. package/scripts/install/plugin.mjs +136 -18
  25. package/scripts/install/shared.mjs +249 -94
  26. package/scripts/install/state.mjs +63 -8
  27. package/scripts/install/strings.mjs +20 -0
  28. package/scripts/install/venv.mjs +25 -6
  29. package/scripts/install/verify.mjs +128 -0
  30. package/scripts/install/vision-prompt.mjs +13 -1
  31. package/scripts/install-mcp.mjs +1 -1
  32. package/scripts/manifest-inventory.mjs +49 -3
  33. package/scripts/mcp_persistence.py +50 -15
  34. package/scripts/node-engine-policy.mjs +74 -0
  35. package/scripts/package-evidence.mjs +6 -0
  36. package/scripts/postinstall.mjs +3 -4
  37. package/scripts/prune.mjs +9 -3
  38. package/scripts/reconcile.mjs +325 -0
  39. package/scripts/restore.mjs +222 -0
  40. package/scripts/uninstall.mjs +258 -34
  41. package/scripts/update.mjs +164 -0
  42. package/scripts/validate-node-engine-policy.mjs +13 -0
  43. package/scripts/version-check.mjs +34 -1
  44. package/scripts/versioning.mjs +9 -1
  45. package/skills-lock.json +4 -4
  46. package/src/agents/iris.md +6 -0
  47. package/src/agents/mnemosyne.md +7 -2
  48. package/src/agents/zeus.md +19 -62
  49. package/src/instructions/agent-return-format.instructions.md +17 -15
  50. package/src/instructions/memory-protocol.instructions.md +3 -2
  51. package/src/instructions/test-economy.instructions.md +21 -0
  52. package/src/instructions/zeus-anti-stall.instructions.md +6 -6
  53. package/src/instructions/zeus-council-synthesis.instructions.md +10 -11
  54. package/src/instructions/zeus-memory-operations.instructions.md +11 -6
  55. package/src/instructions/zeus-timeout-retry.instructions.md +28 -9
  56. package/src/mcp/mcp_persistence.py +50 -15
  57. package/src/pantheon/cost-command.ts +5 -2
  58. package/src/pantheon/model-agents.ts +19 -0
  59. package/src/pantheon/model-command.ts +218 -56
  60. package/src/pantheon/v2-model-overrides.ts +275 -0
  61. package/src/pantheon/v2-tools.ts +18 -29
  62. package/src/pantheon/v2-unsupported.mjs +2 -3
  63. package/src/plugin-v2.ts +13 -0
  64. package/src/plugins/tui/dist/tui-v2.js +2 -2
  65. package/src/plugins/tui/dist/tui.js +1 -1
  66. package/src/plugins/tui/package-lock.json +3 -3
  67. package/src/plugins/tui/package.json +2 -2
  68. package/src/skills/artifact-management/SKILL.md +5 -1
  69. package/src/skills/auto-continue/SKILL.md +14 -6
  70. package/src/skills/memory-bank/SKILL.md +5 -1
  71. 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
+ }
@@ -311,7 +311,7 @@ async function executeCost(
311
311
 
312
312
  // ─── pantheon_model ─────────────────────────────────────────────────────
313
313
 
314
- /** JSON Schema for `pantheon_model`, mirroring the V1 zod args. */
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', 'global'],
334
- description: 'Scope for active-preset.json (default project).',
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 WIZARD_UNAVAILABLE =
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 (project or global). ' +
419
- 'Overrides win over preset; env preset wins over file. Never writes .env or top-level ' +
420
- 'model/small_model. Pass action="status" to read the current overrides; unlike the V1 ' +
421
- 'command there is no interactive wizard on this surface.',
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
- * `^22.22.2 || ^24.15.0 || >=26.0.0`, every admitted version already defaults to
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.10`);
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.10${preset().name ? ` ⚡ ${preset().name}` : ""}`);
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
  })();
@@ -167,7 +167,7 @@ async function detectVersion(api) {
167
167
  if (ver) return ver;
168
168
  }
169
169
  } catch {}
170
- return "1.6.0-beta.10";
170
+ return "1.6.0-beta.12";
171
171
  }
172
172
  /**
173
173
  * usage-bar — AI subscription usage gauge for the opencode TUI.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pantheon-tui",
3
- "version": "1.6.0-beta.10",
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.10",
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": "^22.22.2 || ^24.15.0 || >=26.0.0"
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.10",
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": "^22.22.2 || ^24.15.0 || >=26.0.0"
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/ ← COMMITTED — permanent ADRs
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 todos only for multi-step work; a one-step fix needs no todo ceremony
59
- 2. Mark first todo in_progress
60
- 3. Complete work → mark completed immediately
61
- 4. Mark next todo in_progress → repeat
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 todos.** Mark each completed as soon as done.
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 a mental table of in-flight delegations:
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 | Permanent, versioned | Project context: architecture, patterns, progress |
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 ../project-feature-x feature-x
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
- # List worktrees
24
- git worktree list
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
- # Remove a worktree
27
- git worktree remove ../project-feature-x
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. Create worktree: `git worktree add ../<name> <branch>`
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. Clean up: `git worktree remove ../<name>`
36
- 5. Delete branch if no longer needed
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
- - Name worktrees descriptively: `../project-auth-refactor`
41
- - Remove worktrees when done (they consume disk space)
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