@aryaminus/controlkeel-opencode 0.2.45 → 0.2.47

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.
@@ -10,7 +10,7 @@ Recommended flow:
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
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 **or** wait times out while still `pending`, 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 or timed out" --json` (or `ck_review_feedback`)
13
+ 6. If `browser_url` is missing/unreachable, the browser does not actually open, **or** wait times out while still `pending`, 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 or timed out" --json` (or `ck_review_feedback`)
14
14
  7. Do not execute until the review is approved
15
15
 
16
16
  Fallback when the `submit_plan` tool is stale in a long-running OpenCode session:
@@ -343,29 +343,45 @@ export const ControlKeelGovernance: Plugin = async ({ project, client, $, direct
343
343
  submitPayload?.review?.browser_url ??
344
344
  null
345
345
 
346
+ const buildPlanResult = (overrides = {}) => ({
347
+ reviewId,
348
+ browserUrl: overrides.browserUrl ?? browserUrl,
349
+ status: overrides.status ?? submitPayload?.review?.status ?? "pending",
350
+ feedbackNotes:
351
+ overrides.feedbackNotes ?? submitPayload?.review?.feedback_notes ?? null,
352
+ opened: overrides.opened ?? (openPayload?.opened === true),
353
+ timedOut: overrides.timedOut ?? false,
354
+ waitSkipped: overrides.waitSkipped ?? false,
355
+ manualApprovalRequired: overrides.manualApprovalRequired ?? false,
356
+ reason: overrides.reason ?? null,
357
+ guidance: overrides.guidance ?? null,
358
+ })
359
+
346
360
  const openError = typeof openPayload?.open_error === "string" ? openPayload.open_error.trim() : ""
347
361
  const openFailure = typeof openPayload?.error === "string" ? openPayload.error.trim() : ""
362
+ const browserNotOpened = openPayload?.opened !== true
363
+ const serverUnavailable = openPayload?.server_serving === false
348
364
 
349
365
  const remoteLocalhostMismatch =
350
366
  typeof browserUrl === "string" &&
351
367
  browserUrl.includes("localhost") &&
352
368
  openPayload?.remote === true
353
369
 
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,
370
+ if (!browserUrl || serverUnavailable || openError || openFailure || remoteLocalhostMismatch || browserNotOpened) {
371
+ return buildPlanResult({
363
372
  waitSkipped: true,
364
373
  manualApprovalRequired: true,
365
- reason: !browserUrl ? "browser_url_unavailable" : "browser_unreachable",
374
+ reason:
375
+ !browserUrl
376
+ ? "browser_url_unavailable"
377
+ : serverUnavailable
378
+ ? "review_server_unavailable"
379
+ : browserNotOpened
380
+ ? "browser_not_opened"
381
+ : "browser_unreachable",
366
382
  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
- }
383
+ "Browser review is unavailable, the CK review server is not reachable, or the browser did not actually open. 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/review server unavailable\" --json` or `ck_review_feedback`.",
384
+ })
369
385
  }
370
386
 
371
387
  const waitEnv = process.env.LOGGER_LEVEL
@@ -388,10 +404,7 @@ export const ControlKeelGovernance: Plugin = async ({ project, client, $, direct
388
404
 
389
405
  if (waitExit !== 0) {
390
406
  if (waitTimedOut && waitPending) {
391
- return {
392
- reviewId,
393
- submitPayload,
394
- waitPayload,
407
+ return buildPlanResult({
395
408
  browserUrl: waitPayload?.browser_url ?? submitPayload?.browser_url,
396
409
  status: "pending",
397
410
  feedbackNotes: waitPayload?.review?.feedback_notes ?? null,
@@ -401,7 +414,7 @@ export const ControlKeelGovernance: Plugin = async ({ project, client, $, direct
401
414
  reason: "review_timeout",
402
415
  guidance:
403
416
  "Plan review is still pending after timeout. Show the `browser_url` to the user if reachable. If browser review is unavailable or the user explicitly approves in chat, record it with `controlkeel review plan respond --id <review_id> --decision approved --feedback-notes \"User approved in chat after timeout/browser issue\" --json` (or `ck_review_feedback`) before proceeding.",
404
- }
417
+ })
405
418
  }
406
419
 
407
420
  throw new Error(
@@ -409,17 +422,13 @@ export const ControlKeelGovernance: Plugin = async ({ project, client, $, direct
409
422
  )
410
423
  }
411
424
 
412
- return {
413
- reviewId,
414
- submitPayload,
415
- openPayload,
416
- waitPayload,
425
+ return buildPlanResult({
417
426
  browserUrl: waitPayload?.browser_url ?? browserUrl,
418
427
  status: waitPayload?.review?.status,
419
428
  feedbackNotes: waitPayload?.review?.feedback_notes ?? null,
420
429
  waitSkipped: false,
421
430
  manualApprovalRequired: false,
422
- }
431
+ })
423
432
  } finally {
424
433
  // Clean up temp file
425
434
  try { await Bun.file(tmpFile).unlink?.() ?? (await $`rm -f ${tmpFile}`.quiet()) } catch {}
@@ -479,7 +488,7 @@ export const ControlKeelGovernance: Plugin = async ({ project, client, $, direct
479
488
  args.task_id,
480
489
  args.session_id
481
490
  )
482
- return JSON.stringify(result, null, 2)
491
+ return JSON.stringify(result)
483
492
  },
484
493
  }),
485
494
  },
package/AGENTS.md CHANGED
@@ -11,8 +11,9 @@ Required workflow:
11
11
  2. Call `ck_validate` before writing code, config, shell, or deploy content.
12
12
  3. Submit plans or approval packets with `ck_review_submit` and check `ck_review_status` before execution.
13
13
  4. Record any human-review issue with `ck_finding`.
14
- 5. Check `ck_budget` before expensive model or multi-agent work.
15
- 6. Use `ck_route`, `ck_skill_list`, and `ck_skill_load` to delegate or activate specialized CK workflows.
14
+ 5. Check `ck_budget` before expensive model or multi-agent work, and keep `ck_context` compact unless full raw context is needed.
15
+ 6. Before AFK or delegated implementation, split large work into human-approved vertical slices with explicit dependencies; prefer durable behavior-first issues, stable deep-module interfaces, and branch-level automated review plus human QA before merge.
16
+ 7. Use `ck_route`, `ck_skill_list`, and `ck_skill_load` to delegate or activate specialized CK workflows.
16
17
 
17
18
  Install ControlKeel:
18
19
  - Homebrew: `brew tap aryaminus/controlkeel && brew install controlkeel`
package/index.js CHANGED
@@ -326,29 +326,45 @@ export const ControlKeelGovernance = async ({ $, directory }) => {
326
326
  submitPayload?.review?.browser_url ??
327
327
  null
328
328
 
329
+ const buildPlanResult = (overrides = {}) => ({
330
+ reviewId,
331
+ browserUrl: overrides.browserUrl ?? browserUrl,
332
+ status: overrides.status ?? submitPayload?.review?.status ?? "pending",
333
+ feedbackNotes:
334
+ overrides.feedbackNotes ?? submitPayload?.review?.feedback_notes ?? null,
335
+ opened: overrides.opened ?? (openPayload?.opened === true),
336
+ timedOut: overrides.timedOut ?? false,
337
+ waitSkipped: overrides.waitSkipped ?? false,
338
+ manualApprovalRequired: overrides.manualApprovalRequired ?? false,
339
+ reason: overrides.reason ?? null,
340
+ guidance: overrides.guidance ?? null,
341
+ })
342
+
329
343
  const openError = typeof openPayload?.open_error === "string" ? openPayload.open_error.trim() : ""
330
344
  const openFailure = typeof openPayload?.error === "string" ? openPayload.error.trim() : ""
345
+ const browserNotOpened = openPayload?.opened !== true
346
+ const serverUnavailable = openPayload?.server_serving === false
331
347
 
332
348
  const remoteLocalhostMismatch =
333
349
  typeof browserUrl === "string" &&
334
350
  browserUrl.includes("localhost") &&
335
351
  openPayload?.remote === true
336
352
 
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,
353
+ if (!browserUrl || serverUnavailable || openError || openFailure || remoteLocalhostMismatch || browserNotOpened) {
354
+ return buildPlanResult({
346
355
  waitSkipped: true,
347
356
  manualApprovalRequired: true,
348
- reason: !browserUrl ? "browser_url_unavailable" : "browser_unreachable",
357
+ reason:
358
+ !browserUrl
359
+ ? "browser_url_unavailable"
360
+ : serverUnavailable
361
+ ? "review_server_unavailable"
362
+ : browserNotOpened
363
+ ? "browser_not_opened"
364
+ : "browser_unreachable",
349
365
  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
- }
366
+ "Browser review is unavailable, the CK review server is not reachable, or the browser did not actually open. 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/review server unavailable\" --json` or `ck_review_feedback`.",
367
+ })
352
368
  }
353
369
 
354
370
  const waitEnv = process.env.LOGGER_LEVEL
@@ -371,10 +387,7 @@ export const ControlKeelGovernance = async ({ $, directory }) => {
371
387
 
372
388
  if (waitExit !== 0) {
373
389
  if (waitTimedOut && waitPending) {
374
- return {
375
- reviewId,
376
- submitPayload,
377
- waitPayload,
390
+ return buildPlanResult({
378
391
  browserUrl: waitPayload?.browser_url ?? submitPayload?.browser_url,
379
392
  status: "pending",
380
393
  feedbackNotes: waitPayload?.review?.feedback_notes ?? null,
@@ -384,7 +397,7 @@ export const ControlKeelGovernance = async ({ $, directory }) => {
384
397
  reason: "review_timeout",
385
398
  guidance:
386
399
  "Plan review is still pending after timeout. Show the `browser_url` to the user if reachable. If browser review is unavailable or the user explicitly approves in chat, record it with `controlkeel review plan respond --id <review_id> --decision approved --feedback-notes \"User approved in chat after timeout/browser issue\" --json` (or `ck_review_feedback`) before proceeding.",
387
- }
400
+ })
388
401
  }
389
402
 
390
403
  throw new Error(
@@ -392,17 +405,13 @@ export const ControlKeelGovernance = async ({ $, directory }) => {
392
405
  )
393
406
  }
394
407
 
395
- return {
396
- reviewId,
397
- submitPayload,
398
- openPayload,
399
- waitPayload,
408
+ return buildPlanResult({
400
409
  browserUrl: waitPayload?.browser_url ?? browserUrl,
401
410
  status: waitPayload?.review?.status,
402
411
  feedbackNotes: waitPayload?.review?.feedback_notes ?? null,
403
412
  waitSkipped: false,
404
413
  manualApprovalRequired: false,
405
- }
414
+ })
406
415
  } finally {
407
416
  // Clean up temp file
408
417
  try { await Bun.file(tmpFile).unlink?.() ?? (await $`rm -f ${tmpFile}`.quiet()) } catch {}
@@ -462,7 +471,7 @@ export const ControlKeelGovernance = async ({ $, directory }) => {
462
471
  args.task_id,
463
472
  args.session_id
464
473
  )
465
- return JSON.stringify(result, null, 2)
474
+ return JSON.stringify(result)
466
475
  },
467
476
  }),
468
477
  },
package/package.json CHANGED
@@ -35,5 +35,5 @@
35
35
  "url": "git+https://github.com/aryaminus/controlkeel.git"
36
36
  },
37
37
  "type": "module",
38
- "version": "0.2.45"
38
+ "version": "0.2.47"
39
39
  }