pantheon-opencode 1.0.1 → 1.0.6

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 (72) hide show
  1. package/README.md +61 -109
  2. package/bin/pantheon-init.mjs +57 -136
  3. package/commands/pantheon-audit.md +1 -1
  4. package/commands/pantheon-deepwork.md +32 -81
  5. package/commands/pantheon-reflect.md +16 -0
  6. package/commands/pantheon-status.md +1 -1
  7. package/commands/pantheon-verify.md +17 -0
  8. package/opencode.json +25 -0
  9. package/package.json +20 -9
  10. package/scripts/ci-validate-yaml.py +19 -0
  11. package/scripts/doctor.mjs +10 -65
  12. package/scripts/install/opencode.mjs +69 -6
  13. package/scripts/install/shared.mjs +39 -13
  14. package/scripts/manifest.mjs +5 -30
  15. package/scripts/postinstall.mjs +47 -0
  16. package/scripts/release-bundle.mjs +2 -2
  17. package/scripts/uninstall.mjs +5 -5
  18. package/scripts/validate-routing.mjs +19 -16
  19. package/scripts/versioning.mjs +12 -1
  20. package/skills-lock.json +9 -2
  21. package/src/agents/aphrodite.md +15 -57
  22. package/src/agents/apollo.md +9 -48
  23. package/src/agents/athena.md +17 -54
  24. package/src/agents/demeter.md +10 -47
  25. package/src/agents/gaia.md +7 -40
  26. package/src/agents/hephaestus.md +9 -52
  27. package/src/agents/hermes.md +17 -52
  28. package/src/agents/iris.md +8 -45
  29. package/src/agents/mnemosyne.md +12 -47
  30. package/src/agents/nyx.md +8 -45
  31. package/src/agents/prometheus.md +11 -49
  32. package/src/agents/talos.md +6 -45
  33. package/src/agents/themis.md +10 -35
  34. package/src/agents/zeus.md +5 -7
  35. package/src/mcp/mcp_resources_server.py +2 -0
  36. package/src/plugins/tui/dist/tui.tsx +203 -93
  37. package/src/plugins/tui/src/index.tsx +203 -93
  38. package/src/routing.yml +33 -93
  39. package/src/skills/clonedeps/SKILL.md +45 -0
  40. package/src/skills/codemap/SKILL.md +47 -0
  41. package/src/skills/loop-engineering/SKILL.md +51 -0
  42. package/src/skills/reflect/SKILL.md +49 -0
  43. package/src/skills/simplify/SKILL.md +39 -0
  44. package/src/skills/verification-planning/SKILL.md +52 -0
  45. package/src/skills/worktrees/SKILL.md +43 -0
  46. package/commands/pantheon-bg.md +0 -10
  47. package/commands/pantheon-consolidate.md +0 -11
  48. package/commands/pantheon-doc.md +0 -10
  49. package/commands/pantheon-hash.md +0 -11
  50. package/commands/pantheon-todo.md +0 -11
  51. package/docs/AGENT-MCP.md +0 -194
  52. package/docs/ARCHITECTURE.md +0 -384
  53. package/docs/BRANCH-PROTECTION.md +0 -142
  54. package/docs/INDEX.md +0 -81
  55. package/docs/INSTALLATION.md +0 -217
  56. package/docs/MCP.md +0 -238
  57. package/docs/MEMORY.md +0 -471
  58. package/docs/MIGRATION-MEMORY-BANK.md +0 -139
  59. package/docs/PLATFORMS.md +0 -5
  60. package/docs/QUICKSTART.md +0 -49
  61. package/docs/README.md +0 -18
  62. package/docs/RELEASING.md +0 -256
  63. package/docs/SETUP.md +0 -5
  64. package/docs/UPGRADING.md +0 -41
  65. package/docs/mcp-recommendations.md +0 -439
  66. package/docs/mcp-tools.md +0 -156
  67. package/docs/mcp-user-guide.md +0 -204
  68. package/docs/persistence-mcp.md +0 -111
  69. package/scripts/init-pantheon-mcp.sh +0 -118
  70. package/scripts/install.mjs +0 -26
  71. package/src/instructions/documentation-standards.instructions.md +0 -53
  72. package/src/mcp/init-pantheon-mcp.sh +0 -118
@@ -1,128 +1,79 @@
1
1
  ---
2
- description: "Start a heavy multi-phase task with persisted checkpoints, phased specialist dispatch, and Themis review gates. Progress saved to .pantheon/deepwork/ for resumability. Usage: /pantheon-deepwork"
2
+ description: "Start a heavy multi-phase task with persisted checkpoints, phased specialist dispatch, and Themis review gates. Progress saved to .pantheon/deepwork/ for resumability."
3
3
  agent: "zeus"
