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