@kbediako/codex-orchestrator 0.1.38 → 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 (299) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +70 -301
  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 +119 -15
  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 +667 -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 +20 -10
  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 +394 -0
  282. package/skills/collab-subagents-first/SKILL.md +1 -1
  283. package/skills/delegation-usage/DELEGATION_GUIDE.md +24 -11
  284. package/skills/delegation-usage/SKILL.md +19 -13
  285. package/skills/land/SKILL.md +77 -0
  286. package/skills/linear/SKILL.md +255 -0
  287. package/skills/release/SKILL.md +47 -3
  288. package/skills/standalone-review/SKILL.md +6 -1
  289. package/templates/README.md +4 -2
  290. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  291. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  292. package/templates/codex/.codex/config.toml +3 -4
  293. package/templates/codex/.codex/providers/README.md +13 -0
  294. package/templates/codex/.codex/providers/control.example.json +18 -0
  295. package/templates/codex/.codex/providers/provider.env.example +15 -0
  296. package/templates/codex/AGENTS.md +12 -7
  297. package/templates/codex/mcp-client.json +5 -1
  298. package/docs/README.md +0 -310
  299. package/docs/assets/setup.gif +0 -0
@@ -1,50 +1,86 @@
1
1
  #!/usr/bin/env node
2
- import { spawn } from 'node:child_process';
3
- import { existsSync } from 'node:fs';
4
- import { opendir, readFile } from 'node:fs/promises';
5
- import { basename, join } from 'node:path';
2
+ import { existsSync, realpathSync } from 'node:fs';
3
+ import { opendir } from 'node:fs/promises';
4
+ import { basename, join, resolve } from 'node:path';
6
5
  import process from 'node:process';
7
- import { fileURLToPath } from 'node:url';
6
+ import { pathToFileURL } from 'node:url';
8
7
  import { CodexOrchestrator } from '../orchestrator/src/cli/orchestrator.js';
9
- import { formatPlanPreview } from '../orchestrator/src/cli/utils/planFormatter.js';
10
- import { executeExecCommand } from '../orchestrator/src/cli/exec/command.js';
8
+ import { runExecCliShell } from '../orchestrator/src/cli/execCliShell.js';
11
9
  import { resolveEnvironmentPaths } from '../scripts/lib/run-manifests.js';
12
- import { runPrWatchMerge } from '../scripts/lib/pr-watch-merge.js';
13
- import { normalizeEnvironmentPaths, sanitizeTaskId } from '../orchestrator/src/cli/run/environment.js';
10
+ import { sanitizeTaskId } from '../orchestrator/src/cli/run/environment.js';
14
11
  import { RunEventEmitter } from '../orchestrator/src/cli/events/runEvents.js';
15
12
  import { evaluateInteractiveGate } from '../orchestrator/src/cli/utils/interactive.js';
16
13
  import { buildSelfCheckResult } from '../orchestrator/src/cli/selfCheck.js';
17
- import { initCodexTemplates, formatInitSummary } from '../orchestrator/src/cli/init.js';
18
- import { runDoctor, runDoctorCloudPreflight, formatDoctorSummary, formatDoctorCloudPreflightSummary } from '../orchestrator/src/cli/doctor.js';
19
- import { formatDoctorUsageSummary, runDoctorUsage } from '../orchestrator/src/cli/doctorUsage.js';
14
+ import { runDoctor } from '../orchestrator/src/cli/doctor.js';
15
+ import { runDoctorUsage } from '../orchestrator/src/cli/doctorUsage.js';
20
16
  import { formatDoctorIssueLogSummary, writeDoctorIssueLog } from '../orchestrator/src/cli/doctorIssueLog.js';
21
- import { formatDevtoolsSetupSummary, runDevtoolsSetup } from '../orchestrator/src/cli/devtoolsSetup.js';
22
- import { formatCodexCliSetupSummary, runCodexCliSetup } from '../orchestrator/src/cli/codexCliSetup.js';
23
- import { formatCodexDefaultsSetupSummary, runCodexDefaultsSetup } from '../orchestrator/src/cli/codexDefaultsSetup.js';
24
- import { formatDelegationSetupSummary, runDelegationSetup } from '../orchestrator/src/cli/delegationSetup.js';
25
- import { formatSkillsInstallSummary, installSkills, listBundledSkills } from '../orchestrator/src/cli/skills.js';
26
- import { findPackageRoot, loadPackageInfo } from '../orchestrator/src/cli/utils/packageInfo.js';
17
+ import { runInitCliShell } from '../orchestrator/src/cli/initCliShell.js';
18
+ import { runCodexCliShell } from '../orchestrator/src/cli/codexCliShell.js';
19
+ import { runDevtoolsCliShell } from '../orchestrator/src/cli/devtoolsCliShell.js';
20
+ import { runDelegationCliShell } from '../orchestrator/src/cli/delegationCliShell.js';
21
+ import { runLinearCliShell } from '../orchestrator/src/cli/linearCliShell.js';
22
+ import { runSkillsCliShell } from '../orchestrator/src/cli/skillsCliShell.js';
23
+ import { runFlowCliRequestShell } from '../orchestrator/src/cli/flowCliRequestShell.js';
24
+ import { runStartCliRequestShell } from '../orchestrator/src/cli/startCliRequestShell.js';
25
+ import { runFrontendTestCliRequestShell } from '../orchestrator/src/cli/frontendTestCliRequestShell.js';
26
+ import { runPlanCliShell } from '../orchestrator/src/cli/planCliShell.js';
27
+ import { runDoctorCliRequestShell } from '../orchestrator/src/cli/doctorCliRequestShell.js';
28
+ import { runRlmCliRequestShell } from '../orchestrator/src/cli/rlmCliRequestShell.js';
29
+ import { runRlmCompletionCliShell } from '../orchestrator/src/cli/rlmCompletionCliShell.js';
30
+ import { runResumeCliShell } from '../orchestrator/src/cli/resumeCliShell.js';
31
+ import { runStatusCliShell } from '../orchestrator/src/cli/statusCliShell.js';
32
+ import { runSelfCheckCliShell } from '../orchestrator/src/cli/selfCheckCliShell.js';
33
+ import { printSetupCliHelp, runSetupCliShell } from '../orchestrator/src/cli/setupCliShell.js';
34
+ import { runReviewCliLaunchShell } from '../orchestrator/src/cli/reviewCliLaunchShell.js';
35
+ import { loadPackageInfo } from '../orchestrator/src/cli/utils/packageInfo.js';
27
36
  import { slugify } from '../orchestrator/src/cli/utils/strings.js';
28
37
  import { serveMcp } from '../orchestrator/src/cli/mcp.js';
29
- import { formatMcpEnableSummary, runMcpEnable } from '../orchestrator/src/cli/mcpEnable.js';
30
- import { startDelegationServer } from '../orchestrator/src/cli/delegationServer.js';
31
- import { splitDelegationConfigOverrides } from '../orchestrator/src/cli/config/delegationConfig.js';
32
- import { buildCommandPreview } from '../orchestrator/src/cli/utils/commandPreview.js';
38
+ import { runMcpEnableCliShell } from '../orchestrator/src/cli/mcpEnableCliShell.js';
39
+ import { runDelegationServerCliShell } from '../orchestrator/src/cli/delegationServerCliShell.js';
40
+ import { DEFAULT_PROVIDER_START_PIPELINE_ID, runControlHostCliShell } from '../orchestrator/src/cli/controlHostCliShell.js';
41
+ import { runControlHostFreshnessGaugeCliShell } from '../orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js';
42
+ import { runControlHostSupervisionCliShell } from '../orchestrator/src/cli/controlHostSupervisionCliShell.js';
43
+ import { runCoStatusAttachCliShell } from '../orchestrator/src/cli/coStatusAttachCliShell.js';
44
+ import { runCoStatusCliShell } from '../orchestrator/src/cli/coStatusCliShell.js';
45
+ import { runCoStatusOperatorAutopilotCliShell } from '../orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js';
33
46
  import { REPO_CONFIG_REQUIRED_ENV_KEY } from '../orchestrator/src/cli/config/repoConfigPolicy.js';
34
47
  const AUTO_ISSUE_LOG_ENV_KEY = 'CODEX_ORCHESTRATOR_AUTO_ISSUE_LOG';
