orizu 0.5.26 → 0.5.28

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.
Files changed (164) hide show
  1. package/README.md +19 -0
  2. package/dist/artifacts-git-runtime.d.ts +34 -0
  3. package/dist/artifacts-git-runtime.d.ts.map +1 -0
  4. package/dist/artifacts-git-runtime.js +312 -0
  5. package/dist/cloudflare-artifacts-git-remote.d.ts +5 -0
  6. package/dist/cloudflare-artifacts-git-remote.d.ts.map +1 -0
  7. package/dist/cloudflare-artifacts-git-remote.js +21 -0
  8. package/dist/dataset-transfer-download.d.ts +2 -0
  9. package/dist/dataset-transfer-download.d.ts.map +1 -0
  10. package/dist/dataset-transfer-download.js +66 -0
  11. package/dist/dataset-transfer-policy.d.ts +2 -0
  12. package/dist/dataset-transfer-policy.d.ts.map +1 -0
  13. package/dist/dataset-transfer-policy.js +8 -0
  14. package/dist/dataset-transfer-upload.d.ts +42 -0
  15. package/dist/dataset-transfer-upload.d.ts.map +1 -0
  16. package/dist/dataset-transfer-upload.js +110 -0
  17. package/dist/git-credential.d.ts.map +1 -1
  18. package/dist/git-credential.js +1 -1
  19. package/dist/git-recovery-environment.d.ts +1 -0
  20. package/dist/git-recovery-environment.d.ts.map +1 -1
  21. package/dist/git-recovery-environment.js +1 -1
  22. package/dist/help.d.ts.map +1 -1
  23. package/dist/help.js +44 -11
  24. package/dist/hosted-boot.d.ts +75 -2
  25. package/dist/hosted-boot.d.ts.map +1 -1
  26. package/dist/hosted-boot.js +585 -102
  27. package/dist/hosted-bootstrap.d.ts +2 -0
  28. package/dist/hosted-bootstrap.d.ts.map +1 -1
  29. package/dist/hosted-bootstrap.js +12 -3
  30. package/dist/hosted-harness-opencode.d.ts +8 -9
  31. package/dist/hosted-harness-opencode.d.ts.map +1 -1
  32. package/dist/hosted-harness-opencode.js +126 -24
  33. package/dist/hosted-harness.d.ts +3 -0
  34. package/dist/hosted-harness.d.ts.map +1 -1
  35. package/dist/hosted-harness.js +4 -1
  36. package/dist/hosted-harvest.d.ts +30 -9
  37. package/dist/hosted-harvest.d.ts.map +1 -1
  38. package/dist/hosted-harvest.js +222 -28
  39. package/dist/hosted-loop-lifecycle.d.ts +15 -3
  40. package/dist/hosted-loop-lifecycle.d.ts.map +1 -1
  41. package/dist/hosted-loop-lifecycle.js +6 -4
  42. package/dist/hosted-loop.d.ts +47 -7
  43. package/dist/hosted-loop.d.ts.map +1 -1
  44. package/dist/hosted-loop.js +310 -64
  45. package/dist/hosted-question-limits.d.ts +7 -0
  46. package/dist/hosted-question-limits.d.ts.map +1 -0
  47. package/dist/hosted-question-limits.js +6 -0
  48. package/dist/hosted-question.d.ts +27 -0
  49. package/dist/hosted-question.d.ts.map +1 -0
  50. package/dist/hosted-question.js +118 -0
  51. package/dist/hosted-run-event-sink.d.ts +10 -5
  52. package/dist/hosted-run-event-sink.d.ts.map +1 -1
  53. package/dist/hosted-run-event-sink.js +12 -8
  54. package/dist/hosted-runtime-assets.d.ts +16 -7
  55. package/dist/hosted-runtime-assets.d.ts.map +1 -1
  56. package/dist/hosted-runtime-assets.js +40 -12
  57. package/dist/hosted-session-cli.d.ts.map +1 -1
  58. package/dist/hosted-session-cli.js +10 -19
  59. package/dist/http.d.ts +1 -1
  60. package/dist/http.d.ts.map +1 -1
  61. package/dist/http.js +10 -4
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +113 -92
  64. package/dist/instruction-set-gepa-launch.d.ts +1 -1
  65. package/dist/instruction-set-gepa-launch.d.ts.map +1 -1
  66. package/dist/instruction-set-gepa-launch.js +5 -3
  67. package/dist/instruction-set-loader.d.ts.map +1 -1
  68. package/dist/instruction-set-loader.js +63 -2
  69. package/dist/instruction-set-lock/index.d.ts +51 -0
  70. package/dist/instruction-set-lock/index.d.ts.map +1 -0
  71. package/dist/instruction-set-lock/index.js +459 -0
  72. package/dist/instruction-set-lock/schema.v1.d.ts +136 -0
  73. package/dist/instruction-set-lock/schema.v1.d.ts.map +1 -0
  74. package/dist/instruction-set-lock/schema.v1.js +155 -0
  75. package/dist/instruction-set-provenance.d.ts +26 -0
  76. package/dist/instruction-set-provenance.d.ts.map +1 -0
  77. package/dist/instruction-set-provenance.js +68 -0
  78. package/dist/instruction-set-sync/helpers.d.ts +22 -0
  79. package/dist/instruction-set-sync/helpers.d.ts.map +1 -0
  80. package/dist/instruction-set-sync/helpers.js +677 -0
  81. package/dist/instruction-set-sync/index.d.ts +60 -0
  82. package/dist/instruction-set-sync/index.d.ts.map +1 -0
  83. package/dist/instruction-set-sync/index.js +689 -0
  84. package/dist/instruction-set-update/index.d.ts +42 -0
  85. package/dist/instruction-set-update/index.d.ts.map +1 -0
  86. package/dist/instruction-set-update/index.js +445 -0
  87. package/dist/instruction-set-verify/index.d.ts +27 -0
  88. package/dist/instruction-set-verify/index.d.ts.map +1 -0
  89. package/dist/instruction-set-verify/index.js +865 -0
  90. package/dist/instruction-sets-cli.d.ts +1 -4
  91. package/dist/instruction-sets-cli.d.ts.map +1 -1
  92. package/dist/instruction-sets-cli.js +220 -109
  93. package/dist/model-config-fields.d.ts +35 -0
  94. package/dist/model-config-fields.d.ts.map +1 -0
  95. package/dist/model-config-fields.js +28 -0
  96. package/dist/optimizations-list-cli.d.ts.map +1 -1
  97. package/dist/optimizations-list-cli.js +7 -4
  98. package/dist/score-format.d.ts +2 -0
  99. package/dist/score-format.d.ts.map +1 -0
  100. package/dist/score-format.js +18 -0
  101. package/dist/workbench-repo-contract.d.ts +65 -0
  102. package/dist/workbench-repo-contract.d.ts.map +1 -0
  103. package/dist/workbench-repo-contract.js +250 -0
  104. package/dist/workspace-bootstrap-job.d.ts +45 -0
  105. package/dist/workspace-bootstrap-job.d.ts.map +1 -0
  106. package/dist/workspace-bootstrap-job.js +431 -0
  107. package/dist/workspace-bootstrap-seed.d.ts +74 -0
  108. package/dist/workspace-bootstrap-seed.d.ts.map +1 -0
  109. package/dist/workspace-bootstrap-seed.js +209 -0
  110. package/package.json +4 -3
  111. package/src/artifacts-git-runtime.ts +360 -0
  112. package/src/cloudflare-artifacts-git-remote.ts +24 -0
  113. package/src/dataset-transfer-download.ts +61 -0
  114. package/src/dataset-transfer-policy.ts +8 -0
  115. package/src/dataset-transfer-upload.ts +145 -0
  116. package/src/git-credential.ts +1 -2
  117. package/src/git-recovery-environment.ts +1 -1
  118. package/src/help.ts +44 -11
  119. package/src/hosted-boot.ts +644 -109
  120. package/src/hosted-bootstrap.ts +14 -3
  121. package/src/hosted-harness-opencode.ts +130 -28
  122. package/src/hosted-harness.ts +4 -1
  123. package/src/hosted-harvest.ts +258 -33
  124. package/src/hosted-loop-lifecycle.ts +19 -5
  125. package/src/hosted-loop.ts +340 -68
  126. package/src/hosted-question-limits.ts +6 -0
  127. package/src/hosted-question.ts +145 -0
  128. package/src/hosted-run-event-sink.ts +24 -12
  129. package/src/hosted-runtime-assets.ts +51 -11
  130. package/src/hosted-session-cli.ts +10 -24
  131. package/src/http.ts +10 -4
  132. package/src/index.ts +108 -134
  133. package/src/instruction-set-gepa-launch.ts +4 -4
  134. package/src/instruction-set-loader.ts +53 -2
  135. package/src/instruction-set-lock/index.ts +561 -0
  136. package/src/instruction-set-lock/schema.v1.json +141 -0
  137. package/src/instruction-set-lock/schema.v1.ts +155 -0
  138. package/src/instruction-set-provenance.ts +89 -0
  139. package/src/instruction-set-sync/helpers.ts +707 -0
  140. package/src/instruction-set-sync/index.ts +791 -0
  141. package/src/instruction-set-update/index.ts +488 -0
  142. package/src/instruction-set-verify/index.ts +1067 -0
  143. package/src/instruction-sets-cli.ts +226 -114
  144. package/src/model-config-fields.ts +31 -0
  145. package/src/optimizations-list-cli.ts +7 -4
  146. package/src/score-format.ts +16 -0
  147. package/src/workbench-repo-contract.ts +314 -0
  148. package/src/workspace-bootstrap-job.ts +611 -0
  149. package/src/workspace-bootstrap-seed.ts +350 -0
  150. package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +46 -2
  151. package/vendor/skills/orizu/SKILL.md +4 -2
  152. package/vendor/skills/orizu/flows/promote.md +4 -0
  153. package/vendor/skills/orizu/references/assess-and-plan.md +1 -1
  154. package/vendor/skills/orizu/references/authority-map.md +1 -1
  155. package/vendor/skills/orizu/references/cli-reference.md +151 -35
  156. package/vendor/skills/orizu/references/instructions-after-prompts.md +3 -3
  157. package/vendor/skills/orizu/references/migrate-existing-gepa-setup.md +5 -6
  158. package/vendor/skills/orizu/references/migrate-hand-rolled-instruction-layout.md +252 -0
  159. package/vendor/skills/orizu/references/optimization-reports.md +5 -4
  160. package/vendor/skills/orizu/references/optimization-with-gepa.md +1 -1
  161. package/vendor/skills/orizu/references/orizu-in-your-codebase.md +195 -0
  162. package/vendor/skills/orizu/references/primer.md +4 -2
  163. package/vendor/skills/orizu/references/prompt-control-plane.md +33 -29
  164. package/vendor/skills/orizu/references/vocabulary.md +1 -1