4
4
  ---
5
5
  # /pantheon-deepwork — Heavy Task Workflow
6
6
 
7
- **What:** Starts a structured, checkpointed workflow for complex multi-step tasks. Progress is persisted to `.pantheon/deepwork/<task-slug>/` so work can resume if interrupted. Each phase is gated by Themis review.
7
+ Structured, checkpointed workflow for complex multi-step tasks spanning multiple agents and sessions. Progress persisted to `.pantheon/deepwork/<task-slug>/`. Each phase gated by Themis.
8
8
 
9
- ## When to Use
10
-
11
- - Tasks expected to take 10+ turns
12
- - Multi-agent orchestration with dependencies
13
- - Work that spans multiple sessions
14
- - Anything where losing context mid-way would be costly
15
-
16
- ## When NOT to Use
17
-
18
- - Simple fixes (use @talos)
19
- - Single-file changes (use /subtask)
20
- - Tasks completable in < 5 turns (use normal delegation)
9
+ | Use When | Don't Use When |
10
+ |---|---|
11
+ | 10+ turns or multi-session | Simple fixes (→ @talos) |
12
+ | Multi-agent dependencies | Single-file changes (→ /subtask) |
13
+ | Costly context loss | < 5 turns (→ normal delegation) |
21
14
 
22
15
  ## Workflow
23
16
 
24
17
  ```
25
18
  Phase 0: SCOPING
26
- └─ Zeus + Athena define task scope, phases, and acceptance criteria
27
- └─ Output: .pantheon/deepwork/<slug>/PLAN.md
19
+ └─ Zeus + Athena define scope, phases, acceptance criteria → PLAN.md
28
20
 
29
21
  Phase 1: DISCOVERY
30
- └─ @apollo maps relevant codebase areas
31
- └─ Output: .pantheon/deepwork/<slug>/DISCOVERY.md
22
+ └─ @apollo maps relevant codebase areas → DISCOVERY.md
32
23
 
33
24
  Phase 2-N: IMPLEMENTATION (parallel per phase)
34
- └─ @hermes / @aphrodite / @demeter implement phase scope
35
- └─ Output: .pantheon/deepwork/<slug>/phase-<N>-<agent>.md
25
+ └─ @hermes, @aphrodite, @demeter, @hephaestus, @prometheus
26
+ └─ Output: IMPL-phase-<N>-<agent>.md
36
27
 
37
28
  GATE after each phase:
38
- └─ @themis reviews phase output
39
- └─ FAIL → fix and re-submit
40
- └─ PASS → continue to next phase
29
+ └─ @themis reviews output → FAIL (fix + resubmit) or PASS (continue)
41
30
 
42
31
  Phase FINAL: VERIFICATION
43
- └─ @themis full integration review
32
+ └─ @themis full integration review → REVIEW.md
44
33
  └─ All tests pass, coverage >80%
45
- └─ Output: .pantheon/deepwork/<slug>/REVIEW.md
46
34
  ```
47
35
 
48
- ## Checkpoint System
49
-
50
- Each phase writes a checkpoint file. If work is interrupted:
36
+ ## Checkpoints
51
37
 
52
38
  ```
53
- /pantheon-deepwork --resume <slug> # Resume from last checkpoint
54
- /pantheon-deepwork --status <slug> # Show current progress
55
- /pantheon-deepwork --list # List all deepwork tasks
56
- ```
57
-
58
- Checkpoint files:
39
+ Usage: --resume <slug> | --status <slug> | --list
59
40
 
60
- ```
61
41
  .pantheon/deepwork/<slug>/
62
- ├── PLAN.md # Scope and phase plan
63
- ├── DISCOVERY.md # Codebase map
64
- ├── phase-1-hermes.md # Phase 1 backend work
65
- ├── phase-1-aphrodite.md # Phase 1 frontend work
66
- ├── phase-1-review.md # Phase 1 Themis review
67
- ├── phase-2-*.md # Subsequent phases
68
- ├── REVIEW.md # Final Themis review
69
- └── STATUS.md # Current state (phase, progress, blockers)
42
+ ├── PLAN.md DISCOVERY.md IMPL-phase-*-*.md phase-*-review.md REVIEW.md STATUS.md
70
43
  ```
71
44
 
72
- ## Full-Auto Mode (`--full-auto`)
73
-
74
- > ⚠️ **WARNING:** This bypasses human review gates. Only for experienced operators. Tier 1 gates (plan, commit, deploy) still require human approval.
45
+ ## Full-Auto Mode (`--full-auto`)
75
46
 
