@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
|
@@ -0,0 +1,860 @@
|
|
|
1
|
+
/* eslint-disable patterns/prefer-logger-over-console */
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { realpathSync } from 'node:fs';
|
|
4
|
+
import { mkdir, readdir, readFile, realpath, stat } from 'node:fs/promises';
|
|
5
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import { pathToFileURL } from 'node:url';
|
|
8
|
+
import { PROVIDER_CONTROL_HOST_RUN_ID_ENV, PROVIDER_CONTROL_HOST_TASK_ID_ENV, PROVIDER_LAUNCH_SOURCE_CONTROL_HOST, PROVIDER_LAUNCH_SOURCE_ENV, PROVIDER_LAUNCH_TOKEN_ENV } from '../../../scripts/lib/provider-run-contract.js';
|
|
9
|
+
import { resolveEnvironmentPaths } from '../../../scripts/lib/run-manifests.js';
|
|
10
|
+
import { computeEffectiveDelegationConfig, loadDelegationConfigFiles, parseDelegationConfigOverride, splitDelegationConfigOverrides } from './config/delegationConfig.js';
|
|
11
|
+
import { logger } from '../logger.js';
|
|
12
|
+
import { resolveRunPaths } from './run/runPaths.js';
|
|
13
|
+
import { normalizeEnvironmentPaths, normalizeTaskId } from './run/environment.js';
|
|
14
|
+
import { loadManifest } from './run/manifest.js';
|
|
15
|
+
import { PROVIDER_PACKAGE_ROOT_ENV_KEY, PROVIDER_REPO_CONFIG_PATH_ENV_KEY } from './utils/providerOverrideEnv.js';
|
|
16
|
+
import { findPackageRoot } from './utils/packageInfo.js';
|
|
17
|
+
import { ensureProviderWorkspace, resolveProviderResumeWorkspacePath } from './run/workspacePath.js';
|
|
18
|
+
import { PROVIDER_LINEAR_RESIDENT_SESSION_SEED_ENV, PROVIDER_LINEAR_WORKER_PROOF_FILENAME } from './providerLinearWorkerRunner.js';
|
|
19
|
+
import { REPO_CONFIG_PATH_ENV_KEY, } from './config/userConfig.js';
|
|
20
|
+
import { REPO_CONFIG_REQUIRED_ENV_KEY } from './config/repoConfigPolicy.js';
|
|
21
|
+
import { closeControlServerPublicLifecycle, runProviderIssueHandoffRefresh, runProviderIssueHandoffRehydrate, startControlServerPublicLifecycle } from './control/controlServerPublicLifecycle.js';
|
|
22
|
+
import { resolveLiveLinearTrackedIssueById, resolveLiveLinearTrackedIssues } from './control/linearDispatchSource.js';
|
|
23
|
+
import { resolveLinearWebhookSourceSetup } from './control/linearWebhookController.js';
|
|
24
|
+
import { createProviderIssueHandoffService } from './control/providerIssueHandoff.js';
|
|
25
|
+
import { runProviderDeterministicMergeCloseout, runProviderReviewHandoffPromotion } from './control/providerMergeCloseout.js';
|
|
26
|
+
import { createProviderWorkflowConfigStore } from './control/providerWorkflowConfigStore.js';
|
|
27
|
+
import { findProviderWorkerHost, normalizeProviderWorkerHostName, PROVIDER_WORKER_HOST_ENV_KEY } from './control/providerWorkerHosts.js';
|
|
28
|
+
import { isProviderLinearWorkerProofFreshForStage, } from './control/providerLinearWorkerTruth.js';
|
|
29
|
+
import { shouldEnableControlStatusDashboard, startControlStatusDashboard } from './control/controlStatusDashboard.js';
|
|
30
|
+
const CONFIG_OVERRIDE_ENV_KEYS = ['CODEX_CONFIG_OVERRIDES', 'CODEX_MCP_CONFIG_OVERRIDES'];
|
|
31
|
+
const LOCAL_SPAWN_MANIFEST_WAIT_TIMEOUT_MS = 5_000;
|
|
32
|
+
const REMOTE_SPAWN_MANIFEST_WAIT_TIMEOUT_MS = 20_000;
|
|
33
|
+
const SPAWN_MANIFEST_WAIT_INTERVAL_MS = 100;
|
|
34
|
+
export const DEFAULT_PROVIDER_START_PIPELINE_ID = 'provider-linear-worker';
|
|
35
|
+
const ALLOWED_REMOTE_PROVIDER_ENV_KEYS = [
|
|
36
|
+
'ALL_PROXY',
|
|
37
|
+
'all_proxy',
|
|
38
|
+
'CO_LINEAR_API_KEY',
|
|
39
|
+
'CO_LINEAR_API_TOKEN',
|
|
40
|
+
...CONFIG_OVERRIDE_ENV_KEYS,
|
|
41
|
+
'CODEX_HOME',
|
|
42
|
+
'CODEX_ORCHESTRATOR_APPSERVER_SKIP_LOGIN_CHECK',
|
|
43
|
+
'CODEX_ORCHESTRATOR_PROVIDER_WORKER_MAX_TURNS',
|
|
44
|
+
'CODEX_ORCHESTRATOR_RUNTIME_MODE',
|
|
45
|
+
'CODEX_ORCHESTRATOR_RUNTIME_MODE_ACTIVE',
|
|
46
|
+
'CODEX_ORCHESTRATOR_RUNTIME_FALLBACK',
|
|
47
|
+
'CO_PROVIDER_WORKER_MAX_TURNS',
|
|
48
|
+
'CODEX_RUNTIME_MODE',
|
|
49
|
+
'HTTPS_PROXY',
|
|
50
|
+
'HTTP_PROXY',
|
|
51
|
+
'https_proxy',
|
|
52
|
+
'http_proxy',
|
|
53
|
+
'LINEAR_API_KEY',
|
|
54
|
+
'NODE_EXTRA_CA_CERTS',
|
|
55
|
+
'NO_PROXY',
|
|
56
|
+
'no_proxy',
|
|
57
|
+
'OPENAI_API_KEY',
|
|
58
|
+
'OPENAI_BASE_URL',
|
|
59
|
+
'OPENAI_ORGANIZATION',
|
|
60
|
+
'OPENAI_ORG_ID',
|
|
61
|
+
'OPENAI_PROJECT',
|
|
62
|
+
'OPENAI_PROJECT_ID',
|
|
63
|
+
'SSL_CERT_DIR',
|
|
64
|
+
'SSL_CERT_FILE'
|
|
65
|
+
];
|
|
66
|
+
export async function runControlHostCliShell(params) {
|
|
67
|
+
if (params.flags['help'] !== undefined) {
|
|
68
|
+
params.printHelp();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const baseEnv = normalizeEnvironmentPaths(resolveEnvironmentPaths());
|
|
72
|
+
const taskId = normalizeTaskId(readStringFlag(params.flags, 'task') ?? 'local-mcp');
|
|
73
|
+
const runId = readStringFlag(params.flags, 'run') ?? 'control-host';
|
|
74
|
+
const startPipelineId = readStringFlag(params.flags, 'pipeline') ?? DEFAULT_PROVIDER_START_PIPELINE_ID;
|
|
75
|
+
const format = readStringFlag(params.flags, 'format') === 'json' ? 'json' : 'text';
|
|
76
|
+
const env = { ...baseEnv, taskId };
|
|
77
|
+
const paths = resolveRunPaths(env, runId);
|
|
78
|
+
await mkdir(paths.runDir, { recursive: true });
|
|
79
|
+
const providerWorkflowConfigStore = createProviderWorkflowConfigStore({
|
|
80
|
+
env,
|
|
81
|
+
runDir: paths.runDir,
|
|
82
|
+
pipelineId: startPipelineId
|
|
83
|
+
});
|
|
84
|
+
await providerWorkflowConfigStore.bootstrap();
|
|
85
|
+
const configFiles = await loadDelegationConfigFiles({ repoRoot: env.repoRoot });
|
|
86
|
+
const layers = [
|
|
87
|
+
configFiles.global,
|
|
88
|
+
configFiles.repo,
|
|
89
|
+
...collectDelegationEnvOverrides()
|
|
90
|
+
].filter(Boolean);
|
|
91
|
+
const config = computeEffectiveDelegationConfig({
|
|
92
|
+
repoRoot: env.repoRoot,
|
|
93
|
+
layers
|
|
94
|
+
});
|
|
95
|
+
const cliEntrypoint = process.argv[1];
|
|
96
|
+
if (!cliEntrypoint) {
|
|
97
|
+
throw new Error('Unable to resolve current codex-orchestrator CLI entrypoint.');
|
|
98
|
+
}
|
|
99
|
+
const lifecycle = await startControlServerPublicLifecycle({
|
|
100
|
+
paths,
|
|
101
|
+
config,
|
|
102
|
+
runId,
|
|
103
|
+
controlHostOwnership: {
|
|
104
|
+
repoRoot: env.repoRoot,
|
|
105
|
+
taskId,
|
|
106
|
+
pipelineId: startPipelineId
|
|
107
|
+
},
|
|
108
|
+
providerWorkflowConfigStore,
|
|
109
|
+
createProviderIssueHandoff: ({ providerIntakeState, persistProviderIntake, publishRuntime, readFeatureToggles }) => createProviderIssueHandoffService({
|
|
110
|
+
paths: { ...paths, repoRoot: env.repoRoot },
|
|
111
|
+
state: providerIntakeState,
|
|
112
|
+
persist: persistProviderIntake,
|
|
113
|
+
startPipelineId,
|
|
114
|
+
publishRuntime,
|
|
115
|
+
readFeatureToggles,
|
|
116
|
+
providerWorkflowConfigStore,
|
|
117
|
+
runReviewHandoffPromotion: runProviderReviewHandoffPromotion,
|
|
118
|
+
runMergeCloseout: runProviderDeterministicMergeCloseout,
|
|
119
|
+
resolveTrackedIssue: async ({ issueId }) => {
|
|
120
|
+
const runtimeEnv = process.env;
|
|
121
|
+
const sourceSetup = resolveLinearWebhookSourceSetup(readFeatureToggles(), runtimeEnv);
|
|
122
|
+
if ('error' in sourceSetup) {
|
|
123
|
+
return { kind: 'skip', reason: sourceSetup.error };
|
|
124
|
+
}
|
|
125
|
+
const resolution = await resolveLiveLinearTrackedIssueById({
|
|
126
|
+
issueId,
|
|
127
|
+
sourceSetup: sourceSetup.sourceSetup,
|
|
128
|
+
env: runtimeEnv
|
|
129
|
+
});
|
|
130
|
+
if (resolution.kind === 'ready') {
|
|
131
|
+
return { kind: 'ready', trackedIssue: resolution.tracked_issue };
|
|
132
|
+
}
|
|
133
|
+
if (shouldReleaseTrackedIssueClaim(resolution.reason)) {
|
|
134
|
+
return { kind: 'release', reason: resolution.reason };
|
|
135
|
+
}
|
|
136
|
+
return { kind: 'skip', reason: resolution.reason };
|
|
137
|
+
},
|
|
138
|
+
resolveTrackedIssues: async (input) => {
|
|
139
|
+
const runtimeEnv = process.env;
|
|
140
|
+
const sourceSetup = resolveLinearWebhookSourceSetup(readFeatureToggles(), runtimeEnv);
|
|
141
|
+
if ('error' in sourceSetup) {
|
|
142
|
+
return { kind: 'skip', reason: sourceSetup.error };
|
|
143
|
+
}
|
|
144
|
+
const resolution = await resolveLiveLinearTrackedIssues({
|
|
145
|
+
sourceSetup: sourceSetup.sourceSetup,
|
|
146
|
+
env: runtimeEnv,
|
|
147
|
+
queryMode: input?.mode,
|
|
148
|
+
eligibleIssueTargetCount: input?.eligibleTargetCount,
|
|
149
|
+
eligibleStateSlotCounts: input?.eligibleStateSlotCounts,
|
|
150
|
+
excludedIssueIds: input?.excludedIssueIds
|
|
151
|
+
});
|
|
152
|
+
if (resolution.kind === 'ready') {
|
|
153
|
+
return { kind: 'ready', trackedIssues: resolution.tracked_issues };
|
|
154
|
+
}
|
|
155
|
+
return { kind: 'skip', reason: resolution.reason };
|
|
156
|
+
},
|
|
157
|
+
launcher: {
|
|
158
|
+
start: async (input) => {
|
|
159
|
+
const launchSpec = await resolveProviderStartLaunchSpec(env, input.taskId, input.workerHost ?? null, providerWorkflowConfigStore);
|
|
160
|
+
return await spawnBackgroundCliAndWaitForManifest(launchSpec, cliEntrypoint, [
|
|
161
|
+
'start',
|
|
162
|
+
input.pipelineId,
|
|
163
|
+
'--task',
|
|
164
|
+
input.taskId,
|
|
165
|
+
'--issue-provider',
|
|
166
|
+
input.provider,
|
|
167
|
+
'--issue-id',
|
|
168
|
+
input.issueId,
|
|
169
|
+
'--issue-identifier',
|
|
170
|
+
input.issueIdentifier,
|
|
171
|
+
...(input.issueUpdatedAt ? ['--issue-updated-at', input.issueUpdatedAt] : [])
|
|
172
|
+
], join(env.runsRoot, input.taskId, 'cli'), input.taskId, {
|
|
173
|
+
...launchSpec.envOverrides,
|
|
174
|
+
...buildProviderOverrideOwnershipEnv(cliEntrypoint, launchSpec.envOverrides),
|
|
175
|
+
...buildProviderLinearSourceEnvOverrides(input),
|
|
176
|
+
...buildProviderResidentSessionEnvOverrides(input.residentSessionSeed ?? null),
|
|
177
|
+
[PROVIDER_CONTROL_HOST_TASK_ID_ENV]: taskId,
|
|
178
|
+
[PROVIDER_CONTROL_HOST_RUN_ID_ENV]: runId,
|
|
179
|
+
[PROVIDER_LAUNCH_SOURCE_ENV]: PROVIDER_LAUNCH_SOURCE_CONTROL_HOST,
|
|
180
|
+
[PROVIDER_LAUNCH_TOKEN_ENV]: input.launchToken
|
|
181
|
+
}, {
|
|
182
|
+
issueProvider: input.provider,
|
|
183
|
+
issueId: input.issueId,
|
|
184
|
+
issueIdentifier: input.issueIdentifier,
|
|
185
|
+
issueUpdatedAt: input.issueUpdatedAt,
|
|
186
|
+
providerControlHostTaskId: taskId,
|
|
187
|
+
providerControlHostRunId: runId
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
resume: async (input) => {
|
|
191
|
+
const launchSpec = await resolveProviderResumeLaunchSpec(env, input.runId, providerWorkflowConfigStore, input.workerHost);
|
|
192
|
+
assertResumeLaunchSpecMatchesAdmittedWorkerHost(input.workerHost, launchSpec);
|
|
193
|
+
await spawnBackgroundCli(launchSpec, cliEntrypoint, [
|
|
194
|
+
'resume',
|
|
195
|
+
'--run',
|
|
196
|
+
input.runId,
|
|
197
|
+
'--actor',
|
|
198
|
+
input.actor,
|
|
199
|
+
'--reason',
|
|
200
|
+
input.reason
|
|
201
|
+
], {
|
|
202
|
+
...launchSpec.envOverrides,
|
|
203
|
+
...buildProviderOverrideOwnershipEnv(cliEntrypoint, launchSpec.envOverrides),
|
|
204
|
+
[PROVIDER_CONTROL_HOST_TASK_ID_ENV]: taskId,
|
|
205
|
+
[PROVIDER_CONTROL_HOST_RUN_ID_ENV]: runId,
|
|
206
|
+
[PROVIDER_LAUNCH_SOURCE_ENV]: PROVIDER_LAUNCH_SOURCE_CONTROL_HOST,
|
|
207
|
+
[PROVIDER_LAUNCH_TOKEN_ENV]: input.launchToken
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
});
|
|
213
|
+
let dashboard = null;
|
|
214
|
+
try {
|
|
215
|
+
await rehydrateProviderIssueHandoffOnStartup(lifecycle.requestContextShared.providerIssueHandoff);
|
|
216
|
+
const providerRefreshStartupTrigger = lifecycle.providerRefreshStartupTrigger ?? null;
|
|
217
|
+
lifecycle.providerRefreshStartupTrigger = null;
|
|
218
|
+
void beginProviderIssueHandoffStartupRefresh(lifecycle.requestContextShared.providerIssueHandoff, () => lifecycle.requestContextShared.runtime.publish({ source: 'provider-intake.rehydrate' }), lifecycle.triggerProviderRefresh ?? undefined, providerRefreshStartupTrigger);
|
|
219
|
+
const payload = {
|
|
220
|
+
status: 'ready',
|
|
221
|
+
base_url: lifecycle.baseUrl,
|
|
222
|
+
task_id: taskId,
|
|
223
|
+
run_id: runId,
|
|
224
|
+
run_dir: paths.runDir,
|
|
225
|
+
start_pipeline_id: startPipelineId
|
|
226
|
+
};
|
|
227
|
+
if (format === 'json') {
|
|
228
|
+
console.log(JSON.stringify(payload));
|
|
229
|
+
}
|
|
230
|
+
else if (shouldEnableControlStatusDashboard({
|
|
231
|
+
format,
|
|
232
|
+
stdoutIsTTY: process.stdout.isTTY === true,
|
|
233
|
+
stderrIsTTY: process.stderr.isTTY === true,
|
|
234
|
+
term: process.env.TERM ?? null,
|
|
235
|
+
env: process.env
|
|
236
|
+
})) {
|
|
237
|
+
dashboard = startControlStatusDashboard({
|
|
238
|
+
runtime: lifecycle.requestContextShared.runtime,
|
|
239
|
+
baseUrl: lifecycle.baseUrl,
|
|
240
|
+
taskId,
|
|
241
|
+
runId,
|
|
242
|
+
runDir: paths.runDir,
|
|
243
|
+
startPipelineId
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
console.log(`Control host ready: ${lifecycle.baseUrl}`);
|
|
248
|
+
console.log(`Task: ${taskId}`);
|
|
249
|
+
console.log(`Run: ${runId}`);
|
|
250
|
+
console.log(`Run dir: ${paths.runDir}`);
|
|
251
|
+
console.log(`Start pipeline: ${startPipelineId}`);
|
|
252
|
+
}
|
|
253
|
+
await waitForSignal();
|
|
254
|
+
}
|
|
255
|
+
finally {
|
|
256
|
+
dashboard?.stop();
|
|
257
|
+
await dashboard?.flush();
|
|
258
|
+
await closeControlServerPublicLifecycle(lifecycle);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async function spawnBackgroundCliAndWaitForManifest(launchSpec, cliEntrypoint, args, taskRunsRoot, taskId, envOverrides = {}, correlation = null) {
|
|
262
|
+
const baselineRuns = await snapshotRunManifests(taskRunsRoot);
|
|
263
|
+
await spawnBackgroundCli(launchSpec, cliEntrypoint, args, envOverrides);
|
|
264
|
+
return await pollForSpawnManifest({
|
|
265
|
+
taskRunsRoot,
|
|
266
|
+
taskId,
|
|
267
|
+
baselineRuns,
|
|
268
|
+
correlation,
|
|
269
|
+
timeoutMs: resolveSpawnManifestWaitTimeoutMs(launchSpec),
|
|
270
|
+
intervalMs: SPAWN_MANIFEST_WAIT_INTERVAL_MS
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
function resolveSpawnManifestWaitTimeoutMs(launchSpec) {
|
|
274
|
+
return isProviderSshLaunchSpec(launchSpec)
|
|
275
|
+
? REMOTE_SPAWN_MANIFEST_WAIT_TIMEOUT_MS
|
|
276
|
+
: LOCAL_SPAWN_MANIFEST_WAIT_TIMEOUT_MS;
|
|
277
|
+
}
|
|
278
|
+
async function spawnBackgroundCli(launchSpec, cliEntrypoint, args, envOverrides = {}) {
|
|
279
|
+
if (isProviderSshLaunchSpec(launchSpec)) {
|
|
280
|
+
await spawnBackgroundCliOverSsh(launchSpec, cliEntrypoint, args, envOverrides);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
await new Promise((resolve, reject) => {
|
|
284
|
+
const child = spawn(process.execPath, [...process.execArgv, cliEntrypoint, ...args], {
|
|
285
|
+
cwd: launchSpec.cwd,
|
|
286
|
+
env: { ...process.env, ...envOverrides },
|
|
287
|
+
detached: true,
|
|
288
|
+
stdio: 'ignore'
|
|
289
|
+
});
|
|
290
|
+
const onError = (error) => reject(error);
|
|
291
|
+
child.once('error', onError);
|
|
292
|
+
child.once('spawn', () => {
|
|
293
|
+
child.off('error', onError);
|
|
294
|
+
child.unref();
|
|
295
|
+
resolve();
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
async function spawnBackgroundCliOverSsh(launchSpec, cliEntrypoint, args, envOverrides = {}) {
|
|
300
|
+
const envValues = buildRemoteProviderEnvValues(process.env, envOverrides);
|
|
301
|
+
const sshInvocation = buildRemoteProviderSshInvocation({
|
|
302
|
+
host: launchSpec.transport.host,
|
|
303
|
+
cwd: launchSpec.cwd,
|
|
304
|
+
nodePath: resolveRemoteProviderNodePath(launchSpec.transport.host),
|
|
305
|
+
cliEntrypoint,
|
|
306
|
+
args,
|
|
307
|
+
envValues
|
|
308
|
+
});
|
|
309
|
+
await new Promise((resolve, reject) => {
|
|
310
|
+
const child = spawn('ssh', sshInvocation.sshArgs, {
|
|
311
|
+
cwd: launchSpec.cwd,
|
|
312
|
+
detached: true,
|
|
313
|
+
stdio: ['pipe', 'ignore', 'ignore']
|
|
314
|
+
});
|
|
315
|
+
const onError = (error) => reject(error);
|
|
316
|
+
child.once('error', onError);
|
|
317
|
+
child.once('spawn', () => {
|
|
318
|
+
child.off('error', onError);
|
|
319
|
+
void writeRemoteProviderScriptToSshChild(child, sshInvocation.remoteScript).then(resolve, reject);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
async function writeRemoteProviderScriptToSshChild(child, remoteScript) {
|
|
324
|
+
const stdin = child.stdin;
|
|
325
|
+
if (!stdin) {
|
|
326
|
+
child.unref();
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
await new Promise((resolve, reject) => {
|
|
330
|
+
let settled = false;
|
|
331
|
+
const cleanup = () => {
|
|
332
|
+
stdin.off('error', onError);
|
|
333
|
+
stdin.off('finish', onFinish);
|
|
334
|
+
};
|
|
335
|
+
const settleResolve = () => {
|
|
336
|
+
if (settled) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
settled = true;
|
|
340
|
+
cleanup();
|
|
341
|
+
child.unref();
|
|
342
|
+
resolve();
|
|
343
|
+
};
|
|
344
|
+
const settleReject = (error) => {
|
|
345
|
+
if (settled) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
settled = true;
|
|
349
|
+
cleanup();
|
|
350
|
+
reject(error);
|
|
351
|
+
};
|
|
352
|
+
const onError = (error) => settleReject(error);
|
|
353
|
+
const onFinish = () => settleResolve();
|
|
354
|
+
stdin.once('error', onError);
|
|
355
|
+
stdin.once('finish', onFinish);
|
|
356
|
+
try {
|
|
357
|
+
stdin.end(remoteScript);
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
settleReject(error instanceof Error ? error : new Error(String(error)));
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
function isProviderSshLaunchSpec(launchSpec) {
|
|
365
|
+
return launchSpec.transport.kind === 'ssh';
|
|
366
|
+
}
|
|
367
|
+
function buildRemoteProviderLaunchCommand(input) {
|
|
368
|
+
const envAssignments = [
|
|
369
|
+
'PATH="$PATH"',
|
|
370
|
+
...Object.entries(input.envValues)
|
|
371
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
372
|
+
.map(([key, value]) => `${key}=${quoteShellArg(value)}`)
|
|
373
|
+
];
|
|
374
|
+
const command = [
|
|
375
|
+
quoteShellArg(input.nodePath),
|
|
376
|
+
quoteShellArg(input.cliEntrypoint),
|
|
377
|
+
...input.args.map((value) => quoteShellArg(value))
|
|
378
|
+
].join(' ');
|
|
379
|
+
return `cd ${quoteShellArg(input.cwd)} && exec env -i ${envAssignments.join(' ')} ${command}`;
|
|
380
|
+
}
|
|
381
|
+
function buildRemoteProviderSshInvocation(input) {
|
|
382
|
+
return {
|
|
383
|
+
sshArgs: [
|
|
384
|
+
'-o',
|
|
385
|
+
'BatchMode=yes',
|
|
386
|
+
...input.host.ssh_options,
|
|
387
|
+
input.host.ssh_destination,
|
|
388
|
+
'sh',
|
|
389
|
+
'-s'
|
|
390
|
+
],
|
|
391
|
+
remoteScript: `${buildRemoteProviderLaunchCommand({
|
|
392
|
+
cwd: input.cwd,
|
|
393
|
+
nodePath: input.nodePath,
|
|
394
|
+
cliEntrypoint: input.cliEntrypoint,
|
|
395
|
+
args: input.args,
|
|
396
|
+
envValues: input.envValues
|
|
397
|
+
})}\n`
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function buildRemoteProviderEnvValues(inheritedEnv, envOverrides = {}) {
|
|
401
|
+
const inheritedValues = Object.fromEntries(ALLOWED_REMOTE_PROVIDER_ENV_KEYS.flatMap((key) => {
|
|
402
|
+
const value = inheritedEnv[key];
|
|
403
|
+
return typeof value === 'string' ? [[key, value]] : [];
|
|
404
|
+
}));
|
|
405
|
+
return Object.fromEntries(Object.entries({
|
|
406
|
+
...inheritedValues,
|
|
407
|
+
...envOverrides
|
|
408
|
+
}).filter((entry) => typeof entry[1] === 'string'));
|
|
409
|
+
}
|
|
410
|
+
function quoteShellArg(value) {
|
|
411
|
+
return `'${value.replace(/'/gu, `'\\''`)}'`;
|
|
412
|
+
}
|
|
413
|
+
function buildProviderOverrideOwnershipEnv(cliEntrypoint, envOverrides) {
|
|
414
|
+
const repoConfigPath = normalizeProviderLinearSourceValue(envOverrides[REPO_CONFIG_PATH_ENV_KEY]);
|
|
415
|
+
const packageRoot = normalizeProviderLinearSourceValue(envOverrides.CODEX_ORCHESTRATOR_PACKAGE_ROOT) ??
|
|
416
|
+
resolveProviderOverridePackageRoot(cliEntrypoint);
|
|
417
|
+
return {
|
|
418
|
+
...(repoConfigPath ? { [PROVIDER_REPO_CONFIG_PATH_ENV_KEY]: repoConfigPath } : {}),
|
|
419
|
+
...(packageRoot ? { [PROVIDER_PACKAGE_ROOT_ENV_KEY]: packageRoot } : {})
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function resolveProviderOverridePackageRoot(cliEntrypoint) {
|
|
423
|
+
const configured = normalizeProviderLinearSourceValue(process.env.CODEX_ORCHESTRATOR_PACKAGE_ROOT);
|
|
424
|
+
if (configured) {
|
|
425
|
+
return configured;
|
|
426
|
+
}
|
|
427
|
+
const resolvedCliEntrypoint = (() => {
|
|
428
|
+
try {
|
|
429
|
+
return realpathSync(cliEntrypoint);
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return cliEntrypoint;
|
|
433
|
+
}
|
|
434
|
+
})();
|
|
435
|
+
try {
|
|
436
|
+
return findPackageRoot(pathToFileURL(resolvedCliEntrypoint).href);
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
const cliDir = dirname(resolvedCliEntrypoint);
|
|
440
|
+
const parentDir = dirname(cliDir);
|
|
441
|
+
const fallbackRoot = basename(cliDir) === 'bin' && basename(parentDir) === 'dist'
|
|
442
|
+
? dirname(parentDir)
|
|
443
|
+
: parentDir;
|
|
444
|
+
return normalizeProviderLinearSourceValue(fallbackRoot);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
async function snapshotRunManifests(taskRunsRoot) {
|
|
448
|
+
let entries;
|
|
449
|
+
try {
|
|
450
|
+
entries = await readdir(taskRunsRoot, { withFileTypes: true });
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
return new Set();
|
|
454
|
+
}
|
|
455
|
+
const snapshot = new Set();
|
|
456
|
+
for (const entry of entries) {
|
|
457
|
+
if (!entry.isDirectory()) {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
snapshot.add(entry.name);
|
|
461
|
+
}
|
|
462
|
+
return snapshot;
|
|
463
|
+
}
|
|
464
|
+
async function pollForSpawnManifest(params) {
|
|
465
|
+
const deadline = Date.now() + params.timeoutMs;
|
|
466
|
+
while (Date.now() <= deadline) {
|
|
467
|
+
const manifest = await findSpawnManifest(params);
|
|
468
|
+
if (manifest) {
|
|
469
|
+
return manifest;
|
|
470
|
+
}
|
|
471
|
+
await delay(params.intervalMs);
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
async function findSpawnManifest(params) {
|
|
476
|
+
let entries;
|
|
477
|
+
try {
|
|
478
|
+
entries = await readdir(params.taskRunsRoot, { withFileTypes: true });
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
const candidates = [];
|
|
484
|
+
for (const entry of entries) {
|
|
485
|
+
if (!entry.isDirectory() || params.baselineRuns.has(entry.name)) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
const manifestPath = join(params.taskRunsRoot, entry.name, 'manifest.json');
|
|
489
|
+
let stats;
|
|
490
|
+
try {
|
|
491
|
+
stats = await stat(manifestPath);
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
candidates.push({ runId: entry.name, manifestPath, mtimeMs: stats.mtimeMs });
|
|
497
|
+
}
|
|
498
|
+
candidates.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
499
|
+
for (const candidate of candidates) {
|
|
500
|
+
try {
|
|
501
|
+
const raw = await readFile(candidate.manifestPath, 'utf8');
|
|
502
|
+
const parsed = JSON.parse(raw);
|
|
503
|
+
if (typeof parsed.task_id === 'string' && parsed.task_id !== params.taskId) {
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
if (!manifestMatchesCorrelation(parsed, params.correlation ?? null)) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
const runId = typeof parsed.run_id === 'string' && parsed.run_id.trim().length > 0
|
|
510
|
+
? parsed.run_id.trim()
|
|
511
|
+
: candidate.runId;
|
|
512
|
+
if (!runId) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
return { runId, manifestPath: candidate.manifestPath };
|
|
516
|
+
}
|
|
517
|
+
catch {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
async function resolveProviderStartLaunchSpec(env, taskId, workerHost, providerWorkflowConfigStore) {
|
|
524
|
+
const workspacePath = await ensureProviderWorkspace(env.repoRoot, taskId);
|
|
525
|
+
const configPath = await resolveProviderLaunchConfigPath(env, providerWorkflowConfigStore);
|
|
526
|
+
return buildProviderLaunchSpec(env, workspacePath, configPath, resolveConfiguredProviderWorkerHost(providerWorkflowConfigStore, workerHost));
|
|
527
|
+
}
|
|
528
|
+
async function resolveProviderResumeLaunchSpec(env, runId, providerWorkflowConfigStore, preferredWorkerHost) {
|
|
529
|
+
const { manifest, paths } = await loadManifest(env, runId);
|
|
530
|
+
const manifestRecord = manifest;
|
|
531
|
+
const resumeTaskId = await resolveProviderResumeTaskId(manifestRecord, runId, {
|
|
532
|
+
runDir: paths.runDir,
|
|
533
|
+
runsRoot: env.runsRoot
|
|
534
|
+
});
|
|
535
|
+
const workspacePath = await resolveProviderResumeWorkspacePath(env.repoRoot, resumeTaskId, manifestRecord);
|
|
536
|
+
const configPath = await resolveProviderLaunchConfigPath(env, providerWorkflowConfigStore);
|
|
537
|
+
const persistedProofContext = await readProviderLinearLaunchContextFromProof(paths.runDir);
|
|
538
|
+
const manifestStartedAt = typeof manifestRecord.started_at === 'string'
|
|
539
|
+
? manifestRecord.started_at
|
|
540
|
+
: null;
|
|
541
|
+
const resolvedWorkerHost = preferredWorkerHost === undefined
|
|
542
|
+
? resolveFreshProviderLaunchContextWorkerHost(persistedProofContext, manifestStartedAt)
|
|
543
|
+
: normalizeProviderWorkerHostName(preferredWorkerHost);
|
|
544
|
+
const launchSpec = buildProviderLaunchSpec(env, workspacePath, configPath, resolveConfiguredProviderWorkerHost(providerWorkflowConfigStore, resolvedWorkerHost, { allowMissing: true }));
|
|
545
|
+
return {
|
|
546
|
+
...launchSpec,
|
|
547
|
+
envOverrides: {
|
|
548
|
+
...launchSpec.envOverrides,
|
|
549
|
+
...buildProviderLinearSourceEnvOverrides(persistedProofContext?.sourceScope ?? {
|
|
550
|
+
provider: 'linear',
|
|
551
|
+
workspaceId: null,
|
|
552
|
+
teamId: null,
|
|
553
|
+
projectId: null
|
|
554
|
+
})
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function assertResumeLaunchSpecMatchesAdmittedWorkerHost(preferredWorkerHost, launchSpec) {
|
|
559
|
+
const normalizedPreferredWorkerHost = normalizeProviderWorkerHostName(preferredWorkerHost);
|
|
560
|
+
if (!normalizedPreferredWorkerHost) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (launchSpec.transport.kind === 'local') {
|
|
564
|
+
throw new Error(`Admitted provider resume host "${normalizedPreferredWorkerHost}" resolved to local at launch time; retry under refreshed admission so the local safety cap is reapplied.`);
|
|
565
|
+
}
|
|
566
|
+
if (launchSpec.transport.host.name !== normalizedPreferredWorkerHost) {
|
|
567
|
+
throw new Error(`Admitted provider resume host "${normalizedPreferredWorkerHost}" drifted to "${launchSpec.transport.host.name}" at launch time; retry under refreshed admission.`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
async function resolveProviderLaunchConfigPath(env, providerWorkflowConfigStore) {
|
|
571
|
+
if (providerWorkflowConfigStore) {
|
|
572
|
+
return await providerWorkflowConfigStore.getLaunchConfigPath();
|
|
573
|
+
}
|
|
574
|
+
return join(env.repoRoot, 'codex.orchestrator.json');
|
|
575
|
+
}
|
|
576
|
+
function buildProviderLinearSourceEnvOverrides(input) {
|
|
577
|
+
const workspaceId = normalizeProviderLinearSourceValue(input.workspaceId);
|
|
578
|
+
const teamId = normalizeProviderLinearSourceValue(input.teamId);
|
|
579
|
+
const projectId = normalizeProviderLinearSourceValue(input.projectId);
|
|
580
|
+
return {
|
|
581
|
+
CO_LINEAR_WORKSPACE_ID: workspaceId ?? '',
|
|
582
|
+
CO_LINEAR_TEAM_ID: teamId ?? '',
|
|
583
|
+
CO_LINEAR_PROJECT_ID: projectId ?? ''
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function buildProviderResidentSessionEnvOverrides(seed) {
|
|
587
|
+
return {
|
|
588
|
+
[PROVIDER_LINEAR_RESIDENT_SESSION_SEED_ENV]: seed ? JSON.stringify(seed) : ''
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
function buildProviderLaunchSpec(env, workspacePath, repoConfigPath, workerHost = null) {
|
|
592
|
+
return {
|
|
593
|
+
cwd: workspacePath,
|
|
594
|
+
envOverrides: {
|
|
595
|
+
CODEX_ORCHESTRATOR_ROOT: workspacePath,
|
|
596
|
+
CODEX_ORCHESTRATOR_RUNS_DIR: env.runsRoot,
|
|
597
|
+
CODEX_ORCHESTRATOR_OUT_DIR: env.outRoot,
|
|
598
|
+
[REPO_CONFIG_PATH_ENV_KEY]: repoConfigPath,
|
|
599
|
+
[REPO_CONFIG_REQUIRED_ENV_KEY]: '1',
|
|
600
|
+
[PROVIDER_WORKER_HOST_ENV_KEY]: workerHost?.name ?? '',
|
|
601
|
+
...(workerHost ? { CODEX_ORCHESTRATOR_NODE_BIN: resolveRemoteProviderNodePath(workerHost) } : {}),
|
|
602
|
+
},
|
|
603
|
+
transport: workerHost
|
|
604
|
+
? {
|
|
605
|
+
kind: 'ssh',
|
|
606
|
+
host: workerHost
|
|
607
|
+
}
|
|
608
|
+
: {
|
|
609
|
+
kind: 'local'
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
function shouldReleaseTrackedIssueClaim(reason) {
|
|
614
|
+
return (reason === 'dispatch_source_issue_not_found' ||
|
|
615
|
+
reason === 'dispatch_source_workspace_mismatch' ||
|
|
616
|
+
reason === 'dispatch_source_team_mismatch' ||
|
|
617
|
+
reason === 'dispatch_source_project_mismatch');
|
|
618
|
+
}
|
|
619
|
+
async function readProviderLinearLaunchContextFromProof(runDir) {
|
|
620
|
+
try {
|
|
621
|
+
const raw = await readFile(join(runDir, PROVIDER_LINEAR_WORKER_PROOF_FILENAME), 'utf8');
|
|
622
|
+
const parsed = JSON.parse(raw);
|
|
623
|
+
return parseProviderLinearLaunchContextFromProof(parsed);
|
|
624
|
+
}
|
|
625
|
+
catch {
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
function parseProviderLinearLaunchContextFromProof(input) {
|
|
630
|
+
if (!isRecord(input)) {
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
const sourceSetup = isRecord(input.source_setup) && input.source_setup.provider === 'linear'
|
|
634
|
+
? input.source_setup
|
|
635
|
+
: null;
|
|
636
|
+
return {
|
|
637
|
+
sourceScope: sourceSetup
|
|
638
|
+
? {
|
|
639
|
+
provider: 'linear',
|
|
640
|
+
workspaceId: typeof sourceSetup.workspace_id === 'string' ? sourceSetup.workspace_id : null,
|
|
641
|
+
teamId: typeof sourceSetup.team_id === 'string' ? sourceSetup.team_id : null,
|
|
642
|
+
projectId: typeof sourceSetup.project_id === 'string' ? sourceSetup.project_id : null
|
|
643
|
+
}
|
|
644
|
+
: null,
|
|
645
|
+
attemptStartedAt: typeof input.attempt_started_at === 'string' ? input.attempt_started_at : null,
|
|
646
|
+
updatedAt: typeof input.updated_at === 'string' ? input.updated_at : null,
|
|
647
|
+
workerHost: normalizeProviderWorkerHostName(input.worker_host)
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function resolveFreshProviderLaunchContextWorkerHost(context, manifestStartedAt) {
|
|
651
|
+
if (!context?.workerHost) {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
return isProviderLinearWorkerProofFreshForStage({
|
|
655
|
+
attempt_started_at: context.attemptStartedAt,
|
|
656
|
+
updated_at: context.updatedAt
|
|
657
|
+
}, manifestStartedAt ?? null)
|
|
658
|
+
? context.workerHost
|
|
659
|
+
: null;
|
|
660
|
+
}
|
|
661
|
+
function resolveConfiguredProviderWorkerHost(providerWorkflowConfigStore, workerHost, options = {}) {
|
|
662
|
+
const normalizedWorkerHost = normalizeProviderWorkerHostName(workerHost);
|
|
663
|
+
if (!normalizedWorkerHost) {
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
666
|
+
const configuredHost = findProviderWorkerHost(providerWorkflowConfigStore?.snapshot().worker_hosts ?? [], normalizedWorkerHost);
|
|
667
|
+
if (!configuredHost) {
|
|
668
|
+
if (options.allowMissing === true) {
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
throw new Error(`Configured provider worker host "${normalizedWorkerHost}" is unavailable in the current provider workflow snapshot.`);
|
|
672
|
+
}
|
|
673
|
+
return configuredHost;
|
|
674
|
+
}
|
|
675
|
+
function resolveRemoteProviderNodePath(workerHost) {
|
|
676
|
+
return workerHost.node_path ?? 'node';
|
|
677
|
+
}
|
|
678
|
+
export const __test__ = {
|
|
679
|
+
DEFAULT_PROVIDER_START_PIPELINE_ID,
|
|
680
|
+
buildProviderLaunchSpec,
|
|
681
|
+
buildRemoteProviderEnvValues,
|
|
682
|
+
buildRemoteProviderLaunchCommand,
|
|
683
|
+
buildRemoteProviderSshInvocation,
|
|
684
|
+
buildProviderLinearSourceEnvOverrides,
|
|
685
|
+
buildProviderResidentSessionEnvOverrides,
|
|
686
|
+
buildProviderOverrideOwnershipEnv,
|
|
687
|
+
beginProviderIssueHandoffStartupRefresh,
|
|
688
|
+
findSpawnManifest,
|
|
689
|
+
rehydrateProviderIssueHandoffOnStartup,
|
|
690
|
+
refreshProviderIssueHandoffOnStartup,
|
|
691
|
+
resolveRemoteProviderNodePath,
|
|
692
|
+
resolveSpawnManifestWaitTimeoutMs,
|
|
693
|
+
resolveProviderResumeLaunchSpec,
|
|
694
|
+
assertResumeLaunchSpecMatchesAdmittedWorkerHost,
|
|
695
|
+
resolveProviderResumeTaskId,
|
|
696
|
+
resolveProviderOverridePackageRoot,
|
|
697
|
+
snapshotRunManifests,
|
|
698
|
+
writeRemoteProviderScriptToSshChild
|
|
699
|
+
};
|
|
700
|
+
function normalizeProviderLinearSourceValue(value) {
|
|
701
|
+
if (typeof value !== 'string') {
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
const trimmed = value.trim();
|
|
705
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
706
|
+
}
|
|
707
|
+
function isRecord(value) {
|
|
708
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
709
|
+
}
|
|
710
|
+
function beginProviderIssueHandoffStartupRefresh(providerIssueHandoff, onSettled, refreshProviderIssueHandoff, startupRefreshTrigger) {
|
|
711
|
+
if (startupRefreshTrigger) {
|
|
712
|
+
clearTimeout(startupRefreshTrigger);
|
|
713
|
+
}
|
|
714
|
+
const refreshPromise = refreshProviderIssueHandoff
|
|
715
|
+
? Promise.resolve()
|
|
716
|
+
.then(() => refreshProviderIssueHandoff())
|
|
717
|
+
.catch((error) => {
|
|
718
|
+
logger.warn(`Provider issue startup refresh failed: ${error?.message ?? String(error)}`);
|
|
719
|
+
})
|
|
720
|
+
: refreshProviderIssueHandoffOnStartup(providerIssueHandoff);
|
|
721
|
+
return refreshPromise.finally(() => {
|
|
722
|
+
onSettled?.();
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
async function refreshProviderIssueHandoffOnStartup(providerIssueHandoff) {
|
|
726
|
+
if (!providerIssueHandoff) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
try {
|
|
730
|
+
await runProviderIssueHandoffRefresh(providerIssueHandoff);
|
|
731
|
+
}
|
|
732
|
+
catch (error) {
|
|
733
|
+
logger.warn(`Provider issue startup refresh failed: ${error?.message ?? String(error)}`);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function rehydrateProviderIssueHandoffOnStartup(providerIssueHandoff) {
|
|
737
|
+
if (!providerIssueHandoff) {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
try {
|
|
741
|
+
await runProviderIssueHandoffRehydrate(providerIssueHandoff);
|
|
742
|
+
}
|
|
743
|
+
catch (error) {
|
|
744
|
+
logger.warn(`Provider issue startup rehydrate failed: ${error?.message ?? String(error)}`);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
function manifestMatchesCorrelation(manifest, correlation) {
|
|
748
|
+
if (!correlation) {
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
return (manifestFieldMatches(manifest, 'issue_provider', correlation.issueProvider) &&
|
|
752
|
+
manifestFieldMatches(manifest, 'issue_id', correlation.issueId) &&
|
|
753
|
+
manifestFieldMatches(manifest, 'issue_identifier', correlation.issueIdentifier) &&
|
|
754
|
+
manifestFieldMatches(manifest, 'issue_updated_at', correlation.issueUpdatedAt) &&
|
|
755
|
+
manifestFieldMatches(manifest, 'provider_control_host_task_id', correlation.providerControlHostTaskId) &&
|
|
756
|
+
manifestFieldMatches(manifest, 'provider_control_host_run_id', correlation.providerControlHostRunId));
|
|
757
|
+
}
|
|
758
|
+
function manifestFieldMatches(manifest, field, expected) {
|
|
759
|
+
if (!expected) {
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
return readManifestString(manifest, field) === expected;
|
|
763
|
+
}
|
|
764
|
+
function readManifestString(manifest, field) {
|
|
765
|
+
const value = manifest[field];
|
|
766
|
+
if (typeof value !== 'string') {
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
const trimmed = value.trim();
|
|
770
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
771
|
+
}
|
|
772
|
+
async function resolveProviderResumeTaskId(manifest, runId, pathMetadata) {
|
|
773
|
+
const manifestTaskId = readManifestString(manifest, 'task_id');
|
|
774
|
+
const taskIdCandidate = manifestTaskId ??
|
|
775
|
+
(pathMetadata
|
|
776
|
+
? await deriveProviderResumeTaskIdFromRunDir(pathMetadata.runDir, pathMetadata.runsRoot)
|
|
777
|
+
: null);
|
|
778
|
+
if (!taskIdCandidate) {
|
|
779
|
+
throw new Error(`Unable to derive provider resume manifest task_id for run ${runId}.`);
|
|
780
|
+
}
|
|
781
|
+
try {
|
|
782
|
+
return normalizeTaskId(taskIdCandidate);
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
throw new Error(`Invalid provider resume manifest task_id for run ${runId}: ${error?.message ?? String(error)}`);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
async function deriveProviderResumeTaskIdFromRunDir(runDir, runsRoot) {
|
|
789
|
+
const [resolvedRunDir, resolvedRunsRoot] = await Promise.all([
|
|
790
|
+
canonicalizePath(runDir),
|
|
791
|
+
canonicalizePath(runsRoot)
|
|
792
|
+
]);
|
|
793
|
+
const relativeRunDir = relative(resolvedRunsRoot, resolvedRunDir);
|
|
794
|
+
if (!relativeRunDir ||
|
|
795
|
+
relativeRunDir === '..' ||
|
|
796
|
+
relativeRunDir.startsWith(`..${sep}`) ||
|
|
797
|
+
isAbsolute(relativeRunDir)) {
|
|
798
|
+
return null;
|
|
799
|
+
}
|
|
800
|
+
const segments = relativeRunDir.split(sep).filter((segment) => segment.length > 0);
|
|
801
|
+
if (segments.length === 3 && segments[1] === 'cli') {
|
|
802
|
+
return segments[0] ?? null;
|
|
803
|
+
}
|
|
804
|
+
if (segments.length === 2) {
|
|
805
|
+
return segments[0] ?? null;
|
|
806
|
+
}
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
async function canonicalizePath(pathname) {
|
|
810
|
+
try {
|
|
811
|
+
return await realpath(pathname);
|
|
812
|
+
}
|
|
813
|
+
catch {
|
|
814
|
+
return resolve(pathname);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
function collectDelegationEnvOverrides(env = process.env) {
|
|
818
|
+
const layers = [];
|
|
819
|
+
for (const key of CONFIG_OVERRIDE_ENV_KEYS) {
|
|
820
|
+
const raw = env[key];
|
|
821
|
+
if (!raw) {
|
|
822
|
+
continue;
|
|
823
|
+
}
|
|
824
|
+
const values = splitDelegationConfigOverrides(raw);
|
|
825
|
+
for (const value of values) {
|
|
826
|
+
try {
|
|
827
|
+
const layer = parseDelegationConfigOverride(value, 'env');
|
|
828
|
+
if (layer) {
|
|
829
|
+
layers.push(layer);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
catch (error) {
|
|
833
|
+
logger.warn(`Invalid delegation config override (env): ${error?.message ?? String(error)}`);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return layers;
|
|
838
|
+
}
|
|
839
|
+
function readStringFlag(flags, key) {
|
|
840
|
+
const value = flags[key];
|
|
841
|
+
if (typeof value !== 'string') {
|
|
842
|
+
return undefined;
|
|
843
|
+
}
|
|
844
|
+
const trimmed = value.trim();
|
|
845
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
846
|
+
}
|
|
847
|
+
async function waitForSignal() {
|
|
848
|
+
await new Promise((resolve) => {
|
|
849
|
+
const handle = () => {
|
|
850
|
+
process.off('SIGINT', handle);
|
|
851
|
+
process.off('SIGTERM', handle);
|
|
852
|
+
resolve();
|
|
853
|
+
};
|
|
854
|
+
process.on('SIGINT', handle);
|
|
855
|
+
process.on('SIGTERM', handle);
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
async function delay(ms) {
|
|
859
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
860
|
+
}
|