@@ -208,6 +208,8 @@ export interface HostedBootstrapResult {
208
208
  steps: HostedBootstrapStep[]
209
209
  events: readonly AppendedRunEvent[]
210
210
  paths: HostedRuntimePaths
211
+ /** Bootstrap-selected helper, carried out-of-repo to checkpoint transport. */
212
+ credentialHelper: string
211
213
  /** Set on the failure path: the residue sweep result after teardown. */
212
214
  sweep: { clean: boolean; findings: HygieneFinding[] } | null
213
215
  failure: { step: string; error: string } | null
@@ -478,7 +480,10 @@ export async function bootstrapHostedSandbox(opts: HostedBootstrapOptions): Prom
478
480
  if (opts.deferSetupHook) {
479
481
  record('setup_hook_deferred', true, 'deferred to loop (runs after egress canary)')
480
482
  await sink.append('setup_hook_deferred', { reason: 'egress canary must pass before customer setup.sh runs' })
481
- return { ok: true, steps, events: sink.recorded, paths, sweep: null, failure: null }
483
+ return {
484
+ ok: true, steps, events: sink.recorded, paths,
485
+ credentialHelper: helperValue, sweep: null, failure: null,
486
+ }
482
487
  }
483
488
  const hookRel = `${workspaceDir}/${SETUP_HOOK_RELATIVE_PATH}`
484
489
  if (await session.fileExists(hookRel)) {
@@ -495,14 +500,20 @@ export async function bootstrapHostedSandbox(opts: HostedBootstrapOptions): Prom
495
500
  await sink.append('setup_hook_skipped', { reason: 'no .orizu/setup.sh' })
496
501
  }
497
502
 
498
- return { ok: true, steps, events: sink.recorded, paths, sweep: null, failure: null }
503
+ return {
504
+ ok: true, steps, events: sink.recorded, paths,
505
+ credentialHelper: helperValue, sweep: null, failure: null,
506
+ }
499
507
  } catch (error) {
500
508
  const message = error instanceof Error ? error.message : String(error)
501
509
  record(currentStep, false, message)
502
510
  // Record the failure (redacted), then tear down + prove no residue remains.
503
511
  await safeAppend(sink, 'bootstrap_failed', { step: currentStep, error: message })
504
512
  const sweep = await teardownHostedSandbox({ session, paths, bearer: opts.bearer, workspaceDir })
505
- return { ok: false, steps, events: sink.recorded, paths, sweep, failure: { step: currentStep, error: message } }
513
+ return {
514
+ ok: false, steps, events: sink.recorded, paths, credentialHelper: helperValue,
515
+ sweep, failure: { step: currentStep, error: message },
516
+ }
506
517
  }
