@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.
Files changed (302) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +73 -291
  3. package/bin/codex-orchestrator.js +161 -0
  4. package/codex.orchestrator.json +149 -13
  5. package/dist/bin/codex-orchestrator.js +795 -1154
  6. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
  7. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
  8. package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
  9. package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +183 -11
  10. package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
  11. package/dist/orchestrator/src/cli/coStatusCliShell.js +429 -0
  12. package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
  13. package/dist/orchestrator/src/cli/codexCliShell.js +72 -0
  14. package/dist/orchestrator/src/cli/codexDefaultsSetup.js +49 -11
  15. package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
  16. package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
  17. package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
  18. package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
  19. package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
  20. package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
  21. package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
  22. package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
  23. package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
  24. package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
  25. package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
  26. package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
  27. package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
  28. package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
  29. package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
  30. package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
  31. package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
  32. package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
  33. package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
  34. package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
  35. package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
  36. package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
  37. package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
  38. package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
  39. package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
  40. package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
  41. package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
  42. package/dist/orchestrator/src/cli/control/controlHostSupervision.js +608 -0
  43. package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
  44. package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
  45. package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
  46. package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
  47. package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
  48. package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
  49. package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
  50. package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
  51. package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
  52. package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
  53. package/dist/orchestrator/src/cli/control/controlRuntime.js +992 -0
  54. package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
  55. package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
  56. package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
  57. package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
  58. package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
  59. package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
  60. package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
  61. package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
  62. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
  63. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
  64. package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
  65. package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
  66. package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
  67. package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
  68. package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
  69. package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
  70. package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
  71. package/dist/orchestrator/src/cli/control/controlState.js +233 -2
  72. package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1899 -0
  73. package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
  74. package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
  75. package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
  76. package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
  77. package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
  78. package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
  79. package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
  80. package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
  81. package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
  82. package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
  83. package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
  84. package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
  85. package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
  86. package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
  87. package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
  88. package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
  89. package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
  90. package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
  91. package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
  92. package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
  93. package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
  94. package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
  95. package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
  96. package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
  97. package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
  98. package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
  99. package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
  100. package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
  101. package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
  102. package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
  103. package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
  104. package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
  105. package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
  106. package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
  107. package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
  108. package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
  109. package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
  110. package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
  111. package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
  112. package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
  113. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
  114. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
  115. package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
  116. package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
  117. package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
  118. package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
  119. package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
  120. package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
  121. package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
  122. package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
  123. package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
  124. package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1838 -0
  125. package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
  126. package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
  127. package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
  128. package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
  129. package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
  130. package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
  131. package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
  132. package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
  133. package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
  134. package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
  135. package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
  136. package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
  137. package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
  138. package/dist/orchestrator/src/cli/delegationServer.js +567 -678
  139. package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
  140. package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
  141. package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
  142. package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
  143. package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
  144. package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
  145. package/dist/orchestrator/src/cli/doctor.js +542 -122
  146. package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
  147. package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
  148. package/dist/orchestrator/src/cli/doctorUsage.js +136 -16
  149. package/dist/orchestrator/src/cli/exec/experience.js +16 -2
  150. package/dist/orchestrator/src/cli/exec/summary.js +3 -0
  151. package/dist/orchestrator/src/cli/execCliShell.js +51 -0
  152. package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
  153. package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
  154. package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
  155. package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
  156. package/dist/orchestrator/src/cli/init.js +1 -0
  157. package/dist/orchestrator/src/cli/initCliShell.js +50 -0
  158. package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
  159. package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
  160. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
  161. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
  162. package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
  163. package/dist/orchestrator/src/cli/planCliShell.js +19 -0
  164. package/dist/orchestrator/src/cli/prCliShell.js +41 -0
  165. package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
  166. package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1772 -0
  167. package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
  168. package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
  169. package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +5738 -0
  170. package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
  171. package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
  172. package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
  173. package/dist/orchestrator/src/cli/rlm/context.js +94 -7
  174. package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
  175. package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
  176. package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
  177. package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
  178. package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
  179. package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
  180. package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
  181. package/dist/orchestrator/src/cli/run/manifest.js +410 -73
  182. package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
  183. package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
  184. package/dist/orchestrator/src/cli/run/source0.js +690 -0
  185. package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
  186. package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
  187. package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
  188. package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
  189. package/dist/orchestrator/src/cli/services/commandRunner.js +668 -18
  190. package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
  191. package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
  192. package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
  193. package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
  194. package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
  195. package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
  196. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
  197. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
  198. package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
  199. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
  200. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
  201. package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
  202. package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
  203. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
  204. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
  205. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
  206. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
  207. package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
  208. package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
  209. package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
  210. package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
  211. package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
  212. package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
  213. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
  214. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
  215. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
  216. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
  217. package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
  218. package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
  219. package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
  220. package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
  221. package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
  222. package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
  223. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
  224. package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
  225. package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
  226. package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
  227. package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
  228. package/dist/orchestrator/src/cli/startCliShell.js +68 -0
  229. package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
  230. package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
  231. package/dist/orchestrator/src/cli/utils/cloudPreflight.js +83 -1
  232. package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
  233. package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
  234. package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
  235. package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
  236. package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
  237. package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
  238. package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
  239. package/dist/orchestrator/src/learning/crystalizer.js +2 -2
  240. package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
  241. package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
  242. package/dist/orchestrator/src/persistence/lockFile.js +70 -4
  243. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
  244. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
  245. package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
  246. package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
  247. package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
  248. package/dist/packages/sdk-node/src/orchestrator.js +137 -13
  249. package/dist/packages/shared/config/designConfig.js +8 -1
  250. package/dist/packages/shared/streams/stdio.js +1 -1
  251. package/dist/scripts/design/pipeline/permit.js +15 -0
  252. package/dist/scripts/lib/docs-catalog.js +365 -0
  253. package/dist/scripts/lib/docs-helpers.js +87 -5
  254. package/dist/scripts/lib/pr-watch-merge.js +1088 -80
  255. package/dist/scripts/lib/provider-run-contract.js +26 -0
  256. package/dist/scripts/lib/review-command-intent-classification.js +532 -0
  257. package/dist/scripts/lib/review-command-probe-classification.js +385 -0
  258. package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
  259. package/dist/scripts/lib/review-execution-runtime.js +753 -0
  260. package/dist/scripts/lib/review-execution-state.js +1144 -0
  261. package/dist/scripts/lib/review-execution-telemetry.js +215 -0
  262. package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
  263. package/dist/scripts/lib/review-launch-attempt.js +601 -0
  264. package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
  265. package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
  266. package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
  267. package/dist/scripts/lib/review-prompt-context.js +376 -0
  268. package/dist/scripts/lib/review-scope-advisory.js +286 -0
  269. package/dist/scripts/lib/review-scope-paths.js +123 -0
  270. package/dist/scripts/lib/review-shell-command-parser.js +389 -0
  271. package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
  272. package/dist/scripts/lib/run-manifests.js +192 -36
  273. package/dist/scripts/lib/spark-policy-classifier.js +593 -0
  274. package/dist/scripts/run-review.js +507 -1777
  275. package/docs/public/downstream-setup.md +106 -0
  276. package/docs/public/provider-onboarding.md +173 -0
  277. package/package.json +30 -11
  278. package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
  279. package/plugins/codex-orchestrator/.mcp.json +13 -0
  280. package/plugins/codex-orchestrator/launcher.mjs +359 -0
  281. package/schemas/manifest.json +395 -0
  282. package/skills/chrome-devtools/SKILL.md +1 -1
  283. package/skills/codex-orchestrator/SKILL.md +83 -0
  284. package/skills/collab-subagents-first/SKILL.md +2 -1
  285. package/skills/delegation-usage/DELEGATION_GUIDE.md +24 -11
  286. package/skills/delegation-usage/SKILL.md +20 -13
  287. package/skills/land/SKILL.md +77 -0
  288. package/skills/linear/SKILL.md +255 -0
  289. package/skills/release/SKILL.md +47 -3
  290. package/skills/standalone-review/SKILL.md +6 -1
  291. package/templates/README.md +4 -2
  292. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  293. package/templates/codex/.codex/agents/explorer-fast.toml +1 -0
  294. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  295. package/templates/codex/.codex/config.toml +3 -4
  296. package/templates/codex/.codex/providers/README.md +13 -0
  297. package/templates/codex/.codex/providers/control.example.json +18 -0
  298. package/templates/codex/.codex/providers/provider.env.example +15 -0
  299. package/templates/codex/AGENTS.md +12 -7
  300. package/templates/codex/mcp-client.json +5 -1
  301. package/docs/README.md +0 -307
  302. package/docs/assets/setup.gif +0 -0