35
- async function main() {
36
- const args = process.argv.slice(2);
48
+ function writeStderrLine(message) {
49
+ process.stderr.write(`${message}\n`);
50
+ }
51
+ export function isDirectExecution(entryArg = process.argv[1], metaUrl = import.meta.url) {
52
+ if (typeof entryArg !== 'string' || entryArg.length === 0) {
53
+ return false;
54
+ }
55
+ const candidateUrls = new Set();
56
+ try {
57
+ candidateUrls.add(pathToFileURL(resolve(entryArg)).href);
58
+ }
59
+ catch {
60
+ // Fall through to the realpath check so missing/cwd issues still fail closed.
61
+ }
62
+ try {
63
+ candidateUrls.add(pathToFileURL(realpathSync(entryArg)).href);
64
+ }
65
+ catch {
66
+ // Missing or unreadable entry points should not be treated as direct execution.
67
+ }
68
+ return candidateUrls.has(metaUrl);
69
+ }
70
+ export async function runCodexOrchestratorCli(rawArgs = process.argv.slice(2)) {
71
+ process.exitCode = 0;
72
+ const args = [...rawArgs];
37
73
  const command = args.shift();
38
74
  if (!command || command === 'help' || command === '--help' || command === '-h') {
39
75
  printHelp();
40
- return;
76
+ return 0;
41
77
  }
42
78
  if (command === '--version' || command === '-v') {
43
79
  printVersion();
44
- return;
80
+ return 0;
45
81
  }
46
- const orchestrator = new CodexOrchestrator();
47
82
  try {
83
+ const orchestrator = new CodexOrchestrator();
48
84
  switch (command) {
49
85
  case 'start':
50
86
  await handleStart(orchestrator, args);
@@ -70,6 +106,12 @@ async function main() {
70
106
  case 'status':
71
107
  await handleStatus(orchestrator, args);
72
108
  break;
109
+ case 'control-host':
110
+ await handleControlHost(args);
111
+ break;
112
+ case 'co-status':
113
+ await handleCoStatus(args);
114
+ break;
73
115
  case 'exec':
74
116
  await handleExec(args);
75
117
  break;
@@ -88,6 +130,9 @@ async function main() {
88
130
  case 'codex':
89
131
  await handleCodex(args);
90
132
  break;
133
+ case 'linear':
134
+ await handleLinear(args);
135
+ break;
91
136
  case 'devtools':
92
137
  await handleDevtools(args);
93
138
  break;
@@ -111,15 +156,16 @@ async function main() {
111
156
  printVersion();
112
157
  break;
113
158
  default:
114
- console.error(`Unknown command: ${command}`);
159
+ writeStderrLine(`Unknown command: ${command}`);
115
160
  printHelp();
116
161
  process.exitCode = 1;
117
162
  }
118
163
  }
119
164
  catch (error) {
120
- console.error(error?.message ?? String(error));
165
+ writeStderrLine(error?.message ?? String(error));
121
166
  process.exitCode = 1;
122
167
  }
168
+ return typeof process.exitCode === 'number' ? process.exitCode : 0;
123
169
  }
124
170
  function parseArgs(raw) {
125
171
  const positionals = [];
@@ -128,6 +174,7 @@ function parseArgs(raw) {
128
174
  const booleanFlagKeys = new Set([
129
175
  'apply',
130
176
  'auto-issue-log',
177
+ 'blocked-by-source',
131
178
  'cloud',
132
179
  'cloud-preflight',
133
180
  'codex-cli',
@@ -206,132 +253,6 @@ function resolveTargetStageId(flags) {
206
253
  }
207
254
  return undefined;
208
255
  }
209
- const FLOW_TARGET_PIPELINE_SCOPES = new Set(['docs-review', 'implementation-gate']);
210
- function isFlowTargetPipelineScope(scope) {
211
- return FLOW_TARGET_PIPELINE_SCOPES.has(scope);
212
- }
213
- function normalizeFlowTargetToken(candidate) {
214
- const trimmed = candidate.trim();
215
- if (!trimmed) {
216
- return null;
217
- }
218
- const tokens = trimmed.split(':');
219
- if (tokens.length > 1 && !(tokens[0] ?? '').trim()) {
220
- return null;
221
- }
222
- let scoped = false;
223
- let scopeToken = null;
224
- let suffixToken = trimmed;
225
- if (tokens.length > 1) {
226
- const candidateScope = (tokens[0] ?? '').trim().toLowerCase();
227
- if (isFlowTargetPipelineScope(candidateScope)) {
228
- scoped = true;
229
- scopeToken = candidateScope;
230
- suffixToken = (tokens[tokens.length - 1] ?? '').trim();
231
- }
232
- }
233
- if (!suffixToken) {
234
- return null;
235
- }
236
- return {
237
- literal: trimmed,
238
- literalLower: trimmed.toLowerCase(),
239
- stageTokenLower: suffixToken.toLowerCase(),
240
- scopeLower: scopeToken,
241
- scoped
242
- };
243
- }
244
- function flowPlanItemPipelineId(item) {
245
- const metadataPipelineId = item.metadata && typeof item.metadata['pipelineId'] === 'string'
246
- ? item.metadata['pipelineId'].trim().toLowerCase()
247
- : '';
248
- if (metadataPipelineId) {
249
- return metadataPipelineId;
250
- }
251
- const delimiterIndex = item.id.indexOf(':');
252
- if (delimiterIndex <= 0) {
253
- return null;
254
- }
255
- return item.id.slice(0, delimiterIndex).trim().toLowerCase() || null;
256
- }
257
- function flowPlanItemMatchesTarget(item, candidate) {
258
- const normalized = normalizeFlowTargetToken(candidate);
259
- if (!normalized) {
260
- return false;
261
- }
262
- if (item.id.toLowerCase() === normalized.literalLower) {
263
- return true;
264
- }
265
- if (normalized.scoped && normalized.scopeLower) {
266
- const itemPipelineId = flowPlanItemPipelineId(item);
267
- if (itemPipelineId && itemPipelineId !== normalized.scopeLower) {
268
- return false;
269
- }
270
- }
271
- const metadataStageId = item.metadata && typeof item.metadata['stageId'] === 'string'
272
- ? item.metadata['stageId'].toLowerCase()
273
- : null;
274
- const aliases = Array.isArray(item.metadata?.['aliases'])
275
- ? item.metadata?.['aliases']
276
- : [];
277
- const aliasTokens = aliases.filter((alias) => typeof alias === 'string')
278
- .map((alias) => alias.toLowerCase());
279
- if (normalized.scoped) {
280
- if (metadataStageId
281
- && (metadataStageId === normalized.literalLower || metadataStageId === normalized.stageTokenLower)) {
282
- return true;
283
- }
284
- return aliasTokens.some((alias) => alias === normalized.literalLower || alias === normalized.stageTokenLower);
285
- }
286
- if (item.id.toLowerCase().endsWith(`:${normalized.stageTokenLower}`)) {
287
- return true;
288
- }
289
- if (metadataStageId
290
- && (metadataStageId === normalized.stageTokenLower
291
- || metadataStageId.endsWith(`:${normalized.stageTokenLower}`))) {
292
- return true;
293
- }
294
- return aliasTokens.some((alias) => alias === normalized.stageTokenLower || alias.endsWith(`:${normalized.stageTokenLower}`));
295
- }
296
- function planIncludesStageId(plan, stageId) {
297
- if (!stageId.trim()) {
298
- return false;
299
- }
300
- return plan.plan.items.some((item) => flowPlanItemMatchesTarget(item, stageId));
301
- }
302
- function resolveFlowTargetScope(stageId) {
303
- const delimiterIndex = stageId.indexOf(':');
304
- if (delimiterIndex <= 0) {
305
- return null;
306
- }
307
- const scope = stageId.slice(0, delimiterIndex).trim().toLowerCase();
308
- if (!isFlowTargetPipelineScope(scope)) {
309
- return null;
310
- }
311
- return scope;
312
- }
313
- async function resolveFlowTargetStageSelection(orchestrator, taskId, requestedTargetStageId) {
314
- if (!requestedTargetStageId) {
315
- return {};
316
- }
317
- const [docsPlan, implementationPlan] = (await Promise.all([
318
- orchestrator.plan({ pipelineId: 'docs-review', taskId }),
319
- orchestrator.plan({ pipelineId: 'implementation-gate', taskId })
320
- ]));
321
- const requestedScope = resolveFlowTargetScope(requestedTargetStageId);
322
- const docsScopeMatch = !requestedScope || requestedScope === 'docs-review';
323
- const implementationScopeMatch = !requestedScope || requestedScope === 'implementation-gate';
324
- const docsReviewTargetStageId = docsScopeMatch && planIncludesStageId(docsPlan, requestedTargetStageId)
325
- ? requestedTargetStageId
326
- : undefined;
327
- const implementationGateTargetStageId = implementationScopeMatch && planIncludesStageId(implementationPlan, requestedTargetStageId)
328
- ? requestedTargetStageId
329
- : undefined;
330
- if (!docsReviewTargetStageId && !implementationGateTargetStageId) {
331
- throw new Error(`Target stage "${requestedTargetStageId}" is not defined in docs-review or implementation-gate.`);
332
- }
333
- return { docsReviewTargetStageId, implementationGateTargetStageId };
334
- }
335
256
  function readStringFlag(flags, key) {
336
257
  const value = flags[key];
337
258
  if (typeof value !== 'string') {
@@ -515,30 +436,6 @@ function resolveRlmTaskId(taskFlag) {
515
436
  const slug = slugify(repoName, 'adhoc');
516
437
  return sanitizeTaskId(`rlm-${slug}`);
517
438
  }
518
- async function waitForManifestCompletion(manifestPath, intervalMs = 2000) {
519
- const terminal = new Set(['succeeded', 'failed', 'cancelled']);
520
- while (true) {
521
- const raw = await readFile(manifestPath, 'utf8');
522
- const manifest = JSON.parse(raw);
523
- if (terminal.has(manifest.status)) {
524
- return manifest;
525
- }
526
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
527
- }
528
- }
529
- async function readRlmState(statePath) {
530
- try {
531
- const raw = await readFile(statePath, 'utf8');
532
- const parsed = JSON.parse(raw);
533
- if (!parsed?.final) {
534
- return null;
535
- }
536
- return { exitCode: parsed.final.exitCode, status: parsed.final.status };
537
- }
538
- catch {
539
- return null;
540
- }
541
- }
542
439
  async function maybeCaptureAutoIssueLog(params) {
543
440
  if (!params.enabled) {
544
441
  return { issueLog: null, issueLogError: null };
@@ -594,110 +491,52 @@ async function handleStart(orchestrator, rawArgs) {
594
491
  printStartHelp();
595
492
  return;
596
493
  }
597
- const pipelineId = positionals[0];
598
- const format = flags['format'] === 'json' ? 'json' : 'text';
599
- const executionMode = resolveExecutionModeFlag(flags);
600
- const runtimeMode = resolveRuntimeModeFlag(flags);
601
- applyRepoConfigRequiredPolicy(flags);
602
- const autoIssueLogEnabled = resolveAutoIssueLogEnabled(flags);
603
- if (pipelineId === 'rlm') {
604
- const goal = readStringFlag(flags, 'goal');
605
- const warnLegacyEnvAlias = shouldWarnLegacyMultiAgentEnv(flags, process.env);
606
- applyRlmEnvOverrides(flags, goal);
607
- if (warnLegacyEnvAlias) {
608
- console.warn('Warning: RLM_SYMBOLIC_COLLAB is a legacy alias; prefer RLM_SYMBOLIC_MULTI_AGENT.');
494
+ await runStartCliRequestShell({
495
+ orchestrator,
496
+ positionals,
497
+ flags,
498
+ runWithUi: async (format, action) => await withRunUi(flags, format, action),
499
+ emitRunOutput,
500
+ maybeCaptureAutoIssueLog,
501
+ resolveTaskFilter,
502
+ withAutoIssueLogContext,
503
+ maybeEmitRunAdoptionHint,
504
+ resolveExecutionModeFlag,
505
+ resolveRuntimeModeFlag,
506
+ applyRepoConfigRequiredPolicy,
507
+ resolveAutoIssueLogEnabled,
508
+ resolveTargetStageId,
509
+ readStringFlag,
510
+ shouldWarnLegacyMultiAgentEnv: (requestFlags) => shouldWarnLegacyMultiAgentEnv(requestFlags, process.env),
511
+ applyRlmEnvOverrides,
512
+ resolveRlmTaskId,
513
+ setTaskEnvironment: (taskId) => {
514
+ process.env.MCP_RUNNER_TASK_ID = taskId;
515
+ },
516
+ log: (line) => console.log(line),
517
+ warn: (line) => console.warn(line),
518
+ setExitCode: (code) => {
519
+ process.exitCode = code;
609
520
  }
610
- }
611
- let taskIdOverride = typeof flags['task'] === 'string' ? flags['task'] : undefined;
612
- try {
613
- await withRunUi(flags, format, async (runEvents) => {
614
- if (pipelineId === 'rlm') {
615
- taskIdOverride = resolveRlmTaskId(taskIdOverride);
616
- process.env.MCP_RUNNER_TASK_ID = taskIdOverride;
617
- if (format !== 'json') {
618
- console.log(`Task: ${taskIdOverride}`);
619
- }
620
- }
621
- const result = await orchestrator.start({
622
- pipelineId,
623
- taskId: taskIdOverride,
624
- parentRunId: typeof flags['parent-run'] === 'string' ? flags['parent-run'] : undefined,
625
- approvalPolicy: typeof flags['approval-policy'] === 'string' ? flags['approval-policy'] : undefined,
626
- targetStageId: resolveTargetStageId(flags),
627
- executionMode,
628
- runtimeMode,
629
- runEvents
630
- });
631
- const issueLogCapture = result.manifest.status !== 'succeeded'
632
- ? await maybeCaptureAutoIssueLog({
633
- enabled: autoIssueLogEnabled,
634
- issueTitle: `Auto issue log: start ${pipelineId ?? 'diagnostics'} failed`,
635
- issueNotes: `Automatic failure capture for run ${result.manifest.run_id} (${result.manifest.status}).`,
636
- taskFilter: resolveTaskFilter(result.manifest.task_id, taskIdOverride)
637
- })
638
- : { issueLog: null, issueLogError: null };
639
- emitRunOutput(result, format, 'Run started', issueLogCapture);
640
- if (result.manifest.status === 'failed' || result.manifest.status === 'cancelled') {
641
- process.exitCode = 1;
642
- }
643
- if (result.manifest.status === 'succeeded' && result.manifest.pipeline_id !== 'rlm') {
644
- await maybeEmitRunAdoptionHint({
645
- format,
646
- taskFilter: resolveTaskFilter(result.manifest.task_id, taskIdOverride)
647
- });
648
- }
649
- });
650
- }
651
- catch (error) {
652
- const issueLogCapture = await maybeCaptureAutoIssueLog({
653
- enabled: autoIssueLogEnabled,
654
- issueTitle: `Auto issue log: start ${pipelineId ?? 'diagnostics'} failed before run manifest`,
655
- issueNotes: 'Automatic failure capture for start setup failure before run manifest creation.',
656
- taskFilter: resolveTaskFilter(undefined, taskIdOverride)
657
- });
658
- throw withAutoIssueLogContext(error, issueLogCapture);
659
- }
521
+ });
660
522
  }
661
523
  async function handleFrontendTest(orchestrator, rawArgs) {
662
524
  const { positionals, flags } = parseArgs(rawArgs);
663
- const format = flags['format'] === 'json' ? 'json' : 'text';
664
- const devtools = Boolean(flags['devtools']);
665
- const runtimeMode = resolveRuntimeModeFlag(flags);
666
- applyRepoConfigRequiredPolicy(flags);
667
- if (positionals.length > 0) {
668
- console.error(`[frontend-test] ignoring extra arguments: ${positionals.join(' ')}`);
669
- }
670
- const originalDevtools = process.env.CODEX_REVIEW_DEVTOOLS;
671
- if (devtools) {
672
- process.env.CODEX_REVIEW_DEVTOOLS = '1';
673
- }
674
- try {
675
- await withRunUi(flags, format, async (runEvents) => {
676
- const result = await orchestrator.start({
677
- pipelineId: 'frontend-testing',
678
- taskId: typeof flags['task'] === 'string' ? flags['task'] : undefined,
679
- parentRunId: typeof flags['parent-run'] === 'string' ? flags['parent-run'] : undefined,
680
- approvalPolicy: typeof flags['approval-policy'] === 'string' ? flags['approval-policy'] : undefined,
681
- targetStageId: resolveTargetStageId(flags),
682
- runtimeMode,
683
- runEvents
684
- });
685
- emitRunOutput(result, format, 'Run started');
686
- if (result.manifest.status === 'failed' || result.manifest.status === 'cancelled') {
687
- process.exitCode = 1;
688
- }
689
- });
690
- }
691
- finally {
692
- if (devtools) {
693
- if (originalDevtools === undefined) {
694
- delete process.env.CODEX_REVIEW_DEVTOOLS;
695
- }
696
- else {
697
- process.env.CODEX_REVIEW_DEVTOOLS = originalDevtools;
698
- }
699
- }
525
+ if (isHelpRequest(positionals, flags)) {
526
+ printFrontendTestHelp();
527
+ return;
700
528
  }
529
+ await runFrontendTestCliRequestShell({
530
+ orchestrator,
531
+ positionals,
532
+ flags,
533
+ resolveRuntimeModeFlag,
534
+ applyRepoConfigRequiredPolicy,
535
+ resolveTargetStageId,
536
+ runWithUi: async (format, action) => await withRunUi(flags, format, action),
537
+ emitRunOutput,
538
+ warn: (line) => console.error(line)
539
+ });
701
540
  }
702
541
  async function handleFlow(orchestrator, rawArgs) {
703
542
  const { positionals, flags } = parseArgs(rawArgs);
@@ -705,174 +544,23 @@ async function handleFlow(orchestrator, rawArgs) {
705
544
  printFlowHelp();
706
545
  return;
707
546
  }
708
- if (positionals.length > 0) {
709
- throw new Error(`flow does not accept positional arguments: ${positionals.join(' ')}`);
710
- }
711
- const format = flags['format'] === 'json' ? 'json' : 'text';
712
- const executionMode = resolveExecutionModeFlag(flags);
713
- const runtimeMode = resolveRuntimeModeFlag(flags);
714
- applyRepoConfigRequiredPolicy(flags);
715
- const autoIssueLogEnabled = resolveAutoIssueLogEnabled(flags);
716
- const taskId = typeof flags['task'] === 'string' ? flags['task'] : undefined;
717
- const parentRunId = typeof flags['parent-run'] === 'string' ? flags['parent-run'] : undefined;
718
- const approvalPolicy = typeof flags['approval-policy'] === 'string' ? flags['approval-policy'] : undefined;
719
- const targetStageId = resolveTargetStageId(flags);
720
- try {
721
- const { docsReviewTargetStageId, implementationGateTargetStageId } = await resolveFlowTargetStageSelection(orchestrator, taskId, targetStageId);
722
- await withRunUi(flags, format, async (runEvents) => {
723
- const docsReviewResult = await orchestrator.start({
724
- pipelineId: 'docs-review',
725
- taskId,
726
- parentRunId,
727
- approvalPolicy,
728
- targetStageId: docsReviewTargetStageId,
729
- executionMode,
730
- runtimeMode,
731
- runEvents
732
- });
733
- const docsPayload = toRunOutputPayload(docsReviewResult);
734
- if (format === 'text') {
735
- emitRunOutput(docsReviewResult, format, 'Docs-review run');
736
- }
737
- if (docsReviewResult.manifest.status !== 'succeeded') {
738
- const issueLogCapture = await maybeCaptureAutoIssueLog({
739
- enabled: autoIssueLogEnabled,
740
- issueTitle: 'Auto issue log: flow docs-review failed',
741
- issueNotes: `Automatic failure capture for docs-review run ${docsReviewResult.manifest.run_id} (${docsReviewResult.manifest.status}).`,
742
- taskFilter: resolveTaskFilter(docsReviewResult.manifest.task_id, taskId)
743
- });
744
- process.exitCode = 1;
745
- if (format === 'json') {
746
- const payload = {
747
- status: docsReviewResult.manifest.status,
748
- failed_stage: 'docs-review',
749
- docs_review: docsPayload,
750
- implementation_gate: null,
751
- issue_log: issueLogCapture.issueLog,
752
- issue_log_error: issueLogCapture.issueLogError
753
- };
754
- console.log(JSON.stringify(payload, null, 2));
755
- }
756
- else {
757
- console.log('Flow halted: docs-review failed.');
758
- if (issueLogCapture.issueLog) {
759
- for (const line of formatDoctorIssueLogSummary(issueLogCapture.issueLog)) {
760
- console.log(line);
761
- }
762
- }
763
- if (issueLogCapture.issueLogError) {
764
- console.log(`Auto issue log: failed (${issueLogCapture.issueLogError})`);
765
- }
766
- }
767
- return;
768
- }
769
- const implementationGateResult = await orchestrator.start({
770
- pipelineId: 'implementation-gate',
771
- taskId,
772
- parentRunId: docsReviewResult.manifest.run_id,
773
- approvalPolicy,
774
- targetStageId: implementationGateTargetStageId,
775
- executionMode,
776
- runtimeMode,
777
- runEvents
778
- });
779
- const implementationPayload = toRunOutputPayload(implementationGateResult);
780
- const issueLogCapture = implementationGateResult.manifest.status !== 'succeeded'
781
- ? await maybeCaptureAutoIssueLog({
782
- enabled: autoIssueLogEnabled,
783
- issueTitle: 'Auto issue log: flow implementation-gate failed',
784
- issueNotes: `Automatic failure capture for implementation-gate run ${implementationGateResult.manifest.run_id} (${implementationGateResult.manifest.status}).`,
785
- taskFilter: resolveTaskFilter(implementationGateResult.manifest.task_id, taskId)
786
- })
787
- : { issueLog: null, issueLogError: null };
788
- if (format === 'json') {
789
- const payload = {
790
- status: implementationGateResult.manifest.status,
791
- failed_stage: implementationGateResult.manifest.status === 'succeeded' ? null : 'implementation-gate',
792
- docs_review: docsPayload,
793
- implementation_gate: implementationPayload,
794
- issue_log: issueLogCapture.issueLog,
795
- issue_log_error: issueLogCapture.issueLogError
796
- };
797
- console.log(JSON.stringify(payload, null, 2));
798
- if (implementationGateResult.manifest.status !== 'succeeded') {
799
- process.exitCode = 1;
800
- }
801
- return;
802
- }
803
- emitRunOutput(implementationGateResult, format, 'Implementation-gate run');
804
- if (implementationGateResult.manifest.status !== 'succeeded') {
805
- process.exitCode = 1;
806
- console.log('Flow halted: implementation-gate failed.');
807
- if (issueLogCapture.issueLog) {
808
- for (const line of formatDoctorIssueLogSummary(issueLogCapture.issueLog)) {
809
- console.log(line);
810
- }
811
- }
812
- if (issueLogCapture.issueLogError) {
813
- console.log(`Auto issue log: failed (${issueLogCapture.issueLogError})`);
814
- }
815
- return;
816
- }
817
- console.log('Flow complete: docs-review -> implementation-gate.');
818
- await maybeEmitRunAdoptionHint({
819
- format,
820
- taskFilter: resolveTaskFilter(implementationGateResult.manifest.task_id, taskId)
821
- });
822
- });
823
- }
824
- catch (error) {
825
- const issueLogCapture = await maybeCaptureAutoIssueLog({
826
- enabled: autoIssueLogEnabled,
827
- issueTitle: 'Auto issue log: flow failed before run manifest',
828
- issueNotes: 'Automatic failure capture for flow setup failure before run manifest creation.',
829
- taskFilter: resolveTaskFilter(undefined, taskId)
830
- });
831
- throw withAutoIssueLogContext(error, issueLogCapture);
832
- }
833
- }
834
- function runningFromSourceRuntime() {
835
- return fileURLToPath(import.meta.url).endsWith('.ts');
836
- }
837
- function resolveReviewRunner() {
838
- const packageRoot = findPackageRoot(import.meta.url);
839
- const sourceRunner = join(packageRoot, 'scripts', 'run-review.ts');
840
- const distRunner = join(packageRoot, 'dist', 'scripts', 'run-review.js');
841
- if (runningFromSourceRuntime() && existsSync(sourceRunner)) {
842
- return {
843
- command: process.execPath,
844
- args: ['--loader', 'ts-node/esm', sourceRunner]
845
- };
846
- }
847
- if (existsSync(distRunner)) {
848
- return {
849
- command: process.execPath,
850
- args: [distRunner]
851
- };
852
- }
853
- if (existsSync(sourceRunner)) {
854
- return {
855
- command: process.execPath,
856
- args: ['--loader', 'ts-node/esm', sourceRunner]
857
- };
858
- }
859
- throw new Error('Unable to locate review runner. Expected dist/scripts/run-review.js (npm) or scripts/run-review.ts (source checkout).');
860
- }
861
- async function runPassthroughCommand(command, args, options = {}) {
862
- return await new Promise((resolve, reject) => {
863
- const child = spawn(command, args, {
864
- env: options.env ?? process.env,
865
- cwd: options.cwd ?? process.cwd(),
866
- stdio: 'inherit'
867
- });
868
- child.once('error', (error) => reject(error instanceof Error ? error : new Error(String(error))));
869
- child.once('close', (code, signal) => {
870
- if (signal) {
871
- resolve(1);
872
- return;
873
- }
874
- resolve(typeof code === 'number' ? code : 1);
875
- });
547
+ await runFlowCliRequestShell({
548
+ orchestrator,
549
+ positionals,
550
+ flags,
551
+ runWithUi: async (format, action) => await withRunUi(flags, format, action),
552
+ emitRunOutput,
553
+ formatIssueLogSummary: formatDoctorIssueLogSummary,
554
+ toRunOutputPayload,
555
+ maybeCaptureAutoIssueLog,
556
+ resolveTaskFilter,
557
+ withAutoIssueLogContext,
558
+ maybeEmitRunAdoptionHint,
559
+ resolveExecutionModeFlag,
560
+ resolveRuntimeModeFlag,
561
+ applyRepoConfigRequiredPolicy,
562
+ resolveAutoIssueLogEnabled,
563
+ resolveTargetStageId
876
564
  });
877
565
  }
878
566
  async function handleReview(rawArgs) {
@@ -881,11 +569,7 @@ async function handleReview(rawArgs) {
881
569
  printReviewHelp();
882
570
  return;
883
571
  }
884
- const runner = resolveReviewRunner();
885
- const exitCode = await runPassthroughCommand(runner.command, [...runner.args, ...rawArgs], {
886
- cwd: process.cwd(),
887
- env: process.env
888
- });
572
+ const exitCode = await runReviewCliLaunchShell({ rawArgs });
889
573
  if (exitCode !== 0) {
890
574
  process.exitCode = exitCode;
891
575
  }
@@ -899,16 +583,13 @@ async function handlePlan(orchestrator, rawArgs) {
899
583
  applyRepoConfigRequiredPolicy(flags);
900
584
  const pipelineId = positionals[0];
901
585
  const format = flags['format'] === 'json' ? 'json' : 'text';
902
- const result = await orchestrator.plan({
586
+ await runPlanCliShell({
587
+ orchestrator,
903
588
  pipelineId,
904
589
  taskId: typeof flags['task'] === 'string' ? flags['task'] : undefined,
905
- targetStageId: resolveTargetStageId(flags)
590
+ targetStageId: resolveTargetStageId(flags),
591
+ format
906
592
  });
907
- if (format === 'json') {
908
- console.log(JSON.stringify(result, null, 2));
909
- return;
910
- }
911
- process.stdout.write(`${formatPlanPreview(result)}\n`);
912
593
  }
913
594
  async function handleRlm(orchestrator, rawArgs) {
914
595
  const { positionals, flags } = parseArgs(rawArgs);
@@ -916,64 +597,36 @@ async function handleRlm(orchestrator, rawArgs) {
916
597
  printRlmHelp();
917
598
  return;
918
599
  }
919
- const runtimeMode = resolveRuntimeModeFlag(flags);
920
- applyRepoConfigRequiredPolicy(flags);
921
- const goalFromArgs = positionals.length > 0 ? positionals.join(' ') : undefined;
922
- const goal = goalFromArgs ?? readStringFlag(flags, 'goal') ?? process.env.RLM_GOAL?.trim();
923
- if (!goal) {
924
- throw new Error('rlm requires a goal. Use: codex-orchestrator rlm \"<goal>\".');
925
- }
926
- const taskFlag = typeof flags['task'] === 'string' ? flags['task'] : undefined;
927
- const taskId = resolveRlmTaskId(taskFlag);
928
- process.env.MCP_RUNNER_TASK_ID = taskId;
929
- const warnLegacyEnvAlias = shouldWarnLegacyMultiAgentEnv(flags, process.env);
930
- applyRlmEnvOverrides(flags, goal);
931
- if (warnLegacyEnvAlias) {
932
- console.warn('Warning: RLM_SYMBOLIC_COLLAB is a legacy alias; prefer RLM_SYMBOLIC_MULTI_AGENT.');
933
- }
934
- console.log(`Task: ${taskId}`);
935
- const collabUserChoice = flags['collab'] !== undefined ||
936
- flags['multi-agent'] !== undefined ||
937
- process.env.RLM_SYMBOLIC_COLLAB !== undefined ||
938
- process.env.RLM_SYMBOLIC_MULTI_AGENT !== undefined;
939
- if (!collabUserChoice) {
940
- const doctor = runDoctor();
941
- if (doctor.collab.status === 'ok') {
942
- console.log('Tip: multi-agent collab is enabled. Try: codex-orchestrator rlm --multi-agent auto \"<goal>\" (legacy: --collab auto).');
943
- }
944
- else if (doctor.collab.status === 'disabled') {
945
- console.log('Tip: multi-agent collab is available but disabled. Enable with: codex features enable multi_agent (legacy alias: collab).');
946
- }
947
- }
948
- let startResult = null;
949
- await withRunUi(flags, 'text', async (runEvents) => {
950
- startResult = await orchestrator.start({
951
- pipelineId: 'rlm',
952
- taskId,
953
- parentRunId: typeof flags['parent-run'] === 'string' ? flags['parent-run'] : undefined,
954
- approvalPolicy: typeof flags['approval-policy'] === 'string' ? flags['approval-policy'] : undefined,
955
- runtimeMode,
956
- runEvents
957
- });
958
- emitRunOutput(startResult, 'text', 'Run started');
600
+ await runRlmCliRequestShell({
601
+ orchestrator,
602
+ positionals,
603
+ flags,
604
+ env: process.env,
605
+ runWithUi: async (action) => await withRunUi(flags, 'text', action),
606
+ emitRunOutput,
607
+ resolveRuntimeModeFlag,
608
+ applyRepoConfigRequiredPolicy,
609
+ readStringFlag,
610
+ applyRlmEnvOverrides,
611
+ shouldWarnLegacyEnvAlias: shouldWarnLegacyMultiAgentEnv,
612
+ resolveRlmTaskId,
613
+ setTaskEnvironment: (taskId) => {
614
+ process.env.MCP_RUNNER_TASK_ID = taskId;
615
+ },
616
+ runDoctor,
617
+ resolveRepoRoot: () => resolveEnvironmentPaths().repoRoot,
618
+ runCompletionShell: async ({ repoRoot, artifactRoot }) => await runRlmCompletionCliShell({
619
+ repoRoot,
620
+ artifactRoot,
621
+ log: (line) => console.log(line),
622
+ error: (line) => console.error(line),
623
+ setExitCode: (code) => {
624
+ process.exitCode = code;
625
+ }
626
+ }),
627
+ log: (line) => console.log(line),
628
+ warn: (line) => console.warn(line)
959
629
  });
960
- if (!startResult) {
961
- throw new Error('rlm run failed to start.');
962
- }
963
- const resolvedStart = startResult;
964
- const { repoRoot } = resolveEnvironmentPaths();
965
- const manifestPath = join(repoRoot, resolvedStart.manifest.artifact_root, 'manifest.json');
966
- const manifest = await waitForManifestCompletion(manifestPath);
967
- const statePath = join(repoRoot, resolvedStart.manifest.artifact_root, 'rlm', 'state.json');
968
- const rlmState = await readRlmState(statePath);
969
- if (rlmState) {
970
- console.log(`RLM status: ${rlmState.status}`);
971
- process.exitCode = rlmState.exitCode;
972
- return;
973
- }
974
- console.log(`RLM status: ${manifest.status}`);
975
- console.error('RLM state file missing; treating as internal error.');
976
- process.exitCode = 10;
977
630
  }
978
631
  async function handleResume(orchestrator, rawArgs) {
979
632
  const { positionals, flags } = parseArgs(rawArgs);
@@ -988,17 +641,17 @@ async function handleResume(orchestrator, rawArgs) {
988
641
  throw new Error('resume requires --run <run-id>.');
989
642
  }
990
643
  const format = flags['format'] === 'json' ? 'json' : 'text';
991
- await withRunUi(flags, format, async (runEvents) => {
992
- const result = await orchestrator.resume({
993
- runId,
994
- resumeToken: typeof flags['token'] === 'string' ? flags['token'] : undefined,
995
- actor: typeof flags['actor'] === 'string' ? flags['actor'] : undefined,
996
- reason: typeof flags['reason'] === 'string' ? flags['reason'] : undefined,
997
- targetStageId: resolveTargetStageId(flags),
998
- runtimeMode,
999
- runEvents
1000
- });
1001
- emitRunOutput(result, format, 'Run resumed');
644
+ await runResumeCliShell({
645
+ orchestrator,
646
+ runId,
647
+ format,
648
+ runtimeMode,
649
+ resumeToken: typeof flags['token'] === 'string' ? flags['token'] : undefined,
650
+ actor: typeof flags['actor'] === 'string' ? flags['actor'] : undefined,
651
+ reason: typeof flags['reason'] === 'string' ? flags['reason'] : undefined,
652
+ targetStageId: resolveTargetStageId(flags),
653
+ runWithUi: async (action) => await withRunUi(flags, format, action),
654
+ emitRunOutput
1002
655
  });
1003
656
  }
1004
657
  async function handleStatus(orchestrator, rawArgs) {
@@ -1014,18 +667,84 @@ async function handleStatus(orchestrator, rawArgs) {
1014
667
  const watch = Boolean(flags['watch']);
1015
668
  const format = flags['format'] === 'json' ? 'json' : 'text';
1016
669
  const interval = parseInt(flags['interval'] ?? '10', 10);
1017
- if (!watch) {
1018
- await orchestrator.status({ runId, format });
670
+ await runStatusCliShell({ orchestrator, runId, watch, format, interval });
671
+ }
672
+ async function handleControlHost(rawArgs) {
673
+ if (rawArgs[0] === 'freshness-gauge') {
674
+ const { positionals, flags } = parseArgs(rawArgs.slice(1));
675
+ if (isHelpRequest(positionals, flags)) {
676
+ printControlHostFreshnessGaugeHelp();
677
+ return;
678
+ }
679
+ if (positionals.length > 0) {
680
+ throw new Error(`Unknown control-host freshness-gauge argument(s): ${positionals.join(' ')}`);
681
+ }
682
+ await runControlHostFreshnessGaugeCliShell({
683
+ flags,
684
+ printHelp: printControlHostFreshnessGaugeHelp
685
+ });
1019
686
  return;
1020
687
  }
1021
- const terminal = new Set(['succeeded', 'failed', 'cancelled']);
1022
- while (true) {
1023
- const manifest = await orchestrator.status({ runId, format });
1024
- if (terminal.has(manifest.status)) {
1025
- break;
688
+ if (rawArgs[0] === 'supervise') {
689
+ const { positionals, flags } = parseArgs(rawArgs.slice(1));
690
+ await runControlHostSupervisionCliShell({
691
+ positionals,
692
+ flags,
693
+ printHelp: printControlHostSupervisionHelp
694
+ });
695
+ return;
696
+ }
697
+ const { positionals, flags } = parseArgs(rawArgs);
698
+ if (isHelpRequest(positionals, flags)) {
699
+ printControlHostHelp();
700
+ return;
701
+ }
702
+ if (positionals.length > 0) {
703
+ throw new Error(`Unknown control-host argument(s): ${positionals.join(' ')}`);
704
+ }
705
+ await runControlHostCliShell({
706
+ flags,
707
+ printHelp: printControlHostHelp
708
+ });
709
+ }
710
+ async function handleCoStatus(rawArgs) {
711
+ if (rawArgs[0] === 'operator-autopilot') {
712
+ const { positionals, flags } = parseArgs(rawArgs.slice(1));
713
+ if (isHelpRequest(positionals, flags)) {
714
+ printCoStatusOperatorAutopilotHelp();
715
+ return;
716
+ }
717
+ await runCoStatusOperatorAutopilotCliShell({
718
+ positionals,
719
+ flags,
720
+ printHelp: printCoStatusOperatorAutopilotHelp
721
+ });
722
+ return;
723
+ }
724
+ if (rawArgs[0] === 'attach') {
725
+ const { positionals, flags } = parseArgs(rawArgs.slice(1));
726
+ if (isHelpRequest(positionals, flags)) {
727
+ printCoStatusAttachHelp();
728
+ return;
1026
729
  }
1027
- await new Promise((resolve) => setTimeout(resolve, interval * 1000));
730
+ if (positionals.length > 0) {
731
+ throw new Error(`Unknown co-status attach argument(s): ${positionals.join(' ')}`);
732
+ }
733
+ await runCoStatusAttachCliShell({
734
+ flags,
735
+ printHelp: printCoStatusAttachHelp
736
+ });
737
+ return;
1028
738
  }
739
+ const { positionals, flags } = parseArgs(rawArgs);
740
+ if (isHelpRequest(positionals, flags)) {
741
+ printCoStatusHelp();
742
+ return;
743
+ }
744
+ await runCoStatusCliShell({
745
+ flags,
746
+ printHelp: printCoStatusHelp
747
+ });
1029
748
  }
1030
749
  async function maybeStartHud(gate, emitter) {
1031
750
  if (!gate.enabled) {
@@ -1111,40 +830,9 @@ function toRunOutputPayload(result, issueLogCapture = { issueLog: null, issueLog
1111
830
  };
1112
831
  }
1113
832
  async function handleExec(rawArgs) {
1114
- const parsed = parseExecArgs(rawArgs);
1115
- if (parsed.commandTokens.length === 0) {
1116
- throw new Error('exec requires a command to run.');
1117
- }
1118
- const isInteractive = process.stdout.isTTY === true && process.stderr.isTTY === true;
1119
- const outputMode = parsed.requestedMode ?? (isInteractive ? 'interactive' : 'jsonl');
1120
- const env = normalizeEnvironmentPaths(resolveEnvironmentPaths());
1121
- if (parsed.taskId) {
1122
- env.taskId = sanitizeTaskId(parsed.taskId);
1123
- }
1124
- const context = {
1125
- env,
1126
- stdout: process.stdout,
1127
- stderr: process.stderr
1128
- };
1129
- const invocation = {
1130
- command: parsed.commandTokens[0],
1131
- args: parsed.commandTokens.slice(1),
1132
- cwd: parsed.cwd,
1133
- outputMode,
1134
- notifyTargets: parsed.notifyTargets,
1135
- otelEndpoint: parsed.otelEndpoint,
1136
- jsonPretty: parsed.jsonPretty
1137
- };
1138
- const result = await executeExecCommand(context, invocation);
1139
- if (result.exitCode !== null) {
1140
- process.exitCode = result.exitCode;
1141
- }
1142
- else if (result.status !== 'succeeded') {
1143
- process.exitCode = 1;
1144
- }
1145
- if (outputMode === 'interactive') {
1146
- await maybeEmitExecAdoptionHint(env.taskId);
1147
- }
833
+ await runExecCliShell(parseExecArgs(rawArgs), {
834
+ maybeEmitAdoptionHint: maybeEmitExecAdoptionHint
835
+ });
1148
836
  }
1149
837
  async function shouldScanAdoptionHint(taskFilter) {
1150
838
  if (!taskFilter) {
@@ -1204,16 +892,11 @@ async function maybeEmitExecAdoptionHint(taskFilter) {
1204
892
  async function handleSelfCheck(rawArgs) {
1205
893
  const { flags } = parseArgs(rawArgs);
1206
894
  const format = flags['format'] === 'json' ? 'json' : 'text';
1207
- const result = buildSelfCheckResult();
1208
- if (format === 'json') {
1209
- console.log(JSON.stringify(result, null, 2));
1210
- return;
1211
- }
1212
- console.log(`Status: ${result.status}`);
1213
- console.log(`Name: ${result.name}`);
1214
- console.log(`Version: ${result.version}`);
1215
- console.log(`Node: ${result.node}`);
1216
- console.log(`Timestamp: ${result.timestamp}`);
895
+ await runSelfCheckCliShell({
896
+ format,
897
+ buildResult: buildSelfCheckResult,
898
+ log: (line) => console.log(line)
899
+ });
1217
900
  }
1218
901
  async function handleInit(rawArgs) {
1219
902
  const { positionals, flags } = parseArgs(rawArgs);
@@ -1221,439 +904,46 @@ async function handleInit(rawArgs) {
1221
904
  printInitHelp();
1222
905
  return;
1223
906
  }
1224
- const template = positionals[0];
1225
- if (!template) {
1226
- throw new Error('init requires a template name (e.g. init codex).');
1227
- }
1228
- if (template !== 'codex') {
1229
- throw new Error(`Unknown init template: ${template}`);
1230
- }
1231
- const cwd = typeof flags['cwd'] === 'string' ? flags['cwd'] : process.cwd();
1232
- const force = Boolean(flags['force']);
1233
- const result = await initCodexTemplates({ template, cwd, force });
1234
- const summary = formatInitSummary(result, cwd);
1235
- for (const line of summary) {
1236
- console.log(line);
1237
- }
1238
- if (flags['codex-cli'] === true) {
1239
- const apply = Boolean(flags['yes']);
1240
- const source = readStringFlag(flags, 'codex-source');
1241
- const ref = readStringFlag(flags, 'codex-ref');
1242
- const downloadUrl = readStringFlag(flags, 'codex-download-url');
1243
- const downloadSha256 = readStringFlag(flags, 'codex-download-sha256');
1244
- const cliForce = Boolean(flags['codex-force']);
1245
- const setupResult = await runCodexCliSetup({
1246
- apply,
1247
- force: cliForce,
1248
- source,
1249
- ref,
1250
- downloadUrl,
1251
- downloadSha256
1252
- });
1253
- for (const line of formatCodexCliSetupSummary(setupResult)) {
1254
- console.log(line);
1255
- }
1256
- }
907
+ await runInitCliShell({ positionals, flags });
1257
908
  }
1258
909
  async function handleSetup(rawArgs) {
1259
910
  const { positionals, flags } = parseArgs(rawArgs);
1260
911
  if (isHelpRequest(positionals, flags)) {
1261
- console.log(`Usage: codex-orchestrator setup [--yes] [--refresh-skills] [--format json]
1262
-
1263
- One-shot bootstrap for downstream users. Installs bundled skills and configures
1264
- delegation + DevTools MCP wiring.
1265
-
1266
- Options:
1267
- --yes Apply setup (otherwise plan only).
1268
- --refresh-skills Overwrite bundled skills in $CODEX_HOME/skills during setup.
1269
- --repo <path> Repo root for delegation wiring (default cwd).
1270
- --format json Emit machine-readable output (dry-run only).
1271
- `);
912
+ printSetupCliHelp();
1272
913
  return;
1273
914
  }
1274
- const format = flags['format'] === 'json' ? 'json' : 'text';
1275
- const apply = Boolean(flags['yes']);
1276
- const refreshSkills = Boolean(flags['refresh-skills']);
1277
- if (format === 'json' && apply) {
1278
- throw new Error('setup does not support --format json with --yes.');
1279
- }
1280
- const repoFlag = readStringFlag(flags, 'repo');
1281
- const repoRoot = repoFlag ?? process.cwd();
1282
- const delegationCommandPreview = repoFlag
1283
- ? buildCommandPreview('codex-orchestrator', ['delegation', 'setup', '--yes', '--repo', repoFlag])
1284
- : 'codex-orchestrator delegation setup --yes';
1285
- const bundledSkills = await listBundledSkills();
1286
- if (bundledSkills.length === 0) {
1287
- throw new Error('No bundled skills detected; cannot run setup.');
1288
- }
1289
- const guidance = buildSetupGuidance();
1290
- if (!apply) {
1291
- const installCommand = `codex-orchestrator skills install ${refreshSkills ? '--force ' : ''}--only ${bundledSkills.join(',')}`;
1292
- const skillsNote = refreshSkills
1293
- ? 'Installs bundled skills into $CODEX_HOME/skills with overwrite enabled via --refresh-skills.'
1294
- : 'Installs bundled skills into $CODEX_HOME/skills without overwriting existing files by default. Add --refresh-skills to force overwrite.';
1295
- const delegation = await runDelegationSetup({ repoRoot });
1296
- const devtools = await runDevtoolsSetup();
1297
- const payload = {
1298
- status: 'planned',
1299
- steps: {
1300
- skills: {
1301
- commandLines: [installCommand],
1302
- note: skillsNote
1303
- },
1304
- delegation,
1305
- devtools,
1306
- guidance
1307
- }
1308
- };
1309
- if (format === 'json') {
1310
- console.log(JSON.stringify(payload, null, 2));
1311
- return;
1312
- }
1313
- console.log('Setup plan:');
1314
- console.log('- Skills:');
1315
- for (const commandLine of payload.steps.skills.commandLines) {
1316
- console.log(` - ${commandLine}`);
1317
- }
1318
- console.log(`- Delegation: ${delegationCommandPreview}`);
1319
- console.log('- DevTools: codex-orchestrator devtools setup --yes');
1320
- for (const line of formatSetupGuidanceSummary(guidance)) {
1321
- console.log(line);
1322
- }
1323
- console.log('Run with --yes to apply this setup.');
1324
- return;
1325
- }
1326
- const skills = await installSkills({ force: refreshSkills, only: bundledSkills });
1327
- const delegation = await runDelegationSetup({ apply: true, repoRoot });
1328
- const devtools = await runDevtoolsSetup({ apply: true });
1329
- for (const line of formatSkillsInstallSummary(skills)) {
1330
- console.log(line);
1331
- }
1332
- for (const line of formatDelegationSetupSummary(delegation)) {
1333
- console.log(line);
1334
- }
1335
- for (const line of formatDevtoolsSetupSummary(devtools)) {
1336
- console.log(line);
1337
- }
1338
- for (const line of formatSetupGuidanceSummary(guidance)) {
1339
- console.log(line);
1340
- }
1341
- console.log('Next: codex-orchestrator doctor --usage');
1342
- }
1343
- function buildSetupGuidance() {
1344
- return {
1345
- note: 'Agent-first default: run docs-review before implementation and implementation-gate before handoff.',
1346
- references: [
1347
- 'https://github.com/Kbediako/CO#downstream-usage-cheatsheet-agent-first',
1348
- 'https://github.com/Kbediako/CO/blob/main/docs/AGENTS.md',
1349
- 'https://github.com/Kbediako/CO/blob/main/docs/guides/collab-vs-mcp.md',
1350
- 'https://github.com/Kbediako/CO/blob/main/docs/guides/rlm-recursion-v2.md'
1351
- ],
1352
- recommended_commands: [
1353
- 'codex-orchestrator flow --task <task-id>',
1354
- 'codex-orchestrator doctor --usage',
1355
- 'codex-orchestrator rlm --multi-agent auto "<goal>"',
1356
- 'codex-orchestrator codex defaults --yes',
1357
- 'codex-orchestrator mcp enable --servers delegation --yes'
1358
- ]
1359
- };
1360
- }
1361
- function formatSetupGuidanceSummary(guidance) {
1362
- const lines = ['Setup guidance:', `- ${guidance.note}`];
1363
- if (guidance.recommended_commands.length > 0) {
1364
- lines.push('- Recommended commands:');
1365
- for (const command of guidance.recommended_commands) {
1366
- lines.push(` - ${command}`);
1367
- }
1368
- }
1369
- if (guidance.references.length > 0) {
1370
- lines.push('- References:');
1371
- for (const reference of guidance.references) {
1372
- lines.push(` - ${reference}`);
1373
- }
1374
- }
1375
- return lines;
915
+ await runSetupCliShell({ flags });
1376
916
  }
1377
917
  async function handleDoctor(rawArgs) {
1378
- const { flags } = parseArgs(rawArgs);
1379
- const format = flags['format'] === 'json' ? 'json' : 'text';
1380
- const includeUsage = Boolean(flags['usage']);
1381
- const includeCloudPreflight = Boolean(flags['cloud-preflight']);
1382
- const includeIssueLog = Boolean(flags['issue-log']);
1383
- const cloudEnvIdOverride = readStringFlag(flags, 'cloud-env-id');
1384
- const cloudBranchOverride = readStringFlag(flags, 'cloud-branch');
1385
- const issueTitle = readStringFlag(flags, 'issue-title');
1386
- const issueNotes = readStringFlag(flags, 'issue-notes');
1387
- const issueLogPath = readStringFlag(flags, 'issue-log-path');
1388
- if (!includeCloudPreflight && (cloudEnvIdOverride || cloudBranchOverride)) {
1389
- throw new Error('--cloud-env-id/--cloud-branch require --cloud-preflight.');
1390
- }
1391
- if (!includeIssueLog && (issueTitle || issueNotes || issueLogPath)) {
1392
- throw new Error('--issue-title/--issue-notes/--issue-log-path require --issue-log.');
1393
- }
1394
- const wantsApply = Boolean(flags['apply']);
1395
- const apply = Boolean(flags['yes']);
1396
- if (wantsApply && format === 'json') {
1397
- throw new Error('doctor --apply does not support --format json.');
1398
- }
1399
- const windowDaysRaw = readStringFlag(flags, 'window-days');
1400
- let windowDays = undefined;
1401
- if (windowDaysRaw) {
1402
- if (!/^\d+$/u.test(windowDaysRaw)) {
1403
- throw new Error(`Invalid --window-days value '${windowDaysRaw}'. Expected a positive integer.`);
1404
- }
1405
- const parsed = Number(windowDaysRaw);
1406
- if (!Number.isInteger(parsed) || parsed <= 0) {
1407
- throw new Error(`Invalid --window-days value '${windowDaysRaw}'. Expected a positive integer.`);
1408
- }
1409
- windowDays = parsed;
1410
- }
1411
- const taskFilter = readStringFlag(flags, 'task') ?? null;
1412
- const doctorResult = runDoctor();
1413
- const usageResult = includeUsage ? await runDoctorUsage({ windowDays, taskFilter }) : null;
1414
- const cloudPreflightResult = includeCloudPreflight
1415
- ? await runDoctorCloudPreflight({
1416
- cwd: process.cwd(),
1417
- environmentId: cloudEnvIdOverride,
1418
- branch: cloudBranchOverride,
1419
- taskId: taskFilter
1420
- })
1421
- : null;
1422
- const issueLogResult = includeIssueLog
1423
- ? await writeDoctorIssueLog({
1424
- doctor: doctorResult,
1425
- usage: usageResult,
1426
- cloudPreflight: cloudPreflightResult,
1427
- issueTitle,
1428
- issueNotes,
1429
- issueLogPath,
1430
- taskFilter
1431
- })
1432
- : null;
1433
- if (format === 'json') {
1434
- const payload = { ...doctorResult };
1435
- if (usageResult) {
1436
- payload.usage = usageResult;
1437
- }
1438
- if (cloudPreflightResult) {
1439
- payload.cloud_preflight = cloudPreflightResult;
1440
- }
1441
- if (issueLogResult) {
1442
- payload.issue_log = issueLogResult;
1443
- }
1444
- console.log(JSON.stringify(payload, null, 2));
1445
- return;
1446
- }
1447
- for (const line of formatDoctorSummary(doctorResult)) {
1448
- console.log(line);
1449
- }
1450
- if (usageResult) {
1451
- for (const line of formatDoctorUsageSummary(usageResult)) {
1452
- console.log(line);
1453
- }
1454
- }
1455
- if (cloudPreflightResult) {
1456
- for (const line of formatDoctorCloudPreflightSummary(cloudPreflightResult)) {
1457
- console.log(line);
1458
- }
1459
- }
1460
- if (issueLogResult) {
1461
- for (const line of formatDoctorIssueLogSummary(issueLogResult)) {
1462
- console.log(line);
1463
- }
1464
- }
1465
- if (!wantsApply) {
1466
- return;
1467
- }
1468
- const repoRoot = process.cwd();
1469
- const delegationPlan = await runDelegationSetup({ repoRoot });
1470
- const devtoolsPlan = await runDevtoolsSetup();
1471
- const needsDelegation = !delegationPlan.readiness.configured;
1472
- const needsDevtoolsSkill = devtoolsPlan.readiness.skill.status !== 'ok';
1473
- const devtoolsConfigStatus = devtoolsPlan.readiness.config.status;
1474
- const needsDevtoolsConfig = devtoolsConfigStatus === 'missing';
1475
- const hasInvalidDevtoolsConfig = devtoolsConfigStatus === 'invalid';
1476
- if (!needsDelegation && !needsDevtoolsSkill && !needsDevtoolsConfig && !hasInvalidDevtoolsConfig) {
1477
- console.log('Doctor apply: nothing to do.');
1478
- return;
1479
- }
1480
- console.log('Doctor apply plan:');
1481
- if (needsDevtoolsSkill) {
1482
- console.log('- Install skill: chrome-devtools (codex-orchestrator skills install --only chrome-devtools)');
1483
- }
1484
- if (hasInvalidDevtoolsConfig) {
1485
- console.log(`- DevTools MCP config is invalid: ${devtoolsPlan.readiness.config.path} (fix config.toml then rerun doctor --apply)`);
1486
- }
1487
- if (needsDevtoolsConfig) {
1488
- console.log('- Configure DevTools MCP: codex-orchestrator devtools setup --yes');
1489
- }
1490
- if (needsDelegation) {
1491
- console.log('- Configure delegation MCP: codex-orchestrator delegation setup --yes');
1492
- }
1493
- if (!apply) {
1494
- console.log('Run with --apply --yes to apply these fixes.');
918
+ const { positionals, flags } = parseArgs(rawArgs);
919
+ if (isHelpRequest(positionals, flags)) {
920
+ printDoctorHelp();
1495
921
  return;
1496
922
  }
1497
- if (needsDevtoolsSkill) {
1498
- const skills = await installSkills({ only: ['chrome-devtools'] });
1499
- for (const line of formatSkillsInstallSummary(skills)) {
1500
- console.log(line);
1501
- }
1502
- }
1503
- if (needsDelegation) {
1504
- const delegation = await runDelegationSetup({ apply: true, repoRoot });
1505
- for (const line of formatDelegationSetupSummary(delegation)) {
1506
- console.log(line);
1507
- }
1508
- }
1509
- if (hasInvalidDevtoolsConfig) {
1510
- console.log(`DevTools setup: skipped (config.toml is invalid: ${devtoolsPlan.readiness.config.path}). Fix it and rerun doctor --apply --yes.`);
1511
- }
1512
- else if (needsDevtoolsConfig) {
1513
- const devtools = await runDevtoolsSetup({ apply: true });
1514
- for (const line of formatDevtoolsSetupSummary(devtools)) {
1515
- console.log(line);
1516
- }
1517
- }
1518
- const doctorAfter = runDoctor();
1519
- for (const line of formatDoctorSummary(doctorAfter)) {
1520
- console.log(line);
923
+ if (positionals.length > 0) {
924
+ throw new Error(`Unknown doctor argument(s): ${positionals.join(' ')}`);
1521
925
  }
926
+ await runDoctorCliRequestShell({ flags });
1522
927
  }
1523
928
  async function handleDevtools(rawArgs) {
1524
929
  const { positionals, flags } = parseArgs(rawArgs);
1525
- const subcommand = positionals.shift();
1526
- if (!subcommand) {
1527
- throw new Error('devtools requires a subcommand (setup).');
1528
- }
1529
- if (subcommand !== 'setup') {
1530
- throw new Error(`Unknown devtools subcommand: ${subcommand}`);
1531
- }
1532
- const format = flags['format'] === 'json' ? 'json' : 'text';
1533
- const apply = Boolean(flags['yes']);
1534
- if (format === 'json' && apply) {
1535
- throw new Error('devtools setup does not support --format json with --yes.');
1536
- }
1537
- const result = await runDevtoolsSetup({ apply });
1538
- if (format === 'json') {
1539
- console.log(JSON.stringify(result, null, 2));
1540
- return;
1541
- }
1542
- const summary = formatDevtoolsSetupSummary(result);
1543
- for (const line of summary) {
1544
- console.log(line);
1545
- }
930
+ await runDevtoolsCliShell({ positionals, flags });
1546
931
  }
1547
932
  async function handleDelegation(rawArgs) {
1548
933
  const { positionals, flags } = parseArgs(rawArgs);
1549
- const subcommand = positionals.shift();
1550
- if (!subcommand) {
1551
- throw new Error('delegation requires a subcommand (setup).');
1552
- }
1553
- if (subcommand !== 'setup') {
1554
- throw new Error(`Unknown delegation subcommand: ${subcommand}`);
1555
- }
1556
- const format = flags['format'] === 'json' ? 'json' : 'text';
1557
- const apply = Boolean(flags['yes']);
1558
- if (format === 'json' && apply) {
1559
- throw new Error('delegation setup does not support --format json with --yes.');
1560
- }
1561
- const repoRoot = readStringFlag(flags, 'repo') ?? process.cwd();
1562
- const result = await runDelegationSetup({ apply, repoRoot });
1563
- if (format === 'json') {
1564
- console.log(JSON.stringify(result, null, 2));
1565
- return;
1566
- }
1567
- for (const line of formatDelegationSetupSummary(result)) {
1568
- console.log(line);
1569
- }
934
+ await runDelegationCliShell({ positionals, flags });
1570
935
  }
1571
936
  async function handleCodex(rawArgs) {
1572
937
  const { positionals, flags } = parseArgs(rawArgs);
1573
- const subcommand = positionals.shift();
1574
- if (flags['help'] === true || flags['--help'] === true || flags['h'] === true || !subcommand || subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
1575
- printCodexHelp();
1576
- return;
1577
- }
1578
- if (subcommand === 'setup') {
1579
- const format = flags['format'] === 'json' ? 'json' : 'text';
1580
- const apply = Boolean(flags['yes']);
1581
- const source = readStringFlag(flags, 'source');
1582
- const ref = readStringFlag(flags, 'ref');
1583
- const downloadUrl = readStringFlag(flags, 'download-url');
1584
- const downloadSha256 = readStringFlag(flags, 'download-sha256');
1585
- const force = Boolean(flags['force']);
1586
- const result = await runCodexCliSetup({
1587
- apply,
1588
- force,
1589
- source,
1590
- ref,
1591
- downloadUrl,
1592
- downloadSha256
1593
- });
1594
- if (format === 'json') {
1595
- console.log(JSON.stringify(result, null, 2));
1596
- return;
1597
- }
1598
- const summary = formatCodexCliSetupSummary(result);
1599
- for (const line of summary) {
1600
- console.log(line);
1601
- }
1602
- return;
1603
- }
1604
- if (subcommand === 'defaults') {
1605
- const format = flags['format'] === 'json' ? 'json' : 'text';
1606
- const apply = Boolean(flags['yes']);
1607
- const force = Boolean(flags['force']);
1608
- const result = await runCodexDefaultsSetup({
1609
- apply,
1610
- force
1611
- });
1612
- if (format === 'json') {
1613
- console.log(JSON.stringify(result, null, 2));
1614
- return;
1615
- }
1616
- const summary = formatCodexDefaultsSetupSummary(result);
1617
- for (const line of summary) {
1618
- console.log(line);
1619
- }
1620
- return;
1621
- }
1622
- throw new Error(`Unknown codex subcommand: ${subcommand}`);
938
+ await runCodexCliShell({ positionals, flags, printHelp: printCodexHelp });
1623
939
  }
1624
940
  async function handleSkills(rawArgs) {
1625
941
  const { positionals, flags } = parseArgs(rawArgs);
1626
- const subcommand = positionals[0];
1627
- const wantsHelp = flags['help'] === true || subcommand === 'help' || subcommand === '--help';
1628
- if (!subcommand || wantsHelp) {
1629
- printSkillsHelp();
1630
- return;
1631
- }
1632
- switch (subcommand) {
1633
- case 'install': {
1634
- const format = flags['format'] === 'json' ? 'json' : 'text';
1635
- const force = flags['force'] === true;
1636
- const codexHome = readStringFlag(flags, 'codex-home');
1637
- const onlyRaw = flags['only'];
1638
- let only;
1639
- if (onlyRaw !== undefined) {
1640
- if (typeof onlyRaw !== 'string') {
1641
- throw new Error('--only requires a comma-separated list of skill names.');
1642
- }
1643
- only = onlyRaw.split(',').map((entry) => entry.trim()).filter(Boolean);
1644
- }
1645
- const result = await installSkills({ force, codexHome, only });
1646
- if (format === 'json') {
1647
- console.log(JSON.stringify(result, null, 2));
1648
- }
1649
- else {
1650
- console.log(formatSkillsInstallSummary(result).join('\n'));
1651
- }
1652
- return;
1653
- }
1654
- default:
1655
- throw new Error(`Unknown skills command: ${subcommand}`);
1656
- }
942
+ await runSkillsCliShell({ positionals, flags, printHelp: printSkillsHelp });
943
+ }
944
+ async function handleLinear(rawArgs) {
945
+ const { positionals, flags } = parseArgs(rawArgs);
946
+ await runLinearCliShell({ positionals, flags, printHelp: printLinearHelp });
1657
947
  }
1658
948
  async function handleMcp(rawArgs) {
1659
949
  const { positionals, flags } = parseArgs(rawArgs);
@@ -1672,182 +962,31 @@ async function handleMcp(rawArgs) {
1672
962
  return;
1673
963
  }
1674
964
  if (subcommand === 'enable') {
1675
- const allowedEnableFlags = new Set(['yes', 'format', 'servers']);
1676
- let yesFlag;
1677
- let formatFlag;
1678
- let serversFlag;
1679
- const unexpectedPositionals = [];
1680
- const enableTokens = rawArgs.slice(1);
1681
- for (let index = 0; index < enableTokens.length; index += 1) {
1682
- const token = enableTokens[index];
1683
- if (!token) {
1684
- continue;
1685
- }
1686
- if (token === '--') {
1687
- unexpectedPositionals.push(...enableTokens.slice(index + 1));
1688
- break;
1689
- }
1690
- if (!token.startsWith('--')) {
1691
- unexpectedPositionals.push(token);
1692
- continue;
1693
- }
1694
- const [key, inlineValue] = token.slice(2).split('=', 2);
1695
- if (!allowedEnableFlags.has(key)) {
1696
- throw new Error(`Unknown mcp enable flag: --${key}`);
1697
- }
1698
- let resolvedValue = true;
1699
- if (inlineValue !== undefined) {
1700
- resolvedValue = inlineValue;
1701
- }
1702
- else {
1703
- const nextToken = enableTokens[index + 1];
1704
- if (nextToken && !nextToken.startsWith('--')) {
1705
- resolvedValue = nextToken;
1706
- index += 1;
1707
- }
1708
- }
1709
- if (key === 'yes') {
1710
- if (yesFlag !== undefined) {
1711
- throw new Error('--yes specified multiple times.');
1712
- }
1713
- yesFlag = resolvedValue;
1714
- continue;
1715
- }
1716
- if (key === 'format') {
1717
- if (formatFlag !== undefined) {
1718
- throw new Error('--format specified multiple times.');
1719
- }
1720
- formatFlag = resolvedValue;
1721
- continue;
1722
- }
1723
- if (serversFlag !== undefined) {
1724
- throw new Error('--servers specified multiple times.');
1725
- }
1726
- serversFlag = resolvedValue;
1727
- }
1728
- if (positionals.length > 0 || unexpectedPositionals.length > 0) {
1729
- throw new Error(`mcp enable does not accept positional arguments: ${[...positionals, ...unexpectedPositionals].join(' ')}`);
1730
- }
1731
- let apply = false;
1732
- if (yesFlag === true) {
1733
- apply = true;
1734
- }
1735
- else if (typeof yesFlag === 'string') {
1736
- const normalizedYes = yesFlag.trim().toLowerCase();
1737
- if (normalizedYes === 'true' || normalizedYes === '1' || normalizedYes === 'yes' || normalizedYes === 'on') {
1738
- apply = true;
1739
- }
1740
- else if (normalizedYes === 'false'
1741
- || normalizedYes === '0'
1742
- || normalizedYes === 'no'
1743
- || normalizedYes === 'off') {
1744
- apply = false;
1745
- }
1746
- else {
1747
- throw new Error('--yes expects true/false when provided as --yes=<value>.');
1748
- }
1749
- }
1750
- let format = 'text';
1751
- if (formatFlag !== undefined) {
1752
- if (formatFlag === true) {
1753
- throw new Error('--format requires a value of "text" or "json".');
1754
- }
1755
- if (formatFlag === 'json') {
1756
- format = 'json';
1757
- }
1758
- else if (formatFlag === 'text') {
1759
- format = 'text';
1760
- }
1761
- else {
1762
- throw new Error('--format must be "text" or "json".');
1763
- }
1764
- }
1765
- let serverNames;
1766
- if (serversFlag !== undefined) {
1767
- if (typeof serversFlag !== 'string') {
1768
- throw new Error('--servers must include a comma-separated list of MCP server names.');
1769
- }
1770
- serverNames = serversFlag
1771
- .split(',')
1772
- .map((entry) => entry.trim())
1773
- .filter((entry) => entry.length > 0);
1774
- if (serverNames.length === 0) {
1775
- throw new Error('--servers must include a comma-separated list of MCP server names.');
1776
- }
1777
- }
1778
- const result = await runMcpEnable({ apply, serverNames });
1779
- const hasApplyFailures = apply
1780
- && result.actions.some((action) => action.status !== 'enabled' && action.status !== 'already_enabled');
1781
- if (format === 'json') {
1782
- console.log(JSON.stringify(result, null, 2));
1783
- }
1784
- else {
1785
- for (const line of formatMcpEnableSummary(result)) {
1786
- console.log(line);
1787
- }
1788
- }
1789
- if (hasApplyFailures) {
1790
- process.exitCode = 1;
1791
- }
965
+ await runMcpEnableCliShell({ rawArgs: rawArgs.slice(1) });
1792
966
  return;
1793
967
  }
1794
968
  throw new Error(`Unknown mcp subcommand: ${subcommand}`);
1795
969
  }
1796
970
  async function handlePr(rawArgs) {
1797
- if (rawArgs.length === 0 || rawArgs[0] === '--help' || rawArgs[0] === '-h' || rawArgs[0] === 'help') {
971
+ if (rawArgs.length === 0 || isCliHelpToken(rawArgs[0])) {
1798
972
  printPrHelp();
1799
973
  return;
1800
974
  }
1801
975
  const [subcommand, ...subcommandArgs] = rawArgs;
1802
- const modeBySubcommand = {
1803
- 'watch-merge': {
1804
- usage: 'codex-orchestrator pr watch-merge'
1805
- },
1806
- 'resolve-merge': {
1807
- usage: 'codex-orchestrator pr resolve-merge',
1808
- defaultExitOnActionRequired: true
1809
- }
1810
- };
1811
- const mode = modeBySubcommand[subcommand];
1812
- if (!mode) {
1813
- throw new Error(`Unknown pr subcommand: ${subcommand}`);
1814
- }
1815
- const exitCode = await runPrWatchMerge(subcommandArgs, mode);
1816
- if (exitCode !== 0) {
1817
- process.exitCode = exitCode;
976
+ if (isPrHelpSubcommand(subcommand) && shouldPrintPrSubcommandHelp(subcommandArgs)) {
977
+ printPrSubcommandHelp(subcommand);
978
+ return;
1818
979
  }
980
+ const { runPrCliShell } = await import('../orchestrator/src/cli/prCliShell.js');
981
+ await runPrCliShell({ rawArgs });
1819
982
  }
1820
983
  async function handleDelegationServer(rawArgs) {
1821
984
  const { positionals, flags } = parseArgs(rawArgs);
1822
- if (isHelpRequest(positionals, flags)) {
1823
- printDelegationServerHelp();
1824
- return;
1825
- }
1826
- const repoRoot = typeof flags['repo'] === 'string' ? flags['repo'] : process.cwd();
1827
- const modeFlag = typeof flags['mode'] === 'string' ? flags['mode'] : undefined;
1828
- const overrideFlag = typeof flags['config'] === 'string'
1829
- ? flags['config']
1830
- : typeof flags['config-override'] === 'string'
1831
- ? flags['config-override']
1832
- : undefined;
1833
- const envMode = process.env.CODEX_DELEGATE_MODE?.trim();
1834
- const resolvedMode = modeFlag ?? envMode;
1835
- let mode;
1836
- if (resolvedMode) {
1837
- if (resolvedMode === 'full' || resolvedMode === 'question_only') {
1838
- mode = resolvedMode;
1839
- }
1840
- else {
1841
- console.warn(`Invalid delegate mode "${resolvedMode}". Falling back to config default.`);
1842
- }
1843
- }
1844
- const configOverrides = overrideFlag
1845
- ? splitDelegationConfigOverrides(overrideFlag).map((value) => ({
1846
- source: 'cli',
1847
- value
1848
- }))
1849
- : [];
1850
- await startDelegationServer({ repoRoot, mode, configOverrides });
985
+ await runDelegationServerCliShell({
986
+ positionals,
987
+ flags,
988
+ printHelp: printDelegationServerHelp
989
+ });
1851
990
  }
1852
991
  function parseExecArgs(rawArgs) {
1853
992
  const notifyTargets = [];
@@ -2136,6 +1275,20 @@ Commands:
2136
1275
  --interactive | --ui Enable read-only HUD when running in a TTY.
2137
1276
  --no-interactive Force disable HUD (default is off unless requested).
2138
1277
 
1278
+ control-host [options]
1279
+ Start a persistent Linear intake and Telegram/status host without tying it to a foreground run.
1280
+ --task <id> Artifact task id for the host state (default: local-mcp).
1281
+ --run <id> Host run id for persisted state files (default: control-host).
1282
+ --pipeline <id> Pipeline used for provider-driven starts (default: diagnostics).
1283
+ --format json Emit machine-readable readiness output.
1284
+ control-host freshness-gauge [options]
1285
+ Replay local provider/control-host artifacts and emit throughput/freshness health JSON.
1286
+
1287
+ co-status [options]
1288
+ Attach the CO STATUS terminal viewer or emit the current snapshot from an already-running local control-host.
1289
+ co-status attach [options]
1290
+ Attach a read-only CO STATUS viewer to an already-running local control-host.
1291
+
2139
1292
  status --run <id> [--watch] [--interval N] [--format json]
2140
1293
 
2141
1294
  self-check [--format json]
@@ -2186,11 +1339,15 @@ Commands:
2186
1339
  --repo <path> Repo root for delegation server (default cwd).
2187
1340
  --yes Apply setup by running "codex mcp add ...".
2188
1341
  --format json Emit machine-readable output (dry-run only).
1342
+ delegation cleanup-stale
1343
+ --yes Terminate stale delegate-server processes not rooted in a live codex client.
1344
+ --format json Emit machine-readable output.
2189
1345
  skills install Install bundled skills into $CODEX_HOME/skills.
2190
1346
  --force Overwrite existing skill files.
2191
1347
  --only <skills> Install only selected skills (comma-separated).
2192
1348
  --codex-home <path> Override the target Codex home directory.
2193
1349
  --format json Emit machine-readable output.
1350
+ linear <subcommand> Run worker-visible Linear helper operations.
2194
1351
  mcp serve [--repo <path>] [--dry-run] [-- <extra args>]
2195
1352
  mcp enable [--servers <csv>] [--yes] [--format json]
2196
1353
  --servers <csv> Comma-separated MCP server names to enable (default: all disabled).
@@ -2202,10 +1359,15 @@ Commands:
2202
1359
  pr resolve-merge [options]
2203
1360
  Monitor until merge-ready or actionable feedback appears; exits early when author action is required.
2204
1361
  Use \`codex-orchestrator pr resolve-merge --help\` for full options.
1362
+ pr ready-review [options]
1363
+ Wait through a bounded automated-feedback drain before human review handoff; exits early when author action is required.
1364
+ Use \`codex-orchestrator pr ready-review --help\` for full options.
2205
1365
  delegate-server Run the delegation MCP server (stdio).
2206
1366
  --repo <path> Repo root for config + manifests (default cwd).
2207
- --mode <full|question_only> Limit tool surface for child runs.
1367
+ --mode <full|question_only|status_only> Limit tool surface for child runs.
2208
1368
  --config "<key>=<value>[;...]" Apply config overrides (repeat via separators).
1369
+ control-host Run the persistent provider intake + oversight host.
1370
+ co-status Attach the CO STATUS terminal viewer or emit the current snapshot from an already-running local control-host.
2209
1371
  version | --version
2210
1372
 
2211
1373
  help Show this message.
@@ -2213,6 +1375,7 @@ Commands:
2213
1375
  Quickstart (agent-first):
2214
1376
  codex-orchestrator flow --task <task-id>
2215
1377
  NOTES="Goal: ... | Summary: ... | Risks: ..." codex-orchestrator review --task <task-id>
1378
+ codex-orchestrator doctor --format json
2216
1379
  codex-orchestrator doctor --usage --window-days 30
2217
1380
  codex-orchestrator rlm --multi-agent auto "<goal>"
2218
1381
  codex-orchestrator start implementation-gate --cloud --target <stage-id>
@@ -2223,7 +1386,9 @@ Notes:
2223
1386
  Review artifacts guide: docs/guides/review-artifacts.md
2224
1387
  `);
2225
1388
  }
2226
- void main();
1389
+ if (isDirectExecution()) {
1390
+ void runCodexOrchestratorCli();
1391
+ }
2227
1392
  function printVersion() {
2228
1393
  const pkg = loadPackageInfo();
2229
1394
  console.log(pkg.version ?? 'unknown');
@@ -2239,6 +1404,144 @@ Commands:
2239
1404
  --format json Emit machine-readable output.
2240
1405
  `);
2241
1406
  }
1407
+ function printLinearHelp() {
1408
+ console.log(`Usage: codex-orchestrator linear <subcommand> [options]
1409
+
1410
+ Subcommands:
1411
+ issue-context
1412
+ --issue-id <id> Linear issue id/key to inspect.
1413
+ --workspace-id <id> Optional workspace scope check (falls back to env when configured).
1414
+ --team-id <id> Optional team scope check (falls back to env when configured).
1415
+ --project-id <id> Optional project scope check (falls back to env when configured).
1416
+ --format json Emit machine-readable output.
1417
+
1418
+ upsert-workpad
1419
+ --issue-id <id> Linear issue id/key to update.
1420
+ --body <text> Workpad body to create/update. Local markdown image refs are uploaded to Linear.
1421
+ --body-file <path> Read workpad body from a file. Supports local image refs like file:///abs/proof.png or <file:///abs/proof (1).png>.
1422
+ --comment-id <id> Optional persisted workpad comment id.
1423
+ --workspace-id <id> Optional workspace scope check.
1424
+ --team-id <id> Optional team scope check.
1425
+ --project-id <id> Optional project scope check.
1426
+ --format json Emit machine-readable output.
1427
+
1428
+ delete-workpad
1429
+ --issue-id <id> Linear issue id/key whose workpad should be deleted.
1430
+ --comment-id <id> Optional persisted workpad comment id to delete.
1431
+ --workspace-id <id> Optional workspace scope check.
1432
+ --team-id <id> Optional team scope check.
1433
+ --project-id <id> Optional project scope check.
1434
+ --format json Emit machine-readable output.
1435
+
1436
+ transition
1437
+ --issue-id <id> Linear issue id/key to update.
1438
+ --state <name> Destination Linear state name (resolved to stateId via team workflow states).
1439
+ --expected-state <name>
1440
+ Optional expected live state name; conflicts fail closed before mutation.
1441
+ --expected-state-type <type>
1442
+ Optional expected live workflow type; conflicts fail closed before mutation.
1443
+ --expected-updated-at <iso>
1444
+ Optional expected live updated_at timestamp; conflicts fail closed before mutation.
1445
+ --force Allow terminal-to-reopen transitions with an audited force reason.
1446
+ --force-reason <text> Required whenever --force is set.
1447
+ --workspace-id <id> Optional workspace scope check.
1448
+ --team-id <id> Optional team scope check.
1449
+ --project-id <id> Optional project scope check.
1450
+ --format json Emit machine-readable output.
1451
+
1452
+ attach-pr
1453
+ --issue-id <id> Linear issue id/key to update.
1454
+ --url <url> GitHub PR URL to attach.
1455
+ --title <title> Optional attachment title.
1456
+ --workspace-id <id> Optional workspace scope check.
1457
+ --team-id <id> Optional team scope check.
1458
+ --project-id <id> Optional project scope check.
1459
+ --format json Emit machine-readable output.
1460
+
1461
+ parallelization
1462
+ --issue-id <id> Linear issue id/key for the active provider-worker turn.
1463
+ --decision <mode> parallelize_now, stay_serial, or forbid_parallel.
1464
+ --reason <code> Reason code allowed for the selected decision.
1465
+ --summary <text> Required operator summary. Include matrix/cap evidence.
1466
+ Parallel-first rule: create a pre-turn decomposition matrix before the decision.
1467
+ Matrix columns: candidate lane, file/phase scope, dependencies, overlap risk,
1468
+ expected validation artifact, child-lane owner, and cap-slot use.
1469
+ stay_serial is invalid while any safe independent child-lane candidate remains;
1470
+ single_bounded_change must label docs/test/research/review slice justifications.
1471
+ Child-lane cap: at most 2 active, pending, or unaccepted same-issue child lanes.
1472
+ On cap exhaustion, use stay_serial/existing_child_lane_active and include cap_exhausted: evidence.
1473
+ Stale in-flight accept claims older than 30 minutes, or legacy claims without timestamps, are recoverable and do not consume cap.
1474
+ Parent ownership: avoid delegated files/phases while a child lane is active; collisions
1475
+ require invalidate/reject/rebase reasoning before child patch acceptance.
1476
+ --format json Emit machine-readable output.
1477
+
1478
+ create-follow-up
1479
+ --issue-id <id> Source Linear issue id/key.
1480
+ --title <title> Follow-up issue title.
1481
+ --description <text> Follow-up issue description.
1482
+ --description-file <path> Read follow-up issue description from a file.
1483
+ --intent-checksum <text> Exact wording, protected terms, and wrong interpretations to reject.
1484
+ --intent-checksum-file <path> Read the intent checksum from a file.
1485
+ --non-goals <text> Explicit follow-up non-goals.
1486
+ --non-goals-file <path> Read follow-up non-goals from a file.
1487
+ --not-done-if <text> Readiness blockers / false-done conditions.
1488
+ --not-done-if-file <path> Read the false-done block from a file.
1489
+ --acceptance-criteria <text> Follow-up acceptance criteria.
1490
+ --acceptance-criteria-file <path> Read follow-up acceptance criteria from a file.
1491
+ --parity-lane Require a parity/alignment matrix for this follow-up.
1492
+ --parity-matrix <text> Current/reference/target matrix (required when --parity-lane is set).
1493
+ --parity-matrix-file <path> Read the parity/alignment matrix from a file (required when --parity-lane is set).
1494
+ --canonical-owner-key <text> Exact canonical owner key for reuse before creating a new issue.
1495
+ --canonical-owner-key-file <path> Read the canonical owner key from a file.
1496
+ --blocked-by-source Add blocker linkage when the follow-up depends on the source issue.
1497
+ --workspace-id <id> Optional workspace scope check.
1498
+ --team-id <id> Optional team scope check.
1499
+ --project-id <id> Optional project scope check.
1500
+ --format json Emit machine-readable output.
1501
+
1502
+ runtime-proof
1503
+ --issue-id <id> Linear issue id/key for audit continuity.
1504
+ --origin <url> App origin whose permit posture should be evaluated.
1505
+ --kind <mode> Optional proof kind: screenshot, external-link, or video.
1506
+ --proof-url <url> Reviewer-usable proof URL for workpad/PR handoff generation.
1507
+ --title <title> Optional proof label (defaults by kind).
1508
+ --summary <text> Optional short proof summary for workpad/PR handoff text.
1509
+ --reachability-mode <mode>
1510
+ Optional reviewer reachability mode: deterministic (default) or dns-public.
1511
+ --workspace-id <id> Optional workspace scope check.
1512
+ --team-id <id> Optional team scope check.
1513
+ --project-id <id> Optional project scope check.
1514
+ --format json Emit machine-readable output.
1515
+
1516
+ screenshot-proof
1517
+ --issue-id <id> Linear issue id/key for audit continuity.
1518
+ --output <path> Optional local screenshot path (.png/.jpg/.jpeg). Defaults under .tmp/.
1519
+ --display-id <id> Optional macOS display id for bounded display capture.
1520
+ --window-id <id> Optional macOS window id for bounded window capture.
1521
+ --open-preview Open the captured file in Preview and attempt bounded AppleScript cleanup.
1522
+ --workspace-id <id> Optional workspace scope check.
1523
+ --team-id <id> Optional team scope check.
1524
+ --project-id <id> Optional project scope check.
1525
+ --format json Emit machine-readable output.
1526
+
1527
+ child-stream
1528
+ --pipeline <id> Allowlisted child pipeline: docs-review, implementation-gate, or docs-relevance-advisory.
1529
+ --stream <name> Optional task-id suffix for the child stream (defaults to the pipeline id).
1530
+ --format json Emit machine-readable output.
1531
+
1532
+ child-lane
1533
+ --action <mode> launch, accept, reject, or invalidate.
1534
+ --stream <name> Lane stream name / task-id suffix.
1535
+ --purpose <text> Required for launch: bounded lane objective.
1536
+ --files <csv> Optional comma-separated file ownership scope.
1537
+ --phases <csv> Optional comma-separated phase ownership scope.
1538
+ --instructions <text> Optional extra bounded instructions for launch.
1539
+ --instructions-file <path>
1540
+ Optional file containing extra bounded instructions for launch.
1541
+ --reason <text> Optional parent decision rationale for accept/reject/invalidate.
1542
+ --format json Emit machine-readable output.
1543
+ `);
1544
+ }
2242
1545
  function printCodexHelp() {
2243
1546
  console.log(`Usage: codex-orchestrator codex <subcommand> [options]
2244
1547
 
@@ -2268,6 +1571,158 @@ Options:
2268
1571
  --format json Emit machine-readable status output.
2269
1572
  `);
2270
1573
  }
1574
+ function printControlHostHelp() {
1575
+ console.log(`Usage:
1576
+ codex-orchestrator control-host [options]
1577
+ codex-orchestrator control-host freshness-gauge [options]
1578
+ codex-orchestrator control-host supervise <install|status|restart|uninstall|run> [options]
1579
+
1580
+ Options:
1581
+ --task <id> Artifact task id for the host state (default: local-mcp).
1582
+ --run <id> Host run id for persisted state files (default: control-host).
1583
+ --pipeline <id> Pipeline used for provider-driven starts (default: ${DEFAULT_PROVIDER_START_PIPELINE_ID}).
1584
+ --format json Emit the startup readiness payload to stdout, then keep the host running.
1585
+ --help Show this message.
1586
+
1587
+ Read-only gauge subcommand:
1588
+ freshness-gauge Replay existing local/sanitized artifacts and classify provider/control-host freshness.
1589
+
1590
+ Supervision subcommands:
1591
+ supervise install Install a launchd LaunchAgent-backed local control-host supervisor.
1592
+ supervise status Show the installed launchd/config/state status.
1593
+ supervise restart Restart the installed control-host supervisor.
1594
+ supervise uninstall Remove the installed launchd supervisor and generated artifacts.
1595
+ supervise run Internal long-lived runner for launchd ProgramArguments.
1596
+ `);
1597
+ }
1598
+ function printControlHostFreshnessGaugeHelp() {
1599
+ console.log(`Usage: codex-orchestrator control-host freshness-gauge [options]
1600
+
1601
+ Replay existing provider/control-host artifacts without starting a host or polling Linear/GitHub.
1602
+
1603
+ Options:
1604
+ --artifact-root <path> Directory to scan for local artifacts (required unless explicit paths are provided).
1605
+ --run-dir <path> Alias for --artifact-root when checking one run directory.
1606
+ --provider-intake-state <csv> Explicit provider-intake-state.json path(s).
1607
+ --provider-manifest <csv> Explicit manifest.json path(s).
1608
+ --provider-proof <csv> Explicit provider-linear-worker-proof.json path(s).
1609
+ --worker-audit-jsonl <csv> Explicit provider worker audit JSONL path(s).
1610
+ --control-endpoint-metadata <csv> Explicit control endpoint metadata path(s).
1611
+ --status-dataset <csv> Explicit CO STATUS/status dataset path(s).
1612
+ --polling-health <csv> Explicit provider polling health path(s).
1613
+ --linear-budget-state <csv> Explicit Linear shared-budget state path(s).
1614
+ --now <iso> Deterministic reference time for age/latency calculations.
1615
+ --strict Exit non-zero when the verdict is stale or contradictory.
1616
+ --max-depth <n> Recursive artifact scan depth (default: 8).
1617
+ --stale-refresh-after-ms <n> Refresh age threshold (default: 300000).
1618
+ --stale-heartbeat-after-ms <n> Active heartbeat age threshold (default: 600000).
1619
+ --stale-retry-after-ms <n> Retry/backoff overdue threshold (default: 600000).
1620
+ --stale-claim-queue-after-ms <n> Claim queue age threshold (default: 1800000).
1621
+ --claim-to-start-degraded-after-ms <n> Claim-to-start degraded threshold (default: 300000).
1622
+ --start-to-heartbeat-degraded-after-ms <n> Start-to-first-heartbeat degraded threshold (default: 120000).
1623
+ --linear-headroom-low-ratio <n> Low Linear shared-budget remaining ratio (default: 0.05).
1624
+ --child-lane-cap <n> Same-parent active/pending child-lane cap (default: 2).
1625
+ --format json Emit machine-readable gauge output.
1626
+ --help Show this message.
1627
+ `);
1628
+ }
1629
+ function printControlHostSupervisionHelp() {
1630
+ console.log(`Usage: codex-orchestrator control-host supervise <install|status|restart|uninstall|run> [options]
1631
+
1632
+ Subcommands:
1633
+ install Install the macOS launchd LaunchAgent plus generated config/state files.
1634
+ status Show the current install, launchctl, and restart-reason state.
1635
+ restart Kickstart the installed launchd service.
1636
+ uninstall Boot out the launchd service and remove generated artifacts.
1637
+ run Internal long-lived supervision runner for launchd use.
1638
+
1639
+ Common options:
1640
+ --label <value> LaunchAgent label (default: com.kbediako.co.control-host).
1641
+ --config <path> Explicit config path for status, restart, uninstall, or run.
1642
+ --format json Emit machine-readable output for install, status, restart, or uninstall.
1643
+
1644
+ Install options:
1645
+ --repo-root <path> Repo root used as the supervised control-host working directory.
1646
+ --node <path> Explicit Node executable for launchd ProgramArguments.
1647
+ --cli-entrypoint <path> Explicit codex-orchestrator JS entrypoint for launchd ProgramArguments.
1648
+ --task <id> Control-host task id (default: local-mcp).
1649
+ --run <id> Control-host run id (default: control-host).
1650
+ --pipeline <id> Provider start pipeline (default: provider-linear-worker).
1651
+ --health-interval <sec> Health poll interval in seconds (default: 30).
1652
+ --unhealthy-threshold <n> Consecutive unhealthy samples before launchd restart (default: 3).
1653
+ --launchd-throttle <sec> LaunchAgent ThrottleInterval value (default: 15).
1654
+ --kill-timeout <sec> Grace period before force-killing the child host (default: 10).
1655
+ --env-files <csv|none> Comma-separated env/bootstrap files to source before launch.
1656
+ --shell <path> Shell used to source env/bootstrap files (default: $SHELL or /bin/zsh).
1657
+ `);
1658
+ }
1659
+ function printCoStatusHelp() {
1660
+ console.log(`Usage:
1661
+ codex-orchestrator co-status [options]
1662
+ codex-orchestrator co-status attach [options]
1663
+ codex-orchestrator co-status operator-autopilot local-rollout <acknowledge|clear|dismiss> [options]
1664
+
1665
+ Attach the CO STATUS terminal viewer to an already-running local JSON control-host,
1666
+ or emit the current CO STATUS snapshot from that host in JSON mode.
1667
+
1668
+ Viewer options:
1669
+ --task <id> Artifact task id for the host state (default: local-mcp).
1670
+ --run <id> Host run id for persisted state files (default: control-host).
1671
+ --format json Emit the current CO STATUS snapshot from the local control-host and exit.
1672
+ --help Show this message.
1673
+
1674
+ JSON contract:
1675
+ co-status --format json reads the authenticated operator-dashboard snapshot from the
1676
+ current local control-host and exits. Use \`control-host --format json\` for startup readiness output.
1677
+
1678
+ Attach subcommand:
1679
+ attach Attach to an already-running local JSON control-host.
1680
+ Run \`codex-orchestrator co-status attach --help\` for attach flags.
1681
+
1682
+ Operator autopilot lifecycle:
1683
+ operator-autopilot Acknowledge, clear, or dismiss a pending local rollout action.
1684
+ Run \`codex-orchestrator co-status operator-autopilot --help\` for lifecycle flags.
1685
+ `);
1686
+ }
1687
+ function printCoStatusOperatorAutopilotHelp() {
1688
+ console.log(`Usage: codex-orchestrator co-status operator-autopilot local-rollout <acknowledge|clear|dismiss> [options]
1689
+
1690
+ Record durable lifecycle metadata for one pending operator-autopilot local rollout
1691
+ action from an already-running local JSON control-host.
1692
+
1693
+ Options:
1694
+ --issue <id|identifier> Pending Linear issue id or identifier to match.
1695
+ --action-id <id> Stable local rollout action instance id to match.
1696
+ --actor <name> Operator recording the lifecycle event (default: current user).
1697
+ --reason <text> Required reason for the lifecycle event.
1698
+ --task <id> Artifact task id for the host state (default: local-mcp).
1699
+ --run <id> Host run id for persisted state files (default: control-host).
1700
+ --run-dir <path> Resolve the host from a specific existing run directory.
1701
+ --manifest-path <path> Resolve the host from an explicit manifest.json path.
1702
+ --format json Emit machine-readable lifecycle output.
1703
+ --help Show this message.
1704
+ `);
1705
+ }
1706
+ function printCoStatusAttachHelp() {
1707
+ console.log(`Usage: codex-orchestrator co-status attach [options]
1708
+
1709
+ Attach a read-only CO STATUS viewer to an already-running local JSON control-host.
1710
+ This reads persisted endpoint/auth artifacts and does not start another control-host,
1711
+ Linear poller, or Telegram poller.
1712
+ If the supervised control-host restarts and rotates control_endpoint.json while
1713
+ attached, the viewer re-resolves the endpoint on fetch failures and reports
1714
+ stale endpoint, unavailable host, auth, and timeout guidance in the dashboard.
1715
+
1716
+ Options:
1717
+ --task <id> Artifact task id for the host state (default: local-mcp).
1718
+ --run <id> Host run id for persisted state files (default: control-host).
1719
+ --run-dir <path> Resolve the host from a specific existing run directory.
1720
+ --manifest-path <path> Resolve the host from an explicit manifest.json path.
1721
+ --refresh-interval-ms <n> Viewer refresh interval in milliseconds (default: 1000).
1722
+ --format json Emit machine-readable attach target output instead of launching the viewer.
1723
+ --help Show this message.
1724
+ `);
1725
+ }
2271
1726
  function printResumeHelp() {
2272
1727
  console.log(`Usage: codex-orchestrator resume --run <id> [options]
2273
1728
 
@@ -2284,12 +1739,43 @@ Options:
2284
1739
  --no-interactive Force disable HUD.
2285
1740
  `);
2286
1741
  }
1742
+ function printDoctorHelp() {
1743
+ console.log(`Usage: codex-orchestrator doctor [options]
1744
+
1745
+ Inspect the current repo/user environment for downstream readiness:
1746
+ - packaged and seeded provider onboarding files
1747
+ - DevTools + delegation MCP wiring
1748
+ - Codex defaults and current CLI posture
1749
+ - optional local usage and cloud preflight checks
1750
+
1751
+ Options:
1752
+ --format json Emit machine-readable output (not supported with --apply).
1753
+ --usage Include a local usage snapshot (scans .runs/).
1754
+ --window-days <n> Window for --usage (default 30).
1755
+ --task <id> Limit --usage scan to a specific task directory.
1756
+ --cloud-preflight Run cloud readiness preflight checks (env/codex/git/branch).
1757
+ --cloud-env-id <id> Override env id for --cloud-preflight (default: CODEX_CLOUD_ENV_ID).
1758
+ --cloud-branch <name> Override branch for --cloud-preflight (default: CODEX_CLOUD_BRANCH).
1759
+ --issue-log Append markdown issue entry + JSON bundle for downstream triage.
1760
+ --issue-title <text> Optional title for --issue-log entries.
1761
+ --issue-notes <text> Optional notes for --issue-log entries.
1762
+ --issue-log-path <p> Output markdown path (default: docs/codex-orchestrator-issues.md).
1763
+ --apply Plan/apply quick fixes for DevTools + delegation wiring (use with --yes).
1764
+ --yes Apply fixes when --apply is set.
1765
+ --help Show this message.
1766
+
1767
+ Examples:
1768
+ codex-orchestrator doctor --format json
1769
+ codex-orchestrator doctor --usage --window-days 30
1770
+ codex-orchestrator doctor --cloud-preflight --cloud-env-id <env-id> --cloud-branch main
1771
+ `);
1772
+ }
2287
1773
  function printDelegationServerHelp() {
2288
1774
  console.log(`Usage: codex-orchestrator delegate-server [options]
2289
1775
 
2290
1776
  Options:
2291
1777
  --repo <path> Repo root for config + manifests (default cwd).
2292
- --mode <full|question_only> Limit tool surface for child runs.
1778
+ --mode <full|question_only|status_only> Limit tool surface for child runs.
2293
1779
  --config "<key>=<value>[;...]" Apply config overrides.
2294
1780
  --help Show this message.
2295
1781
  `);
@@ -2316,17 +1802,144 @@ Subcommands:
2316
1802
  Supports PR_MONITOR_* env vars and standard flags (see: pr watch-merge --help).
2317
1803
  resolve-merge Watch for merge readiness but exit early on actionable feedback requiring author response.
2318
1804
  Inherits watch-merge flags; defaults exit-on-action-required to on.
1805
+ ready-review Wait through a bounded automated-feedback drain before review handoff.
1806
+ Reuses watch-merge polling, treats REVIEW_REQUIRED as informational, and defaults exit-on-action-required to on.
2319
1807
 
2320
1808
  Examples:
2321
1809
  codex-orchestrator pr watch-merge --pr 211 --dry-run --quiet-minutes 10
2322
1810
  codex-orchestrator pr watch-merge --pr 211 --auto-merge --merge-method squash
2323
1811
  codex-orchestrator pr resolve-merge --pr 211 --quiet-minutes 15
2324
1812
  codex-orchestrator pr resolve-merge --pr 211 --auto-merge --quiet-minutes 10
1813
+ codex-orchestrator pr ready-review --pr 211 --quiet-minutes 15 --timeout-minutes 20
2325
1814
 
2326
1815
  Guide:
2327
1816
  Review artifacts (prompt + output log paths): docs/guides/review-artifacts.md
2328
1817
  `);
2329
1818
  }
1819
+ function isCliHelpToken(value) {
1820
+ return value === '--help' || value === '-h' || value === 'help';
1821
+ }
1822
+ function envFlagEnabled(value, fallback = false) {
1823
+ if (value === undefined || value === null) {
1824
+ return fallback;
1825
+ }
1826
+ const normalized = value.trim().toLowerCase();
1827
+ if (normalized.length === 0) {
1828
+ return fallback;
1829
+ }
1830
+ if (normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on') {
1831
+ return true;
1832
+ }
1833
+ if (normalized === '0' || normalized === 'false' || normalized === 'no' || normalized === 'off') {
1834
+ return false;
1835
+ }
1836
+ return fallback;
1837
+ }
1838
+ function isPrHelpSubcommand(value) {
1839
+ return value === 'watch-merge' || value === 'resolve-merge' || value === 'ready-review';
1840
+ }
1841
+ function shouldPrintPrSubcommandHelp(args) {
1842
+ if (args.length === 0) {
1843
+ return false;
1844
+ }
1845
+ if (args[0] === 'help') {
1846
+ return true;
1847
+ }
1848
+ return args.some((arg) => arg === '--help' || arg === '-h');
1849
+ }
1850
+ function printPrSubcommandHelp(subcommand) {
1851
+ const defaultAutoMerge = envFlagEnabled(process.env.PR_MONITOR_AUTO_MERGE, false);
1852
+ switch (subcommand) {
1853
+ case 'watch-merge':
1854
+ console.log(`Usage: codex-orchestrator pr watch-merge [options]
1855
+
1856
+ Monitor PR checks/reviews with polling and optionally merge after a quiet window.
1857
+
1858
+ Options:
1859
+ --pr <number> PR number (default: PR for current branch)
1860
+ --owner <name> Repo owner (default: inferred via gh repo view)
1861
+ --repo <name> Repo name (default: inferred via gh repo view)
1862
+ --interval-seconds <n> Poll interval in seconds (default: 30)
1863
+ --quiet-minutes <n> Required quiet window after ready state (default: 15)
1864
+ --timeout-minutes <n> Max monitor duration before failing (default: 180)
1865
+ --merge-method <method> merge|squash|rebase (default: squash)
1866
+ --auto-merge Merge automatically after quiet window
1867
+ --no-auto-merge Never merge automatically (monitor only)
1868
+ --delete-branch Delete remote branch when merging
1869
+ --no-delete-branch Keep remote branch after merge
1870
+ --exit-on-action-required Exit non-zero when author action is required
1871
+ --no-exit-on-action-required Keep monitoring even when author action is required
1872
+ --dry-run Never call gh pr merge (report only)
1873
+ -h, --help Show this help message
1874
+
1875
+ Environment:
1876
+ PR_MONITOR_QUIET_MINUTES=<n> Override quiet window default
1877
+ PR_MONITOR_INTERVAL_SECONDS=<n>
1878
+ PR_MONITOR_TIMEOUT_MINUTES=<n>
1879
+ PR_MONITOR_AUTO_MERGE=1 Default auto-merge on (current default: ${defaultAutoMerge ? 'on' : 'off'})
1880
+ PR_MONITOR_DELETE_BRANCH=1 Default delete branch on merge
1881
+ PR_MONITOR_MERGE_METHOD=<method>
1882
+ `);
1883
+ return;
1884
+ case 'resolve-merge':
1885
+ console.log(`Usage: codex-orchestrator pr resolve-merge [options]
1886
+
1887
+ Monitor until merge-ready or actionable feedback appears; exits early when author action is required.
1888
+
1889
+ Options:
1890
+ --pr <number> PR number (default: PR for current branch)
1891
+ --owner <name> Repo owner (default: inferred via gh repo view)
1892
+ --repo <name> Repo name (default: inferred via gh repo view)
1893
+ --interval-seconds <n> Poll interval in seconds (default: 30)
1894
+ --quiet-minutes <n> Required quiet window after ready state (default: 15)
1895
+ --timeout-minutes <n> Max monitor duration before failing (default: 180)
1896
+ --merge-method <method> merge|squash|rebase (default: squash)
1897
+ --auto-merge Merge automatically after quiet window
1898
+ --no-auto-merge Never merge automatically (monitor only)
1899
+ --delete-branch Delete remote branch when merging
1900
+ --no-delete-branch Keep remote branch after merge
1901
+ --exit-on-action-required Exit non-zero when author action is required
1902
+ --no-exit-on-action-required Keep monitoring even when author action is required
1903
+ --dry-run Never call gh pr merge (report only)
1904
+ -h, --help Show this help message
1905
+
1906
+ Environment:
1907
+ PR_MONITOR_QUIET_MINUTES=<n> Override quiet window default
1908
+ PR_MONITOR_INTERVAL_SECONDS=<n>
1909
+ PR_MONITOR_TIMEOUT_MINUTES=<n>
1910
+ PR_MONITOR_AUTO_MERGE=1 Default auto-merge on (current default: ${defaultAutoMerge ? 'on' : 'off'})
1911
+ PR_MONITOR_DELETE_BRANCH=1 Default delete branch on merge
1912
+ PR_MONITOR_MERGE_METHOD=<method>
1913
+ resolve-merge default: exit-on-action-required is on
1914
+ `);
1915
+ return;
1916
+ case 'ready-review':
1917
+ console.log(`Usage: codex-orchestrator pr ready-review [options]
1918
+
1919
+ Monitor PR checks/reviews with polling and report when review handoff is safe after a bounded automated-feedback drain.
1920
+
1921
+ Options:
1922
+ --pr <number> PR number (default: PR for current branch)
1923
+ --owner <name> Repo owner (default: inferred via gh repo view)
1924
+ --repo <name> Repo name (default: inferred via gh repo view)
1925
+ --interval-seconds <n> Poll interval in seconds (default: 30)
1926
+ --quiet-minutes <n> Required quiet window after ready state (default: 15)
1927
+ --timeout-minutes <n> Max monitor duration before failing (default: 180)
1928
+ --exit-on-action-required Exit non-zero when author action is required
1929
+ --no-exit-on-action-required Keep monitoring even when author action is required
1930
+ --dry-run Never call gh pr merge (report only)
1931
+ -h, --help Show this help message
1932
+
1933
+ Environment:
1934
+ PR_MONITOR_QUIET_MINUTES=<n> Override quiet window default
1935
+ PR_MONITOR_INTERVAL_SECONDS=<n>
1936
+ PR_MONITOR_TIMEOUT_MINUTES=<n>
1937
+ ready-review default: exit-on-action-required is on
1938
+ ready-review treats REVIEW_REQUIRED as informational; CHANGES_REQUESTED and actionable machine feedback still block handoff.
1939
+ `);
1940
+ return;
1941
+ }
1942
+ }
2330
1943
  function printRlmHelp() {
2331
1944
  console.log(`Usage: codex-orchestrator rlm "<goal>" [options]
2332
1945
 
@@ -2356,6 +1969,29 @@ Tips:
2356
1969
  - Ensure multi-agent is enabled in Codex: codex features enable multi_agent (legacy alias: collab).
2357
1970
  `);
2358
1971
  }
1972
+ function printFrontendTestHelp() {
1973
+ console.log(`Usage: codex-orchestrator frontend-test [options]
1974
+
1975
+ Runs the frontend-testing pipeline.
1976
+
1977
+ Options:
1978
+ --devtools Enable Chrome DevTools MCP for this run.
1979
+ --task <id> Override task identifier (defaults to MCP_RUNNER_TASK_ID).
1980
+ --runtime-mode <cli|appserver> Force runtime mode for this run.
1981
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1982
+ --parent-run <id> Link run to parent run id.
1983
+ --approval-policy <p> Record approval policy metadata.
1984
+ --format json Emit machine-readable output.
1985
+ --target <stage-id> Focus plan/build metadata on a specific stage (alias: --target-stage).
1986
+ --interactive | --ui Enable read-only HUD when running in a TTY.
1987
+ --no-interactive Force disable HUD.
1988
+ --help Show this message.
1989
+
1990
+ Examples:
1991
+ codex-orchestrator frontend-test
1992
+ codex-orchestrator frontend-test --devtools --format json
1993
+ `);
1994
+ }
2359
1995
  function printFlowHelp() {
2360
1996
  console.log(`Usage: codex-orchestrator flow [options]
2361
1997
 
@@ -2393,6 +2029,7 @@ Common options:
2393
2029
  --manifest <path> Explicit manifest path for review evidence.
2394
2030
  --runs-dir <path> Root runs directory when auto-resolving manifest.
2395
2031
  --task <id> Task id used for prompt context.
2032
+ --surface <diff|audit|architecture> Select review surface (default: diff).
2396
2033
  --uncommitted Review uncommitted diff scope.
2397
2034
  --base <branch> Review against a base branch.
2398
2035
  --commit <sha> Review a specific commit.
@@ -2425,6 +2062,10 @@ Options:
2425
2062
  --task <id> Override task identifier.
2426
2063
  --parent-run <id> Link run to parent run id.
2427
2064
  --approval-policy <p> Record approval policy metadata.
2065
+ --issue-provider <name> Persist provider identity for autonomous intake handoff.
2066
+ --issue-id <id> Persist provider issue id on the run manifest.
2067
+ --issue-identifier <id> Persist human issue identifier on the run manifest.
2068
+ --issue-updated-at <iso> Persist provider issue updated timestamp on the run manifest.
2428
2069
  --format json Emit machine-readable output.
2429
2070
  --execution-mode <mcp|cloud> Force execution mode for this run.
2430
2071
  --cloud Shortcut for --execution-mode cloud.