@kbediako/codex-orchestrator 0.1.38 → 0.2.1

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 (311) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +46 -317
  3. package/bin/codex-orchestrator.js +161 -0
  4. package/codex.orchestrator.json +149 -13
  5. package/dist/bin/codex-orchestrator.js +797 -1154
  6. package/dist/orchestrator/src/cli/adapters/CommandBuilder.js +50 -0
  7. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
  8. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
  9. package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
  10. package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +295 -11
  11. package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
  12. package/dist/orchestrator/src/cli/coStatusCliShell.js +451 -0
  13. package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
  14. package/dist/orchestrator/src/cli/codexCliShell.js +119 -0
  15. package/dist/orchestrator/src/cli/codexDefaultsSetup.js +265 -36
  16. package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
  17. package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
  18. package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
  19. package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
  20. package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
  21. package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
  22. package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
  23. package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
  24. package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
  25. package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
  26. package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
  27. package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
  28. package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
  29. package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
  30. package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
  31. package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
  32. package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
  33. package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
  34. package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
  35. package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
  36. package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
  37. package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
  38. package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
  39. package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
  40. package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
  41. package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
  42. package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
  43. package/dist/orchestrator/src/cli/control/controlHostSupervision.js +630 -0
  44. package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
  45. package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
  46. package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
  47. package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
  48. package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
  49. package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
  50. package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
  51. package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
  52. package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
  53. package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
  54. package/dist/orchestrator/src/cli/control/controlRuntime.js +1003 -0
  55. package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
  56. package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
  57. package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
  58. package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
  59. package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
  60. package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
  61. package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
  62. package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
  63. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
  64. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
  65. package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
  66. package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
  67. package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
  68. package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
  69. package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
  70. package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
  71. package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
  72. package/dist/orchestrator/src/cli/control/controlState.js +233 -2
  73. package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1904 -0
  74. package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
  75. package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
  76. package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
  77. package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
  78. package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
  79. package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
  80. package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
  81. package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
  82. package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
  83. package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
  84. package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
  85. package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
  86. package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
  87. package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
  88. package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
  89. package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
  90. package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
  91. package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
  92. package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
  93. package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
  94. package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
  95. package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
  96. package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
  97. package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
  98. package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
  99. package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
  100. package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
  101. package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
  102. package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
  103. package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
  104. package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
  105. package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
  106. package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
  107. package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
  108. package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
  109. package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
  110. package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
  111. package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
  112. package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
  113. package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
  114. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
  115. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
  116. package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
  117. package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
  118. package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
  119. package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
  120. package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
  121. package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
  122. package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
  123. package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
  124. package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
  125. package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1885 -0
  126. package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
  127. package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
  128. package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
  129. package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
  130. package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
  131. package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
  132. package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
  133. package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
  134. package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
  135. package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
  136. package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
  137. package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
  138. package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
  139. package/dist/orchestrator/src/cli/delegationServer.js +567 -678
  140. package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
  141. package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
  142. package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
  143. package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
  144. package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
  145. package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
  146. package/dist/orchestrator/src/cli/doctor.js +678 -164
  147. package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
  148. package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
  149. package/dist/orchestrator/src/cli/doctorUsage.js +119 -15
  150. package/dist/orchestrator/src/cli/exec/experience.js +16 -2
  151. package/dist/orchestrator/src/cli/exec/summary.js +3 -0
  152. package/dist/orchestrator/src/cli/execCliShell.js +51 -0
  153. package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
  154. package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
  155. package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
  156. package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
  157. package/dist/orchestrator/src/cli/init.js +95 -1
  158. package/dist/orchestrator/src/cli/initCliShell.js +50 -0
  159. package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
  160. package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
  161. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
  162. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
  163. package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
  164. package/dist/orchestrator/src/cli/planCliShell.js +19 -0
  165. package/dist/orchestrator/src/cli/prCliShell.js +41 -0
  166. package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
  167. package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1835 -0
  168. package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
  169. package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
  170. package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +6834 -0
  171. package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
  172. package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
  173. package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
  174. package/dist/orchestrator/src/cli/rlm/context.js +94 -7
  175. package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
  176. package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
  177. package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
  178. package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
  179. package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
  180. package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
  181. package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
  182. package/dist/orchestrator/src/cli/run/manifest.js +410 -73
  183. package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
  184. package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
  185. package/dist/orchestrator/src/cli/run/source0.js +690 -0
  186. package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
  187. package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
  188. package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
  189. package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
  190. package/dist/orchestrator/src/cli/services/commandRunner.js +698 -18
  191. package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
  192. package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
  193. package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
  194. package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
  195. package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
  196. package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
  197. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
  198. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
  199. package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
  200. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
  201. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
  202. package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
  203. package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
  204. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
  205. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
  206. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
  207. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
  208. package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
  209. package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
  210. package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
  211. package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
  212. package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
  213. package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
  214. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
  215. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
  216. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
  217. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
  218. package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
  219. package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
  220. package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
  221. package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
  222. package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
  223. package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
  224. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
  225. package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
  226. package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
  227. package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
  228. package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
  229. package/dist/orchestrator/src/cli/startCliShell.js +68 -0
  230. package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
  231. package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
  232. package/dist/orchestrator/src/cli/utils/cloudPreflight.js +285 -7
  233. package/dist/orchestrator/src/cli/utils/codexFeatures.js +60 -0
  234. package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
  235. package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
  236. package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
  237. package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
  238. package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
  239. package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
  240. package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
  241. package/dist/orchestrator/src/learning/crystalizer.js +2 -2
  242. package/dist/orchestrator/src/manager.js +74 -4
  243. package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
  244. package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
  245. package/dist/orchestrator/src/persistence/lockFile.js +70 -4
  246. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
  247. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
  248. package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
  249. package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
  250. package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
  251. package/dist/packages/sdk-node/src/orchestrator.js +137 -13
  252. package/dist/packages/shared/config/designConfig.js +8 -1
  253. package/dist/packages/shared/streams/stdio.js +1 -1
  254. package/dist/scripts/design/pipeline/permit.js +15 -0
  255. package/dist/scripts/lib/docs-catalog.js +399 -0
  256. package/dist/scripts/lib/docs-helpers.js +87 -5
  257. package/dist/scripts/lib/pr-watch-merge.js +1088 -80
  258. package/dist/scripts/lib/provider-run-contract.js +26 -0
  259. package/dist/scripts/lib/review-command-intent-classification.js +532 -0
  260. package/dist/scripts/lib/review-command-probe-classification.js +385 -0
  261. package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
  262. package/dist/scripts/lib/review-execution-runtime.js +753 -0
  263. package/dist/scripts/lib/review-execution-state.js +1144 -0
  264. package/dist/scripts/lib/review-execution-telemetry.js +215 -0
  265. package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
  266. package/dist/scripts/lib/review-launch-attempt.js +601 -0
  267. package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
  268. package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
  269. package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
  270. package/dist/scripts/lib/review-prompt-context.js +376 -0
  271. package/dist/scripts/lib/review-scope-advisory.js +286 -0
  272. package/dist/scripts/lib/review-scope-paths.js +123 -0
  273. package/dist/scripts/lib/review-shell-command-parser.js +389 -0
  274. package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
  275. package/dist/scripts/lib/run-manifests.js +192 -36
  276. package/dist/scripts/lib/spark-policy-classifier.js +593 -0
  277. package/dist/scripts/run-review.js +507 -1777
  278. package/docs/README.md +43 -20
  279. package/docs/book/README.md +19 -0
  280. package/docs/book/codex-cli-0124-adoption.md +68 -0
  281. package/docs/book/local-hook-impact.md +73 -0
  282. package/docs/book/operations.md +60 -0
  283. package/docs/book/public-posture.md +34 -0
  284. package/docs/book/setup.md +91 -0
  285. package/docs/book/skills.md +11 -0
  286. package/docs/guides/codex-version-policy.md +104 -0
  287. package/docs/public/downstream-setup.md +113 -0
  288. package/docs/public/provider-onboarding.md +173 -0
  289. package/package.json +23 -10
  290. package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
  291. package/plugins/codex-orchestrator/.mcp.json +13 -0
  292. package/plugins/codex-orchestrator/launcher.mjs +361 -0
  293. package/schemas/manifest.json +411 -0
  294. package/skills/README.md +26 -0
  295. package/skills/collab-subagents-first/SKILL.md +1 -1
  296. package/skills/delegation-usage/DELEGATION_GUIDE.md +30 -12
  297. package/skills/delegation-usage/SKILL.md +25 -14
  298. package/skills/land/SKILL.md +77 -0
  299. package/skills/linear/SKILL.md +255 -0
  300. package/skills/release/SKILL.md +47 -3
  301. package/skills/standalone-review/SKILL.md +6 -1
  302. package/templates/README.md +4 -2
  303. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  304. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  305. package/templates/codex/.codex/config.toml +3 -4
  306. package/templates/codex/.codex/providers/README.md +13 -0
  307. package/templates/codex/.codex/providers/control.example.json +18 -0
  308. package/templates/codex/.codex/providers/provider.env.example +15 -0
  309. package/templates/codex/AGENTS.md +15 -8
  310. package/templates/codex/mcp-client.json +5 -1
  311. package/docs/assets/setup.gif +0 -0
