@kbediako/codex-orchestrator 0.1.38 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +46 -317
  3. package/bin/codex-orchestrator.js +161 -0
  4. package/codex.orchestrator.json +149 -13
  5. package/dist/bin/codex-orchestrator.js +797 -1154
  6. package/dist/orchestrator/src/cli/adapters/CommandBuilder.js +50 -0
  7. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
  8. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
  9. package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
  10. package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +295 -11
  11. package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
  12. package/dist/orchestrator/src/cli/coStatusCliShell.js +451 -0
  13. package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
  14. package/dist/orchestrator/src/cli/codexCliShell.js +119 -0
  15. package/dist/orchestrator/src/cli/codexDefaultsSetup.js +265 -36
  16. package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
  17. package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
  18. package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
  19. package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
  20. package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
  21. package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
  22. package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
  23. package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
  24. package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
  25. package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
  26. package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
  27. package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
  28. package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
  29. package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
  30. package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
  31. package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
  32. package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
  33. package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
  34. package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
  35. package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
  36. package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
  37. package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
  38. package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
  39. package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
  40. package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
  41. package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
  42. package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
  43. package/dist/orchestrator/src/cli/control/controlHostSupervision.js +630 -0
  44. package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
  45. package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
  46. package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
  47. package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
  48. package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
  49. package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
  50. package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
  51. package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
  52. package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
  53. package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
  54. package/dist/orchestrator/src/cli/control/controlRuntime.js +1003 -0
  55. package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
  56. package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
  57. package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
  58. package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
  59. package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
  60. package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
  61. package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
  62. package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
  63. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
  64. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
  65. package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
  66. package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
  67. package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
  68. package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
  69. package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
  70. package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
  71. package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
  72. package/dist/orchestrator/src/cli/control/controlState.js +233 -2
  73. package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1904 -0
  74. package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
  75. package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
  76. package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
  77. package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
  78. package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
  79. package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
  80. package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
  81. package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
  82. package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
  83. package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
  84. package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
  85. package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
  86. package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
  87. package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
  88. package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
  89. package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
  90. package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
  91. package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
  92. package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
  93. package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
  94. package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
  95. package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
  96. package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
  97. package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
  98. package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
  99. package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
  100. package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
  101. package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
  102. package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
  103. package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
  104. package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
  105. package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
  106. package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
  107. package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
  108. package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
  109. package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
  110. package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
  111. package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
  112. package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
  113. package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
  114. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
  115. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
  116. package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
  117. package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
  118. package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
  119. package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
  120. package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
  121. package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
  122. package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
  123. package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
  124. package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
  125. package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1885 -0
  126. package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
  127. package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
  128. package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
  129. package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
  130. package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
  131. package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
  132. package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
  133. package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
  134. package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
  135. package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
  136. package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
  137. package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
  138. package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
  139. package/dist/orchestrator/src/cli/delegationServer.js +567 -678
  140. package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
  141. package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
  142. package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
  143. package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
  144. package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
  145. package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
  146. package/dist/orchestrator/src/cli/doctor.js +678 -164
  147. package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
  148. package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
  149. package/dist/orchestrator/src/cli/doctorUsage.js +119 -15
  150. package/dist/orchestrator/src/cli/exec/experience.js +16 -2
  151. package/dist/orchestrator/src/cli/exec/summary.js +3 -0
  152. package/dist/orchestrator/src/cli/execCliShell.js +51 -0
  153. package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
  154. package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
  155. package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
  156. package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
  157. package/dist/orchestrator/src/cli/init.js +95 -1
  158. package/dist/orchestrator/src/cli/initCliShell.js +50 -0
  159. package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
  160. package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
  161. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
  162. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
  163. package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
  164. package/dist/orchestrator/src/cli/planCliShell.js +19 -0
  165. package/dist/orchestrator/src/cli/prCliShell.js +41 -0
  166. package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
  167. package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1835 -0
  168. package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
  169. package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
  170. package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +6834 -0
  171. package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
  172. package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
  173. package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
  174. package/dist/orchestrator/src/cli/rlm/context.js +94 -7
  175. package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
  176. package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
  177. package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
  178. package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
  179. package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
  180. package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
  181. package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
  182. package/dist/orchestrator/src/cli/run/manifest.js +410 -73
  183. package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
  184. package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
  185. package/dist/orchestrator/src/cli/run/source0.js +690 -0
  186. package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
  187. package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
  188. package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
  189. package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
  190. package/dist/orchestrator/src/cli/services/commandRunner.js +698 -18
  191. package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
  192. package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
  193. package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
  194. package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
  195. package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
  196. package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
  197. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
  198. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
  199. package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
  200. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
  201. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
  202. package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
  203. package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
  204. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
  205. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
  206. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
  207. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
  208. package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
  209. package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
  210. package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
  211. package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
  212. package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
  213. package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
  214. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
  215. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
  216. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
  217. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
  218. package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
  219. package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
  220. package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
  221. package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
  222. package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
  223. package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
  224. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
  225. package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
  226. package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
  227. package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
  228. package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
  229. package/dist/orchestrator/src/cli/startCliShell.js +68 -0
  230. package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
  231. package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
  232. package/dist/orchestrator/src/cli/utils/cloudPreflight.js +285 -7
  233. package/dist/orchestrator/src/cli/utils/codexFeatures.js +60 -0
  234. package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
  235. package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
  236. package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
  237. package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
  238. package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
  239. package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
  240. package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
  241. package/dist/orchestrator/src/learning/crystalizer.js +2 -2
  242. package/dist/orchestrator/src/manager.js +74 -4
  243. package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
  244. package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
  245. package/dist/orchestrator/src/persistence/lockFile.js +70 -4
  246. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
  247. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
  248. package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
  249. package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
  250. package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
  251. package/dist/packages/sdk-node/src/orchestrator.js +137 -13
  252. package/dist/packages/shared/config/designConfig.js +8 -1
  253. package/dist/packages/shared/streams/stdio.js +1 -1
  254. package/dist/scripts/design/pipeline/permit.js +15 -0
  255. package/dist/scripts/lib/docs-catalog.js +399 -0
  256. package/dist/scripts/lib/docs-helpers.js +87 -5
  257. package/dist/scripts/lib/pr-watch-merge.js +1088 -80
  258. package/dist/scripts/lib/provider-run-contract.js +26 -0
  259. package/dist/scripts/lib/review-command-intent-classification.js +532 -0
  260. package/dist/scripts/lib/review-command-probe-classification.js +385 -0
  261. package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
  262. package/dist/scripts/lib/review-execution-runtime.js +753 -0
  263. package/dist/scripts/lib/review-execution-state.js +1144 -0
  264. package/dist/scripts/lib/review-execution-telemetry.js +215 -0
  265. package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
  266. package/dist/scripts/lib/review-launch-attempt.js +601 -0
  267. package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
  268. package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
  269. package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
  270. package/dist/scripts/lib/review-prompt-context.js +376 -0
  271. package/dist/scripts/lib/review-scope-advisory.js +286 -0
  272. package/dist/scripts/lib/review-scope-paths.js +123 -0
  273. package/dist/scripts/lib/review-shell-command-parser.js +389 -0
  274. package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
  275. package/dist/scripts/lib/run-manifests.js +192 -36
  276. package/dist/scripts/lib/spark-policy-classifier.js +593 -0
  277. package/dist/scripts/run-review.js +507 -1777
  278. package/docs/README.md +43 -20
  279. package/docs/book/README.md +19 -0
  280. package/docs/book/codex-cli-0124-adoption.md +68 -0
  281. package/docs/book/local-hook-impact.md +73 -0
  282. package/docs/book/operations.md +60 -0
  283. package/docs/book/public-posture.md +34 -0
  284. package/docs/book/setup.md +91 -0
  285. package/docs/book/skills.md +11 -0
  286. package/docs/guides/codex-version-policy.md +104 -0
  287. package/docs/public/downstream-setup.md +113 -0
  288. package/docs/public/provider-onboarding.md +173 -0
  289. package/package.json +23 -10
  290. package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
  291. package/plugins/codex-orchestrator/.mcp.json +13 -0
  292. package/plugins/codex-orchestrator/launcher.mjs +361 -0
  293. package/schemas/manifest.json +411 -0
  294. package/skills/README.md +26 -0
  295. package/skills/collab-subagents-first/SKILL.md +1 -1
  296. package/skills/delegation-usage/DELEGATION_GUIDE.md +30 -12
  297. package/skills/delegation-usage/SKILL.md +25 -14
  298. package/skills/land/SKILL.md +77 -0
  299. package/skills/linear/SKILL.md +255 -0
  300. package/skills/release/SKILL.md +47 -3
  301. package/skills/standalone-review/SKILL.md +6 -1
  302. package/templates/README.md +4 -2
  303. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  304. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  305. package/templates/codex/.codex/config.toml +3 -4
  306. package/templates/codex/.codex/providers/README.md +13 -0
  307. package/templates/codex/.codex/providers/control.example.json +18 -0
  308. package/templates/codex/.codex/providers/provider.env.example +15 -0
  309. package/templates/codex/AGENTS.md +15 -8
  310. package/templates/codex/mcp-client.json +5 -1
  311. package/docs/assets/setup.gif +0 -0
