@prevalentware/opencode-goal-plugin 0.1.55 → 0.1.56
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/README.md +2 -0
- package/dist/server.js +9 -1
- package/package.json +1 -1
- package/src/tui.ts +3 -1
package/README.md
CHANGED
|
@@ -259,6 +259,8 @@ Ordinary fsync improves crash consistency but is not `F_FULLFSYNC`, so sudden po
|
|
|
259
259
|
|
|
260
260
|
The plugin migrates version 1 state files to version 2 on the next write. Version 2 adds stable goal identities, the terminal `cancelled` status, and compact archives. Older plugin versions intentionally reject version 2 instead of silently dropping archived history on their next write; back up or isolate `OPENCODE_GOAL_STATE_PATH` before downgrading.
|
|
261
261
|
|
|
262
|
+
Planless version 3 files from the planning development build are also compatible: empty `plan: null` and `planRevision: 0` metadata survives reads, updates, and archival, and writes retain version 3. This prevents an otherwise valid shared state file from breaking ordinary OpenCode tool calls in sessions without a goal. Populated plans, nonzero planning revisions, and unknown future versions remain rejected without rewriting the file; use the corresponding planning build or an isolated `OPENCODE_GOAL_STATE_PATH` for those files.
|
|
263
|
+
|
|
262
264
|
If the rename succeeds but syncing the parent directory reports a genuine I/O error, the mutation reports a write failure even though the new valid state may already be present. This avoids claiming durability that the filesystem did not confirm.
|
|
263
265
|
|
|
264
266
|
If a non-empty state file contains only whitespace, a UTF-8 BOM, or NUL bytes after an interrupted write, the next mutation preserves its exact contents beside the state file as `goals.json.corrupt-<timestamp>-<uuid>` before writing recovered state. If another process replaces the state during recovery, the mutation refuses to overwrite that newer content. If the quarantine copy itself cannot be created, the plugin reports the failure and continues recovery rather than making every prompt fail indefinitely. OpenCode 1 also records the quarantine outcome and path through its application log so the data-loss event remains discoverable.
|
package/dist/server.js
CHANGED
|
@@ -179,6 +179,8 @@ var GoalSchema = Schema.Struct({
|
|
|
179
179
|
id: Schema.optionalWith(Schema.String, { default: () => "" }),
|
|
180
180
|
sessionID: Schema.String,
|
|
181
181
|
objective: Schema.String,
|
|
182
|
+
plan: Schema.optional(Schema.Null),
|
|
183
|
+
planRevision: Schema.optional(Schema.Literal(0)),
|
|
182
184
|
status: Schema.Literal("active", "paused", "budgetLimited", "usageLimited", "complete", "unmet", "cancelled"),
|
|
183
185
|
tokenBudget: NullableNumber,
|
|
184
186
|
tokensUsed: Schema.Number,
|
|
@@ -216,6 +218,8 @@ var ArchivedGoalSchema = Schema.Struct({
|
|
|
216
218
|
id: Schema.String,
|
|
217
219
|
sessionID: Schema.String,
|
|
218
220
|
objective: Schema.String,
|
|
221
|
+
plan: Schema.optional(Schema.Null),
|
|
222
|
+
planRevision: Schema.optional(Schema.Literal(0)),
|
|
219
223
|
status: Schema.Literal("active", "paused", "budgetLimited", "usageLimited", "complete", "unmet", "cancelled"),
|
|
220
224
|
tokenBudget: NullableNumber,
|
|
221
225
|
tokensUsed: Schema.Number,
|
|
@@ -234,7 +238,7 @@ var LegacyStateSchema = Schema.Struct({
|
|
|
234
238
|
goals: Schema.Record({ key: Schema.String, value: GoalSchema })
|
|
235
239
|
});
|
|
236
240
|
var StateSchema = Schema.Struct({
|
|
237
|
-
version: Schema.Literal(2),
|
|
241
|
+
version: Schema.Literal(2, 3),
|
|
238
242
|
goals: Schema.Record({ key: Schema.String, value: GoalSchema }),
|
|
239
243
|
archives: Schema.optionalWith(Schema.Record({ key: Schema.String, value: Schema.Array(ArchivedGoalSchema) }), {
|
|
240
244
|
default: () => ({})
|
|
@@ -551,6 +555,8 @@ function snapshot(goal) {
|
|
|
551
555
|
id: goal.id,
|
|
552
556
|
sessionID: goal.sessionID,
|
|
553
557
|
objective: goal.objective,
|
|
558
|
+
...goal.plan === null ? { plan: null } : {},
|
|
559
|
+
...goal.planRevision === 0 ? { planRevision: 0 } : {},
|
|
554
560
|
status: goal.status,
|
|
555
561
|
tokenBudget: goal.tokenBudget,
|
|
556
562
|
tokensUsed: goal.tokensUsed,
|
|
@@ -678,6 +684,8 @@ function archivedGoal(goal) {
|
|
|
678
684
|
id: goal.id,
|
|
679
685
|
sessionID: goal.sessionID,
|
|
680
686
|
objective: summarizeText(goal.objective, MAX_ARCHIVED_OBJECTIVE_CHARS),
|
|
687
|
+
...goal.plan === null ? { plan: null } : {},
|
|
688
|
+
...goal.planRevision === 0 ? { planRevision: 0 } : {},
|
|
681
689
|
status: goal.status,
|
|
682
690
|
tokenBudget: goal.tokenBudget,
|
|
683
691
|
tokensUsed: goal.tokensUsed,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prevalentware/opencode-goal-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.56",
|
|
4
4
|
"description": "OpenCode goal plugin that adds Codex-style long-running goal mode, /goal commands, persistence, and TUI status for AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opencode",
|
package/src/tui.ts
CHANGED
|
@@ -419,10 +419,12 @@ function isGoalSnapshot(value: unknown): value is GoalSnapshot {
|
|
|
419
419
|
export async function readPersistedGoal(sessionID: string): Promise<GoalSnapshot | null | undefined> {
|
|
420
420
|
try {
|
|
421
421
|
const state: unknown = JSON.parse(await readFile(statePath(), "utf8"))
|
|
422
|
-
if (!isRecord(state) || (state.version !== 1 && state.version !== 2) || !isRecord(state.goals)) return undefined
|
|
422
|
+
if (!isRecord(state) || (state.version !== 1 && state.version !== 2 && state.version !== 3) || !isRecord(state.goals)) return undefined
|
|
423
423
|
const stored = state.goals[sessionID]
|
|
424
424
|
if (stored === undefined) return null
|
|
425
425
|
if (!isRecord(stored) || stored.sessionID !== sessionID) return undefined
|
|
426
|
+
if (stored.plan !== undefined && stored.plan !== null) return undefined
|
|
427
|
+
if (stored.planRevision !== undefined && stored.planRevision !== 0) return undefined
|
|
426
428
|
const sampledAt = currentEpochSeconds()
|
|
427
429
|
const timeUsedSeconds = typeof stored.timeUsedSeconds === "number" ? stored.timeUsedSeconds : 0
|
|
428
430
|
const activeSeconds = stored.status === "active" && typeof stored.lastAccountedAt === "number"
|