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