@@ -0,0 +1,1838 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
3
+ import { stripNonApplicableGuardrailSummaryLines } from '../run/manifest.js';
4
+ import { LINEAR_ADVISORY_STATE_FILE } from './controlPersistenceFiles.js';
5
+ import { resolveLegacyWorkspacePathFromRunDir, resolveManifestWorkspacePath, resolveProviderWorkspacePath } from '../run/workspacePath.js';
6
+ import { PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID, PROVIDER_LINEAR_CHILD_LANE_RESERVED_SUMMARY, PROVIDER_LINEAR_WORKER_CHILD_LANES_FILENAME, PROVIDER_LINEAR_WORKER_PROOF_FILENAME, refreshProviderLinearWorkerProofSnapshot } from '../providerLinearWorkerRunner.js';
7
+ import { buildTrackedLinearPayload } from './observabilityReadModel.js';
8
+ import { buildProviderFallbackTaskId, buildProviderIssueKey, hasQueuedProviderIntakeRetry, readProviderIntakeClaim, selectProviderIntakeClaim } from './providerIntakeState.js';
9
+ import { classifyProviderLinearWorkflowState } from './providerLinearWorkflowStates.js';
10
+ import { buildProviderIssueDebugSnapshot } from './providerIssueObservability.js';
11
+ import { writeJsonAtomic } from '../utils/fs.js';
12
+ import { buildProviderLinearWorkerTerminalSummary, deriveDeterministicProviderMutationSuppressions, formatDeterministicProviderMutationDegradationSummary, isAuxiliaryProviderProofHarnessManifest, isProviderLinearWorkerProofFreshForStage, resolveProviderLinearWorkerAttemptStartedAt, resolveProviderLinearWorkerTerminalReason, resolveProviderLinearWorkerTerminalStatus, shouldUseProviderLinearWorkerTerminalProofForSelectedRun } from './providerLinearWorkerTruth.js';
13
+ const PROVIDER_LINEAR_WORKER_PIPELINE_TITLE = 'Provider Linear Worker';
14
+ const PROVIDER_LINEAR_WORKER_PIPELINE_ID = 'provider-linear-worker';
15
+ const PROVIDER_LINEAR_WORKER_RECONCILIATION_FILENAME = 'provider-linear-worker-reconciliation.json';
16
+ const SYNTHETIC_LINEAR_TASK_ID_PATTERN = /^linear-[a-z0-9]+(?:-[a-z0-9]+)*$/i;
17
+ const PROVIDER_LINEAR_CHILD_PIPELINE_IDS = new Set([
18
+ 'docs-review',
19
+ 'implementation-gate',
20
+ 'docs-relevance-advisory',
21
+ 'provider-linear-child-lane'
22
+ ]);
23
+ function selectFreshLinearAdvisoryTrackedIssue(advisoryState) {
24
+ if (!advisoryState || advisoryState.stale_source) {
25
+ return null;
26
+ }
27
+ return advisoryState.tracked_issue ?? null;
28
+ }
29
+ export function createSelectedRunProjectionReader(context) {
30
+ let selectedSnapshotPromise = null;
31
+ let selectedContextPromise = null;
32
+ let compatibilityContextPromise = null;
33
+ const readSelectedRunManifestSnapshot = async () => {
34
+ selectedSnapshotPromise ??= readSelectedRunManifestSnapshotInternal(context);
35
+ return selectedSnapshotPromise;
36
+ };
37
+ const buildSelectedRunContext = async (snapshot = null) => {
38
+ if (snapshot) {
39
+ return buildSelectedRunContextFromSnapshot(context, snapshot);
40
+ }
41
+ selectedContextPromise ??= (async () => {
42
+ const selectedSnapshot = await readSelectedRunManifestSnapshot();
43
+ return buildSelectedRunContextFromSnapshot(context, selectedSnapshot);
44
+ })();
45
+ return selectedContextPromise;
46
+ };
47
+ const buildCompatibilitySourceContext = async (snapshot = null) => {
48
+ if (snapshot) {
49
+ return buildCompatibilitySourceContextFromSnapshot(context, snapshot);
50
+ }
51
+ compatibilityContextPromise ??= (async () => {
52
+ const selectedSnapshot = await readSelectedRunManifestSnapshot();
53
+ return buildCompatibilitySourceContextFromSnapshot(context, selectedSnapshot);
54
+ })();
55
+ return compatibilityContextPromise;
56
+ };
57
+ return {
58
+ readSelectedRunManifestSnapshot,
59
+ buildSelectedRunContext,
60
+ buildCompatibilitySourceContext
61
+ };
62
+ }
63
+ export async function discoverCompatibilityCollectionContexts(context) {
64
+ const runsRoot = resolveRunsRootFromRunDir(context.paths.runDir);
65
+ const currentTaskId = resolveTaskIdFromManifestPath(context.paths.manifestPath);
66
+ const currentRunId = resolveRunIdFromManifestPath(context.paths.manifestPath);
67
+ if (!runsRoot) {
68
+ return { running: [], retrying: [], all: [] };
69
+ }
70
+ const controlWorkspacePath = await resolveControlWorkspacePath(context);
71
+ const selectedSnapshot = await readSelectedRunManifestSnapshotInternal(context);
72
+ const selectedContext = await buildUnreconciledCompatibilitySourceContextFromSnapshot(context, selectedSnapshot);
73
+ const discovered = await readDiscoveredTaskCompatibilityContexts(context, runsRoot, currentTaskId, currentRunId, controlWorkspacePath);
74
+ const reconciled = await reconcileProviderLinearWorkerDiscoveredContexts(discovered, context.providerIntakeState ?? null, selectedContext ? [selectedContext] : []);
75
+ const running = [];
76
+ const retrying = [];
77
+ const all = [];
78
+ for (const entry of reconciled) {
79
+ const discoveredContext = entry.context;
80
+ all.push(discoveredContext);
81
+ if (discoveredContext.rawStatus === 'in_progress') {
82
+ running.push(discoveredContext);
83
+ continue;
84
+ }
85
+ if ((context.providerIntakeState?.claims.length ?? 0) === 0 && entry.retryFallbackEligible) {
86
+ retrying.push(discoveredContext);
87
+ }
88
+ }
89
+ return { running, retrying, all };
90
+ }
91
+ async function readDiscoveredTaskCompatibilityContexts(context, runsRoot, currentTaskId, currentRunId, controlWorkspacePath) {
92
+ const discovered = [];
93
+ const taskEntries = await readDirectoryNames(runsRoot);
94
+ for (const taskEntry of taskEntries.sort((left, right) => left.localeCompare(right)).reverse()) {
95
+ if (taskEntry === 'local-mcp') {
96
+ continue;
97
+ }
98
+ const discoveredContexts = await readTaskCompatibilityContexts(join(runsRoot, taskEntry, 'cli'), {
99
+ excludeRunId: taskEntry === currentTaskId ? currentRunId : null,
100
+ providerIntakeState: context.providerIntakeState,
101
+ controlWorkspacePath
102
+ });
103
+ discovered.push(...discoveredContexts);
104
+ }
105
+ return discovered;
106
+ }
107
+ export async function discoverAuthoritativeRetryCollectionContexts(context) {
108
+ if (!context.providerIntakeState) {
109
+ return [];
110
+ }
111
+ const retrying = [];
112
+ for (const claim of context.providerIntakeState.claims) {
113
+ if (!hasQueuedProviderIntakeRetry(claim)) {
114
+ continue;
115
+ }
116
+ retrying.push(await buildProviderRetryContextFromClaim(context, claim));
117
+ }
118
+ return retrying.sort((left, right) => Date.parse(right.updatedAt ?? '') - Date.parse(left.updatedAt ?? ''));
119
+ }
120
+ async function buildSelectedRunContextFromSnapshot(context, snapshot) {
121
+ return await reconcileSelectedProviderLinearWorkerContext(context, await buildUnreconciledCompatibilitySourceContextFromSnapshot(context, snapshot));
122
+ }
123
+ async function buildCompatibilitySourceContextFromSnapshot(context, snapshot) {
124
+ return await reconcileSelectedProviderLinearWorkerContext(context, await buildUnreconciledCompatibilitySourceContextFromSnapshot(context, snapshot));
125
+ }
126
+ async function buildUnreconciledCompatibilitySourceContextFromSnapshot(context, snapshot) {
127
+ const [parts, controlWorkspacePath] = await Promise.all([
128
+ resolveProjectionContextParts(context, snapshot),
129
+ resolveControlWorkspacePath(context)
130
+ ]);
131
+ const providerClaim = findMatchingProviderIntakeClaim(context.providerIntakeState, snapshot, parts.providerLinearWorkerProof);
132
+ return buildProjectionContextFromParts(snapshot, parts, resolveRunsRootFromRunDir(context.paths.runDir), controlWorkspacePath, providerClaim, context.providerIntakeState ?? null);
133
+ }
134
+ async function reconcileSelectedProviderLinearWorkerContext(context, selected) {
135
+ if (!selected || !context.providerIntakeState) {
136
+ return selected;
137
+ }
138
+ if (!isProviderLinearWorkerReconciliationSource(selected) ||
139
+ !isActiveLookingProviderLinearWorkerManifestStatus(selected.rawStatus)) {
140
+ return selected;
141
+ }
142
+ const selectedRunDir = selected.runDir ?? (selected.manifestPath ? dirname(selected.manifestPath) : context.paths.runDir);
143
+ const selectedManifestPath = selected.manifestPath ?? context.paths.manifestPath;
144
+ const runsRoot = resolveRunsRootFromRunDir(selectedRunDir);
145
+ const currentTaskId = resolveTaskIdFromManifestPath(selectedManifestPath) ?? selected.taskId;
146
+ const currentRunId = resolveRunIdFromManifestPath(selectedManifestPath) ?? selected.runId;
147
+ if (!runsRoot) {
148
+ return selected;
149
+ }
150
+ const controlWorkspacePath = await resolveControlWorkspacePath(context);
151
+ const discovered = await readDiscoveredTaskCompatibilityContexts(context, runsRoot, currentTaskId, currentRunId, controlWorkspacePath);
152
+ const [reconciled] = await reconcileProviderLinearWorkerDiscoveredContexts([{ context: selected, retryFallbackEligible: false }], context.providerIntakeState, discovered.map((entry) => entry.context));
153
+ return (reconciled?.context ?? selected);
154
+ }
155
+ function buildProjectionContextFromParts(snapshot, parts, controlRunsRoot, controlWorkspacePath, providerClaim = null, providerIntakeState = null) {
156
+ if (!snapshot) {
157
+ return null;
158
+ }
159
+ const { manifestRecord, taskId, runId } = snapshot;
160
+ const issueProvider = snapshot.issueProvider ?? providerClaim?.provider ?? null;
161
+ const allowTrackedIssueFallbackIdentityRebinding = hasProviderLinearClaimBindingProvenance(snapshot, parts.providerLinearWorkerProof);
162
+ const { issueIdentifier, issueId, lookupAliases } = resolveProjectionIssueIdentity(snapshot, parts.trackedIssue, providerClaim, allowTrackedIssueFallbackIdentityRebinding);
163
+ const matchedTrackedIssue = resolveProjectionTrackedIssue(parts.trackedIssue, {
164
+ issueIdentifier,
165
+ issueId,
166
+ taskId,
167
+ runId
168
+ });
169
+ const control = parts.control;
170
+ const manifestRawStatus = readStringValue(manifestRecord, 'status') ?? 'unknown';
171
+ const startedAt = readStringValue(manifestRecord, 'started_at', 'startedAt') ?? null;
172
+ const providerProofRecord = (parts.providerLinearWorkerProof ?? null);
173
+ const proofIsFreshForStage = isProviderLinearWorkerProofFreshForStage(providerProofRecord, startedAt);
174
+ const useTerminalProof = shouldUseProviderLinearWorkerTerminalProofForSelectedRun(manifestRecord, providerProofRecord);
175
+ const useScopedTerminalProof = useTerminalProof && proofIsFreshForStage;
176
+ const proofTerminalStatus = useScopedTerminalProof
177
+ ? resolveProviderLinearWorkerTerminalStatus(providerProofRecord)
178
+ : null;
179
+ const rawStatus = proofTerminalStatus ?? manifestRawStatus;
180
+ const manifestUpdatedAt = readStringValue(manifestRecord, 'updated_at', 'updatedAt') ?? null;
181
+ const proofUpdatedAt = useScopedTerminalProof
182
+ ? readStringValue(providerProofRecord ?? {}, 'updated_at')
183
+ : null;
184
+ const updatedAt = proofUpdatedAt && (!manifestUpdatedAt || compareIsoTimestamp(proofUpdatedAt, manifestUpdatedAt) >= 0)
185
+ ? proofUpdatedAt
186
+ : manifestUpdatedAt;
187
+ const manifestCompletedAt = readStringValue(manifestRecord, 'completed_at', 'completedAt');
188
+ const completedAt = manifestCompletedAt ?? (isTerminalRunStatus(rawStatus) ? proofUpdatedAt ?? updatedAt : null);
189
+ const manifestSummary = stripNonApplicableGuardrailSummaryLines(manifestRecord, readStringValue(manifestRecord, 'summary'));
190
+ const proofAttemptStartedAt = useScopedTerminalProof
191
+ ? resolveProviderLinearWorkerAttemptStartedAt(providerProofRecord)
192
+ : null;
193
+ const proofSummary = useScopedTerminalProof && proofTerminalStatus
194
+ ? buildProviderLinearWorkerTerminalSummary({
195
+ status: proofTerminalStatus,
196
+ endReason: resolveProviderLinearWorkerTerminalReason(providerProofRecord),
197
+ degradationSummary: proofAttemptStartedAt === null
198
+ ? null
199
+ : formatDeterministicProviderMutationDegradationSummary(deriveDeterministicProviderMutationSuppressions(parts.providerLinearWorkerProof?.linear_audit ?? null, {
200
+ recordedAtNotBefore: proofAttemptStartedAt,
201
+ issueId: parts.providerLinearWorkerProof?.issue_id ?? null
202
+ }))
203
+ })
204
+ : null;
205
+ const providerDebugSnapshot = buildProviderIssueDebugSnapshot({
206
+ tracked_issue: matchedTrackedIssue,
207
+ claim: providerClaim,
208
+ proof: proofIsFreshForStage ? parts.providerLinearWorkerProof : null,
209
+ rehydrated_at: providerIntakeState?.rehydrated_at ?? null
210
+ });
211
+ const terminalMergeCloseoutProgress = resolveTerminalMergeCloseoutProgress({
212
+ rawStatus,
213
+ providerDebugSnapshot,
214
+ trackedIssue: matchedTrackedIssue
215
+ });
216
+ const summary = resolveSelectedRunDisplaySummary({
217
+ manifestRecord,
218
+ rawStatus,
219
+ summary: proofSummary ?? manifestSummary,
220
+ terminalMergeCloseoutProgress
221
+ });
222
+ const workspacePath = resolveSelectedRunWorkspacePath({
223
+ manifestRecord,
224
+ manifestPath: snapshot.manifestPath,
225
+ controlRunsRoot,
226
+ controlWorkspacePath
227
+ });
228
+ const questionSummary = buildSelectedRunQuestionSummary(parts.questions);
229
+ const latestAction = control.latest_action?.action ?? null;
230
+ const compatibilityState = resolveCompatibilityState(shouldPreferTrackedIssueCompatibilityState(matchedTrackedIssue, providerClaim)
231
+ ? matchedTrackedIssue
232
+ : null, providerClaim);
233
+ const { displayStatus, statusReason } = resolveSelectedRunDisplayStatus({
234
+ rawStatus,
235
+ latestAction,
236
+ questionSummary,
237
+ compatibilityState,
238
+ terminalMergeCloseoutProgress
239
+ });
240
+ const tracked = buildTrackedLinearPayload(matchedTrackedIssue);
241
+ const latestEvent = buildSelectedRunLatestEvent({
242
+ controlAction: control.latest_action ?? null,
243
+ updatedAt,
244
+ summary,
245
+ fallbackEvent: rawStatus,
246
+ providerDebugSnapshot,
247
+ terminalMergeCloseoutProgress
248
+ });
249
+ const lastError = terminalMergeCloseoutProgress?.status === 'failed'
250
+ ? terminalMergeCloseoutProgress.stall_reason ??
251
+ summary ??
252
+ 'merge_closeout_failed'
253
+ : rawStatus === 'failed'
254
+ ? summary ?? control.latest_action?.reason ?? 'run_failed'
255
+ : latestAction === 'fail'
256
+ ? control.latest_action?.reason ?? manifestSummary ?? 'run_failed'
257
+ : null;
258
+ return {
259
+ issueProvider,
260
+ issueIdentifier,
261
+ issueId,
262
+ taskId,
263
+ runId,
264
+ lookupAliases,
265
+ rawStatus,
266
+ displayStatus,
267
+ statusReason,
268
+ startedAt,
269
+ updatedAt,
270
+ completedAt,
271
+ summary,
272
+ lastError,
273
+ latestAction,
274
+ latestEvent,
275
+ workspacePath,
276
+ pipelineId: readStringValue(manifestRecord, 'pipeline_id', 'pipelineId') ?? null,
277
+ pipelineTitle: readStringValue(manifestRecord, 'pipeline_title', 'pipelineTitle') ?? null,
278
+ stages: readManifestStageSummaries(manifestRecord),
279
+ approvalsTotal: readManifestApprovalsTotal(manifestRecord),
280
+ manifestPath: snapshot.manifestPath,
281
+ runDir: snapshot.runDir,
282
+ questionSummary,
283
+ tracked,
284
+ compatibilityState: compatibilityState?.state ?? null,
285
+ providerLinearWorkerProof: parts.providerLinearWorkerProof,
286
+ providerDebugSnapshot,
287
+ providerRetryState: buildProviderRetryState(providerClaim)
288
+ };
289
+ }
290
+ function resolveProjectionIssueIdentity(snapshot, trackedIssue, providerClaim, allowTrackedIssueFallbackIdentityRebinding) {
291
+ const manifestIssueIdentifier = isProjectionFallbackIdentityValue(snapshot.issueIdentifier, snapshot)
292
+ ? null
293
+ : snapshot.issueIdentifier;
294
+ const manifestIssueId = isProjectionFallbackIdentityValue(snapshot.issueId, snapshot)
295
+ ? null
296
+ : snapshot.issueId;
297
+ const issueIdentifier = manifestIssueIdentifier ??
298
+ providerClaim?.issue_identifier ??
299
+ (allowTrackedIssueFallbackIdentityRebinding ? trackedIssue?.identifier : null) ??
300
+ snapshot.issueIdentifier;
301
+ const trackedIssueId = allowTrackedIssueFallbackIdentityRebinding &&
302
+ trackedIssue?.identifier === issueIdentifier
303
+ ? trackedIssue.id
304
+ : null;
305
+ const issueId = manifestIssueId ??
306
+ providerClaim?.issue_id ??
307
+ trackedIssueId ??
308
+ snapshot.issueId;
309
+ return {
310
+ issueIdentifier,
311
+ issueId,
312
+ lookupAliases: Array.from(new Set(snapshot.lookupAliases.concat(buildProjectionLookupAliases({
313
+ issueIdentifier,
314
+ issueId,
315
+ taskId: snapshot.taskId,
316
+ runId: snapshot.runId
317
+ }))))
318
+ };
319
+ }
320
+ function resolveProjectionTrackedIssue(trackedIssue, identity) {
321
+ if (!trackedIssue) {
322
+ return null;
323
+ }
324
+ if (!hasAuthoritativeProjectionIssueIdentity(identity)) {
325
+ return trackedIssue;
326
+ }
327
+ if (identity.issueId && trackedIssue.id === identity.issueId) {
328
+ return trackedIssue;
329
+ }
330
+ if (trackedIssue.identifier === identity.issueIdentifier) {
331
+ return trackedIssue;
332
+ }
333
+ return null;
334
+ }
335
+ function isProjectionFallbackIdentityValue(value, input) {
336
+ if (!value) {
337
+ return false;
338
+ }
339
+ return (isProjectionFallbackIdentityAlias(value, input.taskId) ||
340
+ isProjectionFallbackIdentityAlias(value, input.runId));
341
+ }
342
+ function isProjectionFallbackIdentityAlias(value, candidate) {
343
+ if (!candidate) {
344
+ return false;
345
+ }
346
+ if (value === candidate) {
347
+ return true;
348
+ }
349
+ return SYNTHETIC_LINEAR_TASK_ID_PATTERN.test(value) && candidate.startsWith(`${value}-`);
350
+ }
351
+ function resolveSelectedRunWorkspacePath(input) {
352
+ const explicitWorkspacePath = resolveManifestWorkspacePath(input.manifestRecord);
353
+ if (explicitWorkspacePath) {
354
+ return explicitWorkspacePath;
355
+ }
356
+ if (!input.controlRunsRoot ||
357
+ !isCliRunManifestPathWithinRunsRoot(input.manifestPath, input.controlRunsRoot)) {
358
+ return null;
359
+ }
360
+ return input.controlWorkspacePath;
361
+ }
362
+ function resolveCompatibilityState(trackedIssue, providerClaim) {
363
+ const state = trackedIssue?.state ?? providerClaim?.issue_state ?? null;
364
+ const stateType = trackedIssue?.state_type ?? providerClaim?.issue_state_type ?? null;
365
+ if (!state && !stateType) {
366
+ return null;
367
+ }
368
+ return {
369
+ state,
370
+ stateType
371
+ };
372
+ }
373
+ function shouldPreferTrackedIssueCompatibilityState(trackedIssue, providerClaim) {
374
+ if (!trackedIssue) {
375
+ return false;
376
+ }
377
+ if (providerClaim?.reason !== 'provider_issue_rehydrated_active_run') {
378
+ return true;
379
+ }
380
+ const trackedUpdatedAt = trackedIssue.updated_at ?? null;
381
+ const claimUpdatedAt = providerClaim.issue_updated_at ?? null;
382
+ if (!claimUpdatedAt) {
383
+ return true;
384
+ }
385
+ if (!trackedUpdatedAt) {
386
+ return false;
387
+ }
388
+ return compareIsoTimestamp(trackedUpdatedAt, claimUpdatedAt) > 0;
389
+ }
390
+ function isCliRunManifestPathWithinRunsRoot(manifestPath, runsRoot) {
391
+ const relativePath = relative(runsRoot, manifestPath);
392
+ if (relativePath === '' || isAbsolute(relativePath)) {
393
+ return false;
394
+ }
395
+ const normalizedRelativePath = relativePath.replace(/\\/g, '/');
396
+ if (normalizedRelativePath.startsWith('../')) {
397
+ return false;
398
+ }
399
+ const segments = normalizedRelativePath.split('/');
400
+ return (segments.length === 4 &&
401
+ segments[0].length > 0 &&
402
+ segments[1] === 'cli' &&
403
+ segments[2].length > 0 &&
404
+ segments[3] === 'manifest.json');
405
+ }
406
+ async function readSelectedRunManifestSnapshotInternal(context) {
407
+ const preferredSnapshot = await resolveProviderSelectedManifestSnapshot(context);
408
+ if (preferredSnapshot) {
409
+ return preferredSnapshot;
410
+ }
411
+ const manifest = await readJsonFile(context.paths.manifestPath);
412
+ if (!manifest) {
413
+ return null;
414
+ }
415
+ const control = context.controlStore.snapshot();
416
+ return buildSelectedRunManifestSnapshot(manifest, context.paths.manifestPath, control.run_id ?? null);
417
+ }
418
+ async function readManifestSnapshotForPath(manifestPath, fallbackRunId = null) {
419
+ const manifest = await readJsonFile(manifestPath);
420
+ if (!manifest) {
421
+ return null;
422
+ }
423
+ return buildSelectedRunManifestSnapshot(manifest, manifestPath, readStringValue(manifest, 'run_id') ?? fallbackRunId);
424
+ }
425
+ function buildSelectedRunQuestionSummary(records) {
426
+ const queued = records.filter((record) => record.status === 'queued');
427
+ let latestQuestion = null;
428
+ for (const record of queued) {
429
+ if (!latestQuestion) {
430
+ latestQuestion = record;
431
+ continue;
432
+ }
433
+ if (Date.parse(record.queued_at) >= Date.parse(latestQuestion.queued_at)) {
434
+ latestQuestion = record;
435
+ }
436
+ }
437
+ return {
438
+ queuedCount: queued.length,
439
+ latestQuestion: latestQuestion
440
+ ? {
441
+ questionId: latestQuestion.question_id,
442
+ prompt: latestQuestion.prompt,
443
+ urgency: latestQuestion.urgency,
444
+ queuedAt: latestQuestion.queued_at
445
+ }
446
+ : null
447
+ };
448
+ }
449
+ function resolveSelectedRunDisplayStatus(input) {
450
+ if (input.terminalMergeCloseoutProgress) {
451
+ return {
452
+ displayStatus: input.terminalMergeCloseoutProgress.phase === 'pending_shared_root_reconciliation'
453
+ ? 'pending_shared_root_reconciliation'
454
+ : 'failed',
455
+ statusReason: input.terminalMergeCloseoutProgress.stall_reason ?? null
456
+ };
457
+ }
458
+ if (input.rawStatus === 'in_progress' && input.latestAction === 'pause') {
459
+ return {
460
+ displayStatus: 'paused',
461
+ statusReason: input.questionSummary.queuedCount > 0 ? 'queued_questions' : 'control_pause'
462
+ };
463
+ }
464
+ if (input.rawStatus === 'in_progress' && input.questionSummary.queuedCount > 0) {
465
+ return { displayStatus: 'awaiting_input', statusReason: 'queued_questions' };
466
+ }
467
+ if (input.rawStatus === 'in_progress') {
468
+ const operatorVisibleState = resolveOperatorVisibleRunningState(input.compatibilityState);
469
+ if (operatorVisibleState) {
470
+ return { displayStatus: operatorVisibleState, statusReason: null };
471
+ }
472
+ }
473
+ return { displayStatus: input.rawStatus, statusReason: null };
474
+ }
475
+ function resolveOperatorVisibleRunningState(compatibilityState) {
476
+ const normalizedState = compatibilityState?.state?.trim() ?? null;
477
+ const normalizedStateType = compatibilityState?.stateType?.trim().toLowerCase() ?? null;
478
+ if (!normalizedState) {
479
+ return null;
480
+ }
481
+ const workflowState = classifyProviderLinearWorkflowState({
482
+ state: normalizedState,
483
+ state_type: normalizedStateType
484
+ });
485
+ if (workflowState.isTodo ||
486
+ workflowState.isTerminal ||
487
+ normalizedStateType === 'triage' ||
488
+ normalizedStateType === 'backlog' ||
489
+ normalizedStateType === 'unstarted') {
490
+ return null;
491
+ }
492
+ const stateKey = normalizedState.toLowerCase().replace(/[^a-z0-9]+/g, '');
493
+ if (stateKey === 'running' || stateKey === 'started') {
494
+ return normalizedState;
495
+ }
496
+ return normalizedState;
497
+ }
498
+ function buildSelectedRunLatestEvent(input) {
499
+ if (!input.controlAction &&
500
+ input.terminalMergeCloseoutProgress &&
501
+ input.providerDebugSnapshot?.progress) {
502
+ return {
503
+ at: input.providerDebugSnapshot.progress.summary_recorded_at ??
504
+ input.providerDebugSnapshot.progress.last_semantic_progress_at ??
505
+ input.providerDebugSnapshot.last_semantic_progress_at ??
506
+ input.updatedAt,
507
+ event: input.terminalMergeCloseoutProgress.phase,
508
+ message: input.terminalMergeCloseoutProgress.summary ?? input.summary,
509
+ source: input.terminalMergeCloseoutProgress.event_source ?? 'merge_closeout',
510
+ messageRecordedAt: input.terminalMergeCloseoutProgress.message_recorded_at ??
511
+ input.terminalMergeCloseoutProgress.summary_recorded_at ??
512
+ null,
513
+ sourceUpdatedAt: input.terminalMergeCloseoutProgress.source_updated_at ??
514
+ input.terminalMergeCloseoutProgress.last_semantic_progress_at ??
515
+ input.providerDebugSnapshot.last_semantic_progress_at ??
516
+ input.updatedAt,
517
+ candidates: input.terminalMergeCloseoutProgress.event_candidates ?? [],
518
+ requestedBy: null,
519
+ reason: input.terminalMergeCloseoutProgress.stall_reason ?? null
520
+ };
521
+ }
522
+ if (!input.controlAction &&
523
+ input.providerDebugSnapshot?.progress &&
524
+ hasAuthoritativeProviderDebugEvidence(input.providerDebugSnapshot) &&
525
+ shouldPreferProviderDebugProgressEvent(input.fallbackEvent)) {
526
+ return {
527
+ at: input.providerDebugSnapshot.progress.summary_recorded_at ??
528
+ input.providerDebugSnapshot.progress.message_recorded_at ??
529
+ input.providerDebugSnapshot.progress.source_updated_at ??
530
+ input.providerDebugSnapshot.progress.last_semantic_progress_at ??
531
+ input.providerDebugSnapshot.last_semantic_progress_at ??
532
+ input.updatedAt,
533
+ event: input.providerDebugSnapshot.progress.selected_event ??
534
+ input.providerDebugSnapshot.progress.phase,
535
+ message: input.providerDebugSnapshot.progress.summary ?? input.summary,
536
+ source: input.providerDebugSnapshot.progress.event_source ?? 'provider_debug_progress',
537
+ messageRecordedAt: input.providerDebugSnapshot.progress.message_recorded_at ??
538
+ input.providerDebugSnapshot.progress.summary_recorded_at ??
539
+ null,
540
+ sourceUpdatedAt: input.providerDebugSnapshot.progress.source_updated_at ??
541
+ input.providerDebugSnapshot.progress.last_semantic_progress_at ??
542
+ input.providerDebugSnapshot.last_semantic_progress_at ??
543
+ input.updatedAt,
544
+ candidates: input.providerDebugSnapshot.progress.event_candidates ?? [],
545
+ requestedBy: null,
546
+ reason: input.providerDebugSnapshot.progress.stall_reason ?? null
547
+ };
548
+ }
549
+ if (!input.controlAction && !input.updatedAt && !input.summary) {
550
+ return null;
551
+ }
552
+ return {
553
+ at: input.controlAction?.requested_at ?? input.updatedAt,
554
+ event: input.controlAction?.action ?? input.fallbackEvent,
555
+ message: input.summary,
556
+ source: input.controlAction ? 'control_action' : 'run_summary',
557
+ messageRecordedAt: null,
558
+ sourceUpdatedAt: input.controlAction?.requested_at ?? input.updatedAt,
559
+ candidates: [],
560
+ requestedBy: input.controlAction?.requested_by ?? null,
561
+ reason: input.controlAction?.reason ?? null
562
+ };
563
+ }
564
+ function hasAuthoritativeProviderDebugEvidence(providerDebugSnapshot) {
565
+ const claimIsStale = providerDebugSnapshot.claim?.freshness === 'stale';
566
+ if (claimIsStale && providerDebugSnapshot.progress?.kind === 'merge_closeout') {
567
+ return false;
568
+ }
569
+ const hasFreshClaim = providerDebugSnapshot.claim !== null && !claimIsStale;
570
+ const hasFreshPullRequest = providerDebugSnapshot.pull_request !== null && !claimIsStale;
571
+ return Boolean(hasFreshClaim ||
572
+ providerDebugSnapshot.worker ||
573
+ hasFreshPullRequest ||
574
+ providerDebugSnapshot.last_audit_operation);
575
+ }
576
+ function shouldPreferProviderDebugProgressEvent(fallbackEvent) {
577
+ return (fallbackEvent === 'in_progress' ||
578
+ fallbackEvent === 'running' ||
579
+ fallbackEvent === 'started' ||
580
+ fallbackEvent === 'resuming');
581
+ }
582
+ function resolveSelectedRunDisplaySummary(input) {
583
+ if (input.terminalMergeCloseoutProgress?.summary) {
584
+ return input.terminalMergeCloseoutProgress.summary;
585
+ }
586
+ const acceptedProviderRetryResumeAt = readLatestAcceptedProviderRetryResumeAt(input.manifestRecord);
587
+ const hasFailedCommandsForAuthoritativeAttempt = acceptedProviderRetryResumeAt === null
588
+ ? manifestHasFailedCommands(input.manifestRecord)
589
+ : manifestHasFailedCommandsSince(input.manifestRecord, acceptedProviderRetryResumeAt);
590
+ if (input.rawStatus === 'succeeded' &&
591
+ input.summary &&
592
+ hasStaleFailureSummary(input.summary, input.manifestRecord) &&
593
+ !hasFailedCommandsForAuthoritativeAttempt) {
594
+ const filteredSummary = filterStaleFailureSummary(input.summary, input.manifestRecord);
595
+ return filteredSummary ?? 'Completed successfully';
596
+ }
597
+ if (input.rawStatus === 'in_progress' &&
598
+ input.summary &&
599
+ hasStaleFailureSummary(input.summary, input.manifestRecord) &&
600
+ acceptedProviderRetryResumeAt !== null &&
601
+ !manifestHasFailedCommandsSince(input.manifestRecord, acceptedProviderRetryResumeAt)) {
602
+ const filteredSummary = filterStaleFailureSummary(input.summary, input.manifestRecord);
603
+ return filteredSummary ?? 'Retry accepted; run resumed after a failed attempt.';
604
+ }
605
+ return input.summary;
606
+ }
607
+ function resolveTerminalMergeCloseoutProgress(input) {
608
+ const progress = input.providerDebugSnapshot?.progress ?? null;
609
+ if (input.rawStatus !== 'succeeded' ||
610
+ !progress ||
611
+ progress.kind !== 'merge_closeout' ||
612
+ !input.providerDebugSnapshot) {
613
+ return null;
614
+ }
615
+ const isTerminalMergeCloseoutProgress = progress.phase === 'pending_shared_root_reconciliation' ||
616
+ progress.status === 'failed';
617
+ if (!isTerminalMergeCloseoutProgress) {
618
+ return null;
619
+ }
620
+ if (hasAuthoritativeProviderDebugEvidence(input.providerDebugSnapshot)) {
621
+ return progress;
622
+ }
623
+ if (input.providerDebugSnapshot.claim?.freshness !== 'stale') {
624
+ return null;
625
+ }
626
+ if (input.trackedIssue && classifyProviderLinearWorkflowState(input.trackedIssue).isTerminal) {
627
+ return null;
628
+ }
629
+ return progress;
630
+ }
631
+ function isTerminalRunStatus(status) {
632
+ return status === 'succeeded' || status === 'failed' || status === 'cancelled' || status === 'canceled';
633
+ }
634
+ function hasStaleFailureSummary(summary, manifestRecord) {
635
+ return summary.split('\n').some((line) => isStaleFailureSummaryLine(line, manifestRecord));
636
+ }
637
+ function filterStaleFailureSummary(summary, manifestRecord) {
638
+ const retainedLines = summary
639
+ .split('\n')
640
+ .map((line) => line.trim())
641
+ .filter((line) => line.length > 0 && !isStaleFailureSummaryLine(line, manifestRecord));
642
+ if (retainedLines.length === 0) {
643
+ return null;
644
+ }
645
+ return retainedLines.join('\n');
646
+ }
647
+ function isStaleFailureSummaryLine(line, manifestRecord) {
648
+ const trimmed = line.trim();
649
+ if (/^Stage '.*' failed with exit code \d+\.$/u.test(trimmed) ||
650
+ /^Sub-pipeline '.*' failed\.$/u.test(trimmed) ||
651
+ /^Execution error: .+/u.test(trimmed)) {
652
+ return true;
653
+ }
654
+ if (!/^Sub-pipeline error: .+/u.test(trimmed)) {
655
+ return false;
656
+ }
657
+ return !hasMatchingSkippedSubpipelineErrorSummary(manifestRecord, trimmed);
658
+ }
659
+ function manifestHasFailedCommands(manifestRecord) {
660
+ const commands = manifestRecord.commands;
661
+ if (!Array.isArray(commands)) {
662
+ return false;
663
+ }
664
+ return commands.some((command) => {
665
+ if (!command || typeof command !== 'object') {
666
+ return false;
667
+ }
668
+ return readStringValue(command, 'status') === 'failed';
669
+ });
670
+ }
671
+ function manifestHasFailedCommandsSince(manifestRecord, sinceAtMs) {
672
+ const commands = manifestRecord.commands;
673
+ if (!Array.isArray(commands)) {
674
+ return false;
675
+ }
676
+ return commands.some((command) => {
677
+ if (!isRecord(command) || readStringValue(command, 'status') !== 'failed') {
678
+ return false;
679
+ }
680
+ const commandFailureAtMs = readLatestCommandFailureTimestampMs(command);
681
+ if (commandFailureAtMs === null) {
682
+ return true;
683
+ }
684
+ return commandFailureAtMs >= sinceAtMs;
685
+ });
686
+ }
687
+ function readLatestAcceptedProviderRetryResumeAt(manifestRecord) {
688
+ const resumeEvents = manifestRecord.resume_events;
689
+ if (!Array.isArray(resumeEvents)) {
690
+ return null;
691
+ }
692
+ let latestAcceptedAt = null;
693
+ for (const event of resumeEvents) {
694
+ if (!isRecord(event) ||
695
+ readStringValue(event, 'reason') !== 'provider-retry' ||
696
+ readStringValue(event, 'outcome') !== 'accepted') {
697
+ continue;
698
+ }
699
+ const acceptedAt = Date.parse(readStringValue(event, 'timestamp') ?? '');
700
+ if (!Number.isFinite(acceptedAt)) {
701
+ continue;
702
+ }
703
+ latestAcceptedAt = latestAcceptedAt === null ? acceptedAt : Math.max(latestAcceptedAt, acceptedAt);
704
+ }
705
+ return latestAcceptedAt;
706
+ }
707
+ function readLatestCommandFailureTimestampMs(command) {
708
+ return readLatestCommandTimestampMs(command);
709
+ }
710
+ function hasMatchingSkippedSubpipelineErrorSummary(manifestRecord, summaryLine) {
711
+ const commands = manifestRecord.commands;
712
+ if (!Array.isArray(commands)) {
713
+ return false;
714
+ }
715
+ return commands.some((command) => {
716
+ if (!isRecord(command) || readStringValue(command, 'status') !== 'skipped') {
717
+ return false;
718
+ }
719
+ if ((readStringValue(command, 'summary') ?? '').trim() !== summaryLine) {
720
+ return false;
721
+ }
722
+ return true;
723
+ });
724
+ }
725
+ function readLatestCommandTimestampMs(command) {
726
+ for (const key of ['completed_at', 'completedAt', 'updated_at', 'updatedAt', 'started_at', 'startedAt']) {
727
+ const value = readStringValue(command, key);
728
+ const parsed = Date.parse(value ?? '');
729
+ if (Number.isFinite(parsed)) {
730
+ return parsed;
731
+ }
732
+ }
733
+ return null;
734
+ }
735
+ function readManifestStageSummaries(manifestRecord) {
736
+ const commands = manifestRecord.commands;
737
+ if (!Array.isArray(commands)) {
738
+ return [];
739
+ }
740
+ return commands.flatMap((command) => {
741
+ if (!isRecord(command)) {
742
+ return [];
743
+ }
744
+ const id = readStringValue(command, 'id');
745
+ if (!id) {
746
+ return [];
747
+ }
748
+ return [
749
+ {
750
+ id,
751
+ title: readStringValue(command, 'title') ?? id,
752
+ status: readStringValue(command, 'status') ?? null
753
+ }
754
+ ];
755
+ });
756
+ }
757
+ function readManifestApprovalsTotal(manifestRecord) {
758
+ return Array.isArray(manifestRecord.approvals) ? manifestRecord.approvals.length : 0;
759
+ }
760
+ async function resolveControlWorkspacePath(context) {
761
+ const controlManifest = await readJsonFile(context.paths.manifestPath);
762
+ const explicitWorkspacePath = controlManifest ? resolveManifestWorkspacePath(controlManifest) : null;
763
+ if (explicitWorkspacePath) {
764
+ return explicitWorkspacePath;
765
+ }
766
+ return resolveSafeLegacyWorkspacePathFromRunDir(context.paths.runDir);
767
+ }
768
+ function resolveSafeLegacyWorkspacePathFromRunDir(runDir) {
769
+ const legacyWorkspacePath = resolveLegacyWorkspacePathFromRunDir(runDir);
770
+ const runsRoot = resolveRunsRootFromRunDir(runDir);
771
+ if (!runsRoot) {
772
+ return null;
773
+ }
774
+ return normalizePathForComparison(runsRoot) === normalizePathForComparison(join(legacyWorkspacePath, '.runs'))
775
+ ? legacyWorkspacePath
776
+ : null;
777
+ }
778
+ function isRecord(value) {
779
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
780
+ }
781
+ function resolveRunsRootFromRunDir(runDir) {
782
+ const candidate = resolve(runDir, '..', '..', '..');
783
+ return candidate || null;
784
+ }
785
+ function resolveTaskIdFromManifestPath(manifestPath) {
786
+ const segments = normalizePathForComparison(manifestPath).split('/').filter((segment) => segment.length > 0);
787
+ const manifestIndex = segments[segments.length - 1] === 'manifest.json' ? segments.length - 1 : segments.length;
788
+ if (manifestIndex < 3) {
789
+ return null;
790
+ }
791
+ if (segments[manifestIndex - 2] !== 'cli') {
792
+ return null;
793
+ }
794
+ return segments[manifestIndex - 3] ?? null;
795
+ }
796
+ function resolveRunIdFromManifestPath(manifestPath) {
797
+ const normalizedPath = manifestPath.replace(/\\/g, '/');
798
+ const match = normalizedPath.match(/\/cli\/([^/]+)\/manifest\.json$/);
799
+ return match?.[1] ?? null;
800
+ }
801
+ function normalizePathForComparison(pathname) {
802
+ return resolve(pathname).replace(/\\/g, '/');
803
+ }
804
+ async function resolveProjectionContextParts(context, snapshot) {
805
+ if (!snapshot || snapshot.runDir === context.paths.runDir) {
806
+ return {
807
+ control: context.controlStore.snapshot(),
808
+ questions: context.questionQueue.list(),
809
+ runDir: context.paths.runDir,
810
+ trackedIssue: selectFreshLinearAdvisoryTrackedIssue(context.linearAdvisoryState),
811
+ providerLinearWorkerProof: await readProviderLinearWorkerProofForProjection(context.paths.runDir)
812
+ };
813
+ }
814
+ const control = normalizeControlState(await readJsonFile(join(snapshot.runDir, 'control.json')), snapshot.runId);
815
+ const questionSnapshot = await readJsonFile(join(snapshot.runDir, 'questions.json'));
816
+ const advisoryState = await readJsonFile(join(snapshot.runDir, LINEAR_ADVISORY_STATE_FILE));
817
+ return {
818
+ control,
819
+ questions: Array.isArray(questionSnapshot?.questions) ? questionSnapshot.questions : [],
820
+ runDir: snapshot.runDir,
821
+ trackedIssue: selectFreshLinearAdvisoryTrackedIssue(advisoryState),
822
+ providerLinearWorkerProof: await readProviderLinearWorkerProofForProjection(snapshot.runDir)
823
+ };
824
+ }
825
+ function buildSelectedRunManifestSnapshot(manifestRecord, manifestPath, fallbackRunId) {
826
+ const issueProvider = readStringValue(manifestRecord, 'issue_provider', 'issueProvider') ?? null;
827
+ const taskId = readStringValue(manifestRecord, 'task_id', 'taskId') ?? resolveTaskIdFromManifestPath(manifestPath);
828
+ const runId = readStringValue(manifestRecord, 'run_id', 'runId') ??
829
+ fallbackRunId ??
830
+ resolveRunIdFromManifestPath(manifestPath);
831
+ const issueIdentifier = readStringValue(manifestRecord, 'issue_identifier', 'issueIdentifier') ?? taskId ?? runId;
832
+ const issueId = readStringValue(manifestRecord, 'issue_id', 'issueId') ?? taskId ?? runId;
833
+ if (!issueIdentifier) {
834
+ return null;
835
+ }
836
+ return {
837
+ manifestRecord,
838
+ manifestPath,
839
+ runDir: dirname(manifestPath),
840
+ issueProvider,
841
+ issueIdentifier,
842
+ issueId,
843
+ taskId,
844
+ runId,
845
+ lookupAliases: buildProjectionLookupAliases({
846
+ issueIdentifier,
847
+ issueId,
848
+ taskId,
849
+ runId
850
+ })
851
+ };
852
+ }
853
+ function normalizeControlState(snapshot, runId) {
854
+ return {
855
+ run_id: snapshot?.run_id ?? runId ?? 'unknown-run',
856
+ control_seq: typeof snapshot?.control_seq === 'number' ? snapshot.control_seq : 0,
857
+ latest_action: snapshot?.latest_action ?? null,
858
+ feature_toggles: snapshot?.feature_toggles ?? null,
859
+ transport_mutation: snapshot?.transport_mutation ?? null
860
+ };
861
+ }
862
+ async function readTaskCompatibilityContexts(cliRoot, options = {}) {
863
+ const discovered = [];
864
+ const runEntries = await readDirectoryNames(cliRoot);
865
+ for (const runEntry of runEntries.sort((left, right) => left.localeCompare(right)).reverse()) {
866
+ if (options.excludeRunId && runEntry === options.excludeRunId) {
867
+ continue;
868
+ }
869
+ const runDir = join(cliRoot, runEntry);
870
+ const manifestPath = join(runDir, 'manifest.json');
871
+ const manifest = await readJsonFile(manifestPath);
872
+ if (!manifest) {
873
+ continue;
874
+ }
875
+ const snapshot = buildSelectedRunManifestSnapshot(manifest, manifestPath, runEntry);
876
+ if (!snapshot) {
877
+ continue;
878
+ }
879
+ if (isAuxiliaryProviderProofHarnessManifest(manifest)) {
880
+ continue;
881
+ }
882
+ const control = normalizeControlState(await readJsonFile(join(runDir, 'control.json')), snapshot.runId);
883
+ const questionSnapshot = await readJsonFile(join(runDir, 'questions.json'));
884
+ const advisoryState = await readJsonFile(join(runDir, LINEAR_ADVISORY_STATE_FILE));
885
+ const providerLinearWorkerProof = await readProviderLinearWorkerProofForProjection(runDir);
886
+ const context = buildProjectionContextFromParts(snapshot, {
887
+ control,
888
+ questions: Array.isArray(questionSnapshot?.questions) ? questionSnapshot.questions : [],
889
+ runDir,
890
+ trackedIssue: selectFreshLinearAdvisoryTrackedIssue(advisoryState),
891
+ providerLinearWorkerProof
892
+ }, resolveRunsRootFromRunDir(runDir), options.controlWorkspacePath ?? resolveSafeLegacyWorkspacePathFromRunDir(runDir), findMatchingProviderIntakeClaim(options.providerIntakeState, snapshot, providerLinearWorkerProof), options.providerIntakeState ?? null);
893
+ if (context) {
894
+ discovered.push({
895
+ context,
896
+ retryFallbackEligible: isManifestRetryFallbackCandidate(manifest)
897
+ });
898
+ }
899
+ }
900
+ return discovered;
901
+ }
902
+ async function reconcileProviderLinearWorkerDiscoveredContexts(discovered, providerIntakeState, additionalContexts = []) {
903
+ if (!providerIntakeState) {
904
+ return discovered;
905
+ }
906
+ const discoveredContexts = discovered.map((candidate) => candidate.context);
907
+ const allContexts = additionalContexts.concat(discoveredContexts);
908
+ return await Promise.all(discovered.map(async (entry) => {
909
+ const reconciliation = resolveProviderLinearWorkerRunArtifactReconciliation(entry.context, allContexts, providerIntakeState);
910
+ if (!reconciliation) {
911
+ return entry;
912
+ }
913
+ await writeProviderLinearWorkerRunArtifactReconciliation(entry.context.runDir, reconciliation).catch(() => undefined);
914
+ return {
915
+ ...entry,
916
+ context: applyProviderLinearWorkerRunArtifactReconciliation(entry.context, reconciliation)
917
+ };
918
+ }));
919
+ }
920
+ function resolveProviderLinearWorkerRunArtifactReconciliation(context, allContexts, providerIntakeState) {
921
+ if (!isProviderLinearWorkerReconciliationSource(context) ||
922
+ !isActiveLookingProviderLinearWorkerManifestStatus(context.rawStatus)) {
923
+ return null;
924
+ }
925
+ const claim = findProviderLinearWorkerClaimForContext(providerIntakeState, context);
926
+ if (claim && isActiveProviderLinearWorkerClaimState(claim.state)) {
927
+ return null;
928
+ }
929
+ const replacementRun = findNewerTerminalProviderLinearWorkerContext(allContexts, context);
930
+ const supersedingRunBoundClaim = !claim
931
+ ? findNewerRunBoundProviderLinearWorkerClaimForContext(providerIntakeState, context)
932
+ : null;
933
+ const claimReconciliationReason = claim
934
+ ? resolveProviderLinearWorkerClaimReconciliationReason(claim)
935
+ : null;
936
+ const absentClaimReconciliationReason = !claim
937
+ ? resolveAbsentProviderLinearWorkerClaimReconciliationReason(providerIntakeState, context, replacementRun, supersedingRunBoundClaim)
938
+ : null;
939
+ const reason = claimReconciliationReason ?? absentClaimReconciliationReason;
940
+ if (!reason) {
941
+ return null;
942
+ }
943
+ const claimForRecord = claim ?? supersedingRunBoundClaim;
944
+ const evidenceUpdatedAt = selectProviderLinearWorkerReconciliationEvidenceUpdatedAt(reason, claimForRecord, replacementRun, providerIntakeState);
945
+ if (!isProviderLinearWorkerReconciliationEvidenceNewerThanContext(evidenceUpdatedAt, context, Boolean(replacementRun) || reason === 'provider_claim_active_newer_run')) {
946
+ return null;
947
+ }
948
+ const reconciledStatus = replacementRun?.rawStatus ??
949
+ (claim?.state === 'completed' ? 'succeeded' : 'cancelled');
950
+ const recordedAt = evidenceUpdatedAt ?? context.updatedAt ?? context.startedAt ?? new Date(0).toISOString();
951
+ const supersedingRunBoundClaimSummaryPrefix = supersedingRunBoundClaim && isActiveProviderLinearWorkerClaimState(supersedingRunBoundClaim.state)
952
+ ? 'newer active claim run'
953
+ : 'newer run-bound claim run';
954
+ const summary = replacementRun
955
+ ? `Provider worker artifact reconciled as ${reconciledStatus}: newer terminal run ${replacementRun.runId ?? 'unknown'} supersedes retained ${context.rawStatus} manifest.`
956
+ : supersedingRunBoundClaim
957
+ ? `Provider worker artifact reconciled as ${reconciledStatus}: ${supersedingRunBoundClaimSummaryPrefix} ${supersedingRunBoundClaim.run_id ?? 'unknown'} supersedes retained ${context.rawStatus} manifest.`
958
+ : reason === 'provider_issue_removed'
959
+ ? `Provider worker artifact reconciled as ${reconciledStatus}: provider intake removed this issue with no active claim.`
960
+ : `Provider worker artifact reconciled as ${reconciledStatus}: provider claim is ${claimForRecord?.state ?? 'absent'} (${claimForRecord?.reason ?? reason}).`;
961
+ return {
962
+ schema_version: 1,
963
+ kind: 'provider-linear-worker-run-artifact-reconciliation',
964
+ status: 'reconciled',
965
+ reconciled_status: reconciledStatus,
966
+ reason,
967
+ summary,
968
+ recorded_at: recordedAt,
969
+ manifest: {
970
+ path: context.manifestPath ?? null,
971
+ run_id: context.runId,
972
+ task_id: context.taskId,
973
+ status: context.rawStatus,
974
+ updated_at: context.updatedAt
975
+ },
976
+ provider_claim: claimForRecord
977
+ ? {
978
+ state: claimForRecord.state,
979
+ reason: claimForRecord.reason,
980
+ issue_state: claimForRecord.issue_state,
981
+ issue_state_type: claimForRecord.issue_state_type,
982
+ updated_at: claimForRecord.updated_at,
983
+ run_id: claimForRecord.run_id,
984
+ run_manifest_path: claimForRecord.run_manifest_path
985
+ }
986
+ : null,
987
+ replacement_run: replacementRun
988
+ ? {
989
+ run_id: replacementRun.runId,
990
+ status: replacementRun.rawStatus,
991
+ manifest_path: replacementRun.manifestPath ?? null,
992
+ updated_at: replacementRun.updatedAt
993
+ }
994
+ : null
995
+ };
996
+ }
997
+ function applyProviderLinearWorkerRunArtifactReconciliation(context, reconciliation) {
998
+ return {
999
+ ...context,
1000
+ rawStatus: reconciliation.reconciled_status,
1001
+ displayStatus: reconciliation.reconciled_status,
1002
+ statusReason: reconciliation.reason,
1003
+ completedAt: context.completedAt ?? reconciliation.recorded_at,
1004
+ summary: reconciliation.summary,
1005
+ lastError: reconciliation.reconciled_status === 'failed'
1006
+ ? context.lastError ?? reconciliation.summary
1007
+ : context.lastError,
1008
+ latestEvent: {
1009
+ ...(context.latestEvent ?? {
1010
+ requestedBy: null,
1011
+ reason: null
1012
+ }),
1013
+ at: reconciliation.recorded_at,
1014
+ event: reconciliation.reconciled_status,
1015
+ message: reconciliation.summary,
1016
+ reason: reconciliation.reason
1017
+ }
1018
+ };
1019
+ }
1020
+ async function writeProviderLinearWorkerRunArtifactReconciliation(runDir, reconciliation) {
1021
+ if (!runDir) {
1022
+ return;
1023
+ }
1024
+ const targetPath = join(runDir, PROVIDER_LINEAR_WORKER_RECONCILIATION_FILENAME);
1025
+ const existing = await readJsonFile(targetPath);
1026
+ if (JSON.stringify(existing) === JSON.stringify(reconciliation)) {
1027
+ return;
1028
+ }
1029
+ await writeJsonAtomic(targetPath, reconciliation);
1030
+ }
1031
+ function isActiveLookingProviderLinearWorkerManifestStatus(status) {
1032
+ return status === 'in_progress' || status === 'launching';
1033
+ }
1034
+ function isProviderLinearWorkerReconciliationSource(context) {
1035
+ if (context.issueProvider !== null && context.issueProvider !== 'linear') {
1036
+ return false;
1037
+ }
1038
+ return (context.pipelineId === PROVIDER_LINEAR_WORKER_PIPELINE_ID ||
1039
+ context.pipelineTitle === PROVIDER_LINEAR_WORKER_PIPELINE_TITLE ||
1040
+ context.providerLinearWorkerProof != null);
1041
+ }
1042
+ function findProviderLinearWorkerClaimForContext(providerIntakeState, context) {
1043
+ const candidates = providerIntakeState.claims.filter((claim) => providerLinearWorkerClaimMatchesContext(claim, context));
1044
+ return candidates.sort((left, right) => compareProviderLinearWorkerClaimForContext(left, right, context))[0] ?? null;
1045
+ }
1046
+ function compareProviderLinearWorkerClaimForContext(left, right, context) {
1047
+ const leftRunIdentityMatch = providerLinearWorkerClaimRunIdentityMatchesContext(left, context);
1048
+ const rightRunIdentityMatch = providerLinearWorkerClaimRunIdentityMatchesContext(right, context);
1049
+ if (leftRunIdentityMatch !== rightRunIdentityMatch) {
1050
+ return leftRunIdentityMatch ? -1 : 1;
1051
+ }
1052
+ return compareIsoTimestamp(right.updated_at, left.updated_at);
1053
+ }
1054
+ function providerLinearWorkerClaimMatchesContext(claim, context) {
1055
+ if (claim.provider !== 'linear') {
1056
+ return false;
1057
+ }
1058
+ if (providerLinearWorkerClaimRunIdentityMatchesContext(claim, context)) {
1059
+ return true;
1060
+ }
1061
+ if (isProviderLinearWorkerRunBoundClaimAuthoritative(claim) &&
1062
+ providerLinearWorkerClaimHasRunIdentity(claim)) {
1063
+ return false;
1064
+ }
1065
+ return providerLinearWorkerClaimIssueIdentityMatchesContext(claim, context);
1066
+ }
1067
+ function isActiveProviderLinearWorkerClaimState(state) {
1068
+ return (state === 'accepted' ||
1069
+ state === 'starting' ||
1070
+ state === 'running' ||
1071
+ state === 'resuming' ||
1072
+ state === 'resumable' ||
1073
+ state === 'handoff_failed');
1074
+ }
1075
+ function resolveProviderLinearWorkerClaimReconciliationReason(claim) {
1076
+ if (claim.state === 'completed') {
1077
+ return 'provider_claim_completed';
1078
+ }
1079
+ if (claim.state === 'released') {
1080
+ const reason = claim.reason ?? '';
1081
+ if (isLiveRehydrateProviderLinearWorkerReleasedClaim(claim)) {
1082
+ return null;
1083
+ }
1084
+ if (reason.includes('not_active') ||
1085
+ reason.includes('not_mutable') ||
1086
+ reason.includes('assignee_changed') ||
1087
+ reason.includes('todo_blocked_by_non_terminal') ||
1088
+ isTerminalProviderLinearIssueState(claim.issue_state, claim.issue_state_type)) {
1089
+ return 'provider_claim_released';
1090
+ }
1091
+ }
1092
+ if (claim.state === 'stale' || claim.state === 'duplicate' || claim.state === 'ignored') {
1093
+ return `provider_claim_${claim.state}`;
1094
+ }
1095
+ return null;
1096
+ }
1097
+ function isLiveRehydrateProviderLinearWorkerReleasedClaim(claim) {
1098
+ if (!isProviderLinearWorkerReleasedLiveRehydrateReason(claim.reason)) {
1099
+ return false;
1100
+ }
1101
+ const workflowState = classifyProviderLinearWorkflowState({
1102
+ state: claim.issue_state,
1103
+ state_type: claim.issue_state_type
1104
+ });
1105
+ return workflowState.isActive && !workflowState.isTodo;
1106
+ }
1107
+ function isProviderLinearWorkerReleasedLiveRehydrateReason(reason) {
1108
+ return (reason === 'provider_issue_released:not_active' ||
1109
+ isProviderLinearWorkerReleasedPendingReopenReason(reason));
1110
+ }
1111
+ function isProviderLinearWorkerReleasedPendingReopenReason(reason) {
1112
+ return (typeof reason === 'string' &&
1113
+ reason.startsWith('provider_issue_released_pending_reopen:'));
1114
+ }
1115
+ function resolveAbsentProviderLinearWorkerClaimReconciliationReason(providerIntakeState, context, replacementRun, supersedingActiveClaim) {
1116
+ if (replacementRun) {
1117
+ return 'provider_claim_absent_newer_terminal_run';
1118
+ }
1119
+ if (supersedingActiveClaim) {
1120
+ return 'provider_claim_active_newer_run';
1121
+ }
1122
+ if (providerLinearWorkerRemovedIntakeReasonMatchesContext(providerIntakeState, context)) {
1123
+ return 'provider_issue_removed';
1124
+ }
1125
+ return null;
1126
+ }
1127
+ function providerLinearWorkerRemovedIntakeReasonMatchesContext(providerIntakeState, context) {
1128
+ if (providerIntakeState.latest_reason !== 'provider_issue_removed') {
1129
+ return false;
1130
+ }
1131
+ const providerIssueKeys = buildProviderLinearWorkerContextProviderIssueKeys(context);
1132
+ return Boolean(providerIntakeState.latest_provider_key &&
1133
+ providerIssueKeys.includes(providerIntakeState.latest_provider_key));
1134
+ }
1135
+ function buildProviderLinearWorkerContextProviderIssueKeys(context) {
1136
+ const identities = [context.issueId, context.issueIdentifier].filter((value) => Boolean(value && !isProjectionFallbackIdentityValue(value, context)));
1137
+ return Array.from(new Set(identities.map((identity) => buildProviderIssueKey('linear', identity))));
1138
+ }
1139
+ function selectProviderLinearWorkerReconciliationEvidenceUpdatedAt(reason, claim, replacementRun, providerIntakeState) {
1140
+ const replacementRunEvidenceAt = replacementRun
1141
+ ? selectProviderLinearWorkerReconciliationRunEvidenceTimestamp(replacementRun)
1142
+ : null;
1143
+ const claimRunEvidenceAt = claim
1144
+ ? selectProviderLinearWorkerClaimRunEvidenceTimestamp(claim)
1145
+ : null;
1146
+ if (reason === 'provider_claim_absent_newer_terminal_run') {
1147
+ return replacementRunEvidenceAt;
1148
+ }
1149
+ if (reason === 'provider_issue_removed') {
1150
+ return providerIntakeState.updated_at;
1151
+ }
1152
+ return selectLatestIsoTimestamp(claim?.updated_at ?? null, claimRunEvidenceAt, replacementRunEvidenceAt);
1153
+ }
1154
+ function selectProviderLinearWorkerReconciliationRunEvidenceTimestamp(context) {
1155
+ return selectLatestIsoTimestamp(context.updatedAt, selectProviderLinearWorkerContextChronologyTimestamp(context));
1156
+ }
1157
+ function isProviderLinearWorkerReconciliationEvidenceNewerThanContext(evidenceUpdatedAt, context, useRunChronologyBoundary = false) {
1158
+ if (!evidenceUpdatedAt) {
1159
+ return false;
1160
+ }
1161
+ const contextEvidenceBoundary = useRunChronologyBoundary
1162
+ ? selectProviderLinearWorkerContextChronologyTimestamp(context) ?? context.updatedAt
1163
+ : selectLatestIsoTimestamp(context.updatedAt, context.startedAt);
1164
+ return !contextEvidenceBoundary || compareIsoTimestamp(evidenceUpdatedAt, contextEvidenceBoundary) > 0;
1165
+ }
1166
+ function isTerminalProviderLinearIssueState(issueState, issueStateType) {
1167
+ return classifyProviderLinearWorkflowState({
1168
+ state: issueState,
1169
+ state_type: issueStateType
1170
+ }).isTerminal;
1171
+ }
1172
+ function findNewerTerminalProviderLinearWorkerContext(contexts, context) {
1173
+ return contexts
1174
+ .filter((candidate) => candidate !== context &&
1175
+ isProviderLinearWorkerReconciliationSource(candidate) &&
1176
+ isTerminalRunStatus(candidate.rawStatus) &&
1177
+ providerLinearWorkerContextsShareIssueIdentity(candidate, context) &&
1178
+ isProviderLinearWorkerContextChronologicallyNewer(candidate, context))
1179
+ .sort(compareProviderLinearWorkerContextChronologyDesc)[0] ?? null;
1180
+ }
1181
+ function compareProviderLinearWorkerContextChronologyDesc(left, right) {
1182
+ const chronologyComparison = compareIsoTimestamp(selectProviderLinearWorkerContextChronologyTimestamp(right), selectProviderLinearWorkerContextChronologyTimestamp(left));
1183
+ return chronologyComparison !== 0
1184
+ ? chronologyComparison
1185
+ : compareIsoTimestamp(right.updatedAt, left.updatedAt);
1186
+ }
1187
+ function isProviderLinearWorkerContextChronologicallyNewer(candidate, context) {
1188
+ const candidateStartedAt = selectProviderLinearWorkerContextChronologyTimestamp(candidate);
1189
+ const contextStartedAt = selectProviderLinearWorkerContextChronologyTimestamp(context);
1190
+ if (!candidateStartedAt) {
1191
+ return false;
1192
+ }
1193
+ if (!contextStartedAt) {
1194
+ const contextUpdatedAt = selectLatestIsoTimestamp(context.updatedAt, context.startedAt);
1195
+ return !contextUpdatedAt || compareIsoTimestamp(candidateStartedAt, contextUpdatedAt) > 0;
1196
+ }
1197
+ return compareIsoTimestamp(candidateStartedAt, contextStartedAt) > 0;
1198
+ }
1199
+ function selectProviderLinearWorkerContextChronologyTimestamp(context) {
1200
+ return selectLatestIsoTimestamp(context.startedAt, parseProviderLinearWorkerRunIdTimestamp(context.runId), parseProviderLinearWorkerRunPathTimestamp(context.manifestPath ?? context.runDir ?? null));
1201
+ }
1202
+ function parseProviderLinearWorkerRunPathTimestamp(pathValue) {
1203
+ if (!pathValue) {
1204
+ return null;
1205
+ }
1206
+ const normalized = pathValue.replace(/\\/g, '/');
1207
+ const segments = normalized.split('/').filter(Boolean);
1208
+ const manifestIndex = segments.lastIndexOf('manifest.json');
1209
+ if (manifestIndex > 0) {
1210
+ return parseProviderLinearWorkerRunIdTimestamp(segments[manifestIndex - 1]);
1211
+ }
1212
+ return parseProviderLinearWorkerRunIdTimestamp(segments[segments.length - 1]);
1213
+ }
1214
+ function parseProviderLinearWorkerRunIdTimestamp(runId) {
1215
+ if (!runId) {
1216
+ return null;
1217
+ }
1218
+ const match = runId.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z/);
1219
+ if (!match) {
1220
+ return null;
1221
+ }
1222
+ const iso = match[0].replace(/^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/, '$1T$2:$3:$4.$5Z');
1223
+ return Number.isFinite(Date.parse(iso)) ? iso : null;
1224
+ }
1225
+ function findNewerRunBoundProviderLinearWorkerClaimForContext(providerIntakeState, context) {
1226
+ return providerIntakeState.claims
1227
+ .filter((claim) => claim.provider === 'linear' &&
1228
+ isProviderLinearWorkerRunBoundClaimAuthoritative(claim) &&
1229
+ providerLinearWorkerClaimHasRunIdentity(claim) &&
1230
+ !providerLinearWorkerClaimRunIdentityMatchesContext(claim, context) &&
1231
+ providerLinearWorkerClaimIssueIdentityMatchesContext(claim, context) &&
1232
+ isProviderLinearWorkerRunBoundClaimNewerThanContext(claim, context))
1233
+ .sort(compareProviderLinearWorkerRunBoundClaimDesc)[0] ?? null;
1234
+ }
1235
+ function isProviderLinearWorkerRunBoundClaimNewerThanContext(claim, context) {
1236
+ const claimRunEvidenceAt = selectProviderLinearWorkerClaimRunEvidenceTimestamp(claim);
1237
+ const contextRunEvidenceAt = selectProviderLinearWorkerContextChronologyTimestamp(context);
1238
+ if (claimRunEvidenceAt && contextRunEvidenceAt) {
1239
+ return compareIsoTimestamp(claimRunEvidenceAt, contextRunEvidenceAt) > 0;
1240
+ }
1241
+ if (claimRunEvidenceAt && !contextRunEvidenceAt) {
1242
+ return true;
1243
+ }
1244
+ return compareIsoTimestamp(claim.updated_at, context.updatedAt) > 0;
1245
+ }
1246
+ function compareProviderLinearWorkerRunBoundClaimDesc(left, right) {
1247
+ const chronologyComparison = compareIsoTimestamp(selectProviderLinearWorkerClaimRunEvidenceTimestamp(right), selectProviderLinearWorkerClaimRunEvidenceTimestamp(left));
1248
+ return chronologyComparison !== 0
1249
+ ? chronologyComparison
1250
+ : compareIsoTimestamp(right.updated_at, left.updated_at);
1251
+ }
1252
+ function selectProviderLinearWorkerClaimRunEvidenceTimestamp(claim) {
1253
+ return selectLatestIsoTimestamp(parseProviderLinearWorkerRunIdTimestamp(claim.run_id), parseProviderLinearWorkerRunPathTimestamp(claim.run_manifest_path));
1254
+ }
1255
+ function isProviderLinearWorkerRunBoundClaimAuthoritative(claim) {
1256
+ return (isActiveProviderLinearWorkerClaimState(claim.state) ||
1257
+ (claim.state === 'released' && isLiveRehydrateProviderLinearWorkerReleasedClaim(claim)));
1258
+ }
1259
+ function providerLinearWorkerClaimHasRunIdentity(claim) {
1260
+ return Boolean(claim.run_id || claim.run_manifest_path);
1261
+ }
1262
+ function providerLinearWorkerClaimRunIdentityMatchesContext(claim, context) {
1263
+ const manifestPath = context.manifestPath ?? null;
1264
+ return Boolean((claim.run_id && claim.run_id === context.runId) ||
1265
+ (claim.run_manifest_path && manifestPath && claim.run_manifest_path === manifestPath));
1266
+ }
1267
+ function providerLinearWorkerClaimIssueIdentityMatchesContext(claim, context) {
1268
+ return Boolean((claim.issue_id && claim.issue_id === context.issueId) ||
1269
+ (claim.issue_identifier && claim.issue_identifier === context.issueIdentifier) ||
1270
+ (claim.task_id && claim.task_id === context.taskId));
1271
+ }
1272
+ function providerLinearWorkerContextsShareIssueIdentity(left, right) {
1273
+ return Boolean((left.issueId && right.issueId && left.issueId === right.issueId) ||
1274
+ (left.issueIdentifier && right.issueIdentifier && left.issueIdentifier === right.issueIdentifier) ||
1275
+ (left.taskId && right.taskId && left.taskId === right.taskId));
1276
+ }
1277
+ function selectLatestIsoTimestamp(...values) {
1278
+ return values
1279
+ .filter((value) => Boolean(value))
1280
+ .sort((left, right) => compareIsoTimestamp(right, left))[0] ?? null;
1281
+ }
1282
+ async function readDirectoryNames(path) {
1283
+ try {
1284
+ const entries = await readdir(path, { withFileTypes: true });
1285
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
1286
+ }
1287
+ catch {
1288
+ return [];
1289
+ }
1290
+ }
1291
+ async function readJsonFile(path) {
1292
+ try {
1293
+ const raw = await readFile(path, 'utf8');
1294
+ return JSON.parse(raw);
1295
+ }
1296
+ catch {
1297
+ return null;
1298
+ }
1299
+ }
1300
+ async function readProviderLinearWorkerProofForProjection(runDir) {
1301
+ const proof = await readJsonFile(join(runDir, PROVIDER_LINEAR_WORKER_PROOF_FILENAME));
1302
+ const refreshPlan = await resolveProviderLinearWorkerProjectionProofRefreshPlan(runDir, proof);
1303
+ if (!refreshPlan) {
1304
+ return proof;
1305
+ }
1306
+ return ((await refreshProviderLinearWorkerProofSnapshot(runDir, null, undefined, undefined, process.env, {
1307
+ updatedAtComparisonScope: refreshPlan.updatedAtComparisonScope,
1308
+ skipSessionLogHydration: refreshPlan.skipSessionLogHydration
1309
+ }).catch(() => proof)) ?? proof);
1310
+ }
1311
+ async function resolveProviderLinearWorkerProjectionProofRefreshPlan(runDir, proof) {
1312
+ if (!proof) {
1313
+ return null;
1314
+ }
1315
+ const hasRetiredResidue = hasProviderLinearWorkerProjectionRetiredChildLaneResidue(proof) ||
1316
+ (await hasProviderLinearWorkerProjectionRetiredChildLaneResidueInLedger(runDir));
1317
+ const telemetryGap = hasProviderLinearWorkerProjectionTelemetryGap(proof);
1318
+ const canSkipSessionLogHydration = canSkipProviderLinearWorkerProjectionSessionLogHydration(proof, telemetryGap);
1319
+ if (!isProviderLinearWorkerProjectionRefreshEligible(proof)) {
1320
+ return hasRetiredResidue
1321
+ ? {
1322
+ updatedAtComparisonScope: 'full',
1323
+ skipSessionLogHydration: canSkipSessionLogHydration
1324
+ }
1325
+ : null;
1326
+ }
1327
+ if (hasRetiredResidue) {
1328
+ return {
1329
+ updatedAtComparisonScope: 'full',
1330
+ skipSessionLogHydration: canSkipSessionLogHydration
1331
+ };
1332
+ }
1333
+ if (hasProviderLinearWorkerProjectionReservationPlaceholder(proof)) {
1334
+ return {
1335
+ updatedAtComparisonScope: 'full',
1336
+ skipSessionLogHydration: canSkipSessionLogHydration
1337
+ };
1338
+ }
1339
+ if (hasProviderLinearWorkerProjectionActivePendingChildLane(proof)) {
1340
+ return {
1341
+ updatedAtComparisonScope: 'full',
1342
+ skipSessionLogHydration: canSkipSessionLogHydration
1343
+ };
1344
+ }
1345
+ if (await hasProviderLinearWorkerProjectionActivePendingChildLaneInLedger(runDir)) {
1346
+ return {
1347
+ updatedAtComparisonScope: 'full',
1348
+ skipSessionLogHydration: canSkipSessionLogHydration
1349
+ };
1350
+ }
1351
+ return telemetryGap
1352
+ ? {
1353
+ updatedAtComparisonScope: 'telemetry',
1354
+ skipSessionLogHydration: false
1355
+ }
1356
+ : null;
1357
+ }
1358
+ function isProviderLinearWorkerProjectionRefreshEligible(proof) {
1359
+ return (proof.owner_status === 'in_progress' &&
1360
+ (proof.owner_phase === 'turn_running' || proof.owner_phase === 'turn_completed'));
1361
+ }
1362
+ function hasProviderLinearWorkerProjectionReservationPlaceholder(proof) {
1363
+ return hasProviderLinearWorkerProjectionReservationPlaceholderInRecords(proof.child_lanes);
1364
+ }
1365
+ function hasProviderLinearWorkerProjectionActivePendingChildLane(proof) {
1366
+ return hasProviderLinearWorkerProjectionActivePendingChildLaneInRecords(proof.child_lanes);
1367
+ }
1368
+ function hasProviderLinearWorkerProjectionRetiredChildLaneResidue(proof) {
1369
+ return hasProviderLinearWorkerProjectionRetiredChildLaneResidueInRecords(proof.child_lanes);
1370
+ }
1371
+ function hasProviderLinearWorkerProjectionTelemetryGap(proof) {
1372
+ const tokens = proof.tokens ?? null;
1373
+ const hasTokens = tokens?.input_tokens != null || tokens?.output_tokens != null || tokens?.total_tokens != null;
1374
+ return (!proof.latest_turn_id ||
1375
+ !proof.latest_session_id ||
1376
+ !hasTokens ||
1377
+ proof.rate_limits == null);
1378
+ }
1379
+ function canSkipProviderLinearWorkerProjectionSessionLogHydration(proof, telemetryGap) {
1380
+ if (proof.owner_phase !== 'turn_completed') {
1381
+ return false;
1382
+ }
1383
+ const currentTurnActivity = proof.current_turn_activity ?? null;
1384
+ return !(telemetryGap ||
1385
+ !proof.last_event_at ||
1386
+ (!proof.last_event && !proof.last_message) ||
1387
+ currentTurnActivity == null ||
1388
+ currentTurnActivity.recorded_at == null ||
1389
+ currentTurnActivity.turn_id !== proof.latest_turn_id ||
1390
+ currentTurnActivity.session_id !== proof.latest_session_id ||
1391
+ proof.auth_provenance == null);
1392
+ }
1393
+ async function hasProviderLinearWorkerProjectionActivePendingChildLaneInLedger(runDir) {
1394
+ const records = await readJsonFile(join(runDir, PROVIDER_LINEAR_WORKER_CHILD_LANES_FILENAME));
1395
+ return hasProviderLinearWorkerProjectionActivePendingChildLaneInRecords(records);
1396
+ }
1397
+ async function hasProviderLinearWorkerProjectionRetiredChildLaneResidueInLedger(runDir) {
1398
+ const records = await readJsonFile(join(runDir, PROVIDER_LINEAR_WORKER_CHILD_LANES_FILENAME));
1399
+ return hasProviderLinearWorkerProjectionRetiredChildLaneResidueInRecords(records);
1400
+ }
1401
+ function hasProviderLinearWorkerProjectionReservationPlaceholderInRecords(records) {
1402
+ if (!Array.isArray(records)) {
1403
+ return false;
1404
+ }
1405
+ return records.some((childLane) => {
1406
+ if (!isRecord(childLane)) {
1407
+ return false;
1408
+ }
1409
+ const runId = readStringValue(childLane, 'run_id');
1410
+ const summary = readStringValue(childLane, 'summary');
1411
+ const status = readStringValue(childLane, 'status');
1412
+ const pipelineId = readStringValue(childLane, 'pipeline_id');
1413
+ const decision = readStringValue(childLane, 'decision');
1414
+ return (pipelineId === PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID &&
1415
+ decision === 'pending' &&
1416
+ (status === 'launching' ||
1417
+ Boolean(runId?.startsWith('launching-')) ||
1418
+ summary === PROVIDER_LINEAR_CHILD_LANE_RESERVED_SUMMARY));
1419
+ });
1420
+ }
1421
+ function hasProviderLinearWorkerProjectionActivePendingChildLaneInRecords(records) {
1422
+ if (!Array.isArray(records)) {
1423
+ return false;
1424
+ }
1425
+ return records.some((childLane) => {
1426
+ if (!isRecord(childLane)) {
1427
+ return false;
1428
+ }
1429
+ const status = readStringValue(childLane, 'status');
1430
+ return (readStringValue(childLane, 'pipeline_id') === PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID &&
1431
+ readStringValue(childLane, 'decision') === 'pending' &&
1432
+ !isProviderLinearWorkerProjectionTerminalChildLaneStatus(status ?? null));
1433
+ });
1434
+ }
1435
+ function hasProviderLinearWorkerProjectionRetiredChildLaneResidueInRecords(records) {
1436
+ if (!Array.isArray(records)) {
1437
+ return false;
1438
+ }
1439
+ return records.some((childLane) => {
1440
+ if (!isRecord(childLane)) {
1441
+ return false;
1442
+ }
1443
+ const status = readStringValue(childLane, 'status');
1444
+ const summary = readStringValue(childLane, 'summary');
1445
+ const decision = readStringValue(childLane, 'decision');
1446
+ const inFlightAction = readStringValue(childLane, 'in_flight_action');
1447
+ const hasActiveLookingStatus = status === 'launching' ||
1448
+ status === 'in_progress' ||
1449
+ status === 'running' ||
1450
+ status === 'queued';
1451
+ return (readStringValue(childLane, 'pipeline_id') === PROVIDER_LINEAR_CHILD_LANE_PIPELINE_ID &&
1452
+ (decision === 'invalidated' || decision === 'rejected') &&
1453
+ (hasActiveLookingStatus ||
1454
+ Boolean(inFlightAction) ||
1455
+ isProviderLinearWorkerProjectionActiveLookingChildLaneSummary(summary)));
1456
+ });
1457
+ }
1458
+ function isProviderLinearWorkerProjectionActiveLookingChildLaneSummary(summary) {
1459
+ if (!summary) {
1460
+ return false;
1461
+ }
1462
+ const normalized = summary.toLowerCase();
1463
+ return (summary === PROVIDER_LINEAR_CHILD_LANE_RESERVED_SUMMARY ||
1464
+ normalized.includes(' is running') ||
1465
+ normalized.includes(' is queued') ||
1466
+ normalized.includes(' status is in_progress') ||
1467
+ normalized.includes(' status is running') ||
1468
+ normalized.includes(' status is queued') ||
1469
+ normalized.includes(' status is launching') ||
1470
+ normalized.includes('reserved before child run startup'));
1471
+ }
1472
+ function isProviderLinearWorkerProjectionTerminalChildLaneStatus(status) {
1473
+ return (status === 'succeeded' ||
1474
+ status === 'failed' ||
1475
+ status === 'completed' ||
1476
+ status === 'canceled' ||
1477
+ status === 'cancelled' ||
1478
+ status === 'invalidated' ||
1479
+ status === 'rejected');
1480
+ }
1481
+ function isManifestRetryFallbackCandidate(manifestRecord) {
1482
+ if (readStringValue(manifestRecord, 'issue_provider', 'issueProvider') !== 'linear') {
1483
+ return false;
1484
+ }
1485
+ const status = readStringValue(manifestRecord, 'status');
1486
+ return status === 'failed' || status === 'cancelled' || status === 'canceled';
1487
+ }
1488
+ function findMatchingProviderIntakeClaim(state, snapshot, providerLinearWorkerProof = null) {
1489
+ if (!state || !snapshot) {
1490
+ return null;
1491
+ }
1492
+ const claimMatchSource = buildSelectedRunProviderClaimMatchSource(snapshot, providerLinearWorkerProof);
1493
+ const issueScopedClaim = findIssueScopedProviderIntakeClaim(state, claimMatchSource);
1494
+ if (issueScopedClaim) {
1495
+ return providerIntakeClaimCanFallbackByIssue(issueScopedClaim, claimMatchSource) ? issueScopedClaim : null;
1496
+ }
1497
+ const matchedClaims = state.claims
1498
+ .filter((claim) => providerIntakeClaimMatchesSelectedRun(claim, claimMatchSource))
1499
+ .sort((left, right) => compareProviderIntakeClaimSpecificity(right, left, claimMatchSource));
1500
+ return matchedClaims[0] ?? null;
1501
+ }
1502
+ function findIssueScopedProviderIntakeClaim(state, snapshot) {
1503
+ if (snapshot.issueId) {
1504
+ const byIssueId = readProviderIntakeClaim(state, buildProviderIssueKey('linear', snapshot.issueId));
1505
+ if (byIssueId) {
1506
+ return byIssueId;
1507
+ }
1508
+ }
1509
+ return state.claims.find((claim) => claim.issue_identifier === snapshot.issueIdentifier) ?? null;
1510
+ }
1511
+ function providerIntakeClaimMatchesSelectedRun(claim, snapshot) {
1512
+ if (claim.run_manifest_path && claim.run_manifest_path === snapshot.manifestPath) {
1513
+ return true;
1514
+ }
1515
+ if (!providerIntakeClaimMatchesIssueIdentity(claim, snapshot)) {
1516
+ return providerIntakeClaimMatchesSyntheticFallbackTaskBinding(claim, snapshot);
1517
+ }
1518
+ if (claim.run_id && snapshot.runId) {
1519
+ if (claim.task_id && snapshot.taskId && claim.task_id !== snapshot.taskId) {
1520
+ return false;
1521
+ }
1522
+ return claim.run_id === snapshot.runId;
1523
+ }
1524
+ if (claim.task_id && snapshot.taskId) {
1525
+ return claim.task_id === snapshot.taskId;
1526
+ }
1527
+ return false;
1528
+ }
1529
+ function compareProviderIntakeClaimSpecificity(left, right, snapshot) {
1530
+ const leftPriority = scoreProviderIntakeClaimSpecificity(left, snapshot);
1531
+ const rightPriority = scoreProviderIntakeClaimSpecificity(right, snapshot);
1532
+ if (leftPriority !== rightPriority) {
1533
+ return leftPriority - rightPriority;
1534
+ }
1535
+ const leftTaskLength = left.task_id?.length ?? 0;
1536
+ const rightTaskLength = right.task_id?.length ?? 0;
1537
+ if (leftTaskLength !== rightTaskLength) {
1538
+ return leftTaskLength - rightTaskLength;
1539
+ }
1540
+ return (left.issue_identifier ?? '').localeCompare(right.issue_identifier ?? '');
1541
+ }
1542
+ function scoreProviderIntakeClaimSpecificity(claim, snapshot) {
1543
+ if (claim.run_manifest_path && claim.run_manifest_path === snapshot.manifestPath) {
1544
+ return 4;
1545
+ }
1546
+ if (claim.run_id && snapshot.runId && claim.run_id === snapshot.runId) {
1547
+ return 3;
1548
+ }
1549
+ if (claim.task_id && snapshot.taskId && claim.task_id === snapshot.taskId) {
1550
+ return 2;
1551
+ }
1552
+ if (providerIntakeClaimMatchesSyntheticFallbackTaskBinding(claim, snapshot)) {
1553
+ return 1;
1554
+ }
1555
+ return 0;
1556
+ }
1557
+ function providerIntakeClaimCanFallbackByIssue(claim, snapshot) {
1558
+ return (providerIntakeClaimMatchesSelectedRun(claim, snapshot) ||
1559
+ (!claim.run_manifest_path && !claim.run_id && !claim.task_id));
1560
+ }
1561
+ function providerIntakeClaimMatchesIssueIdentity(claim, snapshot) {
1562
+ return ((claim.issue_id != null && snapshot.issueId != null && claim.issue_id === snapshot.issueId) ||
1563
+ claim.issue_identifier === snapshot.issueIdentifier);
1564
+ }
1565
+ function providerIntakeClaimMatchesSyntheticFallbackTaskBinding(claim, snapshot) {
1566
+ if (!claim.task_id || !snapshot.taskId) {
1567
+ return false;
1568
+ }
1569
+ if (!hasProviderLinearClaimBindingProvenance(snapshot, snapshot.providerLinearWorkerProof)) {
1570
+ return false;
1571
+ }
1572
+ if (claim.task_id !== buildProviderFallbackTaskId({ id: claim.issue_id })) {
1573
+ return false;
1574
+ }
1575
+ if (snapshot.taskId === claim.task_id) {
1576
+ return !hasAuthoritativeProjectionIssueIdentity(snapshot);
1577
+ }
1578
+ const pipelineId = readStringValue(snapshot.manifestRecord, 'pipeline_id', 'pipelineId') ?? null;
1579
+ return (matchesSyntheticProviderChildTaskId(claim.task_id, snapshot.taskId, pipelineId) &&
1580
+ !hasAuthoritativeProjectionIssueIdentity(snapshot));
1581
+ }
1582
+ function isProviderLinearChildPipelineId(pipelineId) {
1583
+ return pipelineId !== null && PROVIDER_LINEAR_CHILD_PIPELINE_IDS.has(pipelineId);
1584
+ }
1585
+ function matchesSyntheticProviderChildTaskId(claimTaskId, snapshotTaskId, pipelineId) {
1586
+ if (!isProviderLinearChildPipelineId(pipelineId)) {
1587
+ return false;
1588
+ }
1589
+ if (pipelineId === 'provider-linear-child-lane') {
1590
+ return snapshotTaskId.startsWith(`${claimTaskId}-`);
1591
+ }
1592
+ return snapshotTaskId === `${claimTaskId}-${pipelineId}`;
1593
+ }
1594
+ function hasProviderLinearClaimBindingProvenance(snapshot, providerLinearWorkerProof) {
1595
+ if (snapshot.issueProvider !== null && snapshot.issueProvider !== 'linear') {
1596
+ return false;
1597
+ }
1598
+ const pipelineId = readStringValue(snapshot.manifestRecord, 'pipeline_id', 'pipelineId') ?? null;
1599
+ const pipelineTitle = readStringValue(snapshot.manifestRecord, 'pipeline_title', 'pipelineTitle') ?? null;
1600
+ return (pipelineId === PROVIDER_LINEAR_WORKER_PIPELINE_ID ||
1601
+ pipelineTitle === PROVIDER_LINEAR_WORKER_PIPELINE_TITLE ||
1602
+ providerLinearWorkerProof != null ||
1603
+ (snapshot.issueProvider === 'linear' && isProviderLinearChildPipelineId(pipelineId)));
1604
+ }
1605
+ function buildSelectedRunProviderClaimMatchSource(snapshot, providerLinearWorkerProof) {
1606
+ return {
1607
+ issueId: snapshot.issueId,
1608
+ issueIdentifier: snapshot.issueIdentifier,
1609
+ issueProvider: snapshot.issueProvider,
1610
+ manifestPath: snapshot.manifestPath,
1611
+ manifestRecord: snapshot.manifestRecord,
1612
+ runId: snapshot.runId,
1613
+ taskId: snapshot.taskId,
1614
+ providerLinearWorkerProof
1615
+ };
1616
+ }
1617
+ function hasAuthoritativeProjectionIssueIdentity(snapshot) {
1618
+ if (snapshot.issueIdentifier && !isProjectionFallbackIdentityValue(snapshot.issueIdentifier, snapshot)) {
1619
+ return true;
1620
+ }
1621
+ if (snapshot.issueId && !isProjectionFallbackIdentityValue(snapshot.issueId, snapshot)) {
1622
+ return true;
1623
+ }
1624
+ return false;
1625
+ }
1626
+ function buildProviderRetryState(claim) {
1627
+ if (!claim) {
1628
+ return null;
1629
+ }
1630
+ const active = claim.retry_queued === true;
1631
+ const attempt = claim.retry_attempt ?? null;
1632
+ const dueAt = claim.retry_due_at ?? null;
1633
+ const error = claim.retry_error ?? null;
1634
+ if (!active && attempt === null && dueAt === null && error === null) {
1635
+ return null;
1636
+ }
1637
+ return {
1638
+ active,
1639
+ attempt,
1640
+ due_at: dueAt,
1641
+ error
1642
+ };
1643
+ }
1644
+ async function buildProviderRetryContextFromClaim(context, claim) {
1645
+ const retryLatestEvent = claim.reason !== null
1646
+ ? {
1647
+ at: claim.updated_at,
1648
+ event: claim.state,
1649
+ message: claim.reason,
1650
+ requestedBy: null,
1651
+ reason: claim.reason
1652
+ }
1653
+ : null;
1654
+ const snapshot = claim.run_manifest_path
1655
+ ? await readManifestSnapshotForPath(claim.run_manifest_path, claim.run_id ?? null)
1656
+ : null;
1657
+ const controlWorkspacePath = await resolveControlWorkspacePath(context);
1658
+ if (!snapshot) {
1659
+ return {
1660
+ issueProvider: claim.provider,
1661
+ issueIdentifier: claim.issue_identifier,
1662
+ issueId: claim.issue_id,
1663
+ taskId: claim.task_id,
1664
+ runId: claim.run_id,
1665
+ lookupAliases: buildProjectionLookupAliases({
1666
+ issueIdentifier: claim.issue_identifier,
1667
+ issueId: claim.issue_id,
1668
+ taskId: claim.task_id,
1669
+ runId: claim.run_id
1670
+ }),
1671
+ rawStatus: claim.state,
1672
+ displayStatus: 'retrying',
1673
+ statusReason: claim.reason,
1674
+ startedAt: claim.accepted_at,
1675
+ updatedAt: claim.updated_at,
1676
+ completedAt: null,
1677
+ summary: claim.reason,
1678
+ lastError: claim.retry_error ?? null,
1679
+ latestAction: null,
1680
+ latestEvent: retryLatestEvent,
1681
+ workspacePath: resolveRetryWorkspacePath(claim, controlWorkspacePath),
1682
+ pipelineTitle: null,
1683
+ stages: [],
1684
+ approvalsTotal: 0,
1685
+ manifestPath: claim.run_manifest_path,
1686
+ runDir: claim.run_manifest_path ? dirname(claim.run_manifest_path) : null,
1687
+ questionSummary: {
1688
+ queuedCount: 0,
1689
+ latestQuestion: null
1690
+ },
1691
+ tracked: null,
1692
+ compatibilityState: claim.issue_state,
1693
+ providerLinearWorkerProof: null,
1694
+ providerDebugSnapshot: buildProviderIssueDebugSnapshot({
1695
+ claim,
1696
+ rehydrated_at: context.providerIntakeState?.rehydrated_at ?? null
1697
+ }),
1698
+ providerRetryState: buildProviderRetryState(claim)
1699
+ };
1700
+ }
1701
+ const parts = await resolveProjectionContextParts(context, snapshot);
1702
+ const base = buildProjectionContextFromParts(snapshot, parts, resolveRunsRootFromRunDir(context.paths.runDir), controlWorkspacePath, claim, context.providerIntakeState ?? null) ??
1703
+ null;
1704
+ if (!base) {
1705
+ return {
1706
+ issueProvider: claim.provider,
1707
+ issueIdentifier: claim.issue_identifier,
1708
+ issueId: claim.issue_id,
1709
+ taskId: claim.task_id,
1710
+ runId: claim.run_id,
1711
+ lookupAliases: buildProjectionLookupAliases({
1712
+ issueIdentifier: claim.issue_identifier,
1713
+ issueId: claim.issue_id,
1714
+ taskId: claim.task_id,
1715
+ runId: claim.run_id
1716
+ }),
1717
+ rawStatus: claim.state,
1718
+ displayStatus: 'retrying',
1719
+ statusReason: claim.reason,
1720
+ startedAt: claim.accepted_at,
1721
+ updatedAt: claim.updated_at,
1722
+ completedAt: null,
1723
+ summary: claim.reason,
1724
+ lastError: claim.retry_error ?? null,
1725
+ latestAction: null,
1726
+ latestEvent: null,
1727
+ workspacePath: resolveRetryWorkspacePath(claim, controlWorkspacePath),
1728
+ pipelineTitle: null,
1729
+ stages: [],
1730
+ approvalsTotal: 0,
1731
+ manifestPath: claim.run_manifest_path,
1732
+ runDir: claim.run_manifest_path ? dirname(claim.run_manifest_path) : null,
1733
+ questionSummary: {
1734
+ queuedCount: 0,
1735
+ latestQuestion: null
1736
+ },
1737
+ tracked: null,
1738
+ compatibilityState: claim.issue_state,
1739
+ providerLinearWorkerProof: null,
1740
+ providerRetryState: buildProviderRetryState(claim)
1741
+ };
1742
+ }
1743
+ return {
1744
+ ...base,
1745
+ lookupAliases: Array.from(new Set(base.lookupAliases.concat(buildProjectionLookupAliases({
1746
+ issueIdentifier: claim.issue_identifier,
1747
+ issueId: claim.issue_id,
1748
+ taskId: claim.task_id,
1749
+ runId: claim.run_id
1750
+ })))),
1751
+ rawStatus: claim.state,
1752
+ displayStatus: 'retrying',
1753
+ statusReason: claim.reason,
1754
+ updatedAt: claim.updated_at,
1755
+ summary: claim.reason ?? base.summary,
1756
+ lastError: claim.retry_error ?? base.lastError,
1757
+ latestEvent: retryLatestEvent ?? base.latestEvent,
1758
+ workspacePath: resolveRetryWorkspacePath(claim, controlWorkspacePath, base),
1759
+ compatibilityState: claim.issue_state ?? base.compatibilityState ?? null,
1760
+ providerRetryState: buildProviderRetryState(claim)
1761
+ };
1762
+ }
1763
+ function resolveRetryWorkspacePath(claim, controlWorkspacePath, source) {
1764
+ const proofWorkspacePath = source?.providerLinearWorkerProof?.workspace_path ?? null;
1765
+ if (proofWorkspacePath) {
1766
+ return proofWorkspacePath;
1767
+ }
1768
+ if (source?.workspacePath &&
1769
+ (!controlWorkspacePath || source.workspacePath !== controlWorkspacePath)) {
1770
+ return source.workspacePath;
1771
+ }
1772
+ if (!controlWorkspacePath || !claim.task_id) {
1773
+ return null;
1774
+ }
1775
+ try {
1776
+ return resolveProviderWorkspacePath(controlWorkspacePath, claim.task_id);
1777
+ }
1778
+ catch {
1779
+ return null;
1780
+ }
1781
+ }
1782
+ function readStringValue(record, ...keys) {
1783
+ for (const key of keys) {
1784
+ const value = record[key];
1785
+ if (typeof value === 'string') {
1786
+ const trimmed = value.trim();
1787
+ if (trimmed.length > 0) {
1788
+ return trimmed;
1789
+ }
1790
+ }
1791
+ }
1792
+ return undefined;
1793
+ }
1794
+ function compareIsoTimestamp(left, right) {
1795
+ const leftValue = Date.parse(left ?? '');
1796
+ const rightValue = Date.parse(right ?? '');
1797
+ if (!Number.isFinite(leftValue) && !Number.isFinite(rightValue)) {
1798
+ return 0;
1799
+ }
1800
+ if (!Number.isFinite(leftValue)) {
1801
+ return -1;
1802
+ }
1803
+ if (!Number.isFinite(rightValue)) {
1804
+ return 1;
1805
+ }
1806
+ return leftValue - rightValue;
1807
+ }
1808
+ function buildProjectionLookupAliases(input) {
1809
+ const aliases = new Set();
1810
+ for (const candidate of [input.issueIdentifier, input.issueId, input.taskId, input.runId]) {
1811
+ if (candidate) {
1812
+ aliases.add(candidate);
1813
+ }
1814
+ }
1815
+ return Array.from(aliases);
1816
+ }
1817
+ async function resolveProviderSelectedManifestSnapshot(context) {
1818
+ const claim = selectProviderIntakeClaim(context.providerIntakeState);
1819
+ if (!claim?.run_manifest_path) {
1820
+ return null;
1821
+ }
1822
+ const preferredSnapshot = await readManifestSnapshotForPath(claim.run_manifest_path);
1823
+ if (!preferredSnapshot) {
1824
+ return null;
1825
+ }
1826
+ const currentTaskId = resolveTaskIdFromManifestPath(context.paths.manifestPath);
1827
+ const currentRunId = resolveRunIdFromManifestPath(context.paths.manifestPath);
1828
+ if (currentTaskId === 'local-mcp' && currentRunId === 'control-host') {
1829
+ return preferredSnapshot;
1830
+ }
1831
+ const providerControlHostTaskId = readStringValue(preferredSnapshot.manifestRecord, 'provider_control_host_task_id');
1832
+ const providerControlHostRunId = readStringValue(preferredSnapshot.manifestRecord, 'provider_control_host_run_id');
1833
+ if (providerControlHostTaskId !== currentTaskId ||
1834
+ providerControlHostRunId !== currentRunId) {
1835
+ return null;
1836
+ }
1837
+ return preferredSnapshot;
1838
+ }