507
518
  }
508
519
 
@@ -331,6 +331,12 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
331
331
  // Set true by the public stop(); makes the next idle terminal resolve as a
332
332
  // cancellation rather than a success (P2-2).
333
333
  let stopRequested = false
334
+ let stopRequest: Promise<void> | null = null
335
+ let promptSubmissionPending = false
336
+ let promptSubmissionSettled: Promise<void> | null = null
337
+ let resolvePromptSubmission: (() => void) | null = null
338
+ let postAcceptanceAbortGeneration = -1
339
+ let promptGeneration = 0
334
340
  // Last title actually forwarded, deduped across the whole harness lifetime so
335
341
  // a repeated identical title is emitted once (P3-6).
336
342
  let lastForwardedTitle: string | null = null
@@ -379,14 +385,51 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
379
385
  }
380
386
  }
381
387
 
382
- async function requestStop(): Promise<void> {
388
+ async function requestStop(options: { force?: boolean } = {}): Promise<void> {
383
389
  if (!opencodeSessionId) return
390
+ if (
391
+ promptSubmissionPending &&
392
+ promptSubmissionSettled &&
393
+ postAcceptanceAbortGeneration !== promptGeneration
394
+ ) {
395
+ const racedGeneration = promptGeneration
396
+ const settlement = promptSubmissionSettled
397
+ postAcceptanceAbortGeneration = racedGeneration
398
+ // The stream consumer may close this generator as soon as its signal
399
+ // aborts. Keep the post-acceptance abort independent of generator
400
+ // continuation so an accepted prompt cannot escape cancellation.
401
+ void settlement.then(() => requestStop({ force: true }))
402
+ }
403
+ // Prompt signal + the hosted-loop stop() belt normally share one successful
404
+ // request. A failed request is never memoized, and prompt acknowledgement
405
+ // can force a post-acceptance abort when an earlier abort raced ahead of it.
406
+ if (stopRequest && !options.force) {
407
+ const inFlight = stopRequest
408
+ try {
409
+ await inFlight
410
+ return
411
+ } catch {
412
+ if (stopRequest === inFlight) stopRequest = null
413
+ // The owner of the failed request handles its own best-effort result.
414
+ // This overlapping caller owns the one follow-up acknowledgement try;
415
+ // it must never inherit the rejected memo as a fatal prompt error.
416
+ return requestStop(options)
417
+ }
418
+ }
419
+ const request = (async () => {
420
+ const response = await timedFetch(
421
+ `${base}/session/${encodeURIComponent(opencodeSessionId!)}/abort`,
422
+ { method: 'POST' }
423
+ )
424
+ if (!response.ok) throw new Error(`OpenCode abort failed (${response.status})`)
425
+ })()
426
+ stopRequest = request
384
427
  try {
385
- await timedFetch(`${base}/session/${encodeURIComponent(opencodeSessionId)}/abort`, {
386
- method: 'POST',
387
- })
428
+ await request
388
429
  } catch {
389
- // best-effort: the stream teardown is the real cancellation
430
+ if (stopRequest === request) stopRequest = null
431
+ // best-effort: stream teardown still settles this attempt, while a later
432
+ // stop can retry because the failed request no longer owns the memo.
390
433
  }
391
434
  }
392
435
 
@@ -454,9 +497,14 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
454
497
  async *runPrompt(prompt: HarnessPrompt, signal: AbortSignal): AsyncIterable<HarnessEvent> {
455
498
  if (!opencodeSessionId) opencodeSessionId = await createSession()
456
499
  const sessionId = opencodeSessionId
500
+ promptGeneration += 1
457
501
 
458
- // Per-prompt state: a fresh stop intent and compaction flag each run.
459
- stopRequested = false
502
+ // Per-prompt state: a fresh stop generation unless a human interrupt was
503
+ // already delivered before this generator began iterating.
504
+ if (!signal.aborted) {
505
+ stopRequested = false
506
+ stopRequest = null
507
+ }
460
508
  let compactionOccurred = false
461
509
  const promptStart = now()
462
510
 
@@ -469,6 +517,20 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
469
517
  }
470
518
  }
