pantheon-opencode 1.5.0-beta.2 → 1.5.0-beta.20

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 (107) hide show
  1. package/.pantheon/code-mode/manifest.json +21 -0
  2. package/AGENTS.md +14 -63
  3. package/CHANGELOG.md +1260 -0
  4. package/README.md +162 -23
  5. package/README.pt-BR.md +104 -19
  6. package/bin/pantheon-init.mjs +178 -21
  7. package/commands/pantheon.md +1 -35
  8. package/package.json +23 -15
  9. package/plugin.json +1 -1
  10. package/pyproject.toml +62 -0
  11. package/scripts/code_mode_server.py +431 -55
  12. package/scripts/doctor.mjs +207 -9
  13. package/scripts/install/cli-ui.mjs +17 -11
  14. package/scripts/install/config-migration.mjs +4 -6
  15. package/scripts/install/opencode.mjs +137 -35
  16. package/scripts/install/plugin.mjs +12 -45
  17. package/scripts/install/shared.mjs +43 -2
  18. package/scripts/install/strings.mjs +129 -0
  19. package/scripts/install-mcp.mjs +1 -0
  20. package/scripts/manifest-inventory.mjs +410 -0
  21. package/scripts/mcp_persistence_server.py +536 -164
  22. package/scripts/package-evidence.mjs +242 -0
  23. package/scripts/probe-pantheon-cost.mjs +10 -1
  24. package/scripts/release-beta-version.mjs +56 -60
  25. package/scripts/sync-artifacts.mjs +169 -0
  26. package/scripts/sync-tui.mjs +129 -64
  27. package/scripts/test-opencode-v1-v2-sandbox.sh +79 -161
  28. package/scripts/validation-policy.mjs +7 -7
  29. package/scripts/version-check.mjs +113 -108
  30. package/scripts/versioning.mjs +230 -86
  31. package/src/agents/apollo.md +1 -0
  32. package/src/agents/gaia.md +1 -0
  33. package/src/agents/mnemosyne.md +1 -1
  34. package/src/agents/zeus.md +11 -54
  35. package/src/instructions/memory-protocol.instructions.md +6 -3
  36. package/src/instructions/zeus-anti-stall.instructions.md +2 -4
  37. package/src/instructions/zeus-council-synthesis.instructions.md +3 -28
  38. package/src/instructions/zeus-timeout-retry.instructions.md +3 -28
  39. package/src/mcp/code_mode_server.py +431 -55
  40. package/src/mcp/mcp_persistence_server.py +536 -164
  41. package/src/mcp/toon_codec.py +2 -4
  42. package/src/pantheon/background-job-board.ts +47 -5
  43. package/src/pantheon/{delegation-compaction.ts → compaction-context.ts} +10 -100
  44. package/src/pantheon/cost-command.ts +309 -44
  45. package/src/pantheon/delegation-enforce.ts +59 -14
  46. package/src/pantheon/file-persistence-salvage.ts +64 -0
  47. package/src/pantheon/file-persistence.ts +194 -45
  48. package/src/pantheon/goal-loop.ts +1 -1
  49. package/src/pantheon/goal-store.ts +1 -1
  50. package/src/pantheon/idle-continuation.ts +4 -6
  51. package/src/pantheon/model-command.ts +1 -2
  52. package/src/pantheon/native-task-status.ts +139 -0
  53. package/src/pantheon/presets.d.mts +0 -20
  54. package/src/pantheon/presets.mjs +0 -64
  55. package/src/pantheon/session-guard.ts +2 -2
  56. package/src/pantheon/session-id.ts +30 -0
  57. package/src/pantheon/shared-board.ts +37 -0
  58. package/src/pantheon/task-result-guard.ts +106 -0
  59. package/src/pantheon/todo-enforcer.ts +3 -3
  60. package/src/pantheon/tool-ceiling.ts +159 -0
  61. package/src/pantheon/tool-context.ts +23 -0
  62. package/src/pantheon/v2-bridge.ts +1 -4
  63. package/src/plugin-v2.ts +8 -21
  64. package/src/plugin.ts +83 -251
  65. package/src/plugins/pantheon-hooks.ts +51 -0
  66. package/src/plugins/tui/dist/server.d.ts +1 -1
  67. package/src/plugins/tui/dist/server.d.ts.map +1 -1
  68. package/src/plugins/tui/dist/server.js +1 -1
  69. package/src/plugins/tui/dist/server.js.map +1 -1
  70. package/src/plugins/tui/dist/tui.d.ts +261 -77
  71. package/src/plugins/tui/dist/tui.d.ts.map +1 -1
  72. package/src/plugins/tui/dist/tui.js +640 -234
  73. package/src/plugins/tui/dist/tui.js.map +1 -1
  74. package/src/plugins/tui/package-lock.json +2 -2
  75. package/src/plugins/tui/package.json +2 -2
  76. package/src/plugins/tui/src/index.tsx +872 -226
  77. package/src/routing.yml +0 -16
  78. package/src/skills/context-compression/SKILL.md +1 -1
  79. package/scripts/generate-preset-docs.mjs +0 -300
  80. package/scripts/generate-prompts.sh +0 -222
  81. package/scripts/hash_verify.py +0 -192
  82. package/scripts/install/component.mjs +0 -24
  83. package/scripts/install/migrate-config.mjs +0 -302
  84. package/scripts/test-context-compression.sh +0 -169
  85. package/src/pantheon/auto-wake.ts +0 -89
  86. package/src/pantheon/chat-reminders.ts +0 -9
  87. package/src/pantheon/comment-checker.ts +0 -48
  88. package/src/pantheon/compaction-assert.ts +0 -160
  89. package/src/pantheon/cost-tracker.ts +0 -108
  90. package/src/pantheon/delegate-manager.ts +0 -669
  91. package/src/pantheon/delegation-classifier.ts +0 -307
  92. package/src/pantheon/delegation-finalize.ts +0 -374
  93. package/src/pantheon/delegation-notify.ts +0 -212
  94. package/src/pantheon/delegation-toast.ts +0 -73
  95. package/src/pantheon/delegation.ts +0 -1120
  96. package/src/pantheon/dispatch-guard.ts +0 -109
  97. package/src/pantheon/permission-eval.ts +0 -284
  98. package/src/pantheon/preemptive-compact.ts +0 -76
  99. package/src/pantheon/retry-policy.ts +0 -212
  100. package/src/pantheon/step-cap.ts +0 -110
  101. package/src/pantheon/token-opt.ts +0 -781
  102. package/src/pantheon/toon-codec.ts +0 -481
  103. package/src/pantheon/v2-events.ts +0 -131
  104. package/src/pantheon/v2-hooks.ts +0 -287
  105. package/src/pantheon/v2-tool-definitions.ts +0 -331
  106. package/src/pantheon/zeus-delegate-with-retry.ts +0 -406
  107. package/src/plugins/tui/dist/tui.tsx +0 -2605