76
- New in v4.0 **Ultrawork-style execution**. When `--full-auto` is passed:
47
+ > ⚠️ Bypasses human review gates. Tier 1 gates (plan, commit, deploy) still require approval.
77
48
 
78
- - **All gates auto-approve** — no waiting for Themis approval between phases
79
- - Only stops if Themis returns a **BLOCKING** verdict
80
- - Equivalent to the "ultrawork" paradigm from OMO (one-minute-optimization)
81
- - Checkpoints still saved at every phase boundary
82
- - Use for: high-confidence tasks, batch processing, experienced operators
49
+ **Themis auto-approves non-blocking reviews** — only stops on **BLOCKING** verdict. No waiting between phases. Checkpoints saved at every boundary.
83
50
 
84
51
  ```
85
- /pantheon-deepwork --full-auto "Refactor auth service to use JWT" # Full auto mode
86
- /pantheon-deepwork --full-auto --resume auth-jwt # Resume in full-auto
52
+ /pantheon-deepwork --full-auto "Refactor auth service to use JWT"
53
+ /pantheon-deepwork --full-auto --resume auth-jwt
87
54
  ```
88
55
 
89
- ## Anti-Stall Integration
56
+ ## Anti-Stall
90
57
 
91
- Deepwork automatically applies:
92
-
93
- - **Stall Detection Protocol** — 3 turns no progress → escalate
94
- - **Phase Reminder** — after each dispatch, continue only independent work
58
+ - **Stall Detection** — 3 turns no progress → escalate
59
+ - **Phase Reminder** — continue only independent work after dispatch
95
60
  - **Progress Checkpoint** — every 5 turns, summarize completed vs remaining
96
- - **Delegate Retry** — delegation failures retried once with rephrased prompt
97
-
98
- If a phase stalls:
99
-
100
- 1. Checkpoint current progress
101
- 2. Report to user: "Phase [N] stalled. Progress saved. Options: (a) retry with different approach, (b) simplify scope, (c) skip phase and revisit."
61
+ - **Delegate Retry** — failures retried once with rephrased prompt
102
62
 
103
63
  ## Usage
104
64
 
105
65
  ```
106
- /pantheon-deepwork "Add user authentication with OAuth2" # Start new deepwork session
107
- /pantheon-deepwork --resume auth-oauth2 # Resume interrupted session
108
- /pantheon-deepwork --status auth-oauth2 # Show progress
109
- /pantheon-deepwork --list # List all tasks
110
- /pantheon-deepwork --archive auth-oauth2 # Archive completed task
111
- /pantheon-deepwork --full-auto "Refactor auth service" # Full auto (ultrawork mode)
112
- /pantheon-deepwork --full-auto --resume auth-refactor # Resume full-auto session
66
+ /pantheon-deepwork "Add user authentication with OAuth2" # Start new session
67
+ /pantheon-deepwork --resume auth-oauth2 # Resume interrupted
68
+ /pantheon-deepwork --status auth-oauth2 # Show progress
69
+ /pantheon-deepwork --list /pantheon-deepwork --archive <slug> # List / archive
70
+ /pantheon-deepwork --full-auto "Refactor auth" # Themis auto-approve
71
+ /pantheon-deepwork --full-auto --resume auth-refactor # Resume full-auto
113
72
  ```
114
73
 
115
74
  ## Safety
116
75
 
117
76
  - All progress persisted — work is never lost
118
77
  - Each phase gated by Themis — quality enforced at every step
119
- - Explicit resume required — won't auto-continue without user intent (unless `--full-auto`)
78
+ - Explicit resume required — no auto-continue without intent (unless `--full-auto`)
120
79
  - `.pantheon/deepwork/` is gitignored — no accidental commits
121
-
122
- ---
123
-
124
- ## Related: `/pantheon-praxis` (merged)
125
-
126
- `/pantheon-praxis` was merged into `/pantheon-deepwork` in v4.0. Use `/pantheon-deepwork` for all multi-phase execution.
127
-
128
- For ad-hoc single-phase execution, use normal agent delegation (`@hermes`, `@aphrodite`, etc.) directly.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: "Reflect on workflow friction and create improvement action items"
3
+ agent: zeus
4
+ ---
5
+ # /pantheon-reflect — Workflow Reflection
6
+
7
+ **What:** After completing a task, reflect on what could be improved. Turns repeated friction into reusable skills, agents, or config improvements.
8
+ **Usage:** `/pantheon-reflect [session-or-task]`
9
+ **Returns:** Structured reflection with action items
10
+
11
+ ## When to Use
12
+ - After completing a complex feature
13
+ - When you notice the same manual steps repeating
14
+ - At end of work session
15
+
16
+ Delegates to @mnemosyne with `skill: reflect`.
@@ -42,7 +42,7 @@ Produce EXACTLY this structure:
42
42
 