471
519
 
520
+ // A durable interrupt can predate generator iteration. Do not submit a
521
+ // prompt merely to abort it; report the prompt-scoped cancellation after
522
+ // the stop belt has had a chance to settle.
523
+ if (signal.aborted) {
524
+ await requestStop()
525
+ yield {
526
+ kind: 'execution_complete',
527
+ messageId: prompt.messageId,
528
+ critical: true,
529
+ payload: { success: false, aborted: true },
530
+ }
531
+ return
532
+ }
533
+
472
534
  const opencodeMessageId = ascendingId('msg')
473
535
  const requestBody = buildPromptRequestBody(
474
536
  prompt.content,
@@ -542,6 +604,20 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
542
604
  return events
543
605
  }
544
606
 
607
+ // The vulnerable submission window begins before /event is opened and
608
+ // ends only when prompt_async settles. A stop anywhere in this window
609
+ // schedules an independent post-acceptance abort.
610
+ promptSubmissionPending = true
611
+ promptSubmissionSettled = new Promise<void>(resolve => {
612
+ resolvePromptSubmission = resolve
613
+ })
614
+ const settlePromptSubmission = (): void => {
615
+ promptSubmissionPending = false
616
+ resolvePromptSubmission?.()
617
+ resolvePromptSubmission = null
618
+ promptSubmissionSettled = null
619
+ }
620
+
545
621
  let sseResponse: Response
