pantheon-opencode 1.6.0-beta.10 → 1.6.0-beta.11
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 +24 -0
- package/README.md +66 -21
- package/bin/pantheon-init.mjs +44 -1
- package/package.json +4 -4
- package/plugin.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/build-agents-md.mjs +60 -6
- package/scripts/install/backup.mjs +475 -0
- package/scripts/install/cli-ui.mjs +6 -1
- package/scripts/install/exit-codes.mjs +26 -0
- package/scripts/install/interactive.mjs +15 -1
- package/scripts/install/migrate.mjs +41 -22
- package/scripts/install/opencode.mjs +562 -50
- package/scripts/install/plan.mjs +287 -0
- package/scripts/install/plugin.mjs +22 -8
- package/scripts/install/shared.mjs +89 -55
- package/scripts/install/strings.mjs +20 -0
- package/scripts/install/venv.mjs +13 -3
- package/scripts/install/vision-prompt.mjs +11 -1
- package/scripts/mcp_persistence.py +50 -15
- package/scripts/prune.mjs +9 -3
- package/scripts/restore.mjs +222 -0
- package/skills-lock.json +1 -1
- package/src/agents/iris.md +6 -0
- 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 +10 -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/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 +2 -2
- package/src/plugins/tui/package.json +1 -1
- package/src/skills/auto-continue/SKILL.md +14 -6
package/AGENTS.global.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- pantheon:generated:begin — Pantheon-managed region; regenerated on install/upgrade, never edit inside -->
|
|
2
2
|
<!-- Generated by scripts/build-agents-md.mjs — do not edit directly. -->
|
|
3
3
|
<!-- Source of truth: src/instructions/*.instructions.md + the static sections in this script. -->
|
|
4
|
-
<!-- pantheon:agents-md v2 artifact=global generated-at=2026-10-
|
|
4
|
+
<!-- pantheon:agents-md v2 artifact=global generated-at=2026-10-15T14:32:32-03:00 sha=66bf918 -->
|
|
5
5
|
|
|
6
6
|
# Pantheon Agent System — OpenCode
|
|
7
7
|
|
|
@@ -76,7 +76,7 @@ the complete plan in the current conversation before requesting approval.
|
|
|
76
76
|
|
|
77
77
|
## Council Specialist Response Format
|
|
78
78
|
|
|
79
|
-
When responding to a `/pantheon` council synthesis invocation, specialists MUST return this structured format
|
|
79
|
+
When responding to a `/pantheon` council synthesis invocation, specialists MUST return this structured format. First-round specialists receive independent prompts without peer responses, whether dispatch is parallel or synchronous/sequential; they therefore cannot know actual peer positions. Do not guess them, claim agreement/disagreement with unseen peers, or self-reference in agreement signals. Omit `agreement_signals` or write `none` in the first round. In a rebuttal round, signals may reference only peer responses included in that round's prompt. Zeus derives agreement and disagreement during synthesis by comparing actual responses.
|
|
80
80
|
|
|
81
81
|
```
|
|
82
82
|
## specialist_response
|
|
@@ -85,8 +85,8 @@ When responding to a `/pantheon` council synthesis invocation, specialists MUST
|
|
|
85
85
|
**trade_offs:** <what's gained vs lost, specific>
|
|
86
86
|
**risks:** <what could go wrong, max 3 items>
|
|
87
87
|
**confidence:** High | Medium | Low
|
|
88
|
-
**agreement_signals:**
|
|
89
|
-
**specific_claims:** <
|
|
88
|
+
**agreement_signals:** <omit or `none` in first round; rebuttal may cite only visible peer responses>
|
|
89
|
+
**specific_claims:** <optional self-reported count; advisory only, not evidence>
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
### Field Rules
|
|
@@ -98,29 +98,31 @@ When responding to a `/pantheon` council synthesis invocation, specialists MUST
|
|
|
98
98
|
| trade_offs | ✅ | At least one gain and one loss, specific to context |
|
|
99
99
|
| risks | ✅ | Max 3 bullet points |
|
|
100
100
|
| confidence | ✅ | One of: High, Medium, Low |
|
|
101
|
-
| agreement_signals | Optional |
|
|
102
|
-
| specific_claims |
|
|
101
|
+
| agreement_signals | Optional | Omit or use `none` in the first round. In rebuttal, reference only peer responses visible in the prompt; never speculate or self-reference. Zeus derives synthesis positions from actual responses, not these signals. |
|
|
102
|
+
| specific_claims | Optional | Self-reported integer count only; advisory and not independently validated. Do not treat the count alone as evidence or proof of confidence. |
|
|
103
103
|
|
|
104
104
|
### Confidence Guidelines
|
|
105
105
|
|
|
106
|
-
- **High**: Position backed by 3
|
|
107
|
-
- **Medium**: Position backed by 1
|
|
106
|
+
- **High**: Position backed by at least 3 verifiable claims supported by evidence in the response; a self-reported count alone does not qualify
|
|
107
|
+
- **Medium**: Position backed by at least 1 verifiable claim supported by evidence in the response
|
|
108
108
|
- **Low**: Position is opinion-based or speculative
|
|
109
109
|
|
|
110
|
+
Equal self-reported counts (for example, several specialists each reporting 7) do not by themselves prove fabrication; assess whether the actual response contains verifiable, supported claims.
|
|
111
|
+
|
|
110
112
|
### Example
|
|
111
113
|
```
|
|
112
114
|
## specialist_response
|
|
113
|
-
**position:**
|
|
114
|
-
**reasoning:** The
|
|
115
|
-
**trade_offs:** Gain:
|
|
116
|
-
**risks:**
|
|
117
|
-
**confidence:**
|
|
118
|
-
**agreement_signals:**
|
|
119
|
-
**specific_claims:**
|
|
115
|
+
**position:** Use a bounded local cache for the read-heavy endpoint.
|
|
116
|
+
**reasoning:** The endpoint repeatedly reads the same reference data. A bounded cache reduces repeated lookups, while a short TTL limits staleness.
|
|
117
|
+
**trade_offs:** Gain: fewer repeated reads. Lose: results may remain stale until the TTL expires.
|
|
118
|
+
**risks:** Cache invalidation may lag after updates.
|
|
119
|
+
**confidence:** Medium
|
|
120
|
+
**agreement_signals:** none
|
|
121
|
+
**specific_claims:** 2 (self-reported; advisory)
|
|
120
122
|
```
|
|
121
123
|
|
|
122
124
|
## Memory Context
|
|
123
|
-
If memory affected the result, state the takeaway briefly; do not repeat the entry or task context.
|
|
125
|
+
If memory affected the result, state the takeaway briefly; do not repeat the entry or task context. If persistence was expected but no write tool was exposed or a write failed, state that it was not persisted; never imply a successful store without confirmation.
|
|
124
126
|
|
|
125
127
|
<!-- Source: src/instructions/memory-protocol.instructions.md -->
|
|
126
128
|
## Memory Protocol
|
|
@@ -138,12 +140,34 @@ These rules apply to all agents; each agent file may add domain-specific rules.
|
|
|
138
140
|
- Use a targeted query (`top_k=2`); do not search the whole prompt by default. Missing or irrelevant results never block current work.
|
|
139
141
|
|
|
140
142
|
### Persistence
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
+
- A memory write is optional and conditional on a write tool being exposed and permitted in the active session. Search permission does not imply write permission; in the reported Beta 10 Zeus root, `memory_store` is not exposed/granted.
|
|
144
|
+
- Store at most one concise, reusable top-level result; never persist routine child summaries, phase updates, test logs, or temporary state. Confirm a successful write before claiming persistence.
|
|
145
|
+
- If no write tool is available or the write did not succeed, say that the information was not persisted. Do not imply automatic memory storage or recovery. Add ADRs to the memory bank only when explicitly requested.
|
|
143
146
|
|
|
144
147
|
### Relevance and permanent records
|
|
145
148
|
Ignore weak matches; routine summaries do not belong in durable memory.
|
|
146
149
|
|
|
150
|
+
<!-- Source: src/instructions/test-economy.instructions.md -->
|
|
151
|
+
## Test Economy
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
Write the smallest test that proves the behavior: one behavior → one focused
|
|
155
|
+
test, never the same coverage duplicated across suites or files.
|
|
156
|
+
|
|
157
|
+
- Do NOT add E2E, full-install, or network-dependent tests unless the change
|
|
158
|
+
actually alters that end-to-end path. Prefer unit or integration tests.
|
|
159
|
+
- Do not assert on copy/format strings redundantly, and do not write
|
|
160
|
+
assertions that only restate the implementation ("test the test").
|
|
161
|
+
- Heavy or slow suites (e.g. real install/E2E) MUST be opt-in via a separate
|
|
162
|
+
script/tier. Never run them per edit or per phase; run only the affected
|
|
163
|
+
subset.
|
|
164
|
+
- Respect a per-phase validation time budget: if a suite takes minutes,
|
|
165
|
+
justify running it and prefer the targeted subset. Reserve the full heavy
|
|
166
|
+
suites for release gates.
|
|
167
|
+
- Fixing a bug: add one targeted regression test, not a broad new suite.
|
|
168
|
+
- This economy rule does NOT weaken stronger gates: auth, security,
|
|
169
|
+
data-integrity, and required coverage thresholds stay mandatory.
|
|
170
|
+
|
|
147
171
|
<!-- Source: src/instructions/yagni.instructions.md -->
|
|
148
172
|
## YAGNI Anti-overengineering
|
|
149
173
|
|
package/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- pantheon:generated:begin — Pantheon-managed region; regenerated on install/upgrade, never edit inside -->
|
|
2
2
|
<!-- Generated by scripts/build-agents-md.mjs — do not edit directly. -->
|
|
3
3
|
<!-- Source of truth: the static project sections in scripts/build-agents-md.mjs. -->
|
|
4
|
-
<!-- pantheon:agents-md v2 artifact=project generated-at=2026-10-
|
|
4
|
+
<!-- pantheon:agents-md v2 artifact=project generated-at=2026-10-15T14:32:32-03:00 sha=66bf918 -->
|
|
5
5
|
|
|
6
6
|
# Pantheon — Repository Setup
|
|
7
7
|
|
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,30 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
18
18
|
|
|
19
19
|
## ✅ Closed Issues
|
|
20
20
|
|
|
21
|
+
## [v1.6.0-beta.11] - 2026-10-15
|
|
22
|
+
|
|
23
|
+
## 🆕 What's New
|
|
24
|
+
|
|
25
|
+
- **record final Beta 11 scope decisions**
|
|
26
|
+
- **record Setup delivery and final-gate lessons in roadmap**
|
|
27
|
+
- **forbid hook bypass in Iris commit contract**
|
|
28
|
+
- **add installer failure reporting and secret-safe output audit**
|
|
29
|
+
- **detect drift between installer plan and apply**
|
|
30
|
+
- **require explicit --yes authorization before installer apply**
|
|
31
|
+
- **exact installer backup set with restore**
|
|
32
|
+
- **add Beta 11 test-economy requirement to shared instructions**
|
|
33
|
+
- **preview per-file change set in installer dry-run**
|
|
34
|
+
- **reconcile Beta 11 roadmap status with completed phases**
|
|
35
|
+
- **describe pantheon_cost window and aggregation limits**
|
|
36
|
+
- **align lean-flow guidance and cost wording**
|
|
37
|
+
- **add project-scoped V2 model overrides**
|
|
38
|
+
- **align host tool and background contracts**
|
|
39
|
+
|
|
40
|
+
## 🐞 Fixed
|
|
41
|
+
|
|
42
|
+
- **restore explicit "both" in zeus memory operations instruction**
|
|
43
|
+
- **correct council protocol and persistence bounds**
|
|
44
|
+
|
|
21
45
|
## [v1.6.0-beta.10] - 2026-10-12
|
|
22
46
|
|
|
23
47
|
## 🆕 What's New
|
package/README.md
CHANGED
|
@@ -52,6 +52,23 @@ opencode
|
|
|
52
52
|
The installer guides you through the available setup. For optional MCP servers,
|
|
53
53
|
project-local installation, or non-interactive setup, see the
|
|
54
54
|
[installation guide](docs/INSTALLATION.md).
|
|
55
|
+
|
|
56
|
+
A non-interactive apply requires `--yes` (alias `-y`): without a TTY and
|
|
57
|
+
without `--yes`, `init` prints the change plan and applies nothing. Exit codes:
|
|
58
|
+
`0` success or plan/no-apply, `1` failure, `2` apply requested without
|
|
59
|
+
authorization, `3` drift (a planned target changed between plan and apply),
|
|
60
|
+
`130` canceled. Drift is checked within a single run (plan → apply); it cannot
|
|
61
|
+
be detected across two separate CLI invocations (no plan is persisted).
|
|
62
|
+
|
|
63
|
+
Preview without writing anything with `init --dry-run`. Before the first write,
|
|
64
|
+
`init` saves an exact backup set under `.pantheon/backups/<timestamp>/`
|
|
65
|
+
(directory `0700`, files `0600`, the 5 most recent kept); it is a byte-for-byte
|
|
66
|
+
copy and therefore also contains any API keys or tokens already present in your
|
|
67
|
+
files — it is never printed. Recover with
|
|
68
|
+
`pantheon-opencode restore [--project] [--yes]` (there is no automatic
|
|
69
|
+
rollback; an interrupted apply is recoverable the same way). The
|
|
70
|
+
`postinstall`/`sync-tui` step only refreshes TUI artifacts and is deliberately
|
|
71
|
+
outside this approval flow — no prompt is possible there.
|
|
55
72
|
The bundled Python MCP servers use the pinned MCP SDK 2.2.0 and standalone
|
|
56
73
|
FastMCP 4.0.10 runtime; see the [MCP guide](docs/MCP.md).
|
|
57
74
|
The installer also turns each agent's `mcp_tools` allowlist into native
|
|
@@ -182,12 +199,17 @@ session/compaction hooks, so the 1.6 line is not full V2 feature parity.
|
|
|
182
199
|
| V2 native subagent admission | OpenCode v2.0.29 | `tests/canary/run-v2-permission-proof.sh`; identity, root/child checks and permission-before-child ordering are recorded in [`bench/results/f4a-v229-admission-identity-2026-10-14.md`](bench/results/f4a-v229-admission-identity-2026-10-14.md) |
|
|
183
200
|
| Exact 1.X host version the 1.6 line is exercised against end-to-end | **Unverified.** No V1 host leg exists: the sandbox runner is V2-only and `--run v1` is rejected | — |
|
|
184
201
|
|
|
185
|
-
## Delegation (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
202
|
+
## Delegation (root `subagent`; host/API `task()`)
|
|
203
|
+
|
|
204
|
+
The host's child-session engine is referred to as native `task()` in API and
|
|
205
|
+
implementation documentation. In the user-reported Beta 10 Zeus-root runtime,
|
|
206
|
+
the callable dispatch tool was `subagent`; `task()` was not exposed as a root
|
|
207
|
+
tool. Treat the API name and examples below as host/API terminology, not a
|
|
208
|
+
guaranteed root-tool name or signature. The active runtime determines the
|
|
209
|
+
`subagent` schema, background options, and completion observability. The former
|
|
210
|
+
custom `pantheon_delegate` tool and the V1 delegation engine (`delegation.ts`,
|
|
211
|
+
`delegate-manager.ts` and supporting modules) were removed; there is no
|
|
212
|
+
Pantheon-specific delegation tool surface to configure. See
|
|
191
213
|
[ADR-0011](.pantheon/memory-bank/adr/0011-delegation-engine-contract.md) for the
|
|
192
214
|
historical engine contract.
|
|
193
215
|
|
|
@@ -210,8 +232,12 @@ global database. Both OpenCode services were running, so the 404 in the global
|
|
|
210
232
|
log may come from the other instance; this remains an end-to-end verification
|
|
211
233
|
item.
|
|
212
234
|
|
|
213
|
-
Delegated
|
|
214
|
-
|
|
235
|
+
Delegated work gets at most one retry after an initial transient failure. If no
|
|
236
|
+
completion/status tool is exposed, prefer synchronous `subagent` dispatch or
|
|
237
|
+
wait for a host-provided completion notification; do not assume polling,
|
|
238
|
+
cancellation, job tracking, or board-based recovery. If the runtime does not
|
|
239
|
+
make completion observable, report that limitation. The configured fallback or
|
|
240
|
+
escalation chain still applies.
|
|
215
241
|
|
|
216
242
|
## Cost tool backend
|
|
217
243
|
|
|
@@ -230,6 +256,8 @@ available.
|
|
|
230
256
|
|----------|---------|---------|
|
|
231
257
|
| `PANTHEON_NODE` | `node` from `PATH` | Path to a Node.js >= 22.5 binary used by the CLI fallback; an explicit path must exist and be executable, otherwise the tool fails fast instead of ignoring the override |
|
|
232
258
|
|
|
259
|
+
Tool interpretation matters: `pantheon_model status` reports configuration, not the model serving a completion. V2 manual model overrides are project-only; global override files are neither read nor applied, and global mutation is unsupported until a future surface can obtain separate explicit human authorization. V2 ignores static presets and applies only explicit per-agent project model/variant overrides, leaving the host default unchanged otherwise; V1 preset behavior remains legacy pending compatibility decisions. `pantheon_cost` is a rolling token aggregate, not a session-level or monetary cost report. See the [OpenCode plugin tool notes](docs/mcp-tools.md#opencode-plugin-tools) for details and measurement limits.
|
|
260
|
+
|
|
233
261
|
|
|
234
262
|
## Code-mode execution (explicit opt-in)
|
|
235
263
|
|
|
@@ -550,23 +578,35 @@ Two freshness guarantees back it up:
|
|
|
550
578
|
current package.
|
|
551
579
|
|
|
552
580
|
`init` also gained `--components agents,skills,...` (narrow install),
|
|
553
|
-
`--clean` (alias of `--force`), `--opencode-version auto`,
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
`
|
|
581
|
+
`--clean` (alias of `--force`), `--opencode-version auto`, preflight checks for
|
|
582
|
+
python3/npm before any file is written, and a non-fatal Python runtime: if the
|
|
583
|
+
venv fails, the install completes but MCP entries are omitted (with a warning)
|
|
584
|
+
instead of pointing at a broken interpreter. Before the first modifying write,
|
|
585
|
+
`init` preserves, byte-for-byte, every regular file it can modify or remove
|
|
586
|
+
inside the config dir (including files a `--clean` run deletes) under
|
|
587
|
+
`.pantheon/backups/<timestamp>/` (directory `0700`, files `0600`, kept 5 deep);
|
|
588
|
+
bulk directories
|
|
589
|
+
(`.venv`, the plugin's `node_modules`) and out-of-target global files
|
|
590
|
+
(`tui.json` copies elsewhere, the global `opencode-vision.json`) are listed in
|
|
591
|
+
the manifest as `notRevertible` rather than silently omitted. The exact-set
|
|
592
|
+
warning is printed once and never echoes file contents. Restore with
|
|
593
|
+
`pantheon-opencode restore [--project] [--yes]` (the old `opencode.json.bak`
|
|
594
|
+
sidecar is gone; the global vision config keeps its own `.bak`). Installer
|
|
595
|
+
messages auto-detect pt-BR via `LANG`/`LC_ALL`.
|
|
559
596
|
|
|
560
597
|
## Migrating to 1.5.x (from 1.4.x)
|
|
561
598
|
|
|
562
599
|
1.5.0 removed the custom `pantheon_delegate` tool (and the V1 delegation
|
|
563
|
-
engine) in favor of
|
|
564
|
-
[Delegation (
|
|
600
|
+
engine) in favor of the host child-session engine; see
|
|
601
|
+
[Delegation (`subagent` / host API `task()`)](#delegation-root-subagent-hostapi-task). In the
|
|
602
|
+
reported Beta 10 runtime Zeus dispatches through `subagent`; `task()` remains
|
|
603
|
+
host/API terminology, not a guaranteed root tool. Two things change on
|
|
565
604
|
an existing install:
|
|
566
605
|
|
|
567
606
|
1. **The tool disappears from the plugin surface.** `pantheon_delegate` is no
|
|
568
607
|
longer registered by `src/plugin.ts` or `src/plugin-v2.ts`. Agents now
|
|
569
|
-
delegate through
|
|
608
|
+
delegate through the dispatch tool actually exposed by the active runtime —
|
|
609
|
+
no Pantheon-specific delegation tool configuration is needed.
|
|
570
610
|
2. **A lockfile-pinned copy can keep the old tool alive.** `npm install` is
|
|
571
611
|
lockfile-authoritative: a `package-lock.json` pinned to `1.4.1` (which
|
|
572
612
|
satisfies `^1.4.1`) is never re-resolved, so a project's
|
|
@@ -839,13 +879,18 @@ with the other.
|
|
|
839
879
|
|
|
840
880
|
### Task-result guard
|
|
841
881
|
|
|
842
|
-
A `task-result-guard` intercepts
|
|
843
|
-
child session returns an empty or missing result.
|
|
882
|
+
A `task-result-guard` intercepts host/API child-session dispatch calls where the
|
|
883
|
+
child session returns an empty or missing result. In the reported Beta 10 Zeus
|
|
884
|
+
root, dispatch is exposed as `subagent`; host/API `task()` terminology does not
|
|
885
|
+
guarantee a root tool by that name. Instead of surfacing a silent
|
|
844
886
|
`completed` with no payload (which confuses the orchestrator), the guard now
|
|
845
887
|
raises an explicit error. This catches the common free-tier failure mode where a
|
|
846
888
|
child session exceeds the uncached-prefill token budget (`BackendAdmissionRejected`)
|
|
847
|
-
and returns nothing.
|
|
848
|
-
|
|
889
|
+
and returns nothing. Background dispatch and status/fan-in facilities are
|
|
890
|
+
runtime-dependent. The reported Beta 10 Zeus root did not expose `task_status`;
|
|
891
|
+
use synchronous `subagent` dispatch or wait for a host-provided completion
|
|
892
|
+
notification when no status tool is visible. Do not claim deterministic fan-in
|
|
893
|
+
or job recovery without an exposed, verified mechanism.
|
|
849
894
|
|
|
850
895
|
|
|
851
896
|
## Configuration (environment variables)
|
package/bin/pantheon-init.mjs
CHANGED
|
@@ -21,6 +21,8 @@ import os from 'node:os'
|
|
|
21
21
|
import path from 'node:path'
|
|
22
22
|
import { fileURLToPath } from 'node:url'
|
|
23
23
|
|
|
24
|
+
import { resolveInstallExitCode } from '../scripts/install/exit-codes.mjs'
|
|
25
|
+
|
|
24
26
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
25
27
|
const ROOT = path.resolve(__dirname, '..')
|
|
26
28
|
|
|
@@ -69,10 +71,24 @@ function printUsage() {
|
|
|
69
71
|
console.log(' npx pantheon-opencode prune # List legacy artifacts (dry-run)')
|
|
70
72
|
console.log(' npx pantheon-opencode prune --apply # Remove stale backups')
|
|
71
73
|
console.log(' npx pantheon-opencode doctor [--profile] # Run health check')
|
|
74
|
+
console.log(
|
|
75
|
+
' npx pantheon-opencode restore [--project] [--yes] # Restore an exact installer backup',
|
|
76
|
+
)
|
|
72
77
|
console.log(' npx pantheon-opencode uninstall --project # Remove project artifacts safely')
|
|
73
78
|
console.log(' npx pantheon-opencode uninstall --global # Remove global artifacts safely')
|
|
74
79
|
console.log(' npx pantheon-opencode --version, -v # Print version and exit')
|
|
75
80
|
console.log(' npx pantheon-opencode --help # Show this help')
|
|
81
|
+
console.log('')
|
|
82
|
+
console.log('Apply authorization:')
|
|
83
|
+
console.log(' A non-interactive run without --yes prints the plan and applies NOTHING.')
|
|
84
|
+
console.log(' Re-run with --yes to apply; an interactive TTY run prompts (default: no).')
|
|
85
|
+
console.log('')
|
|
86
|
+
console.log('Exit codes:')
|
|
87
|
+
console.log(' 0 success, or plan/no-apply (declined)')
|
|
88
|
+
console.log(' 1 failure')
|
|
89
|
+
console.log(' 2 apply was requested without authorization (non-interactive, no --yes)')
|
|
90
|
+
console.log(' 3 drift detected (a planned file changed after the plan)')
|
|
91
|
+
console.log(' 130 canceled')
|
|
76
92
|
}
|
|
77
93
|
|
|
78
94
|
async function main() {
|
|
@@ -109,6 +125,17 @@ async function main() {
|
|
|
109
125
|
process.exit(result.status ?? 1)
|
|
110
126
|
}
|
|
111
127
|
|
|
128
|
+
// restore delegates to scripts/restore.mjs (same spawnSync pattern as prune).
|
|
129
|
+
if (command === 'restore') {
|
|
130
|
+
const { spawnSync } = await import('node:child_process')
|
|
131
|
+
const restoreScript = path.join(ROOT, 'scripts', 'restore.mjs')
|
|
132
|
+
const result = spawnSync(process.execPath, [restoreScript, ...args.slice(1)], {
|
|
133
|
+
stdio: 'inherit',
|
|
134
|
+
cwd: process.cwd(),
|
|
135
|
+
})
|
|
136
|
+
process.exit(result.status ?? 1)
|
|
137
|
+
}
|
|
138
|
+
|
|
112
139
|
// doctor delegates to scripts/doctor.mjs (same spawnSync pattern as prune).
|
|
113
140
|
// Forwarding the FULL args (profile, target, --fix, ...) keeps the packaged
|
|
114
141
|
// CLI a thin wrapper; the doctor banner reports the resolved profile.
|
|
@@ -414,10 +441,11 @@ async function main() {
|
|
|
414
441
|
console.log('')
|
|
415
442
|
}
|
|
416
443
|
|
|
444
|
+
let result
|
|
417
445
|
try {
|
|
418
446
|
const { installOpenCode } = await import('../scripts/install/opencode.mjs')
|
|
419
447
|
const target = isProject ? process.cwd() : undefined
|
|
420
|
-
await installOpenCode(target, isDryRun, forceReinstall, components, {
|
|
448
|
+
result = await installOpenCode(target, isDryRun, forceReinstall, components, {
|
|
421
449
|
interactive: forceInteractive,
|
|
422
450
|
headless: forceHeadless,
|
|
423
451
|
yes: autoYes,
|
|
@@ -436,6 +464,21 @@ async function main() {
|
|
|
436
464
|
process.exit(1)
|
|
437
465
|
}
|
|
438
466
|
|
|
467
|
+
// Beta 11 Setup phases 3-4: a run that did NOT apply (declined /
|
|
468
|
+
// unauthorized / drift) must never print a success banner. Exit codes:
|
|
469
|
+
// 0 ok / no-apply · 2 apply-requested-without-authorization · 3 drift
|
|
470
|
+
// 130 canceled · 1 failure (thrown above).
|
|
471
|
+
if (result?.applied === false) {
|
|
472
|
+
if (!isDryRun) {
|
|
473
|
+
if (result.reason === 'canceled') console.error(S.canceled)
|
|
474
|
+
process.exit(resolveInstallExitCode(result, isDryRun))
|
|
475
|
+
}
|
|
476
|
+
// Dry-run preview: report honestly instead of the "installed!" banner.
|
|
477
|
+
console.log('')
|
|
478
|
+
console.log(` ${S.dryRunNothingWritten}`)
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
|
|
439
482
|
if (runDoctor && !isDryRun) {
|
|
440
483
|
console.log('')
|
|
441
484
|
console.log(` ${S.runningHealthCheck}`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-opencode",
|
|
3
|
-
"version": "1.6.0-beta.
|
|
3
|
+
"version": "1.6.0-beta.11",
|
|
4
4
|
"description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"workspaces": [
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"postinstall": "node scripts/postinstall.mjs && node scripts/sync-tui.mjs",
|
|
20
20
|
"prepare": "husky",
|
|
21
|
-
"setup": "node bin/pantheon-init.mjs init",
|
|
21
|
+
"setup": "node bin/pantheon-init.mjs init --yes",
|
|
22
22
|
"build:agents-md": "node scripts/build-agents-md.mjs",
|
|
23
|
-
"setup:lite": "node bin/pantheon-init.mjs init --clean --components agents,skills,instructions",
|
|
23
|
+
"setup:lite": "node bin/pantheon-init.mjs init --yes --clean --components agents,skills,instructions",
|
|
24
24
|
"doctor": "node scripts/doctor.mjs",
|
|
25
25
|
"prune": "node scripts/prune.mjs",
|
|
26
|
-
"init": "node bin/pantheon-init.mjs init",
|
|
26
|
+
"init": "node bin/pantheon-init.mjs init --yes",
|
|
27
27
|
"opencode": "OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true opencode",
|
|
28
28
|
"start": "OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true opencode",
|
|
29
29
|
"prepublishOnly": "node scripts/validate-routing.mjs",
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon",
|
|
3
3
|
"publisher": "ils15",
|
|
4
|
-
"version": "1.6.0-beta.
|
|
4
|
+
"version": "1.6.0-beta.11",
|
|
5
5
|
"displayName": "Pantheon",
|
|
6
6
|
"description": "Conductor-Delegate orchestration platform with 14 specialized agents, 20 skills, and OpenCode support.",
|
|
7
7
|
"agents": "./src/agents",
|
package/pyproject.toml
CHANGED
|
@@ -36,6 +36,8 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSy
|
|
|
36
36
|
import { dirname, join, resolve } from 'node:path'
|
|
37
37
|
import { fileURLToPath } from 'node:url'
|
|
38
38
|
|
|
39
|
+
import { ACTIONS, isRecording, recordChange } from './install/plan.mjs'
|
|
40
|
+
|
|
39
41
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
40
42
|
export const ROOT = join(__dirname, '..')
|
|
41
43
|
const INSTRUCTIONS_DIR = join(ROOT, 'src', 'instructions')
|
|
@@ -323,16 +325,26 @@ export function generateProjectAgentsMd(git = readGitInfo()) {
|
|
|
323
325
|
* @param {boolean} [dryRun=false] - Do not write when true
|
|
324
326
|
* @returns {'created' | 'skipped' | 'updated' | 'upgraded' | 'merged'}
|
|
325
327
|
*/
|
|
326
|
-
export function writeAgentsMdManaged(filePath, generated, dryRun = false) {
|
|
328
|
+
export function writeAgentsMdManaged(filePath, generated, dryRun = false, recorder = null) {
|
|
327
329
|
const existing = existsSync(filePath) ? readFileSync(filePath, 'utf8') : null
|
|
328
330
|
if (existing === null) {
|
|
329
331
|
if (!dryRun) {
|
|
330
332
|
mkdirSync(dirname(filePath), { recursive: true })
|
|
331
333
|
writeFileSync(filePath, generated, 'utf8')
|
|
332
334
|
}
|
|
335
|
+
recordChange(
|
|
336
|
+
{ path: filePath, action: ACTIONS.CREATE, bytes: Buffer.byteLength(generated, 'utf8') },
|
|
337
|
+
recorder,
|
|
338
|
+
)
|
|
333
339
|
return 'created'
|
|
334
340
|
}
|
|
335
|
-
if (existing === generated)
|
|
341
|
+
if (existing === generated) {
|
|
342
|
+
recordChange(
|
|
343
|
+
{ path: filePath, action: ACTIONS.UNCHANGED, bytes: Buffer.byteLength(existing, 'utf8') },
|
|
344
|
+
recorder,
|
|
345
|
+
)
|
|
346
|
+
return 'skipped'
|
|
347
|
+
}
|
|
336
348
|
|
|
337
349
|
const begin = existing.indexOf(MANAGED_BEGIN)
|
|
338
350
|
const end = existing.indexOf(MANAGED_END)
|
|
@@ -340,22 +352,41 @@ export function writeAgentsMdManaged(filePath, generated, dryRun = false) {
|
|
|
340
352
|
const before = existing.slice(0, begin)
|
|
341
353
|
const after = existing.slice(end + MANAGED_END.length)
|
|
342
354
|
const next = `${before}${generated}${after}`
|
|
343
|
-
if (next === existing)
|
|
355
|
+
if (next === existing) {
|
|
356
|
+
recordChange(
|
|
357
|
+
{ path: filePath, action: ACTIONS.UNCHANGED, bytes: Buffer.byteLength(existing, 'utf8') },
|
|
358
|
+
recorder,
|
|
359
|
+
)
|
|
360
|
+
return 'skipped'
|
|
361
|
+
}
|
|
344
362
|
if (!dryRun) writeFileSync(filePath, next, 'utf8')
|
|
363
|
+
recordChange(
|
|
364
|
+
{ path: filePath, action: ACTIONS.UPDATE, bytes: Buffer.byteLength(next, 'utf8') },
|
|
365
|
+
recorder,
|
|
366
|
+
)
|
|
345
367
|
return before.trim() === '' && after.trim() === '' ? 'updated' : 'merged'
|
|
346
368
|
}
|
|
347
369
|
|
|
348
370
|
if (existing.startsWith(GENERATED_BY)) {
|
|
349
371
|
// Legacy format: the header declares the whole file machine-generated.
|
|
350
372
|
if (!dryRun) writeFileSync(filePath, generated, 'utf8')
|
|
373
|
+
recordChange(
|
|
374
|
+
{ path: filePath, action: ACTIONS.UPDATE, bytes: Buffer.byteLength(generated, 'utf8') },
|
|
375
|
+
recorder,
|
|
376
|
+
)
|
|
351
377
|
return 'upgraded'
|
|
352
378
|
}
|
|
353
379
|
|
|
354
380
|
// Foreign content: preserve it verbatim and append the managed region.
|
|
381
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n'
|
|
382
|
+
const payload = `${existing}${separator}${generated}`
|
|
355
383
|
if (!dryRun) {
|
|
356
|
-
|
|
357
|
-
writeFileSync(filePath, `${existing}${separator}${generated}`, 'utf8')
|
|
384
|
+
writeFileSync(filePath, payload, 'utf8')
|
|
358
385
|
}
|
|
386
|
+
recordChange(
|
|
387
|
+
{ path: filePath, action: ACTIONS.UPDATE, bytes: Buffer.byteLength(payload, 'utf8') },
|
|
388
|
+
recorder,
|
|
389
|
+
)
|
|
359
390
|
return 'merged'
|
|
360
391
|
}
|
|
361
392
|
|
|
@@ -423,9 +454,16 @@ export function generateAgentPrompt(agentName, prompt, instructions = readInstru
|
|
|
423
454
|
* @param {string} targetDir - OpenCode agents directory
|
|
424
455
|
* @param {boolean} dryRun - Do not write when true
|
|
425
456
|
* @param {boolean} existingOnly - Refresh installed prompts without adding missing agents
|
|
457
|
+
* @param {(change: object) => void} [recorder] - optional change recorder for --dry-run preview
|
|
426
458
|
* @returns {{ created: number, skipped: number }}
|
|
427
459
|
*/
|
|
428
|
-
export function copyAgentPrompts(
|
|
460
|
+
export function copyAgentPrompts(
|
|
461
|
+
sourceDir,
|
|
462
|
+
targetDir,
|
|
463
|
+
dryRun = false,
|
|
464
|
+
existingOnly = false,
|
|
465
|
+
recorder = null,
|
|
466
|
+
) {
|
|
429
467
|
const instructions = readInstructions()
|
|
430
468
|
if (!dryRun && !existingOnly) mkdirSync(targetDir, { recursive: true })
|
|
431
469
|
let created = 0
|
|
@@ -443,9 +481,25 @@ export function copyAgentPrompts(sourceDir, targetDir, dryRun = false, existingO
|
|
|
443
481
|
const existing = existsSync(targetPath) ? readFileSync(targetPath, 'utf8') : null
|
|
444
482
|
if (existing === output) {
|
|
445
483
|
skipped++
|
|
484
|
+
if (isRecording(recorder)) {
|
|
485
|
+
recordChange(
|
|
486
|
+
{ path: targetPath, action: ACTIONS.UNCHANGED, bytes: Buffer.byteLength(output, 'utf8') },
|
|
487
|
+
recorder,
|
|
488
|
+
)
|
|
489
|
+
}
|
|
446
490
|
} else {
|
|
447
491
|
if (!dryRun) writeFileSync(targetPath, output, 'utf8')
|
|
448
492
|
created++
|
|
493
|
+
if (isRecording(recorder)) {
|
|
494
|
+
recordChange(
|
|
495
|
+
{
|
|
496
|
+
path: targetPath,
|
|
497
|
+
action: existing === null ? ACTIONS.CREATE : ACTIONS.UPDATE,
|
|
498
|
+
bytes: Buffer.byteLength(output, 'utf8'),
|
|
499
|
+
},
|
|
500
|
+
recorder,
|
|
501
|
+
)
|
|
502
|
+
}
|
|
449
503
|
}
|
|
450
504
|
}
|
|
451
505
|
return { created, skipped }
|