@@ -2,18 +2,24 @@ import process from 'node:process';
2
2
  import { spawnSync } from 'node:child_process';
3
3
  import { existsSync, readFileSync } from 'node:fs';
4
4
  import { createRequire } from 'node:module';
5
+ import { release as osRelease } from 'node:os';
5
6
  import { dirname, join, resolve } from 'node:path';
6
7
  import { buildDevtoolsSetupPlan, DEVTOOLS_SKILL_NAME, resolveDevtoolsReadiness } from './utils/devtools.js';
7
8
  import { isManagedCodexCliEnabled, resolveCodexCliBin, resolveCodexCliReadiness } from './utils/codexCli.js';
9
+ import { codexFeatureProbeDisablesMultiAgentV2, codexFeatureProbeRejectsAgentMaxThreads, readCodexFeatureProbe } from './utils/codexFeatures.js';
8
10
  import { resolveCodexHome } from './utils/codexPaths.js';
9
11
  import { resolveOptionalDependency } from './utils/optionalDeps.js';
10
- import { runCloudPreflight } from './utils/cloudPreflight.js';
11
- import { BASELINE_AGENTS, BASELINE_MODEL, BASELINE_REASONING_MINIMUM } from './codexDefaultsSetup.js';
12
+ import { buildCloudPreflightAuthProvenance, buildCloudPreflightRequest, runCloudPreflight } from './utils/cloudPreflight.js';
13
+ import { classifyDelegationTransport, formatDelegateServerProcessSummary, inspectDelegateServerProcesses, inspectDelegationMcpConfig, probeDelegationInitialize, resolveDelegationServerInvocation } from './utils/delegationMcpHealth.js';
14
+ import { sanitizeProviderOverrideEnv } from './utils/providerOverrideEnv.js';
15
+ import { hasLinearApiCredentials, hasLinearSourceBinding, resolveLinearSourceSetup } from './control/linearDispatchSource.js';
16
+ import { normalizeDispatchSourceProvider } from './control/trackerDispatchPilot.js';
17
+ import { BASELINE_AGENTS, BASELINE_MODEL, BASELINE_REVIEW_MODEL, BASELINE_REASONING_MINIMUM, formatModelDefaultExpectation, isLocalModelOptIn } from './codexDefaultsSetup.js';
12
18
  import { CommandPlanner } from './adapters/CommandPlanner.js';
13
19
  import { PipelineResolver } from './services/pipelineResolver.js';
14
20
  import { isRepoConfigRequired } from './config/repoConfigPolicy.js';
15
21
  const require = createRequire(import.meta.url);