546
622
  try {
547
623
  sseResponse = await fetchImpl(`${base}/event`, {
@@ -549,10 +625,22 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
549
625
  signal,
550
626
  })
551
627
  } catch (error) {
552
- yield errorEvent(prompt.messageId, error)
628
+ settlePromptSubmission()
629
+ if (signal.aborted) {
630
+ await requestStop()
631
+ yield {
632
+ kind: 'execution_complete',
633
+ messageId: prompt.messageId,
634
+ critical: true,
635
+ payload: { success: false, aborted: true },
636
+ }
637
+ } else {
638
+ yield errorEvent(prompt.messageId, error)
639
+ }
553
640
  return
554
641
  }
555
642
  if (!sseResponse.ok || !sseResponse.body) {
643
+ settlePromptSubmission()
556
644
  // Cancel the body on the failure path too — a non-2xx response can still
557
645
  // carry an (unconsumed) body that would otherwise leak (P3-7).
558
646
  await cancelBody(sseResponse.body)
@@ -565,18 +653,22 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
565
653
  let errorText: string | null = null
566
654
  let terminalYielded = false
567
655
  try {
568
- const promptRes = await timedFetch(
569
- `${base}/session/${encodeURIComponent(sessionId)}/prompt_async`,
570
- {
571
- method: 'POST',
572
- headers: { 'Content-Type': 'application/json' },
573
- body: JSON.stringify(requestBody),
574
- }
575
- )
656
+ let promptRes: Response
657
+ try {
658
+ promptRes = await timedFetch(
659
+ `${base}/session/${encodeURIComponent(sessionId)}/prompt_async`,
660
+ {
661
+ method: 'POST',
662
+ headers: { 'Content-Type': 'application/json' },
663
+ body: JSON.stringify(requestBody),
664
+ }
665
+ )
666
+ } finally {
667
+ settlePromptSubmission()
668
+ }
576
669
  if (promptRes.status !== 200 && promptRes.status !== 204) {
577
670
  throw new Error(`Async prompt failed (${promptRes.status})`)
578
671
  }
579
-
580
672
  for await (const event of parseSseEvents(sseBody, signal, inactivityMs)) {
581
673
  // Wall-clock max-duration guard (P3-1): a stream that stays busy (or
582
674
  // heartbeats) forever never trips the inactivity deadline, so bound it
@@ -747,16 +839,23 @@ export function createOpenCodeHarness(options: OpenCodeHarnessOptions): AgentHar
747
839
  },
748
840
 
749
841
  async stop(): Promise<void> {
750
- // Mark intent so the resulting idle terminal is reported as cancelled, not
751
- // succeeded (P2-2), then best-effort ask OpenCode to abort.
842
+ // Mark intent so the resulting idle terminal is reported as cancelled,
843
+ // not succeeded (P2-2), then best-effort ask OpenCode to abort.
752
844
  stopRequested = true
753
845
  await requestStop()
754
846
  },
755
847
 
756
848
  async shutdown(): Promise<void> {
849
+ if (process.env.NODE_ENV === 'test' &&
850
+ process.env.ORIZU_HOSTED_TEST_HARNESS_SHUTDOWN_THROWS === '1') {
851
+ throw new Error('fixture harness shutdown failed')
852
+ }
757
853
  opencodeSessionId = null
758
854
  readyEmitted = false
759
855
  stopRequested = false
856
+ stopRequest = null
857
+ promptGeneration = 0
858
+ postAcceptanceAbortGeneration = -1
760
859
  },
761
860
  }
762
861
  }
