@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
@@ -1,222 +1,30 @@
1
- import process from 'node:process';
2
- import { readFile } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { TaskManager } from '../manager.js';
5
- import { RunManifestWriter } from '../persistence/RunManifestWriter.js';
6
- import { TaskStateStore } from '../persistence/TaskStateStore.js';
7
- import { CommandPlanner, CommandBuilder, CommandTester, CommandReviewer } from './adapters/index.js';
8
1
  import { resolveEnvironmentPaths } from '../../../scripts/lib/run-manifests.js';
9
2
  import { normalizeEnvironmentPaths } from './run/environment.js';
10
- import { bootstrapManifest, loadManifest, updateHeartbeat, finalizeStatus, appendSummary, ensureGuardrailStatus, resetForResume, recordResumeEvent } from './run/manifest.js';
11
- import { ManifestPersister, persistManifest } from './run/manifestPersister.js';
12
- import { resolveRuntimeActivitySnapshot } from './run/runtimeActivity.js';
13
- import { generateRunId } from './utils/runId.js';
14
- import { runCommandStage } from './services/commandRunner.js';
15
- import { appendMetricsEntry } from './metrics/metricsRecorder.js';
16
- import { isoTimestamp } from './utils/time.js';
17
- import { resolveRunPaths, relativeToRepo } from './run/runPaths.js';
3
+ import { finalizeStatus } from './run/manifest.js';
4
+ import { persistManifest } from './run/manifestPersister.js';
18
5
  import { logger } from '../logger.js';
19
- import { getPrivacyGuard } from './services/execRuntime.js';
20
- import { PipelineResolver } from './services/pipelineResolver.js';
21
6
  import { ControlPlaneService } from './services/controlPlaneService.js';
22
- import { ControlWatcher } from './control/controlWatcher.js';
23
7
  import { SchedulerService } from './services/schedulerService.js';
24
- import { applyRuntimeToRunSummary, applyHandlesToRunSummary, applyPrivacyToRunSummary, applyCloudExecutionToRunSummary, applyCloudFallbackToRunSummary, applyUsageKpiToRunSummary, persistRunSummary } from './services/runSummaryWriter.js';
25
- import { prepareRun, resolvePipelineForResume, overrideTaskEnvironment } from './services/runPreparation.js';
26
- import { loadPackageConfig, loadUserConfig } from './config/userConfig.js';
27
- import { formatRepoConfigRequiredError, isRepoConfigRequired } from './config/repoConfigPolicy.js';
28
- import { loadDelegationConfigFiles, computeEffectiveDelegationConfig, parseDelegationConfigOverride, splitDelegationConfigOverrides } from './config/delegationConfig.js';
29
- import { ControlServer } from './control/controlServer.js';
30
- import { RunEventEmitter, RunEventPublisher, snapshotStages } from './events/runEvents.js';
31
- import { RunEventStream, attachRunEventAdapter } from './events/runEventStream.js';
32
- import { CLI_EXECUTION_MODE_PARSER, resolveRequiresCloudPolicy } from '../utils/executionMode.js';
33
- import { resolveCodexCliBin } from './utils/codexCli.js';
34
- import { CodexCloudTaskExecutor } from '../cloud/CodexCloudTaskExecutor.js';
35
- import { persistPipelineExperience } from './services/pipelineExperience.js';
36
- import { runCloudPreflight } from './utils/cloudPreflight.js';
37
- import { writeJsonAtomic } from './utils/fs.js';
38
- import { resolveRuntimeMode, resolveRuntimeSelection } from './runtime/index.js';
39
- import { buildAutoScoutEvidence, resolveAdvancedAutopilotDecision } from './utils/advancedAutopilot.js';
8
+ import { recordOrchestratorAutoScoutEvidence } from './services/orchestratorAutoScoutEvidenceRecorder.js';
9
+ import { runOrchestratorRunLifecycle } from './services/orchestratorRunLifecycleOrchestrationShell.js';
10
+ import { executeOrchestratorPipelineRouteEntryShell } from './services/orchestratorExecutionRouteAdapterShell.js';
11
+ import { runOrchestratorControlPlaneLifecycleShell } from './services/orchestratorControlPlaneLifecycleShell.js';
12
+ import { runOrchestratorStartPreparationShell } from './services/orchestratorStartPreparationShell.js';
13
+ import { runOrchestratorResumePreparationShell } from './services/orchestratorResumePreparationShell.js';
14
+ import { runOrchestratorStatusShell } from './services/orchestratorStatusShell.js';
15
+ import { runOrchestratorPlanShell } from './services/orchestratorPlanShell.js';
16
+ import { applyRequestedRuntimeModeToManifest, applyRuntimeSelectionToManifest } from './services/orchestratorRuntimeManifestMutation.js';
17
+ import { validateOrchestratorResumeToken } from './services/orchestratorResumeTokenValidation.js';
40
18
  const resolveBaseEnvironment = () => normalizeEnvironmentPaths(resolveEnvironmentPaths());
