@kbediako/codex-orchestrator 0.1.37 → 0.2.0

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 (302) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +73 -291
  3. package/bin/codex-orchestrator.js +161 -0
  4. package/codex.orchestrator.json +149 -13
  5. package/dist/bin/codex-orchestrator.js +795 -1154
  6. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
  7. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
  8. package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
  9. package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +183 -11
  10. package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
  11. package/dist/orchestrator/src/cli/coStatusCliShell.js +429 -0
  12. package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
  13. package/dist/orchestrator/src/cli/codexCliShell.js +72 -0
  14. package/dist/orchestrator/src/cli/codexDefaultsSetup.js +49 -11
  15. package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
  16. package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
  17. package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
  18. package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
  19. package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
  20. package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
  21. package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
  22. package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
  23. package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
  24. package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
  25. package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
  26. package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
  27. package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
  28. package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
  29. package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
  30. package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
  31. package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
  32. package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
  33. package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
  34. package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
  35. package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
  36. package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
  37. package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
  38. package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
  39. package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
  40. package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
  41. package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
  42. package/dist/orchestrator/src/cli/control/controlHostSupervision.js +608 -0
  43. package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
  44. package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
  45. package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
  46. package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
  47. package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
  48. package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
  49. package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
  50. package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
  51. package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
  52. package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
  53. package/dist/orchestrator/src/cli/control/controlRuntime.js +992 -0
  54. package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
  55. package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
  56. package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
  57. package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
  58. package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
  59. package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
  60. package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
  61. package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
  62. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
  63. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
  64. package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
  65. package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
  66. package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
  67. package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
  68. package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
  69. package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
  70. package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
  71. package/dist/orchestrator/src/cli/control/controlState.js +233 -2
  72. package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1899 -0
  73. package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
  74. package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
  75. package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
  76. package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
  77. package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
  78. package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
  79. package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
  80. package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
  81. package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
  82. package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
  83. package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
  84. package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
  85. package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
  86. package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
  87. package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
  88. package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
  89. package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
  90. package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
  91. package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
  92. package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
  93. package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
  94. package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
  95. package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
  96. package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
  97. package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
  98. package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
  99. package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
  100. package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
  101. package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
  102. package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
  103. package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
  104. package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
  105. package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
  106. package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
  107. package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
  108. package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
  109. package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
  110. package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
  111. package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
  112. package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
  113. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
  114. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
  115. package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
  116. package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
  117. package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
  118. package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
  119. package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
  120. package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
  121. package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
  122. package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
  123. package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
  124. package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1838 -0
  125. package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
  126. package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
  127. package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
  128. package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
  129. package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
  130. package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
  131. package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
  132. package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
  133. package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
  134. package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
  135. package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
  136. package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
  137. package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
  138. package/dist/orchestrator/src/cli/delegationServer.js +567 -678
  139. package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
  140. package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
  141. package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
  142. package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
  143. package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
  144. package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
  145. package/dist/orchestrator/src/cli/doctor.js +542 -122
  146. package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
  147. package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
  148. package/dist/orchestrator/src/cli/doctorUsage.js +136 -16
  149. package/dist/orchestrator/src/cli/exec/experience.js +16 -2
  150. package/dist/orchestrator/src/cli/exec/summary.js +3 -0
  151. package/dist/orchestrator/src/cli/execCliShell.js +51 -0
  152. package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
  153. package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
  154. package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
  155. package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
  156. package/dist/orchestrator/src/cli/init.js +1 -0
  157. package/dist/orchestrator/src/cli/initCliShell.js +50 -0
  158. package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
  159. package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
  160. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
  161. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
  162. package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
  163. package/dist/orchestrator/src/cli/planCliShell.js +19 -0
  164. package/dist/orchestrator/src/cli/prCliShell.js +41 -0
  165. package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
  166. package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1772 -0
  167. package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
  168. package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
  169. package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +5738 -0
  170. package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
  171. package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
  172. package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
  173. package/dist/orchestrator/src/cli/rlm/context.js +94 -7
  174. package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
  175. package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
  176. package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
  177. package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
  178. package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
  179. package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
  180. package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
  181. package/dist/orchestrator/src/cli/run/manifest.js +410 -73
  182. package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
  183. package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
  184. package/dist/orchestrator/src/cli/run/source0.js +690 -0
  185. package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
  186. package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
  187. package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
  188. package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
  189. package/dist/orchestrator/src/cli/services/commandRunner.js +668 -18
  190. package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
  191. package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
  192. package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
  193. package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
  194. package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
  195. package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
  196. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
  197. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
  198. package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
  199. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
  200. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
  201. package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
  202. package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
  203. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
  204. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
  205. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
  206. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
  207. package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
  208. package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
  209. package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
  210. package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
  211. package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
  212. package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
  213. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
  214. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
  215. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
  216. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
  217. package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
  218. package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
  219. package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
  220. package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
  221. package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
  222. package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
  223. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
  224. package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
  225. package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
  226. package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
  227. package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
  228. package/dist/orchestrator/src/cli/startCliShell.js +68 -0
  229. package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
  230. package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
  231. package/dist/orchestrator/src/cli/utils/cloudPreflight.js +83 -1
  232. package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
  233. package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
  234. package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
  235. package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
  236. package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
  237. package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
  238. package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
  239. package/dist/orchestrator/src/learning/crystalizer.js +2 -2
  240. package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
  241. package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
  242. package/dist/orchestrator/src/persistence/lockFile.js +70 -4
  243. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
  244. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
  245. package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
  246. package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
  247. package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
  248. package/dist/packages/sdk-node/src/orchestrator.js +137 -13
  249. package/dist/packages/shared/config/designConfig.js +8 -1
  250. package/dist/packages/shared/streams/stdio.js +1 -1
  251. package/dist/scripts/design/pipeline/permit.js +15 -0
  252. package/dist/scripts/lib/docs-catalog.js +365 -0
  253. package/dist/scripts/lib/docs-helpers.js +87 -5
  254. package/dist/scripts/lib/pr-watch-merge.js +1088 -80
  255. package/dist/scripts/lib/provider-run-contract.js +26 -0
  256. package/dist/scripts/lib/review-command-intent-classification.js +532 -0
  257. package/dist/scripts/lib/review-command-probe-classification.js +385 -0
  258. package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
  259. package/dist/scripts/lib/review-execution-runtime.js +753 -0
  260. package/dist/scripts/lib/review-execution-state.js +1144 -0
  261. package/dist/scripts/lib/review-execution-telemetry.js +215 -0
  262. package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
  263. package/dist/scripts/lib/review-launch-attempt.js +601 -0
  264. package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
  265. package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
  266. package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
  267. package/dist/scripts/lib/review-prompt-context.js +376 -0
  268. package/dist/scripts/lib/review-scope-advisory.js +286 -0
  269. package/dist/scripts/lib/review-scope-paths.js +123 -0
  270. package/dist/scripts/lib/review-shell-command-parser.js +389 -0
  271. package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
  272. package/dist/scripts/lib/run-manifests.js +192 -36
  273. package/dist/scripts/lib/spark-policy-classifier.js +593 -0
  274. package/dist/scripts/run-review.js +507 -1777
  275. package/docs/public/downstream-setup.md +106 -0
  276. package/docs/public/provider-onboarding.md +173 -0
  277. package/package.json +30 -11
  278. package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
  279. package/plugins/codex-orchestrator/.mcp.json +13 -0
  280. package/plugins/codex-orchestrator/launcher.mjs +359 -0
  281. package/schemas/manifest.json +395 -0
  282. package/skills/chrome-devtools/SKILL.md +1 -1
  283. package/skills/codex-orchestrator/SKILL.md +83 -0
  284. package/skills/collab-subagents-first/SKILL.md +2 -1
  285. package/skills/delegation-usage/DELEGATION_GUIDE.md +24 -11
  286. package/skills/delegation-usage/SKILL.md +20 -13
  287. package/skills/land/SKILL.md +77 -0
  288. package/skills/linear/SKILL.md +255 -0
  289. package/skills/release/SKILL.md +47 -3
  290. package/skills/standalone-review/SKILL.md +6 -1
  291. package/templates/README.md +4 -2
  292. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  293. package/templates/codex/.codex/agents/explorer-fast.toml +1 -0
  294. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  295. package/templates/codex/.codex/config.toml +3 -4
  296. package/templates/codex/.codex/providers/README.md +13 -0
  297. package/templates/codex/.codex/providers/control.example.json +18 -0
  298. package/templates/codex/.codex/providers/provider.env.example +15 -0
  299. package/templates/codex/AGENTS.md +12 -7
  300. package/templates/codex/mcp-client.json +5 -1
  301. package/docs/README.md +0 -307
  302. package/docs/assets/setup.gif +0 -0
