@kbediako/codex-orchestrator 0.1.38 → 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 (299) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +70 -301
  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 +119 -15
  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 +667 -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 +20 -10
  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 +394 -0
  282. package/skills/collab-subagents-first/SKILL.md +1 -1
  283. package/skills/delegation-usage/DELEGATION_GUIDE.md +24 -11
  284. package/skills/delegation-usage/SKILL.md +19 -13
  285. package/skills/land/SKILL.md +77 -0
  286. package/skills/linear/SKILL.md +255 -0
  287. package/skills/release/SKILL.md +47 -3
  288. package/skills/standalone-review/SKILL.md +6 -1
  289. package/templates/README.md +4 -2
  290. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  291. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  292. package/templates/codex/.codex/config.toml +3 -4
  293. package/templates/codex/.codex/providers/README.md +13 -0
  294. package/templates/codex/.codex/providers/control.example.json +18 -0
  295. package/templates/codex/.codex/providers/provider.env.example +15 -0
  296. package/templates/codex/AGENTS.md +12 -7
  297. package/templates/codex/mcp-client.json +5 -1
  298. package/docs/README.md +0 -310
  299. package/docs/assets/setup.gif +0 -0
@@ -0,0 +1,499 @@
1
+ import { createHmac, timingSafeEqual } from 'node:crypto';
2
+ import { isoTimestamp } from '../utils/time.js';
3
+ import { evaluateTrackerDispatchPilot } from './trackerDispatchPilot.js';
4
+ import { resolveLiveLinearTrackedIssueById } from './linearDispatchSource.js';
5
+ const LINEAR_WEBHOOK_MAX_AGE_MS = 5 * 60 * 1000;
6
+ const LINEAR_ADVISORY_SEEN_DELIVERY_LIMIT = 100;
7
+ export async function handleLinearWebhookRequest(input) {
8
+ const { req, res } = input;
9
+ const pathname = new URL(req.url ?? '/', 'http://localhost').pathname;
10
+ if (pathname !== '/integrations/linear/webhook') {
11
+ return false;
12
+ }
13
+ const env = input.env ?? process.env;
14
+ const now = input.now ?? Date.now;
15
+ if (req.method !== 'POST') {
16
+ writeLinearWebhookResponse(res, 405, 'rejected', 'method_not_allowed');
17
+ return true;
18
+ }
19
+ const deliveryId = readHeaderValue(req.headers['linear-delivery']);
20
+ if (!deliveryId) {
21
+ writeLinearWebhookResponse(res, 400, 'rejected', 'linear_delivery_header_missing');
22
+ return true;
23
+ }
24
+ const signature = readHeaderValue(req.headers['linear-signature']);
25
+ if (!signature) {
26
+ writeLinearWebhookResponse(res, 401, 'rejected', 'linear_signature_missing');
27
+ return true;
28
+ }
29
+ const webhookSecret = env.CO_LINEAR_WEBHOOK_SECRET?.trim();
30
+ if (!webhookSecret) {
31
+ writeLinearWebhookResponse(res, 503, 'rejected', 'linear_webhook_secret_missing');
32
+ return true;
33
+ }
34
+ const rawBody = await input.readRawBody(req);
35
+ if (!isLinearWebhookSignatureValid(signature, rawBody, webhookSecret)) {
36
+ writeLinearWebhookResponse(res, 401, 'rejected', 'linear_signature_invalid');
37
+ return true;
38
+ }
39
+ const payload = parseJsonRecord(rawBody);
40
+ if (!payload) {
41
+ writeLinearWebhookResponse(res, 400, 'rejected', 'invalid_json');
42
+ return true;
43
+ }
44
+ const eventName = readHeaderValue(req.headers['linear-event']) ?? readStringValue(payload, 'type') ?? null;
45
+ const action = readStringValue(payload, 'action') ?? null;
46
+ const issueId = readLinearWebhookIssueId(payload);
47
+ const webhookTimestamp = resolveLinearWebhookTimestamp(payload);
48
+ if (!webhookTimestamp) {
49
+ await recordAndPersistLinearAdvisoryOutcome(input, {
50
+ deliveryId,
51
+ event: eventName,
52
+ action,
53
+ issueId,
54
+ webhookTimestamp: null,
55
+ outcome: 'rejected',
56
+ reason: 'linear_webhook_timestamp_invalid'
57
+ });
58
+ writeLinearWebhookResponse(res, 401, 'rejected', 'linear_webhook_timestamp_invalid');
59
+ return true;
60
+ }
61
+ if (Math.abs(now() - webhookTimestamp) > LINEAR_WEBHOOK_MAX_AGE_MS) {
62
+ await recordAndPersistLinearAdvisoryOutcome(input, {
63
+ deliveryId,
64
+ event: eventName,
65
+ action,
66
+ issueId,
67
+ webhookTimestamp,
68
+ outcome: 'rejected',
69
+ reason: 'linear_webhook_timestamp_expired'
70
+ });
71
+ writeLinearWebhookResponse(res, 401, 'rejected', 'linear_webhook_timestamp_expired');
72
+ return true;
73
+ }
74
+ if (hasSeenLinearDelivery(input.linearAdvisoryState, deliveryId)) {
75
+ markLinearAdvisoryDuplicate(input.linearAdvisoryState, {
76
+ deliveryId,
77
+ event: eventName,
78
+ action,
79
+ issueId,
80
+ webhookTimestamp
81
+ });
82
+ await input.persistLinearAdvisory();
83
+ await input.emitAuditEvent({
84
+ deliveryId,
85
+ event: eventName,
86
+ action,
87
+ issueId,
88
+ outcome: 'duplicate',
89
+ reason: 'linear_delivery_duplicate'
90
+ });
91
+ writeLinearWebhookResponse(res, 200, 'duplicate', 'linear_delivery_duplicate');
92
+ return true;
93
+ }
94
+ const sourceSetup = resolveLinearWebhookSourceSetup(input.readFeatureToggles(), env);
95
+ if ('error' in sourceSetup) {
96
+ await recordAndPersistLinearAdvisoryOutcome(input, {
97
+ deliveryId,
98
+ event: eventName,
99
+ action,
100
+ issueId,
101
+ webhookTimestamp,
102
+ outcome: 'rejected',
103
+ reason: sourceSetup.error
104
+ });
105
+ writeLinearWebhookResponse(res, sourceSetup.status, 'rejected', sourceSetup.error);
106
+ return true;
107
+ }
108
+ if ((eventName ?? '').toLowerCase() !== 'issue' || (readStringValue(payload, 'type') ?? '').toLowerCase() !== 'issue') {
109
+ await recordAndPersistLinearAdvisoryOutcome(input, {
110
+ deliveryId,
111
+ event: eventName,
112
+ action,
113
+ issueId,
114
+ webhookTimestamp,
115
+ outcome: 'ignored',
116
+ reason: 'linear_event_unsupported'
117
+ });
118
+ writeLinearWebhookResponse(res, 200, 'ignored', 'linear_event_unsupported');
119
+ return true;
120
+ }
121
+ if (action !== 'create' && action !== 'update') {
122
+ await recordAndPersistLinearAdvisoryOutcome(input, {
123
+ deliveryId,
124
+ event: eventName,
125
+ action,
126
+ issueId,
127
+ webhookTimestamp,
128
+ outcome: 'ignored',
129
+ reason: 'linear_action_unsupported'
130
+ });
131
+ writeLinearWebhookResponse(res, 200, 'ignored', 'linear_action_unsupported');
132
+ return true;
133
+ }
134
+ if (!issueId) {
135
+ await recordAndPersistLinearAdvisoryOutcome(input, {
136
+ deliveryId,
137
+ event: eventName,
138
+ action,
139
+ issueId: null,
140
+ webhookTimestamp,
141
+ outcome: 'rejected',
142
+ reason: 'linear_issue_id_missing'
143
+ });
144
+ writeLinearWebhookResponse(res, 400, 'rejected', 'linear_issue_id_missing');
145
+ return true;
146
+ }
147
+ const resolution = await resolveLiveLinearTrackedIssueById({
148
+ issueId,
149
+ sourceSetup: sourceSetup.sourceSetup,
150
+ env
151
+ });
152
+ if (resolution.kind === 'ready') {
153
+ await input.providerIssueHandoff?.handleAcceptedTrackedIssue({
154
+ trackedIssue: resolution.tracked_issue,
155
+ deliveryId,
156
+ event: eventName,
157
+ action,
158
+ webhookTimestamp
159
+ });
160
+ await recordAndPersistLinearAdvisoryOutcome(input, {
161
+ deliveryId,
162
+ event: eventName,
163
+ action,
164
+ issueId,
165
+ webhookTimestamp,
166
+ outcome: 'accepted',
167
+ reason: 'linear_delivery_accepted',
168
+ trackedIssue: resolution.tracked_issue
169
+ });
170
+ writeLinearWebhookResponse(res, 200, 'accepted', 'linear_delivery_accepted');
171
+ input.publishRuntime();
172
+ return true;
173
+ }
174
+ if (shouldIgnoreLinearResolutionReason(resolution.reason)) {
175
+ await recordAndPersistLinearAdvisoryOutcome(input, {
176
+ deliveryId,
177
+ event: eventName,
178
+ action,
179
+ issueId,
180
+ webhookTimestamp,
181
+ outcome: 'ignored',
182
+ reason: resolution.reason
183
+ });
184
+ writeLinearWebhookResponse(res, 200, 'ignored', resolution.reason);
185
+ return true;
186
+ }
187
+ await recordAndPersistLinearAdvisoryOutcome(input, {
188
+ deliveryId,
189
+ event: eventName,
190
+ action,
191
+ issueId,
192
+ webhookTimestamp,
193
+ outcome: 'rejected',
194
+ reason: resolution.reason
195
+ });
196
+ writeLinearWebhookResponse(res, resolution.status, 'rejected', resolution.reason);
197
+ return true;
198
+ }
199
+ export function normalizeLinearAdvisoryState(input) {
200
+ const state = input ?? {
201
+ schema_version: 1,
202
+ updated_at: new Date(0).toISOString(),
203
+ latest_delivery_id: null,
204
+ latest_result: null,
205
+ latest_reason: null,
206
+ latest_event: null,
207
+ latest_accepted_at: null,
208
+ tracked_issue: null,
209
+ seen_deliveries: []
210
+ };
211
+ const staleSource = normalizeLinearAdvisoryStaleSource(state.stale_source);
212
+ return {
213
+ schema_version: 1,
214
+ updated_at: typeof state.updated_at === 'string' && state.updated_at.trim().length > 0
215
+ ? state.updated_at
216
+ : new Date(0).toISOString(),
217
+ latest_delivery_id: typeof state.latest_delivery_id === 'string' ? state.latest_delivery_id : null,
218
+ latest_result: state.latest_result === 'accepted' ||
219
+ state.latest_result === 'duplicate' ||
220
+ state.latest_result === 'ignored' ||
221
+ state.latest_result === 'rejected'
222
+ ? state.latest_result
223
+ : null,
224
+ latest_reason: typeof state.latest_reason === 'string' ? state.latest_reason : null,
225
+ latest_event: state.latest_event ?? null,
226
+ latest_accepted_at: typeof state.latest_accepted_at === 'string' ? state.latest_accepted_at : null,
227
+ tracked_issue: state.tracked_issue ?? null,
228
+ seen_deliveries: Array.isArray(state.seen_deliveries)
229
+ ? state.seen_deliveries.slice(-LINEAR_ADVISORY_SEEN_DELIVERY_LIMIT)
230
+ : [],
231
+ ...(staleSource ? { stale_source: staleSource } : {})
232
+ };
233
+ }
234
+ export function markLinearAdvisoryStateStaleFromProviderIntake(state, providerIntakeState, options = {}) {
235
+ if (!state.tracked_issue) {
236
+ return false;
237
+ }
238
+ const providerIntakeUpdatedAt = resolveProviderIntakeTruthUpdatedAt(providerIntakeState, state.tracked_issue);
239
+ const advisoryUpdatedAt = resolveLinearAdvisoryTrackedIssueReferenceUpdatedAt(state);
240
+ if (!isIsoNewer(providerIntakeUpdatedAt, advisoryUpdatedAt)) {
241
+ return false;
242
+ }
243
+ const nextStaleSource = {
244
+ source: 'provider-intake',
245
+ reason: 'provider_intake_newer_than_linear_advisory',
246
+ marked_at: options.now?.() ?? isoTimestamp(),
247
+ provider_intake_updated_at: providerIntakeUpdatedAt,
248
+ advisory_updated_at: advisoryUpdatedAt
249
+ };
250
+ if (state.stale_source?.source === nextStaleSource.source &&
251
+ state.stale_source.reason === nextStaleSource.reason &&
252
+ state.stale_source.provider_intake_updated_at === nextStaleSource.provider_intake_updated_at &&
253
+ state.stale_source.advisory_updated_at === nextStaleSource.advisory_updated_at) {
254
+ return false;
255
+ }
256
+ state.stale_source = nextStaleSource;
257
+ return true;
258
+ }
259
+ function resolveProviderIntakeTruthUpdatedAt(providerIntakeState, trackedIssue) {
260
+ const matchingClaims = (providerIntakeState?.claims ?? []).filter((claim) => claim.issue_id === trackedIssue.id || claim.issue_identifier === trackedIssue.identifier);
261
+ if (matchingClaims.length === 0) {
262
+ return null;
263
+ }
264
+ let truthUpdatedAt = null;
265
+ for (const claim of matchingClaims) {
266
+ truthUpdatedAt = pickLatestIsoTimestamp(pickLatestIsoTimestamp(truthUpdatedAt, claim.updated_at), claim.issue_updated_at);
267
+ }
268
+ return truthUpdatedAt;
269
+ }
270
+ function resolveLinearAdvisoryTrackedIssueReferenceUpdatedAt(state) {
271
+ return pickLatestIsoTimestamp(typeof state.latest_accepted_at === 'string' ? state.latest_accepted_at : null, state.tracked_issue?.updated_at);
272
+ }
273
+ function pickLatestIsoTimestamp(left, right) {
274
+ if (typeof right !== 'string' || right.trim().length === 0) {
275
+ return left;
276
+ }
277
+ if (isIsoNewer(right, left)) {
278
+ return right;
279
+ }
280
+ return left;
281
+ }
282
+ async function recordAndPersistLinearAdvisoryOutcome(input, outcome) {
283
+ recordLinearAdvisoryOutcome(input.linearAdvisoryState, outcome);
284
+ await input.persistLinearAdvisory();
285
+ await input.emitAuditEvent({
286
+ deliveryId: outcome.deliveryId,
287
+ event: outcome.event,
288
+ action: outcome.action,
289
+ issueId: outcome.issueId,
290
+ outcome: outcome.outcome,
291
+ reason: outcome.reason
292
+ });
293
+ }
294
+ function writeLinearWebhookResponse(res, status, outcome, reason) {
295
+ res.writeHead(status, { 'Content-Type': 'application/json' });
296
+ res.end(JSON.stringify({ status: outcome, reason, timestamp: isoTimestamp() }));
297
+ }
298
+ export function resolveLinearWebhookSourceSetup(featureToggles, env) {
299
+ const evaluation = evaluateTrackerDispatchPilot({
300
+ featureToggles,
301
+ defaultIssueIdentifier: null,
302
+ env
303
+ });
304
+ if (!evaluation.summary.configured) {
305
+ return { status: 503, error: 'dispatch_source_unavailable' };
306
+ }
307
+ if (!evaluation.summary.enabled) {
308
+ return { status: 409, error: 'dispatch_source_disabled' };
309
+ }
310
+ if (evaluation.summary.kill_switch) {
311
+ return { status: 409, error: 'dispatch_source_kill_switched' };
312
+ }
313
+ if (!evaluation.summary.source_setup || evaluation.summary.source_setup.provider !== 'linear') {
314
+ return { status: 422, error: 'dispatch_source_binding_missing' };
315
+ }
316
+ return { sourceSetup: evaluation.summary.source_setup };
317
+ }
318
+ function shouldIgnoreLinearResolutionReason(reason) {
319
+ return (reason === 'dispatch_source_issue_not_found' ||
320
+ reason === 'dispatch_source_workspace_mismatch' ||
321
+ reason === 'dispatch_source_team_mismatch' ||
322
+ reason === 'dispatch_source_project_mismatch');
323
+ }
324
+ function readLinearWebhookIssueId(payload) {
325
+ const data = readRecordValue(payload, 'data');
326
+ if (!data) {
327
+ return null;
328
+ }
329
+ return readStringValue(data, 'id') ?? null;
330
+ }
331
+ function resolveLinearWebhookTimestamp(payload) {
332
+ const raw = payload.webhookTimestamp;
333
+ if (typeof raw === 'number' && Number.isFinite(raw)) {
334
+ return raw;
335
+ }
336
+ if (typeof raw === 'string' && raw.trim().length > 0) {
337
+ const parsed = Number(raw);
338
+ if (Number.isFinite(parsed)) {
339
+ return parsed;
340
+ }
341
+ }
342
+ return null;
343
+ }
344
+ function parseJsonRecord(payload) {
345
+ if (payload.length === 0) {
346
+ return null;
347
+ }
348
+ try {
349
+ const parsed = JSON.parse(payload.toString('utf8'));
350
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
351
+ return null;
352
+ }
353
+ return parsed;
354
+ }
355
+ catch {
356
+ return null;
357
+ }
358
+ }
359
+ function isLinearWebhookSignatureValid(signature, payload, secret) {
360
+ const expected = createHmac('sha256', secret).update(payload).digest('hex');
361
+ return safeTokenCompare(signature, expected);
362
+ }
363
+ function hasSeenLinearDelivery(state, deliveryId) {
364
+ return state.seen_deliveries.some((entry) => entry.delivery_id === deliveryId);
365
+ }
366
+ function markLinearAdvisoryDuplicate(state, input) {
367
+ state.updated_at = isoTimestamp();
368
+ state.latest_result = 'duplicate';
369
+ state.latest_reason = 'linear_delivery_duplicate';
370
+ state.latest_event = {
371
+ delivery_id: input.deliveryId,
372
+ event: input.event,
373
+ action: input.action,
374
+ issue_id: input.issueId,
375
+ webhook_timestamp: input.webhookTimestamp,
376
+ processed_at: state.updated_at
377
+ };
378
+ }
379
+ function recordLinearAdvisoryOutcome(state, input) {
380
+ const processedAt = isoTimestamp();
381
+ state.updated_at = processedAt;
382
+ state.latest_result = input.outcome;
383
+ state.latest_reason = input.reason;
384
+ state.latest_event = {
385
+ delivery_id: input.deliveryId,
386
+ event: input.event,
387
+ action: input.action,
388
+ issue_id: input.issueId,
389
+ webhook_timestamp: input.webhookTimestamp,
390
+ processed_at: processedAt
391
+ };
392
+ state.latest_delivery_id = input.deliveryId;
393
+ state.seen_deliveries = [
394
+ ...state.seen_deliveries.filter((entry) => entry.delivery_id !== input.deliveryId),
395
+ {
396
+ delivery_id: input.deliveryId,
397
+ event: input.event,
398
+ action: input.action,
399
+ issue_id: input.issueId,
400
+ webhook_timestamp: input.webhookTimestamp,
401
+ processed_at: processedAt,
402
+ outcome: input.outcome,
403
+ reason: input.reason
404
+ }
405
+ ].slice(-LINEAR_ADVISORY_SEEN_DELIVERY_LIMIT);
406
+ if (input.outcome === 'accepted' && input.trackedIssue) {
407
+ state.latest_accepted_at = processedAt;
408
+ state.tracked_issue = input.trackedIssue;
409
+ delete state.stale_source;
410
+ }
411
+ }
412
+ function normalizeLinearAdvisoryStaleSource(value) {
413
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
414
+ return null;
415
+ }
416
+ const record = value;
417
+ if (record.source !== 'provider-intake' ||
418
+ record.reason !== 'provider_intake_newer_than_linear_advisory') {
419
+ return null;
420
+ }
421
+ return {
422
+ source: 'provider-intake',
423
+ reason: 'provider_intake_newer_than_linear_advisory',
424
+ marked_at: typeof record.marked_at === 'string' ? record.marked_at : new Date(0).toISOString(),
425
+ provider_intake_updated_at: typeof record.provider_intake_updated_at === 'string'
426
+ ? record.provider_intake_updated_at
427
+ : null,
428
+ advisory_updated_at: typeof record.advisory_updated_at === 'string' ? record.advisory_updated_at : null
429
+ };
430
+ }
431
+ function isIsoNewer(candidateIso, currentIso) {
432
+ const candidateMs = Date.parse(candidateIso ?? '');
433
+ const currentMs = Date.parse(currentIso ?? '');
434
+ if (!Number.isFinite(candidateMs)) {
435
+ return false;
436
+ }
437
+ if (!Number.isFinite(currentMs)) {
438
+ return true;
439
+ }
440
+ return candidateMs > currentMs;
441
+ }
442
+ function safeTokenCompare(left, right) {
443
+ if (left.length !== right.length) {
444
+ return false;
445
+ }
446
+ return timingSafeEqual(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8'));
447
+ }
448
+ function readStringValue(record, ...keys) {
449
+ for (const key of keys) {
450
+ const value = record[key];
451
+ if (typeof value === 'string' && value.trim().length > 0) {
452
+ return value.trim();
453
+ }
454
+ }
455
+ return undefined;
456
+ }
457
+ function readRecordValue(record, key) {
458
+ const value = record[key];
459
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
460
+ return value;
461
+ }
462
+ return undefined;
463
+ }
464
+ function readHeaderValue(value) {
465
+ if (Array.isArray(value)) {
466
+ const values = [];
467
+ for (const entry of value) {
468
+ if (typeof entry !== 'string') {
469
+ continue;
470
+ }
471
+ const parts = entry.split(',');
472
+ for (const part of parts) {
473
+ const trimmed = part.trim();
474
+ if (trimmed) {
475
+ values.push(trimmed);
476
+ }
477
+ }
478
+ }
479
+ return readUniqueHeaderValue(values);
480
+ }
481
+ if (typeof value === 'string') {
482
+ const values = value
483
+ .split(',')
484
+ .map((part) => part.trim())
485
+ .filter(Boolean);
486
+ return readUniqueHeaderValue(values);
487
+ }
488
+ return null;
489
+ }
490
+ function readUniqueHeaderValue(values) {
491
+ if (values.length === 0) {
492
+ return null;
493
+ }
494
+ const unique = new Set(values);
495
+ if (unique.size > 1) {
496
+ return null;
497
+ }
498
+ return values[0];
499
+ }
@@ -0,0 +1,70 @@
1
+ import { summarizeTrackerDispatchPilotPolicy, evaluateTrackerDispatchPilotAsync } from './trackerDispatchPilot.js';
2
+ export function createLiveLinearAdvisoryRuntime(context) {
3
+ let generation = 0;
4
+ let cachedEvaluation = null;
5
+ let inflightEvaluation = null;
6
+ let cachedSnapshotSummary = null;
7
+ return {
8
+ readSnapshotSummary(issueIdentifier = null) {
9
+ const normalizedIssueIdentifier = normalizeIssueIdentifier(issueIdentifier);
10
+ if (cachedEvaluation && cachedEvaluation.issueIdentifier === normalizedIssueIdentifier) {
11
+ return cachedEvaluation.evaluation.summary;
12
+ }
13
+ cachedSnapshotSummary ??= summarizeTrackerDispatchPilotPolicy({
14
+ featureToggles: context.controlStore.snapshot().feature_toggles,
15
+ env: context.env ?? process.env
16
+ });
17
+ return cachedSnapshotSummary;
18
+ },
19
+ readDispatchEvaluation(issueIdentifier = null) {
20
+ const normalizedIssueIdentifier = normalizeIssueIdentifier(issueIdentifier);
21
+ if (cachedEvaluation && cachedEvaluation.issueIdentifier === normalizedIssueIdentifier) {
22
+ return Promise.resolve(cachedEvaluation.evaluation);
23
+ }
24
+ if (inflightEvaluation && inflightEvaluation.issueIdentifier === normalizedIssueIdentifier) {
25
+ return inflightEvaluation.promise;
26
+ }
27
+ const requestGeneration = generation;
28
+ const promise = evaluateTrackerDispatchPilotAsync({
29
+ featureToggles: context.controlStore.snapshot().feature_toggles,
30
+ defaultIssueIdentifier: normalizedIssueIdentifier,
31
+ env: context.env ?? process.env,
32
+ fetchImpl: context.fetchImpl
33
+ }).then((evaluation) => {
34
+ if (generation === requestGeneration) {
35
+ cachedEvaluation = {
36
+ issueIdentifier: normalizedIssueIdentifier,
37
+ evaluation
38
+ };
39
+ }
40
+ if (inflightEvaluation?.promise === promise) {
41
+ inflightEvaluation = null;
42
+ }
43
+ return evaluation;
44
+ }, (error) => {
45
+ if (inflightEvaluation?.promise === promise) {
46
+ inflightEvaluation = null;
47
+ }
48
+ throw error;
49
+ });
50
+ inflightEvaluation = {
51
+ issueIdentifier: normalizedIssueIdentifier,
52
+ promise
53
+ };
54
+ return promise;
55
+ },
56
+ invalidate() {
57
+ generation += 1;
58
+ cachedEvaluation = null;
59
+ inflightEvaluation = null;
60
+ cachedSnapshotSummary = null;
61
+ }
62
+ };
63
+ }
64
+ function normalizeIssueIdentifier(value) {
65
+ if (!value) {
66
+ return null;
67
+ }
68
+ const trimmed = value.trim();
69
+ return trimmed.length > 0 ? trimmed : null;
70
+ }