41
- const CONFIG_OVERRIDE_ENV_KEYS = ['CODEX_CONFIG_OVERRIDES', 'CODEX_MCP_CONFIG_OVERRIDES'];
42
- const DEFAULT_CLOUD_POLL_INTERVAL_SECONDS = 10;
43
- const DEFAULT_CLOUD_TIMEOUT_SECONDS = 1800;
44
- const DEFAULT_CLOUD_ATTEMPTS = 1;
45
- const DEFAULT_CLOUD_STATUS_RETRY_LIMIT = 12;
46
- const DEFAULT_CLOUD_STATUS_RETRY_BACKOFF_MS = 1500;
47
- const DEFAULT_AUTO_SCOUT_TIMEOUT_MS = 4000;
48
- const MAX_CLOUD_PROMPT_EXPERIENCES = 3;
49
- const MAX_CLOUD_PROMPT_EXPERIENCE_CHARS = 320;
50
- function collectDelegationEnvOverrides(env = process.env) {
51
- const layers = [];
52
- for (const key of CONFIG_OVERRIDE_ENV_KEYS) {
53
- const raw = env[key];
54
- if (!raw) {
55
- continue;
56
- }
57
- const values = splitDelegationConfigOverrides(raw);
58
- for (const value of values) {
59
- try {
60
- const layer = parseDelegationConfigOverride(value, 'env');
61
- if (layer) {
62
- layers.push(layer);
63
- }
64
- }
65
- catch (error) {
66
- logger.warn(`Invalid delegation config override (env): ${error?.message ?? String(error)}`);
67
- }
68
- }
19
+ const RESUME_PRE_START_FAILURE_STATUS_DETAIL = 'resume-pre-start-failed';
20
+ async function persistResumePreStartFailureState(manifest, paths, persister) {
21
+ finalizeStatus(manifest, 'failed', RESUME_PRE_START_FAILURE_STATUS_DETAIL);
22
+ try {
23
+ await persistManifest(paths, manifest, persister, { force: true });
69
24
  }
70
- return layers;
71
- }
72
- function readCloudString(value) {
73
- return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
74
- }
75
- function readCloudNumber(raw, fallback) {
76
- if (!raw) {
77
- return fallback;
78
- }
79
- const parsed = Number.parseInt(raw, 10);
80
- if (!Number.isFinite(parsed) || parsed <= 0) {
81
- return fallback;
82
- }
83
- return parsed;
84
- }
85
- function allowCloudFallback(envOverrides) {
86
- const raw = readCloudString(envOverrides?.CODEX_ORCHESTRATOR_CLOUD_FALLBACK) ??
87
- readCloudString(process.env.CODEX_ORCHESTRATOR_CLOUD_FALLBACK);
88
- if (!raw) {
89
- return true;
90
- }
91
- const normalized = raw.toLowerCase();
92
- return !['0', 'false', 'off', 'deny', 'disabled', 'never', 'strict'].includes(normalized);
93
- }
94
- function normalizeCloudFallbackIssues(issues) {
95
- return issues.map((issue) => ({ code: issue.code, message: issue.message }));
96
- }
97
- function readCloudFeatureList(raw) {
98
- if (!raw) {
99
- return [];
100
- }
101
- const seen = new Set();
102
- const features = [];
103
- for (const token of raw.split(/[,\s]+/u)) {
104
- const feature = token.trim();
105
- if (!feature || seen.has(feature)) {
106
- continue;
107
- }
108
- seen.add(feature);
109
- features.push(feature);
110
- }
111
- return features;
112
- }
113
- function normalizePromptSnippet(value) {
114
- return value.replace(/\s+/gu, ' ').trim();
115
- }
116
- function truncatePromptSnippet(value) {
117
- if (value.length <= MAX_CLOUD_PROMPT_EXPERIENCE_CHARS) {
118
- return value;
119
- }
120
- return `${value.slice(0, MAX_CLOUD_PROMPT_EXPERIENCE_CHARS - 1).trimEnd()}…`;
121
- }
122
- function readPromptPackDomain(value) {
123
- if (typeof value !== 'string') {
124
- return null;
125
- }
126
- const trimmed = value.trim();
127
- return trimmed.length > 0 ? trimmed : null;
128
- }
129
- function readPromptPackDomainLower(pack) {
130
- const domain = readPromptPackDomain(pack.domain);
131
- return domain ? domain.toLowerCase() : null;
132
- }
133
- function hasPromptPackExperiences(pack) {
134
- if (!readPromptPackDomain(pack.domain)) {
135
- return false;
136
- }
137
- return (Array.isArray(pack.experiences) &&
138
- pack.experiences.some((entry) => typeof entry === 'string' && normalizePromptSnippet(entry).length > 0));
139
- }
140
- function selectPromptPackForCloudPrompt(params) {
141
- const candidates = (params.promptPacks ?? []).filter(hasPromptPackExperiences);
142
- if (candidates.length === 0) {
143
- return null;
144
- }
145
- const haystack = [
146
- params.pipeline.id,
147
- params.pipeline.title,
148
- (params.pipeline.tags ?? []).join(' '),
149
- params.target.id,
150
- params.target.description ?? '',
151
- params.stage.id,
152
- params.stage.title
153
- ]
154
- .join(' ')
155
- .toLowerCase();
156
- const directMatch = candidates.find((pack) => {
157
- const domainLower = readPromptPackDomainLower(pack);
158
- return domainLower !== null && domainLower !== 'implementation' && haystack.includes(domainLower);
159
- });
160
- if (directMatch) {
161
- return directMatch;
25
+ catch (persistError) {
26
+ logger.warn(`Failed to persist resume pre-start failure state: ${persistError?.message ?? String(persistError)}`);
162
27
  }
163
- const broadDirectMatch = candidates.find((pack) => {
164
- const domainLower = readPromptPackDomainLower(pack);
165
- return domainLower !== null && haystack.includes(domainLower);
166
- });
167
- if (broadDirectMatch) {
168
- return broadDirectMatch;
169
- }
170
- const implementation = candidates.find((pack) => readPromptPackDomainLower(pack) === 'implementation');
171
- if (implementation) {
172
- return implementation;
173
- }
174
- return candidates[0] ?? null;
175
- }
176
- function buildCloudExperiencePromptLines(params) {
177
- const selectedPack = selectPromptPackForCloudPrompt({
178
- promptPacks: params.manifest.prompt_packs,
179
- pipeline: params.pipeline,
180
- target: params.target,
181
- stage: params.stage
182
- });
183
- if (!selectedPack || !Array.isArray(selectedPack.experiences)) {
184
- return [];
185
- }
186
- const snippets = selectedPack.experiences
187
- .filter((entry) => typeof entry === 'string')
188
- .map((entry) => normalizePromptSnippet(entry))
189
- .filter((entry) => entry.length > 0)
190
- .slice(0, MAX_CLOUD_PROMPT_EXPERIENCES)
191
- .map((entry) => truncatePromptSnippet(entry));
192
- if (snippets.length === 0) {
193
- return [];
194
- }
195
- const domainLabel = readPromptPackDomain(selectedPack.domain) ?? 'unknown';
196
- return [
197
- '',
198
- 'Relevant prior experiences (hints, not strict instructions):',
199
- `Domain: ${domainLabel}`,
200
- ...snippets.map((entry, index) => `${index + 1}. ${entry}`)
201
- ];
202
- }
203
- function resolveCloudEnvironmentId(task, target, envOverrides) {
204
- const metadata = (target.metadata ?? {});
205
- const taskMetadata = (task.metadata ?? {});
206
- const taskCloud = (taskMetadata.cloud ?? null);
207
- const candidates = [
208
- readCloudString(metadata.cloudEnvId),
209
- readCloudString(metadata.cloud_env_id),
210
- readCloudString(metadata.envId),
211
- readCloudString(metadata.environmentId),
212
- readCloudString(taskCloud?.envId),
213
- readCloudString(taskCloud?.environmentId),
214
- readCloudString(taskMetadata.cloudEnvId),
215
- readCloudString(taskMetadata.cloud_env_id),
216
- readCloudString(envOverrides?.CODEX_CLOUD_ENV_ID),
217
- readCloudString(process.env.CODEX_CLOUD_ENV_ID)
218
- ];
219
- return candidates.find((candidate) => candidate !== null) ?? null;
220
28
  }
221
29
  export class CodexOrchestrator {
222
30
  baseEnv;
@@ -226,80 +34,18 @@ export class CodexOrchestrator {
226
34
  this.baseEnv = baseEnv;
227
35
  }
228
36
  async start(options = {}) {
229
- const preparation = await prepareRun({
37
+ const { preparation, runId, runtimeModeResolution, manifest, paths, persister } = await runOrchestratorStartPreparationShell({
230
38
  baseEnv: this.baseEnv,
231
- taskIdOverride: options.taskId,
232
- pipelineId: options.pipelineId,
233
- targetStageId: options.targetStageId ?? null,
234
- planTargetFallback: null
39
+ options,
40
+ applyRequestedRuntimeMode: applyRequestedRuntimeModeToManifest
235
41
  });
236
- const runId = generateRunId();
237
- const runtimeModeResolution = resolveRuntimeMode({
238
- flag: options.runtimeMode,
239
- env: { ...process.env, ...(preparation.envOverrides ?? {}) },
240
- configDefault: preparation.runtimeModeDefault
241
- });
242
- const { manifest, paths } = await bootstrapManifest(runId, {
243
- env: preparation.env,
42
+ return await runOrchestratorControlPlaneLifecycleShell({
43
+ repoRoot: preparation.env.repoRoot,
44
+ paths,
244
45
  pipeline: preparation.pipeline,
245
- parentRunId: options.parentRunId ?? null,
246
- taskSlug: preparation.metadata.slug,
247
- approvalPolicy: options.approvalPolicy ?? null,
248
- planTargetId: preparation.planPreview?.targetId ?? preparation.plannerTargetId ?? null
249
- });
250
- this.applyRequestedRuntimeMode(manifest, runtimeModeResolution.mode);
251
- if (preparation.configNotice) {
252
- appendSummary(manifest, preparation.configNotice);
253
- }
254
- const persister = new ManifestPersister({
255
46
  manifest,
256
- paths,
257
- persistIntervalMs: Math.max(1000, manifest.heartbeat_interval_seconds * 1000)
258
- });
259
- const emitter = options.runEvents ?? new RunEventEmitter();
260
- let eventStream = null;
261
- let controlServer = null;
262
- let detachStream = null;
263
- let onEventEntry;
264
- try {
265
- const stream = await RunEventStream.create({
266
- paths,
267
- taskId: manifest.task_id,
268
- runId,
269
- pipelineId: preparation.pipeline.id,
270
- pipelineTitle: preparation.pipeline.title
271
- });
272
- eventStream = stream;
273
- const configFiles = await loadDelegationConfigFiles({ repoRoot: preparation.env.repoRoot });
274
- const envOverrideLayers = collectDelegationEnvOverrides();
275
- const layers = [configFiles.global, configFiles.repo, ...envOverrideLayers].filter(Boolean);
276
- const effectiveConfig = computeEffectiveDelegationConfig({
277
- repoRoot: preparation.env.repoRoot,
278
- layers
279
- });
280
- controlServer = effectiveConfig.ui.controlEnabled
281
- ? await ControlServer.start({
282
- paths,
283
- config: effectiveConfig,
284
- eventStream: stream,
285
- runId
286
- })
287
- : null;
288
- onEventEntry = (entry) => {
289
- controlServer?.broadcast(entry);
290
- };
291
- const onStreamError = (error, payload) => {
292
- logger.warn(`Failed to append run event ${payload.event}: ${error.message}`);
293
- };
294
- detachStream = attachRunEventAdapter(emitter, stream, onEventEntry, onStreamError);
295
- const runEvents = this.createRunEventPublisher({
296
- runId,
297
- pipeline: preparation.pipeline,
298
- manifest,
299
- paths,
300
- emitter
301
- });
302
- return await this.performRunLifecycle({
47
+ emitter: options.runEvents,
48
+ runWithLifecycle: ({ runEvents, eventStream, onEventEntry }) => this.performRunLifecycle({
303
49
  env: preparation.env,
304
50
  pipeline: preparation.pipeline,
305
51
  manifest,
@@ -308,1136 +54,80 @@ export class CodexOrchestrator {
308
54
  taskContext: preparation.taskContext,
309
55
  runId,
310
56
  runEvents,
311
- eventStream: stream,
57
+ eventStream,
312
58
  onEventEntry,
313
59
  persister,
314
60
  envOverrides: preparation.envOverrides,
315
61
  runtimeModeRequested: runtimeModeResolution.mode,
316
62
  runtimeModeSource: runtimeModeResolution.source,
317
63
  executionModeOverride: options.executionMode
318
- });
319
- }
320
- finally {
321
- if (detachStream) {
322
- try {
323
- detachStream();
324
- }
325
- catch (error) {
326
- logger.warn(`Failed to detach run event stream: ${error?.message ?? String(error)}`);
327
- }
328
- }
329
- if (controlServer) {
330
- try {
331
- await controlServer.close();
332
- }
333
- catch (error) {
334
- logger.warn(`Failed to close control server: ${error?.message ?? String(error)}`);
335
- }
336
- }
337
- if (eventStream) {
338
- try {
339
- await eventStream.close();
340
- }
341
- catch (error) {
342
- logger.warn(`Failed to close run event stream: ${error?.message ?? String(error)}`);
343
- }
344
- }
345
- }
64
+ })
65
+ });
346
66
  }
347
67
  async resume(options) {
348
- const env = this.baseEnv;
349
- const { manifest, paths } = await loadManifest(env, options.runId);
350
- const actualEnv = overrideTaskEnvironment(env, manifest.task_id);
351
- const resolver = new PipelineResolver();
352
- const designConfig = await resolver.loadDesignConfig(actualEnv.repoRoot);
353
- const repoConfigRequired = isRepoConfigRequired(process.env);
354
- const userConfig = await loadUserConfig(actualEnv, { allowPackageFallback: !repoConfigRequired });
355
- if (repoConfigRequired && userConfig?.source !== 'repo') {
356
- throw new Error(formatRepoConfigRequiredError(actualEnv.repoRoot));
357
- }
358
- const fallbackConfig = !repoConfigRequired && manifest.pipeline_id === 'rlm' && userConfig?.source === 'repo'
359
- ? await loadPackageConfig(actualEnv)
360
- : null;
361
- const pipeline = resolvePipelineForResume(actualEnv, manifest, userConfig, fallbackConfig);
362
- const envOverrides = resolver.resolveDesignEnvOverrides(designConfig, pipeline.id);
363
- await this.validateResumeToken(paths, manifest, options.resumeToken ?? null);
364
- recordResumeEvent(manifest, {
365
- actor: options.actor ?? 'cli',
366
- reason: options.reason ?? 'manual-resume',
367
- outcome: 'accepted'
368
- });
369
- resetForResume(manifest);
370
- updateHeartbeat(manifest);
371
- const preparation = await prepareRun({
372
- baseEnv: actualEnv,
373
- pipeline,
374
- runtimeModeDefault: userConfig?.runtimeMode ?? null,
375
- resolver,
376
- taskIdOverride: manifest.task_id,
377
- targetStageId: options.targetStageId,
378
- planTargetFallback: manifest.plan_target_id ?? null,
379
- envOverrides
380
- });
381
- if (preparation.configNotice && !(manifest.summary ?? '').includes(preparation.configNotice)) {
382
- appendSummary(manifest, preparation.configNotice);
383
- }
384
- const runtimeModeResolution = resolveRuntimeMode({
385
- flag: options.runtimeMode,
386
- env: { ...process.env, ...(preparation.envOverrides ?? {}) },
387
- configDefault: preparation.runtimeModeDefault,
388
- manifestMode: manifest.runtime_mode_requested ?? manifest.runtime_mode ?? null,
389
- preferManifest: true
68
+ const { preparation, runtimeModeResolution, manifest, paths, persister } = await runOrchestratorResumePreparationShell({
69
+ baseEnv: this.baseEnv,
70
+ options,
71
+ validateResumeToken: validateOrchestratorResumeToken,
72
+ applyRequestedRuntimeMode: applyRequestedRuntimeModeToManifest
390
73
  });
391
- this.applyRequestedRuntimeMode(manifest, runtimeModeResolution.mode);
392
- manifest.plan_target_id = preparation.planPreview?.targetId ?? preparation.plannerTargetId ?? null;
393
- const persister = new ManifestPersister({
394
- manifest,
74
+ return await runOrchestratorControlPlaneLifecycleShell({
75
+ repoRoot: preparation.env.repoRoot,
395
76
  paths,
396
- persistIntervalMs: Math.max(1000, manifest.heartbeat_interval_seconds * 1000)
397
- });
398
- await persister.schedule({ manifest: true, heartbeat: true, force: true });
399
- const emitter = options.runEvents ?? new RunEventEmitter();
400
- let eventStream = null;
401
- let controlServer = null;
402
- let detachStream = null;
403
- let onEventEntry;
404
- try {
405
- const stream = await RunEventStream.create({
406
- paths,
407
- taskId: manifest.task_id,
408
- runId: manifest.run_id,
409
- pipelineId: pipeline.id,
410
- pipelineTitle: pipeline.title
411
- });
412
- eventStream = stream;
413
- const configFiles = await loadDelegationConfigFiles({ repoRoot: preparation.env.repoRoot });
414
- const envOverrideLayers = collectDelegationEnvOverrides();
415
- const layers = [configFiles.global, configFiles.repo, ...envOverrideLayers].filter(Boolean);
416
- const effectiveConfig = computeEffectiveDelegationConfig({
417
- repoRoot: preparation.env.repoRoot,
418
- layers
419
- });
420
- controlServer = effectiveConfig.ui.controlEnabled
421
- ? await ControlServer.start({
422
- paths,
423
- config: effectiveConfig,
424
- eventStream: stream,
425
- runId: manifest.run_id
426
- })
427
- : null;
428
- onEventEntry = (entry) => {
429
- controlServer?.broadcast(entry);
430
- };
431
- const onStreamError = (error, payload) => {
432
- logger.warn(`Failed to append run event ${payload.event}: ${error.message}`);
433
- };
434
- detachStream = attachRunEventAdapter(emitter, stream, onEventEntry, onStreamError);
435
- const runEvents = this.createRunEventPublisher({
436
- runId: manifest.run_id,
437
- pipeline,
438
- manifest,
439
- paths,
440
- emitter
441
- });
442
- return await this.performRunLifecycle({
77
+ pipeline: preparation.pipeline,
78
+ manifest,
79
+ emitter: options.runEvents,
80
+ onStartFailure: () => persistResumePreStartFailureState(manifest, paths, persister),
81
+ runWithLifecycle: ({ runEvents, eventStream, onEventEntry }) => this.performRunLifecycle({
443
82
  env: preparation.env,
444
- pipeline,
83
+ pipeline: preparation.pipeline,
445
84
  manifest,
446
85
  paths,
447
86
  planner: preparation.planner,
448
87
  taskContext: preparation.taskContext,
449
88
  runId: manifest.run_id,
450
89
  runEvents,
451
- eventStream: stream,
90
+ eventStream,
452
91
  onEventEntry,
453
92
  persister,
454
93
  envOverrides: preparation.envOverrides,
455
94
  runtimeModeRequested: runtimeModeResolution.mode,
456
95
  runtimeModeSource: runtimeModeResolution.source
457
- });
458
- }
459
- finally {
460
- if (detachStream) {
461
- try {
462
- detachStream();
463
- }
464
- catch (error) {
465
- logger.warn(`Failed to detach run event stream: ${error?.message ?? String(error)}`);
466
- }
467
- }
468
- if (controlServer) {
469
- try {
470
- await controlServer.close();
471
- }
472
- catch (error) {
473
- logger.warn(`Failed to close control server: ${error?.message ?? String(error)}`);
474
- }
475
- }
476
- if (eventStream) {
477
- try {
478
- await eventStream.close();
479
- }
480
- catch (error) {
481
- logger.warn(`Failed to close run event stream: ${error?.message ?? String(error)}`);
482
- }
483
- }
484
- }
96
+ })
97
+ });
485
98
  }
486
99
  async status(options) {
487
- const env = this.baseEnv;
488
- const { manifest, paths } = await loadManifest(env, options.runId);
489
- const activity = await resolveRuntimeActivitySnapshot(manifest, paths);
490
- if (options.format === 'json') {
491
- const payload = this.buildStatusPayload(env, manifest, paths, activity);
492
- process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
493
- return manifest;
494
- }
495
- this.renderStatus(manifest, activity);
496
- return manifest;
497
- }
498
- async plan(options = {}) {
499
- const preparation = await prepareRun({
100
+ return await runOrchestratorStatusShell({
500
101
  baseEnv: this.baseEnv,
501
- taskIdOverride: options.taskId,
502
- pipelineId: options.pipelineId,
503
- targetStageId: options.targetStageId,
504
- planTargetFallback: null
505
- });
506
- const plan = preparation.planPreview ?? (await preparation.planner.plan(preparation.taskContext));
507
- const stages = preparation.pipeline.stages.map((stage, index) => {
508
- if (stage.kind === 'command') {
509
- return {
510
- index: index + 1,
511
- id: stage.id,
512
- title: stage.title,
513
- kind: stage.kind,
514
- command: stage.command,
515
- cwd: stage.cwd ?? null,
516
- env: stage.env ?? null,
517
- allowFailure: Boolean(stage.allowFailure),
518
- summaryHint: stage.summaryHint ?? null
519
- };
520
- }
521
- return {
522
- index: index + 1,
523
- id: stage.id,
524
- title: stage.title,
525
- kind: stage.kind,
526
- pipeline: stage.pipeline,
527
- optional: Boolean(stage.optional)
528
- };
102
+ options
529
103
  });
530
- const pipelineSource = preparation.pipelineSource === 'user'
531
- ? 'user'
532
- : preparation.pipelineSource === 'default'
533
- ? 'default'
534
- : null;
535
- return {
536
- pipeline: {
537
- id: preparation.pipeline.id,
538
- title: preparation.pipeline.title,
539
- description: preparation.pipeline.description ?? null,
540
- source: pipelineSource
541
- },
542
- stages,
543
- plan,
544
- targetId: plan.targetId ?? null
545
- };
546
- }
547
- createRunEventPublisher(params) {
548
- if (!params.emitter) {
549
- return undefined;
550
- }
551
- return new RunEventPublisher(params.emitter, {
552
- taskId: params.manifest.task_id,
553
- runId: params.runId,
554
- pipelineId: params.pipeline.id,
555
- pipelineTitle: params.pipeline.title,
556
- manifestPath: params.paths.manifestPath,
557
- logPath: params.paths.logPath
558
- });
559
- }
560
- createTaskManager(runId, pipeline, executePipeline, getResult, plannerInstance, env, modeOverride) {
561
- const planner = plannerInstance ?? new CommandPlanner(pipeline);
562
- const builder = new CommandBuilder(executePipeline);
563
- const tester = new CommandTester(getResult);
564
- const reviewer = new CommandReviewer(getResult);
565
- const stateStore = new TaskStateStore({ outDir: env.outRoot, runsDir: env.runsRoot });
566
- const manifestWriter = new RunManifestWriter({ runsDir: env.runsRoot });
567
- const options = {
568
- planner,
569
- builder,
570
- tester,
571
- reviewer,
572
- runIdFactory: () => runId,
573
- modePolicy: (task, subtask) => this.determineMode(task, subtask, modeOverride),
574
- persistence: { autoStart: true, stateStore, manifestWriter }
575
- };
576
- return new TaskManager(options);
577
104
  }
578
- determineMode(task, subtask, overrideMode) {
579
- if (overrideMode) {
580
- return overrideMode;
581
- }
582
- if (this.requiresCloudExecution(task, subtask)) {
583
- return 'cloud';
584
- }
585
- return 'mcp';
586
- }
587
- requiresCloudExecution(task, subtask) {
588
- const requiresCloudFlag = resolveRequiresCloudPolicy({
589
- boolFlags: [subtask.requires_cloud, subtask.requiresCloud],
590
- metadata: {
591
- executionMode: typeof subtask.metadata?.executionMode === 'string'
592
- ? subtask.metadata.executionMode
593
- : null,
594
- mode: typeof subtask.metadata?.mode === 'string' ? subtask.metadata.mode : null
595
- },
596
- metadataOrder: ['executionMode', 'mode'],
597
- parseMode: CLI_EXECUTION_MODE_PARSER
105
+ async plan(options = {}) {
106
+ return await runOrchestratorPlanShell({
107
+ baseEnv: this.baseEnv,
108
+ options
598
109
  });
599
- if (requiresCloudFlag !== null) {
600
- return requiresCloudFlag;
601
- }
602
- return Boolean(task.metadata?.execution?.parallel);
603
110
  }
604
111
  async executePipeline(options) {
605
- const baseEnvOverrides = { ...(options.envOverrides ?? {}) };
606
- const mergedEnv = { ...process.env, ...baseEnvOverrides };
607
- let runtimeSelection;
608
- try {
609
- runtimeSelection = await resolveRuntimeSelection({
610
- requestedMode: options.runtimeModeRequested,
611
- source: options.runtimeModeSource,
612
- executionMode: options.mode,
613
- repoRoot: options.env.repoRoot,
614
- env: mergedEnv,
615
- runId: options.manifest.run_id
616
- });
617
- }
618
- catch (error) {
619
- const detail = `Runtime selection failed: ${error?.message ?? String(error)}`;
620
- finalizeStatus(options.manifest, 'failed', 'runtime-selection-failed');
621
- appendSummary(options.manifest, detail);
622
- logger.error(detail);
623
- return {
624
- success: false,
625
- notes: [detail],
626
- manifest: options.manifest,
627
- manifestPath: options.paths.manifestPath,
628
- logPath: options.paths.logPath
629
- };
630
- }
631
- this.applyRuntimeSelection(options.manifest, runtimeSelection);
632
- const effectiveEnvOverrides = {
633
- ...baseEnvOverrides,
634
- ...runtimeSelection.env_overrides
635
- };
636
- const effectiveMergedEnv = { ...process.env, ...effectiveEnvOverrides };
637
- if (options.mode === 'cloud') {
638
- const environmentId = resolveCloudEnvironmentId(options.task, options.target, effectiveEnvOverrides);
639
- const branch = readCloudString(effectiveEnvOverrides.CODEX_CLOUD_BRANCH) ??
640
- readCloudString(process.env.CODEX_CLOUD_BRANCH);
641
- const codexBin = resolveCodexCliBin(effectiveMergedEnv);
642
- const preflight = await runCloudPreflight({
643
- repoRoot: options.env.repoRoot,
644
- codexBin,
645
- environmentId,
646
- branch,
647
- env: effectiveMergedEnv
648
- });
649
- if (!preflight.ok) {
650
- if (!allowCloudFallback(effectiveEnvOverrides)) {
651
- const detail = `Cloud preflight failed and cloud fallback is disabled. ` +
652
- preflight.issues.map((issue) => issue.message).join(' ');
653
- finalizeStatus(options.manifest, 'failed', 'cloud-preflight-failed');
654
- appendSummary(options.manifest, detail);
655
- logger.error(detail);
656
- return {
657
- success: false,
658
- notes: [detail],
659
- manifest: options.manifest,
660
- manifestPath: options.paths.manifestPath,
661
- logPath: options.paths.logPath
662
- };
663
- }
664
- const detail = `Cloud preflight failed; falling back to mcp. ` +
665
- preflight.issues.map((issue) => issue.message).join(' ');
666
- options.manifest.cloud_fallback = {
667
- mode_requested: 'cloud',
668
- mode_used: 'mcp',
669
- reason: detail,
670
- issues: normalizeCloudFallbackIssues(preflight.issues),
671
- checked_at: isoTimestamp()
672
- };
673
- appendSummary(options.manifest, detail);
674
- logger.warn(detail);
675
- const fallback = await this.executePipeline({
676
- ...options,
677
- mode: 'mcp',
678
- executionModeOverride: 'mcp',
679
- runtimeModeRequested: runtimeSelection.selected_mode,
680
- runtimeModeSource: runtimeSelection.source,
681
- envOverrides: effectiveEnvOverrides
682
- });
683
- fallback.notes.unshift(detail);
684
- return fallback;
685
- }
686
- return await this.executeCloudPipeline({ ...options, envOverrides: effectiveEnvOverrides });
687
- }
688
- const { env, pipeline, manifest, paths, runEvents } = options;
689
- const notes = [];
690
- let success = true;
691
- manifest.guardrail_status = undefined;
692
- if (runtimeSelection.fallback.occurred) {
693
- const fallbackCode = runtimeSelection.fallback.code ?? 'runtime-fallback';
694
- const fallbackReason = runtimeSelection.fallback.reason ?? 'runtime fallback occurred';
695
- const fallbackSummary = `Runtime fallback (${fallbackCode}): ${fallbackReason}`;
696
- appendSummary(manifest, fallbackSummary);
697
- notes.push(fallbackSummary);
698
- }
699
- const advancedDecision = resolveAdvancedAutopilotDecision({
700
- pipelineId: pipeline.id,
701
- targetMetadata: (options.target.metadata ?? null),
702
- taskMetadata: (options.task.metadata ?? null),
703
- env: effectiveMergedEnv
704
- });
705
- if (advancedDecision.enabled || advancedDecision.source !== 'default') {
706
- const advancedSummary = `Advanced mode (${advancedDecision.mode}) ${advancedDecision.enabled ? 'enabled' : 'disabled'}: ${advancedDecision.reason}.`;
707
- appendSummary(manifest, advancedSummary);
708
- notes.push(advancedSummary);
709
- }
710
- const persister = options.persister ??
711
- new ManifestPersister({
712
- manifest,
713
- paths,
714
- persistIntervalMs: Math.max(1000, manifest.heartbeat_interval_seconds * 1000)
715
- });
716
- const schedulePersist = (options = {}) => persister.schedule(options);
717
- const pushHeartbeat = (forceManifest = false) => {
718
- updateHeartbeat(manifest);
719
- return schedulePersist({ manifest: forceManifest, heartbeat: true, force: forceManifest });
720
- };
721
- const controlWatcher = new ControlWatcher({
722
- paths,
723
- manifest,
724
- eventStream: options.eventStream,
725
- onEntry: options.onEventEntry,
726
- persist: () => schedulePersist({ manifest: true, force: true })
112
+ return executeOrchestratorPipelineRouteEntryShell({
113
+ options,
114
+ applyRuntimeSelection: applyRuntimeSelectionToManifest,
115
+ runAutoScout: this.runAutoScout.bind(this),
116
+ startPipeline: this.start.bind(this)
727
117
  });
728
- manifest.status = 'in_progress';
729
- updateHeartbeat(manifest);
730
- await schedulePersist({ manifest: true, heartbeat: true, force: true });
731
- runEvents?.runStarted(snapshotStages(manifest, pipeline), manifest.status);
732
- if (advancedDecision.autoScout) {
733
- const scoutOutcome = await this.runAutoScout({
734
- env,
735
- paths,
736
- manifest,
737
- mode: options.mode,
738
- pipeline,
739
- target: options.target,
740
- task: options.task,
741
- envOverrides: effectiveEnvOverrides,
742
- advancedDecision
743
- });
744
- const scoutMessage = scoutOutcome.status === 'recorded'
745
- ? `Auto scout: evidence recorded at ${scoutOutcome.path}.`
746
- : `Auto scout: ${scoutOutcome.message} (non-blocking).`;
747
- appendSummary(manifest, scoutMessage);
748
- notes.push(scoutMessage);
749
- await schedulePersist({ manifest: true, force: true });
750
- }
751
- const heartbeatInterval = setInterval(() => {
752
- void pushHeartbeat(false).catch((error) => {
753
- logger.warn(`Heartbeat update failed for run ${manifest.run_id}: ${error?.message ?? String(error)}`);
754
- });
755
- }, manifest.heartbeat_interval_seconds * 1000);
756
- try {
757
- for (let i = 0; i < pipeline.stages.length; i += 1) {
758
- await controlWatcher.sync();
759
- await controlWatcher.waitForResume();
760
- if (controlWatcher.isCanceled()) {
761
- manifest.status_detail = 'run-canceled';
762
- success = false;
763
- break;
764
- }
765
- const stage = pipeline.stages[i];
766
- const entry = manifest.commands[i];
767
- if (!entry) {
768
- continue;
769
- }
770
- if (entry.status === 'succeeded' || entry.status === 'skipped') {
771
- notes.push(`${stage.title}: ${entry.status}`);
772
- continue;
773
- }
774
- entry.status = 'pending';
775
- entry.started_at = isoTimestamp();
776
- void schedulePersist({ manifest: true });
777
- if (stage.kind === 'command') {
778
- try {
779
- const result = await runCommandStage({
780
- env,
781
- paths,
782
- manifest,
783
- stage,
784
- index: entry.index,
785
- events: runEvents,
786
- persister,
787
- envOverrides: effectiveEnvOverrides,
788
- runtimeMode: runtimeSelection.selected_mode,
789
- runtimeSessionId: runtimeSelection.runtime_session_id
790
- });
791
- notes.push(`${stage.title}: ${result.summary}`);
792
- const updatedEntry = manifest.commands[i];
793
- if (updatedEntry?.status === 'failed') {
794
- manifest.status_detail = `stage:${stage.id}:failed`;
795
- appendSummary(manifest, `Stage '${stage.title}' failed with exit code ${result.exitCode}.`);
796
- success = false;
797
- await schedulePersist({ manifest: true, force: true });
798
- break;
799
- }
800
- }
801
- catch (error) {
802
- entry.status = 'failed';
803
- entry.completed_at = isoTimestamp();
804
- entry.summary = `Execution error: ${error?.message ?? String(error)}`;
805
- manifest.status_detail = `stage:${stage.id}:error`;
806
- appendSummary(manifest, entry.summary);
807
- await schedulePersist({ manifest: true, force: true });
808
- runEvents?.stageCompleted({
809
- stageId: stage.id,
810
- stageIndex: entry.index,
811
- title: stage.title,
812
- kind: 'command',
813
- status: entry.status,
814
- exitCode: entry.exit_code,
815
- summary: entry.summary,
816
- logPath: entry.log_path
817
- });
818
- success = false;
819
- break;
820
- }
821
- }
822
- else {
823
- entry.status = 'running';
824
- await schedulePersist({ manifest: true, force: true });
825
- runEvents?.stageStarted({
826
- stageId: stage.id,
827
- stageIndex: entry.index,
828
- title: stage.title,
829
- kind: 'subpipeline',
830
- logPath: entry.log_path,
831
- status: entry.status
832
- });
833
- try {
834
- const child = await this.start({
835
- taskId: env.taskId,
836
- pipelineId: stage.pipeline,
837
- parentRunId: manifest.run_id,
838
- format: 'json',
839
- executionMode: options.executionModeOverride,
840
- runtimeMode: options.runtimeModeRequested
841
- });
842
- entry.completed_at = isoTimestamp();
843
- entry.sub_run_id = child.manifest.run_id;
844
- entry.summary = child.runSummary.review.summary ?? null;
845
- entry.status = child.manifest.status === 'succeeded' ? 'succeeded' : stage.optional ? 'skipped' : 'failed';
846
- entry.command = null;
847
- manifest.child_runs.push({
848
- run_id: child.manifest.run_id,
849
- pipeline_id: stage.pipeline,
850
- status: child.manifest.status,
851
- manifest: relativeToRepo(env, resolveRunPaths(env, child.manifest.run_id).manifestPath)
852
- });
853
- notes.push(`${stage.title}: ${entry.status}`);
854
- await schedulePersist({ manifest: true, force: true });
855
- runEvents?.stageCompleted({
856
- stageId: stage.id,
857
- stageIndex: entry.index,
858
- title: stage.title,
859
- kind: 'subpipeline',
860
- status: entry.status,
861
- exitCode: entry.exit_code,
862
- summary: entry.summary,
863
- logPath: entry.log_path,
864
- subRunId: entry.sub_run_id
865
- });
866
- if (!stage.optional && entry.status === 'failed') {
867
- manifest.status_detail = `subpipeline:${stage.pipeline}:failed`;
868
- appendSummary(manifest, `Sub-pipeline '${stage.pipeline}' failed.`);
869
- await schedulePersist({ manifest: true, force: true });
870
- success = false;
871
- break;
872
- }
873
- }
874
- catch (error) {
875
- entry.completed_at = isoTimestamp();
876
- entry.summary = `Sub-pipeline error: ${error?.message ?? String(error)}`;
877
- entry.status = stage.optional ? 'skipped' : 'failed';
878
- entry.command = null;
879
- manifest.status_detail = `subpipeline:${stage.pipeline}:error`;
880
- appendSummary(manifest, entry.summary);
881
- notes.push(`${stage.title}: ${entry.status}`);
882
- await schedulePersist({ manifest: true, force: true });
883
- runEvents?.stageCompleted({
884
- stageId: stage.id,
885
- stageIndex: entry.index,
886
- title: stage.title,
887
- kind: 'subpipeline',
888
- status: entry.status,
889
- exitCode: entry.exit_code,
890
- summary: entry.summary,
891
- logPath: entry.log_path,
892
- subRunId: entry.sub_run_id
893
- });
894
- if (!stage.optional) {
895
- success = false;
896
- break;
897
- }
898
- }
899
- }
900
- }
901
- }
902
- finally {
903
- clearInterval(heartbeatInterval);
904
- await schedulePersist({ force: true });
905
- }
906
- await controlWatcher.sync();
907
- if (controlWatcher.isCanceled()) {
908
- finalizeStatus(manifest, 'cancelled', manifest.status_detail ?? 'run-canceled');
909
- }
910
- else if (success) {
911
- finalizeStatus(manifest, 'succeeded');
912
- }
913
- else {
914
- finalizeStatus(manifest, 'failed', manifest.status_detail ?? 'pipeline-failed');
915
- }
916
- const guardrailStatus = ensureGuardrailStatus(manifest);
917
- if (guardrailStatus.recommendation) {
918
- appendSummary(manifest, guardrailStatus.recommendation);
919
- }
920
- updateHeartbeat(manifest);
921
- await schedulePersist({ manifest: true, heartbeat: true, force: true }).catch((error) => {
922
- logger.warn(`Heartbeat update failed for run ${manifest.run_id}: ${error?.message ?? String(error)}`);
923
- });
924
- await persistPipelineExperience({ env, pipeline, manifest, paths });
925
- await schedulePersist({ force: true });
926
- await appendMetricsEntry(env, paths, manifest, persister);
927
- return {
928
- success,
929
- notes,
930
- manifest,
931
- manifestPath: relativeToRepo(env, paths.manifestPath),
932
- logPath: relativeToRepo(env, paths.logPath)
933
- };
934
- }
935
- async executeCloudPipeline(options) {
936
- const { env, pipeline, manifest, paths, runEvents, target, task, envOverrides } = options;
937
- const notes = [];
938
- let success = true;
939
- manifest.guardrail_status = undefined;
940
- const persister = options.persister ??
941
- new ManifestPersister({
942
- manifest,
943
- paths,
944
- persistIntervalMs: Math.max(1000, manifest.heartbeat_interval_seconds * 1000)
945
- });
946
- const schedulePersist = (persistOptions = {}) => persister.schedule(persistOptions);
947
- const pushHeartbeat = (forceManifest = false) => {
948
- updateHeartbeat(manifest);
949
- return schedulePersist({ manifest: forceManifest, heartbeat: true, force: forceManifest });
950
- };
951
- const controlWatcher = new ControlWatcher({
952
- paths,
953
- manifest,
954
- eventStream: options.eventStream,
955
- onEntry: options.onEventEntry,
956
- persist: () => schedulePersist({ manifest: true, force: true })
957
- });
958
- manifest.status = 'in_progress';
959
- updateHeartbeat(manifest);
960
- await schedulePersist({ manifest: true, heartbeat: true, force: true });
961
- runEvents?.runStarted(snapshotStages(manifest, pipeline), manifest.status);
962
- const advancedDecision = resolveAdvancedAutopilotDecision({
963
- pipelineId: pipeline.id,
964
- targetMetadata: (target.metadata ?? null),
965
- taskMetadata: (task.metadata ?? null),
966
- env: { ...process.env, ...(envOverrides ?? {}) }
967
- });
968
- if (advancedDecision.enabled || advancedDecision.source !== 'default') {
969
- const advancedSummary = `Advanced mode (${advancedDecision.mode}) ${advancedDecision.enabled ? 'enabled' : 'disabled'}: ${advancedDecision.reason}.`;
970
- appendSummary(manifest, advancedSummary);
971
- notes.push(advancedSummary);
972
- await schedulePersist({ manifest: true, force: true });
973
- }
974
- if (advancedDecision.autoScout) {
975
- const scoutOutcome = await this.runAutoScout({
976
- env,
977
- paths,
978
- manifest,
979
- mode: options.mode,
980
- pipeline,
981
- target,
982
- task,
983
- envOverrides,
984
- advancedDecision
985
- });
986
- const scoutMessage = scoutOutcome.status === 'recorded'
987
- ? `Auto scout: evidence recorded at ${scoutOutcome.path}.`
988
- : `Auto scout: ${scoutOutcome.message} (non-blocking).`;
989
- appendSummary(manifest, scoutMessage);
990
- notes.push(scoutMessage);
991
- await schedulePersist({ manifest: true, force: true });
992
- }
993
- const heartbeatInterval = setInterval(() => {
994
- void pushHeartbeat(false).catch((error) => {
995
- logger.warn(`Heartbeat update failed for run ${manifest.run_id}: ${error?.message ?? String(error)}`);
996
- });
997
- }, manifest.heartbeat_interval_seconds * 1000);
998
- const targetStageId = this.resolveTargetStageId(target, pipeline);
999
- const targetStage = targetStageId
1000
- ? pipeline.stages.find((stage) => stage.id === targetStageId)
1001
- : undefined;
1002
- const targetEntry = targetStageId
1003
- ? manifest.commands.find((command) => command.id === targetStageId)
1004
- : undefined;
1005
- try {
1006
- await controlWatcher.sync();
1007
- await controlWatcher.waitForResume();
1008
- if (controlWatcher.isCanceled()) {
1009
- manifest.status_detail = 'run-canceled';
1010
- success = false;
1011
- }
1012
- else if (!targetStage || targetStage.kind !== 'command' || !targetEntry) {
1013
- success = false;
1014
- manifest.status_detail = 'cloud-target-missing';
1015
- const detail = targetStageId
1016
- ? `Cloud execution target "${targetStageId}" could not be resolved to a command stage.`
1017
- : `Cloud execution target "${target.id}" could not be resolved.`;
1018
- appendSummary(manifest, detail);
1019
- notes.push(detail);
1020
- }
1021
- else {
1022
- for (let i = 0; i < manifest.commands.length; i += 1) {
1023
- const entry = manifest.commands[i];
1024
- if (!entry || entry.id === targetStageId) {
1025
- continue;
1026
- }
1027
- entry.status = 'skipped';
1028
- entry.started_at = entry.started_at ?? isoTimestamp();
1029
- entry.completed_at = isoTimestamp();
1030
- entry.summary = `Skipped in cloud mode (target stage: ${targetStageId}).`;
1031
- }
1032
- const environmentId = resolveCloudEnvironmentId(task, target, envOverrides);
1033
- if (!environmentId) {
1034
- success = false;
1035
- manifest.status_detail = 'cloud-env-missing';
1036
- const detail = 'Cloud execution requested but no environment id is configured. Set CODEX_CLOUD_ENV_ID or provide target metadata.cloudEnvId.';
1037
- manifest.cloud_execution = {
1038
- task_id: null,
1039
- environment_id: null,
1040
- status: 'failed',
1041
- status_url: null,
1042
- submitted_at: null,
1043
- completed_at: isoTimestamp(),
1044
- last_polled_at: null,
1045
- poll_count: 0,
1046
- poll_interval_seconds: DEFAULT_CLOUD_POLL_INTERVAL_SECONDS,
1047
- timeout_seconds: DEFAULT_CLOUD_TIMEOUT_SECONDS,
1048
- attempts: DEFAULT_CLOUD_ATTEMPTS,
1049
- diff_path: null,
1050
- diff_url: null,
1051
- diff_status: 'unavailable',
1052
- apply_status: 'not_requested',
1053
- log_path: null,
1054
- error: detail
1055
- };
1056
- appendSummary(manifest, detail);
1057
- notes.push(detail);
1058
- targetEntry.status = 'failed';
1059
- targetEntry.started_at = targetEntry.started_at ?? isoTimestamp();
1060
- targetEntry.completed_at = isoTimestamp();
1061
- targetEntry.exit_code = 1;
1062
- targetEntry.summary = detail;
1063
- }
1064
- else {
1065
- targetEntry.status = 'running';
1066
- targetEntry.started_at = isoTimestamp();
1067
- await schedulePersist({ manifest: true, force: true });
1068
- runEvents?.stageStarted({
1069
- stageId: targetStage.id,
1070
- stageIndex: targetEntry.index,
1071
- title: targetStage.title,
1072
- kind: 'command',
1073
- logPath: targetEntry.log_path,
1074
- status: targetEntry.status
1075
- });
1076
- const executor = new CodexCloudTaskExecutor();
1077
- const prompt = this.buildCloudPrompt(task, target, pipeline, targetStage, manifest);
1078
- const pollIntervalSeconds = readCloudNumber(envOverrides?.CODEX_CLOUD_POLL_INTERVAL_SECONDS ?? process.env.CODEX_CLOUD_POLL_INTERVAL_SECONDS, DEFAULT_CLOUD_POLL_INTERVAL_SECONDS);
1079
- const timeoutSeconds = readCloudNumber(envOverrides?.CODEX_CLOUD_TIMEOUT_SECONDS ?? process.env.CODEX_CLOUD_TIMEOUT_SECONDS, DEFAULT_CLOUD_TIMEOUT_SECONDS);
1080
- const attempts = readCloudNumber(envOverrides?.CODEX_CLOUD_EXEC_ATTEMPTS ?? process.env.CODEX_CLOUD_EXEC_ATTEMPTS, DEFAULT_CLOUD_ATTEMPTS);
1081
- const statusRetryLimit = readCloudNumber(envOverrides?.CODEX_CLOUD_STATUS_RETRY_LIMIT ?? process.env.CODEX_CLOUD_STATUS_RETRY_LIMIT, DEFAULT_CLOUD_STATUS_RETRY_LIMIT);
1082
- const statusRetryBackoffMs = readCloudNumber(envOverrides?.CODEX_CLOUD_STATUS_RETRY_BACKOFF_MS ?? process.env.CODEX_CLOUD_STATUS_RETRY_BACKOFF_MS, DEFAULT_CLOUD_STATUS_RETRY_BACKOFF_MS);
1083
- const branch = readCloudString(envOverrides?.CODEX_CLOUD_BRANCH) ??
1084
- readCloudString(process.env.CODEX_CLOUD_BRANCH);
1085
- const enableFeatures = readCloudFeatureList(readCloudString(envOverrides?.CODEX_CLOUD_ENABLE_FEATURES) ??
1086
- readCloudString(process.env.CODEX_CLOUD_ENABLE_FEATURES));
1087
- const disableFeatures = readCloudFeatureList(readCloudString(envOverrides?.CODEX_CLOUD_DISABLE_FEATURES) ??
1088
- readCloudString(process.env.CODEX_CLOUD_DISABLE_FEATURES));
1089
- const codexBin = resolveCodexCliBin({ ...process.env, ...(envOverrides ?? {}) });
1090
- const cloudEnvOverrides = {
1091
- ...(envOverrides ?? {}),
1092
- CODEX_NON_INTERACTIVE: envOverrides?.CODEX_NON_INTERACTIVE ?? process.env.CODEX_NON_INTERACTIVE ?? '1',
1093
- CODEX_NO_INTERACTIVE: envOverrides?.CODEX_NO_INTERACTIVE ?? process.env.CODEX_NO_INTERACTIVE ?? '1',
1094
- CODEX_INTERACTIVE: envOverrides?.CODEX_INTERACTIVE ?? process.env.CODEX_INTERACTIVE ?? '0'
1095
- };
1096
- const cloudResult = await executor.execute({
1097
- codexBin,
1098
- prompt,
1099
- environmentId,
1100
- repoRoot: env.repoRoot,
1101
- runDir: paths.runDir,
1102
- pollIntervalSeconds,
1103
- timeoutSeconds,
1104
- attempts,
1105
- statusRetryLimit,
1106
- statusRetryBackoffMs,
1107
- branch,
1108
- enableFeatures,
1109
- disableFeatures,
1110
- env: cloudEnvOverrides,
1111
- onUpdate: async (cloudExecution) => {
1112
- manifest.cloud_execution = cloudExecution;
1113
- targetEntry.log_path = cloudExecution.log_path;
1114
- await schedulePersist({ manifest: true, force: true });
1115
- }
1116
- });
1117
- success = cloudResult.success;
1118
- notes.push(...cloudResult.notes);
1119
- manifest.cloud_execution = cloudResult.cloudExecution;
1120
- targetEntry.log_path = cloudResult.cloudExecution.log_path;
1121
- targetEntry.completed_at = isoTimestamp();
1122
- targetEntry.exit_code = cloudResult.success ? 0 : 1;
1123
- targetEntry.status = cloudResult.success ? 'succeeded' : 'failed';
1124
- targetEntry.summary = cloudResult.summary;
1125
- if (!cloudResult.success) {
1126
- manifest.status_detail = `cloud:${targetStage.id}:failed`;
1127
- appendSummary(manifest, cloudResult.summary);
1128
- }
1129
- await schedulePersist({ manifest: true, force: true });
1130
- runEvents?.stageCompleted({
1131
- stageId: targetStage.id,
1132
- stageIndex: targetEntry.index,
1133
- title: targetStage.title,
1134
- kind: 'command',
1135
- status: targetEntry.status,
1136
- exitCode: targetEntry.exit_code,
1137
- summary: targetEntry.summary,
1138
- logPath: targetEntry.log_path
1139
- });
1140
- }
1141
- }
1142
- }
1143
- finally {
1144
- clearInterval(heartbeatInterval);
1145
- await schedulePersist({ force: true });
1146
- }
1147
- await controlWatcher.sync();
1148
- if (controlWatcher.isCanceled()) {
1149
- finalizeStatus(manifest, 'cancelled', manifest.status_detail ?? 'run-canceled');
1150
- }
1151
- else if (success) {
1152
- finalizeStatus(manifest, 'succeeded');
1153
- }
1154
- else {
1155
- finalizeStatus(manifest, 'failed', manifest.status_detail ?? 'cloud-execution-failed');
1156
- }
1157
- updateHeartbeat(manifest);
1158
- await schedulePersist({ manifest: true, heartbeat: true, force: true }).catch((error) => {
1159
- logger.warn(`Heartbeat update failed for run ${manifest.run_id}: ${error?.message ?? String(error)}`);
1160
- });
1161
- await persistPipelineExperience({ env, pipeline, manifest, paths });
1162
- await schedulePersist({ force: true });
1163
- await appendMetricsEntry(env, paths, manifest, persister);
1164
- return {
1165
- success,
1166
- notes,
1167
- manifest,
1168
- manifestPath: relativeToRepo(env, paths.manifestPath),
1169
- logPath: relativeToRepo(env, paths.logPath)
1170
- };
1171
- }
1172
- resolveTargetStageId(target, pipeline) {
1173
- const metadataStageId = typeof target.metadata?.stageId === 'string' ? target.metadata.stageId : null;
1174
- if (metadataStageId && pipeline.stages.some((stage) => stage.id === metadataStageId)) {
1175
- return metadataStageId;
1176
- }
1177
- if (target.id.includes(':')) {
1178
- const suffix = target.id.split(':').pop() ?? null;
1179
- if (suffix && pipeline.stages.some((stage) => stage.id === suffix)) {
1180
- return suffix;
1181
- }
1182
- }
1183
- if (pipeline.stages.some((stage) => stage.id === target.id)) {
1184
- return target.id;
1185
- }
1186
- return null;
1187
- }
1188
- buildCloudPrompt(task, target, pipeline, stage, manifest) {
1189
- const lines = [
1190
- `Task ID: ${task.id}`,
1191
- `Task title: ${task.title}`,
1192
- task.description ? `Task description: ${task.description}` : null,
1193
- `Pipeline: ${pipeline.id}`,
1194
- `Target stage: ${stage.id} (${target.description})`,
1195
- '',
1196
- 'Apply the required repository changes for this target stage and produce a diff.'
1197
- ].filter((line) => Boolean(line));
1198
- lines.push(...buildCloudExperiencePromptLines({ manifest, pipeline, target, stage }));
1199
- return lines.join('\n');
1200
118
  }
1201
119
  async runAutoScout(params) {
1202
- const mergedEnv = { ...process.env, ...(params.envOverrides ?? {}) };
1203
- const timeoutMs = readCloudNumber(mergedEnv.CODEX_ORCHESTRATOR_AUTO_SCOUT_TIMEOUT_MS, DEFAULT_AUTO_SCOUT_TIMEOUT_MS);
1204
- const work = async () => {
1205
- const cloudEnvironmentId = resolveCloudEnvironmentId(params.task, params.target, params.envOverrides);
1206
- const cloudBranch = readCloudString(params.envOverrides?.CODEX_CLOUD_BRANCH) ??
1207
- readCloudString(process.env.CODEX_CLOUD_BRANCH);
1208
- const cloudRequested = params.mode === 'cloud' || params.manifest.cloud_fallback?.mode_requested === 'cloud';
1209
- const evidence = buildAutoScoutEvidence({
1210
- taskId: params.manifest.task_id,
1211
- pipelineId: params.pipeline.id,
1212
- targetId: params.target.id,
1213
- targetDescription: params.target.description,
1214
- executionMode: params.mode,
1215
- cloudRequested,
1216
- advanced: params.advancedDecision,
1217
- cloudEnvironmentId,
1218
- cloudBranch,
1219
- env: mergedEnv,
1220
- generatedAt: isoTimestamp()
1221
- });
1222
- const evidencePath = join(params.paths.runDir, 'auto-scout.json');
1223
- await writeJsonAtomic(evidencePath, evidence);
1224
- return { status: 'recorded', path: relativeToRepo(params.env, evidencePath) };
1225
- };
1226
- try {
1227
- let timeoutHandle = null;
1228
- const timeoutPromise = new Promise((resolve) => {
1229
- timeoutHandle = setTimeout(() => {
1230
- resolve({
1231
- status: 'timeout',
1232
- message: `timed out after ${Math.round(timeoutMs / 1000)}s`
1233
- });
1234
- }, timeoutMs);
1235
- timeoutHandle.unref?.();
1236
- });
1237
- const workPromise = work().catch((error) => ({
1238
- status: 'error',
1239
- message: error?.message ?? String(error)
1240
- }));
1241
- const result = await Promise.race([workPromise, timeoutPromise]);
1242
- if (timeoutHandle) {
1243
- clearTimeout(timeoutHandle);
1244
- }
1245
- return result;
1246
- }
1247
- catch (error) {
1248
- return {
1249
- status: 'error',
1250
- message: error?.message ?? String(error)
1251
- };
1252
- }
120
+ return await recordOrchestratorAutoScoutEvidence(params);
1253
121
  }
1254
122
  async performRunLifecycle(context) {
1255
- const { env, pipeline, manifest, paths, planner, taskContext, runId, persister, envOverrides, runtimeModeRequested, runtimeModeSource, executionModeOverride } = context;
1256
- let latestPipelineResult = null;
1257
- const executingByKey = new Map();
1258
- const executePipeline = async (input) => {
1259
- const key = `${input.mode}:${input.target.id}`;
1260
- const existing = executingByKey.get(key);
1261
- if (existing) {
1262
- return existing;
1263
- }
1264
- const executing = this.executePipeline({
1265
- env,
1266
- pipeline,
1267
- manifest,
1268
- paths,
1269
- mode: input.mode,
1270
- runtimeModeRequested,
1271
- runtimeModeSource,
1272
- executionModeOverride,
1273
- target: input.target,
1274
- task: taskContext,
1275
- runEvents: context.runEvents,
1276
- eventStream: context.eventStream,
1277
- onEventEntry: context.onEventEntry,
1278
- persister,
1279
- envOverrides
1280
- }).then((result) => {
1281
- latestPipelineResult = result;
1282
- return result;
1283
- });
1284
- executingByKey.set(key, executing);
1285
- return executing;
1286
- };
1287
- const getResult = () => latestPipelineResult;
1288
- const manager = this.createTaskManager(runId, pipeline, executePipeline, getResult, planner, env, executionModeOverride);
1289
- this.attachPlanTargetTracker(manager, manifest, paths, persister);
1290
- getPrivacyGuard().reset();
1291
- const controlPlaneResult = await this.controlPlane.guard({
1292
- env,
1293
- manifest,
1294
- paths,
1295
- pipeline,
1296
- task: taskContext,
1297
- runId,
1298
- requestedBy: { actorId: 'codex-cli', channel: 'cli', name: 'Codex CLI' },
1299
- persister
123
+ return await runOrchestratorRunLifecycle({
124
+ ...context,
125
+ executePipeline: (options) => this.executePipeline(options),
126
+ controlPlaneGuard: (options) => this.controlPlane.guard(options),
127
+ createSchedulerPlan: (options) => this.scheduler.createPlanForRun(options),
128
+ finalizePlan: (options) => this.scheduler.finalizePlan(options),
129
+ applySchedulerToRunSummary: (summary, plan) => this.scheduler.applySchedulerToRunSummary(summary, plan),
130
+ applyControlPlaneToRunSummary: (summary, result) => this.controlPlane.applyControlPlaneToRunSummary(summary, result)
1300
131
  });
1301
- const schedulerPlan = await this.scheduler.createPlanForRun({
1302
- env,
1303
- manifest,
1304
- paths,
1305
- controlPlaneResult,
1306
- persister
1307
- });
1308
- let runSummary;
1309
- try {
1310
- runSummary = await manager.execute(taskContext);
1311
- }
1312
- catch (error) {
1313
- context.runEvents?.runError({
1314
- pipelineId: pipeline.id,
1315
- message: error?.message ?? String(error),
1316
- stageId: null
1317
- });
1318
- throw error;
1319
- }
1320
- await this.scheduler.finalizePlan({
1321
- manifest,
1322
- paths,
1323
- plan: schedulerPlan,
1324
- persister
1325
- });
1326
- this.scheduler.applySchedulerToRunSummary(runSummary, schedulerPlan);
1327
- applyRuntimeToRunSummary(runSummary, manifest);
1328
- applyHandlesToRunSummary(runSummary, manifest);
1329
- applyPrivacyToRunSummary(runSummary, manifest);
1330
- applyCloudExecutionToRunSummary(runSummary, manifest);
1331
- applyCloudFallbackToRunSummary(runSummary, manifest);
1332
- applyUsageKpiToRunSummary(runSummary, manifest);
1333
- this.controlPlane.applyControlPlaneToRunSummary(runSummary, controlPlaneResult);
1334
- await persistRunSummary(env, paths, manifest, runSummary, persister);
1335
- context.runEvents?.runCompleted({
1336
- pipelineId: pipeline.id,
1337
- status: manifest.status,
1338
- manifestPath: paths.manifestPath,
1339
- runSummaryPath: manifest.run_summary_path,
1340
- metricsPath: join(env.runsRoot, env.taskId, 'metrics.json'),
1341
- summary: manifest.summary ?? null
1342
- });
1343
- return { manifest, runSummary };
1344
- }
1345
- attachPlanTargetTracker(manager, manifest, paths, persister) {
1346
- manager.bus.on('plan:completed', (event) => {
1347
- const targetId = event.payload.plan.targetId ?? null;
1348
- if (manifest.plan_target_id === targetId) {
1349
- return;
1350
- }
1351
- manifest.plan_target_id = targetId;
1352
- void persistManifest(paths, manifest, persister, { force: true }).catch((error) => {
1353
- logger.warn(`Failed to persist plan target for run ${manifest.run_id}: ${error?.message ?? String(error)}`);
1354
- });
1355
- });
1356
- }
1357
- applyRequestedRuntimeMode(manifest, mode) {
1358
- manifest.runtime_mode_requested = mode;
1359
- manifest.runtime_mode = mode;
1360
- manifest.runtime_provider = mode === 'appserver' ? 'AppServerRuntimeProvider' : 'CliRuntimeProvider';
1361
- manifest.runtime_fallback = {
1362
- occurred: false,
1363
- code: null,
1364
- reason: null,
1365
- from_mode: null,
1366
- to_mode: null,
1367
- checked_at: isoTimestamp()
1368
- };
1369
- }
1370
- applyRuntimeSelection(manifest, selection) {
1371
- manifest.runtime_mode_requested = selection.requested_mode;
1372
- manifest.runtime_mode = selection.selected_mode;
1373
- manifest.runtime_provider = selection.provider;
1374
- manifest.runtime_fallback = selection.fallback;
1375
- }
1376
- async validateResumeToken(paths, manifest, provided) {
1377
- let stored = manifest.resume_token;
1378
- if (!stored) {
1379
- try {
1380
- stored = (await readFile(paths.resumeTokenPath, 'utf8')).trim();
1381
- }
1382
- catch (error) {
1383
- throw new Error(`Resume token missing for run ${manifest.run_id}: ${error?.message ?? String(error)}`);
1384
- }
1385
- }
1386
- if (provided && stored !== provided) {
1387
- throw new Error('Resume token mismatch.');
1388
- }
1389
- }
1390
- buildStatusPayload(env, manifest, paths, activity) {
1391
- return {
1392
- run_id: manifest.run_id,
1393
- status: manifest.status,
1394
- status_detail: manifest.status_detail,
1395
- started_at: manifest.started_at,
1396
- completed_at: manifest.completed_at,
1397
- manifest: relativeToRepo(env, paths.manifestPath),
1398
- artifact_root: manifest.artifact_root,
1399
- log_path: manifest.log_path,
1400
- heartbeat_at: manifest.heartbeat_at,
1401
- activity,
1402
- commands: manifest.commands,
1403
- child_runs: manifest.child_runs,
1404
- runtime_mode_requested: manifest.runtime_mode_requested,
1405
- runtime_mode: manifest.runtime_mode,
1406
- runtime_provider: manifest.runtime_provider,
1407
- runtime_fallback: manifest.runtime_fallback ?? null,
1408
- cloud_execution: manifest.cloud_execution ?? null,
1409
- cloud_fallback: manifest.cloud_fallback ?? null
1410
- };
1411
- }
1412
- renderStatus(manifest, activity) {
1413
- logger.info(`Run: ${manifest.run_id}`);
1414
- logger.info(`Status: ${manifest.status}${manifest.status_detail ? ` (${manifest.status_detail})` : ''}`);
1415
- logger.info(`Started: ${manifest.started_at}`);
1416
- logger.info(`Completed: ${manifest.completed_at ?? 'in-progress'}`);
1417
- logger.info(`Manifest: ${manifest.artifact_root}/manifest.json`);
1418
- if (manifest.runtime_mode || manifest.runtime_mode_requested || manifest.runtime_provider) {
1419
- const selectedMode = manifest.runtime_mode ?? 'unknown';
1420
- logger.info(`Runtime: ${selectedMode}${manifest.runtime_mode_requested ? ` (requested ${manifest.runtime_mode_requested})` : ''}` +
1421
- (manifest.runtime_provider ? ` via ${manifest.runtime_provider}` : ''));
1422
- }
1423
- if (manifest.runtime_fallback?.occurred) {
1424
- const fallbackCode = manifest.runtime_fallback.code ?? 'runtime-fallback';
1425
- logger.info(`Runtime fallback: ${fallbackCode} — ${manifest.runtime_fallback.reason ?? 'n/a'}`);
1426
- }
1427
- if (activity.observed_at) {
1428
- const staleSuffix = activity.stale === null ? '' : activity.stale ? ' [stale]' : ' [active]';
1429
- const sourceLabel = activity.observed_source ? ` via ${activity.observed_source}` : '';
1430
- const ageLabel = activity.age_seconds === null ? '' : ` age=${activity.age_seconds}s`;
1431
- logger.info(`Activity: ${activity.observed_at}${sourceLabel}${ageLabel}${staleSuffix}`);
1432
- }
1433
- if (manifest.cloud_execution?.task_id) {
1434
- logger.info(`Cloud: ${manifest.cloud_execution.task_id} [${manifest.cloud_execution.status}]` +
1435
- (manifest.cloud_execution.status_url ? ` ${manifest.cloud_execution.status_url}` : ''));
1436
- }
1437
- logger.info('Commands:');
1438
- for (const command of manifest.commands) {
1439
- const summary = command.summary ? ` — ${command.summary}` : '';
1440
- logger.info(` [${command.status}] ${command.title}${summary}`);
1441
- }
1442
132
  }
1443
133
  }