@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.
- package/.agents/plugins/marketplace.json +20 -0
- package/README.md +46 -317
- package/bin/codex-orchestrator.js +161 -0
- package/codex.orchestrator.json +149 -13
- package/dist/bin/codex-orchestrator.js +797 -1154
- package/dist/orchestrator/src/cli/adapters/CommandBuilder.js +50 -0
- package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
- package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
- package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
- package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +295 -11
- package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
- package/dist/orchestrator/src/cli/coStatusCliShell.js +451 -0
- package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
- package/dist/orchestrator/src/cli/codexCliShell.js +119 -0
- package/dist/orchestrator/src/cli/codexDefaultsSetup.js +265 -36
- package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
- package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
- package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
- package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
- package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
- package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
- package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
- package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
- package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
- package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
- package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
- package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
- package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
- package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
- package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
- package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
- package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
- package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
- package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
- package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
- package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
- package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
- package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
- package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
- package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
- package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
- package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
- package/dist/orchestrator/src/cli/control/controlHostSupervision.js +630 -0
- package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
- package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
- package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
- package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
- package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
- package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
- package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
- package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
- package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
- package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
- package/dist/orchestrator/src/cli/control/controlRuntime.js +1003 -0
- package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
- package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
- package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
- package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
- package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
- package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
- package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
- package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
- package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
- package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
- package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
- package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
- package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
- package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
- package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
- package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
- package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
- package/dist/orchestrator/src/cli/control/controlState.js +233 -2
- package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1904 -0
- package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
- package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
- package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
- package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
- package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
- package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
- package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
- package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
- package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
- package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
- package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
- package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
- package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
- package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
- package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
- package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
- package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
- package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
- package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
- package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
- package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
- package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
- package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
- package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
- package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
- package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
- package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
- package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
- package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
- package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
- package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
- package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
- package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
- package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
- package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
- package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
- package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
- package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
- package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
- package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
- package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
- package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
- package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
- package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
- package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
- package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
- package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
- package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
- package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1885 -0
- package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
- package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
- package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
- package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
- package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
- package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
- package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
- package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
- package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
- package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
- package/dist/orchestrator/src/cli/delegationServer.js +567 -678
- package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
- package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
- package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
- package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
- package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
- package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
- package/dist/orchestrator/src/cli/doctor.js +678 -164
- package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
- package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
- package/dist/orchestrator/src/cli/doctorUsage.js +119 -15
- package/dist/orchestrator/src/cli/exec/experience.js +16 -2
- package/dist/orchestrator/src/cli/exec/summary.js +3 -0
- package/dist/orchestrator/src/cli/execCliShell.js +51 -0
- package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
- package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
- package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
- package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
- package/dist/orchestrator/src/cli/init.js +95 -1
- package/dist/orchestrator/src/cli/initCliShell.js +50 -0
- package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
- package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
- package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
- package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
- package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
- package/dist/orchestrator/src/cli/planCliShell.js +19 -0
- package/dist/orchestrator/src/cli/prCliShell.js +41 -0
- package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
- package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1835 -0
- package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
- package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
- package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +6834 -0
- package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
- package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
- package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
- package/dist/orchestrator/src/cli/rlm/context.js +94 -7
- package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
- package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
- package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
- package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
- package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
- package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
- package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
- package/dist/orchestrator/src/cli/run/manifest.js +410 -73
- package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
- package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
- package/dist/orchestrator/src/cli/run/source0.js +690 -0
- package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
- package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
- package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
- package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
- package/dist/orchestrator/src/cli/services/commandRunner.js +698 -18
- package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
- package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
- package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
- package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
- package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
- package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
- package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
- package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
- package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
- package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
- package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
- package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
- package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
- package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
- package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
- package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
- package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
- package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
- package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
- package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
- package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
- package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
- package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
- package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
- package/dist/orchestrator/src/cli/startCliShell.js +68 -0
- package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
- package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
- package/dist/orchestrator/src/cli/utils/cloudPreflight.js +285 -7
- package/dist/orchestrator/src/cli/utils/codexFeatures.js +60 -0
- package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
- package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
- package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
- package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
- package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
- package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
- package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
- package/dist/orchestrator/src/learning/crystalizer.js +2 -2
- package/dist/orchestrator/src/manager.js +74 -4
- package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
- package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
- package/dist/orchestrator/src/persistence/lockFile.js +70 -4
- package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
- package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
- package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
- package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
- package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
- package/dist/packages/sdk-node/src/orchestrator.js +137 -13
- package/dist/packages/shared/config/designConfig.js +8 -1
- package/dist/packages/shared/streams/stdio.js +1 -1
- package/dist/scripts/design/pipeline/permit.js +15 -0
- package/dist/scripts/lib/docs-catalog.js +399 -0
- package/dist/scripts/lib/docs-helpers.js +87 -5
- package/dist/scripts/lib/pr-watch-merge.js +1088 -80
- package/dist/scripts/lib/provider-run-contract.js +26 -0
- package/dist/scripts/lib/review-command-intent-classification.js +532 -0
- package/dist/scripts/lib/review-command-probe-classification.js +385 -0
- package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
- package/dist/scripts/lib/review-execution-runtime.js +753 -0
- package/dist/scripts/lib/review-execution-state.js +1144 -0
- package/dist/scripts/lib/review-execution-telemetry.js +215 -0
- package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
- package/dist/scripts/lib/review-launch-attempt.js +601 -0
- package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
- package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
- package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
- package/dist/scripts/lib/review-prompt-context.js +376 -0
- package/dist/scripts/lib/review-scope-advisory.js +286 -0
- package/dist/scripts/lib/review-scope-paths.js +123 -0
- package/dist/scripts/lib/review-shell-command-parser.js +389 -0
- package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
- package/dist/scripts/lib/run-manifests.js +192 -36
- package/dist/scripts/lib/spark-policy-classifier.js +593 -0
- package/dist/scripts/run-review.js +507 -1777
- package/docs/README.md +43 -20
- package/docs/book/README.md +19 -0
- package/docs/book/codex-cli-0124-adoption.md +68 -0
- package/docs/book/local-hook-impact.md +73 -0
- package/docs/book/operations.md +60 -0
- package/docs/book/public-posture.md +34 -0
- package/docs/book/setup.md +91 -0
- package/docs/book/skills.md +11 -0
- package/docs/guides/codex-version-policy.md +104 -0
- package/docs/public/downstream-setup.md +113 -0
- package/docs/public/provider-onboarding.md +173 -0
- package/package.json +23 -10
- package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
- package/plugins/codex-orchestrator/.mcp.json +13 -0
- package/plugins/codex-orchestrator/launcher.mjs +361 -0
- package/schemas/manifest.json +411 -0
- package/skills/README.md +26 -0
- package/skills/collab-subagents-first/SKILL.md +1 -1
- package/skills/delegation-usage/DELEGATION_GUIDE.md +30 -12
- package/skills/delegation-usage/SKILL.md +25 -14
- package/skills/land/SKILL.md +77 -0
- package/skills/linear/SKILL.md +255 -0
- package/skills/release/SKILL.md +47 -3
- package/skills/standalone-review/SKILL.md +6 -1
- package/templates/README.md +4 -2
- package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
- package/templates/codex/.codex/agents/worker-complex.toml +1 -1
- package/templates/codex/.codex/config.toml +3 -4
- package/templates/codex/.codex/providers/README.md +13 -0
- package/templates/codex/.codex/providers/control.example.json +18 -0
- package/templates/codex/.codex/providers/provider.env.example +15 -0
- package/templates/codex/AGENTS.md +15 -8
- package/templates/codex/mcp-client.json +5 -1
- 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 {
|
|
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
|
-
|
|
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
|
|
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
|
|
108
|
-
const
|
|
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 &&
|
|
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:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
158
|
-
const
|
|
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
|
|
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
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
407
|
-
|
|
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 =
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
-
|
|
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
|
-
}
|