opencode-goal-plugin 0.6.4 → 0.6.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.
- package/CHANGELOG.md +8 -0
- package/README.md +17 -16
- package/docs/compatibility.md +2 -0
- package/index.d.ts +9 -7
- package/package.json +1 -1
- package/src/goal-plugin.js +460 -253
- package/src/persistence-lease.js +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.6 — 2026-07-29
|
|
4
|
+
|
|
5
|
+
- Shard persisted goal state and lifecycle ledgers by hashed OpenCode session ID so independent sessions can run concurrently in one project. Keep same-session single-writer leases, lazy session loading, crash recovery, and safe migration of aggregate, legacy, and XDG state.
|
|
6
|
+
|
|
7
|
+
## 0.6.5 — 2026-07-12
|
|
8
|
+
|
|
9
|
+
- Make `/goal sequence` the canonical ordered multi-goal command, retain the previous command and mode spelling as input-only compatibility aliases, correct the public auditor snapshot mode type to `"normal" | "ordered"`, and align README archive and compatibility claims with verified behavior.
|
|
10
|
+
|
|
3
11
|
## 0.6.4 — 2026-07-12
|
|
4
12
|
|
|
5
13
|
- Re-check session status and recent messages after an auto-continue cooldown, pause immediately for human intervention, Plan-agent switches, permission rejection, aborts, and provider errors, and abort an accepted continuation when the user takes control.
|
package/README.md
CHANGED
|
@@ -36,15 +36,16 @@ surface and versioning expectations.
|
|
|
36
36
|
|
|
37
37
|
### OpenCode version compatibility
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
Tested against real OpenCode 1.17.15 processes with live provider credentials and no mocked plugin hooks. State, ledger entries, and workspace files were checked independently of terminal or model prose:
|
|
40
40
|
|
|
41
41
|
| OpenCode Version | Provider Tested | `/goal status` | Auto-continue | Evidence-gated completion | Hook Output Display |
|
|
42
42
|
|---|---|---|---|---|---|
|
|
43
|
+
| 1.17.15 | opencode (`deepseek-v4-flash-free`) | ✅ Canonical tool | ✅ Checkpoint + idle continuation | ✅ Structured `goal_complete` claim | ⚠️ Command text routed to model; mutation guard verified |
|
|
43
44
|
| 1.17.15 | opencode-go (`qwen3.7-plus`) | ✅ | ✅ | ✅ Self-corrected after one rejection (bare `[goal:complete]` with no evidence), then completed cleanly | ⚠️ Not displayed |
|
|
44
45
|
| 1.17.15 | opencode-go (`glm-5.2`) | ✅ | ✅ | ✅ Clean `[goal:evidence]` + `[goal:complete]` on the first attempt | ⚠️ Not displayed |
|
|
45
46
|
| 1.17.15 | deepseek (`deepseek-chat`) | ✅ | ✅ | ✅ Clean `[goal:evidence]` + `[goal:complete]` on the first attempt; also verified end-to-end via the [demo](demo/) — autonomously fixed a real bug and reported evidence-backed completion | ⚠️ Not displayed |
|
|
46
47
|
|
|
47
|
-
`/goal status` and auto-continue are graded on **state correctness** (verified directly against
|
|
48
|
+
`/goal status` and auto-continue are graded on **state correctness** (verified directly against persisted state: correct limits, turn/stop accounting, completion state, and file effects), not on terminal rendering. The `deepseek-v4-flash-free` canary suite additionally covers pause/resume across processes, blocker/restart, hard-process recovery, real host compaction, and stale-history clear enforcement. See [`docs/providers.md`](docs/providers.md) for the complete lifecycle matrix and session evidence.
|
|
48
49
|
|
|
49
50
|
**Note:** Hook output display depends on OpenCode version — on 1.17.15, `command.execute.before`'s `output.parts` text is not rendered in the TUI for any provider tested; the raw command argument is instead routed to the model as a normal chat turn (see [Limitations](#limitations)). State mutations always work regardless of display: goal creation, flag parsing, auto-continue, limit enforcement, and evidence-gated completion detection were all verified correct via the persisted state file in every combination above. Re-test against your own OpenCode build before relying on unattended runs, and see [`docs/providers.md`](docs/providers.md) for the full per-model marker-compliance notes.
|
|
50
51
|
|
|
@@ -89,7 +90,7 @@ Add success criteria, constraints / non-goals, and a mode:
|
|
|
89
90
|
/goal ship the release --success "tests pass and changelog updated" --constraints "do not touch the public API" --mode ordered
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
`--success` (alias `--success-criteria`) and `--constraints` (alias `--non-goals`) take quoted text and are injected alongside the objective so the assistant keeps them in view. `--mode` is `normal` (default) or `ordered
|
|
93
|
+
`--success` (alias `--success-criteria`) and `--constraints` (alias `--non-goals`) take quoted text and are injected alongside the objective so the assistant keeps them in view. `--mode` is `normal` (default) or `ordered`; `ordered` tells the assistant to preserve step order inside one objective. To queue distinct objectives that auto-promote one at a time, use `/goal sequence`. Multi-word values must be quoted.
|
|
93
94
|
|
|
94
95
|
Flags accept either `--flag value` or `--flag=value`. If a flag is unknown, missing a value, given a non-positive integer, or (for `--mode`) an unrecognized mode, the plugin rejects the command with a helpful error instead of silently folding the bad flag into the goal text.
|
|
95
96
|
|
|
@@ -125,7 +126,7 @@ Pause without clearing the active goal:
|
|
|
125
126
|
/goal pause
|
|
126
127
|
```
|
|
127
128
|
|
|
128
|
-
Clear the
|
|
129
|
+
Clear all live goals in the current session and discard their saved status:
|
|
129
130
|
|
|
130
131
|
```
|
|
131
132
|
/goal clear
|
|
@@ -155,14 +156,14 @@ A session can hold more than one goal. `/goal <condition>` replaces the focused
|
|
|
155
156
|
/goal focus 1
|
|
156
157
|
```
|
|
157
158
|
|
|
158
|
-
`/goal list` shows
|
|
159
|
+
`/goal list` shows numbered live goals (focused and backgrounded) plus achieved goals retained in the per-session archive. `/goal clear` intentionally removes live goals and saved status from these views; its terminal ledger entries remain available for crash-safe recovery decisions. `/goal focus <number>` switches the active goal, backgrounding the previous one. Focus is tracked per session and survives a restart.
|
|
159
160
|
|
|
160
|
-
#### Ordered
|
|
161
|
+
#### Ordered sequences
|
|
161
162
|
|
|
162
|
-
`/goal
|
|
163
|
+
`/goal sequence` sets up a strict execution queue: separate objectives with `;` or newlines, and the plugin runs them one at a time, focusing the next as soon as the current one completes.
|
|
163
164
|
|
|
164
165
|
```
|
|
165
|
-
/goal
|
|
166
|
+
/goal sequence build the parser; write the tests; ship the release
|
|
166
167
|
```
|
|
167
168
|
|
|
168
169
|
The first goal is focused and the rest are queued. `/goal list` marks the session as ordered. Auto-promotion stops when the sequence is exhausted; `/goal clear` ends the sequence.
|
|
@@ -187,7 +188,7 @@ With success criteria, constraints, and a token budget shorthand:
|
|
|
187
188
|
An ordered sequence, run as a strict pipeline:
|
|
188
189
|
|
|
189
190
|
```
|
|
190
|
-
/goal
|
|
191
|
+
/goal sequence build the parser; write the tests; ship the release
|
|
191
192
|
```
|
|
192
193
|
|
|
193
194
|
## How it works
|
|
@@ -238,7 +239,7 @@ Markers must appear on their own final line. The bracketed form is canonical, bu
|
|
|
238
239
|
|
|
239
240
|
**Wrap-up vs. hard stop.** When a limit is reached, the plugin sends one final prompt asking the assistant to summarize what is done, what remains, and the next concrete step — rather than stopping silently. Use `/goal resume` to continue after any stop, including limit stops and no-progress pauses.
|
|
240
241
|
|
|
241
|
-
Goal state is persisted by default to a **project-local**
|
|
242
|
+
Goal state is persisted by default to a **project-local** namespace rooted at `.opencode/goals/state.json` relative to the working directory, so goals follow the project rather than your home directory. Each OpenCode session gets a separate hashed shard at `<stateFilePath>.sessions/<sha256(sessionID)>/state.json`, allowing unrelated sessions in the same project to run concurrently. The state is local and is not synchronized across machines. You may want to add `.opencode/goals/` to your `.gitignore`.
|
|
242
243
|
|
|
243
244
|
The state-file location is resolved with this precedence:
|
|
244
245
|
|
|
@@ -246,11 +247,11 @@ The state-file location is resolved with this precedence:
|
|
|
246
247
|
2. the `OPENCODE_GOAL_STATE_PATH` environment variable, if set;
|
|
247
248
|
3. the project-local default `<cwd>/.opencode/goals/state.json`.
|
|
248
249
|
|
|
249
|
-
When
|
|
250
|
+
When a project has no shard namespace yet, the plugin migrates all sessions from older locations on first session access: the legacy `~/.opencode-goal-plugin/state.json` and the XDG path `${XDG_STATE_HOME:-~/.local/state}/opencode-goal-plugin/state.json`. Migration is exclusively claimed; after every session shard is written, the source files are retired to timestamped `.migrated…` backups so another project cannot import the same private goal state. An explicit `stateFilePath` or `OPENCODE_GOAL_STATE_PATH` is used as the shard namespace root and has no migration fallback.
|
|
250
251
|
|
|
251
252
|
The state directory is created with owner-only permissions, and the JSON state file is written as `0600` because it may contain goal text, assistant checkpoints, and workflow history.
|
|
252
253
|
|
|
253
|
-
Alongside
|
|
254
|
+
Alongside each session shard the plugin keeps an **append-only lifecycle ledger** (`<shard>/state.json.ledger.jsonl`, also `0600`). Every lifecycle event — set, edit, auto-continue, pause, resume, blocked, completed, limit — is appended as one JSON line. Because the in-memory history is capped, the ledger is the durable record: if a session state file is missing or corrupted, the plugin reconstructs still-active (non-completed) goals from that session's ledger on startup and reloads them in the paused recovery state. Terminal events (complete/blocked) are written to the ledger *before* the state write, so a goal's terminal outcome survives even if that write fails (**fail-closed**); such a failure is logged at error level.
|
|
254
255
|
|
|
255
256
|
Recovered active goals are loaded in a **paused** state with a recovery note, so unattended auto-continue does not resume blindly after a restart. Set `"persistState": false` to keep purely in-memory behavior (this also disables the ledger).
|
|
256
257
|
|
|
@@ -272,7 +273,7 @@ Override any limit for a single goal:
|
|
|
272
273
|
| `--no-progress-turns <n>` | Consecutive stalled low-output turns before pausing |
|
|
273
274
|
| `--success <text>` | Success criteria that define when the goal is satisfied (quote multi-word text) |
|
|
274
275
|
| `--constraints <text>` | Constraints / non-goals to respect (alias `--non-goals`) |
|
|
275
|
-
| `--mode <normal\|ordered>` |
|
|
276
|
+
| `--mode <normal\|ordered>` | Prompt mode for one goal; `ordered` preserves step order inside its objective |
|
|
276
277
|
| `--no-tool-turns <n>` | Consecutive tool-free continuation turns before pausing |
|
|
277
278
|
|
|
278
279
|
Examples:
|
|
@@ -327,7 +328,7 @@ Additional plugin-level options:
|
|
|
327
328
|
- `goalAgentName` / `verifierAgentName` — customize the registered native agent names (defaults `goal` and `goal-verify`). The verifier is a hidden subagent with a default-deny tool policy; only `read`, `glob`, and `grep` are allowed.
|
|
328
329
|
- `sdkShape` — OpenCode session-client argument shape: `legacy` (the default generated `PluginInput` client using `{ path, body, query }`) or `flat` (clients using `{ sessionID, ... }`). Read-only `messages`/`get` calls may probe the alternate shape after an argument/schema `TypeError`; mutating calls are never replayed, so set this option correctly for embedded clients.
|
|
329
330
|
- `persistState` — whether to persist active goals and recent goal results to disk.
|
|
330
|
-
- `stateFilePath` —
|
|
331
|
+
- `stateFilePath` — root path for the persisted session-shard namespace. Overrides the default project-local path and the `OPENCODE_GOAL_STATE_PATH` env var. Useful if you want a fixed or ephemeral location. When unset, the default root is `<cwd>/.opencode/goals/state.json`; shards are written below `<stateFilePath>.sessions/` (see the persistence section above).
|
|
331
332
|
- `ledgerMaxBytes` / `ledgerRetentionFiles` — bound the lifecycle ledger to 2 MiB per generation and three rotated generations by default. Set retention to `0` to discard the active ledger when it reaches the size ceiling.
|
|
332
333
|
- `resultRetentionMs` — how long a completed goal summary remains available through `/goal status` after the goal leaves active memory.
|
|
333
334
|
- `maxStoredResults` — maximum number of completed-goal summaries retained in process memory before the oldest ones are evicted.
|
|
@@ -343,7 +344,7 @@ Registered tools:
|
|
|
343
344
|
|
|
344
345
|
`goal_set` and `set_goal` are explicitly constrained to user-requested goals. `goal_complete` accepts a structured claim: a required non-empty `summary`, plus optional criterion/evidence pairs, checks (`passed`, `failed`, or `not-run`), changed files, and known limitations. Failed checks and empty criterion evidence are rejected before archival; accepted claims are serialized deterministically for the configured completion auditor. The legacy `update_goal` tool retains its string `evidence` field for compatibility.
|
|
345
346
|
|
|
346
|
-
These operate on the same per-session multi-goal state as the command path: a tool-set goal persists, shows up in `/goal list`, and is driven by the idle auto-continue; completing a goal in an ordered
|
|
347
|
+
These operate on the same per-session multi-goal state as the command path: a tool-set goal persists, shows up in `/goal list`, and is driven by the idle auto-continue; completing a goal in an ordered sequence auto-promotes the next.
|
|
347
348
|
|
|
348
349
|
> Integration note: the tool execute-context shape (`ctx.sessionID`) and the `tool.schema` surface follow the OpenCode plugin docs. The tool **logic** is unit-tested independently, but the live registration should be confirmed against a real OpenCode run (see the smoke-test checklist).
|
|
349
350
|
|
|
@@ -388,7 +389,7 @@ OpenCode's current `command.execute.before` hook does not fully intercept comman
|
|
|
388
389
|
|
|
389
390
|
The plugin depends on `experimental.chat.system.transform` and other OpenCode plugin hooks that may change between OpenCode versions.
|
|
390
391
|
|
|
391
|
-
|
|
392
|
+
Distinct OpenCode sessions may own shards under the same `stateFilePath` concurrently. A second process using the same session shard is still rejected with the owning PID/host instead of risking last-writer-wins state loss; use the original session or wait for its owner to dispose.
|
|
392
393
|
|
|
393
394
|
## Diagnostics and recovery
|
|
394
395
|
|
package/docs/compatibility.md
CHANGED
|
@@ -10,6 +10,8 @@ The latest published release is the supported line. Public compatibility covers:
|
|
|
10
10
|
- the documented OpenCode hook names
|
|
11
11
|
- the six canonical goal tools and five legacy tool aliases
|
|
12
12
|
- persisted-state recovery from versions documented in the changelog
|
|
13
|
+
- concurrent persistence for distinct OpenCode sessions in one project, with
|
|
14
|
+
single-writer protection retained per session
|
|
13
15
|
|
|
14
16
|
The package requires Node.js 18 or newer and OpenCode 1.17.15 through the latest
|
|
15
17
|
compatible 1.x release. CI runs the complete unit suite on Node 18, 20, 22, and
|
package/index.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export interface GoalAuditSnapshot {
|
|
|
48
48
|
condition: string
|
|
49
49
|
successCriteria: string
|
|
50
50
|
constraints: string
|
|
51
|
-
mode: "normal" | "
|
|
51
|
+
mode: "normal" | "ordered"
|
|
52
52
|
sessionID: string
|
|
53
53
|
turnCount: number
|
|
54
54
|
startedAt: number
|
|
@@ -222,17 +222,19 @@ export interface GoalPluginOptions {
|
|
|
222
222
|
persistState?: boolean
|
|
223
223
|
|
|
224
224
|
/**
|
|
225
|
-
*
|
|
226
|
-
* `persistState` is enabled.
|
|
227
|
-
*
|
|
225
|
+
* Root filesystem path for persisted session-shard state when
|
|
226
|
+
* `persistState` is enabled. Each session is written below
|
|
227
|
+
* `<stateFilePath>.sessions/<sha256(sessionID)>/state.json`. Overrides both
|
|
228
|
+
* the project-local default and the `OPENCODE_GOAL_STATE_PATH` environment
|
|
229
|
+
* variable.
|
|
228
230
|
* @default "<cwd>/.opencode/goals/state.json"
|
|
229
231
|
*/
|
|
230
232
|
stateFilePath?: string
|
|
231
233
|
|
|
232
234
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
235
|
+
* Legacy aggregate filesystem path for the append-only lifecycle ledger.
|
|
236
|
+
* During migration, events are partitioned into per-session shard ledgers;
|
|
237
|
+
* new writes use `<shard>/state.json.ledger.jsonl`.
|
|
236
238
|
* @default "<stateFilePath>.ledger.jsonl"
|
|
237
239
|
*/
|
|
238
240
|
ledgerFilePath?: string
|