@@ -971,15 +1070,12 @@ export interface OpenCodeConfigOptions {
971
1070
  }
972
1071
 
973
1072
  /**
974
- * Tools DENIED in a hosted headless run (ALI-1037). OpenCode exposes a `question`
975
- * permission key (docs/permissions) that gates the interactive "ask the user a
976
- * question" tool. In an unattended sandbox there is no human to answer it, and
977
- * OpenCode's only external reply endpoint — `POST /session/{id}/permissions/{permID}`
978
- * — takes a BOOLEAN allow/deny, so it cannot select one of the tool's multiple
979
- * options anyway. Denying the tool makes the model's ask fail fast (surfaced back
980
- * to it as a tool error) so it proceeds autonomously per the standing preamble
981
- * (HOSTED_TASK_PREAMBLE), instead of blocking the run forever. This is the
982
- * documented fallback path in ALI-1037 (answer-externally is not cleanly possible).
1073
+ * Tools denied for CLI-origin headless runs (ALI-1037). OpenCode 1.14.41 removes
1074
+ * a tool from the model toolset when its permission rule is `deny` on `*`; it does
1075
+ * not expose the tool and report a denial result. Hosted-web therefore overrides
1076
+ * `question` to `allow`, intercepts its measured running part, and quiesces the
1077
+ * turn while waiting for the human. CLI-origin runs retain this deny list because
1078
+ * no human reply flow exists there.
983
1079
  */
984
1080
  export const HEADLESS_DENIED_TOOLS = ['question'] as const
985
1081
 
@@ -991,6 +1087,12 @@ export function defaultHeadlessPermission(): Record<string, unknown> {
991
1087
  return permission
992
1088
  }
993
1089
 
1090
+ /** Select the OpenCode permission map for the session's human-input surface. */
1091
+ export function permissionForOrigin(origin?: 'hosted-web' | 'cli'): Record<string, unknown> {
1092
+ if (origin === 'hosted-web') return { ...defaultHeadlessPermission(), question: 'allow' }
1093
+ return defaultHeadlessPermission()
1094
+ }
1095
+
994
1096
  /**
995
1097
  * Build the `OPENCODE_CONFIG_CONTENT` payload OpenCode reads at boot (mirrors
996
1098
  * OpenInspect's `start_opencode`). Kept pure so the launch command and the
@@ -81,13 +81,16 @@ export const HARNESS_EVENT_KINDS = {
81
81
  egress_allowed: 'egress_allowed',
82
82
  // Durability + headless (ALI-1036 / ALI-1037). NOT produced by a harness — the
83
83
  // in-sandbox loop emits these through the SAME single-writer run-event sink:
84
- // the end-of-run auto-harvest result (work_persisted/work_none/work_persist_failed)
84
+ // the end-of-run auto-harvest result (persisted/none/not-inspected/failed)
85
85
  // and the headless question auto-handling record (question_auto_answered). They
86
86
  // are ordinary structural events (never terminal), appended like any other.
87
87
  work_persisted: 'work_persisted',
88
88
  work_none: 'work_none',
89
+ work_not_inspected: 'work_not_inspected',
89
90
  work_persist_failed: 'work_persist_failed',
90
91
  question_auto_answered: 'question_auto_answered',
92
+ question_pending: 'question_pending',
93
+ question_invalid: 'question_invalid',
91
94
  error: 'error',
92
95
  execution_complete: 'execution_complete',
93
96
  } as const