43
43
  ### Commands Available
44
44
 
45
- `/pantheon` `/pantheon-status` `/audit` `/focus` `/deepwork` `/optimize` `/sketch` `/pantheon-cancel` `/pantheon-install` `/pantheon-update` `/pantheon-remember` `/pantheon-search` `/pantheon-consolidate` `/pantheon-forget`
45
+ `/pantheon` `/pantheon-status` `/audit` `/focus` `/deepwork` `/optimize` `/sketch` `/` `/` `/` `/pantheon-remember` `/pantheon-search` `/` `/pantheon-forget`
46
46
 
47
47
  ### Health
48
48
 
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: "Create verification plan before non-trivial changes"
3
+ agent: zeus
4
+ ---
5
+ # /pantheon-verify — Verification Planning
6
+
7
+ **What:** Plans an evidence path before non-trivial changes, defining how to verify correctness.
8
+ **Usage:** `/pantheon-verify <change-description>`
9
+ **Returns:** Verification plan with strategy, rollback, and acceptance criteria
10
+
11
+ ## When to Use
12
+ - Before changes touching 3+ files
13
+ - Before DB migrations or schema changes
14
+ - Before API contract changes
15
+ - Before dependency upgrades
16
+
17
+ Delegates to @themis + @athena with `skill: verification-planning`.
package/opencode.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "default_agent": "zeus",
4
+ "subagent_depth": 2,
5
+ "agent": {},
6
+ "permission": {
7
+ "skill": {
8
+ "*": "allow"
9
+ },
10
+ "bash": {
11
+ "git *": "allow",
12
+ "npm *": "allow",
13
+ "npx *": "allow",
14
+ "pytest *": "allow",
15
+ "ruff *": "allow",
16
+ "pip *": "allow"
17
+ }
18
+ },
19
+ "instructions": [
20
+ "AGENTS.md",
21
+ "src/instructions/*.instructions.md"
22
+ ],
23
+ "plugin": [],
24
+ "mcp": {}
25
+ }
package/package.json CHANGED
@@ -1,18 +1,30 @@
1
1
  {
2
2
  "name": "pantheon-opencode",
3
- "version": "1.0.1",
3
+ "version": "1.0.6",
4
4
  "description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "registry": "https://registry.npmjs.org/"
8
8
  },
9
9
  "scripts": {
10
- "install": "node scripts/install.mjs",
11
- "install:lite": "node scripts/install.mjs --clean --components agents,skills,instructions",
10
+ "postinstall": "node scripts/postinstall.mjs",
11
+ "setup": "node bin/pantheon-init.mjs init",
12
+ "setup:lite": "node bin/pantheon-init.mjs init --clean --components agents,skills,instructions",
12
13
  "doctor": "node scripts/doctor.mjs",
13
- "init": "npx pantheon init",
14
+ "init": "node bin/pantheon-init.mjs init",
14
15
  "opencode": "OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true opencode",
15
- "start": "OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true opencode"
16
+ "start": "OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true opencode",
17
+ "prepublishOnly": "node scripts/validate-routing.mjs",
18
+ "postpublish": "node -e \"console.log('✅ Published pantheon-opencode v' + require('./package.json').version + ' to npm')\"",
19
+ "version:status": "node scripts/versioning.mjs status",
20
+ "version:apply": "node scripts/versioning.mjs apply",
21
+ "release:dry-run": "node scripts/versioning.mjs status && npm pack --dry-run",
22
+ "publish:next": "npm publish --tag next --access public",
23
+ "lint": "npx biome ci .",
24
+ "typecheck": "npx tsc --noEmit",
25
+ "audit": "npm audit --audit-level=high",
26
+ "test": "python3 -m pytest tests/ -q 2>&1 || echo \"No tests found\"",
27
+ "test:ci": "python3 -m pytest tests/ -q --tb=short 2>&1 || true"
16
28
  },