@@ -5,12 +5,13 @@
5
5
  import { execSync } from 'node:child_process'
6
6
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from 'node:fs'
7
7
  import { isAbsolute, join, resolve } from 'node:path'
8
- import { warning } from './cli-ui.mjs'
9
8
  import { ROOT, writeIfChanged } from './shared.mjs'
10
9
 
11
10
  /**
12
- * Copy a plugin's runtime payload (src/index.tsx → index.tsx, dist/*,
13
- * package.json and package-lock.json) from source to destination.
11
+ * Copy a plugin's runtime payload (the bundled dist/*, package.json and
12
+ * package-lock.json) from source to destination. Only the bundle is copied —
13
+ * the raw TSX source is never shipped to the destination, so the plugin can
14
+ * be modularized without the loader needing relative imports.
14
15
  * @param {string} srcDir - Source plugin directory (e.g. ROOT/src/plugins/tui)
15
16
  * @param {string} dstDir - Destination plugin directory
16
17
  * @param {object} [options]
@@ -23,16 +24,11 @@ export function copyPluginFiles(srcDir, dstDir, { dryRun = false } = {}) {
23
24
  if (!dryRun) mkdirSync(dstDir, { recursive: true })
24
25
  if (!dryRun) mkdirSync(join(dstDir, 'dist'), { recursive: true })
25
26
 
26
- // Copy src/index.tsx -> index.tsx
27
- const srcIdx = join(srcDir, 'src', 'index.tsx')
28
- if (existsSync(srcIdx)) {
29
- const idxStatus = writeIfChanged(
30
- join(dstDir, 'index.tsx'),
31
- readFileSync(srcIdx, 'utf8'),
32
- dryRun,
33
- )
34
- if (idxStatus === 'created') result.created++
35
- else result.skipped++
27
+ // Drop legacy raw copies from previous installs (root index.tsx + dist/tui.tsx).
28
+ // The loader consumes only the bundle, so stale raws must not linger.
29
+ if (!dryRun) {
30
+ rmSync(join(dstDir, 'index.tsx'), { force: true })
31
+ rmSync(join(dstDir, 'dist', 'tui.tsx'), { force: true })
36
32
  }
37
33
 
38
34
  // Copy dist/* files
@@ -95,31 +91,9 @@ export function installPlugin(srcDir, dstDir, { dryRun = false, clean = false }
95
91
  result.skipped += copyResult.skipped
96
92
 
97
93
  // Install plugin dependencies (@opentui/core, @opentui/solid, solid-js).
98
- // npm ci is deterministic when the copied lockfile is present. The legacy
99
- // fallback is opt-in because npm install may rewrite the dependency graph.
94
+ // Lockfile installation is the only accepted dependency path.
100
95
  if (!dryRun) {
101
- try {
102
- execSync('npm ci --omit=dev --no-audit --no-fund', { cwd: dstDir, stdio: 'pipe' })
103
- } catch (e) {
104
- if (process.env.PANTHEON_ALLOW_NPM_INSTALL_FALLBACK === '1') {
105
- warning(`npm ci failed; explicit fallback enabled: ${e.message}`)
106
- try {
107
- execSync('npm install --omit=dev --no-audit --no-fund --package-lock=false', {
108
- cwd: dstDir,
109
- stdio: 'pipe',
110
- })
111
- } catch (fallbackError) {
112
- warning(`Failed to install TUI plugin dependencies: ${fallbackError.message}`)
113
- result.errors++
114
- }
115
- } else {
116
- warning(
117
- `npm ci failed; dependencies were not changed. Set ` +
118
- `PANTHEON_ALLOW_NPM_INSTALL_FALLBACK=1 to explicitly allow npm install: ${e.message}`,
119
- )
120
- result.errors++
121
- }
122
- }
96
+ execSync('npm ci --omit=dev --no-audit --no-fund', { cwd: dstDir, stdio: 'pipe' })
123
97
  }
124
98
 
125
99
  return result
@@ -133,14 +107,7 @@ export function installPlugin(srcDir, dstDir, { dryRun = false, clean = false }
133
107
  */
