@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
@@ -29,6 +29,7 @@ export class UnifiedExecRunner {
29
29
  async run(options) {
30
30
  const args = options.args;
31
31
  const resolvedArgs = args ?? [];
32
+ const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
32
33
  const invocationId = options.invocationId ?? this.idGenerator();
33
34
  const correlationId = this.idGenerator();
34
35
  const issuedHandle = this.handleService ? this.handleService.issueHandle(correlationId) : undefined;
@@ -55,7 +56,8 @@ export class UnifiedExecRunner {
55
56
  sessionId: lease.id,
56
57
  correlationId,
57
58
  persisted: lease.persisted,
58
- handleId
59
+ handleId,
60
+ timeoutMs
59
61
  };
60
62
  const toolInvocation = {
61
63
  id: invocationId,
@@ -98,7 +100,9 @@ export class UnifiedExecRunner {
98
100
  durationMs: 0,
99
101
  status: 'failed',
100
102
  sandboxState,
101
- sessionId: lease.id
103
+ sessionId: lease.id,
104
+ timedOut: false,
105
+ ...(timeoutMs !== null ? { timeoutMs } : {})
102
106
  };
103
107
  try {
104
108
  const outcome = await this.executor({
@@ -109,6 +113,7 @@ export class UnifiedExecRunner {
109
113
  attempt,
110
114
  sandboxState,
111
115
  session: lease,
116
+ ...(timeoutMs !== null ? { timeoutMs } : {}),
112
117
  onStdout: (chunk) => {
113
118
  const sequenced = this.recordChunk(tracker, 'stdout', chunk);
114
119
  chunkSequence = sequenced.sequence;
@@ -132,7 +137,11 @@ export class UnifiedExecRunner {
132
137
  });
133
138
  attemptSummary.exitCode = outcome.exitCode ?? null;
134
139
  attemptSummary.signal = outcome.signal ?? null;
135
- attemptSummary.status = outcome.exitCode === 0 ? 'succeeded' : 'failed';
140
+ attemptSummary.timedOut = outcome.timedOut === true;
141
+ if (typeof outcome.timeoutMs === 'number' && Number.isFinite(outcome.timeoutMs) && outcome.timeoutMs > 0) {
142
+ attemptSummary.timeoutMs = Math.trunc(outcome.timeoutMs);
143
+ }
144
+ attemptSummary.status = outcome.exitCode === 0 && !attemptSummary.timedOut ? 'succeeded' : 'failed';
136
145
  attemptSummary.durationMs = outcome.durationMs ?? 0;
137
146
  }
138
147
  catch (error) {
@@ -171,6 +180,8 @@ export class UnifiedExecRunner {
171
180
  durationMs: attemptResult.durationMs,
172
181
  status: attemptResult.status,
173
182
  sandboxState: attemptResult.sandboxState,
183
+ ...(attemptResult.timedOut ? { timedOut: true } : {}),
184
+ ...(attemptResult.timeoutMs !== undefined ? { timeoutMs: attemptResult.timeoutMs } : {}),
174
185
  record: invocationRecord,
175
186
  events,
176
187
  handle: undefined
@@ -307,7 +318,9 @@ export class UnifiedExecRunner {
307
318
  correlationId,
308
319
  handleId,
309
320
  exitCode: attemptResult?.exitCode ?? null,
310
- signal: attemptResult?.signal ?? null
321
+ signal: attemptResult?.signal ?? null,
322
+ timedOut: attemptResult?.timedOut ?? null,
323
+ timeoutMs: attemptResult?.timeoutMs ?? null
311
324
  }
312
325
  };
313
326
  record.metadata = execMetadata;
@@ -414,20 +427,100 @@ const defaultExecutor = async (request) => {
414
427
  }
415
428
  child.stdout.on('data', request.onStdout);
416
429
  child.stderr.on('data', request.onStderr);
430
+ const timeoutMs = normalizeTimeoutMs(request.timeoutMs);
431
+ const startedAt = Date.now();
417
432
  return await new Promise((resolve, reject) => {
418
- const handleExit = (exitCode, signal) => {
433
+ let settled = false;
434
+ let timedOut = false;
435
+ let timeoutHandle = null;
436
+ let forceKillHandle = null;
437
+ let forcedSettleHandle = null;
438
+ const resolveResult = (exitCode, signal) => {
439
+ if (settled) {
440
+ return;
441
+ }
442
+ settled = true;
419
443
  cleanup();
420
- resolve({ exitCode, signal });
444
+ const result = {
445
+ exitCode,
446
+ signal,
447
+ durationMs: Math.max(0, Date.now() - startedAt)
448
+ };
449
+ if (timedOut) {
450
+ result.timedOut = true;
451
+ if (timeoutMs !== null) {
452
+ result.timeoutMs = timeoutMs;
453
+ }
454
+ }
455
+ resolve(result);
456
+ };
457
+ const handleExit = (exitCode, signal) => {
458
+ resolveResult(exitCode, signal);
421
459
  };
422
460
  const handleError = (error) => {
461
+ if (timedOut) {
462
+ return;
463
+ }
423
464
  cleanup();
424
465
  reject(error);
425
466
  };
426
467
  const cleanup = () => {
427
468
  child.off('exit', handleExit);
428
469
  child.off('error', handleError);
470
+ if (timeoutHandle) {
471
+ clearTimeout(timeoutHandle);
472
+ timeoutHandle = null;
473
+ }
474
+ if (forceKillHandle) {
475
+ clearTimeout(forceKillHandle);
476
+ forceKillHandle = null;
477
+ }
478
+ if (forcedSettleHandle) {
479
+ clearTimeout(forcedSettleHandle);
480
+ forcedSettleHandle = null;
481
+ }
429
482
  };
483
+ if (timeoutMs !== null) {
484
+ timeoutHandle = setTimeout(() => {
485
+ timedOut = true;
486
+ if (!child.killed) {
487
+ try {
488
+ child.kill('SIGTERM');
489
+ }
490
+ catch {
491
+ // ignore kill errors and continue to forced settlement fallback
492
+ }
493
+ }
494
+ forceKillHandle = setTimeout(() => {
495
+ if (settled) {
496
+ return;
497
+ }
498
+ try {
499
+ child.kill('SIGKILL');
500
+ }
501
+ catch {
502
+ // ignore kill errors and allow forced settlement to conclude
503
+ }
504
+ }, 1000);
505
+ forceKillHandle.unref?.();
506
+ forcedSettleHandle = setTimeout(() => {
507
+ resolveResult(null, 'SIGKILL');
508
+ }, 1500);
509
+ forcedSettleHandle.unref?.();
510
+ }, timeoutMs);
511
+ timeoutHandle.unref?.();
512
+ }
430
513
  child.once('exit', handleExit);
431
514
  child.once('error', handleError);
432
515
  });
433
516
  };
517
+ function normalizeTimeoutMs(value) {
518
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
519
+ return null;
520
+ }
521
+ const normalized = Math.trunc(value);
522
+ if (normalized <= 0) {
523
+ return null;
524
+ }
525
+ return normalized;
526
+ }
@@ -3,6 +3,9 @@ import { readFile, readdir, stat } from 'node:fs/promises';
3
3
  import { join, relative } from 'node:path';
4
4
  const PROMPT_SECTIONS = ['system', 'inject', 'summarize', 'extract', 'optimize'];
5
5
  const PROMPT_PACK_DIR = ['.agent', 'prompts', 'prompt-packs'];
6
+ const DEFAULT_PROMPT_PACK_RETRIEVAL_POLICY_KIND = 'competitive_scoring_v1';
7
+ const DEFAULT_PROMPT_PACK_SOURCE_GROUPING = 'provenance_fallback_v1';
8
+ const DEFAULT_ANTI_DOMINANCE_STRENGTH = 0.5;
6
9
  export async function loadPromptPacks(repoRoot) {
7
10
  const manifestPaths = await discoverPromptPackManifests(repoRoot);
8
11
  const packs = [];
@@ -17,6 +20,20 @@ export async function loadPromptPacks(repoRoot) {
17
20
  });
18
21
  return packs;
19
22
  }
23
+ export async function loadPromptPackMetadata(repoRoot) {
24
+ const manifestPaths = await discoverPromptPackManifests(repoRoot);
25
+ const packs = [];
26
+ for (const manifestPath of manifestPaths) {
27
+ packs.push(await loadPromptPackMetadataEntry(manifestPath, repoRoot));
28
+ }
29
+ packs.sort((a, b) => {
30
+ if (a.domain === b.domain) {
31
+ return a.id.localeCompare(b.id);
32
+ }
33
+ return a.domain.localeCompare(b.domain);
34
+ });
35
+ return packs;
36
+ }
20
37
  async function discoverPromptPackManifests(repoRoot) {
21
38
  const baseDir = join(repoRoot, ...PROMPT_PACK_DIR);
22
39
  let entries;
@@ -49,15 +66,11 @@ async function discoverPromptPackManifests(repoRoot) {
49
66
  return manifests;
50
67
  }
51
68
  async function loadPromptPack(manifestPath, repoRoot) {
52
- let parsed;
53
- try {
54
- const raw = await readFile(manifestPath, 'utf8');
55
- parsed = JSON.parse(raw);
56
- }
57
- catch (error) {
58
- throw new Error(`Failed to read prompt pack manifest at ${relative(repoRoot, manifestPath)}: ${String(error)}`);
59
- }
69
+ const parsed = await readPromptPackManifestFile(manifestPath, repoRoot);
60
70
  validateManifest(parsed, manifestPath, repoRoot);
71
+ const id = requireNonEmptyManifestString(parsed.id, 'id', manifestPath, repoRoot);
72
+ const domain = requireNonEmptyManifestString(parsed.domain, 'domain', manifestPath, repoRoot);
73
+ const system = requireNonEmptyManifestString(parsed.system, 'system', manifestPath, repoRoot);
61
74
  const sections = {
62
75
  system: [],
63
76
  inject: [],
@@ -65,34 +78,70 @@ async function loadPromptPack(manifestPath, repoRoot) {
65
78
  extract: [],
66
79
  optimize: []
67
80
  };
68
- sections.system = [await loadSectionSource(repoRoot, 'system', parsed.system, manifestPath)];
81
+ sections.system = [await loadSectionSource(repoRoot, 'system', system, manifestPath)];
69
82
  sections.inject = await loadSectionArray(repoRoot, 'inject', parsed.inject ?? [], manifestPath);
70
83
  sections.summarize = await loadSectionArray(repoRoot, 'summarize', parsed.summarize ?? [], manifestPath);
71
84
  sections.extract = await loadSectionArray(repoRoot, 'extract', parsed.extract ?? [], manifestPath);
72
85
  sections.optimize = await loadSectionArray(repoRoot, 'optimize', parsed.optimize ?? [], manifestPath);
73
86
  const allSources = PROMPT_SECTIONS.flatMap((section) => sections[section]);
74
87
  if (allSources.length === 0) {
75
- throw new Error(`Prompt pack ${parsed.id} ${parsed.domain} has no sources defined (${relative(repoRoot, manifestPath)})`);
88
+ throw new Error(`Prompt pack ${id} ${domain} has no sources defined (${relative(repoRoot, manifestPath)})`);
76
89
  }
77
- const computedStamp = computePromptPackStamp(allSources);
90
+ const experienceSlots = resolvePromptPackExperienceSlots(parsed, manifestPath, repoRoot);
91
+ const retrievalPolicy = normalizePromptPackRetrievalPolicy(parsed.retrievalPolicy);
92
+ const computedStamp = computePromptPackStamp(allSources, {
93
+ experienceSlots,
94
+ retrievalPolicy
95
+ });
78
96
  if (!parsed.stamp) {
79
- throw new Error(`Prompt pack ${parsed.id} is missing a stamp (manifest: ${relative(repoRoot, manifestPath)})`);
97
+ throw new Error(`Prompt pack ${id} is missing a stamp (manifest: ${relative(repoRoot, manifestPath)})`);
80
98
  }
81
99
  if (computedStamp !== parsed.stamp) {
82
- throw new Error(`Prompt pack ${parsed.id} stamp mismatch. expected ${parsed.stamp}, computed ${computedStamp} (${relative(repoRoot, manifestPath)})`);
100
+ throw new Error(`Prompt pack ${id} stamp mismatch. expected ${parsed.stamp}, computed ${computedStamp} (${relative(repoRoot, manifestPath)})`);
83
101
  }
84
- const experienceSlots = Number.isInteger(parsed.experienceSlots) && parsed.experienceSlots >= 0
85
- ? parsed.experienceSlots
86
- : 0;
87
102
  return {
88
- id: parsed.id,
89
- domain: parsed.domain,
103
+ id,
104
+ domain,
90
105
  stamp: parsed.stamp,
91
106
  experienceSlots,
107
+ retrievalPolicy,
92
108
  sections,
93
109
  sources: allSources
94
110
  };
95
111
  }
112
+ async function loadPromptPackMetadataEntry(manifestPath, repoRoot) {
113
+ const parsed = await readPromptPackManifestFile(manifestPath, repoRoot);
114
+ validateManifest(parsed, manifestPath, repoRoot);
115
+ const id = requireNonEmptyManifestString(parsed.id, 'id', manifestPath, repoRoot);
116
+ const domain = requireNonEmptyManifestString(parsed.domain, 'domain', manifestPath, repoRoot);
117
+ requireNonEmptyManifestString(parsed.system, 'system', manifestPath, repoRoot);
118
+ if (!parsed.stamp) {
119
+ throw new Error(`Prompt pack ${id} is missing a stamp (manifest: ${relative(repoRoot, manifestPath)})`);
120
+ }
121
+ return {
122
+ id,
123
+ domain,
124
+ experienceSlots: resolvePromptPackExperienceSlots(parsed, manifestPath, repoRoot)
125
+ };
126
+ }
127
+ async function readPromptPackManifestFile(manifestPath, repoRoot) {
128
+ try {
129
+ const raw = await readFile(manifestPath, 'utf8');
130
+ return JSON.parse(raw);
131
+ }
132
+ catch (error) {
133
+ throw new Error(`Failed to read prompt pack manifest at ${relative(repoRoot, manifestPath)}: ${String(error)}`);
134
+ }
135
+ }
136
+ function resolvePromptPackExperienceSlots(parsed, manifestPath, repoRoot) {
137
+ if (parsed.experienceSlots !== undefined &&
138
+ (typeof parsed.experienceSlots !== 'number' ||
139
+ !Number.isInteger(parsed.experienceSlots) ||
140
+ parsed.experienceSlots < 0)) {
141
+ throw new Error(`Prompt pack ${parsed.id} has invalid experienceSlots; expected a non-negative integer (${relative(repoRoot, manifestPath)})`);
142
+ }
143
+ return parsed.experienceSlots ?? 0;
144
+ }
96
145
  function validateManifest(manifest, manifestPath, repoRoot) {
97
146
  const missing = [];
98
147
  if (!manifest.id) {
@@ -108,6 +157,69 @@ function validateManifest(manifest, manifestPath, repoRoot) {
108
157
  throw new Error(`Prompt pack manifest ${relative(repoRoot, manifestPath)} missing required fields: ${missing.join(', ')}`);
109
158
  }
110
159
  }
160
+ function requireNonEmptyManifestString(value, field, manifestPath, repoRoot) {
161
+ if (typeof value !== 'string' || value.trim().length === 0) {
162
+ throw new Error(`Prompt pack manifest ${relative(repoRoot, manifestPath)} has invalid '${field}'; expected a non-empty string (repoRoot: ${repoRoot})`);
163
+ }
164
+ return value.trim();
165
+ }
166
+ function normalizePromptPackRetrievalPolicy(input) {
167
+ const antiDominance = input?.antiDominanceNormalization;
168
+ return {
169
+ kind: normalizeRetrievalPolicyKind(input?.kind),
170
+ minScore: input?.minScore === null || input?.minScore === undefined
171
+ ? null
172
+ : normalizeNonNegativeNumber(input.minScore, 'retrievalPolicy.minScore'),
173
+ scoreWeights: {
174
+ gtScore: normalizeNonNegativeNumber(input?.scoreWeights?.gtScore, 'retrievalPolicy.scoreWeights.gtScore', 1),
175
+ relativeRank: normalizeNonNegativeNumber(input?.scoreWeights?.relativeRank, 'retrievalPolicy.scoreWeights.relativeRank', 1)
176
+ },
177
+ antiDominanceNormalization: {
178
+ enabled: normalizeBoolean(antiDominance?.enabled, 'retrievalPolicy.antiDominanceNormalization.enabled', true),
179
+ strength: normalizeNonNegativeNumber(antiDominance?.strength, 'retrievalPolicy.antiDominanceNormalization.strength', DEFAULT_ANTI_DOMINANCE_STRENGTH),
180
+ sourceGrouping: normalizeSourceGrouping(antiDominance?.sourceGrouping)
181
+ }
182
+ };
183
+ }
184
+ function normalizeRetrievalPolicyKind(value) {
185
+ if (!value || !value.trim()) {
186
+ return DEFAULT_PROMPT_PACK_RETRIEVAL_POLICY_KIND;
187
+ }
188
+ if (value !== DEFAULT_PROMPT_PACK_RETRIEVAL_POLICY_KIND) {
189
+ throw new Error(`Unsupported prompt-pack retrieval policy kind '${value}'. Expected '${DEFAULT_PROMPT_PACK_RETRIEVAL_POLICY_KIND}'.`);
190
+ }
191
+ return DEFAULT_PROMPT_PACK_RETRIEVAL_POLICY_KIND;
192
+ }
193
+ function normalizeSourceGrouping(value) {
194
+ if (!value || !value.trim()) {
195
+ return DEFAULT_PROMPT_PACK_SOURCE_GROUPING;
196
+ }
197
+ if (value !== DEFAULT_PROMPT_PACK_SOURCE_GROUPING) {
198
+ throw new Error(`Unsupported prompt-pack source grouping '${value}'. Expected '${DEFAULT_PROMPT_PACK_SOURCE_GROUPING}'.`);
199
+ }
200
+ return DEFAULT_PROMPT_PACK_SOURCE_GROUPING;
201
+ }
202
+ function normalizeNonNegativeNumber(value, field, defaultValue) {
203
+ if (value === undefined) {
204
+ if (defaultValue === undefined) {
205
+ throw new Error(`${field} is required.`);
206
+ }
207
+ return defaultValue;
208
+ }
209
+ if (!Number.isFinite(value) || value < 0) {
210
+ throw new Error(`${field} must be a finite non-negative number.`);
211
+ }
212
+ return value;
213
+ }
214
+ function normalizeBoolean(value, field, defaultValue) {
215
+ if (value === undefined) {
216
+ return defaultValue;
217
+ }
218
+ if (typeof value !== 'boolean') {
219
+ throw new Error(`${field} must be a boolean.`);
220
+ }
221
+ return value;
222
+ }
111
223
  async function loadSectionArray(repoRoot, section, paths, manifestPath) {
112
224
  const sources = [];
113
225
  for (const relPath of paths) {
@@ -134,7 +246,7 @@ async function loadSectionSource(repoRoot, section, relativePath, manifestPath)
134
246
  content
135
247
  };
136
248
  }
137
- export function computePromptPackStamp(sources) {
249
+ export function computePromptPackStamp(sources, config) {
138
250
  const hash = createHash('sha256');
139
251
  const sorted = [...sources].sort((a, b) => {
140
252
  if (a.section === b.section) {
@@ -147,5 +259,24 @@ export function computePromptPackStamp(sources) {
147
259
  hash.update(source.content, 'utf8');
148
260
  hash.update('\n', 'utf8');
149
261
  }
262
+ if (config) {
263
+ hash.update(JSON.stringify({
264
+ experienceSlots: config.experienceSlots,
265
+ retrievalPolicy: {
266
+ kind: config.retrievalPolicy.kind,
267
+ minScore: config.retrievalPolicy.minScore,
268
+ scoreWeights: {
269
+ gtScore: config.retrievalPolicy.scoreWeights.gtScore,
270
+ relativeRank: config.retrievalPolicy.scoreWeights.relativeRank
271
+ },
272
+ antiDominanceNormalization: {
273
+ enabled: config.retrievalPolicy.antiDominanceNormalization.enabled,
274
+ strength: config.retrievalPolicy.antiDominanceNormalization.strength,
275
+ sourceGrouping: config.retrievalPolicy.antiDominanceNormalization.sourceGrouping
276
+ }
277
+ }
278
+ }), 'utf8');
279
+ hash.update('\n', 'utf8');
280
+ }
150
281
  return hash.digest('hex');
151
282
  }
@@ -1,11 +1,76 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { createWriteStream, mkdtempSync } from 'node:fs';
2
+ import { createWriteStream, mkdtempSync, rmSync } from 'node:fs';
3
3
  import { rm } from 'node:fs/promises';
4
4
  import { EventEmitter } from 'node:events';
5
5
  import { join } from 'node:path';
6
6
  import { createInterface } from 'node:readline';
7
7
  import { PassThrough } from 'node:stream';
8
8
  import { tmpdir } from 'node:os';
9
+ const activeArtifactRoots = new Set();
10
+ const artifactCleanupFinalizer = new FinalizationRegistry((retention) => {
11
+ retention.releaseCollectedHolder();
12
+ });
13
+ process.once('exit', () => {
14
+ for (const artifactRoot of activeArtifactRoots) {
15
+ try {
16
+ rmSync(artifactRoot, { recursive: true, force: true });
17
+ }
18
+ catch {
19
+ // Best-effort cleanup only.
20
+ }
21
+ }
22
+ });
23
+ class ArtifactRetention {
24
+ artifactRoot;
25
+ holderCount = 0;
26
+ cleaned = false;
27
+ cleanupPromise = null;
28
+ constructor(artifactRoot) {
29
+ this.artifactRoot = artifactRoot;
30
+ activeArtifactRoots.add(artifactRoot);
31
+ }
32
+ registerHolder(target, token) {
33
+ if (this.cleaned) {
34
+ return;
35
+ }
36
+ this.holderCount += 1;
37
+ artifactCleanupFinalizer.register(target, this, token);
38
+ }
39
+ unregisterHolder(token) {
40
+ if (!artifactCleanupFinalizer.unregister(token)) {
41
+ return;
42
+ }
43
+ this.releaseHolder();
44
+ }
45
+ releaseCollectedHolder() {
46
+ this.releaseHolder();
47
+ }
48
+ async cleanup() {
49
+ if (this.cleanupPromise) {
50
+ return await this.cleanupPromise;
51
+ }
52
+ if (!this.cleaned) {
53
+ this.cleaned = true;
54
+ this.holderCount = 0;
55
+ this.cleanupPromise = rm(this.artifactRoot, { recursive: true, force: true })
56
+ .catch(() => { })
57
+ .finally(() => {
58
+ activeArtifactRoots.delete(this.artifactRoot);
59
+ })
60
+ .then(() => undefined);
61
+ }
62
+ await this.cleanupPromise;
63
+ }
64
+ releaseHolder() {
65
+ if (this.cleaned || this.holderCount === 0) {
66
+ return;
67
+ }
68
+ this.holderCount -= 1;
69
+ if (this.holderCount === 0) {
70
+ void this.cleanup();
71
+ }
72
+ }
73
+ }
9
74
  export class ExecClient {
10
75
  cliPath;
11
76
  cwd;
@@ -49,11 +114,15 @@ export class ExecRunHandle extends EventEmitter {
49
114
  eventsFilePath;
50
115
  stderrFilePath;
51
116
  artifactRoot;
117
+ artifactRetention;
52
118
  maxEventBuffer = 200;
53
119
  maxStderrBuffer = 200;
54
120
  streamsClosed = false;
121
+ artifactsCleaned = false;
122
+ resultSettled = false;
55
123
  summaryEvent = null;
56
124
  resultPromise;
125
+ resolvedResult = null;
57
126
  resolveResult;
58
127
  rejectResult;
59
128
  constructor(client, baseOptions, child) {
@@ -64,12 +133,15 @@ export class ExecRunHandle extends EventEmitter {
64
133
  this.artifactRoot = mkdtempSync(join(tmpdir(), 'codex-exec-'));
65
134
  this.eventsFilePath = join(this.artifactRoot, 'events.ndjson');
66
135
  this.stderrFilePath = join(this.artifactRoot, 'stderr.log');
136
+ this.artifactRetention = new ArtifactRetention(this.artifactRoot);
137
+ this.artifactRetention.registerHolder(this, this);
67
138
  this.eventsStream = createWriteStream(this.eventsFilePath, { flags: 'a' });
68
139
  this.stderrStream = createWriteStream(this.stderrFilePath, { flags: 'a' });
69
140
  this.resultPromise = new Promise((resolve, reject) => {
70
141
  this.resolveResult = resolve;
71
142
  this.rejectResult = reject;
72
143
  });
144
+ this.artifactRetention.registerHolder(this.resultPromise, this.resultPromise);
73
145
  const stdout = child.stdout ?? new PassThrough();
74
146
  const stderr = child.stderr ?? new PassThrough();
75
147
  const rl = createInterface({ input: stdout, crlfDelay: Infinity });
@@ -94,7 +166,6 @@ export class ExecRunHandle extends EventEmitter {
94
166
  this.emit('event', parsed);
95
167
  if (parsed.type === 'run:summary') {
96
168
  this.summaryEvent = parsed;
97
- this.resolveResult(this.buildResult());
98
169
  this.emit('summary', this.summaryEvent);
99
170
  }
100
171
  });
@@ -108,19 +179,32 @@ export class ExecRunHandle extends EventEmitter {
108
179
  this.emit('stderr', text);
109
180
  });
110
181
  child.once('error', (error) => {
111
- this.closeStreams();
112
- this.emit('error', error);
113
- this.rejectResult(error);
182
+ if (this.listenerCount('error') > 0) {
183
+ this.emit('error', error);
184
+ }
185
+ this.rejectResultOnce(error);
186
+ void this.closeStreams({ preserveArtifacts: false }).catch(() => {
187
+ // Preserve the original child-process failure as the terminal result.
188
+ });
114
189
  });
115
- child.once('close', (code, signal) => {
116
- this.closeStreams();
190
+ child.once('close', async (code, signal) => {
191
+ const preserveArtifacts = this.summaryEvent !== null;
192
+ try {
193
+ await this.closeStreams({ preserveArtifacts });
194
+ }
195
+ catch (error) {
196
+ this.rejectResultOnce(error);
197
+ return;
198
+ }
117
199
  this.emit('exit', { code, signal });
118
200
  if (!this.summaryEvent) {
119
201
  const error = new Error('Exec command exited without emitting a summary event.');
120
202
  error.exitCode = code ?? null;
121
203
  error.signal = signal ?? null;
122
- this.rejectResult(error);
204
+ this.rejectResultOnce(error);
205
+ return;
123
206
  }
207
+ this.resolveResultOnce(this.buildResult());
124
208
  });
125
209
  }
126
210
  get events() {
@@ -147,12 +231,19 @@ export class ExecRunHandle extends EventEmitter {
147
231
  delete merged.inheritedEnv;
148
232
  return this.client.run(merged);
149
233
  }
234
+ async cleanupArtifacts() {
235
+ await this.result.catch(() => undefined);
236
+ await this.removeArtifacts();
237
+ }
150
238
  buildResult() {
239
+ if (this.resolvedResult) {
240
+ return this.resolvedResult;
241
+ }
151
242
  if (!this.summaryEvent) {
152
243
  throw new Error('Summary not available');
153
244
  }
154
245
  const payload = this.summaryEvent.payload;
155
- return {
246
+ const result = {
156
247
  summary: this.summaryEvent,
157
248
  events: [...this.eventsList],
158
249
  eventsPath: this.eventsFilePath,
@@ -162,15 +253,48 @@ export class ExecRunHandle extends EventEmitter {
162
253
  rawStderr: [...this.stderrLines],
163
254
  stderrPath: this.stderrFilePath
164
255
  };
256
+ this.resolvedResult = result;
257
+ this.artifactRetention.registerHolder(result, result);
258
+ return result;
259
+ }
260
+ resolveResultOnce(value) {
261
+ if (this.resultSettled) {
262
+ return;
263
+ }
264
+ this.resultSettled = true;
265
+ this.resolveResult(value);
266
+ }
267
+ rejectResultOnce(reason) {
268
+ if (this.resultSettled) {
269
+ return;
270
+ }
271
+ this.resultSettled = true;
272
+ this.rejectResult(reason);
165
273
  }
166
- closeStreams() {
274
+ async closeStreams(options) {
167
275
  if (this.streamsClosed) {
168
276
  return;
169
277
  }
170
278
  this.streamsClosed = true;
171
- this.eventsStream.end();
172
- this.stderrStream.end();
173
- void rm(this.artifactRoot, { recursive: true, force: true }).catch(() => { });
279
+ await Promise.all([
280
+ new Promise((resolve) => this.eventsStream.end(resolve)),
281
+ new Promise((resolve) => this.stderrStream.end(resolve))
282
+ ]);
283
+ if (!options.preserveArtifacts) {
284
+ await this.removeArtifacts();
285
+ }
286
+ }
287
+ async removeArtifacts() {
288
+ if (this.artifactsCleaned) {
289
+ return;
290
+ }
291
+ this.artifactsCleaned = true;
292
+ this.artifactRetention.unregisterHolder(this);
293
+ this.artifactRetention.unregisterHolder(this.resultPromise);
294
+ if (this.resolvedResult) {
295
+ this.artifactRetention.unregisterHolder(this.resolvedResult);
296
+ }
297
+ await this.artifactRetention.cleanup();
174
298
  }
175
299
  }
176
300
  function buildCliArgs(options) {
@@ -1,6 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
- import { load as parseYaml } from 'js-yaml';
4
3
  const DEFAULT_CONFIG_PATH = 'design.config.yaml';
5
4
  const DEFAULT_RETENTION_DAYS = 30;
6
5
  const DEFAULT_CONFIG = {
@@ -76,6 +75,7 @@ const DEFAULT_CONFIG = {
76
75
  };
77
76
  const DESIGN_REFERENCE_PIPELINE_ID = 'design-reference';
78
77
  const HI_FI_TOOLKIT_PIPELINE_ID = 'hi-fi-design-toolkit';
78
+ let designConfigYamlLoader = null;
79
79
  export function designPipelineId(result, env = process.env) {
80
80
  return selectDesignPipeline(result ?? null, env).id;
81
81
  }
@@ -84,6 +84,7 @@ export async function loadDesignConfig(options = {}) {
84
84
  const path = options.filePath ?? join(rootDir, DEFAULT_CONFIG_PATH);
85
85
  try {
86
86
  const raw = await readFile(path, 'utf-8');
87
+ const parseYaml = await loadDesignConfigYaml();
87
88
  const parsed = parseYaml(raw);
88
89
  const warnings = [];
89
90
  const config = normalizeDesignConfig(parsed, warnings);
@@ -97,6 +98,12 @@ export async function loadDesignConfig(options = {}) {
97
98
  throw new Error(`Failed to load design config at ${path}: ${error.message}`);
98
99
  }
99
100
  }
101
+ async function loadDesignConfigYaml() {
102
+ if (!designConfigYamlLoader) {
103
+ designConfigYamlLoader = import('js-yaml').then((module) => module.load);
104
+ }
105
+ return await designConfigYamlLoader;
106
+ }
100
107
  export function shouldActivateDesignPipeline(result, env = process.env) {
101
108
  return selectDesignPipeline(result, env).shouldRun;
102
109
  }
@@ -1,2 +1,2 @@
1
- // Deprecated shim: keep exports stable while stdio tracking moves into packages/orchestrator.
1
+ // Deprecated shim: keep exports stable for published importers while stdio tracking lives in packages/orchestrator.
2
2
  export * from '../../orchestrator/src/exec/stdio.js';