opencode-goal-mode 0.3.10 → 0.3.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.3.11
|
|
4
|
+
|
|
5
|
+
- Fixed Goal sidebar/status isolation so an explicit Build or other non-Goal
|
|
6
|
+
session never falls back to another active Goal session in the same worktree.
|
|
7
|
+
- Blocked mutating `goal_*` tools from activating Goal Guard state in non-Goal
|
|
8
|
+
sessions; read-only tools remain strictly scoped to the current session.
|
|
9
|
+
- Added regression coverage for mixed Goal/Build persisted snapshots, session-scoped
|
|
10
|
+
status/evidence/memory reads, and Build-mode tool calls.
|
|
11
|
+
|
|
3
12
|
## v0.3.10
|
|
4
13
|
|
|
5
14
|
- Clarified the recommended install command to use a persistent global npm install
|
package/package.json
CHANGED
|
@@ -30,8 +30,10 @@ function normalize(record) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Choose which session's goal to show
|
|
34
|
-
*
|
|
33
|
+
* Choose which session's goal to show. When OpenCode gives us a concrete session
|
|
34
|
+
* id, never fall back to another session: Build/non-Goal sessions must not show a
|
|
35
|
+
* Goal from the same worktree. The most-recent active fallback is only for
|
|
36
|
+
* no-session contexts such as initial sidebar registration polling.
|
|
35
37
|
*/
|
|
36
38
|
export function pickSession(snapshot, sessionId) {
|
|
37
39
|
if (!snapshot || !Array.isArray(snapshot.sessions)) return null;
|
|
@@ -41,6 +43,7 @@ export function pickSession(snapshot, sessionId) {
|
|
|
41
43
|
if (sessionId) {
|
|
42
44
|
const direct = records.find(([key, st]) => key === sessionId && st.active);
|
|
43
45
|
if (direct) return direct[1];
|
|
46
|
+
return null;
|
|
44
47
|
}
|
|
45
48
|
const active = records.filter(([, st]) => st.active);
|
|
46
49
|
if (active.length === 0) return null;
|
|
@@ -16,6 +16,7 @@ import { evidenceMapReport, reviewerMemoryReport, statusReport } from "./summary
|
|
|
16
16
|
import { recordEvidence } from "./events.js";
|
|
17
17
|
import { refreshStickyGates } from "./gates.js";
|
|
18
18
|
import { createState } from "./state.js";
|
|
19
|
+
import { isPrimaryAgent } from "./agents.js";
|
|
19
20
|
|
|
20
21
|
const s = tool.schema;
|
|
21
22
|
|
|
@@ -28,6 +29,18 @@ const s = tool.schema;
|
|
|
28
29
|
export function createGoalTools({ store, config, persist }) {
|
|
29
30
|
const save = typeof persist === "function" ? persist : () => {};
|
|
30
31
|
|
|
32
|
+
function requireGoalMode(state) {
|
|
33
|
+
return Boolean(state?.active || isPrimaryAgent(state?.currentAgent));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function goalModeOnlyResult() {
|
|
37
|
+
return {
|
|
38
|
+
title: "Goal Mode required",
|
|
39
|
+
output: "This goal_* tool can only mutate Goal Guard state from an active Goal session. Switch to the `goal` agent or start with /goal.",
|
|
40
|
+
metadata: { blocked: true, reason: "not_goal_mode" },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
31
44
|
return {
|
|
32
45
|
goal_status: tool({
|
|
33
46
|
description:
|
|
@@ -109,6 +122,7 @@ export function createGoalTools({ store, config, persist }) {
|
|
|
109
122
|
},
|
|
110
123
|
async execute(args, ctx) {
|
|
111
124
|
const state = store.stateFor(ctx.sessionID);
|
|
125
|
+
if (!requireGoalMode(state)) return goalModeOnlyResult();
|
|
112
126
|
state.active = true;
|
|
113
127
|
state.contract = {
|
|
114
128
|
title: String(args.title || "").replace(/\s+/g, " ").trim(),
|
|
@@ -145,6 +159,7 @@ export function createGoalTools({ store, config, persist }) {
|
|
|
145
159
|
},
|
|
146
160
|
async execute(args, ctx) {
|
|
147
161
|
const state = store.stateFor(ctx.sessionID);
|
|
162
|
+
if (!requireGoalMode(state)) return goalModeOnlyResult();
|
|
148
163
|
state.active = true;
|
|
149
164
|
recordEvidence(store, state, args.command, args.result, args.criteria);
|
|
150
165
|
save();
|
|
@@ -164,6 +179,8 @@ export function createGoalTools({ store, config, persist }) {
|
|
|
164
179
|
confirm: s.boolean().describe("Must be true to actually reset."),
|
|
165
180
|
},
|
|
166
181
|
async execute(args, ctx) {
|
|
182
|
+
const state = store.stateFor(ctx.sessionID);
|
|
183
|
+
if (!requireGoalMode(state)) return goalModeOnlyResult();
|
|
167
184
|
if (!args.confirm) {
|
|
168
185
|
return { title: "Reset not confirmed", output: "Pass confirm=true to reset Goal Guard state." };
|
|
169
186
|
}
|