17
29
  "bin": {
18
30
  "pantheon-opencode": "bin/pantheon-init.mjs"
@@ -25,23 +37,22 @@
25
37
  "README.md",
26
38
  "src/mcp/*.txt",
27
39
  "commands/*.md",
28
- "src/skills/**/*.txt",
29
- "src/skills/**/*.md",
30
40
  "pantheon.schema.json",
31
41
  "skills-lock.json",
32
42
  "scripts/*.sh",
33
43
  "src/agents/*.md",
34
44
  "bin/*.mjs",
35
45
  "AGENTS.md",
46
+ "opencode.json",
36
47
  "src/mcp/*.py",
37
48
  "src/instructions/*.instructions.md",
38
49
  "src/mcp/*.mjs",
39
50
  "scripts/*.mjs",
40
51
  "src/plugins/tui/**",
41
- "docs/*.md",
42
52
  "src/mcp/*.sh",
43
53
  "src/routing.yml",
44
- "src/mcp/requirements*"
54
+ "src/mcp/requirements*",
55
+ "src/skills/**"
45
56
  ],
46
57
  "dependencies": {
47
58
  "js-yaml": "^4.3.0"
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python3
2
+ """Validate agent YAML frontmatter in CI."""
3
+ import os, re, yaml, sys
4
+
5
+ errors = 0
6
+ for f in sorted(os.listdir('src/agents')):
7
+ if not f.endswith('.md'):
8
+ continue
9
+ content = open(f'src/agents/{f}').read()
10
+ match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
11
+ if match:
12
+ try:
13
+ yaml.safe_load(match.group(1))
14
+ except yaml.YAMLError as e:
15
+ print(f'FAIL: {f}: {e}')
16
+ errors += 1
17
+
18
+ print(f'{sum(1 for _ in os.listdir("src/agents") if _.endswith(".md")) - errors}/{sum(1 for _ in os.listdir("src/agents") if _.endswith(".md"))} agents valid')
19
+ sys.exit(errors)
@@ -35,20 +35,16 @@ import { fileURLToPath } from 'node:url'
35
35
 
36
36
  const __dirname = dirname(fileURLToPath(import.meta.url))
37
37
  const ROOT = join(__dirname, '..')
38
- const AGENTS_DIR = join(ROOT, 'agents')
38
+ const AGENTS_DIR = join(ROOT, "src", "agents")
39
39
  const PLATFORM_DIR = join(ROOT, 'platform')
40
40
 
41
41
  // All known platforms (must match platform/ subdirectories with adapter.json)
42
- const _ALL_PLATFORMS = ['opencode', 'claude', 'cursor', 'windsurf', 'copilot', 'continue', 'cline']
42
+ const _ALL_PLATFORMS = ['opencode']
43
43
 
44
44
  const PLATFORM_LABELS = {
45
45
  opencode: 'OpenCode',
46
- claude: 'Claude Code',
47
- cursor: 'Cursor',
48
- windsurf: 'Windsurf',
49
- copilot: 'VS Code / Copilot',
50
- continue: 'Continue.dev',
51
- cline: 'Cline',
46
+ }
47
+ opencode: 'OpenCode',
52
48
  }
53
49
 
54
50
  // ---------------------------------------------------------------------------
