open-plan-annotator 0.2.16 → 0.2.17
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.
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"name": "open-plan-annotator",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"description": "Interactive plan annotation UI: review, strikethrough, and comment on Claude's plans before approving. Fully local, no external services.",
|
|
15
|
-
"version": "0.2.
|
|
15
|
+
"version": "0.2.17",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "ndom91"
|
|
18
18
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-plan-annotator",
|
|
3
3
|
"description": "Interactive plan annotation UI: review, strikethrough, and comment on Claude's plans before approving. Fully local, no external services.",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.17",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ndom91"
|
|
7
7
|
},
|
package/opencode/bridge.js
CHANGED
|
@@ -175,7 +175,7 @@ export async function runPlanReview(options) {
|
|
|
175
175
|
|
|
176
176
|
const payload = buildHookPayload(options);
|
|
177
177
|
|
|
178
|
-
const
|
|
178
|
+
const output = await new Promise((resolve, reject) => {
|
|
179
179
|
let cwd = options.cwd ?? process.cwd();
|
|
180
180
|
|
|
181
181
|
// Guard: ensure cwd is a directory, not a file
|
|
@@ -187,19 +187,39 @@ export async function runPlanReview(options) {
|
|
|
187
187
|
cwd = PKG_ROOT;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
// Spawn the
|
|
191
|
-
//
|
|
190
|
+
// Spawn detached so the binary can outlive this call — it keeps its
|
|
191
|
+
// HTTP server alive for ~10s after emitting the JSON hook response.
|
|
192
192
|
const child = spawn(BINARY_PATH, [], {
|
|
193
193
|
cwd,
|
|
194
194
|
stdio: ["pipe", "pipe", "pipe"],
|
|
195
195
|
env: process.env,
|
|
196
|
+
detached: true,
|
|
196
197
|
});
|
|
197
198
|
|
|
198
199
|
let stdout = "";
|
|
199
200
|
let stderr = "";
|
|
201
|
+
let resolved = false;
|
|
200
202
|
|
|
201
203
|
child.stdout.on("data", (chunk) => {
|
|
202
204
|
stdout += String(chunk);
|
|
205
|
+
if (resolved) return;
|
|
206
|
+
|
|
207
|
+
// Scan for a complete JSON hook-output line. Once found, resolve
|
|
208
|
+
// immediately and let the binary keep running in the background.
|
|
209
|
+
const lines = stdout.split("\n");
|
|
210
|
+
for (const line of lines) {
|
|
211
|
+
const trimmed = line.trim();
|
|
212
|
+
if (!trimmed) continue;
|
|
213
|
+
try {
|
|
214
|
+
const parsed = validateHookOutput(JSON.parse(trimmed));
|
|
215
|
+
resolved = true;
|
|
216
|
+
child.unref();
|
|
217
|
+
resolve(parsed);
|
|
218
|
+
return;
|
|
219
|
+
} catch {
|
|
220
|
+
// Not valid hook JSON yet, keep buffering
|
|
221
|
+
}
|
|
222
|
+
}
|
|
203
223
|
});
|
|
204
224
|
|
|
205
225
|
child.stderr.on("data", (chunk) => {
|
|
@@ -207,40 +227,38 @@ export async function runPlanReview(options) {
|
|
|
207
227
|
});
|
|
208
228
|
|
|
209
229
|
child.on("error", (error) => {
|
|
210
|
-
reject(error);
|
|
230
|
+
if (!resolved) reject(error);
|
|
211
231
|
});
|
|
212
232
|
|
|
213
233
|
child.on("close", (code, signal) => {
|
|
214
|
-
|
|
234
|
+
if (resolved) return;
|
|
235
|
+
// Binary exited without producing valid JSON
|
|
236
|
+
if (signal) {
|
|
237
|
+
reject(
|
|
238
|
+
new Error(
|
|
239
|
+
stderr.trim()
|
|
240
|
+
? `open-plan-annotator was terminated by signal ${signal}: ${stderr.trim()}`
|
|
241
|
+
: `open-plan-annotator was terminated by signal ${signal}`,
|
|
242
|
+
),
|
|
243
|
+
);
|
|
244
|
+
} else if (code !== 0) {
|
|
245
|
+
reject(
|
|
246
|
+
new Error(
|
|
247
|
+
stderr.trim()
|
|
248
|
+
? `open-plan-annotator exited with code ${code}: ${stderr.trim()}`
|
|
249
|
+
: `open-plan-annotator exited with code ${code}`,
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
} else {
|
|
253
|
+
reject(new Error("open-plan-annotator exited without producing hook output"));
|
|
254
|
+
}
|
|
215
255
|
});
|
|
216
256
|
|
|
217
257
|
child.stdin.write(`${JSON.stringify(payload)}\n`);
|
|
218
258
|
child.stdin.end();
|
|
219
259
|
});
|
|
220
260
|
|
|
221
|
-
const
|
|
222
|
-
/** @type {{ code: number | null, signal: NodeJS.Signals | null, stdout: string, stderr: string }} */ (result);
|
|
223
|
-
|
|
224
|
-
if (settled.signal) {
|
|
225
|
-
const errorText = settled.stderr.trim();
|
|
226
|
-
throw new Error(
|
|
227
|
-
errorText
|
|
228
|
-
? `open-plan-annotator was terminated by signal ${settled.signal}: ${errorText}`
|
|
229
|
-
: `open-plan-annotator was terminated by signal ${settled.signal}`,
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (settled.code !== 0) {
|
|
234
|
-
const errorText = settled.stderr.trim();
|
|
235
|
-
throw new Error(
|
|
236
|
-
errorText
|
|
237
|
-
? `open-plan-annotator exited with code ${settled.code}: ${errorText}`
|
|
238
|
-
: `open-plan-annotator exited with code ${settled.code}`,
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const output = parseHookOutput(settled.stdout, settled.stderr);
|
|
243
|
-
const decision = output.hookSpecificOutput.decision;
|
|
261
|
+
const decision = /** @type {HookOutput} */ (output).hookSpecificOutput.decision;
|
|
244
262
|
|
|
245
263
|
if (decision.behavior === "allow") {
|
|
246
264
|
return { approved: true };
|