134
108
  export function installPluginDependencies(pluginDir, { dryRun = false } = {}) {
135
109
  if (dryRun) return
136
- try {
137
- execSync('npm ci --omit=dev --no-audit --no-fund', { cwd: pluginDir, stdio: 'pipe' })
138
- } catch (e) {
139
- warning(
140
- `npm ci failed; dependencies were not changed. Set ` +
141
- `PANTHEON_ALLOW_NPM_INSTALL_FALLBACK=1 to explicitly allow npm install: ${e.message}`,
142
- )
143
- }
110
+ execSync('npm ci --omit=dev --no-audit --no-fund', { cwd: pluginDir, stdio: 'pipe' })
144
111
  }
145
112
 
146
113
  /**
@@ -2,12 +2,15 @@
2
2
  * shared.mjs — Shared utilities for the OpenCode installer
3
3
  */
4
4
 
5
+ import { spawnSync } from 'node:child_process'
5
6
  import {
7
+ copyFileSync,
6
8
  cpSync,
7
9
  existsSync,
8
10
  mkdirSync,
9
11
  readdirSync,
10
12
  readFileSync,
13
+ renameSync,
11
14
  rmSync,
12
15
  statSync,
13
16
  writeFileSync,
@@ -41,7 +44,7 @@ export function getAgentNames() {
41
44
  // Cached constant for backward compatibility
42
45
  export const AGENT_NAMES = getAgentNames()
43
46
 
44
- export const summary = { opencode: { created: 0, skipped: 0, errors: 0 } }
47
+ export const summary = { opencode: { created: 0, skipped: 0, errors: 0, warnings: 0 } }
45
48
 
46
49
  export function showHelp() {
47
50
  console.log(`
@@ -260,11 +263,49 @@ export function writeIfChanged(filePath, content, dryRun) {
260
263
  return 'skipped'
261
264
  }
262
265
  if (!dryRun) {
263
- writeFileSync(filePath, content, 'utf8')
266
+ // Atomic write: write a temp sibling and rename over the target so a
267
+ // crash mid-write can never leave a truncated file behind (rename is
268
+ // atomic within the same directory).
269
+ const tmpPath = `${filePath}.tmp-${process.pid}`
270
+ writeFileSync(tmpPath, content, 'utf8')
271
+ renameSync(tmpPath, filePath)
264
272
  }
265
273
  return 'created'
266
274
  }
267
275
 
276
+ /**
277
+ * beta.5: write the user's opencode.json with a same-directory backup of the
278
+ * previous content. The installer rewrites the whole config; a `.bak` gives
279
+ * the user a one-step recovery if a merge ever goes wrong.
280
+ */
281
+ export function writeConfigWithBackup(filePath, content, dryRun) {
282
+ if (!dryRun && existsSync(filePath)) {
283
+ copyFileSync(filePath, `${filePath}.bak`)
284
+ }
285
+ return writeIfChanged(filePath, content, dryRun)
286
+ }
287
+
288
+ /**
289
+ * beta.5 preflight: verify the toolchain pieces the runtime component needs
290
+ * BEFORE any files are written, so a missing python3/npm fails in seconds
291
+ * with a clear message instead of aborting a half-done install.
292
+ * Returns a list of human-readable problems (empty = all good).
293
+ */
294
+ export function checkRuntimePrerequisites(env = process.env) {
295
+ const problems = []
296
+ const checks = [
297
+ { cmd: 'python3', hint: 'install Python 3.10+ (https://www.python.org/downloads/)' },
298
+ { cmd: 'npm', hint: 'install Node.js 22+ (https://nodejs.org) — npm ships with it' },
299
+ ]
300
+ for (const { cmd, hint } of checks) {
301
+ const probe = spawnSync(cmd, ['--version'], { encoding: 'utf8', timeout: 10_000, env })
302
+ if (probe.error || probe.status !== 0) {
303
+ problems.push(`${cmd} not found or not runnable — ${hint}`)
304
+ }
305
+ }
306
+ return problems
307
+ }
308
+
268
309
  export function collectSkillNames() {
269
310
  const skillsDir = join(ROOT, 'src', 'skills')
270
311
  if (!existsSync(skillsDir)) return []
@@ -0,0 +1,129 @@
1
+ /**
2
+ * strings.mjs — installer strings with locale auto-detection.
3
+ *
4
+ * LANG/LC_ALL/LC_MESSAGES starting with "pt" selects the PT-BR table;
5
+ * everything else (and the absence of a locale) selects EN. A plain string
6
+ * table — deliberately no i18n framework (YAGNI).
7
+ *
8
+ * Scope: the user journey (banner → install steps → health → summary →
9
+ * next steps). Deep diagnostics (per-file copy detail, doctor output) and
10
+ * the model-picker wizard remain single-language by design.
11
+ */
12
+
13
+ const TABLE = {
14
+ en: {
15
+ installing: 'Installing...',
16
+ dryRun: 'DRY RUN',
17
+ canceled: 'Installation canceled — nothing was broken; run init again anytime.',
18
+ canceledShort: 'Installation canceled.',
19
+ installFailed: (msg) => `❌ Installation failed: ${msg}`,
20
+ failHintNoMcp:
21
+ ' Run with --no-mcp to skip Python dependencies:\n npx pantheon-opencode init --no-mcp',
22
+ failHintForce:
23
+ ' Or retry with --force to recreate the venv:\n npx pantheon-opencode init --force',
24
+ runningHealthCheck: 'Running health check...',
25
+ installedTitle: (v) => `✅ Pantheon OpenCode v${v} installed!`,
26
+ nextSteps: 'Next steps:',
27
+ nextVerify: '1. Verify installation:\n npx pantheon-opencode doctor',
28
+ nextLaunch: '2. Launch OpenCode',
29
+ nextAgents: '3. Invoke agents with @agent-name in chat',
30
+ nextProject: '4. For project-local install:\n npx pantheon-opencode init --project',
31
+ // install steps
32
+ globalLayout:
33
+ 'Global config directory detected — using flat layout (agents/, skills/, commands/)',
34
+ installingAgents: 'Installing agents',
35
+ installingSkills: 'Installing skills',
36
+ installingInstructions: 'Installing instructions',
37
+ installingPrompts: 'Installing prompts',
38
+ installingCommands: 'Installing commands',
39
+ installingPlugins: 'Installing plugins',
40
+ settingUpRuntime: 'Setting up Python virtual environment',
41
+ healthSection: 'Health Check',
42
+ runningHealthChecks: 'Running health checks',
43
+ runtimeFailed: (msg) => `Python runtime setup failed: ${msg}`,
44
+ runtimeSkippedMcp:
45
+ 'MCP servers were NOT configured because the Python runtime is unavailable. ' +
46
+ 'Fix python3 (or free disk space) and re-run init to add them; everything else was installed.',
47
+ prereqMissing:
48
+ 'runtime prerequisites missing — install the tools above, or re-run with --no-mcp to install without Python MCP servers',
49
+ v2Migrating: 'Migrating config to V2 native format...',
50
+ // summary (printSummary)
51
+ summaryInstalled: (target) => `OpenCode installed in ${target}`,
52
+ summaryWithErrors: (target) => `Installation finished WITH ERRORS in ${target}`,
53
+ summaryComponents: (created, skipped) =>
54
+ ` Components:\t${created} installed, ${skipped} skipped`,
55
+ summaryErrors: (n) => ` ${n} error(s) found`,
56
+ summaryWarnings: (n) => ` ${n} warning(s) — run 'doctor' for details`,
57
+ summaryNext: ' Next steps:',
58
+ summaryNextAgents: ' • Configure your agents in opencode.json',
59
+ summaryNextMcp: ' • Add MCP servers in opencode.json (mcp section)',
60
+ summaryNextDoctor: " • Run 'opencode doctor' to verify the installation",
61
+ },
62
+ pt: {
63
+ installing: 'Instalando...',
64
+ dryRun: 'SIMULAÇÃO',
65
+ canceled: 'Instalação cancelada — nada foi quebrado; rode init de novo quando quiser.',
66
+ canceledShort: 'Instalação cancelada.',
67
+ installFailed: (msg) => `❌ Instalação falhou: ${msg}`,
68
+ failHintNoMcp:
69
+ ' Rode com --no-mcp para pular dependências Python:\n npx pantheon-opencode init --no-mcp',
70
+ failHintForce:
71
+ ' Ou tente de novo com --force para recriar a venv:\n npx pantheon-opencode init --force',
72
+ runningHealthCheck: 'Rodando verificação de saúde...',
73
+ installedTitle: (v) => `✅ Pantheon OpenCode v${v} instalado!`,
74
+ nextSteps: 'Próximos passos:',
75
+ nextVerify: '1. Verifique a instalação:\n npx pantheon-opencode doctor',
76
+ nextLaunch: '2. Abra o OpenCode',
77
+ nextAgents: '3. Invoc agentes com @nome-do-agente no chat',
78
+ nextProject: '4. Para instalar no projeto:\n npx pantheon-opencode init --project',
79
+ // install steps
80
+ globalLayout:
81
+ 'Diretório de config global detectado — layout plano (agents/, skills/, commands/)',
82
+ installingAgents: 'Instalando agentes',
83
+ installingSkills: 'Instalando skills',
84
+ installingInstructions: 'Instalando instruções',
85
+ installingPrompts: 'Instalando prompts',
86
+ installingCommands: 'Instalando comandos',
87
+ installingPlugins: 'Instalando plugins',
88
+ settingUpRuntime: 'Configurando ambiente virtual Python',
89
+ healthSection: 'Verificação de saúde',
90
+ runningHealthChecks: 'Rodando verificações de saúde',
91
+ runtimeFailed: (msg) => `Falha ao configurar o runtime Python: ${msg}`,
92
+ runtimeSkippedMcp:
93
+ 'Os servidores MCP NÃO foram configurados porque o runtime Python está indisponível. ' +
94
+ 'Corrija o python3 (ou libere espaço em disco) e rode init de novo para adicioná-los; todo o resto foi instalado.',
95
+ prereqMissing:
96
+ 'pré-requisitos do runtime ausentes — instale as ferramentas acima, ou rode de novo com --no-mcp para instalar sem os MCPs Python',
97
+ v2Migrating: 'Migrando config para o formato nativo V2...',
98
+ // summary (printSummary)
99
+ summaryInstalled: (target) => `OpenCode instalado em ${target}`,
100
+ summaryWithErrors: (target) => `Instalação concluída COM ERROS em ${target}`,
101
+ summaryComponents: (created, skipped) =>
102
+ ` Componentes:\t${created} instalados, ${skipped} pulados`,
103
+ summaryErrors: (n) => ` ${n} erro(s) encontrados`,
104
+ summaryWarnings: (n) => ` ${n} aviso(s) — rode 'doctor' para detalhes`,
105
+ summaryNext: ' Próximos passos:',
106
+ summaryNextAgents: ' • Configure seus agentes em opencode.json',
107
+ summaryNextMcp: ' • Adicione MCP servers em opencode.json (seção mcp)',
108
+ summaryNextDoctor: " • Rode 'opencode doctor' para verificar a instalação",
109
+ },
110
+ }
111
+
112
+ /** Pure locale resolution (exported for tests). */
113
+ export function detectLocale(env = process.env) {
114
+ const raw = env.LC_ALL ?? env.LC_MESSAGES ?? env.LANG ?? ''
115
+ return /^pt/i.test(raw) ? 'pt' : 'en'
116
+ }
117
+
118
+ /** Pure table access (exported for tests and explicit-locale callers). */
119
+ export function stringsFor(locale) {
120
+ return TABLE[locale] ?? TABLE.en
121
+ }
122
+
123
+ let cached = null
124
+
125
+ /** Locale-resolved string table for the current process. */
126
+ export function strings(env = process.env) {
127
+ if (cached === null) cached = stringsFor(detectLocale(env))
128
+ return cached
129
+ }
@@ -221,6 +221,7 @@ export const MCPS = {
221
221
  type: 'local',
222
222
  command: VENV_PYTHON,
223
223
  args: [CODE_MODE_SERVER],
224
+ cwd: '.',
224
225
  },
225
226
  },
226
227
  env: [],