@aryaminus/controlkeel-opencode 0.2.32 → 0.2.34
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.
|
@@ -9,8 +9,9 @@ Recommended flow:
|
|
|
9
9
|
2. Ensure `controlkeel version` reports `>= 0.1.26`
|
|
10
10
|
3. Run `controlkeel review plan submit --body-file .opencode/review-plan.md --submitted-by opencode --task-id <task_id> --json` (or use `--session-id <session_id>`)
|
|
11
11
|
4. Read the returned `review.id` and `browser_url`
|
|
12
|
-
5.
|
|
13
|
-
6.
|
|
12
|
+
5. If `browser_url` is available, wait with `controlkeel review plan wait --id <review_id> --timeout 30 --json`
|
|
13
|
+
6. If `browser_url` is missing/unreachable, do **not** loop on wait; ask for explicit user approval in chat and record it with `controlkeel review plan respond --id <review_id> --decision approved --feedback-notes "User approved in chat; browser unavailable" --json` (or `ck_review_feedback`)
|
|
14
|
+
7. Do not execute until the review is approved
|
|
14
15
|
|
|
15
16
|
Fallback when the `submit_plan` tool is stale in a long-running OpenCode session:
|
|
16
17
|
- If the tool returns an error like `ControlKeel CLI [object Object] is too old`, run the CLI flow above directly.
|
|
@@ -309,6 +309,65 @@ export const ControlKeelGovernance: Plugin = async ({ project, client, $, direct
|
|
|
309
309
|
throw new Error("ControlKeel did not return a review id")
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
const openEnv = process.env.LOGGER_LEVEL
|
|
313
|
+
? process.env
|
|
314
|
+
: { ...process.env, LOGGER_LEVEL: "warning" }
|
|
315
|
+
|
|
316
|
+
let openPayload = null
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
const openProc = Bun.spawn(["controlkeel", "review", "plan", "open", "--id", String(reviewId), "--json"], {
|
|
320
|
+
stdout: "pipe",
|
|
321
|
+
stderr: "pipe",
|
|
322
|
+
env: openEnv,
|
|
323
|
+
})
|
|
324
|
+
const openOut = await new Response(openProc.stdout).text()
|
|
325
|
+
const openErr = await new Response(openProc.stderr).text()
|
|
326
|
+
const openExit = await openProc.exited
|
|
327
|
+
|
|
328
|
+
if (openExit === 0) {
|
|
329
|
+
openPayload = parseJson([openOut, openErr].filter(Boolean).join("\n"))
|
|
330
|
+
} else {
|
|
331
|
+
openPayload = {
|
|
332
|
+
error: `controlkeel review plan open failed with exit code ${openExit}${openErr.trim() ? `: ${openErr.trim()}` : ""}`,
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
} catch (error) {
|
|
336
|
+
openPayload = { error: error instanceof Error ? error.message : String(error) }
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const browserUrl =
|
|
340
|
+
openPayload?.browser_url ??
|
|
341
|
+
submitPayload?.browser_url ??
|
|
342
|
+
submitPayload?.url ??
|
|
343
|
+
submitPayload?.review?.browser_url ??
|
|
344
|
+
null
|
|
345
|
+
|
|
346
|
+
const openError = typeof openPayload?.open_error === "string" ? openPayload.open_error.trim() : ""
|
|
347
|
+
const openFailure = typeof openPayload?.error === "string" ? openPayload.error.trim() : ""
|
|
348
|
+
|
|
349
|
+
const remoteLocalhostMismatch =
|
|
350
|
+
typeof browserUrl === "string" &&
|
|
351
|
+
browserUrl.includes("localhost") &&
|
|
352
|
+
openPayload?.remote === true
|
|
353
|
+
|
|
354
|
+
if (!browserUrl || openError || openFailure || remoteLocalhostMismatch) {
|
|
355
|
+
return {
|
|
356
|
+
reviewId,
|
|
357
|
+
submitPayload,
|
|
358
|
+
openPayload,
|
|
359
|
+
browserUrl,
|
|
360
|
+
status: submitPayload?.review?.status ?? "pending",
|
|
361
|
+
feedbackNotes: submitPayload?.review?.feedback_notes ?? null,
|
|
362
|
+
timedOut: false,
|
|
363
|
+
waitSkipped: true,
|
|
364
|
+
manualApprovalRequired: true,
|
|
365
|
+
reason: !browserUrl ? "browser_url_unavailable" : "browser_unreachable",
|
|
366
|
+
guidance:
|
|
367
|
+
"Browser review is unavailable from this environment. Ask the user for explicit approval in chat, then record it with `controlkeel review plan respond --id <review_id> --decision approved --feedback-notes \"User approved in chat; browser unavailable\" --json` or `ck_review_feedback`.",
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
312
371
|
const waitEnv = process.env.LOGGER_LEVEL
|
|
313
372
|
? process.env
|
|
314
373
|
: { ...process.env, LOGGER_LEVEL: "warning" }
|
|
@@ -348,10 +407,13 @@ export const ControlKeelGovernance: Plugin = async ({ project, client, $, direct
|
|
|
348
407
|
return {
|
|
349
408
|
reviewId,
|
|
350
409
|
submitPayload,
|
|
410
|
+
openPayload,
|
|
351
411
|
waitPayload,
|
|
352
|
-
browserUrl: waitPayload?.browser_url ??
|
|
412
|
+
browserUrl: waitPayload?.browser_url ?? browserUrl,
|
|
353
413
|
status: waitPayload?.review?.status,
|
|
354
414
|
feedbackNotes: waitPayload?.review?.feedback_notes ?? null,
|
|
415
|
+
waitSkipped: false,
|
|
416
|
+
manualApprovalRequired: false,
|
|
355
417
|
}
|
|
356
418
|
} finally {
|
|
357
419
|
// Clean up temp file
|
package/index.js
CHANGED
|
@@ -292,6 +292,65 @@ export const ControlKeelGovernance = async ({ $, directory }) => {
|
|
|
292
292
|
throw new Error("ControlKeel did not return a review id")
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
const openEnv = process.env.LOGGER_LEVEL
|
|
296
|
+
? process.env
|
|
297
|
+
: { ...process.env, LOGGER_LEVEL: "warning" }
|
|
298
|
+
|
|
299
|
+
let openPayload = null
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
const openProc = Bun.spawn(["controlkeel", "review", "plan", "open", "--id", String(reviewId), "--json"], {
|
|
303
|
+
stdout: "pipe",
|
|
304
|
+
stderr: "pipe",
|
|
305
|
+
env: openEnv,
|
|
306
|
+
})
|
|
307
|
+
const openOut = await new Response(openProc.stdout).text()
|
|
308
|
+
const openErr = await new Response(openProc.stderr).text()
|
|
309
|
+
const openExit = await openProc.exited
|
|
310
|
+
|
|
311
|
+
if (openExit === 0) {
|
|
312
|
+
openPayload = parseJson([openOut, openErr].filter(Boolean).join("\n"))
|
|
313
|
+
} else {
|
|
314
|
+
openPayload = {
|
|
315
|
+
error: `controlkeel review plan open failed with exit code ${openExit}${openErr.trim() ? `: ${openErr.trim()}` : ""}`,
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} catch (error) {
|
|
319
|
+
openPayload = { error: error instanceof Error ? error.message : String(error) }
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const browserUrl =
|
|
323
|
+
openPayload?.browser_url ??
|
|
324
|
+
submitPayload?.browser_url ??
|
|
325
|
+
submitPayload?.url ??
|
|
326
|
+
submitPayload?.review?.browser_url ??
|
|
327
|
+
null
|
|
328
|
+
|
|
329
|
+
const openError = typeof openPayload?.open_error === "string" ? openPayload.open_error.trim() : ""
|
|
330
|
+
const openFailure = typeof openPayload?.error === "string" ? openPayload.error.trim() : ""
|
|
331
|
+
|
|
332
|
+
const remoteLocalhostMismatch =
|
|
333
|
+
typeof browserUrl === "string" &&
|
|
334
|
+
browserUrl.includes("localhost") &&
|
|
335
|
+
openPayload?.remote === true
|
|
336
|
+
|
|
337
|
+
if (!browserUrl || openError || openFailure || remoteLocalhostMismatch) {
|
|
338
|
+
return {
|
|
339
|
+
reviewId,
|
|
340
|
+
submitPayload,
|
|
341
|
+
openPayload,
|
|
342
|
+
browserUrl,
|
|
343
|
+
status: submitPayload?.review?.status ?? "pending",
|
|
344
|
+
feedbackNotes: submitPayload?.review?.feedback_notes ?? null,
|
|
345
|
+
timedOut: false,
|
|
346
|
+
waitSkipped: true,
|
|
347
|
+
manualApprovalRequired: true,
|
|
348
|
+
reason: !browserUrl ? "browser_url_unavailable" : "browser_unreachable",
|
|
349
|
+
guidance:
|
|
350
|
+
"Browser review is unavailable from this environment. Ask the user for explicit approval in chat, then record it with `controlkeel review plan respond --id <review_id> --decision approved --feedback-notes \"User approved in chat; browser unavailable\" --json` or `ck_review_feedback`.",
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
295
354
|
const waitEnv = process.env.LOGGER_LEVEL
|
|
296
355
|
? process.env
|
|
297
356
|
: { ...process.env, LOGGER_LEVEL: "warning" }
|
|
@@ -331,10 +390,13 @@ export const ControlKeelGovernance = async ({ $, directory }) => {
|
|
|
331
390
|
return {
|
|
332
391
|
reviewId,
|
|
333
392
|
submitPayload,
|
|
393
|
+
openPayload,
|
|
334
394
|
waitPayload,
|
|
335
|
-
browserUrl: waitPayload?.browser_url ??
|
|
395
|
+
browserUrl: waitPayload?.browser_url ?? browserUrl,
|
|
336
396
|
status: waitPayload?.review?.status,
|
|
337
397
|
feedbackNotes: waitPayload?.review?.feedback_notes ?? null,
|
|
398
|
+
waitSkipped: false,
|
|
399
|
+
manualApprovalRequired: false,
|
|
338
400
|
}
|
|
339
401
|
} finally {
|
|
340
402
|
// Clean up temp file
|
package/package.json
CHANGED