@kbediako/codex-orchestrator 0.1.38 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +46 -317
  3. package/bin/codex-orchestrator.js +161 -0
  4. package/codex.orchestrator.json +149 -13
  5. package/dist/bin/codex-orchestrator.js +797 -1154
  6. package/dist/orchestrator/src/cli/adapters/CommandBuilder.js +50 -0
  7. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
  8. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
  9. package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
  10. package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +295 -11
  11. package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
  12. package/dist/orchestrator/src/cli/coStatusCliShell.js +451 -0
  13. package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
  14. package/dist/orchestrator/src/cli/codexCliShell.js +119 -0
  15. package/dist/orchestrator/src/cli/codexDefaultsSetup.js +265 -36
  16. package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
  17. package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
  18. package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
  19. package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
  20. package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
  21. package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
  22. package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
  23. package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
  24. package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
  25. package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
  26. package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
  27. package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
  28. package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
  29. package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
  30. package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
  31. package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
  32. package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
  33. package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
  34. package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
  35. package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
  36. package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
  37. package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
  38. package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
  39. package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
  40. package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
  41. package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
  42. package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
  43. package/dist/orchestrator/src/cli/control/controlHostSupervision.js +630 -0
  44. package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
  45. package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
  46. package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
  47. package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
  48. package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
  49. package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
  50. package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
  51. package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
  52. package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
  53. package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
  54. package/dist/orchestrator/src/cli/control/controlRuntime.js +1003 -0
  55. package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
  56. package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
  57. package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
  58. package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
  59. package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
  60. package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
  61. package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
  62. package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
  63. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
  64. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
  65. package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
  66. package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
  67. package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
  68. package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
  69. package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
  70. package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
  71. package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
  72. package/dist/orchestrator/src/cli/control/controlState.js +233 -2
  73. package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1904 -0
  74. package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
  75. package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
  76. package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
  77. package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
  78. package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
  79. package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
  80. package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
  81. package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
  82. package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
  83. package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
  84. package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
  85. package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
  86. package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
  87. package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
  88. package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
  89. package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
  90. package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
  91. package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
  92. package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
  93. package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
  94. package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
  95. package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
  96. package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
  97. package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
  98. package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
  99. package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
  100. package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
  101. package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
  102. package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
  103. package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
  104. package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
  105. package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
  106. package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
  107. package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
  108. package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
  109. package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
  110. package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
  111. package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
  112. package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
  113. package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
  114. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
  115. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
  116. package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
  117. package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
  118. package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
  119. package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
  120. package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
  121. package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
  122. package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
  123. package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
  124. package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
  125. package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1885 -0
  126. package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
  127. package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
  128. package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
  129. package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
  130. package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
  131. package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
  132. package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
  133. package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
  134. package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
  135. package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
  136. package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
  137. package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
  138. package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
  139. package/dist/orchestrator/src/cli/delegationServer.js +567 -678
  140. package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
  141. package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
  142. package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
  143. package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
  144. package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
  145. package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
  146. package/dist/orchestrator/src/cli/doctor.js +678 -164
  147. package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
  148. package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
  149. package/dist/orchestrator/src/cli/doctorUsage.js +119 -15
  150. package/dist/orchestrator/src/cli/exec/experience.js +16 -2
  151. package/dist/orchestrator/src/cli/exec/summary.js +3 -0
  152. package/dist/orchestrator/src/cli/execCliShell.js +51 -0
  153. package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
  154. package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
  155. package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
  156. package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
  157. package/dist/orchestrator/src/cli/init.js +95 -1
  158. package/dist/orchestrator/src/cli/initCliShell.js +50 -0
  159. package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
  160. package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
  161. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
  162. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
  163. package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
  164. package/dist/orchestrator/src/cli/planCliShell.js +19 -0
  165. package/dist/orchestrator/src/cli/prCliShell.js +41 -0
  166. package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
  167. package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1835 -0
  168. package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
  169. package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
  170. package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +6834 -0
  171. package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
  172. package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
  173. package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
  174. package/dist/orchestrator/src/cli/rlm/context.js +94 -7
  175. package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
  176. package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
  177. package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
  178. package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
  179. package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
  180. package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
  181. package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
  182. package/dist/orchestrator/src/cli/run/manifest.js +410 -73
  183. package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
  184. package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
  185. package/dist/orchestrator/src/cli/run/source0.js +690 -0
  186. package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
  187. package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
  188. package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
  189. package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
  190. package/dist/orchestrator/src/cli/services/commandRunner.js +698 -18
  191. package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
  192. package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
  193. package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
  194. package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
  195. package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
  196. package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
  197. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
  198. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
  199. package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
  200. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
  201. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
  202. package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
  203. package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
  204. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
  205. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
  206. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
  207. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
  208. package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
  209. package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
  210. package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
  211. package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
  212. package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
  213. package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
  214. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
  215. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
  216. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
  217. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
  218. package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
  219. package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
  220. package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
  221. package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
  222. package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
  223. package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
  224. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
  225. package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
  226. package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
  227. package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
  228. package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
  229. package/dist/orchestrator/src/cli/startCliShell.js +68 -0
  230. package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
  231. package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
  232. package/dist/orchestrator/src/cli/utils/cloudPreflight.js +285 -7
  233. package/dist/orchestrator/src/cli/utils/codexFeatures.js +60 -0
  234. package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
  235. package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
  236. package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
  237. package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
  238. package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
  239. package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
  240. package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
  241. package/dist/orchestrator/src/learning/crystalizer.js +2 -2
  242. package/dist/orchestrator/src/manager.js +74 -4
  243. package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
  244. package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
  245. package/dist/orchestrator/src/persistence/lockFile.js +70 -4
  246. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
  247. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
  248. package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
  249. package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
  250. package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
  251. package/dist/packages/sdk-node/src/orchestrator.js +137 -13
  252. package/dist/packages/shared/config/designConfig.js +8 -1
  253. package/dist/packages/shared/streams/stdio.js +1 -1
  254. package/dist/scripts/design/pipeline/permit.js +15 -0
  255. package/dist/scripts/lib/docs-catalog.js +399 -0
  256. package/dist/scripts/lib/docs-helpers.js +87 -5
  257. package/dist/scripts/lib/pr-watch-merge.js +1088 -80
  258. package/dist/scripts/lib/provider-run-contract.js +26 -0
  259. package/dist/scripts/lib/review-command-intent-classification.js +532 -0
  260. package/dist/scripts/lib/review-command-probe-classification.js +385 -0
  261. package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
  262. package/dist/scripts/lib/review-execution-runtime.js +753 -0
  263. package/dist/scripts/lib/review-execution-state.js +1144 -0
  264. package/dist/scripts/lib/review-execution-telemetry.js +215 -0
  265. package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
  266. package/dist/scripts/lib/review-launch-attempt.js +601 -0
  267. package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
  268. package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
  269. package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
  270. package/dist/scripts/lib/review-prompt-context.js +376 -0
  271. package/dist/scripts/lib/review-scope-advisory.js +286 -0
  272. package/dist/scripts/lib/review-scope-paths.js +123 -0
  273. package/dist/scripts/lib/review-shell-command-parser.js +389 -0
  274. package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
  275. package/dist/scripts/lib/run-manifests.js +192 -36
  276. package/dist/scripts/lib/spark-policy-classifier.js +593 -0
  277. package/dist/scripts/run-review.js +507 -1777
  278. package/docs/README.md +43 -20
  279. package/docs/book/README.md +19 -0
  280. package/docs/book/codex-cli-0124-adoption.md +68 -0
  281. package/docs/book/local-hook-impact.md +73 -0
  282. package/docs/book/operations.md +60 -0
  283. package/docs/book/public-posture.md +34 -0
  284. package/docs/book/setup.md +91 -0
  285. package/docs/book/skills.md +11 -0
  286. package/docs/guides/codex-version-policy.md +104 -0
  287. package/docs/public/downstream-setup.md +113 -0
  288. package/docs/public/provider-onboarding.md +173 -0
  289. package/package.json +23 -10
  290. package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
  291. package/plugins/codex-orchestrator/.mcp.json +13 -0
  292. package/plugins/codex-orchestrator/launcher.mjs +361 -0
  293. package/schemas/manifest.json +411 -0
  294. package/skills/README.md +26 -0
  295. package/skills/collab-subagents-first/SKILL.md +1 -1
  296. package/skills/delegation-usage/DELEGATION_GUIDE.md +30 -12
  297. package/skills/delegation-usage/SKILL.md +25 -14
  298. package/skills/land/SKILL.md +77 -0
  299. package/skills/linear/SKILL.md +255 -0
  300. package/skills/release/SKILL.md +47 -3
  301. package/skills/standalone-review/SKILL.md +6 -1
  302. package/templates/README.md +4 -2
  303. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  304. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  305. package/templates/codex/.codex/config.toml +3 -4
  306. package/templates/codex/.codex/providers/README.md +13 -0
  307. package/templates/codex/.codex/providers/control.example.json +18 -0
  308. package/templates/codex/.codex/providers/provider.env.example +15 -0
  309. package/templates/codex/AGENTS.md +15 -8
  310. package/templates/codex/mcp-client.json +5 -1
  311. package/docs/assets/setup.gif +0 -0