16
- const toml = require('@iarna/toml');
22
+ let tomlParser;
17
23
  const OPTIONAL_DEPENDENCIES = [
18
24
  {
19
25
  name: 'playwright',
@@ -23,6 +29,8 @@ const OPTIONAL_DEPENDENCIES = [
23
29
  { name: 'pixelmatch', install: 'npm install --save-dev pixelmatch' },
24
30
  { name: 'cheerio', install: 'npm install --save-dev cheerio' }
25
31
  ];
32
+ const PROVIDER_ROOT_RELATIVE_PATH = '.codex/providers';
33
+ const CODEX_DEBUG_MODELS_JSON_ENV = 'CODEX_ORCHESTRATOR_DEBUG_MODELS_JSON';
26
34
  export function runDoctor(cwd = process.cwd()) {
27
35
  const dependencies = OPTIONAL_DEPENDENCIES.map((entry) => {
28
36
  const resolved = resolveOptionalDependency(entry.name, cwd);
@@ -79,11 +87,12 @@ export function runDoctor(cwd = process.cwd()) {
79
87
  if (readiness.config.status !== 'ok') {
80
88
  missing.push(`${DEVTOOLS_SKILL_NAME}-config`);
81
89
  }
82
- const codexDefaults = inspectCodexDefaultsAdvisory(process.env);
83
90
  const codexBin = resolveCodexCliBin(process.env);
84
91
  const managedOptIn = isManagedCodexCliEnabled(process.env);
85
92
  const managedCodex = resolveCodexCliReadiness(process.env);
86
- const features = readCodexFeatureFlags(codexBin);
93
+ const featureProbe = readCodexFeatureProbe(codexBin, process.env);
94
+ const features = featureProbe.flags;
95
+ const codexDefaults = inspectCodexDefaultsAdvisory(process.env, codexBin, featureProbe);
87
96
  const collabFeatureKey = features === null
88
97
  ? null
89
98
  : Object.prototype.hasOwnProperty.call(features, 'multi_agent')
@@ -104,10 +113,30 @@ export function runDoctor(cwd = process.cwd()) {
104
113
  : null;
105
114
  const cloudStatus = !cloudCmdAvailable ? 'unavailable' : cloudEnvIdConfigured ? 'ok' : 'not_configured';
106
115
  const cloudFallbackPolicy = resolveCloudFallbackPolicy();
107
- const delegationConfig = inspectDelegationConfig();
108
- const delegationStatus = delegationConfig.status === 'ok' ? 'ok' : 'missing-config';
116
+ const repoRoot = resolveDoctorRepoRoot(cwd);
117
+ const delegationSnapshot = inspectDelegationMcpConfig(process.env);
118
+ const delegationTransport = classifyDelegationTransport(delegationSnapshot.entry);
119
+ const delegationStartup = probeDelegationInitialize(delegationSnapshot.entry, { env: process.env });
120
+ const delegationProcesses = inspectDelegateServerProcesses({ repoRoot });
121
+ const delegationStatus = delegationSnapshot.status !== 'ok'
122
+ ? 'missing-config'
123
+ : delegationTransport.status !== 'safe'
124
+ || delegationStartup.status === 'slow'
125
+ || delegationStartup.status === 'failed'
126
+ || delegationProcesses.status === 'stale'
127
+ ? 'warning'
128
+ : delegationProcesses.status === 'unavailable'
129
+ ? 'unavailable'
130
+ : 'ok';
131
+ const delegationBlocksOverallStatus = delegationStatus === 'missing-config';
132
+ const providers = inspectProviderReadiness(repoRoot, process.env);
109
133
  return {
110
- status: missing.length === 0 && codexDefaults.status === 'ok' ? 'ok' : 'warning',
134
+ status: missing.length === 0 &&
135
+ codexDefaults.status === 'ok' &&
136
+ providers.status === 'ok' &&
137
+ !delegationBlocksOverallStatus
138
+ ? 'ok'
139
+ : 'warning',
111
140
  missing,
112
141
  dependencies,
113
142
  devtools,
@@ -141,24 +170,71 @@ export function runDoctor(cwd = process.cwd()) {
141
170
  },
142
171
  delegation: {
143
172
  status: delegationStatus,
144
- config: delegationConfig,
145
- enablement: [
146
- 'Quick fix: codex-orchestrator doctor --apply --yes',
147
- 'Run: codex-orchestrator delegation setup --yes',
148
- 'Or manually: codex mcp add delegation -- codex-orchestrator delegate-server',
149
- "Enable for a run with: codex -c 'mcp_servers.delegation.enabled=true' ...",
150
- 'See: codex-orchestrator init codex'
151
- ]
152
- }
173
+ config: {
174
+ status: delegationSnapshot.status,
175
+ path: delegationSnapshot.path,
176
+ detail: delegationSnapshot.detail,
177
+ source: delegationSnapshot.entry?.source,
178
+ pinned_repo: delegationSnapshot.entry?.pinnedRepo ?? null
179
+ },
180
+ transport: {
181
+ status: delegationTransport.status,
182
+ kind: delegationTransport.kind,
183
+ command_line: delegationTransport.commandLine,
184
+ detail: delegationTransport.detail
185
+ },
186
+ startup: {
187
+ status: delegationStartup.status,
188
+ latency_ms: delegationStartup.latencyMs,
189
+ threshold_ms: delegationStartup.thresholdMs,
190
+ detail: delegationStartup.detail
191
+ },
192
+ processes: {
193
+ status: delegationProcesses.status,
194
+ active_count: delegationProcesses.activeCount,
195
+ active_pids: delegationProcesses.activePids,
196
+ stale_count: delegationProcesses.staleCount,
197
+ stale_pids: delegationProcesses.stalePids,
198
+ stale_rss_mb: Number((delegationProcesses.staleRssKb / 1024).toFixed(1)),
199
+ threshold_minutes: delegationProcesses.thresholdSeconds / 60,
200
+ detail: delegationProcesses.detail,
201
+ details: delegationProcesses.details.map((detail) => ({
202
+ pid: detail.pid,
203
+ ppid: detail.ppid,
204
+ elapsed_seconds: detail.elapsedSeconds,
205
+ rss_mb: Number((detail.rssKb / 1024).toFixed(1)),
206
+ cwd: detail.cwd,
207
+ parent_pid: detail.parentPid,
208
+ parent_cwd: detail.parentCwd,
209
+ root_codex_parent_pid: detail.rootCodexParentPid,
210
+ root_codex_parent_cwd: detail.rootCodexParentCwd,
211
+ classification: detail.classification,
212
+ classification_detail: detail.classificationDetail,
213
+ manifest_path: detail.manifestAssociation?.manifestPath ?? null,
214
+ issue_identifier: detail.manifestAssociation?.issueIdentifier ?? null,
215
+ pipeline_id: detail.manifestAssociation?.pipelineId ?? null,
216
+ task_id: detail.manifestAssociation?.taskId ?? null,
217
+ run_id: detail.manifestAssociation?.runId ?? null,
218
+ status: detail.manifestAssociation?.status ?? null
219
+ }))
220
+ },
221
+ enablement: buildDelegationEnablementGuidance({
222
+ configStatus: delegationSnapshot.status,
223
+ transportStatus: delegationTransport.status,
224
+ directTransportGuidance: buildDelegationDirectTransportGuidance()
225
+ })
226
+ },
227
+ providers
153
228
  };
154
229
  }
155
230
  export async function runDoctorCloudPreflight(options = {}) {
156
- const env = options.env ?? process.env;
157
- const cwd = options.cwd ?? process.cwd();
158
- const configuredRoot = normalizeOptionalString(env.CODEX_ORCHESTRATOR_ROOT);
231
+ const env = sanitizeProviderOverrideEnv(options.env ?? process.env);
232
+ const explicitCwd = normalizeOptionalString(options.cwd);
233
+ const cwd = explicitCwd ? resolve(explicitCwd) : process.cwd();
234
+ // An explicit cwd is the caller's repo hint; only fall back to the ambient root override when cwd is implicit.
235
+ const configuredRoot = explicitCwd ? null : normalizeOptionalString(env.CODEX_ORCHESTRATOR_ROOT);
159
236
  const rootHint = configuredRoot ? resolve(cwd, configuredRoot) : cwd;
160
237
  const repoRoot = resolveDoctorRepoRoot(rootHint);
161
- const codexBin = resolveCodexCliBin(env);
162
238
  const taskId = normalizeOptionalString(options.taskId)
163
239
  ?? normalizeOptionalString(env.MCP_RUNNER_TASK_ID)
164
240
  ?? normalizeOptionalString(env.TASK)
@@ -185,41 +261,113 @@ export async function runDoctorCloudPreflight(options = {}) {
185
261
  ?? planMetadataEnvironmentId
186
262
  ?? normalizeOptionalString(env.CODEX_CLOUD_ENV_ID)
187
263
  ?? resolveTaskMetadataCloudEnvironmentId(repoRoot, taskId);
188
- const branch = normalizeOptionalBranch(options.branch) ?? normalizeOptionalBranch(env.CODEX_CLOUD_BRANCH);
189
- const preflight = await runCloudPreflight({
264
+ const preflight = await runCloudPreflight(buildCloudPreflightRequest({
190
265
  repoRoot,
191
- codexBin,
192
266
  environmentId,
193
- branch,
267
+ branch: options.branch,
194
268
  env
195
- });
269
+ }));
270
+ const authProvenance = preflight.details.authProvenance ??
271
+ buildCloudPreflightAuthProvenance({
272
+ env,
273
+ environmentId: preflight.details.environmentId,
274
+ branch: preflight.details.branch
275
+ });
196
276
  const issues = planMetadataIssue ? [planMetadataIssue, ...preflight.issues] : preflight.issues;
277
+ const securityAdvisories = inspectCodexSandboxSecurityAdvisories({ env });
197
278
  const guidance = buildCloudPreflightGuidance(issues);
198
279
  return {
199
280
  ok: preflight.ok && planMetadataIssue === null,
200
281
  details: {
201
282
  codex_bin: preflight.details.codexBin,
202
283
  environment_id: preflight.details.environmentId,
203
- branch: preflight.details.branch
284
+ branch: preflight.details.branch,
285
+ auth_provenance: {
286
+ provider_kind: authProvenance.providerKind,
287
+ active_profile_fingerprint: authProvenance.activeProfileFingerprint,
288
+ active_account_fingerprint: authProvenance.activeAccountFingerprint,
289
+ cloud_env_id: authProvenance.cloudEnvId,
290
+ cloud_branch: authProvenance.cloudBranch,
291
+ credential_source: authProvenance.credentialSource,
292
+ auth_freshness: authProvenance.authFreshness
293
+ }
204
294
  },
205
295
  issues,
296
+ security_advisories: securityAdvisories,
206
297
  guidance
207
298
  };
208
299
  }
300
+ export function inspectCodexSandboxSecurityAdvisories(options = {}) {
301
+ const env = options.env ?? process.env;
302
+ const advisories = [];
303
+ const configPath = join(resolveCodexHome(env), 'config.toml');
304
+ if (existsSync(configPath)) {
305
+ try {
306
+ const raw = readFileSync(configPath, 'utf8');
307
+ const parsed = getTomlParser().parse(raw);
308
+ if (isRecord(parsed)) {
309
+ const sandboxMode = normalizeOptionalString(readStringValue(parsed.sandbox_mode));
310
+ if (sandboxMode === 'danger-full-access') {
311
+ advisories.push({
312
+ code: 'codex_config_danger_full_access',
313
+ scope: 'local-only',
314
+ severity: 'warning',
315
+ message: 'Codex config sets top-level sandbox_mode to danger-full-access.',
316
+ guidance: 'Treat this as a local-only advisory; do not use it to satisfy cloud readiness or weaken CO sandbox defaults.',
317
+ details: {
318
+ path: configPath,
319
+ sandbox_mode: sandboxMode
320
+ }
321
+ });
322
+ }
323
+ }
324
+ }
325
+ catch {
326
+ // Existing Codex defaults checks already report invalid TOML; keep this advisory focused on security posture.
327
+ }
328
+ }
329
+ const platform = options.platform ?? process.platform;
330
+ const releaseText = normalizeOptionalString(options.osRelease ?? osRelease());
331
+ if (isWsl1Release(platform, releaseText)) {
332
+ advisories.push({
333
+ code: 'wsl1_bubblewrap_unsupported',
334
+ scope: 'local-only',
335
+ severity: 'warning',
336
+ message: 'WSL1 detected; Codex bubblewrap sandbox behavior is unsupported for this local platform.',
337
+ guidance: 'Run local Codex sandbox checks on WSL2/Linux/macOS, or keep this as a local-only limitation; it is not cloud canary evidence.',
338
+ details: {
339
+ platform,
340
+ os_release: releaseText ?? undefined
341
+ }
342
+ });
343
+ }
344
+ return advisories;
345
+ }
346
+ function isWsl1Release(platform, releaseText) {
347
+ if (platform !== 'linux' || !releaseText) {
348
+ return false;
349
+ }
350
+ const normalized = releaseText.toLowerCase();
351
+ return normalized.includes('microsoft') && !normalized.includes('microsoft-standard') && !normalized.includes('wsl2');
352
+ }
209
353
  function resolveDoctorRepoRoot(cwd) {
210
354
  const fallback = resolve(cwd);
211
355
  let current = fallback;
356
+ let providerRootCandidate = null;
212
357
  while (current) {
213
358
  if (existsSync(join(current, 'tasks', 'index.json'))) {
214
359
  return current;
215
360
  }
361
+ if (!providerRootCandidate && existsSync(join(current, PROVIDER_ROOT_RELATIVE_PATH))) {
362
+ providerRootCandidate = current;
363
+ }
216
364
  const parent = dirname(current);
217
365
  if (parent === current) {
218
366
  break;
219
367
  }
220
368
  current = parent;
221
369
  }
222
- return fallback;
370
+ return providerRootCandidate ?? fallback;
223
371
  }
224
372
  export function formatDoctorCloudPreflightSummary(result) {
225
373
  const lines = [];
@@ -227,6 +375,11 @@ export function formatDoctorCloudPreflightSummary(result) {
227
375
  lines.push(` - codex bin: ${result.details.codex_bin}`);
228
376
  lines.push(` - environment id: ${result.details.environment_id ?? '<unset>'}`);
229
377
  lines.push(` - branch: ${result.details.branch ?? '<unset>'}`);
378
+ lines.push(` - auth provider: ${result.details.auth_provenance.provider_kind}`);
379
+ lines.push(` - credential source: ${result.details.auth_provenance.credential_source ?? '<none detected>'}`);
380
+ lines.push(` - profile fingerprint: ${result.details.auth_provenance.active_profile_fingerprint ?? '<unset>'}`);
381
+ lines.push(` - account fingerprint: ${result.details.auth_provenance.active_account_fingerprint ?? '<unset>'}`);
382
+ lines.push(` - auth freshness: ${result.details.auth_provenance.auth_freshness}`);
230
383
  if (result.issues.length > 0) {
231
384
  lines.push(' - issues:');
232
385
  for (const issue of result.issues) {
@@ -239,6 +392,19 @@ export function formatDoctorCloudPreflightSummary(result) {
239
392
  lines.push(` - ${item}`);
240
393
  }
241
394
  }
395
+ if (result.security_advisories.length > 0) {
396
+ lines.push(' - sandbox/security advisories:');
397
+ for (const advisory of result.security_advisories) {
398
+ lines.push(` - [${advisory.code}/${advisory.scope}] ${advisory.message}`);
399
+ lines.push(` guidance: ${advisory.guidance}`);
400
+ if (advisory.details?.path) {
401
+ lines.push(` path: ${advisory.details.path}`);
402
+ }
403
+ if (advisory.details?.platform || advisory.details?.os_release) {
404
+ lines.push(` platform: ${advisory.details.platform ?? '<unknown>'}, os_release: ${advisory.details.os_release ?? '<unknown>'}`);
405
+ }
406
+ }
407
+ }
242
408
  return lines;
243
409
  }
244
410
  export function formatDoctorSummary(result) {
@@ -308,10 +474,21 @@ export function formatDoctorSummary(result) {
308
474
  lines.push(` detail: ${result.codex_defaults.config.detail}`);
309
475
  }
310
476
  lines.push(` - model: ${result.codex_defaults.checks.model.status} (actual: ${result.codex_defaults.checks.model.actual ?? '<unset>'}, expected: ${result.codex_defaults.checks.model.expected})`);
477
+ lines.push(` - review_model: ${result.codex_defaults.checks.review_model.status} (actual: ${result.codex_defaults.checks.review_model.actual ?? '<unset>'}, expected: ${result.codex_defaults.checks.review_model.expected})`);
311
478
  lines.push(` - model_reasoning_effort: ${result.codex_defaults.checks.model_reasoning_effort.status} (actual: ${result.codex_defaults.checks.model_reasoning_effort.actual ?? '<unset>'}, expected >= ${result.codex_defaults.checks.model_reasoning_effort.expected_minimum})`);
312
- lines.push(` - agents.max_threads: ${result.codex_defaults.checks.max_threads.status} (actual: ${result.codex_defaults.checks.max_threads.actual ?? '<unset>'}, expected >= ${result.codex_defaults.checks.max_threads.expected_minimum})`);
313
- lines.push(` - agents.max_depth: ${result.codex_defaults.checks.max_depth.status} (actual: ${result.codex_defaults.checks.max_depth.actual ?? '<unset>'}, expected >= ${result.codex_defaults.checks.max_depth.expected_minimum})`);
314
- lines.push(` - agents.max_spawn_depth: ${result.codex_defaults.checks.max_spawn_depth.status} (actual: ${result.codex_defaults.checks.max_spawn_depth.actual ?? '<unset>'}, expected >= ${result.codex_defaults.checks.max_spawn_depth.expected_minimum})`);
479
+ if (result.codex_defaults.checks.max_threads.status === 'skipped') {
480
+ lines.push(` - agents.max_threads: skipped (actual: ${result.codex_defaults.checks.max_threads.actual ?? '<unset>'}; ${result.codex_defaults.checks.max_threads.detail ?? 'omitted by policy'})`);
481
+ }
482
+ else if (result.codex_defaults.checks.max_threads.detail) {
483
+ lines.push(` - agents.max_threads: ${result.codex_defaults.checks.max_threads.status} (actual: ${result.codex_defaults.checks.max_threads.actual ?? '<unset>'}; ${result.codex_defaults.checks.max_threads.detail})`);
484
+ }
485
+ else {
486
+ lines.push(` - agents.max_threads: ${result.codex_defaults.checks.max_threads.status} (actual: ${result.codex_defaults.checks.max_threads.actual ?? '<unset>'}, expected >= ${result.codex_defaults.checks.max_threads.expected_minimum})`);
487
+ }
488
+ lines.push(` - agents.max_depth: ${result.codex_defaults.checks.max_depth.status} (actual: ${result.codex_defaults.checks.max_depth.actual ?? '<unset>'}, expected >= ${result.codex_defaults.checks.max_depth.expected_minimum} when set; <unset> accepted)`);
489
+ if (result.codex_defaults.legacy_max_spawn_depth?.present) {
490
+ lines.push(` - legacy agents.max_spawn_depth: ${result.codex_defaults.legacy_max_spawn_depth.status} (actual: ${result.codex_defaults.legacy_max_spawn_depth.actual ?? '<unset>'}; ${result.codex_defaults.legacy_max_spawn_depth.detail})`);
491
+ }
315
492
  for (const line of result.codex_defaults.guidance) {
316
493
  lines.push(` - ${line}`);
317
494
  }
@@ -340,24 +517,192 @@ export function formatDoctorSummary(result) {
340
517
  if (result.delegation.config.detail) {
341
518
  lines.push(` detail: ${result.delegation.config.detail}`);
342
519
  }
520
+ if (result.delegation.config.source) {
521
+ lines.push(` - source: ${result.delegation.config.source}`);
522
+ }
523
+ lines.push(` - transport: ${result.delegation.transport.status} (${result.delegation.transport.kind})`);
524
+ if (result.delegation.transport.command_line) {
525
+ lines.push(` command: ${result.delegation.transport.command_line}`);
526
+ }
527
+ lines.push(` detail: ${result.delegation.transport.detail}`);
528
+ lines.push(` - initialize: ${result.delegation.startup.status} (latency: ${result.delegation.startup.latency_ms ?? '<skipped>'} ms, threshold: ${result.delegation.startup.threshold_ms} ms)`);
529
+ lines.push(` detail: ${result.delegation.startup.detail}`);
530
+ lines.push(` - processes: ${result.delegation.processes.status} (active: ${result.delegation.processes.active_count}, stale: ${result.delegation.processes.stale_count}, stale rss: ${result.delegation.processes.stale_rss_mb.toFixed(1)} MB)`);
531
+ lines.push(` detail: ${result.delegation.processes.detail}`);
532
+ if (result.delegation.processes.stale_pids.length > 0) {
533
+ lines.push(` stale pids: ${result.delegation.processes.stale_pids.join(', ')}`);
534
+ for (const detail of result.delegation.processes.details
535
+ .filter((entry) => entry.classification === 'stale-parent-session' || entry.classification === 'stale-orphan')
536
+ .slice(0, 3)) {
537
+ lines.push(` stale detail: ${formatDelegateServerProcessSummary({
538
+ pid: detail.pid,
539
+ classification: detail.classification,
540
+ cwd: detail.cwd,
541
+ parentPid: detail.parent_pid,
542
+ parentCwd: detail.parent_cwd,
543
+ rootCodexParentPid: detail.root_codex_parent_pid,
544
+ rootCodexParentCwd: detail.root_codex_parent_cwd,
545
+ manifestPath: detail.manifest_path
546
+ })}`);
547
+ }
548
+ }
343
549
  for (const line of result.delegation.enablement) {
344
550
  lines.push(` - ${line}`);
345
551
  }
552
+ lines.push(`Providers: ${result.providers.status}`);
553
+ lines.push(` - repo examples: ${result.providers.repo_examples.status} (${result.providers.repo_examples.root})`);
554
+ if (result.providers.repo_examples.missing.length > 0) {
555
+ lines.push(` missing: ${result.providers.repo_examples.missing.join(', ')}`);
556
+ }
557
+ lines.push(` - control policy: ${result.providers.control_policy.status} (${result.providers.control_policy.path})`);
558
+ if (result.providers.control_policy.detail) {
559
+ lines.push(` detail: ${result.providers.control_policy.detail}`);
560
+ }
561
+ lines.push(` - Linear: ${result.providers.linear.status}`);
562
+ lines.push(` credentials: ${result.providers.linear.credentials_present ? 'present' : 'missing'}`);
563
+ lines.push(` binding: ${result.providers.linear.binding_present ? 'present' : 'missing'}`);
564
+ lines.push(` webhook secret: ${result.providers.linear.webhook_secret_present ? 'present' : 'missing'}`);
565
+ lines.push(` dispatch_pilot: ${renderProviderToggleSummary(result.providers.linear.dispatch_pilot_enabled, result.providers.linear.dispatch_pilot_provider)}`);
566
+ lines.push(` - Telegram: ${result.providers.telegram.status}`);
567
+ lines.push(` polling: ${result.providers.telegram.polling_enabled ? 'enabled' : 'disabled'}`);
568
+ lines.push(` bot token: ${result.providers.telegram.bot_token_present ? 'present' : 'missing'}`);
569
+ lines.push(` allowlisted chats: ${result.providers.telegram.allowed_chat_ids}`);
570
+ lines.push(` mutations: ${result.providers.telegram.mutations_enabled ? 'enabled' : 'disabled'}`);
571
+ lines.push(` push: ${result.providers.telegram.push_enabled ? 'enabled' : 'disabled'}`);
572
+ lines.push(` transport policy: ${renderTransportPolicySummary(result.providers.telegram.telegram_transport_allowed)}`);
573
+ for (const line of result.providers.guidance) {
574
+ lines.push(` - ${line}`);
575
+ }
576
+ return lines;
577
+ }
578
+ export function buildDelegationDirectTransportGuidance(resolver = () => resolveDelegationServerInvocation({ env: process.env, execPath: process.execPath })) {
579
+ try {
580
+ return `Direct dist transport: ${resolver().commandLine} --repo <path>`;
581
+ }
582
+ catch (error) {
583
+ const detail = error instanceof Error ? error.message : String(error);
584
+ return `Direct dist transport unavailable until dist is built: ${detail}`;
585
+ }
586
+ }
587
+ export function buildDelegationEnablementGuidance(options) {
588
+ const lines = [];
589
+ const setupApplyWouldHelp = options.configStatus !== 'ok' || options.transportStatus !== 'safe';
590
+ if (setupApplyWouldHelp) {
591
+ lines.push('Quick fix: codex-orchestrator doctor --apply --yes');
592
+ }
593
+ lines.push('Run: codex-orchestrator delegation setup --yes');
594
+ lines.push('Run: codex-orchestrator delegation cleanup-stale --yes');
595
+ lines.push(options.directTransportGuidance ?? buildDelegationDirectTransportGuidance());
596
+ lines.push("Enable for a run with: codex -c 'mcp_servers.delegation.enabled=true' ...");
597
+ lines.push('See: codex-orchestrator init codex');
346
598
  return lines;
347
599
  }
348
- function inspectCodexDefaultsAdvisory(env = process.env) {
600
+ function inspectProviderReadiness(repoRoot, env = process.env) {
601
+ const providerRoot = join(repoRoot, PROVIDER_ROOT_RELATIVE_PATH);
602
+ const repoExamples = {
603
+ readme: join(providerRoot, 'README.md'),
604
+ env_example: join(providerRoot, 'provider.env.example'),
605
+ control_example: join(providerRoot, 'control.example.json')
606
+ };
607
+ const missingRepoExamples = Object.entries(repoExamples)
608
+ .filter(([, filePath]) => !existsSync(filePath))
609
+ .map(([key]) => key);
610
+ const controlPolicy = readProviderControlPolicy(providerRoot);
611
+ const linearSourceSetup = resolveLinearSourceSetup({
612
+ provider: 'linear',
613
+ workspace_id: controlPolicy.dispatch_pilot_source_setup?.workspace_id ?? null,
614
+ team_id: controlPolicy.dispatch_pilot_source_setup?.team_id ?? null,
615
+ project_id: controlPolicy.dispatch_pilot_source_setup?.project_id ?? null
616
+ }, env);
617
+ const linearCredentialsPresent = hasLinearApiCredentials(env);
618
+ const linearBindingPresent = hasLinearSourceBinding(linearSourceSetup);
619
+ const linearWebhookSecretPresent = Boolean(normalizeOptionalString(env.CO_LINEAR_WEBHOOK_SECRET));
620
+ const linearRequired = controlPolicy.dispatch_pilot_enabled === true && controlPolicy.dispatch_pilot_provider === 'linear';
621
+ const linearReady = linearCredentialsPresent &&
622
+ linearBindingPresent &&
623
+ linearWebhookSecretPresent &&
624
+ linearRequired;
625
+ const telegramPollingEnabled = parseEnvBoolean(env.CO_TELEGRAM_POLLING_ENABLED);
626
+ const telegramBotTokenPresent = Boolean(normalizeOptionalString(env.CO_TELEGRAM_BOT_TOKEN));
627
+ const telegramAllowedChatIds = parseCsvList(env.CO_TELEGRAM_ALLOWED_CHAT_IDS).length;
628
+ const telegramMutationsEnabled = parseEnvBoolean(env.CO_TELEGRAM_ENABLE_MUTATIONS);
629
+ const telegramPushEnabled = parseEnvBoolean(env.CO_TELEGRAM_PUSH_ENABLED);
630
+ const telegramRequired = controlPolicy.telegram_transport_allowed === true;
631
+ const telegramReady = telegramPollingEnabled &&
632
+ telegramBotTokenPresent &&
633
+ telegramAllowedChatIds > 0 &&
634
+ telegramMutationsEnabled &&
635
+ telegramRequired;
636
+ const repoExamplesStatus = missingRepoExamples.length === 0 ? 'ok' : 'missing';
637
+ return {
638
+ status: repoExamplesStatus === 'ok' &&
639
+ controlPolicy.status === 'ok' &&
640
+ (!linearRequired || linearReady) &&
641
+ (!telegramRequired || telegramReady)
642
+ ? 'ok'
643
+ : 'advisory',
644
+ repo_examples: {
645
+ status: repoExamplesStatus,
646
+ root: providerRoot,
647
+ paths: repoExamples,
648
+ missing: missingRepoExamples
649
+ },
650
+ control_policy: controlPolicy,
651
+ linear: {
652
+ status: linearReady ? 'ready' : 'incomplete',
653
+ credentials_present: linearCredentialsPresent,
654
+ binding_present: linearBindingPresent,
655
+ webhook_secret_present: linearWebhookSecretPresent,
656
+ dispatch_pilot_enabled: controlPolicy.dispatch_pilot_enabled,
657
+ dispatch_pilot_provider: controlPolicy.dispatch_pilot_provider
658
+ },
659
+ telegram: {
660
+ status: telegramReady ? 'ready' : 'incomplete',
661
+ polling_enabled: telegramPollingEnabled,
662
+ bot_token_present: telegramBotTokenPresent,
663
+ allowed_chat_ids: telegramAllowedChatIds,
664
+ mutations_enabled: telegramMutationsEnabled,
665
+ push_enabled: telegramPushEnabled,
666
+ telegram_transport_allowed: controlPolicy.telegram_transport_allowed
667
+ },
668
+ guidance: [
669
+ 'Seed the current repo with: codex-orchestrator init codex --cwd <repo>',
670
+ 'Review .codex/providers/provider.env.example and .codex/providers/control.example.json before enabling providers.',
671
+ 'Re-run codex-orchestrator doctor --format json after exporting provider env vars to confirm readiness.'
672
+ ]
673
+ };
674
+ }
675
+ function inspectCodexDefaultsAdvisory(env = process.env, codexBin = resolveCodexCliBin(env), featureProbe = readCodexFeatureProbe(codexBin, env)) {
349
676
  const configPath = join(resolveCodexHome(env), 'config.toml');
350
677
  const checks = {
351
- model: { status: 'advisory', expected: BASELINE_MODEL, actual: null },
678
+ model: { status: 'advisory', expected: formatModelDefaultExpectation(BASELINE_MODEL), actual: null },
679
+ review_model: {
680
+ status: 'advisory',
681
+ expected: formatModelDefaultExpectation(BASELINE_REVIEW_MODEL),
682
+ actual: null
683
+ },
352
684
  model_reasoning_effort: { status: 'advisory', expected_minimum: BASELINE_REASONING_MINIMUM, actual: null },
353
685
  max_threads: { status: 'advisory', expected_minimum: BASELINE_AGENTS.max_threads, actual: null },
354
- max_depth: { status: 'advisory', expected_minimum: BASELINE_AGENTS.max_depth, actual: null },
355
- max_spawn_depth: { status: 'advisory', expected_minimum: BASELINE_AGENTS.max_spawn_depth, actual: null }
686
+ max_depth: { status: 'advisory', expected_minimum: BASELINE_AGENTS.max_depth, actual: null }
356
687
  };
688
+ let legacyMaxSpawnDepth = null;
357
689
  const guidance = [
358
690
  'Run `codex-orchestrator codex defaults --yes` to apply additive baseline defaults.',
359
- 'Additive policy: unrelated config keys are preserved; existing role files stay untouched unless `--force` is set.'
691
+ 'Additive policy: unrelated config keys are preserved; existing role files stay untouched unless `--force` is set or they exactly match a prior CO-managed model baseline.',
692
+ 'When `features.multi_agent_v2=true`, omit `agents.max_threads`; Codex CLI 0.125+ rejects that key.',
693
+ 'Current CO baseline no longer seeds or expects `agents.max_spawn_depth`; keep it only as a legacy local override when an older parser/runtime still honors it.',
694
+ 'Leaving `agents.max_depth` unset remains accepted when local parser/runtime constraints require it.'
360
695
  ];
696
+ const featureProbeDisablesMultiAgentV2 = featureProbe ? codexFeatureProbeDisablesMultiAgentV2(featureProbe) : false;
697
+ const featureProbeIndicatesMultiAgentV2 = !featureProbeDisablesMultiAgentV2
698
+ && (featureProbe?.flags?.multi_agent_v2 === true
699
+ || (featureProbe ? codexFeatureProbeRejectsAgentMaxThreads(featureProbe) : false));
700
+ if (featureProbeIndicatesMultiAgentV2) {
701
+ checks.max_threads.status = 'skipped';
702
+ checks.max_threads.actual = null;
703
+ checks.max_threads.detail =
704
+ 'features.multi_agent_v2=true; omit agents.max_threads because Codex CLI 0.125+ rejects it';
705
+ }
361
706
  if (!existsSync(configPath)) {
362
707
  return {
363
708
  status: 'advisory',
@@ -369,7 +714,7 @@ function inspectCodexDefaultsAdvisory(env = process.env) {
369
714
  let parsed;
370
715
  try {
371
716
  const raw = readFileSync(configPath, 'utf8');
372
- const value = toml.parse(raw);
717
+ const value = getTomlParser().parse(raw);
373
718
  if (!isRecord(value)) {
374
719
  throw new Error('top-level TOML document must be a table.');
375
720
  }
@@ -391,42 +736,322 @@ function inspectCodexDefaultsAdvisory(env = process.env) {
391
736
  };
392
737
  }
393
738
  const model = normalizeOptionalString(readStringValue(parsed.model));
739
+ const reviewModel = normalizeOptionalString(readStringValue(parsed.review_model));
740
+ const localModelCandidates = new Set([model, reviewModel].filter(isLocalModelOptIn));
741
+ const modelAccess = localModelCandidates.size === 0
742
+ ? {
743
+ status: 'unavailable',
744
+ models: new Set(),
745
+ detail: 'model access was not checked because no local ChatGPT-auth model is configured'
746
+ }
747
+ : inspectCodexModelAccess(codexBin, env);
748
+ const verifiedLocalModels = new Set([...localModelCandidates].filter((candidate) => modelAccess.status === 'ok' && modelAccess.models.has(candidate)));
749
+ const unverifiedLocalModels = [...localModelCandidates].filter((candidate) => !verifiedLocalModels.has(candidate));
750
+ for (const candidate of unverifiedLocalModels) {
751
+ guidance.push(`Configured local ChatGPT-auth model ${candidate} is not verified by \`codex debug models\`; rerun local access smoke or use the portable ${BASELINE_MODEL} fallback for this surface.`);
752
+ }
394
753
  checks.model.actual = model;
395
- checks.model.status = model === BASELINE_MODEL ? 'ok' : 'advisory';
754
+ checks.model.status =
755
+ model === BASELINE_MODEL || (isLocalModelOptIn(model) && verifiedLocalModels.has(model))
756
+ ? 'ok'
757
+ : 'advisory';
758
+ checks.review_model.actual = reviewModel;
759
+ checks.review_model.status =
760
+ reviewModel === BASELINE_REVIEW_MODEL || (isLocalModelOptIn(reviewModel) && verifiedLocalModels.has(reviewModel))
761
+ ? 'ok'
762
+ : 'advisory';
396
763
  const reasoning = normalizeOptionalString(readStringValue(parsed.model_reasoning_effort));
397
764
  checks.model_reasoning_effort.actual = reasoning;
398
765
  checks.model_reasoning_effort.status = isReasoningAtLeastMinimum(reasoning, BASELINE_REASONING_MINIMUM)
399
766
  ? 'ok'
400
767
  : 'advisory';
401
768
  const agents = isRecord(parsed.agents) ? parsed.agents : {};
769
+ const multiAgentV2Enabled = featureProbeIndicatesMultiAgentV2
770
+ || (!featureProbeDisablesMultiAgentV2
771
+ && readBooleanValue(readRecordValue(parsed, 'features')?.multi_agent_v2) === true);
402
772
  const maxThreads = readNumberValue(agents.max_threads);
403
773
  const maxDepth = readNumberValue(agents.max_depth);
404
774
  const maxSpawnDepth = readNumberValue(agents.max_spawn_depth);
775
+ const hasMaxThreads = Object.prototype.hasOwnProperty.call(agents, 'max_threads');
405
776
  checks.max_threads.actual = maxThreads;
406
- checks.max_threads.status =
407
- typeof maxThreads === 'number' && maxThreads >= BASELINE_AGENTS.max_threads ? 'ok' : 'advisory';
777
+ if (multiAgentV2Enabled) {
778
+ checks.max_threads.status = hasMaxThreads ? 'advisory' : 'skipped';
779
+ checks.max_threads.detail =
780
+ hasMaxThreads
781
+ ? 'features.multi_agent_v2=true; remove agents.max_threads because Codex CLI 0.125+ rejects it'
782
+ : 'features.multi_agent_v2=true; omit agents.max_threads because Codex CLI 0.125+ rejects it';
783
+ }
784
+ else {
785
+ checks.max_threads.status =
786
+ typeof maxThreads === 'number' && maxThreads >= BASELINE_AGENTS.max_threads ? 'ok' : 'advisory';
787
+ }
408
788
  checks.max_depth.actual = maxDepth;
409
- checks.max_depth.status = typeof maxDepth === 'number' && maxDepth >= BASELINE_AGENTS.max_depth ? 'ok' : 'advisory';
410
- checks.max_spawn_depth.actual = maxSpawnDepth;
411
- checks.max_spawn_depth.status =
412
- typeof maxSpawnDepth === 'number' && maxSpawnDepth >= BASELINE_AGENTS.max_spawn_depth ? 'ok' : 'advisory';
413
- const allChecksOk = Object.values(checks).every((check) => check.status === 'ok');
789
+ checks.max_depth.status =
790
+ maxDepth === null || (typeof maxDepth === 'number' && maxDepth >= BASELINE_AGENTS.max_depth) ? 'ok' : 'advisory';
791
+ if (maxSpawnDepth !== null) {
792
+ const legacySpawnDepthOk = maxSpawnDepth >= BASELINE_AGENTS.max_depth;
793
+ legacyMaxSpawnDepth = {
794
+ present: true,
795
+ status: legacySpawnDepthOk ? 'ok' : 'advisory',
796
+ actual: maxSpawnDepth,
797
+ detail: legacySpawnDepthOk
798
+ ? 'legacy override detected; safe for the CO baseline, but remove it when your local parser/runtime no longer consumes spawn-depth caps'
799
+ : `older parser/runtime may still treat this as a hard cap below the CO baseline depth; raise it to >= ${BASELINE_AGENTS.max_depth} or remove it`
800
+ };
801
+ }
802
+ const allChecksOk = Object.values(checks).every((check) => check.status === 'ok' || check.status === 'skipped')
803
+ && unverifiedLocalModels.length === 0
804
+ && legacyMaxSpawnDepth?.status !== 'advisory';
414
805
  return {
415
806
  status: allChecksOk ? 'ok' : 'advisory',
416
807
  config: { path: configPath, status: 'ok' },
417
808
  checks,
809
+ legacy_max_spawn_depth: legacyMaxSpawnDepth,
418
810
  guidance
419
811
  };
420
812
  }
813
+ function inspectCodexModelAccess(codexBin, env) {
814
+ const overrideJson = env[CODEX_DEBUG_MODELS_JSON_ENV];
815
+ if (typeof overrideJson === 'string' && overrideJson.trim().length > 0) {
816
+ return parseCodexDebugModels(overrideJson, `${CODEX_DEBUG_MODELS_JSON_ENV} override`);
817
+ }
818
+ const result = spawnSync(codexBin, ['debug', 'models'], {
819
+ encoding: 'utf8',
820
+ env,
821
+ timeout: 5000,
822
+ maxBuffer: 5 * 1024 * 1024
823
+ });
824
+ if (result.error) {
825
+ return {
826
+ status: 'unavailable',
827
+ models: new Set(),
828
+ detail: result.error.message
829
+ };
830
+ }
831
+ if (result.status !== 0) {
832
+ const stderr = typeof result.stderr === 'string' ? result.stderr.trim() : '';
833
+ return {
834
+ status: 'unavailable',
835
+ models: new Set(),
836
+ detail: stderr || `codex debug models exited ${result.status ?? 'without a status'}`
837
+ };
838
+ }
839
+ return parseCodexDebugModels(result.stdout, '`codex debug models`');
840
+ }
841
+ function parseCodexDebugModels(source, detailPrefix) {
842
+ if (typeof source !== 'string' || source.trim().length === 0) {
843
+ return {
844
+ status: 'unavailable',
845
+ models: new Set(),
846
+ detail: `${detailPrefix} produced no model catalog output`
847
+ };
848
+ }
849
+ try {
850
+ const parsed = JSON.parse(source);
851
+ const models = new Set();
852
+ const entries = isRecord(parsed) && Array.isArray(parsed.models) ? parsed.models : [];
853
+ for (const entry of entries) {
854
+ if (!isRecord(entry)) {
855
+ continue;
856
+ }
857
+ const slug = readStringValue(entry.slug);
858
+ if (slug) {
859
+ models.add(slug);
860
+ }
861
+ }
862
+ return {
863
+ status: models.size > 0 ? 'ok' : 'unavailable',
864
+ models,
865
+ detail: `${detailPrefix} reported ${models.size} model(s)`
866
+ };
867
+ }
868
+ catch (error) {
869
+ return {
870
+ status: 'unavailable',
871
+ models: new Set(),
872
+ detail: error instanceof Error ? error.message : String(error)
873
+ };
874
+ }
875
+ }
876
+ function getTomlParser() {
877
+ if (tomlParser) {
878
+ return tomlParser;
879
+ }
880
+ if (tomlParser === null) {
881
+ throw new Error('Failed to load @iarna/toml.');
882
+ }
883
+ try {
884
+ tomlParser = require('@iarna/toml');
885
+ return tomlParser;
886
+ }
887
+ catch (error) {
888
+ tomlParser = null;
889
+ throw error;
890
+ }
891
+ }
421
892
  function isRecord(value) {
422
893
  return typeof value === 'object' && value !== null && !Array.isArray(value);
423
894
  }
424
- function readStringValue(value) {
425
- return typeof value === 'string' ? value : null;
895
+ function readStringValue(value, ...keys) {
896
+ if (keys.length === 0) {
897
+ return typeof value === 'string' ? value : null;
898
+ }
899
+ if (!isRecord(value)) {
900
+ return null;
901
+ }
902
+ for (const key of keys) {
903
+ if (typeof value[key] === 'string') {
904
+ return value[key];
905
+ }
906
+ }
907
+ return null;
426
908
  }
427
909
  function readNumberValue(value) {
428
910
  return typeof value === 'number' && Number.isFinite(value) ? value : null;
429
911
  }
912
+ function readBooleanValue(value) {
913
+ return typeof value === 'boolean' ? value : null;
914
+ }
915
+ function readRecordValue(value, ...keys) {
916
+ if (!isRecord(value)) {
917
+ return null;
918
+ }
919
+ for (const key of keys) {
920
+ if (isRecord(value[key])) {
921
+ return value[key];
922
+ }
923
+ }
924
+ return null;
925
+ }
926
+ function readStringArrayValue(value, ...keys) {
927
+ const raw = isRecord(value)
928
+ ? keys.map((key) => value[key]).find((entry) => Array.isArray(entry))
929
+ : Array.isArray(value)
930
+ ? value
931
+ : undefined;
932
+ if (!Array.isArray(raw)) {
933
+ return undefined;
934
+ }
935
+ return raw
936
+ .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))
937
+ .filter((entry) => entry.length > 0);
938
+ }
939
+ function parseEnvBoolean(value) {
940
+ const normalized = normalizeOptionalString(value);
941
+ if (!normalized) {
942
+ return false;
943
+ }
944
+ return ['1', 'true', 'yes', 'on'].includes(normalized.toLowerCase());
945
+ }
946
+ function parseCsvList(value) {
947
+ const normalized = normalizeOptionalString(value);
948
+ if (!normalized) {
949
+ return [];
950
+ }
951
+ return normalized
952
+ .split(',')
953
+ .map((entry) => entry.trim())
954
+ .filter((entry) => entry.length > 0);
955
+ }
956
+ function readProviderControlPolicy(providerRoot) {
957
+ const preferredPath = join(providerRoot, 'control.json');
958
+ const fallbackPath = join(providerRoot, 'control.example.json');
959
+ const candidate = existsSync(preferredPath) ? preferredPath : existsSync(fallbackPath) ? fallbackPath : preferredPath;
960
+ if (!existsSync(candidate)) {
961
+ return {
962
+ status: 'missing',
963
+ path: preferredPath,
964
+ dispatch_pilot_enabled: null,
965
+ dispatch_pilot_provider: null,
966
+ dispatch_pilot_source_setup: null,
967
+ transport_mutating_enabled: null,
968
+ telegram_transport_allowed: null
969
+ };
970
+ }
971
+ try {
972
+ const parsed = JSON.parse(readFileSync(candidate, 'utf8'));
973
+ if (!isRecord(parsed)) {
974
+ throw new Error('provider control policy must be a JSON object');
975
+ }
976
+ const featureToggles = isRecord(parsed.feature_toggles) ? parsed.feature_toggles : null;
977
+ const dispatchPilot = resolveDispatchPilotControls(featureToggles);
978
+ const dispatchSource = readRecordValue(dispatchPilot, 'source');
979
+ const dispatchBindingSource = readRecordValue(dispatchSource, 'linear') ?? dispatchSource;
980
+ const dispatchPilotEnabled = readBooleanValue(dispatchPilot?.enabled);
981
+ const rawDispatchPilotProvider = normalizeOptionalString(readStringValue(dispatchSource, 'provider', 'source_provider', 'sourceProvider'));
982
+ const normalizedDispatchPilotProvider = normalizeDispatchSourceProvider(rawDispatchPilotProvider ?? undefined);
983
+ if (dispatchPilotEnabled === true) {
984
+ if (!dispatchSource) {
985
+ throw new Error('dispatch_pilot.source is required when dispatch_pilot.enabled=true');
986
+ }
987
+ if (!normalizedDispatchPilotProvider) {
988
+ throw new Error(rawDispatchPilotProvider
989
+ ? `unsupported dispatch_pilot.source.provider: ${rawDispatchPilotProvider}`
990
+ : 'dispatch_pilot.source.provider is required when dispatch_pilot.enabled=true');
991
+ }
992
+ }
993
+ const transportMutating = resolveTransportMutatingControls(featureToggles);
994
+ const transportMutatingEnabled = readBooleanValue(transportMutating?.enabled);
995
+ const allowedTransports = readStringArrayValue(transportMutating, 'allowed_transports', 'allowedTransports');
996
+ const telegramTransportAllowed = transportMutating === null
997
+ ? null
998
+ : transportMutatingEnabled === true
999
+ ? allowedTransports ? allowedTransports.includes('telegram') : true
1000
+ : false;
1001
+ return {
1002
+ status: 'ok',
1003
+ path: candidate,
1004
+ dispatch_pilot_enabled: dispatchPilotEnabled,
1005
+ dispatch_pilot_provider: normalizedDispatchPilotProvider ?? rawDispatchPilotProvider,
1006
+ dispatch_pilot_source_setup: dispatchBindingSource
1007
+ ? {
1008
+ workspace_id: normalizeOptionalString(readStringValue(dispatchBindingSource, 'workspace_id', 'workspaceId')),
1009
+ team_id: normalizeOptionalString(readStringValue(dispatchBindingSource, 'team_id', 'teamId')),
1010
+ project_id: normalizeOptionalString(readStringValue(dispatchBindingSource, 'project_id', 'projectId'))
1011
+ }
1012
+ : null,
1013
+ transport_mutating_enabled: transportMutatingEnabled,
1014
+ telegram_transport_allowed: telegramTransportAllowed
1015
+ };
1016
+ }
1017
+ catch (error) {
1018
+ return {
1019
+ status: 'invalid',
1020
+ path: candidate,
1021
+ detail: error instanceof Error ? error.message : String(error),
1022
+ dispatch_pilot_enabled: null,
1023
+ dispatch_pilot_provider: null,
1024
+ dispatch_pilot_source_setup: null,
1025
+ transport_mutating_enabled: null,
1026
+ telegram_transport_allowed: null
1027
+ };
1028
+ }
1029
+ }
1030
+ function resolveTransportMutatingControls(featureToggles) {
1031
+ const direct = readRecordValue(featureToggles, 'transport_mutating_controls');
1032
+ const coordinator = readRecordValue(featureToggles, 'coordinator');
1033
+ const nested = readRecordValue(coordinator, 'transport_mutating_controls');
1034
+ return nested ?? direct ?? null;
1035
+ }
1036
+ function resolveDispatchPilotControls(featureToggles) {
1037
+ const direct = readRecordValue(featureToggles, 'dispatch_pilot');
1038
+ const coordinator = readRecordValue(featureToggles, 'coordinator');
1039
+ const nested = readRecordValue(coordinator, 'dispatch_pilot');
1040
+ return nested ?? direct ?? null;
1041
+ }
1042
+ function renderProviderToggleSummary(enabled, provider) {
1043
+ if (enabled === null) {
1044
+ return 'unconfigured';
1045
+ }
1046
+ const label = enabled ? 'enabled' : 'disabled';
1047
+ return provider ? `${label} (${provider})` : label;
1048
+ }
1049
+ function renderTransportPolicySummary(allowed) {
1050
+ if (allowed === null) {
1051
+ return 'unconfigured';
1052
+ }
1053
+ return allowed ? 'telegram allowed' : 'telegram blocked';
1054
+ }
430
1055
  function isReasoningAtLeastMinimum(value, minimum) {
431
1056
  const rank = resolveReasoningRank(value);
432
1057
  const minimumRank = resolveReasoningRank(minimum);
@@ -464,10 +1089,6 @@ function normalizeOptionalString(value) {
464
1089
  const trimmed = value.trim();
465
1090
  return trimmed.length > 0 ? trimmed : null;
466
1091
  }
467
- function normalizeOptionalBranch(value) {
468
- const normalized = normalizeOptionalString(value);
469
- return normalized ? normalized.replace(/^refs\/heads\//u, '') : null;
470
- }
471
1092
  function resolveCloudFallbackPolicy(env = process.env) {
472
1093
  const raw = normalizeOptionalString(env.CODEX_ORCHESTRATOR_CLOUD_FALLBACK);
473
1094
  if (!raw) {
@@ -578,6 +1199,12 @@ function buildCloudPreflightGuidance(issues) {
578
1199
  case 'missing_environment':
579
1200
  guidance.push('Set CODEX_CLOUD_ENV_ID or provide target metadata.cloudEnvId.');
580
1201
  break;
1202
+ case 'environment_not_found':
1203
+ guidance.push('Set CODEX_CLOUD_ENV_ID to a Codex Cloud environment visible to the active account; run `codex cloud` to list available environments.');
1204
+ break;
1205
+ case 'environment_unavailable':
1206
+ guidance.push('Verify the active Codex account/profile can read CODEX_CLOUD_ENV_ID before running required cloud canaries.');
1207
+ break;
581
1208
  case 'branch_missing':
582
1209
  guidance.push('Push the branch to origin or set CODEX_CLOUD_BRANCH to an existing remote branch.');
583
1210
  break;
@@ -596,40 +1223,6 @@ function buildCloudPreflightGuidance(issues) {
596
1223
  }
597
1224
  return [...new Set(guidance)];
598
1225
  }
599
- function readCodexFeatureFlags(codexBin) {
600
- const result = spawnSync(codexBin, ['features', 'list'], {
601
- encoding: 'utf8',
602
- stdio: ['ignore', 'pipe', 'pipe'],
603
- timeout: 5000
604
- });
605
- if (result.error || result.status !== 0) {
606
- return null;
607
- }
608
- const stdout = String(result.stdout ?? '');
609
- const flags = {};
610
- for (const line of stdout.split(/\r?\n/u)) {
611
- const trimmed = line.trim();
612
- if (!trimmed) {
613
- continue;
614
- }
615
- const tokens = trimmed.split(/\s+/u);
616
- if (tokens.length < 2) {
617
- continue;
618
- }
619
- const name = tokens[0] ?? '';
620
- const enabledToken = tokens[tokens.length - 1] ?? '';
621
- if (!name) {
622
- continue;
623
- }
624
- if (enabledToken === 'true') {
625
- flags[name] = true;
626
- }
627
- else if (enabledToken === 'false') {
628
- flags[name] = false;
629
- }
630
- }
631
- return flags;
632
- }
633
1226
  function canRunCommand(command, args) {
634
1227
  const result = spawnSync(command, args, {
635
1228
  encoding: 'utf8',
@@ -641,82 +1234,3 @@ function canRunCommand(command, args) {
641
1234
  }
642
1235
  return result.status === 0;
643
1236
  }
644
- function inspectDelegationConfig(env = process.env) {
645
- const codexHome = resolveCodexHome(env);
646
- const configPath = join(codexHome, 'config.toml');
647
- if (!existsSync(configPath)) {
648
- return { status: 'missing', path: configPath, detail: 'config.toml not found' };
649
- }
650
- try {
651
- const raw = readFileSync(configPath, 'utf8');
652
- const hasEntry = hasMcpServerEntry(raw, 'delegation');
653
- if (hasEntry) {
654
- return { status: 'ok', path: configPath };
655
- }
656
- return { status: 'missing', path: configPath, detail: 'mcp_servers.delegation entry not found' };
657
- }
658
- catch (error) {
659
- return {
660
- status: 'missing',
661
- path: configPath,
662
- detail: error instanceof Error ? error.message : String(error)
663
- };
664
- }
665
- }
666
- function hasMcpServerEntry(raw, serverName) {
667
- const lines = raw.split('\n');
668
- let currentTable = null;
669
- for (const line of lines) {
670
- const trimmed = stripTomlComment(line).trim();
671
- if (!trimmed) {
672
- continue;
673
- }
674
- const tableMatch = trimmed.match(/^\[(.+)\]$/u);
675
- if (tableMatch) {
676
- currentTable = tableMatch[1]?.trim() ?? null;
677
- if (currentTable === `mcp_servers.${serverName}` ||
678
- currentTable === `mcp_servers."${serverName}"` ||
679
- currentTable === `mcp_servers.'${serverName}'`) {
680
- return true;
681
- }
682
- continue;
683
- }
684
- if (trimmed.startsWith('mcp_servers.')) {
685
- if (trimmed.startsWith(`mcp_servers."${serverName}".`)) {
686
- return true;
687
- }
688
- if (trimmed.startsWith(`mcp_servers.'${serverName}'.`)) {
689
- return true;
690
- }
691
- if (trimmed.startsWith(`mcp_servers.${serverName}.`)) {
692
- return true;
693
- }
694
- if (trimmed.startsWith(`mcp_servers."${serverName}"=`)) {
695
- return true;
696
- }
697
- if (trimmed.startsWith(`mcp_servers.'${serverName}'=`)) {
698
- return true;
699
- }
700
- if (trimmed.startsWith(`mcp_servers.${serverName}=`)) {
701
- return true;
702
- }
703
- }
704
- if (currentTable === 'mcp_servers') {
705
- const entryPattern = new RegExp(`^"?${escapeRegExp(serverName)}"?\\s*=`, 'u');
706
- if (entryPattern.test(trimmed)) {
707
- return true;
708
- }
709
- }
710
- }
711
- return false;
712
- }
713
- function stripTomlComment(line) {
714
- const index = line.indexOf('#');
715
- if (index === -1) {
716
- return line;
717
- }
718
- return line.slice(0, index);
719
- }
720
- function escapeRegExp(value) {
721
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
722
- }