@@ -7,20 +7,19 @@ import { resolveCodexHome } from './utils/codexPaths.js';
7
7
  import { findPackageRoot } from './utils/packageInfo.js';
8
8
  import { writeAtomicFile } from '../utils/atomicWrite.js';
9
9
  const require = createRequire(import.meta.url);
10
- const toml = require('@iarna/toml');
11
- const canonicalize = require('canonicalize');
12
- export const BASELINE_MODEL = 'gpt-5.3-codex';
10
+ let tomlLibrary;
11
+ export const BASELINE_MODEL = 'gpt-5.4';
12
+ export const BASELINE_REVIEW_MODEL = BASELINE_MODEL;
13
13
  export const BASELINE_REASONING = 'xhigh';
14
14
  export const BASELINE_REASONING_MINIMUM = 'high';
15
15
  export const BASELINE_AGENTS = {
16
16
  max_threads: 12,
17
- max_depth: 4,
18
- max_spawn_depth: 4
17
+ max_depth: 4
19
18
  };
20
19
  const ROLE_DEFINITIONS = [
21
20
  {
22
21
  key: 'explorer_fast',
23
- description: 'Fast explorer (spark text-only).',
22
+ description: 'Fast explorer (spark file/codebase search only).',
24
23
  fileName: 'explorer-fast.toml',
25
24
  configFile: './agents/explorer-fast.toml',
26
25
  templatePath: join('templates', 'codex', '.codex', 'agents', 'explorer-fast.toml')
@@ -48,7 +47,7 @@ export async function runCodexDefaultsSetup(options = {}) {
48
47
  const roleDefinitions = await loadRoleDefinitions();
49
48
  const configState = await loadConfigState(plan.configPath);
50
49
  const nextConfig = mergeBaselineDefaults(configState.parsed, roleDefinitions);
51
- const configChanged = canonicalize(configState.parsed) !== canonicalize(nextConfig);
50
+ const configChanged = canonicalizeConfigValue(configState.parsed) !== canonicalizeConfigValue(nextConfig);
52
51
  const roleChanges = await planRoleChanges(plan.agentsDir, force, roleDefinitions);
53
52
  if (!apply) {
54
53
  const changes = buildPlannedChanges({
@@ -65,7 +64,7 @@ export async function runCodexDefaultsSetup(options = {}) {
65
64
  }
66
65
  const changes = [];
67
66
  if (configChanged || !configState.exists) {
68
- const rendered = `${toml.stringify(nextConfig)}\n`;
67
+ const rendered = `${getTomlLibrary().stringify(nextConfig)}\n`;
69
68
  await writeAtomicFile(plan.configPath, rendered, { ensureDir: true, encoding: 'utf8' });
70
69
  changes.push({
71
70
  target: 'config',
@@ -152,7 +151,7 @@ async function loadConfigState(configPath) {
152
151
  }
153
152
  const raw = await readFile(configPath, 'utf8');
154
153
  try {
155
- const parsed = toml.parse(raw);
154
+ const parsed = getTomlLibrary().parse(raw);
156
155
  if (!isRecord(parsed)) {
157
156
  throw new Error('top-level TOML document must be a table.');
158
157
  }
@@ -163,14 +162,53 @@ async function loadConfigState(configPath) {
163
162
  throw new Error(`Failed to parse Codex config TOML at ${configPath}: ${reason}`);
164
163
  }
165
164
  }
165
+ function getTomlLibrary() {
166
+ if (tomlLibrary) {
167
+ return tomlLibrary;
168
+ }
169
+ if (tomlLibrary === null) {
170
+ throw new Error('Failed to load @iarna/toml.');
171
+ }
172
+ try {
173
+ tomlLibrary = require('@iarna/toml');
174
+ return tomlLibrary;
175
+ }
176
+ catch (error) {
177
+ tomlLibrary = null;
178
+ throw error;
179
+ }
180
+ }
181
+ function canonicalizeConfigValue(value) {
182
+ if (value === null) {
183
+ return 'null';
184
+ }
185
+ if (typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string') {
186
+ return JSON.stringify(value);
187
+ }
188
+ if (Array.isArray(value)) {
189
+ return `[${value.map((entry) => canonicalizeConfigValue(entry) ?? 'null').join(',')}]`;
190
+ }
191
+ if (value && typeof value === 'object') {
192
+ const entries = Object.entries(value)
193
+ .sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
194
+ .flatMap(([key, entry]) => {
195
+ const canonicalEntry = canonicalizeConfigValue(entry);
196
+ if (typeof canonicalEntry === 'undefined') {
197
+ return [];
198
+ }
199
+ return [`${JSON.stringify(key)}:${canonicalEntry}`];
200
+ });
201
+ return `{${entries.join(',')}}`;
202
+ }
203
+ return undefined;
204
+ }
166
205
  function mergeBaselineDefaults(existing, roleDefinitions) {
167
206
  const next = structuredClone(existing);
168
207
  next.model = BASELINE_MODEL;
208
+ next.review_model = BASELINE_REVIEW_MODEL;
169
209
  next.model_reasoning_effort = BASELINE_REASONING;
170
210
  const agents = isRecord(next.agents) ? structuredClone(next.agents) : {};
171
211
  agents.max_threads = BASELINE_AGENTS.max_threads;
172
- agents.max_depth = BASELINE_AGENTS.max_depth;
173
- agents.max_spawn_depth = BASELINE_AGENTS.max_spawn_depth;
174
212
  for (const role of roleDefinitions) {
175
213
  const existingRole = isRecord(agents[role.key])
176
214
  ? structuredClone(agents[role.key])
@@ -5,7 +5,7 @@ import { homedir } from 'node:os';
5
5
  import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
6
6
  import { logger } from '../../logger.js';
7
7
  const require = createRequire(import.meta.url);
8
- const toml = require('@iarna/toml');
8
+ let tomlParser;
9
9
  const DEFAULT_ALLOWED_RUN_ROOTS = [];
10
10
  const DEFAULT_CONFIG = {
11
11
  delegate: {
@@ -60,6 +60,16 @@ const SOURCE_PRIORITY = {
60
60
  env: 3,
61
61
  cli: 4
62
62
  };
63
+ const DELEGATION_CONFIG_ROOT_KEYS = new Set([
64
+ 'delegate',
65
+ 'rlm',
66
+ 'runner',
67
+ 'ui',
68
+ 'github',
69
+ 'paths',
70
+ 'confirm',
71
+ 'sandbox'
72
+ ]);
63
73
  export async function loadDelegationConfigFiles(options) {
64
74
  const env = options.env ?? process.env;
65
75
  const codexHome = options.codexHome ?? resolveCodexHome(env);
@@ -112,7 +122,7 @@ export function computeEffectiveDelegationConfig(options) {
112
122
  ...(merged.sandbox ?? {})
113
123
  }
114
124
  };
115
- if (effective.delegate.mode !== 'full' && effective.delegate.mode !== 'question_only') {
125
+ if (effective.delegate.mode !== 'full' && effective.delegate.mode !== 'question_only' && effective.delegate.mode !== 'status_only') {
116
126
  effective.delegate.mode = defaults.delegate.mode;
117
127
  }
118
128
  const repoAllowedRoots = typeof repoLayer?.paths?.allowedRoots !== 'undefined' ? repoLayer.paths.allowedRoots : [options.repoRoot];
@@ -214,8 +224,7 @@ function mergeSection(base, update) {
214
224
  async function readTomlFile(path) {
215
225
  try {
216
226
  const raw = await readFile(path, 'utf8');
217
- const parsed = toml.parse(raw);
218
- return parsed;
227
+ return parseDelegationTomlConfig(raw);
219
228
  }
220
229
  catch (error) {
221
230
  if (error.code === 'ENOENT') {
@@ -477,9 +486,312 @@ export function parseDelegationConfigOverride(value, source) {
477
486
  if (!trimmed) {
478
487
  return null;
479
488
  }
480
- const parsed = toml.parse(trimmed);
489
+ const parsed = parseDelegationTomlConfig(trimmed);
481
490
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
482
491
  return null;
483
492
  }
484
493
  return normalizeLayer(parsed, source);
485
494
  }
495
+ function getTomlParser() {
496
+ if (typeof tomlParser !== 'undefined') {
497
+ return tomlParser;
498
+ }
499
+ try {
500
+ tomlParser = require('@iarna/toml');
501
+ }
502
+ catch {
503
+ tomlParser = null;
504
+ }
505
+ return tomlParser;
506
+ }
507
+ function parseDelegationTomlConfig(raw) {
508
+ const parser = getTomlParser();
509
+ if (parser) {
510
+ const parsed = parser.parse(raw);
511
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
512
+ return parsed;
513
+ }
514
+ return {};
515
+ }
516
+ return parseDelegationTomlSubset(raw);
517
+ }
518
+ function parseDelegationTomlSubset(raw) {
519
+ const parsed = {};
520
+ let currentSection = [];
521
+ for (const line of raw.split(/\r?\n/u)) {
522
+ const trimmed = stripTomlComment(line).trim();
523
+ if (!trimmed) {
524
+ continue;
525
+ }
526
+ const tableMatch = trimmed.match(/^\[(.+)\]$/u);
527
+ if (tableMatch) {
528
+ const tablePath = parseTomlDottedPath(tableMatch[1] ?? '');
529
+ currentSection =
530
+ tablePath.length > 0 && DELEGATION_CONFIG_ROOT_KEYS.has(tablePath[0] ?? '')
531
+ ? tablePath
532
+ : null;
533
+ continue;
534
+ }
535
+ const separatorIndex = findTomlAssignmentSeparator(trimmed);
536
+ if (separatorIndex === -1) {
537
+ continue;
538
+ }
539
+ const keyPath = parseTomlDottedPath(trimmed.slice(0, separatorIndex));
540
+ if (keyPath.length === 0) {
541
+ continue;
542
+ }
543
+ if (currentSection === null) {
544
+ continue;
545
+ }
546
+ const fullPath = [...currentSection, ...keyPath];
547
+ if (!DELEGATION_CONFIG_ROOT_KEYS.has(fullPath[0] ?? '')) {
548
+ continue;
549
+ }
550
+ const parsedValue = parseTomlValue(trimmed.slice(separatorIndex + 1).trim());
551
+ if (typeof parsedValue === 'undefined') {
552
+ continue;
553
+ }
554
+ assignNestedTomlValue(parsed, fullPath, parsedValue);
555
+ }
556
+ return parsed;
557
+ }
558
+ function assignNestedTomlValue(target, pathSegments, value) {
559
+ let current = target;
560
+ for (let index = 0; index < pathSegments.length - 1; index += 1) {
561
+ const segment = pathSegments[index];
562
+ const existing = current[segment];
563
+ if (!existing || typeof existing !== 'object' || Array.isArray(existing)) {
564
+ current[segment] = {};
565
+ }
566
+ current = current[segment];
567
+ }
568
+ const leafKey = pathSegments[pathSegments.length - 1];
569
+ current[leafKey] = value;
570
+ }
571
+ function parseTomlDottedPath(raw) {
572
+ const segments = [];
573
+ let current = '';
574
+ let quote = null;
575
+ let escaping = false;
576
+ const flush = () => {
577
+ const normalized = normalizeTomlKeySegment(current);
578
+ if (normalized) {
579
+ segments.push(normalized);
580
+ }
581
+ current = '';
582
+ };
583
+ for (const character of raw.trim()) {
584
+ if (escaping) {
585
+ current += character;
586
+ escaping = false;
587
+ continue;
588
+ }
589
+ if (quote && character === '\\') {
590
+ current += character;
591
+ escaping = true;
592
+ continue;
593
+ }
594
+ if (character === '"' || character === '\'') {
595
+ if (quote === character) {
596
+ quote = null;
597
+ }
598
+ else if (!quote) {
599
+ quote = character;
600
+ }
601
+ current += character;
602
+ continue;
603
+ }
604
+ if (!quote && character === '.') {
605
+ flush();
606
+ continue;
607
+ }
608
+ current += character;
609
+ }
610
+ flush();
611
+ return segments;
612
+ }
613
+ function normalizeTomlKeySegment(raw) {
614
+ const trimmed = raw.trim();
615
+ if (!trimmed) {
616
+ return null;
617
+ }
618
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
619
+ (trimmed.startsWith('\'') && trimmed.endsWith('\''))) {
620
+ return decodeTomlString(trimmed);
621
+ }
622
+ return trimmed;
623
+ }
624
+ function parseTomlValue(raw) {
625
+ if (!raw) {
626
+ return undefined;
627
+ }
628
+ if ((raw.startsWith('"') && raw.endsWith('"')) ||
629
+ (raw.startsWith('\'') && raw.endsWith('\''))) {
630
+ return decodeTomlString(raw);
631
+ }
632
+ if (raw.startsWith('[') && raw.endsWith(']')) {
633
+ return splitTomlArrayEntries(raw.slice(1, -1)).map((entry) => parseTomlValue(entry));
634
+ }
635
+ if (raw === 'true') {
636
+ return true;
637
+ }
638
+ if (raw === 'false') {
639
+ return false;
640
+ }
641
+ const integer = parseTomlInteger(raw);
642
+ if (integer !== null) {
643
+ return integer;
644
+ }
645
+ const numeric = Number(raw);
646
+ if (Number.isFinite(numeric)) {
647
+ return numeric;
648
+ }
649
+ return undefined;
650
+ }
651
+ function parseTomlInteger(raw) {
652
+ const trimmed = raw.trim();
653
+ if (!trimmed) {
654
+ return null;
655
+ }
656
+ if (/^[+-]?(?:0|[1-9](?:_?\d)*)$/u.test(trimmed)) {
657
+ return Number.parseInt(trimmed.replace(/_/gu, ''), 10);
658
+ }
659
+ if (/^[+-]?0x[0-9a-f](?:_?[0-9a-f])*$/iu.test(trimmed)) {
660
+ return parseTomlBasedInteger(trimmed, /^([+-]?)0x/iu, 16);
661
+ }
662
+ if (/^[+-]?0o[0-7](?:_?[0-7])*$/iu.test(trimmed)) {
663
+ return parseTomlBasedInteger(trimmed, /^([+-]?)0o/iu, 8);
664
+ }
665
+ if (/^[+-]?0b[01](?:_?[01])*$/iu.test(trimmed)) {
666
+ return parseTomlBasedInteger(trimmed, /^([+-]?)0b/iu, 2);
667
+ }
668
+ return null;
669
+ }
670
+ function parseTomlBasedInteger(raw, prefixPattern, radix) {
671
+ const normalized = raw.replace(/_/gu, '');
672
+ const prefixMatch = normalized.match(prefixPattern);
673
+ if (!prefixMatch) {
674
+ return null;
675
+ }
676
+ const sign = prefixMatch[1] === '-' ? -1 : 1;
677
+ const digits = normalized.slice(prefixMatch[0].length);
678
+ return sign * Number.parseInt(digits, radix);
679
+ }
680
+ function splitTomlArrayEntries(raw) {
681
+ const entries = [];
682
+ let current = '';
683
+ let bracketDepth = 0;
684
+ let quote = null;
685
+ let escaping = false;
686
+ const flush = () => {
687
+ const trimmed = current.trim();
688
+ if (trimmed) {
689
+ entries.push(trimmed);
690
+ }
691
+ current = '';
692
+ };
693
+ for (const character of raw) {
694
+ if (escaping) {
695
+ current += character;
696
+ escaping = false;
697
+ continue;
698
+ }
699
+ if (quote && character === '\\') {
700
+ current += character;
701
+ escaping = true;
702
+ continue;
703
+ }
704
+ if (character === '"' || character === '\'') {
705
+ if (quote === character) {
706
+ quote = null;
707
+ }
708
+ else if (!quote) {
709
+ quote = character;
710
+ }
711
+ current += character;
712
+ continue;
713
+ }
714
+ if (!quote) {
715
+ if (character === '[') {
716
+ bracketDepth += 1;
717
+ }
718
+ else if (character === ']') {
719
+ bracketDepth = Math.max(0, bracketDepth - 1);
720
+ }
721
+ else if (character === ',' && bracketDepth === 0) {
722
+ flush();
723
+ continue;
724
+ }
725
+ }
726
+ current += character;
727
+ }
728
+ flush();
729
+ return entries;
730
+ }
731
+ function findTomlAssignmentSeparator(raw) {
732
+ let quote = null;
733
+ let escaping = false;
734
+ for (let index = 0; index < raw.length; index += 1) {
735
+ const character = raw[index];
736
+ if (escaping) {
737
+ escaping = false;
738
+ continue;
739
+ }
740
+ if (quote && character === '\\') {
741
+ escaping = true;
742
+ continue;
743
+ }
744
+ if (character === '"' || character === '\'') {
745
+ if (quote === character) {
746
+ quote = null;
747
+ }
748
+ else if (!quote) {
749
+ quote = character;
750
+ }
751
+ continue;
752
+ }
753
+ if (!quote && character === '=') {
754
+ return index;
755
+ }
756
+ }
757
+ return -1;
758
+ }
759
+ function decodeTomlString(raw) {
760
+ if (raw.startsWith('"') && raw.endsWith('"')) {
761
+ try {
762
+ return JSON.parse(raw);
763
+ }
764
+ catch {
765
+ return raw.slice(1, -1).replace(/\\\\/gu, '\\').replace(/\\"/gu, '"').replace(/\\'/gu, '\'');
766
+ }
767
+ }
768
+ return raw.slice(1, -1).replace(/\\'/gu, '\'');
769
+ }
770
+ function stripTomlComment(line) {
771
+ let quote = null;
772
+ let escaping = false;
773
+ for (let index = 0; index < line.length; index += 1) {
774
+ const character = line[index];
775
+ if (escaping) {
776
+ escaping = false;
777
+ continue;
778
+ }
779
+ if (quote && character === '\\') {
780
+ escaping = true;
781
+ continue;
782
+ }
783
+ if (character === '"' || character === '\'') {
784
+ if (quote === character) {
785
+ quote = null;
786
+ }
787
+ else if (!quote) {
788
+ quote = character;
789
+ }
790
+ continue;
791
+ }
792
+ if (!quote && character === '#') {
793
+ return line.slice(0, index);
794
+ }
795
+ }
796
+ return line;
797
+ }
@@ -1,4 +1,3 @@
1
- import { join } from 'node:path';
2
1
  import process from 'node:process';
3
2
  export const REPO_CONFIG_REQUIRED_ENV_KEY = 'CODEX_ORCHESTRATOR_REPO_CONFIG_REQUIRED';
4
3
  const REPO_CONFIG_REQUIRED_TRUE_VALUES = new Set(['1', 'true', 'yes', 'on']);
@@ -13,10 +12,10 @@ export function isRepoConfigRequired(env = process.env) {
13
12
  }
14
13
  return REPO_CONFIG_REQUIRED_TRUE_VALUES.has(normalized);
15
14
  }
16
- export function formatRepoConfigRequiredError(repoRoot) {
15
+ export function formatRepoConfigRequiredError(repoConfigPath) {
17
16
  return [
18
17
  `Repo-local codex.orchestrator.json is required when ${REPO_CONFIG_REQUIRED_ENV_KEY}=1.`,
19
- `Expected: ${join(repoRoot, 'codex.orchestrator.json')}.`,
18
+ `Expected: ${repoConfigPath}.`,
20
19
  'Run `codex-orchestrator init codex` to scaffold repo-local config.'
21
20
  ].join(' ');
22
21
  }
@@ -1,20 +1,11 @@
1
+ import process from 'node:process';
1
2
  import { readFile } from 'node:fs/promises';
2
- import { join } from 'node:path';
3
+ import { isAbsolute, join, resolve } from 'node:path';
3
4
  import { logger } from '../../logger.js';
4
5
  import { findPackageRoot } from '../utils/packageInfo.js';
6
+ export const REPO_CONFIG_PATH_ENV_KEY = 'CODEX_ORCHESTRATOR_REPO_CONFIG_PATH';
5
7
  export async function loadRepoConfig(env, options = {}) {
6
- const repoConfigPath = join(env.repoRoot, 'codex.orchestrator.json');
7
- const repoConfig = await readConfig(repoConfigPath);
8
- if (repoConfig) {
9
- if (!options.quiet) {
10
- logger.info(`[codex-config] Loaded user config from ${repoConfigPath}`);
11
- }
12
- return normalizeUserConfig(repoConfig, 'repo');
13
- }
14
- if (!options.quiet) {
15
- logger.warn(`[codex-config] Missing codex.orchestrator.json at ${repoConfigPath}`);
16
- }
17
- return null;
8
+ return await loadRepoConfigFromPath(resolveRepoConfigPath(env, options.processEnv), options);
18
9
  }
19
10
  export async function loadPackageConfig(env, options = {}) {
20
11
  const repoConfigPath = join(env.repoRoot, 'codex.orchestrator.json');
@@ -45,6 +36,30 @@ export async function loadUserConfig(env, options = {}) {
45
36
  }
46
37
  return await loadPackageConfig(env, options);
47
38
  }
39
+ export function resolveRepoConfigPath(env, runtimeEnv = process.env) {
40
+ const override = runtimeEnv[REPO_CONFIG_PATH_ENV_KEY];
41
+ if (typeof override !== 'string' || override.trim().length === 0) {
42
+ return join(env.repoRoot, 'codex.orchestrator.json');
43
+ }
44
+ const trimmed = override.trim();
45
+ return isAbsolute(trimmed) ? trimmed : resolve(env.repoRoot, trimmed);
46
+ }
47
+ export async function loadRepoConfigFromPath(repoConfigPath, options = {}) {
48
+ const repoConfig = await readConfig(repoConfigPath);
49
+ if (repoConfig) {
50
+ if (!options.quiet) {
51
+ logger.info(`[codex-config] Loaded user config from ${repoConfigPath}`);
52
+ }
53
+ return normalizeUserConfig(repoConfig, 'repo');
54
+ }
55
+ if (!options.quiet) {
56
+ logger.warn(`[codex-config] Missing codex.orchestrator.json at ${repoConfigPath}`);
57
+ }
58
+ return null;
59
+ }
60
+ export function parseUserConfigRaw(raw, source) {
61
+ return normalizeUserConfig(JSON.parse(raw), source);
62
+ }
48
63
  export function findPipeline(config, id) {
49
64
  if (!config?.pipelines) {
50
65
  return null;
@@ -0,0 +1,69 @@
1
+ import { timingSafeEqual } from 'node:crypto';
2
+ const CSRF_HEADER = 'x-csrf-token';
3
+ export function admitAuthenticatedControlRoute(context) {
4
+ const auth = resolveAuthToken({
5
+ authorizationHeader: context.req.headers.authorization,
6
+ controlToken: context.controlToken,
7
+ isSessionTokenValid: context.isSessionTokenValid
8
+ });
9
+ if (!auth) {
10
+ writeGateError(context.res, 401, 'unauthorized');
11
+ return null;
12
+ }
13
+ if (requiresCsrfProtection(context.req.method) && !isCsrfValid(context.req, auth.token)) {
14
+ writeGateError(context.res, 403, 'csrf_invalid');
15
+ return null;
16
+ }
17
+ if (isRunnerOnlyEndpoint(context.pathname, context.req.method) && auth.kind !== 'control') {
18
+ writeGateError(context.res, 403, 'runner_only');
19
+ return null;
20
+ }
21
+ return auth;
22
+ }
23
+ function resolveAuthToken(input) {
24
+ const header = typeof input.authorizationHeader === 'string' ? input.authorizationHeader : null;
25
+ if (!header || !header.startsWith('Bearer ')) {
26
+ return null;
27
+ }
28
+ const token = header.slice('Bearer '.length);
29
+ if (safeTokenCompare(token, input.controlToken)) {
30
+ return { token, kind: 'control' };
31
+ }
32
+ if (input.isSessionTokenValid(token)) {
33
+ return { token, kind: 'session' };
34
+ }
35
+ return null;
36
+ }
37
+ function isCsrfValid(req, token) {
38
+ const header = req.headers[CSRF_HEADER];
39
+ if (!header) {
40
+ return false;
41
+ }
42
+ return safeTokenCompare(header, token);
43
+ }
44
+ function requiresCsrfProtection(method) {
45
+ const normalized = (method ?? 'GET').toUpperCase();
46
+ return normalized !== 'GET' && normalized !== 'HEAD';
47
+ }
48
+ function isRunnerOnlyEndpoint(pathname, method) {
49
+ if ((method ?? 'GET').toUpperCase() !== 'POST') {
50
+ return false;
51
+ }
52
+ const normalized = pathname.endsWith('/') && pathname !== '/' ? pathname.slice(0, -1) : pathname;
53
+ return (normalized === '/confirmations/issue' ||
54
+ normalized === '/confirmations/consume' ||
55
+ normalized === '/confirmations/validate' ||
56
+ normalized === '/delegation/register' ||
57
+ normalized === '/questions/enqueue' ||
58
+ normalized === '/security/violation');
59
+ }
60
+ function writeGateError(res, status, error) {
61
+ res.writeHead(status, { 'Content-Type': 'application/json' });
62
+ res.end(JSON.stringify({ error }));
63
+ }
64
+ function safeTokenCompare(left, right) {
65
+ if (left.length !== right.length) {
66
+ return false;
67
+ }
68
+ return timingSafeEqual(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8'));
69
+ }