@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
|
@@ -0,0 +1,1200 @@
|
|
|
1
|
+
/* eslint-disable patterns/prefer-logger-over-console */
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import { resolveLinearSourceSetup, } from './control/linearDispatchSource.js';
|
|
7
|
+
import { attachProviderLinearIssuePr, createProviderLinearFollowUpIssue, deleteProviderLinearWorkpadComment, getProviderLinearIssueContext, transitionProviderLinearIssueState, upsertProviderLinearWorkpadComment } from './control/providerLinearWorkflowFacade.js';
|
|
8
|
+
import { appendProviderLinearAuditEntry, isProviderLinearParallelizationDecision, isProviderLinearParallelizationReason, isProviderLinearParallelizationReasonAllowed, resolveProviderLinearAuditPath, summarizeProviderLinearAuditPath } from './control/providerLinearWorkflowAudit.js';
|
|
9
|
+
import { findDeterministicProviderMutationSuppression, isFollowUpParityMatrixSuppressionCode, resolveProviderLinearWorkerAttemptStartedAt } from './control/providerLinearWorkerTruth.js';
|
|
10
|
+
import { resolveProviderLinearRuntimeProof } from './control/providerLinearRuntimeProof.js';
|
|
11
|
+
import { resolveProviderLinearScreenshotProof } from './control/providerLinearScreenshotProof.js';
|
|
12
|
+
import { runProviderLinearChildStreamShell } from './providerLinearChildStreamShell.js';
|
|
13
|
+
import { runProviderLinearChildLaneShell } from './providerLinearChildLaneShell.js';
|
|
14
|
+
import { PROVIDER_LINEAR_WORKER_PROOF_FILENAME, loadProviderLinearWorkerContext, refreshProviderLinearWorkerProofSnapshot } from './providerLinearWorkerRunner.js';
|
|
15
|
+
const DEFAULT_DEPENDENCIES = {
|
|
16
|
+
getProviderLinearIssueContext,
|
|
17
|
+
upsertProviderLinearWorkpadComment,
|
|
18
|
+
deleteProviderLinearWorkpadComment,
|
|
19
|
+
transitionProviderLinearIssueState,
|
|
20
|
+
attachProviderLinearIssuePr,
|
|
21
|
+
runProviderLinearChildStreamShell,
|
|
22
|
+
runProviderLinearChildLaneShell,
|
|
23
|
+
createProviderLinearFollowUpIssue,
|
|
24
|
+
resolveProviderLinearRuntimeProof,
|
|
25
|
+
resolveProviderLinearScreenshotProof,
|
|
26
|
+
loadProviderLinearWorkerContext,
|
|
27
|
+
refreshProviderLinearWorkerProofSnapshot,
|
|
28
|
+
appendAuditEntry: appendProviderLinearAuditEntry,
|
|
29
|
+
readTextFile: async (path) => await readFile(path, 'utf8'),
|
|
30
|
+
getEnv: () => process.env,
|
|
31
|
+
getCwd: () => process.cwd(),
|
|
32
|
+
now: () => new Date().toISOString(),
|
|
33
|
+
log: (line) => console.log(line),
|
|
34
|
+
warn: (line) => console.warn(line),
|
|
35
|
+
setExitCode: (code) => {
|
|
36
|
+
process.exitCode = code;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const LINEAR_MUTATING_SUBCOMMANDS = new Set([
|
|
40
|
+
'upsert-workpad',
|
|
41
|
+
'delete-workpad',
|
|
42
|
+
'transition',
|
|
43
|
+
'attach-pr',
|
|
44
|
+
'parallelization',
|
|
45
|
+
'create-follow-up',
|
|
46
|
+
'child-stream',
|
|
47
|
+
'child-lane'
|
|
48
|
+
]);
|
|
49
|
+
export async function runLinearCliShell(params, overrides = {}) {
|
|
50
|
+
const dependencies = { ...DEFAULT_DEPENDENCIES, ...overrides };
|
|
51
|
+
try {
|
|
52
|
+
const env = dependencies.getEnv();
|
|
53
|
+
const positionals = [...params.positionals];
|
|
54
|
+
const subcommand = positionals.shift();
|
|
55
|
+
const wantsHelp = params.flags['help'] === true
|
|
56
|
+
|| params.flags['--help'] === true
|
|
57
|
+
|| params.flags['h'] === true
|
|
58
|
+
|| !subcommand
|
|
59
|
+
|| subcommand === 'help'
|
|
60
|
+
|| subcommand === '--help'
|
|
61
|
+
|| subcommand === '-h';
|
|
62
|
+
if (wantsHelp) {
|
|
63
|
+
params.printHelp();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (positionals.length > 0) {
|
|
67
|
+
throw usageError('linear_extra_arguments', `linear does not accept extra positional arguments: ${positionals.join(' ')}`);
|
|
68
|
+
}
|
|
69
|
+
await assertLinearMutationAllowed(subcommand, params.flags, env, dependencies.readTextFile);
|
|
70
|
+
switch (subcommand) {
|
|
71
|
+
case 'issue-context': {
|
|
72
|
+
assertAllowedFlags(params.flags, ['format', 'issue-id', 'workspace-id', 'team-id', 'project-id']);
|
|
73
|
+
const result = await dependencies.getProviderLinearIssueContext({
|
|
74
|
+
issueId: requireFlag(params.flags, 'issue-id'),
|
|
75
|
+
sourceSetup: readSourceSetup(params.flags),
|
|
76
|
+
allowReadOnlyCacheReuse: true,
|
|
77
|
+
env
|
|
78
|
+
});
|
|
79
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
80
|
+
emitJsonResult(result, dependencies);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
case 'upsert-workpad': {
|
|
84
|
+
assertAllowedFlags(params.flags, [
|
|
85
|
+
'format',
|
|
86
|
+
'issue-id',
|
|
87
|
+
'workspace-id',
|
|
88
|
+
'team-id',
|
|
89
|
+
'project-id',
|
|
90
|
+
'body',
|
|
91
|
+
'body-file',
|
|
92
|
+
'comment-id'
|
|
93
|
+
]);
|
|
94
|
+
const bodyInput = await resolveBodyInput(params.flags, dependencies.readTextFile, dependencies.getCwd());
|
|
95
|
+
const result = await dependencies.upsertProviderLinearWorkpadComment({
|
|
96
|
+
issueId: requireFlag(params.flags, 'issue-id'),
|
|
97
|
+
body: bodyInput.text,
|
|
98
|
+
bodyFilePath: bodyInput.filePath,
|
|
99
|
+
commentId: readStringFlag(params.flags, 'comment-id') ?? null,
|
|
100
|
+
sourceSetup: readSourceSetup(params.flags),
|
|
101
|
+
env
|
|
102
|
+
});
|
|
103
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
104
|
+
emitJsonResult(result, dependencies);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
case 'delete-workpad': {
|
|
108
|
+
assertAllowedFlags(params.flags, [
|
|
109
|
+
'format',
|
|
110
|
+
'issue-id',
|
|
111
|
+
'workspace-id',
|
|
112
|
+
'team-id',
|
|
113
|
+
'project-id',
|
|
114
|
+
'comment-id'
|
|
115
|
+
]);
|
|
116
|
+
const result = await dependencies.deleteProviderLinearWorkpadComment({
|
|
117
|
+
issueId: requireFlag(params.flags, 'issue-id'),
|
|
118
|
+
commentId: readStringFlag(params.flags, 'comment-id') ?? null,
|
|
119
|
+
sourceSetup: readSourceSetup(params.flags),
|
|
120
|
+
env
|
|
121
|
+
});
|
|
122
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
123
|
+
emitJsonResult(result, dependencies);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
case 'transition': {
|
|
127
|
+
assertAllowedFlags(params.flags, [
|
|
128
|
+
'format',
|
|
129
|
+
'issue-id',
|
|
130
|
+
'workspace-id',
|
|
131
|
+
'team-id',
|
|
132
|
+
'project-id',
|
|
133
|
+
'state',
|
|
134
|
+
'expected-state',
|
|
135
|
+
'expected-state-type',
|
|
136
|
+
'expected-updated-at',
|
|
137
|
+
'force',
|
|
138
|
+
'force-reason'
|
|
139
|
+
]);
|
|
140
|
+
const result = await dependencies.transitionProviderLinearIssueState({
|
|
141
|
+
issueId: requireFlag(params.flags, 'issue-id'),
|
|
142
|
+
stateName: requireFlag(params.flags, 'state'),
|
|
143
|
+
expectedStateName: readStringFlag(params.flags, 'expected-state') ?? null,
|
|
144
|
+
expectedStateType: readStringFlag(params.flags, 'expected-state-type') ?? null,
|
|
145
|
+
expectedUpdatedAt: readStringFlag(params.flags, 'expected-updated-at') ?? null,
|
|
146
|
+
force: readBooleanFlag(params.flags, 'force'),
|
|
147
|
+
forceReason: readRawStringFlag(params.flags, 'force-reason'),
|
|
148
|
+
sourceSetup: readSourceSetup(params.flags),
|
|
149
|
+
env
|
|
150
|
+
});
|
|
151
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
152
|
+
emitJsonResult(result, dependencies);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
case 'attach-pr': {
|
|
156
|
+
assertAllowedFlags(params.flags, ['format', 'issue-id', 'workspace-id', 'team-id', 'project-id', 'url', 'title']);
|
|
157
|
+
const result = await dependencies.attachProviderLinearIssuePr({
|
|
158
|
+
issueId: requireFlag(params.flags, 'issue-id'),
|
|
159
|
+
url: requireFlag(params.flags, 'url'),
|
|
160
|
+
title: readStringFlag(params.flags, 'title') ?? null,
|
|
161
|
+
sourceSetup: readSourceSetup(params.flags),
|
|
162
|
+
env
|
|
163
|
+
});
|
|
164
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
165
|
+
emitJsonResult(result, dependencies);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
case 'parallelization': {
|
|
169
|
+
assertAllowedFlags(params.flags, [
|
|
170
|
+
'format',
|
|
171
|
+
'issue-id',
|
|
172
|
+
'workspace-id',
|
|
173
|
+
'team-id',
|
|
174
|
+
'project-id',
|
|
175
|
+
'decision',
|
|
176
|
+
'reason',
|
|
177
|
+
'summary'
|
|
178
|
+
]);
|
|
179
|
+
const issueId = requireFlag(params.flags, 'issue-id');
|
|
180
|
+
const decision = requireParallelizationDecision(params.flags);
|
|
181
|
+
const reason = requireParallelizationReason(params.flags, decision);
|
|
182
|
+
const summary = requireParallelizationSummary(params.flags, decision, reason);
|
|
183
|
+
const proofRefreshContext = await resolveParallelizationProofRefreshContext(issueId, env, dependencies);
|
|
184
|
+
const result = {
|
|
185
|
+
ok: true,
|
|
186
|
+
operation: 'parallelization',
|
|
187
|
+
issue_id: issueId,
|
|
188
|
+
issue_identifier: proofRefreshContext?.issueIdentifier ?? null,
|
|
189
|
+
source_setup: resolveAuditSourceSetup(params.flags, env),
|
|
190
|
+
decision,
|
|
191
|
+
reason,
|
|
192
|
+
summary
|
|
193
|
+
};
|
|
194
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
195
|
+
await refreshParallelizationProofSnapshotBestEffort(result, proofRefreshContext, env, dependencies);
|
|
196
|
+
emitJsonResult(result, dependencies);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
case 'create-follow-up': {
|
|
200
|
+
assertAllowedFlags(params.flags, [
|
|
201
|
+
'format',
|
|
202
|
+
'issue-id',
|
|
203
|
+
'workspace-id',
|
|
204
|
+
'team-id',
|
|
205
|
+
'project-id',
|
|
206
|
+
'title',
|
|
207
|
+
'description',
|
|
208
|
+
'description-file',
|
|
209
|
+
'intent-checksum',
|
|
210
|
+
'intent-checksum-file',
|
|
211
|
+
'non-goals',
|
|
212
|
+
'non-goals-file',
|
|
213
|
+
'not-done-if',
|
|
214
|
+
'not-done-if-file',
|
|
215
|
+
'acceptance-criteria',
|
|
216
|
+
'acceptance-criteria-file',
|
|
217
|
+
'parity-lane',
|
|
218
|
+
'parity-matrix',
|
|
219
|
+
'parity-matrix-file',
|
|
220
|
+
'canonical-owner-key',
|
|
221
|
+
'canonical-owner-key-file',
|
|
222
|
+
'blocked-by-source'
|
|
223
|
+
]);
|
|
224
|
+
const description = await resolveRequiredText(params.flags, dependencies.readTextFile, 'description', 'description-file');
|
|
225
|
+
const intentChecksum = await resolveRequiredText(params.flags, dependencies.readTextFile, 'intent-checksum', 'intent-checksum-file');
|
|
226
|
+
const nonGoals = await resolveRequiredText(params.flags, dependencies.readTextFile, 'non-goals', 'non-goals-file');
|
|
227
|
+
const notDoneIf = await resolveRequiredText(params.flags, dependencies.readTextFile, 'not-done-if', 'not-done-if-file');
|
|
228
|
+
const acceptanceCriteria = await resolveRequiredText(params.flags, dependencies.readTextFile, 'acceptance-criteria', 'acceptance-criteria-file');
|
|
229
|
+
const parityLane = readBooleanFlag(params.flags, 'parity-lane');
|
|
230
|
+
const parityMatrix = await resolveOptionalText(params.flags, dependencies.readTextFile, 'parity-matrix', 'parity-matrix-file');
|
|
231
|
+
const retrySuppressed = await resolveCreateFollowUpRetrySuppression({
|
|
232
|
+
issueId: requireFlag(params.flags, 'issue-id'),
|
|
233
|
+
parityLane,
|
|
234
|
+
parityMatrix,
|
|
235
|
+
env,
|
|
236
|
+
dependencies
|
|
237
|
+
});
|
|
238
|
+
if (retrySuppressed) {
|
|
239
|
+
await recordAuditResult(retrySuppressed, params.flags, env, dependencies);
|
|
240
|
+
emitJsonResult(retrySuppressed, dependencies);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const result = await dependencies.createProviderLinearFollowUpIssue({
|
|
244
|
+
issueId: requireFlag(params.flags, 'issue-id'),
|
|
245
|
+
title: requireFlag(params.flags, 'title'),
|
|
246
|
+
description,
|
|
247
|
+
intentChecksum,
|
|
248
|
+
nonGoals,
|
|
249
|
+
notDoneIf,
|
|
250
|
+
acceptanceCriteria,
|
|
251
|
+
parityLane,
|
|
252
|
+
parityMatrix,
|
|
253
|
+
canonicalOwnerKey: await resolveOptionalText(params.flags, dependencies.readTextFile, 'canonical-owner-key', 'canonical-owner-key-file'),
|
|
254
|
+
blockedBySource: readBooleanFlag(params.flags, 'blocked-by-source'),
|
|
255
|
+
sourceSetup: readSourceSetup(params.flags),
|
|
256
|
+
env
|
|
257
|
+
});
|
|
258
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
259
|
+
emitJsonResult(result, dependencies);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
case 'runtime-proof': {
|
|
263
|
+
assertAllowedFlags(params.flags, [
|
|
264
|
+
'format',
|
|
265
|
+
'issue-id',
|
|
266
|
+
'workspace-id',
|
|
267
|
+
'team-id',
|
|
268
|
+
'project-id',
|
|
269
|
+
'origin',
|
|
270
|
+
'kind',
|
|
271
|
+
'proof-url',
|
|
272
|
+
'title',
|
|
273
|
+
'summary',
|
|
274
|
+
'reachability-mode'
|
|
275
|
+
]);
|
|
276
|
+
const issueId = requireFlag(params.flags, 'issue-id');
|
|
277
|
+
const sourceSetup = resolveAuditSourceSetup(params.flags, env);
|
|
278
|
+
const resolved = await dependencies.resolveProviderLinearRuntimeProof({
|
|
279
|
+
repoRoot: resolveRuntimeProofRepoRoot(dependencies.getCwd(), env),
|
|
280
|
+
origin: requireFlag(params.flags, 'origin'),
|
|
281
|
+
kind: readStringFlag(params.flags, 'kind') ?? null,
|
|
282
|
+
proofUrl: readStringFlag(params.flags, 'proof-url') ?? null,
|
|
283
|
+
title: readRawStringFlag(params.flags, 'title'),
|
|
284
|
+
summary: readRawStringFlag(params.flags, 'summary'),
|
|
285
|
+
reachabilityMode: readStringFlag(params.flags, 'reachability-mode') ?? null
|
|
286
|
+
});
|
|
287
|
+
const result = resolved.ok
|
|
288
|
+
? {
|
|
289
|
+
ok: true,
|
|
290
|
+
operation: 'runtime-proof',
|
|
291
|
+
issue_id: issueId,
|
|
292
|
+
source_setup: sourceSetup,
|
|
293
|
+
policy: resolved.policy,
|
|
294
|
+
proof: resolved.proof,
|
|
295
|
+
handoff: resolved.handoff,
|
|
296
|
+
reachability: resolved.reachability
|
|
297
|
+
}
|
|
298
|
+
: {
|
|
299
|
+
ok: false,
|
|
300
|
+
operation: 'runtime-proof',
|
|
301
|
+
issue_id: issueId,
|
|
302
|
+
source_setup: sourceSetup,
|
|
303
|
+
policy: resolved.policy,
|
|
304
|
+
error: resolved.error
|
|
305
|
+
};
|
|
306
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
307
|
+
emitJsonResult(result, dependencies);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
case 'screenshot-proof': {
|
|
311
|
+
assertAllowedFlags(params.flags, [
|
|
312
|
+
'format',
|
|
313
|
+
'issue-id',
|
|
314
|
+
'workspace-id',
|
|
315
|
+
'team-id',
|
|
316
|
+
'project-id',
|
|
317
|
+
'output',
|
|
318
|
+
'display-id',
|
|
319
|
+
'window-id',
|
|
320
|
+
'open-preview'
|
|
321
|
+
]);
|
|
322
|
+
const issueId = requireFlag(params.flags, 'issue-id');
|
|
323
|
+
const sourceSetup = resolveAuditSourceSetup(params.flags, env);
|
|
324
|
+
const resolved = await dependencies.resolveProviderLinearScreenshotProof({
|
|
325
|
+
cwd: dependencies.getCwd(),
|
|
326
|
+
outputPath: readRawStringFlag(params.flags, 'output') ?? null,
|
|
327
|
+
displayId: readStringFlag(params.flags, 'display-id') ?? null,
|
|
328
|
+
windowId: readStringFlag(params.flags, 'window-id') ?? null,
|
|
329
|
+
openPreview: readBooleanFlag(params.flags, 'open-preview')
|
|
330
|
+
});
|
|
331
|
+
const result = resolved.ok
|
|
332
|
+
? {
|
|
333
|
+
ok: true,
|
|
334
|
+
operation: 'screenshot-proof',
|
|
335
|
+
issue_id: issueId,
|
|
336
|
+
source_setup: sourceSetup,
|
|
337
|
+
capture: resolved.capture
|
|
338
|
+
}
|
|
339
|
+
: {
|
|
340
|
+
ok: false,
|
|
341
|
+
operation: 'screenshot-proof',
|
|
342
|
+
issue_id: issueId,
|
|
343
|
+
source_setup: sourceSetup,
|
|
344
|
+
capture: resolved.capture,
|
|
345
|
+
error: resolved.error
|
|
346
|
+
};
|
|
347
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
348
|
+
emitJsonResult(result, dependencies);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
case 'child-stream': {
|
|
352
|
+
assertAllowedFlags(params.flags, ['format', 'pipeline', 'stream']);
|
|
353
|
+
const result = await dependencies.runProviderLinearChildStreamShell({
|
|
354
|
+
pipelineId: requireFlag(params.flags, 'pipeline'),
|
|
355
|
+
streamName: readStringFlag(params.flags, 'stream') ?? null,
|
|
356
|
+
env
|
|
357
|
+
});
|
|
358
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
359
|
+
emitJsonResult(result, dependencies);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
case 'child-lane': {
|
|
363
|
+
assertAllowedFlags(params.flags, [
|
|
364
|
+
'format',
|
|
365
|
+
'action',
|
|
366
|
+
'stream',
|
|
367
|
+
'purpose',
|
|
368
|
+
'files',
|
|
369
|
+
'phases',
|
|
370
|
+
'instructions',
|
|
371
|
+
'instructions-file',
|
|
372
|
+
'reason'
|
|
373
|
+
]);
|
|
374
|
+
const result = await dependencies.runProviderLinearChildLaneShell({
|
|
375
|
+
action: requireFlag(params.flags, 'action'),
|
|
376
|
+
streamName: readStringFlag(params.flags, 'stream') ?? null,
|
|
377
|
+
purpose: readRawStringFlag(params.flags, 'purpose') ?? null,
|
|
378
|
+
files: readCommaSeparatedFlag(params.flags, 'files'),
|
|
379
|
+
phases: readCommaSeparatedFlag(params.flags, 'phases'),
|
|
380
|
+
instructions: await resolveOptionalText(params.flags, dependencies.readTextFile, 'instructions', 'instructions-file'),
|
|
381
|
+
reason: readRawStringFlag(params.flags, 'reason') ?? null,
|
|
382
|
+
env
|
|
383
|
+
});
|
|
384
|
+
await recordAuditResult(result, params.flags, env, dependencies);
|
|
385
|
+
emitJsonResult(result, dependencies);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
default:
|
|
389
|
+
throw usageError('linear_unknown_subcommand', `Unknown linear subcommand: ${subcommand}`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
emitJsonResult(isLinearCliUsageError(error) ? error.result : failureResult('linear_cli_error', resolveErrorMessage(error), 500), dependencies);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async function resolveParallelizationProofRefreshContext(issueId, env, dependencies) {
|
|
397
|
+
try {
|
|
398
|
+
const context = await dependencies.loadProviderLinearWorkerContext(env);
|
|
399
|
+
if (context.pipelineId !== 'provider-linear-worker' || context.issueId !== issueId) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
runDir: context.runDir,
|
|
404
|
+
issueId: context.issueId,
|
|
405
|
+
issueIdentifier: context.issueIdentifier
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
async function resolveProviderLinearWorkerAttemptStartedAtForIssue(issueId, env, dependencies) {
|
|
413
|
+
const context = await resolveParallelizationProofRefreshContext(issueId, env, dependencies);
|
|
414
|
+
if (!context) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
const raw = await dependencies.readTextFile(join(context.runDir, PROVIDER_LINEAR_WORKER_PROOF_FILENAME));
|
|
419
|
+
const parsed = JSON.parse(raw);
|
|
420
|
+
return resolveProviderLinearWorkerAttemptStartedAt(parsed);
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async function resolveCreateFollowUpRetrySuppression(input) {
|
|
427
|
+
if (!input.parityLane || (input.parityMatrix?.trim().length ?? 0) > 0) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
const auditPath = resolveProviderLinearAuditPath(input.env);
|
|
431
|
+
if (!auditPath) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
const attemptStartedAt = await resolveProviderLinearWorkerAttemptStartedAtForIssue(input.issueId, input.env, input.dependencies);
|
|
435
|
+
if (!attemptStartedAt) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
let audit = null;
|
|
439
|
+
try {
|
|
440
|
+
audit = await summarizeProviderLinearAuditPath(auditPath);
|
|
441
|
+
}
|
|
442
|
+
catch (error) {
|
|
443
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
444
|
+
input.dependencies.warn(`linear create-follow-up warning: failed to summarize provider-linear audit at ${auditPath}; proceeding without retry suppression. error=${message}`);
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
const suppression = findDeterministicProviderMutationSuppression(audit, 'create-follow-up', {
|
|
448
|
+
recordedAtNotBefore: attemptStartedAt,
|
|
449
|
+
issueId: input.issueId
|
|
450
|
+
});
|
|
451
|
+
if (!suppression || !isFollowUpParityMatrixSuppressionCode(suppression.error_code)) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
ok: false,
|
|
456
|
+
operation: 'create-follow-up',
|
|
457
|
+
error: {
|
|
458
|
+
code: 'linear_follow_up_parity_matrix_retry_suppressed',
|
|
459
|
+
message: `Same-attempt retry suppressed: ${suppression.instruction}`,
|
|
460
|
+
status: 409
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
async function refreshParallelizationProofSnapshotBestEffort(result, context, env, dependencies) {
|
|
465
|
+
if (!result.ok || !context) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const auditPath = resolveProviderLinearAuditPath(env);
|
|
469
|
+
try {
|
|
470
|
+
await dependencies.refreshProviderLinearWorkerProofSnapshot(context.runDir, auditPath, undefined, undefined, env);
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
474
|
+
dependencies.warn(`linear parallelization warning: failed to refresh provider-linear-worker proof snapshot for ${context.issueIdentifier}: ${message}`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function emitJsonResult(result, dependencies) {
|
|
478
|
+
dependencies.log(JSON.stringify(result, null, 2));
|
|
479
|
+
if (!result.ok) {
|
|
480
|
+
dependencies.setExitCode(1);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
function assertAllowedFlags(flags, allowed) {
|
|
484
|
+
const allowedSet = new Set([...allowed, 'help', '--help', 'h']);
|
|
485
|
+
for (const key of Object.keys(flags)) {
|
|
486
|
+
if (!allowedSet.has(key)) {
|
|
487
|
+
throw usageError('linear_unknown_flag', `Unknown linear flag: --${key}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
const format = flags['format'];
|
|
491
|
+
if (format !== undefined && format !== 'json') {
|
|
492
|
+
throw usageError('linear_format_unsupported', 'linear only supports --format json.');
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function requireFlag(flags, key) {
|
|
496
|
+
const value = readStringFlag(flags, key);
|
|
497
|
+
if (!value) {
|
|
498
|
+
throw usageError('linear_missing_flag', `--${key} is required.`);
|
|
499
|
+
}
|
|
500
|
+
return value;
|
|
501
|
+
}
|
|
502
|
+
function readRawStringFlag(flags, key) {
|
|
503
|
+
const value = flags[key];
|
|
504
|
+
return typeof value === 'string' ? value : undefined;
|
|
505
|
+
}
|
|
506
|
+
function readStringFlag(flags, key) {
|
|
507
|
+
const value = flags[key];
|
|
508
|
+
if (typeof value !== 'string') {
|
|
509
|
+
return undefined;
|
|
510
|
+
}
|
|
511
|
+
const trimmed = value.trim();
|
|
512
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
513
|
+
}
|
|
514
|
+
function readBooleanFlag(flags, key) {
|
|
515
|
+
const value = flags[key];
|
|
516
|
+
if (typeof value === 'boolean') {
|
|
517
|
+
return value;
|
|
518
|
+
}
|
|
519
|
+
if (typeof value !== 'string') {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
const normalized = value.trim().toLowerCase();
|
|
523
|
+
return ['1', 'true', 'yes', 'on'].includes(normalized);
|
|
524
|
+
}
|
|
525
|
+
function requireParallelizationDecision(flags) {
|
|
526
|
+
const decision = readStringFlag(flags, 'decision');
|
|
527
|
+
if (!isProviderLinearParallelizationDecision(decision)) {
|
|
528
|
+
throw usageError('linear_parallelization_decision_invalid', 'linear parallelization requires --decision parallelize_now|stay_serial|forbid_parallel.');
|
|
529
|
+
}
|
|
530
|
+
return decision;
|
|
531
|
+
}
|
|
532
|
+
function requireParallelizationReason(flags, decision) {
|
|
533
|
+
const reason = readStringFlag(flags, 'reason');
|
|
534
|
+
if (!isProviderLinearParallelizationReason(reason)) {
|
|
535
|
+
throw usageError('linear_parallelization_reason_invalid', 'linear parallelization requires a recognized --reason code.');
|
|
536
|
+
}
|
|
537
|
+
if (!isProviderLinearParallelizationReasonAllowed(decision, reason)) {
|
|
538
|
+
throw usageError('linear_parallelization_reason_mismatch', `linear parallelization reason ${reason} is not allowed for decision ${decision}.`);
|
|
539
|
+
}
|
|
540
|
+
return reason;
|
|
541
|
+
}
|
|
542
|
+
function requireParallelizationSummary(flags, decision, reason) {
|
|
543
|
+
const summary = readStringFlag(flags, 'summary');
|
|
544
|
+
if (!summary) {
|
|
545
|
+
throw usageError('linear_parallelization_summary_missing', 'linear parallelization requires --summary with matrix/cap evidence for the decision.');
|
|
546
|
+
}
|
|
547
|
+
if (decision === 'stay_serial' && reason === 'single_bounded_change') {
|
|
548
|
+
const missingSlices = ['docs', 'test', 'research', 'review'].filter((slice) => !new RegExp(`(?:^|;)\\s*${slice}\\s*:\\s*[^;\\s][^;]*`, 'i').test(summary));
|
|
549
|
+
if (missingSlices.length > 0) {
|
|
550
|
+
throw usageError('linear_parallelization_single_bounded_change_summary_incomplete', `linear parallelization single_bounded_change summaries must explain why no docs/test/research/review slice can be separated safely with labeled slice evidence; missing: ${missingSlices.join(', ')}.`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (decision === 'stay_serial' &&
|
|
554
|
+
reason === 'existing_child_lane_active' &&
|
|
555
|
+
!/(?:^|;)\s*cap_exhausted\s*:\s*[^;\s][^;]*/iu.test(summary)) {
|
|
556
|
+
throw usageError('linear_parallelization_cap_exhausted_summary_missing', 'linear parallelization existing_child_lane_active summaries must include labeled cap_exhausted evidence, for example `cap_exhausted: 2/2 active child lanes`.');
|
|
557
|
+
}
|
|
558
|
+
return summary;
|
|
559
|
+
}
|
|
560
|
+
function readCommaSeparatedFlag(flags, key) {
|
|
561
|
+
const value = readRawStringFlag(flags, key);
|
|
562
|
+
if (!value) {
|
|
563
|
+
return [];
|
|
564
|
+
}
|
|
565
|
+
return value
|
|
566
|
+
.split(',')
|
|
567
|
+
.map((entry) => entry.trim())
|
|
568
|
+
.filter((entry) => entry.length > 0);
|
|
569
|
+
}
|
|
570
|
+
function readSourceSetup(flags) {
|
|
571
|
+
const workspaceId = readStringFlag(flags, 'workspace-id') ?? null;
|
|
572
|
+
const teamId = readStringFlag(flags, 'team-id') ?? null;
|
|
573
|
+
const projectId = readStringFlag(flags, 'project-id') ?? null;
|
|
574
|
+
if (!workspaceId && !teamId && !projectId) {
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
provider: 'linear',
|
|
579
|
+
workspace_id: workspaceId,
|
|
580
|
+
team_id: teamId,
|
|
581
|
+
project_id: projectId
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
async function resolveBodyInput(flags, readTextFile, cwd) {
|
|
585
|
+
const inlineValue = readRawStringFlag(flags, 'body');
|
|
586
|
+
const fileValue = readStringFlag(flags, 'body-file');
|
|
587
|
+
const hasInlineValue = typeof inlineValue === 'string' && inlineValue.trim().length > 0;
|
|
588
|
+
if (hasInlineValue && fileValue) {
|
|
589
|
+
throw usageError('linear_body_conflict', 'Use either --body or --body-file, not both.');
|
|
590
|
+
}
|
|
591
|
+
if (hasInlineValue) {
|
|
592
|
+
return {
|
|
593
|
+
text: inlineValue,
|
|
594
|
+
filePath: null
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
if (!fileValue) {
|
|
598
|
+
throw usageError('linear_body_missing', '--body or --body-file is required.');
|
|
599
|
+
}
|
|
600
|
+
const resolvedFilePath = resolveInputFilePath(fileValue, cwd);
|
|
601
|
+
let fileText;
|
|
602
|
+
try {
|
|
603
|
+
fileText = await readTextFile(resolvedFilePath);
|
|
604
|
+
}
|
|
605
|
+
catch {
|
|
606
|
+
throw usageError('linear_body_file_unreadable', '--body-file must reference a readable file.');
|
|
607
|
+
}
|
|
608
|
+
if (fileText.trim().length === 0) {
|
|
609
|
+
throw usageError('linear_body_missing', '--body or --body-file is required.');
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
text: fileText,
|
|
613
|
+
filePath: resolvedFilePath
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
function resolveInputFilePath(filePath, cwd) {
|
|
617
|
+
return isAbsolute(filePath) ? filePath : resolve(cwd, filePath);
|
|
618
|
+
}
|
|
619
|
+
async function resolveOptionalText(flags, readTextFile, inlineFlag, fileFlag) {
|
|
620
|
+
const inlineValue = readRawStringFlag(flags, inlineFlag);
|
|
621
|
+
const fileValue = readStringFlag(flags, fileFlag);
|
|
622
|
+
const hasInlineValue = typeof inlineValue === 'string' && inlineValue.trim().length > 0;
|
|
623
|
+
if (hasInlineValue && fileValue) {
|
|
624
|
+
throw usageError(`linear_${inlineFlag.replace(/-/gu, '_')}_conflict`, `Use either --${inlineFlag} or --${fileFlag}, not both.`);
|
|
625
|
+
}
|
|
626
|
+
if (hasInlineValue) {
|
|
627
|
+
return inlineValue;
|
|
628
|
+
}
|
|
629
|
+
if (!fileValue) {
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
let fileText;
|
|
633
|
+
try {
|
|
634
|
+
fileText = await readTextFile(fileValue);
|
|
635
|
+
}
|
|
636
|
+
catch {
|
|
637
|
+
throw usageError(`linear_${fileFlag.replace(/-/gu, '_')}_unreadable`, `--${fileFlag} must reference a readable file.`);
|
|
638
|
+
}
|
|
639
|
+
return fileText.trim().length > 0 ? fileText : null;
|
|
640
|
+
}
|
|
641
|
+
async function resolveRequiredText(flags, readTextFile, inlineFlag, fileFlag) {
|
|
642
|
+
const inlineValue = readRawStringFlag(flags, inlineFlag);
|
|
643
|
+
const fileValue = readStringFlag(flags, fileFlag);
|
|
644
|
+
const hasInlineValue = typeof inlineValue === 'string' && inlineValue.trim().length > 0;
|
|
645
|
+
if (hasInlineValue && fileValue) {
|
|
646
|
+
throw usageError(`linear_${inlineFlag.replace(/-/gu, '_')}_conflict`, `Use either --${inlineFlag} or --${fileFlag}, not both.`);
|
|
647
|
+
}
|
|
648
|
+
if (hasInlineValue) {
|
|
649
|
+
return inlineValue;
|
|
650
|
+
}
|
|
651
|
+
if (fileValue) {
|
|
652
|
+
let fileText;
|
|
653
|
+
try {
|
|
654
|
+
fileText = await readTextFile(fileValue);
|
|
655
|
+
}
|
|
656
|
+
catch {
|
|
657
|
+
throw usageError(`linear_${fileFlag.replace(/-/gu, '_')}_unreadable`, `--${fileFlag} must reference a readable file.`);
|
|
658
|
+
}
|
|
659
|
+
if (fileText.trim().length === 0) {
|
|
660
|
+
throw usageError(`linear_${inlineFlag.replace(/-/gu, '_')}_missing`, `--${inlineFlag} or --${fileFlag} is required.`);
|
|
661
|
+
}
|
|
662
|
+
return fileText;
|
|
663
|
+
}
|
|
664
|
+
throw usageError(`linear_${inlineFlag.replace(/-/gu, '_')}_missing`, `--${inlineFlag} or --${fileFlag} is required.`);
|
|
665
|
+
}
|
|
666
|
+
function usageError(code, message) {
|
|
667
|
+
return cliError(code, message, 422);
|
|
668
|
+
}
|
|
669
|
+
function cliError(code, message, status) {
|
|
670
|
+
const error = new Error(message);
|
|
671
|
+
error.result = failureResult(code, message, status);
|
|
672
|
+
return error;
|
|
673
|
+
}
|
|
674
|
+
function isLinearCliUsageError(error) {
|
|
675
|
+
return (error instanceof Error
|
|
676
|
+
&& typeof error.result?.error?.code === 'string'
|
|
677
|
+
&& typeof error.result?.error?.message === 'string'
|
|
678
|
+
&& typeof error.result?.error?.status === 'number');
|
|
679
|
+
}
|
|
680
|
+
function failureResult(code, message, status) {
|
|
681
|
+
return {
|
|
682
|
+
ok: false,
|
|
683
|
+
error: {
|
|
684
|
+
code,
|
|
685
|
+
message,
|
|
686
|
+
status
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
async function assertLinearMutationAllowed(subcommand, flags, env, readTextFile) {
|
|
691
|
+
if (!LINEAR_MUTATING_SUBCOMMANDS.has(subcommand)) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const pipelineIdFromEnv = readStringEnv(env, 'CODEX_ORCHESTRATOR_PIPELINE_ID');
|
|
695
|
+
const isChildLane = pipelineIdFromEnv === 'provider-linear-child-lane';
|
|
696
|
+
const manifestPath = readStringEnv(env, 'CODEX_ORCHESTRATOR_MANIFEST_PATH');
|
|
697
|
+
if (!manifestPath) {
|
|
698
|
+
if (isChildLane) {
|
|
699
|
+
throw cliError('provider_worker_parent_mutation_required', `${subcommand} is only available to the parent provider-linear-worker; subordinate same-issue child lanes are read-only for Linear mutations.`, 409);
|
|
700
|
+
}
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
let manifestRecord;
|
|
704
|
+
try {
|
|
705
|
+
manifestRecord = JSON.parse(await readTextFile(manifestPath));
|
|
706
|
+
}
|
|
707
|
+
catch {
|
|
708
|
+
if (isChildLane) {
|
|
709
|
+
throw cliError('provider_worker_parent_mutation_required', `${subcommand} is only available to the parent provider-linear-worker; subordinate same-issue child lanes are read-only for Linear mutations.`, 409);
|
|
710
|
+
}
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
const pipelineId = readUnknownString(manifestRecord.pipeline_id) ?? readUnknownString(manifestRecord.pipelineId);
|
|
714
|
+
const parentRunId = readUnknownString(manifestRecord.parent_run_id) ?? readUnknownString(manifestRecord.parentRunId);
|
|
715
|
+
if (pipelineId !== 'provider-linear-child-lane' || !parentRunId) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
throw cliError('provider_worker_parent_mutation_required', `${subcommand} is only available to the parent provider-linear-worker; subordinate same-issue child lanes are read-only for Linear mutations.`, 409);
|
|
719
|
+
}
|
|
720
|
+
function resolveErrorMessage(error) {
|
|
721
|
+
return error instanceof Error ? error.message : String(error);
|
|
722
|
+
}
|
|
723
|
+
function readStringEnv(env, key) {
|
|
724
|
+
const value = env[key];
|
|
725
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
|
|
726
|
+
}
|
|
727
|
+
async function recordAuditResult(result, flags, env, dependencies) {
|
|
728
|
+
const auditPath = resolveProviderLinearAuditPath(env);
|
|
729
|
+
if (!auditPath) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
try {
|
|
733
|
+
await dependencies.appendAuditEntry(auditPath, buildAuditEntry(result, flags, env, dependencies.now()));
|
|
734
|
+
}
|
|
735
|
+
catch (error) {
|
|
736
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
737
|
+
dependencies.warn(`linear audit warning: failed to append audit entry to ${auditPath}: ${message}`);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
function buildAuditEntry(result, flags, env, recordedAt) {
|
|
741
|
+
const requestedIssueId = readStringFlag(flags, 'issue-id') ?? null;
|
|
742
|
+
const sourceSetup = resolveAuditSourceSetup(flags, env);
|
|
743
|
+
const followUpAuditFields = resolveFollowUpAuditFields(result);
|
|
744
|
+
if (!result.ok) {
|
|
745
|
+
if (result.operation === 'child-stream') {
|
|
746
|
+
return {
|
|
747
|
+
recorded_at: recordedAt,
|
|
748
|
+
operation: result.operation,
|
|
749
|
+
ok: false,
|
|
750
|
+
issue_id: result.issue_id ?? requestedIssueId,
|
|
751
|
+
issue_identifier: result.issue_identifier,
|
|
752
|
+
source_setup: result.source_setup ?? sourceSetup,
|
|
753
|
+
action: result.stream ? `stream:${result.stream}` : null,
|
|
754
|
+
via: result.pipeline_id ? `pipeline:${result.pipeline_id}` : null,
|
|
755
|
+
state: result.child_run?.status ?? null,
|
|
756
|
+
follow_up_issue_id: null,
|
|
757
|
+
follow_up_issue_identifier: null,
|
|
758
|
+
failed_relation_type: null,
|
|
759
|
+
comment_id: null,
|
|
760
|
+
attachment_id: null,
|
|
761
|
+
error_code: result.error.code,
|
|
762
|
+
error_message: result.error.message
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
if (result.operation === 'child-lane') {
|
|
766
|
+
return {
|
|
767
|
+
recorded_at: recordedAt,
|
|
768
|
+
operation: result.operation,
|
|
769
|
+
ok: false,
|
|
770
|
+
issue_id: result.issue_id ?? requestedIssueId,
|
|
771
|
+
issue_identifier: result.issue_identifier,
|
|
772
|
+
source_setup: result.source_setup ?? sourceSetup,
|
|
773
|
+
action: result.stream ? `${result.action}:${result.stream}` : result.action,
|
|
774
|
+
via: result.child_lane ? `pipeline:${result.child_lane.pipeline_id}` : null,
|
|
775
|
+
state: result.child_lane?.decision ?? result.child_run?.status ?? null,
|
|
776
|
+
follow_up_issue_id: null,
|
|
777
|
+
follow_up_issue_identifier: null,
|
|
778
|
+
failed_relation_type: null,
|
|
779
|
+
comment_id: null,
|
|
780
|
+
attachment_id: null,
|
|
781
|
+
error_code: result.error.code,
|
|
782
|
+
error_message: result.error.message
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
if (result.operation === 'screenshot-proof') {
|
|
786
|
+
return {
|
|
787
|
+
recorded_at: recordedAt,
|
|
788
|
+
operation: result.operation,
|
|
789
|
+
ok: false,
|
|
790
|
+
issue_id: result.issue_id ?? requestedIssueId,
|
|
791
|
+
issue_identifier: null,
|
|
792
|
+
source_setup: result.source_setup ?? sourceSetup,
|
|
793
|
+
action: result.capture?.mode ?? null,
|
|
794
|
+
via: result.capture ? `cleanup:${result.capture.cleanup.status}` : null,
|
|
795
|
+
state: null,
|
|
796
|
+
follow_up_issue_id: null,
|
|
797
|
+
follow_up_issue_identifier: null,
|
|
798
|
+
failed_relation_type: null,
|
|
799
|
+
comment_id: null,
|
|
800
|
+
attachment_id: null,
|
|
801
|
+
error_code: result.error.code,
|
|
802
|
+
error_message: result.error.message
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
return {
|
|
806
|
+
recorded_at: recordedAt,
|
|
807
|
+
operation: result.operation,
|
|
808
|
+
ok: false,
|
|
809
|
+
issue_id: requestedIssueId,
|
|
810
|
+
issue_identifier: null,
|
|
811
|
+
source_setup: sourceSetup,
|
|
812
|
+
action: null,
|
|
813
|
+
via: null,
|
|
814
|
+
state: null,
|
|
815
|
+
...followUpAuditFields,
|
|
816
|
+
comment_id: null,
|
|
817
|
+
attachment_id: null,
|
|
818
|
+
...resolveTransitionAuditFieldsFromFailure(result, resolveRequestedTransitionAuditFields(flags)),
|
|
819
|
+
error_code: result.error.code,
|
|
820
|
+
error_message: result.error.message
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
switch (result.operation) {
|
|
824
|
+
case 'issue-context':
|
|
825
|
+
return {
|
|
826
|
+
recorded_at: recordedAt,
|
|
827
|
+
operation: result.operation,
|
|
828
|
+
ok: true,
|
|
829
|
+
issue_id: result.issue.id,
|
|
830
|
+
issue_identifier: result.issue.identifier,
|
|
831
|
+
source_setup: result.source_setup,
|
|
832
|
+
action: null,
|
|
833
|
+
via: null,
|
|
834
|
+
state: result.issue.state?.name ?? null,
|
|
835
|
+
...followUpAuditFields,
|
|
836
|
+
comment_id: result.issue.workpad_comment?.id ?? null,
|
|
837
|
+
attachment_id: null,
|
|
838
|
+
error_code: null,
|
|
839
|
+
error_message: null
|
|
840
|
+
};
|
|
841
|
+
case 'upsert-workpad':
|
|
842
|
+
return {
|
|
843
|
+
recorded_at: recordedAt,
|
|
844
|
+
operation: result.operation,
|
|
845
|
+
ok: true,
|
|
846
|
+
issue_id: result.issue.id,
|
|
847
|
+
issue_identifier: result.issue.identifier,
|
|
848
|
+
source_setup: result.source_setup,
|
|
849
|
+
action: result.action,
|
|
850
|
+
via: null,
|
|
851
|
+
state: null,
|
|
852
|
+
...followUpAuditFields,
|
|
853
|
+
comment_id: result.comment.id,
|
|
854
|
+
attachment_id: null,
|
|
855
|
+
...(Array.isArray(result.embedded_assets) && result.embedded_assets.length > 0
|
|
856
|
+
? {
|
|
857
|
+
asset_urls: result.embedded_assets.map((entry) => entry.asset_url)
|
|
858
|
+
}
|
|
859
|
+
: {}),
|
|
860
|
+
error_code: null,
|
|
861
|
+
error_message: null
|
|
862
|
+
};
|
|
863
|
+
case 'delete-workpad':
|
|
864
|
+
return {
|
|
865
|
+
recorded_at: recordedAt,
|
|
866
|
+
operation: result.operation,
|
|
867
|
+
ok: true,
|
|
868
|
+
issue_id: result.issue.id,
|
|
869
|
+
issue_identifier: result.issue.identifier,
|
|
870
|
+
source_setup: result.source_setup,
|
|
871
|
+
action: result.action,
|
|
872
|
+
via: null,
|
|
873
|
+
state: null,
|
|
874
|
+
...followUpAuditFields,
|
|
875
|
+
comment_id: result.comment_id,
|
|
876
|
+
attachment_id: null,
|
|
877
|
+
error_code: null,
|
|
878
|
+
error_message: null
|
|
879
|
+
};
|
|
880
|
+
case 'transition':
|
|
881
|
+
return {
|
|
882
|
+
recorded_at: recordedAt,
|
|
883
|
+
operation: result.operation,
|
|
884
|
+
ok: true,
|
|
885
|
+
issue_id: result.issue.id,
|
|
886
|
+
issue_identifier: result.issue.identifier,
|
|
887
|
+
source_setup: result.source_setup,
|
|
888
|
+
action: result.action,
|
|
889
|
+
via: null,
|
|
890
|
+
state: result.issue.state?.name ?? result.target_state.name,
|
|
891
|
+
...followUpAuditFields,
|
|
892
|
+
comment_id: null,
|
|
893
|
+
attachment_id: null,
|
|
894
|
+
...resolveTransitionAuditFieldsFromSuccess(result),
|
|
895
|
+
error_code: null,
|
|
896
|
+
error_message: null
|
|
897
|
+
};
|
|
898
|
+
case 'attach-pr':
|
|
899
|
+
return {
|
|
900
|
+
recorded_at: recordedAt,
|
|
901
|
+
operation: result.operation,
|
|
902
|
+
ok: true,
|
|
903
|
+
issue_id: result.issue.id,
|
|
904
|
+
issue_identifier: result.issue.identifier,
|
|
905
|
+
source_setup: result.source_setup,
|
|
906
|
+
action: result.action,
|
|
907
|
+
via: result.via,
|
|
908
|
+
state: null,
|
|
909
|
+
...followUpAuditFields,
|
|
910
|
+
comment_id: null,
|
|
911
|
+
attachment_id: result.attachment.id,
|
|
912
|
+
error_code: null,
|
|
913
|
+
error_message: null
|
|
914
|
+
};
|
|
915
|
+
case 'parallelization':
|
|
916
|
+
return {
|
|
917
|
+
recorded_at: recordedAt,
|
|
918
|
+
operation: result.operation,
|
|
919
|
+
ok: true,
|
|
920
|
+
issue_id: result.issue_id,
|
|
921
|
+
issue_identifier: result.issue_identifier,
|
|
922
|
+
source_setup: result.source_setup,
|
|
923
|
+
action: result.decision,
|
|
924
|
+
via: result.summary,
|
|
925
|
+
state: result.reason,
|
|
926
|
+
...followUpAuditFields,
|
|
927
|
+
comment_id: null,
|
|
928
|
+
attachment_id: null,
|
|
929
|
+
error_code: null,
|
|
930
|
+
error_message: null
|
|
931
|
+
};
|
|
932
|
+
case 'create-follow-up':
|
|
933
|
+
return {
|
|
934
|
+
recorded_at: recordedAt,
|
|
935
|
+
operation: result.operation,
|
|
936
|
+
ok: true,
|
|
937
|
+
issue_id: result.issue.id,
|
|
938
|
+
issue_identifier: result.issue.identifier,
|
|
939
|
+
source_setup: result.source_setup,
|
|
940
|
+
action: result.action,
|
|
941
|
+
via: result.relations.blocked_by_source ? 'related+blocks' : 'related',
|
|
942
|
+
state: result.follow_up_issue.state?.name ?? null,
|
|
943
|
+
...followUpAuditFields,
|
|
944
|
+
comment_id: null,
|
|
945
|
+
attachment_id: null,
|
|
946
|
+
error_code: null,
|
|
947
|
+
error_message: null
|
|
948
|
+
};
|
|
949
|
+
case 'runtime-proof':
|
|
950
|
+
return {
|
|
951
|
+
recorded_at: recordedAt,
|
|
952
|
+
operation: result.operation,
|
|
953
|
+
ok: true,
|
|
954
|
+
issue_id: result.issue_id,
|
|
955
|
+
issue_identifier: null,
|
|
956
|
+
source_setup: result.source_setup,
|
|
957
|
+
action: result.proof?.kind ?? 'policy',
|
|
958
|
+
via: `permit:${result.policy.permit_status}`,
|
|
959
|
+
state: null,
|
|
960
|
+
...followUpAuditFields,
|
|
961
|
+
comment_id: null,
|
|
962
|
+
attachment_id: null,
|
|
963
|
+
error_code: null,
|
|
964
|
+
error_message: null
|
|
965
|
+
};
|
|
966
|
+
case 'screenshot-proof':
|
|
967
|
+
return {
|
|
968
|
+
recorded_at: recordedAt,
|
|
969
|
+
operation: result.operation,
|
|
970
|
+
ok: true,
|
|
971
|
+
issue_id: result.issue_id,
|
|
972
|
+
issue_identifier: null,
|
|
973
|
+
source_setup: result.source_setup,
|
|
974
|
+
action: result.capture.mode,
|
|
975
|
+
via: `cleanup:${result.capture.cleanup.status}`,
|
|
976
|
+
state: null,
|
|
977
|
+
...followUpAuditFields,
|
|
978
|
+
comment_id: null,
|
|
979
|
+
attachment_id: null,
|
|
980
|
+
error_code: null,
|
|
981
|
+
error_message: null
|
|
982
|
+
};
|
|
983
|
+
case 'child-stream':
|
|
984
|
+
return {
|
|
985
|
+
recorded_at: recordedAt,
|
|
986
|
+
operation: result.operation,
|
|
987
|
+
ok: true,
|
|
988
|
+
issue_id: result.issue.id,
|
|
989
|
+
issue_identifier: result.issue.identifier,
|
|
990
|
+
source_setup: result.source_setup,
|
|
991
|
+
action: `stream:${result.stream}`,
|
|
992
|
+
via: `pipeline:${result.pipeline_id}`,
|
|
993
|
+
state: result.child_run.status,
|
|
994
|
+
follow_up_issue_id: null,
|
|
995
|
+
follow_up_issue_identifier: null,
|
|
996
|
+
failed_relation_type: null,
|
|
997
|
+
comment_id: null,
|
|
998
|
+
attachment_id: null,
|
|
999
|
+
error_code: null,
|
|
1000
|
+
error_message: null
|
|
1001
|
+
};
|
|
1002
|
+
case 'child-lane':
|
|
1003
|
+
return {
|
|
1004
|
+
recorded_at: recordedAt,
|
|
1005
|
+
operation: result.operation,
|
|
1006
|
+
ok: true,
|
|
1007
|
+
issue_id: result.issue.id,
|
|
1008
|
+
issue_identifier: result.issue.identifier,
|
|
1009
|
+
source_setup: result.source_setup,
|
|
1010
|
+
action: `${result.action}:${result.stream}`,
|
|
1011
|
+
via: `pipeline:${result.child_lane.pipeline_id}`,
|
|
1012
|
+
state: result.child_lane.decision,
|
|
1013
|
+
follow_up_issue_id: null,
|
|
1014
|
+
follow_up_issue_identifier: null,
|
|
1015
|
+
failed_relation_type: null,
|
|
1016
|
+
comment_id: null,
|
|
1017
|
+
attachment_id: null,
|
|
1018
|
+
error_code: null,
|
|
1019
|
+
error_message: null
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
function resolveTransitionAuditFieldsFromSuccess(result) {
|
|
1024
|
+
return {
|
|
1025
|
+
previous_state: result.previous_state?.name ?? null,
|
|
1026
|
+
previous_state_type: result.previous_state?.type ?? null,
|
|
1027
|
+
target_state: result.target_state.name,
|
|
1028
|
+
target_state_type: result.target_state.type ?? null,
|
|
1029
|
+
issue_updated_at: result.issue.updated_at ?? null,
|
|
1030
|
+
expected_state: result.transition_guard?.expected_state ?? null,
|
|
1031
|
+
expected_state_type: result.transition_guard?.expected_state_type ?? null,
|
|
1032
|
+
expected_updated_at: result.transition_guard?.expected_updated_at ?? null,
|
|
1033
|
+
force: result.transition_guard?.force ?? null,
|
|
1034
|
+
force_reason: result.transition_guard?.force_reason ?? null
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
function resolveRequestedTransitionAuditFields(flags) {
|
|
1038
|
+
const hasForce = Object.prototype.hasOwnProperty.call(flags, 'force');
|
|
1039
|
+
return {
|
|
1040
|
+
expected_state: readStringFlag(flags, 'expected-state') ?? null,
|
|
1041
|
+
expected_state_type: readStringFlag(flags, 'expected-state-type') ?? null,
|
|
1042
|
+
expected_updated_at: readStringFlag(flags, 'expected-updated-at') ?? null,
|
|
1043
|
+
force: hasForce ? readBooleanFlag(flags, 'force') : null,
|
|
1044
|
+
force_reason: normalizeOptionalAuditString(readRawStringFlag(flags, 'force-reason'))
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
function resolveTransitionAuditFieldsFromFailure(result, fallbackGuardFields = {}) {
|
|
1048
|
+
if (result.operation !== 'transition') {
|
|
1049
|
+
return {};
|
|
1050
|
+
}
|
|
1051
|
+
const details = result.error.details && typeof result.error.details === 'object'
|
|
1052
|
+
? result.error.details
|
|
1053
|
+
: null;
|
|
1054
|
+
const issueId = details ? normalizeOptionalAuditString(details.issue_id) : null;
|
|
1055
|
+
const issueIdentifier = details ? normalizeOptionalAuditString(details.issue_identifier) : null;
|
|
1056
|
+
const expectedState = details
|
|
1057
|
+
? normalizeOptionalAuditString(details.expected_state)
|
|
1058
|
+
: null;
|
|
1059
|
+
const expectedStateType = details
|
|
1060
|
+
? normalizeOptionalAuditString(details.expected_state_type)
|
|
1061
|
+
: null;
|
|
1062
|
+
const expectedUpdatedAt = details
|
|
1063
|
+
? normalizeOptionalAuditString(details.expected_updated_at)
|
|
1064
|
+
: null;
|
|
1065
|
+
const force = details && typeof details.force === 'boolean'
|
|
1066
|
+
? details.force
|
|
1067
|
+
: (fallbackGuardFields.force ?? null);
|
|
1068
|
+
const forceReason = details
|
|
1069
|
+
? normalizeOptionalAuditString(details.force_reason)
|
|
1070
|
+
: null;
|
|
1071
|
+
return {
|
|
1072
|
+
...(issueId ? { issue_id: issueId } : {}),
|
|
1073
|
+
...(issueIdentifier ? { issue_identifier: issueIdentifier } : {}),
|
|
1074
|
+
previous_state: details ? normalizeOptionalAuditString(details.previous_state) : null,
|
|
1075
|
+
previous_state_type: details ? normalizeOptionalAuditString(details.previous_state_type) : null,
|
|
1076
|
+
target_state: details ? normalizeOptionalAuditString(details.target_state) : null,
|
|
1077
|
+
target_state_type: details ? normalizeOptionalAuditString(details.target_state_type) : null,
|
|
1078
|
+
issue_updated_at: details ? normalizeOptionalAuditString(details.issue_updated_at) : null,
|
|
1079
|
+
expected_state: expectedState ?? fallbackGuardFields.expected_state ?? null,
|
|
1080
|
+
expected_state_type: expectedStateType ?? fallbackGuardFields.expected_state_type ?? null,
|
|
1081
|
+
expected_updated_at: expectedUpdatedAt ?? fallbackGuardFields.expected_updated_at ?? null,
|
|
1082
|
+
force,
|
|
1083
|
+
force_reason: forceReason ?? fallbackGuardFields.force_reason ?? null
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
function normalizeOptionalAuditString(value) {
|
|
1087
|
+
if (typeof value !== 'string') {
|
|
1088
|
+
return null;
|
|
1089
|
+
}
|
|
1090
|
+
const trimmed = value.trim();
|
|
1091
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1092
|
+
}
|
|
1093
|
+
function resolveFollowUpAuditFields(result) {
|
|
1094
|
+
if (result.ok) {
|
|
1095
|
+
if (result.operation !== 'create-follow-up') {
|
|
1096
|
+
return {
|
|
1097
|
+
follow_up_issue_id: null,
|
|
1098
|
+
follow_up_issue_identifier: null,
|
|
1099
|
+
failed_relation_type: null
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
return {
|
|
1103
|
+
follow_up_issue_id: result.follow_up_issue.id,
|
|
1104
|
+
follow_up_issue_identifier: result.follow_up_issue.identifier,
|
|
1105
|
+
failed_relation_type: null
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
if (result.operation !== 'create-follow-up') {
|
|
1109
|
+
return {
|
|
1110
|
+
follow_up_issue_id: null,
|
|
1111
|
+
follow_up_issue_identifier: null,
|
|
1112
|
+
failed_relation_type: null
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
const details = result.error.details;
|
|
1116
|
+
const followUpIssue = readIssueLikeRecord(details?.follow_up_issue)
|
|
1117
|
+
?? readIssueLikeRecord(details?.created_issue);
|
|
1118
|
+
return {
|
|
1119
|
+
follow_up_issue_id: readRecordString(followUpIssue, 'id'),
|
|
1120
|
+
follow_up_issue_identifier: readRecordString(followUpIssue, 'identifier'),
|
|
1121
|
+
failed_relation_type: readUnknownString(details?.failed_relation_type)
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
function readIssueLikeRecord(value) {
|
|
1125
|
+
return value && typeof value === 'object' ? value : null;
|
|
1126
|
+
}
|
|
1127
|
+
function readRecordString(record, key) {
|
|
1128
|
+
if (!record) {
|
|
1129
|
+
return null;
|
|
1130
|
+
}
|
|
1131
|
+
return readUnknownString(record[key]);
|
|
1132
|
+
}
|
|
1133
|
+
function readUnknownString(value) {
|
|
1134
|
+
if (typeof value !== 'string') {
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
1137
|
+
const trimmed = value.trim();
|
|
1138
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1139
|
+
}
|
|
1140
|
+
function resolveAuditSourceSetup(flags, env) {
|
|
1141
|
+
const sourceSetup = readSourceSetup(flags);
|
|
1142
|
+
if (sourceSetup) {
|
|
1143
|
+
return sourceSetup;
|
|
1144
|
+
}
|
|
1145
|
+
const resolved = resolveLinearSourceSetup({
|
|
1146
|
+
provider: 'linear',
|
|
1147
|
+
workspace_id: null,
|
|
1148
|
+
team_id: null,
|
|
1149
|
+
project_id: null
|
|
1150
|
+
}, env);
|
|
1151
|
+
return resolved.workspace_id || resolved.team_id || resolved.project_id ? resolved : null;
|
|
1152
|
+
}
|
|
1153
|
+
function resolveRuntimeProofRepoRoot(cwd, env) {
|
|
1154
|
+
const configuredRoot = normalizeEnvPath(env.CODEX_ORCHESTRATOR_ROOT);
|
|
1155
|
+
if (!configuredRoot) {
|
|
1156
|
+
return resolveRepoRootFromHint(cwd);
|
|
1157
|
+
}
|
|
1158
|
+
const configuredHint = isAbsolute(configuredRoot) ? configuredRoot : resolve(cwd, configuredRoot);
|
|
1159
|
+
return resolveRepoRootFromHint(configuredHint);
|
|
1160
|
+
}
|
|
1161
|
+
function resolveRepoRootFromHint(rootHint) {
|
|
1162
|
+
const normalizedHint = resolve(rootHint);
|
|
1163
|
+
const gitBoundary = findNearestGitBoundary(normalizedHint);
|
|
1164
|
+
let current = normalizedHint;
|
|
1165
|
+
while (current) {
|
|
1166
|
+
if (existsSync(join(current, 'tasks', 'index.json'))) {
|
|
1167
|
+
return current;
|
|
1168
|
+
}
|
|
1169
|
+
if (gitBoundary && current === gitBoundary) {
|
|
1170
|
+
break;
|
|
1171
|
+
}
|
|
1172
|
+
const parent = dirname(current);
|
|
1173
|
+
if (parent === current) {
|
|
1174
|
+
break;
|
|
1175
|
+
}
|
|
1176
|
+
current = parent;
|
|
1177
|
+
}
|
|
1178
|
+
return gitBoundary ?? normalizedHint;
|
|
1179
|
+
}
|
|
1180
|
+
function findNearestGitBoundary(start) {
|
|
1181
|
+
let current = resolve(start);
|
|
1182
|
+
while (current) {
|
|
1183
|
+
if (existsSync(join(current, '.git'))) {
|
|
1184
|
+
return current;
|
|
1185
|
+
}
|
|
1186
|
+
const parent = dirname(current);
|
|
1187
|
+
if (parent === current) {
|
|
1188
|
+
break;
|
|
1189
|
+
}
|
|
1190
|
+
current = parent;
|
|
1191
|
+
}
|
|
1192
|
+
return null;
|
|
1193
|
+
}
|
|
1194
|
+
function normalizeEnvPath(value) {
|
|
1195
|
+
if (typeof value !== 'string') {
|
|
1196
|
+
return null;
|
|
1197
|
+
}
|
|
1198
|
+
const trimmed = value.trim();
|
|
1199
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1200
|
+
}
|