@@ -0,0 +1,1137 @@
1
+ import { executeLinearGraphql, resolveLinearApiToken, resolveLinearRequestTimeoutMs } from './linearGraphqlClient.js';
2
+ import { recordLinearBudgetHeadersObservation, recordLinearBudgetRateLimitObservation, readSharedLinearBudgetStatus, reserveLinearBudgetReservation, resolveLinearBudgetPreflight } from './linearBudgetState.js';
3
+ import { mapLinearRateLimitedFailure } from './linearRateLimit.js';
4
+ import { isProviderLinearTrackedIssueEligibleForExecution, normalizeProviderLinearWorkflowState } from './providerLinearWorkflowStates.js';
5
+ const LINEAR_RECENT_ACTIVITY_LIMIT = 3;
6
+ const LINEAR_BLOCKER_LIMIT = 50;
7
+ const LINEAR_INVERSE_RELATION_MAX_PAGES = 20;
8
+ const DEFAULT_LINEAR_TRACKED_ISSUE_PAGE_SIZE = 50;
9
+ const LINEAR_FRESH_DISCOVERY_PRIORITY_BUCKETS = [1, 2, 3, 4, 0];
10
+ export async function resolveLiveLinearDispatchRecommendation(input) {
11
+ const confidence = readNumberValue(input.source, 'confidence', 'score') ?? null;
12
+ if (confidence !== null && (confidence < 0 || confidence > 1)) {
13
+ return malformed('dispatch_source_confidence_out_of_range');
14
+ }
15
+ const trackedIssuesResolution = await resolveLiveLinearTrackedIssues({
16
+ sourceSetup: input.sourceSetup,
17
+ env: input.env,
18
+ fetchImpl: input.fetchImpl,
19
+ limit: DEFAULT_LINEAR_TRACKED_ISSUE_PAGE_SIZE
20
+ });
21
+ if (trackedIssuesResolution.kind !== 'ready') {
22
+ return trackedIssuesResolution;
23
+ }
24
+ const trackedIssue = trackedIssuesResolution.tracked_issues.find(isLiveLinearTrackedIssueEligibleForFreshDispatch) ??
25
+ null;
26
+ if (!trackedIssue) {
27
+ return unavailable('dispatch_source_issue_not_found');
28
+ }
29
+ return {
30
+ kind: 'ready',
31
+ summary: readStringValue(input.source, 'summary', 'dispatch_summary', 'dispatchSummary') ??
32
+ `Review Linear advisory ${trackedIssue.identifier}: ${trackedIssue.title}`,
33
+ rationale: readStringValue(input.source, 'rationale', 'reason') ??
34
+ buildDefaultRationale(trackedIssue, input.defaultIssueIdentifier ?? null),
35
+ confidence,
36
+ dispatch_id: readStringValue(input.source, 'dispatch_id', 'dispatchId') ?? 'dispatch-advisory-live-linear',
37
+ generated_at: new Date().toISOString(),
38
+ source_setup: {
39
+ provider: 'linear',
40
+ workspace_id: trackedIssue.workspace_id,
41
+ team_id: trackedIssue.team_id,
42
+ project_id: trackedIssue.project_id
43
+ },
44
+ tracked_issue: trackedIssue
45
+ };
46
+ }
47
+ export async function resolveLiveLinearTrackedIssueById(input) {
48
+ const issueId = normalizeEnvValue(input.issueId);
49
+ if (!issueId) {
50
+ return malformed('dispatch_source_issue_id_missing');
51
+ }
52
+ const env = input.env ?? process.env;
53
+ const fetchImpl = input.fetchImpl ?? fetch;
54
+ const token = resolveLinearApiToken(env);
55
+ if (!token) {
56
+ return unavailable('dispatch_source_credentials_missing');
57
+ }
58
+ const timeoutMs = resolveLinearRequestTimeoutMs(env);
59
+ const sourceSetup = input.sourceSetup ? resolveLinearSourceSetup(input.sourceSetup, env) : null;
60
+ if (input.sourceSetup && !sourceSetup?.workspace_id && !sourceSetup?.team_id && !sourceSetup?.project_id) {
61
+ return malformed('dispatch_source_binding_missing');
62
+ }
63
+ const query = buildLinearIssueByIdQuery(issueId);
64
+ const queryResult = await executeLinearQuery({
65
+ env,
66
+ token,
67
+ timeoutMs,
68
+ fetchImpl,
69
+ source: 'dispatch_source_issue_by_id',
70
+ query: query.query,
71
+ variables: query.variables
72
+ });
73
+ if (!queryResult.ok) {
74
+ return queryResult.resolution;
75
+ }
76
+ const workspaceId = queryResult.payload.data?.viewer?.organization?.id?.trim() ?? null;
77
+ if (sourceSetup?.workspace_id && workspaceId && sourceSetup.workspace_id !== workspaceId) {
78
+ return malformed('dispatch_source_workspace_mismatch');
79
+ }
80
+ const issue = queryResult.payload.data?.issue ?? null;
81
+ if (!issue) {
82
+ return unavailable('dispatch_source_issue_not_found');
83
+ }
84
+ const hydratedIssue = await hydratePaginatedIssueInverseRelations({
85
+ issue,
86
+ env,
87
+ token,
88
+ timeoutMs,
89
+ fetchImpl,
90
+ source: 'dispatch_source_issue_by_id_inverse_relations'
91
+ });
92
+ if (!hydratedIssue.ok) {
93
+ return hydratedIssue.resolution;
94
+ }
95
+ const trackedIssue = parseTrackedIssue(hydratedIssue.issue, {
96
+ workspaceId: sourceSetup?.workspace_id ?? workspaceId,
97
+ viewerId: queryResult.payload.data?.viewer?.id?.trim() ?? null
98
+ });
99
+ if (!trackedIssue) {
100
+ return malformed('dispatch_source_provider_response_invalid');
101
+ }
102
+ if (sourceSetup) {
103
+ const scopeMismatch = validateTrackedIssueScope(trackedIssue, sourceSetup);
104
+ if (scopeMismatch) {
105
+ return scopeMismatch;
106
+ }
107
+ }
108
+ return {
109
+ kind: 'ready',
110
+ tracked_issue: trackedIssue,
111
+ source_setup: {
112
+ provider: 'linear',
113
+ workspace_id: trackedIssue.workspace_id,
114
+ team_id: trackedIssue.team_id,
115
+ project_id: trackedIssue.project_id
116
+ }
117
+ };
118
+ }
119
+ export async function resolveLiveLinearTrackedIssues(input) {
120
+ const env = input.env ?? process.env;
121
+ const fetchImpl = input.fetchImpl ?? fetch;
122
+ const token = resolveLinearApiToken(env);
123
+ if (!token) {
124
+ return unavailable('dispatch_source_credentials_missing');
125
+ }
126
+ const timeoutMs = resolveLinearRequestTimeoutMs(env);
127
+ const sourceSetup = resolveLinearSourceSetup(input.sourceSetup, env);
128
+ if (!sourceSetup.workspace_id && !sourceSetup.team_id && !sourceSetup.project_id) {
129
+ return malformed('dispatch_source_binding_missing');
130
+ }
131
+ const queryMode = resolveLiveLinearTrackedIssuesQueryMode(input.queryMode);
132
+ const eligibleIssueTargetCount = resolveEligibleIssueTargetCount({
133
+ stopWhenEligibleForExecution: input.stopWhenEligibleForExecution,
134
+ eligibleIssueTargetCount: input.eligibleIssueTargetCount
135
+ });
136
+ const eligibleStateSlotCounts = normalizeEligibleStateSlotCounts(input.eligibleStateSlotCounts);
137
+ const excludedIssueIds = new Set(input.excludedIssueIds ?? []);
138
+ if (queryMode === 'fresh_discovery') {
139
+ return await resolveFreshDiscoveryTrackedIssues({
140
+ sourceSetup,
141
+ env,
142
+ token,
143
+ timeoutMs,
144
+ fetchImpl,
145
+ limit: input.limit,
146
+ eligibleIssueTargetCount,
147
+ eligibleStateSlotCounts,
148
+ excludedIssueIds,
149
+ sortForDispatch: input.sortForDispatch !== false
150
+ });
151
+ }
152
+ const trackedIssues = [];
153
+ const seenIssueIds = new Set();
154
+ let workspaceId = null;
155
+ let afterCursor = null;
156
+ let hasNextPage = true;
157
+ let eligibleIssueCount = 0;
158
+ const consumedEligibleStateSlots = new Map();
159
+ while (hasNextPage) {
160
+ const query = buildLinearTrackedIssuesQuery(sourceSetup, input.limit, afterCursor, queryMode);
161
+ const queryResult = await executeLinearQuery({
162
+ env,
163
+ token,
164
+ timeoutMs,
165
+ fetchImpl,
166
+ source: resolveTrackedIssuesQuerySource(queryMode),
167
+ query: query.query,
168
+ variables: query.variables
169
+ });
170
+ if (!queryResult.ok) {
171
+ return queryResult.resolution;
172
+ }
173
+ const responseWorkspaceId = queryResult.payload.data?.viewer?.organization?.id?.trim() ?? null;
174
+ if (workspaceId === null) {
175
+ workspaceId = responseWorkspaceId;
176
+ }
177
+ if (sourceSetup.workspace_id && responseWorkspaceId && sourceSetup.workspace_id !== responseWorkspaceId) {
178
+ return malformed('dispatch_source_workspace_mismatch');
179
+ }
180
+ const nodes = Array.isArray(queryResult.payload.data?.issues?.nodes)
181
+ ? queryResult.payload.data?.issues?.nodes ?? []
182
+ : [];
183
+ let stopScanning = false;
184
+ for (const node of nodes) {
185
+ const hydratedIssue = await hydratePaginatedIssueInverseRelations({
186
+ issue: node ?? {},
187
+ env,
188
+ token,
189
+ timeoutMs,
190
+ fetchImpl,
191
+ source: `${resolveTrackedIssuesQuerySource(queryMode)}_inverse_relations`
192
+ });
193
+ if (!hydratedIssue.ok) {
194
+ return hydratedIssue.resolution;
195
+ }
196
+ const trackedIssue = parseTrackedIssue(hydratedIssue.issue, {
197
+ workspaceId: sourceSetup.workspace_id ?? workspaceId,
198
+ viewerId: queryResult.payload.data?.viewer?.id?.trim() ?? null
199
+ });
200
+ if (!trackedIssue) {
201
+ continue;
202
+ }
203
+ const scopeMismatch = validateTrackedIssueScope(trackedIssue, sourceSetup);
204
+ if (scopeMismatch) {
205
+ return scopeMismatch;
206
+ }
207
+ if (seenIssueIds.has(trackedIssue.id)) {
208
+ continue;
209
+ }
210
+ seenIssueIds.add(trackedIssue.id);
211
+ trackedIssues.push(trackedIssue);
212
+ if (!excludedIssueIds.has(trackedIssue.id) &&
213
+ shouldCountTrackedIssueTowardEligibilityTarget(trackedIssue, eligibleStateSlotCounts, consumedEligibleStateSlots)) {
214
+ eligibleIssueCount += 1;
215
+ }
216
+ if (eligibleIssueTargetCount !== null &&
217
+ eligibleIssueCount >= eligibleIssueTargetCount) {
218
+ stopScanning = true;
219
+ break;
220
+ }
221
+ }
222
+ if (stopScanning) {
223
+ hasNextPage = false;
224
+ continue;
225
+ }
226
+ const nextCursor = resolveLinearTrackedIssuesNextCursor(queryResult.payload.data?.issues?.pageInfo ?? null, queryMode);
227
+ if (nextCursor === null) {
228
+ hasNextPage = false;
229
+ continue;
230
+ }
231
+ if (nextCursor === undefined) {
232
+ return malformed('dispatch_source_provider_response_invalid');
233
+ }
234
+ afterCursor = nextCursor;
235
+ }
236
+ return {
237
+ kind: 'ready',
238
+ tracked_issues: input.sortForDispatch === false
239
+ ? trackedIssues
240
+ : sortLiveLinearTrackedIssuesForDispatch(trackedIssues),
241
+ source_setup: sourceSetup
242
+ };
243
+ }
244
+ async function resolveFreshDiscoveryTrackedIssues(input) {
245
+ const trackedIssues = [];
246
+ const seenIssueIds = new Set();
247
+ let workspaceId = null;
248
+ let eligibleIssueCount = 0;
249
+ const consumedEligibleStateSlots = new Map();
250
+ for (const priorityBucket of LINEAR_FRESH_DISCOVERY_PRIORITY_BUCKETS) {
251
+ let beforeCursor = null;
252
+ let hasPreviousPage = true;
253
+ while (hasPreviousPage) {
254
+ const query = buildLinearTrackedIssuesQuery(input.sourceSetup, input.limit, beforeCursor, 'fresh_discovery', priorityBucket);
255
+ const queryResult = await executeLinearQuery({
256
+ env: input.env,
257
+ token: input.token,
258
+ timeoutMs: input.timeoutMs,
259
+ fetchImpl: input.fetchImpl,
260
+ source: resolveTrackedIssuesQuerySource('fresh_discovery'),
261
+ query: query.query,
262
+ variables: query.variables
263
+ });
264
+ if (!queryResult.ok) {
265
+ return queryResult.resolution;
266
+ }
267
+ const responseWorkspaceId = queryResult.payload.data?.viewer?.organization?.id?.trim() ?? null;
268
+ if (workspaceId === null) {
269
+ workspaceId = responseWorkspaceId;
270
+ }
271
+ if (input.sourceSetup.workspace_id &&
272
+ responseWorkspaceId &&
273
+ input.sourceSetup.workspace_id !== responseWorkspaceId) {
274
+ return malformed('dispatch_source_workspace_mismatch');
275
+ }
276
+ const nodes = Array.isArray(queryResult.payload.data?.issues?.nodes)
277
+ ? queryResult.payload.data?.issues?.nodes ?? []
278
+ : [];
279
+ let stopScanning = false;
280
+ for (const node of nodes) {
281
+ const hydratedIssue = await hydratePaginatedIssueInverseRelations({
282
+ issue: node ?? {},
283
+ env: input.env,
284
+ token: input.token,
285
+ timeoutMs: input.timeoutMs,
286
+ fetchImpl: input.fetchImpl,
287
+ source: 'dispatch_source_fresh_discovery_inverse_relations'
288
+ });
289
+ if (!hydratedIssue.ok) {
290
+ return hydratedIssue.resolution;
291
+ }
292
+ const trackedIssue = parseTrackedIssue(hydratedIssue.issue, {
293
+ workspaceId: input.sourceSetup.workspace_id ?? workspaceId,
294
+ viewerId: queryResult.payload.data?.viewer?.id?.trim() ?? null
295
+ });
296
+ if (!trackedIssue) {
297
+ continue;
298
+ }
299
+ const scopeMismatch = validateTrackedIssueScope(trackedIssue, input.sourceSetup);
300
+ if (scopeMismatch) {
301
+ return scopeMismatch;
302
+ }
303
+ if (seenIssueIds.has(trackedIssue.id)) {
304
+ continue;
305
+ }
306
+ seenIssueIds.add(trackedIssue.id);
307
+ trackedIssues.push(trackedIssue);
308
+ if (!input.excludedIssueIds.has(trackedIssue.id) &&
309
+ shouldCountTrackedIssueTowardEligibilityTarget(trackedIssue, input.eligibleStateSlotCounts, consumedEligibleStateSlots)) {
310
+ eligibleIssueCount += 1;
311
+ }
312
+ if (input.eligibleIssueTargetCount !== null &&
313
+ eligibleIssueCount >= input.eligibleIssueTargetCount) {
314
+ stopScanning = true;
315
+ break;
316
+ }
317
+ }
318
+ if (stopScanning) {
319
+ return {
320
+ kind: 'ready',
321
+ tracked_issues: input.sortForDispatch
322
+ ? sortLiveLinearTrackedIssuesForDispatch(trackedIssues)
323
+ : trackedIssues,
324
+ source_setup: input.sourceSetup
325
+ };
326
+ }
327
+ const nextCursor = resolveLinearTrackedIssuesNextCursor(queryResult.payload.data?.issues?.pageInfo ?? null, 'fresh_discovery');
328
+ if (nextCursor === null) {
329
+ hasPreviousPage = false;
330
+ continue;
331
+ }
332
+ if (nextCursor === undefined) {
333
+ return malformed('dispatch_source_provider_response_invalid');
334
+ }
335
+ beforeCursor = nextCursor;
336
+ }
337
+ }
338
+ return {
339
+ kind: 'ready',
340
+ tracked_issues: input.sortForDispatch
341
+ ? sortLiveLinearTrackedIssuesForDispatch(trackedIssues)
342
+ : trackedIssues,
343
+ source_setup: input.sourceSetup
344
+ };
345
+ }
346
+ export function sortLiveLinearTrackedIssuesForDispatch(trackedIssues) {
347
+ return [...trackedIssues].sort((left, right) => {
348
+ const priorityDiff = resolveTrackedIssuePriorityRank(left) - resolveTrackedIssuePriorityRank(right);
349
+ if (priorityDiff !== 0) {
350
+ return priorityDiff;
351
+ }
352
+ const createdAtDiff = resolveTrackedIssueCreatedAtSortKey(left) - resolveTrackedIssueCreatedAtSortKey(right);
353
+ if (createdAtDiff !== 0) {
354
+ return createdAtDiff;
355
+ }
356
+ return left.identifier.localeCompare(right.identifier);
357
+ });
358
+ }
359
+ export function isLiveLinearTrackedIssueOwnedByCurrentViewerOrUnassigned(issue) {
360
+ if (issue.assignee_id === null) {
361
+ return true;
362
+ }
363
+ return (typeof issue.viewer_id === 'string' &&
364
+ issue.viewer_id.length > 0 &&
365
+ issue.assignee_id === issue.viewer_id);
366
+ }
367
+ export function isLiveLinearTrackedIssueEligibleForFreshDispatch(issue) {
368
+ return (isProviderLinearTrackedIssueEligibleForExecution(issue) &&
369
+ isLiveLinearTrackedIssueOwnedByCurrentViewerOrUnassigned(issue));
370
+ }
371
+ function buildLinearTrackedIssuesQuery(sourceSetup, limit, cursor, queryMode, priorityBucket) {
372
+ const discoveryMode = queryMode === 'fresh_discovery';
373
+ const variableDefinitions = ['$limit: Int!', discoveryMode ? '$before: String' : '$after: String'];
374
+ const filterParts = [];
375
+ const variables = {
376
+ limit: normalizeLinearTrackedIssueLimit(limit),
377
+ ...(discoveryMode ? { before: cursor } : { after: cursor })
378
+ };
379
+ if (sourceSetup.team_id) {
380
+ variableDefinitions.push('$teamId: ID!');
381
+ filterParts.push('team: { id: { eq: $teamId } }');
382
+ variables.teamId = sourceSetup.team_id;
383
+ }
384
+ if (sourceSetup.project_id) {
385
+ variableDefinitions.push('$projectId: ID!');
386
+ filterParts.push('project: { id: { eq: $projectId } }');
387
+ variables.projectId = sourceSetup.project_id;
388
+ }
389
+ filterParts.push('state: { type: { nin: ["completed", "canceled"] } }');
390
+ if (discoveryMode) {
391
+ if (priorityBucket === 0) {
392
+ filterParts.push('priority: { eq: 0 }');
393
+ }
394
+ else if (priorityBucket !== undefined) {
395
+ variableDefinitions.push('$priority: Float!');
396
+ filterParts.push('priority: { eq: $priority }');
397
+ variables.priority = priorityBucket;
398
+ }
399
+ }
400
+ const variableSection = `(${variableDefinitions.join(', ')})`;
401
+ const filterSection = `, filter: { ${filterParts.join(' ')} }`;
402
+ const includeRichIssueDetails = queryMode !== 'fresh_discovery';
403
+ const orderBy = queryMode === 'fresh_discovery' ? 'createdAt' : 'updatedAt';
404
+ const paginationClause = discoveryMode
405
+ ? 'last: $limit, before: $before'
406
+ : 'first: $limit, after: $after';
407
+ return {
408
+ query: `query ResolveLiveLinearTrackedIssues${variableSection} {
409
+ viewer {
410
+ id
411
+ organization {
412
+ id
413
+ }
414
+ }
415
+ issues(orderBy: ${orderBy}, ${paginationClause}${filterSection}) {
416
+ nodes {
417
+ id
418
+ identifier
419
+ title
420
+ url
421
+ priority
422
+ createdAt
423
+ updatedAt
424
+ archivedAt
425
+ trashed
426
+ ${includeRichIssueDetails ? 'description' : ''}
427
+ assignee {
428
+ id
429
+ name
430
+ displayName
431
+ }
432
+ state {
433
+ name
434
+ type
435
+ }
436
+ team {
437
+ id
438
+ key
439
+ name
440
+ }
441
+ project {
442
+ id
443
+ name
444
+ }
445
+ inverseRelations(first: ${LINEAR_BLOCKER_LIMIT}) {
446
+ nodes {
447
+ type
448
+ issue {
449
+ id
450
+ identifier
451
+ state {
452
+ name
453
+ type
454
+ }
455
+ }
456
+ }
457
+ pageInfo {
458
+ hasNextPage
459
+ endCursor
460
+ }
461
+ }
462
+ relations(first: ${LINEAR_BLOCKER_LIMIT}) {
463
+ nodes {
464
+ type
465
+ relatedIssue {
466
+ id
467
+ identifier
468
+ state {
469
+ name
470
+ type
471
+ }
472
+ }
473
+ }
474
+ pageInfo {
475
+ hasNextPage
476
+ }
477
+ }
478
+ ${includeRichIssueDetails
479
+ ? `history(first: ${LINEAR_RECENT_ACTIVITY_LIMIT}) {
480
+ nodes {
481
+ id
482
+ createdAt
483
+ actor {
484
+ name
485
+ displayName
486
+ }
487
+ fromState {
488
+ name
489
+ }
490
+ toState {
491
+ name
492
+ }
493
+ fromProject {
494
+ name
495
+ }
496
+ toProject {
497
+ name
498
+ }
499
+ fromTitle
500
+ toTitle
501
+ }
502
+ }`
503
+ : ''}
504
+ }
505
+ pageInfo {
506
+ hasNextPage
507
+ endCursor
508
+ hasPreviousPage
509
+ startCursor
510
+ }
511
+ }
512
+ }`,
513
+ variables
514
+ };
515
+ }
516
+ function resolveLiveLinearTrackedIssuesQueryMode(mode) {
517
+ if (mode === 'recovery_sweep' || mode === 'fresh_discovery') {
518
+ return mode;
519
+ }
520
+ return 'full';
521
+ }
522
+ function resolveEligibleIssueTargetCount(input) {
523
+ if (typeof input.eligibleIssueTargetCount === 'number' &&
524
+ Number.isInteger(input.eligibleIssueTargetCount) &&
525
+ input.eligibleIssueTargetCount > 0) {
526
+ return input.eligibleIssueTargetCount;
527
+ }
528
+ return input.stopWhenEligibleForExecution === true ? 1 : null;
529
+ }
530
+ function normalizeEligibleStateSlotCounts(input) {
531
+ const normalized = new Map();
532
+ if (!input) {
533
+ return normalized;
534
+ }
535
+ for (const [rawState, rawCount] of Object.entries(input)) {
536
+ const state = normalizeProviderLinearWorkflowState(rawState);
537
+ if (!state || !Number.isInteger(rawCount) || rawCount < 0) {
538
+ continue;
539
+ }
540
+ normalized.set(state, rawCount);
541
+ }
542
+ return normalized;
543
+ }
544
+ function shouldCountTrackedIssueTowardEligibilityTarget(trackedIssue, eligibleStateSlotCounts, consumedEligibleStateSlots) {
545
+ if (!isLiveLinearTrackedIssueEligibleForFreshDispatch(trackedIssue)) {
546
+ return false;
547
+ }
548
+ const normalizedState = normalizeProviderLinearWorkflowState(trackedIssue.state);
549
+ if (!normalizedState) {
550
+ return true;
551
+ }
552
+ const stateLimit = eligibleStateSlotCounts.get(normalizedState);
553
+ if (stateLimit === undefined) {
554
+ return true;
555
+ }
556
+ const consumed = consumedEligibleStateSlots.get(normalizedState) ?? 0;
557
+ if (consumed >= stateLimit) {
558
+ return false;
559
+ }
560
+ consumedEligibleStateSlots.set(normalizedState, consumed + 1);
561
+ return true;
562
+ }
563
+ function resolveTrackedIssuesQuerySource(queryMode) {
564
+ if (queryMode === 'recovery_sweep') {
565
+ return 'dispatch_source_tracked_issues:recovery_sweep';
566
+ }
567
+ if (queryMode === 'fresh_discovery') {
568
+ return 'dispatch_source_tracked_issues:fresh_discovery';
569
+ }
570
+ return 'dispatch_source_tracked_issues';
571
+ }
572
+ function buildLinearIssueByIdQuery(issueId) {
573
+ return {
574
+ query: `query ResolveLiveLinearTrackedIssueById($issueId: String!) {
575
+ viewer {
576
+ id
577
+ organization {
578
+ id
579
+ }
580
+ }
581
+ issue(id: $issueId) {
582
+ id
583
+ identifier
584
+ title
585
+ description
586
+ url
587
+ updatedAt
588
+ archivedAt
589
+ trashed
590
+ assignee {
591
+ id
592
+ name
593
+ displayName
594
+ }
595
+ state {
596
+ name
597
+ type
598
+ }
599
+ team {
600
+ id
601
+ key
602
+ name
603
+ }
604
+ project {
605
+ id
606
+ name
607
+ }
608
+ inverseRelations(first: ${LINEAR_BLOCKER_LIMIT}) {
609
+ nodes {
610
+ type
611
+ issue {
612
+ id
613
+ identifier
614
+ state {
615
+ name
616
+ type
617
+ }
618
+ }
619
+ }
620
+ pageInfo {
621
+ hasNextPage
622
+ endCursor
623
+ }
624
+ }
625
+ relations(first: ${LINEAR_BLOCKER_LIMIT}) {
626
+ nodes {
627
+ type
628
+ relatedIssue {
629
+ id
630
+ identifier
631
+ state {
632
+ name
633
+ type
634
+ }
635
+ }
636
+ }
637
+ pageInfo {
638
+ hasNextPage
639
+ }
640
+ }
641
+ history(first: ${LINEAR_RECENT_ACTIVITY_LIMIT}) {
642
+ nodes {
643
+ id
644
+ createdAt
645
+ actor {
646
+ name
647
+ displayName
648
+ }
649
+ fromState {
650
+ name
651
+ }
652
+ toState {
653
+ name
654
+ }
655
+ fromProject {
656
+ name
657
+ }
658
+ toProject {
659
+ name
660
+ }
661
+ fromTitle
662
+ toTitle
663
+ }
664
+ }
665
+ }
666
+ }`,
667
+ variables: {
668
+ issueId
669
+ }
670
+ };
671
+ }
672
+ function buildLinearIssueInverseRelationsPageQuery(issueId, afterCursor) {
673
+ return {
674
+ query: `query ResolveLiveLinearIssueInverseRelationsPage($issueId: String!, $after: String!) {
675
+ issue(id: $issueId) {
676
+ id
677
+ inverseRelations(first: ${LINEAR_BLOCKER_LIMIT}, after: $after) {
678
+ nodes {
679
+ type
680
+ issue {
681
+ id
682
+ identifier
683
+ state {
684
+ name
685
+ type
686
+ }
687
+ }
688
+ }
689
+ pageInfo {
690
+ hasNextPage
691
+ endCursor
692
+ }
693
+ }
694
+ }
695
+ }`,
696
+ variables: {
697
+ issueId,
698
+ after: afterCursor
699
+ }
700
+ };
701
+ }
702
+ async function hydratePaginatedIssueInverseRelations(input) {
703
+ const connection = input.issue.inverseRelations;
704
+ if (connection?.pageInfo?.hasNextPage !== true) {
705
+ return {
706
+ ok: true,
707
+ issue: input.issue
708
+ };
709
+ }
710
+ const issueId = normalizeEnvValue(input.issue.id);
711
+ let afterCursor = normalizeEnvValue(connection.pageInfo.endCursor);
712
+ const firstPageNodes = Array.isArray(connection.nodes) ? connection.nodes : [];
713
+ if (!issueId || !afterCursor || !Array.isArray(connection.nodes)) {
714
+ return {
715
+ ok: true,
716
+ issue: buildTruncatedInverseRelationsIssue(input.issue, firstPageNodes)
717
+ };
718
+ }
719
+ const nodes = [...firstPageNodes];
720
+ let hasNextPage = true;
721
+ let pagesRead = 0;
722
+ while (hasNextPage && pagesRead < LINEAR_INVERSE_RELATION_MAX_PAGES) {
723
+ if (!afterCursor) {
724
+ return {
725
+ ok: true,
726
+ issue: buildTruncatedInverseRelationsIssue(input.issue, nodes)
727
+ };
728
+ }
729
+ const query = buildLinearIssueInverseRelationsPageQuery(issueId, afterCursor);
730
+ const queryResult = await executeLinearQuery({
731
+ env: input.env,
732
+ token: input.token,
733
+ timeoutMs: input.timeoutMs,
734
+ fetchImpl: input.fetchImpl,
735
+ source: input.source,
736
+ query: query.query,
737
+ variables: query.variables
738
+ });
739
+ if (!queryResult.ok) {
740
+ return {
741
+ ok: true,
742
+ issue: buildTruncatedInverseRelationsIssue(input.issue, nodes)
743
+ };
744
+ }
745
+ const nextConnection = queryResult.payload.data?.issue?.inverseRelations ?? null;
746
+ if (!Array.isArray(nextConnection?.nodes)) {
747
+ return {
748
+ ok: true,
749
+ issue: buildTruncatedInverseRelationsIssue(input.issue, nodes)
750
+ };
751
+ }
752
+ nodes.push(...nextConnection.nodes);
753
+ hasNextPage = nextConnection.pageInfo?.hasNextPage === true;
754
+ afterCursor = normalizeEnvValue(nextConnection.pageInfo?.endCursor);
755
+ if (hasNextPage && !afterCursor) {
756
+ return {
757
+ ok: true,
758
+ issue: buildTruncatedInverseRelationsIssue(input.issue, nodes)
759
+ };
760
+ }
761
+ pagesRead += 1;
762
+ }
763
+ return {
764
+ ok: true,
765
+ issue: {
766
+ ...input.issue,
767
+ inverseRelations: {
768
+ nodes,
769
+ pageInfo: {
770
+ ...(input.issue.inverseRelations?.pageInfo ?? {}),
771
+ hasNextPage,
772
+ endCursor: afterCursor
773
+ }
774
+ }
775
+ }
776
+ };
777
+ }
778
+ function buildTruncatedInverseRelationsIssue(issue, nodes) {
779
+ return {
780
+ ...issue,
781
+ inverseRelations: {
782
+ nodes,
783
+ pageInfo: {
784
+ ...(issue.inverseRelations?.pageInfo ?? {}),
785
+ hasNextPage: true
786
+ }
787
+ }
788
+ };
789
+ }
790
+ async function executeLinearQuery(input) {
791
+ const sharedBudget = await readSharedLinearBudgetStatus(input.env, {
792
+ operation: input.source
793
+ });
794
+ const preflight = resolveLinearBudgetPreflight({
795
+ budget: sharedBudget,
796
+ operation: input.source
797
+ });
798
+ if (!preflight.ok) {
799
+ return {
800
+ ok: false,
801
+ resolution: unavailable('dispatch_source_provider_rate_limited', {
802
+ status: preflight.error.status,
803
+ message: preflight.error.message,
804
+ retryable: preflight.error.retryable,
805
+ details: {
806
+ error_code: preflight.error.code,
807
+ ...preflight.error.details
808
+ }
809
+ })
810
+ };
811
+ }
812
+ const reservation = await reserveLinearBudgetReservation({
813
+ env: input.env,
814
+ operation: input.source
815
+ });
816
+ if (!reservation.ok) {
817
+ return {
818
+ ok: false,
819
+ resolution: unavailable('dispatch_source_provider_rate_limited', {
820
+ status: reservation.error.status,
821
+ message: reservation.error.message,
822
+ retryable: reservation.error.retryable,
823
+ details: {
824
+ error_code: reservation.error.code,
825
+ ...reservation.error.details
826
+ }
827
+ })
828
+ };
829
+ }
830
+ try {
831
+ const result = await executeLinearGraphql({
832
+ token: input.token,
833
+ timeoutMs: input.timeoutMs,
834
+ fetchImpl: input.fetchImpl,
835
+ query: input.query,
836
+ variables: input.variables
837
+ });
838
+ if (!result.ok) {
839
+ await recordLinearBudgetHeadersObservation({
840
+ env: input.env,
841
+ headers: result.failure.headers ?? null,
842
+ source: input.source
843
+ }).catch(() => undefined);
844
+ const rateLimitFailure = mapLinearRateLimitedFailure(result.failure);
845
+ if (rateLimitFailure) {
846
+ await recordLinearBudgetRateLimitObservation({
847
+ env: input.env,
848
+ rateLimit: rateLimitFailure,
849
+ source: input.source
850
+ }).catch(() => undefined);
851
+ }
852
+ return {
853
+ ok: false,
854
+ resolution: mapLinearGraphqlFailureToDispatchResolution(result.failure)
855
+ };
856
+ }
857
+ await recordLinearBudgetHeadersObservation({
858
+ env: input.env,
859
+ headers: result.headers ?? null,
860
+ source: input.source,
861
+ scope: {
862
+ workspaceId: result.payload.data?.viewer?.organization?.id?.trim() ?? null,
863
+ viewerId: result.payload.data?.viewer?.id?.trim() ?? null
864
+ }
865
+ }).catch(() => undefined);
866
+ return {
867
+ ok: true,
868
+ payload: result.payload
869
+ };
870
+ }
871
+ finally {
872
+ await reservation.reservation?.release().catch(() => undefined);
873
+ }
874
+ }
875
+ function resolveLinearTrackedIssuesNextCursor(pageInfo, queryMode) {
876
+ if (queryMode === 'fresh_discovery') {
877
+ if (pageInfo?.hasPreviousPage !== true) {
878
+ return null;
879
+ }
880
+ const startCursor = normalizeEnvValue(pageInfo.startCursor);
881
+ return startCursor ?? undefined;
882
+ }
883
+ if (pageInfo?.hasNextPage !== true) {
884
+ return null;
885
+ }
886
+ const endCursor = normalizeEnvValue(pageInfo.endCursor);
887
+ return endCursor ?? undefined;
888
+ }
889
+ export function hasLinearApiCredentials(env) {
890
+ return resolveLinearApiToken(env ?? process.env) !== null;
891
+ }
892
+ export function hasLinearSourceBinding(sourceSetup) {
893
+ return Boolean(sourceSetup.workspace_id || sourceSetup.team_id || sourceSetup.project_id);
894
+ }
895
+ export function resolveLinearSourceSetup(sourceSetup, env) {
896
+ return {
897
+ provider: 'linear',
898
+ workspace_id: sourceSetup.workspace_id ?? normalizeEnvValue(env.CO_LINEAR_WORKSPACE_ID),
899
+ team_id: sourceSetup.team_id ?? normalizeEnvValue(env.CO_LINEAR_TEAM_ID),
900
+ project_id: sourceSetup.project_id ?? normalizeEnvValue(env.CO_LINEAR_PROJECT_ID)
901
+ };
902
+ }
903
+ function normalizeLinearTrackedIssueLimit(limit) {
904
+ return Number.isInteger(limit) && (limit ?? 0) > 0
905
+ ? Math.min(limit, DEFAULT_LINEAR_TRACKED_ISSUE_PAGE_SIZE)
906
+ : DEFAULT_LINEAR_TRACKED_ISSUE_PAGE_SIZE;
907
+ }
908
+ function parseTrackedIssue(issue, input) {
909
+ const id = normalizeEnvValue(issue.id);
910
+ const identifier = normalizeEnvValue(issue.identifier);
911
+ const title = normalizeEnvValue(issue.title);
912
+ if (!id || !identifier || !title) {
913
+ return null;
914
+ }
915
+ return {
916
+ provider: 'linear',
917
+ id,
918
+ identifier,
919
+ title,
920
+ description: normalizeEnvValue(issue.description),
921
+ url: normalizeEnvValue(issue.url),
922
+ state: normalizeEnvValue(issue.state?.name),
923
+ state_type: normalizeEnvValue(issue.state?.type),
924
+ archived_at: normalizeIso(issue.archivedAt),
925
+ trashed: normalizeOptionalBoolean(issue.trashed),
926
+ viewer_id: input.viewerId,
927
+ assignee_id: normalizeEnvValue(issue.assignee?.id),
928
+ assignee_name: normalizeEnvValue(issue.assignee?.displayName ?? issue.assignee?.name),
929
+ workspace_id: input.workspaceId,
930
+ team_id: normalizeEnvValue(issue.team?.id),
931
+ team_key: normalizeEnvValue(issue.team?.key),
932
+ team_name: normalizeEnvValue(issue.team?.name),
933
+ project_id: normalizeEnvValue(issue.project?.id),
934
+ project_name: normalizeEnvValue(issue.project?.name),
935
+ priority: normalizeTrackedIssuePriority(issue.priority),
936
+ created_at: normalizeIso(issue.createdAt),
937
+ updated_at: normalizeIso(issue.updatedAt),
938
+ blocked_by: extractTrackedIssueBlockers(issue),
939
+ blocked_by_truncated: isTrackedIssueBlockerPageTruncated(issue),
940
+ relations: extractTrackedIssueRelations(issue),
941
+ relations_truncated: issue.relations?.pageInfo?.hasNextPage === true,
942
+ recent_activity: Array.isArray(issue.history?.nodes)
943
+ ? issue.history.nodes
944
+ .map((entry) => buildTrackedActivity(entry))
945
+ .filter((entry) => entry !== null)
946
+ : []
947
+ };
948
+ }
949
+ function resolveTrackedIssuePriorityRank(issue) {
950
+ return normalizeTrackedIssuePriority(issue.priority) ?? 5;
951
+ }
952
+ function resolveTrackedIssueCreatedAtSortKey(issue) {
953
+ const createdAt = normalizeIso(issue.created_at);
954
+ if (!createdAt) {
955
+ return Number.MAX_SAFE_INTEGER;
956
+ }
957
+ const parsed = Date.parse(createdAt);
958
+ return Number.isFinite(parsed) ? parsed : Number.MAX_SAFE_INTEGER;
959
+ }
960
+ function normalizeTrackedIssuePriority(value) {
961
+ return Number.isInteger(value) && value >= 1 && value <= 4
962
+ ? value
963
+ : null;
964
+ }
965
+ function normalizeOptionalBoolean(value) {
966
+ return typeof value === 'boolean' ? value : null;
967
+ }
968
+ function validateTrackedIssueScope(trackedIssue, sourceSetup) {
969
+ if (sourceSetup.workspace_id && trackedIssue.workspace_id && sourceSetup.workspace_id !== trackedIssue.workspace_id) {
970
+ return malformed('dispatch_source_workspace_mismatch');
971
+ }
972
+ if (sourceSetup.team_id && sourceSetup.team_id !== trackedIssue.team_id) {
973
+ return malformed('dispatch_source_team_mismatch');
974
+ }
975
+ if (sourceSetup.project_id && sourceSetup.project_id !== trackedIssue.project_id) {
976
+ return malformed('dispatch_source_project_mismatch');
977
+ }
978
+ return null;
979
+ }
980
+ function extractTrackedIssueBlockers(issue) {
981
+ if (!Array.isArray(issue.inverseRelations?.nodes)) {
982
+ return [];
983
+ }
984
+ return issue.inverseRelations.nodes.flatMap((node) => {
985
+ const relationType = normalizeEnvValue(node.type)?.toLowerCase();
986
+ if (relationType !== 'blocks' || !node.issue) {
987
+ return [];
988
+ }
989
+ return [
990
+ {
991
+ id: normalizeEnvValue(node.issue.id),
992
+ identifier: normalizeEnvValue(node.issue.identifier),
993
+ state: normalizeEnvValue(node.issue.state?.name),
994
+ state_type: normalizeEnvValue(node.issue.state?.type)
995
+ }
996
+ ];
997
+ });
998
+ }
999
+ function isTrackedIssueBlockerPageTruncated(issue) {
1000
+ return issue.inverseRelations?.pageInfo?.hasNextPage === true;
1001
+ }
1002
+ function extractTrackedIssueRelations(issue) {
1003
+ return [
1004
+ ...extractTrackedIssueRelationNodes(issue.relations?.nodes, 'outbound', 'relatedIssue'),
1005
+ ...extractTrackedIssueRelationNodes(issue.inverseRelations?.nodes, 'inbound', 'issue')
1006
+ ];
1007
+ }
1008
+ function extractTrackedIssueRelationNodes(nodes, direction, issueField) {
1009
+ if (!Array.isArray(nodes)) {
1010
+ return [];
1011
+ }
1012
+ return nodes.flatMap((node) => {
1013
+ const relationIssue = node[issueField];
1014
+ if (!relationIssue) {
1015
+ return [];
1016
+ }
1017
+ return [{
1018
+ direction,
1019
+ type: normalizeEnvValue(node.type),
1020
+ issue: {
1021
+ id: normalizeEnvValue(relationIssue.id),
1022
+ identifier: normalizeEnvValue(relationIssue.identifier),
1023
+ state: normalizeEnvValue(relationIssue.state?.name),
1024
+ state_type: normalizeEnvValue(relationIssue.state?.type)
1025
+ }
1026
+ }];
1027
+ });
1028
+ }
1029
+ function buildTrackedActivity(node) {
1030
+ const id = normalizeEnvValue(node.id);
1031
+ if (!id) {
1032
+ return null;
1033
+ }
1034
+ return {
1035
+ id,
1036
+ created_at: normalizeIso(node.createdAt),
1037
+ actor_name: normalizeEnvValue(node.actor?.displayName) ?? normalizeEnvValue(node.actor?.name),
1038
+ summary: summarizeHistoryNode(node)
1039
+ };
1040
+ }
1041
+ function summarizeHistoryNode(node) {
1042
+ if (node.toState?.name || node.fromState?.name) {
1043
+ return `State ${node.fromState?.name ?? 'unknown'} -> ${node.toState?.name ?? 'unknown'}`;
1044
+ }
1045
+ if (node.toProject?.name || node.fromProject?.name) {
1046
+ return `Project ${node.fromProject?.name ?? 'none'} -> ${node.toProject?.name ?? 'none'}`;
1047
+ }
1048
+ if (node.toTitle || node.fromTitle) {
1049
+ return 'Title updated';
1050
+ }
1051
+ return 'Issue updated';
1052
+ }
1053
+ function buildDefaultRationale(issue, defaultIssueIdentifier) {
1054
+ const fragments = [
1055
+ `Live Linear advisory selected ${issue.identifier}`,
1056
+ issue.team_key ? `team ${issue.team_key}` : null,
1057
+ issue.project_name ? `project ${issue.project_name}` : null,
1058
+ issue.state ? `state ${issue.state}` : null,
1059
+ defaultIssueIdentifier ? `for ${defaultIssueIdentifier}` : null
1060
+ ].filter((value) => Boolean(value));
1061
+ return fragments.join(', ');
1062
+ }
1063
+ function mapLinearGraphqlFailureToDispatchResolution(failure) {
1064
+ if (failure.kind === 'response_invalid') {
1065
+ return malformed('dispatch_source_provider_response_invalid');
1066
+ }
1067
+ const rateLimitFailure = mapLinearRateLimitedFailure(failure);
1068
+ if (rateLimitFailure) {
1069
+ return unavailable('dispatch_source_provider_rate_limited', {
1070
+ status: rateLimitFailure.status,
1071
+ message: rateLimitFailure.message,
1072
+ retryable: rateLimitFailure.retryable,
1073
+ details: {
1074
+ error_code: rateLimitFailure.code,
1075
+ ...rateLimitFailure.details
1076
+ }
1077
+ });
1078
+ }
1079
+ return unavailable('dispatch_source_provider_request_failed');
1080
+ }
1081
+ function unavailable(reason, options = {}) {
1082
+ return {
1083
+ kind: 'unavailable',
1084
+ status: options.status ?? 503,
1085
+ code: 'dispatch_source_unavailable',
1086
+ reason,
1087
+ ...(options.message ? { message: options.message } : {}),
1088
+ ...(typeof options.retryable === 'boolean' ? { retryable: options.retryable } : {}),
1089
+ ...(options.details ? { details: options.details } : {})
1090
+ };
1091
+ }
1092
+ function malformed(reason) {
1093
+ return {
1094
+ kind: 'malformed',
1095
+ status: 422,
1096
+ code: 'dispatch_source_malformed',
1097
+ reason
1098
+ };
1099
+ }
1100
+ function normalizeEnvValue(value) {
1101
+ return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
1102
+ }
1103
+ function normalizeIso(value) {
1104
+ const normalized = normalizeEnvValue(value);
1105
+ if (!normalized) {
1106
+ return null;
1107
+ }
1108
+ const parsed = Date.parse(normalized);
1109
+ if (!Number.isFinite(parsed)) {
1110
+ return null;
1111
+ }
1112
+ return new Date(parsed).toISOString();
1113
+ }
1114
+ function readStringValue(record, ...keys) {
1115
+ for (const key of keys) {
1116
+ const value = record[key];
1117
+ if (typeof value === 'string' && value.trim().length > 0) {
1118
+ return value.trim();
1119
+ }
1120
+ }
1121
+ return undefined;
1122
+ }
1123
+ function readNumberValue(record, ...keys) {
1124
+ for (const key of keys) {
1125
+ const value = record[key];
1126
+ if (typeof value === 'number' && Number.isFinite(value)) {
1127
+ return value;
1128
+ }
1129
+ if (typeof value === 'string' && value.trim().length > 0) {
1130
+ const parsed = Number(value);
1131
+ if (Number.isFinite(parsed)) {
1132
+ return parsed;
1133
+ }
1134
+ }
1135
+ }
1136
+ return undefined;
1137
+ }