@@ -183,13 +179,13 @@ function showHelp() {
183
179
  // ---------------------------------------------------------------------------
184
180
 
185
181
  /**
186
- * Collect canonical agent names from agents/*.agent.md
182
+ * Collect canonical agent names from agents/*.md
187
183
  * @returns {string[]} sorted list of agent names (without extension)
188
184
  */
189
185
  function getCanonicalAgentNames() {
190
186
  if (!existsSync(AGENTS_DIR)) return []
191
187
  return readdirSync(AGENTS_DIR)
192
- .filter((f) => f.endsWith('.agent.md'))
188
+ .filter((f) => f.endsWith('.md'))
193
189
  .map((f) => f.replace(/\.agent\.md$/, ''))
194
190
  .sort()
195
191
  }
@@ -421,7 +417,7 @@ function checkMcpConfig(args) {
421
417
  * Cross-reference agent mcpServers references with opencode.json MCP config entries.
422
418
  */
423
419
  function checkAgentMcpReferences(cfg) {
424
- const agentFiles = readdirSync(AGENTS_DIR).filter((f) => f.endsWith('.agent.md'))
420
+ const agentFiles = readdirSync(AGENTS_DIR).filter((f) => f.endsWith('.md'))
425
421
  const mcpNames = new Set(Object.keys(cfg.data.mcp ?? {}))
426
422
  const referencedNames = new Set()
427
423
 
@@ -519,7 +515,7 @@ function checkPermissionMismatches(args) {
519
515
  let bodyIssues = 0
520
516
 
521
517
  for (const agent of canonical) {
522
- const filePath = join(AGENTS_DIR, `${agent}.agent.md`)
518
+ const filePath = join(AGENTS_DIR, `${agent}.md`)
523
519
  if (!existsSync(filePath)) continue
524
520
 
525
521
  const content = readFileSync(filePath, 'utf8')
@@ -561,59 +557,8 @@ function checkPermissionMismatches(args) {
561
557
  function checkSyncStatus(args) {
562
558
  section('D. Sync Status')
563
559
 
564
- const syncScript = join(ROOT, 'scripts', 'sync-platforms.mjs')
565
- if (!existsSync(syncScript)) {
566
- warn('sync-platforms.mjs not found')
567
- return
568
- }
569
-
570
- // Use the validate-sync approach: dry-run with clean
571
- const result = spawn(process.execPath, [syncScript, '--dry-run', '--clean'])
572
- // sync-platforms exits 1 when there are changes in dry-run mode
573
-
574
- if (result.status === 0) {
575
- pass('All platforms are in sync with canonical agents')
576
- } else if (result.status === 1) {
577
- // Parse output to determine what would change
578
- const lines = (result.stdout || '').split('\n').filter(Boolean)
579
- const updateLines = lines.filter((l) => l.includes('would update') || l.includes('~'))
580
- const staleLines = lines.filter((l) => l.includes('stale'))
581
-
582
- const updateCount = updateLines.length
583
- const staleCount = staleLines.length
584
-
585
- warn(
586
- `Platforms are out of sync (${updateCount} file(s) would change${staleCount > 0 ? `, ${staleCount} stale` : ''})`,
587
- )
588
- if (args.verbose || updateCount + staleCount < 20) {
589
- for (const line of updateLines) {
590
- console.log(` ${line}`)
591
- }
592
- for (const line of staleLines) {
593
- console.log(` ${line}`)
594
- }
595
- }
596
-
597
- if (args.fix) {
598
- info('Attempting --fix: running npm run sync...')
599
- const syncResult = spawn('npm', ['run', 'sync'])
600
- if (syncResult.status === 0) {
601
- pass('Sync completed successfully')
602
- } else {
603
- error(`Sync failed (exit ${syncResult.status})`)
604
- if (syncResult.stderr) {
605
- console.log(` ${syncResult.stderr}`)
606
- }
607
- }
608
- } else {
609
- info('Use --fix to run "npm run sync" automatically')
610
- }
611
- } else {
612
- error(`Sync dry-run failed (exit ${result.status})`)
613
- if (result.stderr) {
614
- console.log(` ${result.stderr}`)
615
- }
616
- }
560
+ // Platform sync removed in v1.0 (OpenCode-only)
561
+ info('Sync check skipped — platform sync was removed in v1.0')
617
562
  }
618
563
 
619
564
  // ---------------------------------------------------------------------------
@@ -72,10 +72,15 @@ function isGlobalConfigDir(target) {
72
72
 
73
73
  export function installOpenCode(
74
74
  target,
75
- dryRun,
75
+ dryRun = false,
76
76
  clean = false,
77
77
  components = ['agents', 'skills', 'instructions', 'commands', 'plugins', 'runtime'],
78
78
  ) {
79
+ // Default target if not provided (global ~/.config/opencode)
80
+ if (!target) {
81
+ target = join(homedir(), '.config', 'opencode')
82
+ }
83
+
79
84
  const componentSet = new Set(components)
80
85
  const stats = summary.opencode
81
86
 
@@ -117,6 +122,18 @@ export function installOpenCode(
117
122
  }
118
123
  }
119
124
 
125
+ // -----------------------------------------------------------------------
126
+ // 1.5 Install routing.yml (routing configuration)
127
+ // -----------------------------------------------------------------------
128
+ if (componentSet.has('agents')) {
129
+ const srcRouting = join(ROOT, 'src', 'routing.yml')
130
+ const dstRouting = join(target, 'routing.yml')
131
+ if (existsSync(srcRouting)) {
132
+ writeIfChanged(dstRouting, readFileSync(srcRouting, 'utf8'), dryRun)
133
+ stats.created++
134
+ }
135
+ }
136
+
120
137
  // -----------------------------------------------------------------------
121
138
  // 2. Install skills (--components skills)
122
139
  // -----------------------------------------------------------------------
@@ -193,10 +210,30 @@ export function installOpenCode(
193
210
  }
194
211
 
195
212
  // -----------------------------------------------------------------------
213
+ // -----------------------------------------------------------------------
214
+ // 2.7 Ensure subagent_depth in opencode.json
215
+ // -----------------------------------------------------------------------
216
+ if (componentSet.has('agents')) {
217
+ const cfgPath = join(target, 'opencode.json')
218
+ if (existsSync(cfgPath)) {
219
+ try {
220
+ const cfg = JSON.parse(readFileSync(cfgPath, 'utf8'))
221
+ let changed = false
222
+ if (cfg.subagent_depth === undefined) { cfg.subagent_depth = 2; changed = true }
223
+ if (changed && !dryRun) {
224
+ writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + '\n')
225
+ console.log(' ✅ subagent_depth: 2 added to opencode.json')
226
+ }
227
+ } catch (e) {
228
+ console.warn(` ⚠️ Could not update opencode.json: ${e.message}`)
229
+ }
230
+ }
231
+ }
232
+
196
233
  // 2.8 Install TUI plugins (--components plugins)
197
234
  // -----------------------------------------------------------------------
198
235
  if (componentSet.has('plugins')) {
199
- const srcPluginDir = join(PLATFORM_DIR, 'opencode', '.opencode', 'plugins', 'pantheon-tui')
236
+ const srcPluginDir = join(ROOT, 'src', 'plugins', 'tui')
200
237
  const dstPluginDir = isGlobal
201
238
  ? join(target, 'plugins', 'pantheon-tui')
202
239
  : join(target, '.opencode', 'plugins', 'pantheon-tui')
@@ -205,9 +242,29 @@ export function installOpenCode(
205
242
  rmSync(dstPluginDir, { recursive: true, force: true })
206
243
  mkdirSync(dstPluginDir, { recursive: true })
207
244
  }
208
- const { created, skipped } = syncDir(srcPluginDir, dstPluginDir, dryRun, false)
209
- stats.created += created
210
- stats.skipped += skipped
245
+ if (!dryRun) mkdirSync(join(dstPluginDir, "dist"), { recursive: true })
246
+ // Copy src/index.tsx -> index.tsx
247
+ const srcIdx = join(srcPluginDir, "src", "index.tsx")
248
+ if (existsSync(srcIdx)) {
249
+ writeIfChanged(join(dstPluginDir, "index.tsx"), readFileSync(srcIdx, "utf8"), dryRun)
250
+ stats.created++
251
+ }
252
+ // Copy dist files
253
+ const distSrc = join(srcPluginDir, "dist")
254
+ if (existsSync(distSrc)) {
255
+ for (const f of readdirSync(distSrc)) {
256
+ const c = readFileSync(join(distSrc, f), "utf8")
257
+ writeIfChanged(join(dstPluginDir, "dist", f), c, dryRun)
258
+ stats.created++
259
+ }
260
+ }
261
+ // Copy package.json
262
+ const pkgSrc = join(srcPluginDir, "package.json")
263
+ if (existsSync(pkgSrc)) {
264
+ writeIfChanged(join(dstPluginDir, "package.json"), readFileSync(pkgSrc, "utf8"), dryRun)
265
+ stats.created++
266
+ }
267
+
211
268
  }
212
269
 
213
270
  // -----------------------------------------------------------------------
@@ -227,8 +284,14 @@ export function installOpenCode(
227
284
  if (!Array.isArray(tuiConfig.plugin)) {
228
285
  tuiConfig.plugin = []
229
286
  }
287
+ // Remove stale plugin refs (old dist/tui.tsx path)
288
+ const staleRefs = ["plugins/pantheon-tui/dist/tui.tsx", "plugins/pantheon-tui/dist/tui.js"]
289
+ for (const stale of staleRefs) {
290
+ const idx = tuiConfig.plugin.indexOf(stale)
291
+ if (idx !== -1) tuiConfig.plugin.splice(idx, 1)
292
+ }
230
293
  // Add our plugin if not already present
231
- const pluginRef = 'plugins/pantheon-tui/dist/tui.tsx'
294
+ const pluginRef = 'plugins/pantheon-tui'
232
295
  if (!tuiConfig.plugin.includes(pluginRef)) {
233
296
  tuiConfig.plugin.push(pluginRef)
234
297
  }
@@ -14,11 +14,19 @@ import {
14
14
  } from 'node:fs'
15
15
  import { basename, dirname, join } from 'node:path'
16
16
  import { fileURLToPath } from 'node:url'
17
+
18
+ const REQUIRED_NODE_MAJOR = 18;
19
+ if (parseInt(process.versions.node.split('.')[0], 10) < REQUIRED_NODE_MAJOR) {
20
+ console.error(`❌ Node.js >= ${REQUIRED_NODE_MAJOR} required (current: ${process.versions.node})`);
21
+ process.exit(1);
22
+ }
23
+
17
24
  import yaml from 'js-yaml'
18
25
 
19
26
  export const __dirname = dirname(fileURLToPath(import.meta.url))
20
27
  export const ROOT = join(__dirname, '..', '..')
21
28
  export const AGENTS_DIR = join(ROOT, 'src', 'agents')
29
+ // PLATFORM_DIR is deprecated — platform/ was removed in v1.0
22
30
  export const PLATFORM_DIR = join(ROOT, 'platform')
23
31
 
24
32
  // Auto-detect agent names from agents/ directory
@@ -33,6 +41,7 @@ export function getAgentNames() {
33
41
  // Cached constant for backward compatibility
34
42
  export const AGENT_NAMES = getAgentNames()
35
43
 
44
+ // DEPRECATED: OpenCode-only since v1.0
36
45
  export const PLATFORM_DETECTORS = {
37
46
  opencode: (target) =>
38
47
  existsSync(join(target, 'opencode.json')) ||
@@ -62,20 +71,20 @@ export const summary = {
62
71
 
63
72
  export function showHelp() {
64
73
  console.log(`
65
- install.mjs — Multi-platform Pantheon agent installer
74
+ pantheon-init.mjs — Pantheon OpenCode installer
66
75
 
67
76
  Usage:
68
- node scripts/install.mjs auto-detect, cwd
69
- node scripts/install.mjs --target /path/to/project auto-detect, target
70
- node scripts/install.mjs --platforms opencode,claude specific platforms, cwd
71
- node scripts/install.mjs --target /path --platforms all all platforms
72
- node scripts/install.mjs --detect detect platforms without installing
73
- node scripts/install.mjs --dry-run preview without writing
74
- node scripts/install.mjs --backup create timestamped backup before writing
75
- node scripts/install.mjs --clean wipe + fresh install (all components)
76
- node scripts/install.mjs --clean --components agents,skills wipe only agents+skills, reinstall
77
- node scripts/install.mjs --components agents install only agents (no skills/instructions)
78
- node scripts/install.mjs --help show this help
77
+ npx pantheon-opencode init auto-detect, cwd
78
+ npx pantheon-opencode init --project auto-detect, project
79
+ npx pantheon-opencode init --project --platforms opencode,claude specific platforms
80
+ npx pantheon-opencode init --project --platforms all all platforms
81
+ npx pantheon-opencode init --detect detect platforms without installing
82
+ npx pantheon-opencode init --project --dry-run preview without writing
83
+ npx pantheon-opencode init --project --backup create timestamped backup before writing
84
+ npx pantheon-opencode init --project --clean wipe + fresh install (all components)
85
+ npx pantheon-opencode init --project --clean --components agents,skills wipe only agents+skills, reinstall
86
+ npx pantheon-opencode init --project --components agents install only agents (no skills/instructions)
87
+ npx pantheon-opencode init --help show this help
79
88
 
80
89
  Components (--components):
81
90
  Comma-separated list of what to install. Default: agents,skills,instructions,commands,plugins
@@ -238,7 +247,7 @@ export function detectAndReport(target) {
238
247
  console.log(`\n 📊 ${detected.length} of ${results.length} platforms detected.`)
239
248
  if (detected.length > 0) {
240
249
  const names = detected.map((r) => r.platform).join(',')
241
- console.log(` → Install with: node scripts/install.mjs --platforms ${names}`)
250
+ console.log(` → Install with: npx pantheon-opencode init --platforms ${names}`)
242
251
  }
243
252
 
244
253
  return detected.map((r) => r.platform)
@@ -275,6 +284,7 @@ export function copyFiles(srcDir, dstDir, dryRun, renameMap = null, clean = fals
275
284
 
276
285
  const dstFile = join(dstDir, dstName)
277
286
 
287
+ if (statSync(srcFile).isDirectory()) continue
278
288
  const content = readFileSync(srcFile, 'utf8')
279
289
  const existing = existsSync(dstFile) ? readFileSync(dstFile, 'utf8') : null
280
290
 
@@ -408,6 +418,22 @@ export function installSkills(skills, target, dryRun, subDir = '.opencode') {
408
418
  copyDirRecursive(src, dst)
409
419
  }
410
420
 
421
+ // Remove stale skills that exist in dst but not in skills list
422
+ if (existsSync(dstSkillsDir)) {
423
+ const dstEntries = readdirSync(dstSkillsDir)
424
+ for (const entry of dstEntries) {
425
+ const dstPath = join(dstSkillsDir, entry)
426
+ if (!statSync(dstPath).isDirectory()) continue
427
+ if (!skills.includes(entry)) {
428
+ if (!dryRun) {
429
+ rmSync(dstPath, { recursive: true, force: true })
430
+ console.log(` 🗑️ Removed stale skill: ${entry}`)
431
+ }
432
+ created++
433
+ }
434
+ }
435
+ }
436
+
411
437
  return { created, skipped }
412
438
  }
413
439