@kbediako/codex-orchestrator 0.1.37 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +20 -0
- package/README.md +73 -291
- package/bin/codex-orchestrator.js +161 -0
- package/codex.orchestrator.json +149 -13
- package/dist/bin/codex-orchestrator.js +795 -1154
- 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 +183 -11
- package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
- package/dist/orchestrator/src/cli/coStatusCliShell.js +429 -0
- package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
- package/dist/orchestrator/src/cli/codexCliShell.js +72 -0
- package/dist/orchestrator/src/cli/codexDefaultsSetup.js +49 -11
- 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 +608 -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 +992 -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 +1899 -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 +1838 -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 +542 -122
- 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 +136 -16
- 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 +1 -0
- 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 +1772 -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 +5738 -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 +668 -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 +83 -1
- 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/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 +365 -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/public/downstream-setup.md +106 -0
- package/docs/public/provider-onboarding.md +173 -0
- package/package.json +30 -11
- package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
- package/plugins/codex-orchestrator/.mcp.json +13 -0
- package/plugins/codex-orchestrator/launcher.mjs +359 -0
- package/schemas/manifest.json +395 -0
- package/skills/chrome-devtools/SKILL.md +1 -1
- package/skills/codex-orchestrator/SKILL.md +83 -0
- package/skills/collab-subagents-first/SKILL.md +2 -1
- package/skills/delegation-usage/DELEGATION_GUIDE.md +24 -11
- package/skills/delegation-usage/SKILL.md +20 -13
- 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/explorer-fast.toml +1 -0
- 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 +12 -7
- package/templates/codex/mcp-client.json +5 -1
- package/docs/README.md +0 -307
- package/docs/assets/setup.gif +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createWriteStream } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
2
3
|
import { join } from 'node:path';
|
|
3
4
|
import { ToolInvocationFailedError } from '../../../../packages/orchestrator/src/index.js';
|
|
4
5
|
import { getCliExecRunner, getPrivacyGuard, getExecHandleService } from './execRuntime.js';
|
|
@@ -6,15 +7,30 @@ import { logger } from '../../logger.js';
|
|
|
6
7
|
import { relativeToRepo } from '../run/runPaths.js';
|
|
7
8
|
import { appendCommandError, updateCommandStatus } from '../run/manifest.js';
|
|
8
9
|
import { persistManifest } from '../run/manifestPersister.js';
|
|
10
|
+
import { PROVIDER_LINEAR_WORKER_PROOF_FILENAME } from '../providerLinearWorkerRunner.js';
|
|
9
11
|
import { slugify } from '../utils/strings.js';
|
|
10
12
|
import { isoTimestamp } from '../utils/time.js';
|
|
13
|
+
import { buildCommandPreview } from '../utils/commandPreview.js';
|
|
11
14
|
import { EnvUtils } from '../../../../packages/shared/config/index.js';
|
|
15
|
+
import { deriveReviewOutcomeDisposition } from '../../../../scripts/lib/review-execution-telemetry.js';
|
|
12
16
|
import { findPackageRoot } from '../utils/packageInfo.js';
|
|
17
|
+
import { applyResolvedProgramInvocationEnvOverrides, resolvePackageProgramInvocation, resolveProviderLinearWorkerProgramInvocation } from '../utils/packageProgramResolver.js';
|
|
18
|
+
import { buildProviderLinearWorkerTerminalSummary, deriveDeterministicProviderMutationSuppressions, formatDeterministicProviderMutationDegradationSummary, isProviderLinearWorkerProofFreshForStage, resolveProviderLinearWorkerAttemptStartedAt, resolveProviderLinearWorkerTerminalReason, resolveProviderLinearWorkerTerminalStatus } from '../control/providerLinearWorkerTruth.js';
|
|
13
19
|
const MAX_BUFFERED_OUTPUT_BYTES = 64 * 1024;
|
|
14
20
|
const EMIT_COMMAND_STREAM_MIRRORS = EnvUtils.getBoolean('CODEX_ORCHESTRATOR_EMIT_COMMAND_STREAMS', false);
|
|
15
21
|
export const MAX_CAPTURED_CHUNK_EVENTS = EnvUtils.getInt('CODEX_ORCHESTRATOR_EXEC_EVENT_MAX_CHUNKS', 500);
|
|
16
22
|
const MAX_COLLAB_TOOL_CALLS = EnvUtils.getInt('CODEX_ORCHESTRATOR_COLLAB_MAX_EVENTS', 200);
|
|
17
23
|
const PACKAGE_ROOT = findPackageRoot();
|
|
24
|
+
const REVIEW_EVIDENCE_CONSISTENCY_ENV_KEY = 'CODEX_REVIEW_ENFORCE_EVIDENCE_CONSISTENCY';
|
|
25
|
+
const REVIEW_EVIDENCE_WAIVER_REASON_ENV_KEY = 'CODEX_REVIEW_EVIDENCE_WAIVER_REASON';
|
|
26
|
+
const REVIEW_TELEMETRY_POLL_INTERVAL_MS = 50;
|
|
27
|
+
const REVIEW_TELEMETRY_WAIT_TIMEOUT_MS = 2_000;
|
|
28
|
+
const REVIEW_OUTCOME_BOUNDARY_PRESENCE_SENTINEL = {
|
|
29
|
+
kind: 'timeout',
|
|
30
|
+
provenance: 'review-timeout',
|
|
31
|
+
reason: '',
|
|
32
|
+
sample: null
|
|
33
|
+
};
|
|
18
34
|
export async function runCommandStage(context, hooks = {}) {
|
|
19
35
|
const { env, paths, manifest, stage, index, events, persister, envOverrides } = context;
|
|
20
36
|
const entryIndex = index - 1;
|
|
@@ -44,8 +60,8 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
44
60
|
runnerLog.write(payload);
|
|
45
61
|
commandLog.write(payload);
|
|
46
62
|
};
|
|
47
|
-
writeEvent({ type: 'command:start', command: stage.command });
|
|
48
63
|
const runner = getCliExecRunner();
|
|
64
|
+
let invocationPreview = stage.command;
|
|
49
65
|
let activeCorrelationId = null;
|
|
50
66
|
let stdoutBytes = 0;
|
|
51
67
|
let stderrBytes = 0;
|
|
@@ -111,7 +127,7 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
111
127
|
stageIndex: index,
|
|
112
128
|
toolName: 'exec',
|
|
113
129
|
status: 'started',
|
|
114
|
-
message:
|
|
130
|
+
message: invocationPreview,
|
|
115
131
|
attempt: event.attempt
|
|
116
132
|
});
|
|
117
133
|
break;
|
|
@@ -175,17 +191,32 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
175
191
|
CODEX_ORCHESTRATOR_ROOT: env.repoRoot,
|
|
176
192
|
CODEX_ORCHESTRATOR_PACKAGE_ROOT: PACKAGE_ROOT
|
|
177
193
|
};
|
|
194
|
+
baseEnv.CODEX_ORCHESTRATOR_NODE_BIN = process.execPath;
|
|
178
195
|
baseEnv.CODEX_ORCHESTRATOR_RUNTIME_MODE_ACTIVE =
|
|
179
196
|
context.runtimeMode ?? (manifest.runtime_mode === 'appserver' ? 'appserver' : 'cli');
|
|
180
197
|
// Keep both keys during migration because downstream tools still read either name.
|
|
181
198
|
baseEnv.CODEX_ORCHESTRATOR_RUNTIME_MODE = baseEnv.CODEX_ORCHESTRATOR_RUNTIME_MODE_ACTIVE;
|
|
182
199
|
const execEnv = { ...baseEnv, ...stage.env };
|
|
200
|
+
execEnv.CODEX_ORCHESTRATOR_NODE_BIN = process.execPath;
|
|
201
|
+
const invocation = resolveStageInvocation(stage, execEnv);
|
|
202
|
+
applyResolvedProgramInvocationEnvOverrides(execEnv, invocation.envOverrides);
|
|
203
|
+
if (invocation.warning) {
|
|
204
|
+
logger.warn(invocation.warning);
|
|
205
|
+
writeEvent({ type: 'command:warning', warning: invocation.warning });
|
|
206
|
+
}
|
|
207
|
+
invocationPreview = invocation.preview;
|
|
208
|
+
writeEvent({ type: 'command:start', command: invocationPreview });
|
|
209
|
+
const timeoutMs = resolveStageTimeoutMs(stage, execEnv);
|
|
183
210
|
const invocationId = `cli-command:${manifest.run_id}:${stage.id}:${Date.now()}`;
|
|
211
|
+
if (timeoutMs !== null) {
|
|
212
|
+
writeEvent({ type: 'command:config', timeout_ms: timeoutMs });
|
|
213
|
+
}
|
|
184
214
|
let result;
|
|
185
215
|
const eventCapture = MAX_CAPTURED_CHUNK_EVENTS > 0 ? { maxChunkEvents: MAX_CAPTURED_CHUNK_EVENTS } : undefined;
|
|
186
216
|
try {
|
|
187
217
|
result = await runner.run({
|
|
188
|
-
command:
|
|
218
|
+
command: invocation.command,
|
|
219
|
+
args: invocation.args,
|
|
189
220
|
cwd: stage.cwd ?? env.repoRoot,
|
|
190
221
|
env: execEnv,
|
|
191
222
|
sessionId: effectiveSessionId ?? undefined,
|
|
@@ -194,6 +225,7 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
194
225
|
invocationId,
|
|
195
226
|
toolId: 'cli:command',
|
|
196
227
|
description: stage.title,
|
|
228
|
+
...(timeoutMs !== null ? { timeoutMs } : {}),
|
|
197
229
|
eventCapture,
|
|
198
230
|
metadata: {
|
|
199
231
|
stageId: stage.id,
|
|
@@ -233,11 +265,161 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
233
265
|
const normalizedExitCode = result.exitCode ?? (result.signal ? 128 : 0);
|
|
234
266
|
const stdoutText = result.stdout.trim();
|
|
235
267
|
const stderrText = result.stderr.trim();
|
|
236
|
-
const
|
|
268
|
+
const timeoutBoundMs = typeof result.timeoutMs === 'number' && Number.isFinite(result.timeoutMs) && result.timeoutMs > 0
|
|
269
|
+
? Math.trunc(result.timeoutMs)
|
|
270
|
+
: timeoutMs;
|
|
271
|
+
const timedOut = result.timedOut === true;
|
|
272
|
+
const summary = buildSummary(stage, normalizedExitCode, stdoutText, stderrText, result.signal, {
|
|
273
|
+
timedOut,
|
|
274
|
+
timeoutMs: timeoutBoundMs
|
|
275
|
+
});
|
|
276
|
+
const enforceReviewEvidenceConsistency = shouldEnforceReviewEvidenceConsistency(stage);
|
|
277
|
+
const providerLinearWorkerStage = isProviderLinearWorkerCommandStage(stage);
|
|
278
|
+
const reviewTelemetryPath = join(paths.runDir, 'review', 'telemetry.json');
|
|
279
|
+
const shouldAwaitReviewTelemetry = (isReviewCommandStage(stage) || providerLinearWorkerStage) &&
|
|
280
|
+
shouldAwaitReviewTelemetryEvidence(execEnv, enforceReviewEvidenceConsistency);
|
|
281
|
+
const reviewTelemetry = isReviewCommandStage(stage) || providerLinearWorkerStage
|
|
282
|
+
? await loadReviewTelemetryEvidence(reviewTelemetryPath, {
|
|
283
|
+
waitForEvidence: shouldAwaitReviewTelemetry
|
|
284
|
+
})
|
|
285
|
+
: null;
|
|
286
|
+
const reviewEvidenceMismatch = isReviewCommandStage(stage) && (enforceReviewEvidenceConsistency || reviewTelemetry !== null)
|
|
287
|
+
? await verifyReviewEvidenceConsistency({
|
|
288
|
+
env,
|
|
289
|
+
paths,
|
|
290
|
+
expectedStatus: result.status === 'succeeded' ? 'succeeded' : 'failed',
|
|
291
|
+
startedAt: entry.started_at,
|
|
292
|
+
telemetry: reviewTelemetry,
|
|
293
|
+
telemetryPreloaded: shouldAwaitReviewTelemetry,
|
|
294
|
+
telemetryPath: reviewTelemetryPath
|
|
295
|
+
})
|
|
296
|
+
: null;
|
|
297
|
+
const providerReviewTelemetryMismatch = providerLinearWorkerStage && reviewTelemetry !== null
|
|
298
|
+
? verifyReviewTelemetryFreshness({
|
|
299
|
+
env,
|
|
300
|
+
paths,
|
|
301
|
+
startedAt: entry.started_at,
|
|
302
|
+
telemetry: reviewTelemetry,
|
|
303
|
+
telemetryPath: reviewTelemetryPath
|
|
304
|
+
})
|
|
305
|
+
: null;
|
|
306
|
+
const providerReviewTelemetry = providerReviewTelemetryMismatch === null
|
|
307
|
+
? reviewTelemetry
|
|
308
|
+
: null;
|
|
309
|
+
const reviewEvidenceWaiverReason = resolveReviewEvidenceWaiverReason(stage.env);
|
|
310
|
+
let effectiveSummary = summary;
|
|
311
|
+
let forceReviewEvidenceFailure = false;
|
|
312
|
+
let forceProviderLinearWorkerFailure = false;
|
|
313
|
+
let providerLinearWorkerFailureReason = null;
|
|
314
|
+
let providerLinearWorkerTerminalStatus = null;
|
|
315
|
+
let providerLinearWorkerTerminalReason = null;
|
|
316
|
+
let providerLinearWorkerReviewOutcomeSummary = null;
|
|
317
|
+
if (reviewEvidenceMismatch && enforceReviewEvidenceConsistency) {
|
|
318
|
+
if (reviewEvidenceWaiverReason) {
|
|
319
|
+
effectiveSummary = `${summary} (review evidence waiver: ${reviewEvidenceWaiverReason}; ${reviewEvidenceMismatch.message})`;
|
|
320
|
+
writeEvent({
|
|
321
|
+
type: 'command:waiver',
|
|
322
|
+
waiver: 'review-evidence-consistency',
|
|
323
|
+
reason: reviewEvidenceWaiverReason,
|
|
324
|
+
telemetry_path: relativeToRepo(env, reviewEvidenceMismatch.telemetryPath),
|
|
325
|
+
detail: reviewEvidenceMismatch.message
|
|
326
|
+
});
|
|
327
|
+
events?.log({
|
|
328
|
+
stageId: stage.id,
|
|
329
|
+
stageIndex: index,
|
|
330
|
+
level: 'warn',
|
|
331
|
+
source: 'system',
|
|
332
|
+
message: `Review evidence waiver applied: ${reviewEvidenceMismatch.message}`
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
effectiveSummary =
|
|
337
|
+
result.status === 'succeeded'
|
|
338
|
+
? `Review evidence mismatch: ${reviewEvidenceMismatch.message}`
|
|
339
|
+
: `Review evidence mismatch after command failure: ${reviewEvidenceMismatch.message} Command result: ${summary}`;
|
|
340
|
+
forceReviewEvidenceFailure = true;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (!reviewEvidenceMismatch) {
|
|
344
|
+
const reviewOutcomeSummary = formatReviewTelemetryOutcomeSummary(providerLinearWorkerStage ? providerReviewTelemetry : reviewTelemetry);
|
|
345
|
+
if (reviewOutcomeSummary) {
|
|
346
|
+
effectiveSummary = `${effectiveSummary} (${reviewOutcomeSummary})`;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (providerLinearWorkerStage) {
|
|
350
|
+
let providerLinearWorkerProof = await loadProviderLinearWorkerProof(join(paths.runDir, PROVIDER_LINEAR_WORKER_PROOF_FILENAME));
|
|
351
|
+
let providerLinearWorkerProofRecord = providerLinearWorkerProof;
|
|
352
|
+
if (providerLinearWorkerProofRecord &&
|
|
353
|
+
!isProviderLinearWorkerProofFreshForStage(providerLinearWorkerProofRecord, entry.started_at ?? null)) {
|
|
354
|
+
providerLinearWorkerProof = null;
|
|
355
|
+
providerLinearWorkerProofRecord = null;
|
|
356
|
+
}
|
|
357
|
+
if (result.status === 'succeeded' && providerLinearWorkerProofRecord === null) {
|
|
358
|
+
providerLinearWorkerFailureReason = 'provider_linear_worker_proof_missing_or_unreadable';
|
|
359
|
+
effectiveSummary = buildProviderLinearWorkerTerminalSummary({
|
|
360
|
+
status: 'failed',
|
|
361
|
+
endReason: 'provider_linear_worker_proof_missing_or_unreadable'
|
|
362
|
+
});
|
|
363
|
+
forceProviderLinearWorkerFailure = true;
|
|
364
|
+
}
|
|
365
|
+
const proofTerminalStatus = resolveProviderLinearWorkerTerminalStatus(providerLinearWorkerProofRecord);
|
|
366
|
+
const proofTerminalReason = resolveProviderLinearWorkerTerminalReason(providerLinearWorkerProofRecord);
|
|
367
|
+
providerLinearWorkerTerminalStatus = proofTerminalStatus;
|
|
368
|
+
providerLinearWorkerTerminalReason = proofTerminalReason;
|
|
369
|
+
const proofAttemptStartedAt = resolveProviderLinearWorkerAttemptStartedAt(providerLinearWorkerProofRecord) ?? entry.started_at ?? null;
|
|
370
|
+
const reviewTelemetryStatus = coerceTelemetryStatusValue(providerReviewTelemetry?.status);
|
|
371
|
+
const reviewOutcomeSummary = formatReviewTelemetryOutcomeSummary(providerReviewTelemetry);
|
|
372
|
+
providerLinearWorkerReviewOutcomeSummary = reviewOutcomeSummary;
|
|
373
|
+
const mutationSuppressions = deriveDeterministicProviderMutationSuppressions(providerLinearWorkerProof?.linear_audit ?? null, {
|
|
374
|
+
recordedAtNotBefore: proofAttemptStartedAt,
|
|
375
|
+
issueId: providerLinearWorkerProof?.issue_id ?? null
|
|
376
|
+
});
|
|
377
|
+
const degradationSummary = formatDeterministicProviderMutationDegradationSummary(mutationSuppressions);
|
|
378
|
+
if (proofTerminalStatus === 'failed') {
|
|
379
|
+
providerLinearWorkerFailureReason = 'provider_linear_worker_terminal_failed';
|
|
380
|
+
effectiveSummary = buildProviderLinearWorkerTerminalSummary({
|
|
381
|
+
status: 'failed',
|
|
382
|
+
endReason: proofTerminalReason,
|
|
383
|
+
reviewOutcomeSummary,
|
|
384
|
+
degradationSummary
|
|
385
|
+
});
|
|
386
|
+
forceProviderLinearWorkerFailure = true;
|
|
387
|
+
}
|
|
388
|
+
else if (providerLinearWorkerFailureReason === null && reviewTelemetryStatus === 'failed') {
|
|
389
|
+
providerLinearWorkerFailureReason = 'provider_linear_worker_review_failed';
|
|
390
|
+
effectiveSummary = buildProviderLinearWorkerTerminalSummary({
|
|
391
|
+
status: 'failed',
|
|
392
|
+
endReason: null,
|
|
393
|
+
reviewOutcomeSummary: reviewOutcomeSummary ?? 'review telemetry reported terminal failure',
|
|
394
|
+
degradationSummary
|
|
395
|
+
});
|
|
396
|
+
forceProviderLinearWorkerFailure = true;
|
|
397
|
+
}
|
|
398
|
+
else if (proofTerminalStatus === 'succeeded' && result.status === 'succeeded') {
|
|
399
|
+
effectiveSummary = buildProviderLinearWorkerTerminalSummary({
|
|
400
|
+
status: 'succeeded',
|
|
401
|
+
endReason: proofTerminalReason,
|
|
402
|
+
reviewOutcomeSummary,
|
|
403
|
+
degradationSummary
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
else if (degradationSummary) {
|
|
407
|
+
effectiveSummary = `${effectiveSummary} (${degradationSummary})`;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const effectiveExitCode = (forceReviewEvidenceFailure || forceProviderLinearWorkerFailure) && normalizedExitCode === 0
|
|
411
|
+
? 1
|
|
412
|
+
: normalizedExitCode;
|
|
237
413
|
entry.completed_at = isoTimestamp();
|
|
238
|
-
entry.exit_code =
|
|
239
|
-
entry.summary =
|
|
240
|
-
entry.status =
|
|
414
|
+
entry.exit_code = effectiveExitCode;
|
|
415
|
+
entry.summary = effectiveSummary;
|
|
416
|
+
entry.status = forceReviewEvidenceFailure || forceProviderLinearWorkerFailure
|
|
417
|
+
? 'failed'
|
|
418
|
+
: result.status === 'succeeded'
|
|
419
|
+
? 'succeeded'
|
|
420
|
+
: stage.allowFailure
|
|
421
|
+
? 'skipped'
|
|
422
|
+
: 'failed';
|
|
241
423
|
if (collabBuffer.trim()) {
|
|
242
424
|
const record = parseCollabToolCallLine(collabBuffer, stage.id, entry.index);
|
|
243
425
|
if (record) {
|
|
@@ -245,22 +427,113 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
245
427
|
}
|
|
246
428
|
collabBuffer = '';
|
|
247
429
|
}
|
|
248
|
-
if (entry.status === '
|
|
249
|
-
const
|
|
430
|
+
if (result.status !== 'succeeded' && entry.status === 'skipped') {
|
|
431
|
+
const fallbackReason = timedOut ? 'timed_out' : 'command_failed';
|
|
432
|
+
writeEvent({
|
|
433
|
+
type: 'command:fallback',
|
|
434
|
+
fallback: 'allow_failure',
|
|
435
|
+
reason: fallbackReason,
|
|
250
436
|
exit_code: normalizedExitCode,
|
|
437
|
+
signal: result.signal,
|
|
438
|
+
timeout_ms: timeoutBoundMs
|
|
439
|
+
});
|
|
440
|
+
events?.log({
|
|
441
|
+
stageId: stage.id,
|
|
442
|
+
stageIndex: index,
|
|
443
|
+
level: 'warn',
|
|
444
|
+
source: 'system',
|
|
445
|
+
message: timedOut
|
|
446
|
+
? `Non-fatal fallback applied after timeout (${timeoutBoundMs !== null ? `${timeoutBoundMs}ms` : 'configured timeout'}).`
|
|
447
|
+
: 'Non-fatal fallback applied after command failure.'
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
if (result.status !== 'succeeded') {
|
|
451
|
+
const failureReason = timedOut ? 'timed_out' : 'command_failed';
|
|
452
|
+
const errorDetails = {
|
|
453
|
+
exit_code: effectiveExitCode,
|
|
251
454
|
sandbox_state: result.sandboxState,
|
|
252
|
-
stderr: stderrText
|
|
455
|
+
stderr: stderrText,
|
|
456
|
+
failure_reason: failureReason
|
|
253
457
|
};
|
|
458
|
+
if (effectiveExitCode !== normalizedExitCode) {
|
|
459
|
+
errorDetails.command_exit_code = normalizedExitCode;
|
|
460
|
+
}
|
|
254
461
|
if (result.signal) {
|
|
255
462
|
errorDetails.signal = result.signal;
|
|
256
463
|
}
|
|
464
|
+
if (timeoutBoundMs !== null) {
|
|
465
|
+
errorDetails.timeout_ms = timeoutBoundMs;
|
|
466
|
+
}
|
|
467
|
+
if (timedOut) {
|
|
468
|
+
errorDetails.timed_out = true;
|
|
469
|
+
}
|
|
470
|
+
if (entry.status === 'skipped') {
|
|
471
|
+
errorDetails.non_fatal_fallback = true;
|
|
472
|
+
}
|
|
257
473
|
if (stdoutTruncated) {
|
|
258
474
|
errorDetails.stdout_truncated = true;
|
|
259
475
|
}
|
|
260
476
|
if (stderrTruncated) {
|
|
261
477
|
errorDetails.stderr_truncated = true;
|
|
262
478
|
}
|
|
263
|
-
entry.error_file = await appendCommandError(env, paths, manifest, entry, 'command-failed', errorDetails);
|
|
479
|
+
entry.error_file = await appendCommandError(env, paths, manifest, entry, entry.status === 'skipped' ? 'command-allow-failure' : 'command-failed', errorDetails);
|
|
480
|
+
}
|
|
481
|
+
if (forceProviderLinearWorkerFailure && result.status === 'succeeded' && !entry.error_file) {
|
|
482
|
+
const errorDetails = {
|
|
483
|
+
exit_code: effectiveExitCode,
|
|
484
|
+
command_exit_code: normalizedExitCode,
|
|
485
|
+
sandbox_state: result.sandboxState,
|
|
486
|
+
failure_reason: providerLinearWorkerFailureReason ?? 'provider_linear_worker_authoritative_failure',
|
|
487
|
+
detail: effectiveSummary
|
|
488
|
+
};
|
|
489
|
+
if (providerLinearWorkerTerminalStatus) {
|
|
490
|
+
errorDetails.provider_linear_worker_terminal_status = providerLinearWorkerTerminalStatus;
|
|
491
|
+
}
|
|
492
|
+
if (providerLinearWorkerTerminalReason) {
|
|
493
|
+
errorDetails.provider_linear_worker_end_reason = providerLinearWorkerTerminalReason;
|
|
494
|
+
}
|
|
495
|
+
if (providerLinearWorkerReviewOutcomeSummary) {
|
|
496
|
+
errorDetails.review_outcome_summary = providerLinearWorkerReviewOutcomeSummary;
|
|
497
|
+
}
|
|
498
|
+
if (stdoutTruncated) {
|
|
499
|
+
errorDetails.stdout_truncated = true;
|
|
500
|
+
}
|
|
501
|
+
if (stderrTruncated) {
|
|
502
|
+
errorDetails.stderr_truncated = true;
|
|
503
|
+
}
|
|
504
|
+
entry.error_file = await appendCommandError(env, paths, manifest, entry, 'provider-linear-worker-authoritative-failed', errorDetails);
|
|
505
|
+
}
|
|
506
|
+
if (forceReviewEvidenceFailure && reviewEvidenceMismatch) {
|
|
507
|
+
if (entry.error_file) {
|
|
508
|
+
writeEvent({
|
|
509
|
+
type: 'command:warning',
|
|
510
|
+
warning: 'review-evidence-inconsistent',
|
|
511
|
+
preserved_error_file: entry.error_file,
|
|
512
|
+
telemetry_path: relativeToRepo(env, reviewEvidenceMismatch.telemetryPath),
|
|
513
|
+
detail: reviewEvidenceMismatch.message
|
|
514
|
+
});
|
|
515
|
+
events?.log({
|
|
516
|
+
stageId: stage.id,
|
|
517
|
+
stageIndex: index,
|
|
518
|
+
level: 'warn',
|
|
519
|
+
source: 'system',
|
|
520
|
+
message: `Review evidence mismatch preserved alongside the original command failure: ${reviewEvidenceMismatch.message}`
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
entry.error_file = await appendCommandError(env, paths, manifest, entry, 'review-evidence-inconsistent', {
|
|
525
|
+
exit_code: effectiveExitCode,
|
|
526
|
+
command_exit_code: normalizedExitCode,
|
|
527
|
+
sandbox_state: result.sandboxState,
|
|
528
|
+
expected_review_status: result.status === 'succeeded' ? 'succeeded' : 'failed',
|
|
529
|
+
telemetry_status: reviewEvidenceMismatch.telemetryStatus,
|
|
530
|
+
telemetry_generated_at: reviewEvidenceMismatch.telemetryGeneratedAt,
|
|
531
|
+
telemetry_output_log_path: reviewEvidenceMismatch.telemetryOutputLogPath,
|
|
532
|
+
telemetry_path: relativeToRepo(env, reviewEvidenceMismatch.telemetryPath),
|
|
533
|
+
failure_reason: 'review_evidence_inconsistent',
|
|
534
|
+
detail: reviewEvidenceMismatch.message
|
|
535
|
+
});
|
|
536
|
+
}
|
|
264
537
|
}
|
|
265
538
|
await persistManifest(paths, manifest, persister, { force: true });
|
|
266
539
|
events?.stageCompleted({
|
|
@@ -273,7 +546,7 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
273
546
|
summary: entry.summary,
|
|
274
547
|
logPath: entry.log_path
|
|
275
548
|
});
|
|
276
|
-
return { exitCode:
|
|
549
|
+
return { exitCode: effectiveExitCode, summary: effectiveSummary };
|
|
277
550
|
}
|
|
278
551
|
finally {
|
|
279
552
|
unsubscribe();
|
|
@@ -282,6 +555,302 @@ export async function runCommandStage(context, hooks = {}) {
|
|
|
282
555
|
privacyLog.end();
|
|
283
556
|
}
|
|
284
557
|
}
|
|
558
|
+
function shouldEnforceReviewEvidenceConsistency(stage) {
|
|
559
|
+
return (parseBooleanEnvFlag(stage.env?.[REVIEW_EVIDENCE_CONSISTENCY_ENV_KEY]) &&
|
|
560
|
+
isReviewCommandStage(stage));
|
|
561
|
+
}
|
|
562
|
+
function shouldAwaitReviewTelemetryEvidence(execEnv, enforceReviewEvidenceConsistency) {
|
|
563
|
+
if (enforceReviewEvidenceConsistency) {
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
const forced = parseBooleanEnvFlag(execEnv.FORCE_CODEX_REVIEW);
|
|
567
|
+
const nonInteractive = process.stdin.isTTY !== true ||
|
|
568
|
+
parseBooleanEnvFlag(execEnv.CODEX_REVIEW_NON_INTERACTIVE) ||
|
|
569
|
+
parseBooleanEnvFlag(execEnv.CODEX_NON_INTERACTIVE) ||
|
|
570
|
+
parseBooleanEnvFlag(execEnv.CODEX_NO_INTERACTIVE);
|
|
571
|
+
return forced || !nonInteractive;
|
|
572
|
+
}
|
|
573
|
+
function isReviewCommandStage(stage) {
|
|
574
|
+
const stageId = stage.id.trim().toLowerCase();
|
|
575
|
+
if (stageId === 'review') {
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
const haystack = `${stage.title} ${stage.command}`.toLowerCase();
|
|
579
|
+
return (haystack.includes('npm run review') ||
|
|
580
|
+
haystack.includes('codex review') ||
|
|
581
|
+
haystack.includes('codex-orchestrator review') ||
|
|
582
|
+
haystack.includes('run-review.ts') ||
|
|
583
|
+
haystack.includes('run-review.js'));
|
|
584
|
+
}
|
|
585
|
+
function isProviderLinearWorkerCommandStage(stage) {
|
|
586
|
+
const stageId = stage.id.trim().toLowerCase();
|
|
587
|
+
if (stageId === 'provider-linear-worker') {
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
const haystack = `${stage.title} ${stage.command}`.toLowerCase();
|
|
591
|
+
return haystack.includes('providerlinearworkerrunner');
|
|
592
|
+
}
|
|
593
|
+
function resolveStageInvocation(stage, env) {
|
|
594
|
+
if (isProviderLinearWorkerCommandStage(stage)) {
|
|
595
|
+
const providerWorkerPackageRoot = normalizeOptionalString(env.CODEX_ORCHESTRATOR_PACKAGE_ROOT) ?? PACKAGE_ROOT;
|
|
596
|
+
const invocation = resolveProviderLinearWorkerProgramInvocation({
|
|
597
|
+
allowConfiguredForeignPackageRoot: true,
|
|
598
|
+
env,
|
|
599
|
+
execPath: normalizeOptionalString(env.CODEX_ORCHESTRATOR_NODE_BIN) ?? process.execPath,
|
|
600
|
+
packageRoot: providerWorkerPackageRoot
|
|
601
|
+
});
|
|
602
|
+
return {
|
|
603
|
+
command: invocation.command,
|
|
604
|
+
args: invocation.args,
|
|
605
|
+
preview: buildCommandPreview(invocation.command, invocation.args),
|
|
606
|
+
warning: invocation.warning,
|
|
607
|
+
envOverrides: invocation.envOverrides
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
const packageRootInvocation = resolvePackageRootDistStageInvocation(stage.command, env);
|
|
611
|
+
if (packageRootInvocation) {
|
|
612
|
+
return packageRootInvocation;
|
|
613
|
+
}
|
|
614
|
+
return {
|
|
615
|
+
command: stage.command,
|
|
616
|
+
preview: stage.command
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
function resolvePackageRootDistStageInvocation(commandLine, env) {
|
|
620
|
+
const match = commandLine.match(/^\s*node\s+["']?\$CODEX_ORCHESTRATOR_PACKAGE_ROOT\/dist\/([^"'\s]+?\.js)["']?(.*)$/u);
|
|
621
|
+
if (!match) {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
const [, distRelativePath, trailingArgsRaw] = match;
|
|
625
|
+
const invocation = resolvePackageProgramInvocation({
|
|
626
|
+
allowConfiguredForeignPackageRoot: true,
|
|
627
|
+
env,
|
|
628
|
+
packageRoot: PACKAGE_ROOT,
|
|
629
|
+
execPath: normalizeOptionalString(env.CODEX_ORCHESTRATOR_NODE_BIN) ?? process.execPath,
|
|
630
|
+
distRelativePath
|
|
631
|
+
});
|
|
632
|
+
const command = `${buildCommandPreview(invocation.command, invocation.args)}${trailingArgsRaw}`;
|
|
633
|
+
return {
|
|
634
|
+
command,
|
|
635
|
+
preview: command,
|
|
636
|
+
warning: invocation.warning,
|
|
637
|
+
envOverrides: invocation.envOverrides
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function resolveReviewEvidenceWaiverReason(env) {
|
|
641
|
+
const reason = env?.[REVIEW_EVIDENCE_WAIVER_REASON_ENV_KEY]?.trim();
|
|
642
|
+
return reason && reason.length > 0 ? reason : null;
|
|
643
|
+
}
|
|
644
|
+
function parseBooleanEnvFlag(value) {
|
|
645
|
+
if (!value) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
const normalized = value.trim().toLowerCase();
|
|
649
|
+
return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
|
|
650
|
+
}
|
|
651
|
+
async function verifyReviewEvidenceConsistency(options) {
|
|
652
|
+
const telemetryPath = options.telemetryPath ?? join(options.paths.runDir, 'review', 'telemetry.json');
|
|
653
|
+
const telemetry = options.telemetryPreloaded === true
|
|
654
|
+
? options.telemetry ?? null
|
|
655
|
+
: options.telemetry ?? (await waitForReviewTelemetryEvidence(telemetryPath));
|
|
656
|
+
if (!telemetry) {
|
|
657
|
+
return {
|
|
658
|
+
message: 'review telemetry is missing, unreadable, or incomplete at terminal stage closeout.',
|
|
659
|
+
telemetryPath,
|
|
660
|
+
telemetryStatus: null,
|
|
661
|
+
telemetryGeneratedAt: null,
|
|
662
|
+
telemetryOutputLogPath: null
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
const freshnessMismatch = verifyReviewTelemetryFreshness({
|
|
666
|
+
env: options.env,
|
|
667
|
+
paths: options.paths,
|
|
668
|
+
startedAt: options.startedAt,
|
|
669
|
+
telemetry,
|
|
670
|
+
telemetryPath
|
|
671
|
+
});
|
|
672
|
+
if (freshnessMismatch) {
|
|
673
|
+
return freshnessMismatch;
|
|
674
|
+
}
|
|
675
|
+
const generatedAt = coerceTelemetryString(telemetry.generated_at);
|
|
676
|
+
const telemetryStatus = coerceTelemetryString(telemetry.status);
|
|
677
|
+
const telemetryOutputLogPath = coerceTelemetryString(telemetry.output_log_path);
|
|
678
|
+
if (telemetryStatus !== options.expectedStatus) {
|
|
679
|
+
return {
|
|
680
|
+
message: `review telemetry status ${telemetryStatus ?? '<missing>'} does not match terminal stage result ${options.expectedStatus}.`,
|
|
681
|
+
telemetryPath,
|
|
682
|
+
telemetryStatus,
|
|
683
|
+
telemetryGeneratedAt: generatedAt,
|
|
684
|
+
telemetryOutputLogPath
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
function verifyReviewTelemetryFreshness(options) {
|
|
690
|
+
const { env, paths, startedAt, telemetry, telemetryPath } = options;
|
|
691
|
+
const generatedAt = typeof telemetry.generated_at === 'string' && telemetry.generated_at.trim().length > 0
|
|
692
|
+
? telemetry.generated_at
|
|
693
|
+
: null;
|
|
694
|
+
if (!generatedAt) {
|
|
695
|
+
return {
|
|
696
|
+
message: 'review telemetry is missing generated_at, so terminal evidence freshness cannot be verified.',
|
|
697
|
+
telemetryPath,
|
|
698
|
+
telemetryStatus: coerceTelemetryString(telemetry.status),
|
|
699
|
+
telemetryGeneratedAt: null,
|
|
700
|
+
telemetryOutputLogPath: coerceTelemetryString(telemetry.output_log_path)
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
const generatedAtMs = Date.parse(generatedAt);
|
|
704
|
+
if (!Number.isFinite(generatedAtMs)) {
|
|
705
|
+
return {
|
|
706
|
+
message: `review telemetry generated_at is invalid (${generatedAt}).`,
|
|
707
|
+
telemetryPath,
|
|
708
|
+
telemetryStatus: coerceTelemetryString(telemetry.status),
|
|
709
|
+
telemetryGeneratedAt: generatedAt,
|
|
710
|
+
telemetryOutputLogPath: coerceTelemetryString(telemetry.output_log_path)
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
const startedAtMs = typeof startedAt === 'string' ? Date.parse(startedAt) : Number.NaN;
|
|
714
|
+
if (Number.isFinite(startedAtMs) && generatedAtMs < startedAtMs) {
|
|
715
|
+
return {
|
|
716
|
+
message: `review telemetry is stale (generated_at ${generatedAt} precedes stage start ${startedAt}).`,
|
|
717
|
+
telemetryPath,
|
|
718
|
+
telemetryStatus: coerceTelemetryString(telemetry.status),
|
|
719
|
+
telemetryGeneratedAt: generatedAt,
|
|
720
|
+
telemetryOutputLogPath: coerceTelemetryString(telemetry.output_log_path)
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
const expectedOutputLogPath = relativeToRepo(env, join(paths.runDir, 'review', 'output.log'));
|
|
724
|
+
const telemetryStatus = coerceTelemetryString(telemetry.status);
|
|
725
|
+
const telemetryOutputLogPath = coerceTelemetryString(telemetry.output_log_path);
|
|
726
|
+
if (telemetryOutputLogPath !== expectedOutputLogPath) {
|
|
727
|
+
return {
|
|
728
|
+
message: `review telemetry output_log_path ${telemetryOutputLogPath ?? '<missing>'} does not match the active run artifact ${expectedOutputLogPath}.`,
|
|
729
|
+
telemetryPath,
|
|
730
|
+
telemetryStatus,
|
|
731
|
+
telemetryGeneratedAt: generatedAt,
|
|
732
|
+
telemetryOutputLogPath
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
return null;
|
|
736
|
+
}
|
|
737
|
+
async function loadReviewTelemetryEvidence(telemetryPath, options) {
|
|
738
|
+
if (options.waitForEvidence) {
|
|
739
|
+
return await waitForReviewTelemetryEvidence(telemetryPath);
|
|
740
|
+
}
|
|
741
|
+
return await readReviewTelemetryEvidence(telemetryPath);
|
|
742
|
+
}
|
|
743
|
+
async function waitForReviewTelemetryEvidence(telemetryPath) {
|
|
744
|
+
const deadline = Date.now() + REVIEW_TELEMETRY_WAIT_TIMEOUT_MS;
|
|
745
|
+
for (;;) {
|
|
746
|
+
const telemetry = await readReviewTelemetryEvidence(telemetryPath);
|
|
747
|
+
if (telemetry) {
|
|
748
|
+
return telemetry;
|
|
749
|
+
}
|
|
750
|
+
if (Date.now() >= deadline) {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
await delay(REVIEW_TELEMETRY_POLL_INTERVAL_MS);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
async function readReviewTelemetryEvidence(telemetryPath) {
|
|
757
|
+
try {
|
|
758
|
+
const raw = await readFile(telemetryPath, 'utf8');
|
|
759
|
+
const parsed = JSON.parse(raw);
|
|
760
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
761
|
+
}
|
|
762
|
+
catch {
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
async function loadProviderLinearWorkerProof(proofPath) {
|
|
767
|
+
try {
|
|
768
|
+
const raw = await readFile(proofPath, 'utf8');
|
|
769
|
+
const parsed = JSON.parse(raw);
|
|
770
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
771
|
+
}
|
|
772
|
+
catch {
|
|
773
|
+
return null;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
function coerceTelemetryString(value) {
|
|
777
|
+
if (typeof value !== 'string') {
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
const trimmed = value.trim();
|
|
781
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
782
|
+
}
|
|
783
|
+
function coerceTelemetryStatusValue(value) {
|
|
784
|
+
if (value === 'succeeded' || value === 'failed') {
|
|
785
|
+
return value;
|
|
786
|
+
}
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
function coerceReviewOutcomeDisposition(value) {
|
|
790
|
+
switch (value) {
|
|
791
|
+
case 'clean-success':
|
|
792
|
+
case 'bounded-success':
|
|
793
|
+
case 'failed-boundary':
|
|
794
|
+
case 'failed-other':
|
|
795
|
+
return value;
|
|
796
|
+
default:
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
function hasTelemetryTerminationBoundary(telemetry) {
|
|
801
|
+
return coerceTelemetryTerminationBoundaryKind(telemetry) !== null;
|
|
802
|
+
}
|
|
803
|
+
function coerceTelemetryTerminationBoundaryKind(telemetry) {
|
|
804
|
+
if (!telemetry) {
|
|
805
|
+
return null;
|
|
806
|
+
}
|
|
807
|
+
const boundary = telemetry.termination_boundary;
|
|
808
|
+
if (boundary === null || typeof boundary !== 'object' || Array.isArray(boundary)) {
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
return coerceTelemetryString(boundary.kind);
|
|
812
|
+
}
|
|
813
|
+
function resolveReviewTelemetryOutcomeDisposition(telemetry) {
|
|
814
|
+
if (!telemetry) {
|
|
815
|
+
return null;
|
|
816
|
+
}
|
|
817
|
+
const explicitDisposition = coerceReviewOutcomeDisposition(telemetry.review_outcome);
|
|
818
|
+
const telemetryStatus = coerceTelemetryStatusValue(telemetry.status);
|
|
819
|
+
if (!telemetryStatus) {
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
const derivedDisposition = deriveReviewOutcomeDisposition({
|
|
823
|
+
status: telemetryStatus,
|
|
824
|
+
terminationBoundary: hasTelemetryTerminationBoundary(telemetry)
|
|
825
|
+
? REVIEW_OUTCOME_BOUNDARY_PRESENCE_SENTINEL
|
|
826
|
+
: null
|
|
827
|
+
});
|
|
828
|
+
return explicitDisposition === derivedDisposition ? explicitDisposition : derivedDisposition;
|
|
829
|
+
}
|
|
830
|
+
function formatReviewTelemetryOutcomeSummary(telemetry) {
|
|
831
|
+
const disposition = resolveReviewTelemetryOutcomeDisposition(telemetry);
|
|
832
|
+
if (!disposition) {
|
|
833
|
+
return null;
|
|
834
|
+
}
|
|
835
|
+
const boundaryKind = coerceTelemetryTerminationBoundaryKind(telemetry);
|
|
836
|
+
switch (disposition) {
|
|
837
|
+
case 'clean-success':
|
|
838
|
+
return 'review outcome: clean success';
|
|
839
|
+
case 'bounded-success':
|
|
840
|
+
return boundaryKind
|
|
841
|
+
? `review outcome: bounded success via ${boundaryKind}; not a wrapper failure`
|
|
842
|
+
: 'review outcome: bounded success with preserved termination boundary; not a wrapper failure';
|
|
843
|
+
case 'failed-boundary':
|
|
844
|
+
return boundaryKind
|
|
845
|
+
? `review outcome: review-wrapper failure via ${boundaryKind}`
|
|
846
|
+
: 'review outcome: review-wrapper failure via explicit termination boundary';
|
|
847
|
+
case 'failed-other':
|
|
848
|
+
return 'review outcome: review command failed without termination-boundary classification; not an explicit wrapper-boundary failure';
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
function delay(ms) {
|
|
852
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
853
|
+
}
|
|
285
854
|
function runtimeSessionIdOrNull(value) {
|
|
286
855
|
if (typeof value !== 'string') {
|
|
287
856
|
return null;
|
|
@@ -454,9 +1023,12 @@ function streamEvent(writeEvent, event, hooks) {
|
|
|
454
1023
|
break;
|
|
455
1024
|
}
|
|
456
1025
|
}
|
|
457
|
-
function buildSummary(stage, exitCode, stdout, stderr, signal) {
|
|
458
|
-
if (
|
|
459
|
-
|
|
1026
|
+
function buildSummary(stage, exitCode, stdout, stderr, signal, options = {}) {
|
|
1027
|
+
if (options.timedOut) {
|
|
1028
|
+
const timeoutLabel = typeof options.timeoutMs === 'number' && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0
|
|
1029
|
+
? `${Math.trunc(options.timeoutMs)}ms`
|
|
1030
|
+
: 'configured timeout';
|
|
1031
|
+
return `Timed out after ${timeoutLabel}${stderr ? ` — ${truncate(stderr)}` : ''}`;
|
|
460
1032
|
}
|
|
461
1033
|
if (signal) {
|
|
462
1034
|
return `Terminated with signal ${signal}${stderr ? ` — ${truncate(stderr)}` : ''}`;
|
|
@@ -464,6 +1036,9 @@ function buildSummary(stage, exitCode, stdout, stderr, signal) {
|
|
|
464
1036
|
if (exitCode !== 0) {
|
|
465
1037
|
return `Exited with code ${exitCode}${stderr ? ` — ${truncate(stderr)}` : ''}`;
|
|
466
1038
|
}
|
|
1039
|
+
if (stage.summaryHint) {
|
|
1040
|
+
return stage.summaryHint;
|
|
1041
|
+
}
|
|
467
1042
|
if (stdout) {
|
|
468
1043
|
return truncate(stdout);
|
|
469
1044
|
}
|
|
@@ -502,9 +1077,15 @@ function parseCollabToolCallLine(line, stageId, commandIndex) {
|
|
|
502
1077
|
if (!item || item.type !== 'collab_tool_call') {
|
|
503
1078
|
return null;
|
|
504
1079
|
}
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
1080
|
+
const receiverThreadIdSlots = parseStringSlots(item.receiver_thread_ids);
|
|
1081
|
+
const receiverThreadIds = receiverThreadIdSlots.filter((entry) => entry !== null);
|
|
1082
|
+
const senderAgentPath = normalizeOptionalString(item.sender_agent_path);
|
|
1083
|
+
const receiverAgentPathSlots = parseStringSlots(item.receiver_agent_paths);
|
|
1084
|
+
const receiverAgentPaths = receiverAgentPathSlots.filter((entry) => entry !== null);
|
|
1085
|
+
const receiverAgents = parseCollabReceiverAgents(item.receiver_agents, {
|
|
1086
|
+
receiverThreadIdSlots,
|
|
1087
|
+
receiverAgentPathSlots
|
|
1088
|
+
});
|
|
508
1089
|
return {
|
|
509
1090
|
observed_at: isoTimestamp(),
|
|
510
1091
|
stage_id: stageId,
|
|
@@ -515,15 +1096,84 @@ function parseCollabToolCallLine(line, stageId, commandIndex) {
|
|
|
515
1096
|
status: normalizeCollabStatus(item.status),
|
|
516
1097
|
sender_thread_id: typeof item.sender_thread_id === 'string' ? item.sender_thread_id : 'unknown',
|
|
517
1098
|
receiver_thread_ids: receiverThreadIds,
|
|
1099
|
+
sender_agent_path: senderAgentPath,
|
|
1100
|
+
receiver_agent_paths: receiverAgentPaths.length > 0
|
|
1101
|
+
? receiverAgentPaths
|
|
1102
|
+
: receiverAgents
|
|
1103
|
+
?.map((entry) => entry.agent_path)
|
|
1104
|
+
.filter((entry) => typeof entry === 'string' && entry.length > 0) ?? null,
|
|
1105
|
+
receiver_agents: receiverAgents,
|
|
518
1106
|
prompt: typeof item.prompt === 'string' ? item.prompt : null,
|
|
1107
|
+
fork_context: typeof item.fork_context === 'boolean' ? item.fork_context : null,
|
|
519
1108
|
agents_states: item.agents_states && typeof item.agents_states === 'object'
|
|
520
1109
|
? item.agents_states
|
|
521
1110
|
: null
|
|
522
1111
|
};
|
|
523
1112
|
}
|
|
1113
|
+
function parseStringSlots(value) {
|
|
1114
|
+
return Array.isArray(value) ? value.map((entry) => normalizeOptionalString(entry)) : [];
|
|
1115
|
+
}
|
|
1116
|
+
function normalizeOptionalString(value) {
|
|
1117
|
+
if (typeof value !== 'string') {
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
const trimmed = value.trim();
|
|
1121
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1122
|
+
}
|
|
1123
|
+
function parseCollabReceiverAgents(value, slots = {}) {
|
|
1124
|
+
if (!Array.isArray(value)) {
|
|
1125
|
+
return null;
|
|
1126
|
+
}
|
|
1127
|
+
const { receiverThreadIdSlots = [], receiverAgentPathSlots = [] } = slots;
|
|
1128
|
+
const parsed = [];
|
|
1129
|
+
for (const [index, entry] of value.entries()) {
|
|
1130
|
+
if (!entry || typeof entry !== 'object') {
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
const record = entry;
|
|
1134
|
+
const threadId = normalizeOptionalString(record.thread_id) ?? receiverThreadIdSlots[index] ?? null;
|
|
1135
|
+
const agentNickname = normalizeOptionalString(record.agent_nickname);
|
|
1136
|
+
const agentRole = normalizeOptionalString(record.agent_role);
|
|
1137
|
+
const agentPath = normalizeOptionalString(record.agent_path) ?? receiverAgentPathSlots[index] ?? null;
|
|
1138
|
+
if (!threadId && !agentNickname && !agentRole && !agentPath) {
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
parsed.push({
|
|
1142
|
+
thread_id: threadId,
|
|
1143
|
+
agent_nickname: agentNickname,
|
|
1144
|
+
agent_role: agentRole,
|
|
1145
|
+
agent_path: agentPath
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
return parsed.length > 0 ? parsed : null;
|
|
1149
|
+
}
|
|
524
1150
|
function normalizeCollabStatus(value) {
|
|
525
1151
|
if (value === 'completed' || value === 'failed' || value === 'in_progress') {
|
|
526
1152
|
return value;
|
|
527
1153
|
}
|
|
528
1154
|
return 'in_progress';
|
|
529
1155
|
}
|
|
1156
|
+
function resolveStageTimeoutMs(stage, env) {
|
|
1157
|
+
const stageTimeout = normalizeTimeoutMs(stage.timeoutMs);
|
|
1158
|
+
if (stageTimeout !== null) {
|
|
1159
|
+
return stageTimeout;
|
|
1160
|
+
}
|
|
1161
|
+
return normalizeTimeoutMs(parseNumber(env.CODEX_ORCHESTRATOR_STAGE_TIMEOUT_MS));
|
|
1162
|
+
}
|
|
1163
|
+
function parseNumber(value) {
|
|
1164
|
+
if (!value || !value.trim()) {
|
|
1165
|
+
return undefined;
|
|
1166
|
+
}
|
|
1167
|
+
const parsed = Number(value);
|
|
1168
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
1169
|
+
}
|
|
1170
|
+
function normalizeTimeoutMs(value) {
|
|
1171
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
const normalized = Math.trunc(value);
|
|
1175
|
+
if (normalized <= 0) {
|
|
1176
|
+
return null;
|
|
1177
|
+
}
|
|
1178
|
+
return normalized;
|
|
1179
|
+
}
|