@@ -0,0 +1,361 @@
1
+ import { realpathSync } from 'node:fs';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { basename, dirname, isAbsolute, relative, resolve, sep } from 'node:path';
4
+ import { logger } from '../../logger.js';
5
+ const CHILD_CONTROL_TIMEOUT_MS = 15_000;
6
+ const CSRF_HEADER = 'x-csrf-token';
7
+ const DELEGATION_TOKEN_HEADER = 'x-codex-delegation-token';
8
+ const DELEGATION_RUN_HEADER = 'x-codex-delegation-run-id';
9
+ const LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '::1']);
10
+ export function createQuestionChildResolutionAdapter(input) {
11
+ const adapter = {
12
+ readDelegationHeaders: (req) => readDelegationHeaders(req),
13
+ validateDelegation: (auth) => input.validateDelegationToken(auth.token, input.readParentRunId(), auth.childRunId),
14
+ resolveManifestPath: (rawPath) => resolveRunManifestPath(rawPath, input.allowedRunRoots, 'from_manifest_path'),
15
+ readManifest: (path) => readJsonFile(path),
16
+ resolveChildQuestion: async (record, outcome) => {
17
+ const resolution = resolveChildQuestionAction(record, outcome, input.expiryFallback);
18
+ if (!resolution) {
19
+ return;
20
+ }
21
+ const manifestPath = record.from_manifest_path ?? null;
22
+ if (!manifestPath) {
23
+ return;
24
+ }
25
+ const shouldResolve = await isChildAwaitingQuestion(manifestPath, input.allowedRunRoots);
26
+ if (!shouldResolve) {
27
+ return;
28
+ }
29
+ try {
30
+ await callChildControlEndpoint({
31
+ manifestPath,
32
+ payload: {
33
+ action: resolution.action,
34
+ requested_by: 'parent',
35
+ reason: resolution.reason
36
+ },
37
+ allowedRunRoots: input.allowedRunRoots,
38
+ allowedBindHosts: input.allowedBindHosts
39
+ });
40
+ }
41
+ catch (error) {
42
+ const message = error?.message ?? String(error);
43
+ logger.warn(`Failed to resolve child question: ${message}`);
44
+ await input.emitResolutionFallback({
45
+ question_id: record.question_id,
46
+ outcome,
47
+ action: resolution.action,
48
+ reason: resolution.reason,
49
+ non_fatal: true,
50
+ error: message
51
+ });
52
+ }
53
+ },
54
+ queueQuestionResolutions: (records) => {
55
+ for (const record of records) {
56
+ if (record.status === 'queued') {
57
+ continue;
58
+ }
59
+ void adapter.resolveChildQuestion(record, record.status).catch((error) => {
60
+ const message = error?.message ?? String(error);
61
+ logger.warn(`Failed to resolve child question: ${message}`);
62
+ void input.emitResolutionFallback({
63
+ question_id: record.question_id,
64
+ outcome: record.status,
65
+ action: 'unknown',
66
+ reason: 'resolution_enqueue_failed',
67
+ non_fatal: true,
68
+ error: message
69
+ });
70
+ });
71
+ }
72
+ }
73
+ };
74
+ return adapter;
75
+ }
76
+ export function readDelegationHeaders(req) {
77
+ const token = readHeaderValue(req.headers[DELEGATION_TOKEN_HEADER]);
78
+ const childRunId = readHeaderValue(req.headers[DELEGATION_RUN_HEADER]);
79
+ if (!token || !childRunId) {
80
+ return null;
81
+ }
82
+ return { token, childRunId };
83
+ }
84
+ export async function callChildControlEndpoint(input) {
85
+ input.assertCurrent?.();
86
+ const { baseUrl, token } = await loadControlEndpoint({
87
+ manifestPath: input.manifestPath,
88
+ allowedRunRoots: input.allowedRunRoots,
89
+ allowedBindHosts: input.allowedBindHosts
90
+ });
91
+ input.assertCurrent?.();
92
+ const url = new URL('/control/action', baseUrl);
93
+ const controller = new AbortController();
94
+ const timer = setTimeout(() => controller.abort(), CHILD_CONTROL_TIMEOUT_MS);
95
+ let staleAssertionError = null;
96
+ const currentCheckTimer = input.assertCurrent === undefined
97
+ ? null
98
+ : setInterval(() => {
99
+ try {
100
+ input.assertCurrent?.();
101
+ }
102
+ catch (error) {
103
+ staleAssertionError = error;
104
+ controller.abort();
105
+ }
106
+ }, 50);
107
+ let res;
108
+ try {
109
+ input.assertCurrent?.();
110
+ res = await fetch(url.toString(), {
111
+ method: 'POST',
112
+ headers: {
113
+ 'Content-Type': 'application/json',
114
+ Authorization: `Bearer ${token}`,
115
+ [CSRF_HEADER]: token
116
+ },
117
+ body: JSON.stringify(input.payload),
118
+ signal: controller.signal
119
+ });
120
+ input.assertCurrent?.();
121
+ }
122
+ catch (error) {
123
+ if (staleAssertionError) {
124
+ throw staleAssertionError;
125
+ }
126
+ if (error?.name === 'AbortError') {
127
+ throw new Error('child control request timeout');
128
+ }
129
+ throw error;
130
+ }
131
+ finally {
132
+ clearTimeout(timer);
133
+ if (currentCheckTimer !== null) {
134
+ clearInterval(currentCheckTimer);
135
+ }
136
+ }
137
+ input.assertCurrent?.();
138
+ if (!res.ok) {
139
+ const message = await res.text();
140
+ input.assertCurrent?.();
141
+ throw new Error(`child control error: ${res.status} ${message}`);
142
+ }
143
+ }
144
+ function resolveChildQuestionAction(record, outcome, defaultExpiryFallback) {
145
+ const autoPause = record.auto_pause ?? true;
146
+ if (!autoPause || !record.from_manifest_path) {
147
+ return null;
148
+ }
149
+ if (outcome === 'expired') {
150
+ const fallback = record.expiry_fallback ?? defaultExpiryFallback ?? 'pause';
151
+ if (fallback === 'pause') {
152
+ return { action: 'pause', reason: 'question_expired' };
153
+ }
154
+ return {
155
+ action: fallback === 'resume' ? 'resume' : 'fail',
156
+ reason: 'question_expired'
157
+ };
158
+ }
159
+ if (outcome === 'answered') {
160
+ return { action: 'resume', reason: 'question_answered' };
161
+ }
162
+ if (outcome === 'dismissed') {
163
+ return { action: 'resume', reason: 'question_dismissed' };
164
+ }
165
+ return null;
166
+ }
167
+ async function isChildAwaitingQuestion(manifestPath, allowedRunRoots) {
168
+ if (!manifestPath) {
169
+ return false;
170
+ }
171
+ try {
172
+ const resolvedManifest = resolveRunManifestPath(manifestPath, allowedRunRoots, 'from_manifest_path');
173
+ const controlPath = resolve(dirname(resolvedManifest), 'control.json');
174
+ const snapshot = await readJsonFile(controlPath);
175
+ const latest = snapshot?.latest_action;
176
+ if (!latest || latest.action !== 'pause') {
177
+ return false;
178
+ }
179
+ return latest.reason === 'awaiting_question_answer';
180
+ }
181
+ catch (error) {
182
+ if (error?.code !== 'ENOENT') {
183
+ logger.warn(`Failed to inspect child question state: ${error?.message ?? error}`);
184
+ }
185
+ return false;
186
+ }
187
+ }
188
+ async function loadControlEndpoint(input) {
189
+ const resolvedManifest = resolveRunManifestPath(input.manifestPath, input.allowedRunRoots, 'from_manifest_path');
190
+ const runDir = dirname(resolvedManifest);
191
+ const endpointPath = resolve(runDir, 'control_endpoint.json');
192
+ const raw = await readFile(endpointPath, 'utf8');
193
+ const endpointInfo = JSON.parse(raw);
194
+ const baseUrl = validateControlBaseUrl(endpointInfo.base_url, input.allowedBindHosts);
195
+ const tokenPath = resolveControlTokenPath(endpointInfo.token_path, runDir);
196
+ const token = await readControlToken(tokenPath);
197
+ return { baseUrl, token };
198
+ }
199
+ function validateControlBaseUrl(raw, allowedHosts) {
200
+ if (typeof raw !== 'string' || raw.trim().length === 0) {
201
+ throw new Error('control base_url missing');
202
+ }
203
+ let parsed;
204
+ try {
205
+ parsed = new URL(raw);
206
+ }
207
+ catch {
208
+ throw new Error('control base_url invalid');
209
+ }
210
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
211
+ throw new Error('control base_url invalid');
212
+ }
213
+ if (parsed.username || parsed.password) {
214
+ throw new Error('control base_url invalid');
215
+ }
216
+ const allowed = normalizeAllowedHosts(allowedHosts);
217
+ if (allowed.size > 0 && !allowed.has(parsed.hostname.toLowerCase())) {
218
+ throw new Error('control base_url not permitted');
219
+ }
220
+ return parsed;
221
+ }
222
+ function normalizeAllowedHosts(allowedHosts) {
223
+ const values = allowedHosts && allowedHosts.length > 0 ? allowedHosts : Array.from(LOOPBACK_HOSTS);
224
+ return new Set(values.map((entry) => entry.toLowerCase()));
225
+ }
226
+ function resolveControlTokenPath(tokenPath, runDir) {
227
+ const fallback = resolve(runDir, 'control_auth.json');
228
+ const raw = typeof tokenPath === 'string' ? tokenPath.trim() : '';
229
+ const resolved = raw ? resolve(runDir, raw) : fallback;
230
+ if (!isPathWithinRoots(resolved, [runDir])) {
231
+ throw new Error('control auth path invalid');
232
+ }
233
+ return resolved;
234
+ }
235
+ async function readControlToken(tokenPath) {
236
+ const tokenRaw = await readFile(tokenPath, 'utf8');
237
+ const parsedToken = safeJsonParse(tokenRaw);
238
+ const tokenValue = parsedToken && typeof parsedToken === 'object' && !Array.isArray(parsedToken)
239
+ ? parsedToken.token
240
+ : null;
241
+ const token = typeof tokenValue === 'string' && tokenValue.trim().length > 0
242
+ ? tokenValue.trim()
243
+ : tokenRaw.trim();
244
+ if (!token) {
245
+ throw new Error('control auth token missing');
246
+ }
247
+ return token;
248
+ }
249
+ function resolveRunManifestPath(rawPath, allowedRoots, label) {
250
+ const resolved = resolve(rawPath);
251
+ const canonicalPath = realpathSafe(resolved);
252
+ assertRunManifestPath(canonicalPath, label);
253
+ if (!isPathWithinRoots(canonicalPath, allowedRoots)) {
254
+ throw new Error(`${label} not permitted`);
255
+ }
256
+ return canonicalPath;
257
+ }
258
+ function assertRunManifestPath(pathname, label) {
259
+ const resolvedPath = resolve(pathname);
260
+ if (basename(resolvedPath) !== 'manifest.json') {
261
+ throw new Error(`${label} invalid`);
262
+ }
263
+ const runDir = dirname(resolvedPath);
264
+ const cliDir = dirname(runDir);
265
+ if (basename(cliDir) !== 'cli') {
266
+ throw new Error(`${label} invalid`);
267
+ }
268
+ const taskDir = dirname(cliDir);
269
+ if (!basename(runDir) || !basename(taskDir)) {
270
+ throw new Error(`${label} invalid`);
271
+ }
272
+ }
273
+ function isPathWithinRoots(pathname, roots) {
274
+ const resolved = normalizePath(realpathSafe(pathname));
275
+ return roots.some((root) => {
276
+ const resolvedRoot = normalizePath(realpathSafe(root));
277
+ if (resolvedRoot === resolved) {
278
+ return true;
279
+ }
280
+ const relativePath = relative(resolvedRoot, resolved);
281
+ if (!relativePath) {
282
+ return true;
283
+ }
284
+ if (isAbsolute(relativePath)) {
285
+ return false;
286
+ }
287
+ return !relativePath.startsWith(`..${sep}`) && relativePath !== '..';
288
+ });
289
+ }
290
+ function realpathSafe(pathname) {
291
+ try {
292
+ return realpathSync(pathname);
293
+ }
294
+ catch {
295
+ return resolve(pathname);
296
+ }
297
+ }
298
+ function normalizePath(pathname) {
299
+ return process.platform === 'win32' ? pathname.toLowerCase() : pathname;
300
+ }
301
+ async function readJsonFile(path) {
302
+ try {
303
+ const raw = await readFile(path, 'utf8');
304
+ return JSON.parse(raw);
305
+ }
306
+ catch (error) {
307
+ if (error.code === 'ENOENT') {
308
+ return null;
309
+ }
310
+ logger.warn(`Failed to read JSON file ${path}: ${error?.message ?? error}`);
311
+ return null;
312
+ }
313
+ }
314
+ function safeJsonParse(text) {
315
+ try {
316
+ return JSON.parse(text);
317
+ }
318
+ catch {
319
+ return null;
320
+ }
321
+ }
322
+ function readHeaderValue(value) {
323
+ if (Array.isArray(value)) {
324
+ const values = [];
325
+ for (const entry of value) {
326
+ if (typeof entry !== 'string') {
327
+ continue;
328
+ }
329
+ const parts = entry.split(',');
330
+ for (const part of parts) {
331
+ const trimmed = part.trim();
332
+ if (trimmed) {
333
+ values.push(trimmed);
334
+ }
335
+ }
336
+ }
337
+ return readUniqueHeaderValue(values);
338
+ }
339
+ if (typeof value === 'string') {
340
+ const parts = value.split(',');
341
+ const values = [];
342
+ for (const part of parts) {
343
+ const trimmed = part.trim();
344
+ if (trimmed) {
345
+ values.push(trimmed);
346
+ }
347
+ }
348
+ return readUniqueHeaderValue(values);
349
+ }
350
+ return null;
351
+ }
352
+ function readUniqueHeaderValue(values) {
353
+ if (values.length === 0) {
354
+ return null;
355
+ }
356
+ const unique = new Set(values);
357
+ if (unique.size > 1) {
358
+ return null;
359
+ }
360
+ return values[0];
361
+ }
@@ -0,0 +1,181 @@
1
+ import { runQuestionReadSequence } from './questionReadSequence.js';
2
+ export async function handleQuestionQueueRequest(context) {
3
+ const method = context.req.method ?? 'GET';
4
+ const pathname = new URL(context.req.url ?? '/', 'http://localhost').pathname;
5
+ if (pathname === '/questions' && method === 'GET') {
6
+ const result = await runQuestionReadSequence({
7
+ listQuestions: () => context.questionQueue.list(),
8
+ expireQuestions: () => context.expireQuestions()
9
+ });
10
+ context.queueQuestionResolutions(result.retryCandidates);
11
+ writeQuestionResponse(context.res, 200, { questions: result.questions });
12
+ return true;
13
+ }
14
+ if (pathname === '/questions/enqueue' && method === 'POST') {
15
+ const delegationAuth = context.readDelegationHeaders();
16
+ if (!delegationAuth || !context.validateDelegation(delegationAuth)) {
17
+ writeQuestionResponse(context.res, 403, { error: 'delegation_token_invalid' });
18
+ return true;
19
+ }
20
+ const body = await context.readRequestBody();
21
+ const prompt = readStringValue(body, 'prompt');
22
+ if (!prompt) {
23
+ writeQuestionResponse(context.res, 400, { error: 'missing_prompt' });
24
+ return true;
25
+ }
26
+ const autoPause = readBooleanValue(body, 'auto_pause', 'autoPause') ?? true;
27
+ const expiryFallback = parseExpiryFallback(readStringValue(body, 'expiry_fallback', 'expiryFallback'));
28
+ const rawFromManifest = readStringValue(body, 'from_manifest_path', 'fromManifestPath');
29
+ let resolvedFromManifest = null;
30
+ if (rawFromManifest) {
31
+ try {
32
+ resolvedFromManifest = context.resolveManifestPath(rawFromManifest);
33
+ }
34
+ catch {
35
+ writeQuestionResponse(context.res, 400, { error: 'invalid_manifest_path' });
36
+ return true;
37
+ }
38
+ const manifest = await context.readManifest(resolvedFromManifest);
39
+ if (!manifest || manifest.run_id !== delegationAuth.childRunId) {
40
+ writeQuestionResponse(context.res, 403, { error: 'delegation_run_mismatch' });
41
+ return true;
42
+ }
43
+ }
44
+ const record = context.questionQueue.enqueue({
45
+ parentRunId: context.getParentRunId(),
46
+ fromRunId: delegationAuth.childRunId,
47
+ fromManifestPath: resolvedFromManifest ?? null,
48
+ prompt,
49
+ urgency: parseUrgency(readStringValue(body, 'urgency')),
50
+ expiresInMs: readNumberValue(body, 'expires_in_ms', 'expiresInMs'),
51
+ autoPause,
52
+ expiryFallback
53
+ });
54
+ await context.persistQuestions();
55
+ await context.emitQuestionQueued(record);
56
+ context.publishRuntime('questions.enqueue');
57
+ writeQuestionResponse(context.res, 200, record);
58
+ return true;
59
+ }
60
+ if (pathname === '/questions/answer' && method === 'POST') {
61
+ const body = await context.readRequestBody();
62
+ const questionId = readStringValue(body, 'question_id', 'questionId');
63
+ const answer = readStringValue(body, 'answer');
64
+ if (!questionId || !answer) {
65
+ writeQuestionResponse(context.res, 400, { error: 'missing_question_or_answer' });
66
+ return true;
67
+ }
68
+ try {
69
+ context.questionQueue.answer(questionId, answer, readStringValue(body, 'answered_by', 'answeredBy') ?? 'user');
70
+ }
71
+ catch (error) {
72
+ const message = error?.message ?? 'question_invalid';
73
+ writeQuestionResponse(context.res, message === 'question_not_found' ? 404 : 409, { error: message });
74
+ return true;
75
+ }
76
+ await context.persistQuestions();
77
+ const record = context.questionQueue.get(questionId);
78
+ if (record) {
79
+ await context.emitQuestionAnswered(record);
80
+ await context.resolveChildQuestion(record, record.status);
81
+ }
82
+ context.publishRuntime('questions.answer');
83
+ writeQuestionResponse(context.res, 200, { status: 'answered' });
84
+ return true;
85
+ }
86
+ if (pathname === '/questions/dismiss' && method === 'POST') {
87
+ const body = await context.readRequestBody();
88
+ const questionId = readStringValue(body, 'question_id', 'questionId');
89
+ if (!questionId) {
90
+ writeQuestionResponse(context.res, 400, { error: 'missing_question_id' });
91
+ return true;
92
+ }
93
+ try {
94
+ context.questionQueue.dismiss(questionId, readStringValue(body, 'dismissed_by', 'dismissedBy') ?? 'user');
95
+ }
96
+ catch (error) {
97
+ const message = error?.message ?? 'question_invalid';
98
+ writeQuestionResponse(context.res, message === 'question_not_found' ? 404 : 409, { error: message });
99
+ return true;
100
+ }
101
+ await context.persistQuestions();
102
+ const record = context.questionQueue.get(questionId);
103
+ if (record) {
104
+ await context.emitQuestionDismissed(record);
105
+ await context.resolveChildQuestion(record, record.status);
106
+ }
107
+ context.publishRuntime('questions.dismiss');
108
+ writeQuestionResponse(context.res, 200, { status: 'dismissed' });
109
+ return true;
110
+ }
111
+ if (pathname.startsWith('/questions/') && method === 'GET') {
112
+ await context.expireQuestions();
113
+ const delegationAuth = context.readDelegationHeaders();
114
+ if (delegationAuth && !context.validateDelegation(delegationAuth)) {
115
+ writeQuestionResponse(context.res, 403, { error: 'delegation_token_invalid' });
116
+ return true;
117
+ }
118
+ const questionId = pathname.split('/').pop();
119
+ const record = questionId ? context.questionQueue.get(questionId) : null;
120
+ if (!record) {
121
+ writeQuestionResponse(context.res, 404, { error: 'not_found' });
122
+ return true;
123
+ }
124
+ if (delegationAuth && record.from_run_id !== delegationAuth.childRunId) {
125
+ writeQuestionResponse(context.res, 403, { error: 'delegation_scope_mismatch' });
126
+ return true;
127
+ }
128
+ writeQuestionResponse(context.res, 200, record);
129
+ return true;
130
+ }
131
+ return false;
132
+ }
133
+ function writeQuestionResponse(res, status, body) {
134
+ res.writeHead(status, { 'Content-Type': 'application/json' });
135
+ res.end(JSON.stringify(body));
136
+ }
137
+ function readStringValue(record, ...keys) {
138
+ for (const key of keys) {
139
+ const value = record[key];
140
+ if (typeof value === 'string' && value.trim().length > 0) {
141
+ return value.trim();
142
+ }
143
+ }
144
+ return undefined;
145
+ }
146
+ function readNumberValue(record, ...keys) {
147
+ for (const key of keys) {
148
+ const value = record[key];
149
+ if (typeof value === 'number' && Number.isFinite(value)) {
150
+ return value;
151
+ }
152
+ if (typeof value === 'string' && value.trim().length > 0) {
153
+ const parsed = Number(value);
154
+ if (Number.isFinite(parsed)) {
155
+ return parsed;
156
+ }
157
+ }
158
+ }
159
+ return undefined;
160
+ }
161
+ function readBooleanValue(record, ...keys) {
162
+ for (const key of keys) {
163
+ const value = record[key];
164
+ if (typeof value === 'boolean') {
165
+ return value;
166
+ }
167
+ }
168
+ return undefined;
169
+ }
170
+ function parseUrgency(value) {
171
+ if (value === 'low' || value === 'med' || value === 'high') {
172
+ return value;
173
+ }
174
+ return 'med';
175
+ }
176
+ function parseExpiryFallback(value) {
177
+ if (value === 'pause' || value === 'resume' || value === 'fail') {
178
+ return value;
179
+ }
180
+ return undefined;
181
+ }
@@ -0,0 +1,9 @@
1
+ export function createQuestionReadRetrySelector(beforeExpiry) {
2
+ const statusBeforeRead = new Map(beforeExpiry.map((record) => [record.question_id, record.status]));
3
+ return (afterExpiry) => afterExpiry.filter((record) => {
4
+ if (record.status === 'queued') {
5
+ return false;
6
+ }
7
+ return !(statusBeforeRead.get(record.question_id) === 'queued' && record.status === 'expired');
8
+ });
9
+ }
@@ -0,0 +1,10 @@
1
+ import { createQuestionReadRetrySelector } from './questionReadRetryDeduplication.js';
2
+ export async function runQuestionReadSequence(context) {
3
+ const selectRetryCandidates = createQuestionReadRetrySelector(context.listQuestions());
4
+ await context.expireQuestions();
5
+ const questions = context.listQuestions();
6
+ return {
7
+ questions,
8
+ retryCandidates: selectRetryCandidates(questions)
9
+ };
10
+ }
@@ -0,0 +1,27 @@
1
+ export async function handleSecurityViolationRequest(context) {
2
+ const method = context.req.method ?? 'GET';
3
+ const pathname = new URL(context.req.url ?? '/', 'http://localhost').pathname;
4
+ if (pathname !== '/security/violation' || method !== 'POST') {
5
+ return false;
6
+ }
7
+ const body = await context.readRequestBody();
8
+ await context.emitSecurityViolation({
9
+ kind: readStringValue(body, 'kind') ?? 'unknown',
10
+ summary: readStringValue(body, 'summary') ?? 'security_violation',
11
+ severity: readStringValue(body, 'severity') ?? 'high',
12
+ related_request_id: readStringValue(body, 'related_request_id', 'relatedRequestId') ?? null,
13
+ details_redacted: true
14
+ });
15
+ context.res.writeHead(200, { 'Content-Type': 'application/json' });
16
+ context.res.end(JSON.stringify({ status: 'recorded' }));
17
+ return true;
18
+ }
19
+ function readStringValue(record, ...keys) {
20
+ for (const key of keys) {
21
+ const value = record[key];
22
+ if (typeof value === 'string' && value.trim().length > 0) {
23
+ return value.trim();
24
+ }
25
+ }
26
+ return undefined;
27
+ }