@kbediako/codex-orchestrator 0.1.38 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/README.md +46 -317
  3. package/bin/codex-orchestrator.js +161 -0
  4. package/codex.orchestrator.json +149 -13
  5. package/dist/bin/codex-orchestrator.js +797 -1154
  6. package/dist/orchestrator/src/cli/adapters/CommandBuilder.js +50 -0
  7. package/dist/orchestrator/src/cli/adapters/CommandPlanner.js +22 -4
  8. package/dist/orchestrator/src/cli/adapters/CommandReviewer.js +3 -3
  9. package/dist/orchestrator/src/cli/adapters/CommandTester.js +2 -2
  10. package/dist/orchestrator/src/cli/adapters/cloudFailureDiagnostics.js +295 -11
  11. package/dist/orchestrator/src/cli/coStatusAttachCliShell.js +402 -0
  12. package/dist/orchestrator/src/cli/coStatusCliShell.js +451 -0
  13. package/dist/orchestrator/src/cli/coStatusOperatorAutopilotCliShell.js +120 -0
  14. package/dist/orchestrator/src/cli/codexCliShell.js +119 -0
  15. package/dist/orchestrator/src/cli/codexDefaultsSetup.js +265 -36
  16. package/dist/orchestrator/src/cli/config/delegationConfig.js +317 -5
  17. package/dist/orchestrator/src/cli/config/repoConfigPolicy.js +2 -3
  18. package/dist/orchestrator/src/cli/config/userConfig.js +28 -13
  19. package/dist/orchestrator/src/cli/control/authenticatedControlRouteGate.js +69 -0
  20. package/dist/orchestrator/src/cli/control/authenticatedRouteComposition.js +267 -0
  21. package/dist/orchestrator/src/cli/control/authenticatedRouteController.js +5 -0
  22. package/dist/orchestrator/src/cli/control/authenticatedRouteDispatcher.js +41 -0
  23. package/dist/orchestrator/src/cli/control/compatibilityIssuePresenter.js +1035 -0
  24. package/dist/orchestrator/src/cli/control/confirmationApproveController.js +62 -0
  25. package/dist/orchestrator/src/cli/control/confirmationCreateController.js +69 -0
  26. package/dist/orchestrator/src/cli/control/confirmationIssueConsumeController.js +43 -0
  27. package/dist/orchestrator/src/cli/control/confirmationListController.js +22 -0
  28. package/dist/orchestrator/src/cli/control/confirmationValidateController.js +58 -0
  29. package/dist/orchestrator/src/cli/control/confirmations.js +25 -3
  30. package/dist/orchestrator/src/cli/control/controlActionCancelConfirmation.js +65 -0
  31. package/dist/orchestrator/src/cli/control/controlActionController.js +77 -0
  32. package/dist/orchestrator/src/cli/control/controlActionControllerSequencing.js +161 -0
  33. package/dist/orchestrator/src/cli/control/controlActionExecution.js +142 -0
  34. package/dist/orchestrator/src/cli/control/controlActionFinalization.js +43 -0
  35. package/dist/orchestrator/src/cli/control/controlActionOutcome.js +60 -0
  36. package/dist/orchestrator/src/cli/control/controlActionPreflight.js +476 -0
  37. package/dist/orchestrator/src/cli/control/controlAuthenticatedRouteHandoff.js +57 -0
  38. package/dist/orchestrator/src/cli/control/controlBootstrapAssembly.js +39 -0
  39. package/dist/orchestrator/src/cli/control/controlBootstrapMetadataPersistence.js +16 -0
  40. package/dist/orchestrator/src/cli/control/controlEventTransport.js +49 -0
  41. package/dist/orchestrator/src/cli/control/controlExpiryLifecycle.js +102 -0
  42. package/dist/orchestrator/src/cli/control/controlHostOwnership.js +480 -0
  43. package/dist/orchestrator/src/cli/control/controlHostSupervision.js +630 -0
  44. package/dist/orchestrator/src/cli/control/controlOversightFacade.js +8 -0
  45. package/dist/orchestrator/src/cli/control/controlOversightReadContract.js +1 -0
  46. package/dist/orchestrator/src/cli/control/controlOversightReadService.js +16 -0
  47. package/dist/orchestrator/src/cli/control/controlOversightUpdateContract.js +1 -0
  48. package/dist/orchestrator/src/cli/control/controlPersistenceFiles.js +6 -0
  49. package/dist/orchestrator/src/cli/control/controlQuestionChildResolution.js +18 -0
  50. package/dist/orchestrator/src/cli/control/controlRequestContext.js +42 -0
  51. package/dist/orchestrator/src/cli/control/controlRequestController.js +9 -0
  52. package/dist/orchestrator/src/cli/control/controlRequestPredispatch.js +17 -0
  53. package/dist/orchestrator/src/cli/control/controlRequestRouteDispatch.js +44 -0
  54. package/dist/orchestrator/src/cli/control/controlRuntime.js +1003 -0
  55. package/dist/orchestrator/src/cli/control/controlServer.js +23 -1456
  56. package/dist/orchestrator/src/cli/control/controlServerAuditAndErrorHelpers.js +115 -0
  57. package/dist/orchestrator/src/cli/control/controlServerAuthenticatedRouteBranch.js +29 -0
  58. package/dist/orchestrator/src/cli/control/controlServerBootstrapLifecycle.js +30 -0
  59. package/dist/orchestrator/src/cli/control/controlServerBootstrapStartSequence.js +21 -0
  60. package/dist/orchestrator/src/cli/control/controlServerOwnedRuntimeLifecycle.js +67 -0
  61. package/dist/orchestrator/src/cli/control/controlServerPublicLifecycle.js +756 -0
  62. package/dist/orchestrator/src/cli/control/controlServerPublicRouteHelpers.js +86 -0
  63. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceLifecycle.js +25 -0
  64. package/dist/orchestrator/src/cli/control/controlServerReadyInstanceStartup.js +18 -0
  65. package/dist/orchestrator/src/cli/control/controlServerRequestBodyHelpers.js +37 -0
  66. package/dist/orchestrator/src/cli/control/controlServerRequestShell.js +40 -0
  67. package/dist/orchestrator/src/cli/control/controlServerRequestShellBinding.js +17 -0
  68. package/dist/orchestrator/src/cli/control/controlServerSeedLoading.js +27 -0
  69. package/dist/orchestrator/src/cli/control/controlServerSeededRuntimeAssembly.js +186 -0
  70. package/dist/orchestrator/src/cli/control/controlServerStartupInputPreparation.js +31 -0
  71. package/dist/orchestrator/src/cli/control/controlServerStartupSequence.js +49 -0
  72. package/dist/orchestrator/src/cli/control/controlState.js +233 -2
  73. package/dist/orchestrator/src/cli/control/controlStatusDashboard.js +1904 -0
  74. package/dist/orchestrator/src/cli/control/controlTelegramBridgeBootstrapLifecycle.js +22 -0
  75. package/dist/orchestrator/src/cli/control/controlTelegramBridgeLifecycle.js +67 -0
  76. package/dist/orchestrator/src/cli/control/controlTelegramBridgeOversightFacadeFactory.js +8 -0
  77. package/dist/orchestrator/src/cli/control/controlTelegramCommandController.js +49 -0
  78. package/dist/orchestrator/src/cli/control/controlTelegramDispatchRead.js +40 -0
  79. package/dist/orchestrator/src/cli/control/controlTelegramPollingController.js +89 -0
  80. package/dist/orchestrator/src/cli/control/controlTelegramProjectionNotificationController.js +29 -0
  81. package/dist/orchestrator/src/cli/control/controlTelegramPushState.js +63 -0
  82. package/dist/orchestrator/src/cli/control/controlTelegramQuestionRead.js +13 -0
  83. package/dist/orchestrator/src/cli/control/controlTelegramReadController.js +216 -0
  84. package/dist/orchestrator/src/cli/control/controlTelegramUpdateHandler.js +63 -0
  85. package/dist/orchestrator/src/cli/control/controlWatcher.js +73 -5
  86. package/dist/orchestrator/src/cli/control/delegationRegisterController.js +35 -0
  87. package/dist/orchestrator/src/cli/control/dynamicToolBridgePolicy.js +139 -0
  88. package/dist/orchestrator/src/cli/control/eventsSseController.js +12 -0
  89. package/dist/orchestrator/src/cli/control/linearBudgetState.js +1789 -0
  90. package/dist/orchestrator/src/cli/control/linearDispatchSource.js +1137 -0
  91. package/dist/orchestrator/src/cli/control/linearGraphqlClient.js +150 -0
  92. package/dist/orchestrator/src/cli/control/linearRateLimit.js +102 -0
  93. package/dist/orchestrator/src/cli/control/linearWebhookController.js +499 -0
  94. package/dist/orchestrator/src/cli/control/liveLinearAdvisoryRuntime.js +70 -0
  95. package/dist/orchestrator/src/cli/control/observabilityApiController.js +173 -0
  96. package/dist/orchestrator/src/cli/control/observabilityReadModel.js +500 -0
  97. package/dist/orchestrator/src/cli/control/observabilitySurface.js +284 -0
  98. package/dist/orchestrator/src/cli/control/observabilityUpdateNotifier.js +22 -0
  99. package/dist/orchestrator/src/cli/control/operatorDashboardPresenter.js +252 -0
  100. package/dist/orchestrator/src/cli/control/providerAgentCapacity.js +70 -0
  101. package/dist/orchestrator/src/cli/control/providerControlHostFreshnessGauge.js +1068 -0
  102. package/dist/orchestrator/src/cli/control/providerIntakeState.js +473 -0
  103. package/dist/orchestrator/src/cli/control/providerIssueHandoff.js +6811 -0
  104. package/dist/orchestrator/src/cli/control/providerIssueObservability.js +1348 -0
  105. package/dist/orchestrator/src/cli/control/providerIssueRetryQueue.js +84 -0
  106. package/dist/orchestrator/src/cli/control/providerLinearRuntimeProof.js +588 -0
  107. package/dist/orchestrator/src/cli/control/providerLinearScreenshotProof.js +473 -0
  108. package/dist/orchestrator/src/cli/control/providerLinearWorkerTruth.js +383 -0
  109. package/dist/orchestrator/src/cli/control/providerLinearWorkflowAudit.js +254 -0
  110. package/dist/orchestrator/src/cli/control/providerLinearWorkflowFacade.js +5573 -0
  111. package/dist/orchestrator/src/cli/control/providerLinearWorkflowStates.js +115 -0
  112. package/dist/orchestrator/src/cli/control/providerMergeCloseout.js +1868 -0
  113. package/dist/orchestrator/src/cli/control/providerOperatorAutopilot.js +1580 -0
  114. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLifecycle.js +154 -0
  115. package/dist/orchestrator/src/cli/control/providerOperatorAutopilotLocalRolloutExecution.js +1006 -0
  116. package/dist/orchestrator/src/cli/control/providerPollingHealth.js +435 -0
  117. package/dist/orchestrator/src/cli/control/providerTerminalCleanup.js +516 -0
  118. package/dist/orchestrator/src/cli/control/providerWorkerHosts.js +191 -0
  119. package/dist/orchestrator/src/cli/control/providerWorkflowConfigStore.js +515 -0
  120. package/dist/orchestrator/src/cli/control/questionChildResolutionAdapter.js +361 -0
  121. package/dist/orchestrator/src/cli/control/questionQueueController.js +181 -0
  122. package/dist/orchestrator/src/cli/control/questionReadRetryDeduplication.js +9 -0
  123. package/dist/orchestrator/src/cli/control/questionReadSequence.js +10 -0
  124. package/dist/orchestrator/src/cli/control/securityViolationController.js +27 -0
  125. package/dist/orchestrator/src/cli/control/selectedRunProjection.js +1885 -0
  126. package/dist/orchestrator/src/cli/control/telegramOversightApiClient.js +48 -0
  127. package/dist/orchestrator/src/cli/control/telegramOversightBridge.js +180 -0
  128. package/dist/orchestrator/src/cli/control/telegramOversightBridgeProjectionDeliveryQueue.js +25 -0
  129. package/dist/orchestrator/src/cli/control/telegramOversightBridgeRuntimeLifecycle.js +45 -0
  130. package/dist/orchestrator/src/cli/control/telegramOversightBridgeStateStore.js +77 -0
  131. package/dist/orchestrator/src/cli/control/telegramOversightControlActionApiClient.js +45 -0
  132. package/dist/orchestrator/src/cli/control/trackerDispatchPilot.js +439 -0
  133. package/dist/orchestrator/src/cli/control/uiDataController.js +34 -0
  134. package/dist/orchestrator/src/cli/control/uiSessionController.js +100 -0
  135. package/dist/orchestrator/src/cli/controlHostCliShell.js +860 -0
  136. package/dist/orchestrator/src/cli/controlHostFreshnessGaugeCliShell.js +129 -0
  137. package/dist/orchestrator/src/cli/controlHostSupervisionCliShell.js +2127 -0
  138. package/dist/orchestrator/src/cli/delegationCliShell.js +62 -0
  139. package/dist/orchestrator/src/cli/delegationServer.js +567 -678
  140. package/dist/orchestrator/src/cli/delegationServerCliShell.js +52 -0
  141. package/dist/orchestrator/src/cli/delegationServerQuestionFlowShell.js +228 -0
  142. package/dist/orchestrator/src/cli/delegationServerToolDispatchShell.js +411 -0
  143. package/dist/orchestrator/src/cli/delegationServerTransport.js +274 -0
  144. package/dist/orchestrator/src/cli/delegationSetup.js +51 -171
  145. package/dist/orchestrator/src/cli/devtoolsCliShell.js +34 -0
  146. package/dist/orchestrator/src/cli/doctor.js +678 -164
  147. package/dist/orchestrator/src/cli/doctorCliRequestShell.js +72 -0
  148. package/dist/orchestrator/src/cli/doctorCliShell.js +138 -0
  149. package/dist/orchestrator/src/cli/doctorUsage.js +119 -15
  150. package/dist/orchestrator/src/cli/exec/experience.js +16 -2
  151. package/dist/orchestrator/src/cli/exec/summary.js +3 -0
  152. package/dist/orchestrator/src/cli/execCliShell.js +51 -0
  153. package/dist/orchestrator/src/cli/flowCliRequestShell.js +44 -0
  154. package/dist/orchestrator/src/cli/flowCliShell.js +239 -0
  155. package/dist/orchestrator/src/cli/frontendTestCliRequestShell.js +80 -0
  156. package/dist/orchestrator/src/cli/frontendTestCliShell.js +41 -0
  157. package/dist/orchestrator/src/cli/init.js +95 -1
  158. package/dist/orchestrator/src/cli/initCliShell.js +50 -0
  159. package/dist/orchestrator/src/cli/linearCliShell.js +1200 -0
  160. package/dist/orchestrator/src/cli/mcpEnableCliShell.js +132 -0
  161. package/dist/orchestrator/src/cli/metrics/metricsAggregator.js +3 -2
  162. package/dist/orchestrator/src/cli/metrics/metricsRecorder.js +56 -0
  163. package/dist/orchestrator/src/cli/orchestrator.js +66 -1376
  164. package/dist/orchestrator/src/cli/planCliShell.js +19 -0
  165. package/dist/orchestrator/src/cli/prCliShell.js +41 -0
  166. package/dist/orchestrator/src/cli/providerLinearChildLanePhaseContract.js +204 -0
  167. package/dist/orchestrator/src/cli/providerLinearChildLaneRunner.js +1835 -0
  168. package/dist/orchestrator/src/cli/providerLinearChildLaneShell.js +2420 -0
  169. package/dist/orchestrator/src/cli/providerLinearChildStreamShell.js +385 -0
  170. package/dist/orchestrator/src/cli/providerLinearWorkerRunner.js +6834 -0
  171. package/dist/orchestrator/src/cli/resumeCliShell.js +14 -0
  172. package/dist/orchestrator/src/cli/reviewCliLaunchShell.js +72 -0
  173. package/dist/orchestrator/src/cli/rlm/alignment.js +3 -3
  174. package/dist/orchestrator/src/cli/rlm/context.js +94 -7
  175. package/dist/orchestrator/src/cli/rlm/rlmCodexRuntimeShell.js +546 -0
  176. package/dist/orchestrator/src/cli/rlm/symbolic.js +4 -2
  177. package/dist/orchestrator/src/cli/rlmCliRequestShell.js +42 -0
  178. package/dist/orchestrator/src/cli/rlmCompletionCliShell.js +46 -0
  179. package/dist/orchestrator/src/cli/rlmLaunchCliShell.js +51 -0
  180. package/dist/orchestrator/src/cli/rlmRunner.js +83 -523
  181. package/dist/orchestrator/src/cli/run/blockMemory.js +500 -0
  182. package/dist/orchestrator/src/cli/run/manifest.js +410 -73
  183. package/dist/orchestrator/src/cli/run/manifestPersister.js +45 -14
  184. package/dist/orchestrator/src/cli/run/runMemoryController.js +216 -0
  185. package/dist/orchestrator/src/cli/run/source0.js +690 -0
  186. package/dist/orchestrator/src/cli/run/workspacePath.js +101 -0
  187. package/dist/orchestrator/src/cli/runtime/mode.js +2 -1
  188. package/dist/orchestrator/src/cli/runtime/provider.js +39 -2
  189. package/dist/orchestrator/src/cli/selfCheckCliShell.js +12 -0
  190. package/dist/orchestrator/src/cli/services/commandRunner.js +698 -18
  191. package/dist/orchestrator/src/cli/services/execRuntime.js +66 -1
  192. package/dist/orchestrator/src/cli/services/orchestratorAutoScoutEvidenceRecorder.js +71 -0
  193. package/dist/orchestrator/src/cli/services/orchestratorCloudBranchResolution.js +8 -0
  194. package/dist/orchestrator/src/cli/services/orchestratorCloudEnvironmentResolution.js +22 -0
  195. package/dist/orchestrator/src/cli/services/orchestratorCloudExecutionLifecycleShell.js +39 -0
  196. package/dist/orchestrator/src/cli/services/orchestratorCloudPromptBuilder.js +37 -0
  197. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteFallbackContract.js +45 -0
  198. package/dist/orchestrator/src/cli/services/orchestratorCloudRouteShell.js +36 -0
  199. package/dist/orchestrator/src/cli/services/orchestratorCloudTargetExecutor.js +277 -0
  200. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycle.js +98 -0
  201. package/dist/orchestrator/src/cli/services/orchestratorControlPlaneLifecycleShell.js +54 -0
  202. package/dist/orchestrator/src/cli/services/orchestratorExecutionLifecycle.js +112 -0
  203. package/dist/orchestrator/src/cli/services/orchestratorExecutionModePolicy.js +27 -0
  204. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteAdapterShell.js +59 -0
  205. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteDecisionShell.js +57 -0
  206. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouteState.js +21 -0
  207. package/dist/orchestrator/src/cli/services/orchestratorExecutionRouter.js +2 -0
  208. package/dist/orchestrator/src/cli/services/orchestratorLocalPipelineExecutor.js +149 -0
  209. package/dist/orchestrator/src/cli/services/orchestratorLocalRouteShell.js +63 -0
  210. package/dist/orchestrator/src/cli/services/orchestratorPlanShell.js +54 -0
  211. package/dist/orchestrator/src/cli/services/orchestratorPlanTargetTracker.js +16 -0
  212. package/dist/orchestrator/src/cli/services/orchestratorResumePreparationShell.js +84 -0
  213. package/dist/orchestrator/src/cli/services/orchestratorResumeTokenValidation.js +15 -0
  214. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleCompletion.js +31 -0
  215. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleExecutionRegistration.js +37 -0
  216. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleOrchestrationShell.js +83 -0
  217. package/dist/orchestrator/src/cli/services/orchestratorRunLifecycleTaskManagerShell.js +37 -0
  218. package/dist/orchestrator/src/cli/services/orchestratorRuntimeManifestMutation.js +20 -0
  219. package/dist/orchestrator/src/cli/services/orchestratorStartPreparationShell.js +56 -0
  220. package/dist/orchestrator/src/cli/services/orchestratorStatusShell.js +70 -0
  221. package/dist/orchestrator/src/cli/services/pipelineResolver.js +7 -3
  222. package/dist/orchestrator/src/cli/services/plannerMemory.js +119 -0
  223. package/dist/orchestrator/src/cli/services/runPreparation.js +7 -3
  224. package/dist/orchestrator/src/cli/services/runSummaryWriter.js +9 -0
  225. package/dist/orchestrator/src/cli/setupBootstrapShell.js +114 -0
  226. package/dist/orchestrator/src/cli/setupCliShell.js +51 -0
  227. package/dist/orchestrator/src/cli/skillsCliShell.js +56 -0
  228. package/dist/orchestrator/src/cli/startCliRequestShell.js +53 -0
  229. package/dist/orchestrator/src/cli/startCliShell.js +68 -0
  230. package/dist/orchestrator/src/cli/statusCliShell.js +22 -0
  231. package/dist/orchestrator/src/cli/utils/authProvenanceFingerprint.js +27 -0
  232. package/dist/orchestrator/src/cli/utils/cloudPreflight.js +285 -7
  233. package/dist/orchestrator/src/cli/utils/codexFeatures.js +60 -0
  234. package/dist/orchestrator/src/cli/utils/delegationConfigParser.js +250 -0
  235. package/dist/orchestrator/src/cli/utils/delegationMcpHealth.js +1382 -0
  236. package/dist/orchestrator/src/cli/utils/devtools.js +2 -54
  237. package/dist/orchestrator/src/cli/utils/mcpServerEntry.js +53 -0
  238. package/dist/orchestrator/src/cli/utils/packageProgramResolver.js +151 -0
  239. package/dist/orchestrator/src/cli/utils/providerOverrideEnv.js +71 -0
  240. package/dist/orchestrator/src/cli/utils/trailingJsonObject.js +59 -0
  241. package/dist/orchestrator/src/learning/crystalizer.js +2 -2
  242. package/dist/orchestrator/src/manager.js +74 -4
  243. package/dist/orchestrator/src/persistence/ExperienceStore.js +233 -49
  244. package/dist/orchestrator/src/persistence/TaskStateStore.js +6 -6
  245. package/dist/orchestrator/src/persistence/lockFile.js +70 -4
  246. package/dist/orchestrator/src/persistence/sanitizeIdentifier.js +39 -0
  247. package/dist/orchestrator/src/sync/createCloudSyncWorker.js +3 -2
  248. package/dist/orchestrator/src/utils/atomicWrite.js +17 -2
  249. package/dist/packages/orchestrator/src/exec/unified-exec.js +99 -6
  250. package/dist/packages/orchestrator/src/instructions/promptPacks.js +150 -19
  251. package/dist/packages/sdk-node/src/orchestrator.js +137 -13
  252. package/dist/packages/shared/config/designConfig.js +8 -1
  253. package/dist/packages/shared/streams/stdio.js +1 -1
  254. package/dist/scripts/design/pipeline/permit.js +15 -0
  255. package/dist/scripts/lib/docs-catalog.js +399 -0
  256. package/dist/scripts/lib/docs-helpers.js +87 -5
  257. package/dist/scripts/lib/pr-watch-merge.js +1088 -80
  258. package/dist/scripts/lib/provider-run-contract.js +26 -0
  259. package/dist/scripts/lib/review-command-intent-classification.js +532 -0
  260. package/dist/scripts/lib/review-command-probe-classification.js +385 -0
  261. package/dist/scripts/lib/review-execution-boundary-preflight.js +279 -0
  262. package/dist/scripts/lib/review-execution-runtime.js +753 -0
  263. package/dist/scripts/lib/review-execution-state.js +1144 -0
  264. package/dist/scripts/lib/review-execution-telemetry.js +215 -0
  265. package/dist/scripts/lib/review-inspection-target-parsing.js +78 -0
  266. package/dist/scripts/lib/review-launch-attempt.js +601 -0
  267. package/dist/scripts/lib/review-meta-surface-boundary-analysis.js +300 -0
  268. package/dist/scripts/lib/review-meta-surface-normalization.js +746 -0
  269. package/dist/scripts/lib/review-non-interactive-handoff.js +61 -0
  270. package/dist/scripts/lib/review-prompt-context.js +376 -0
  271. package/dist/scripts/lib/review-scope-advisory.js +286 -0
  272. package/dist/scripts/lib/review-scope-paths.js +123 -0
  273. package/dist/scripts/lib/review-shell-command-parser.js +389 -0
  274. package/dist/scripts/lib/review-shell-env-interpreter.js +340 -0
  275. package/dist/scripts/lib/run-manifests.js +192 -36
  276. package/dist/scripts/lib/spark-policy-classifier.js +593 -0
  277. package/dist/scripts/run-review.js +507 -1777
  278. package/docs/README.md +43 -20
  279. package/docs/book/README.md +19 -0
  280. package/docs/book/codex-cli-0124-adoption.md +68 -0
  281. package/docs/book/local-hook-impact.md +73 -0
  282. package/docs/book/operations.md +60 -0
  283. package/docs/book/public-posture.md +34 -0
  284. package/docs/book/setup.md +91 -0
  285. package/docs/book/skills.md +11 -0
  286. package/docs/guides/codex-version-policy.md +104 -0
  287. package/docs/public/downstream-setup.md +113 -0
  288. package/docs/public/provider-onboarding.md +173 -0
  289. package/package.json +23 -10
  290. package/plugins/codex-orchestrator/.codex-plugin/plugin.json +30 -0
  291. package/plugins/codex-orchestrator/.mcp.json +13 -0
  292. package/plugins/codex-orchestrator/launcher.mjs +361 -0
  293. package/schemas/manifest.json +411 -0
  294. package/skills/README.md +26 -0
  295. package/skills/collab-subagents-first/SKILL.md +1 -1
  296. package/skills/delegation-usage/DELEGATION_GUIDE.md +30 -12
  297. package/skills/delegation-usage/SKILL.md +25 -14
  298. package/skills/land/SKILL.md +77 -0
  299. package/skills/linear/SKILL.md +255 -0
  300. package/skills/release/SKILL.md +47 -3
  301. package/skills/standalone-review/SKILL.md +6 -1
  302. package/templates/README.md +4 -2
  303. package/templates/codex/.codex/agents/awaiter-high.toml +2 -2
  304. package/templates/codex/.codex/agents/worker-complex.toml +1 -1
  305. package/templates/codex/.codex/config.toml +3 -4
  306. package/templates/codex/.codex/providers/README.md +13 -0
  307. package/templates/codex/.codex/providers/control.example.json +18 -0
  308. package/templates/codex/.codex/providers/provider.env.example +15 -0
  309. package/templates/codex/AGENTS.md +15 -8
  310. package/templates/codex/mcp-client.json +5 -1
  311. package/docs/assets/setup.gif +0 -0
@@ -0,0 +1,1835 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { mkdir, mkdtemp, open, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
3
+ import { createRequire } from 'node:module';
4
+ import { tmpdir } from 'node:os';
5
+ import { basename, dirname, isAbsolute, join, parse as parsePath, relative, resolve } from 'node:path';
6
+ import process from 'node:process';
7
+ import { promisify } from 'node:util';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { logger } from '../logger.js';
10
+ import { acquireLockWithRetry } from '../persistence/lockFile.js';
11
+ import { writeAtomicFile } from '../utils/atomicWrite.js';
12
+ import { buildEmptyProviderLinearWorkerTokenUsage, defaultExecRunner, parseProviderLinearWorkerJsonl, PROVIDER_LINEAR_CHILD_LANE_DIAGNOSTICS_FILENAME } from './providerLinearWorkerRunner.js';
13
+ import { createRuntimeCodexCommandContext, formatRuntimeSelectionSummary, parseRuntimeMode, resolveRuntimeCodexCommand } from './runtime/index.js';
14
+ import { buildRunMemoryPromptLines, selectRunMemoryForRole } from './run/runMemoryController.js';
15
+ import { resolveProviderLinearChildLaneScopeContract } from './providerLinearChildLanePhaseContract.js';
16
+ import { resolveCodexHome } from './utils/codexPaths.js';
17
+ const execFileAsync = promisify(execFile);
18
+ const require = createRequire(import.meta.url);
19
+ const PROVIDER_LINEAR_CHILD_LANE_APPSERVER_STARTUP_TIMEOUT_MS = 90 * 1000;
20
+ const PROVIDER_LINEAR_CHILD_LANE_APPSERVER_STARTUP_POLL_INTERVAL_MS = 250;
21
+ const PROVIDER_LINEAR_CHILD_LANE_SCOPE_DRIFT_POLL_INTERVAL_MS = 250;
22
+ const PROVIDER_LINEAR_CHILD_LANE_SESSION_LOG_DISCOVERY_WINDOW_MS = 10 * 60 * 1000;
23
+ const PROVIDER_LINEAR_CHILD_LANE_SESSION_LOG_HEADER_BYTES = 256 * 1024;
24
+ const PROVIDER_LINEAR_CHILD_LANE_SESSION_LOG_MTIME_SKEW_MS = 1000;
25
+ const PROVIDER_LINEAR_CHILD_LANE_RUNNER_ENTRYPOINT = 'providerLinearChildLaneRunner';
26
+ let tomlParser;
27
+ const PROVIDER_LINEAR_CHILD_LANE_TRUSTED_PROJECT_CONFIG_LOCK_RETRY = {
28
+ maxAttempts: 50,
29
+ initialDelayMs: 10,
30
+ backoffFactor: 1.5,
31
+ maxDelayMs: 250,
32
+ staleMs: 30_000
33
+ };
34
+ export const PROVIDER_LINEAR_CHILD_LANE_PROOF_FILENAME = 'provider-linear-child-lane-proof.json';
35
+ export const PROVIDER_LINEAR_CHILD_LANE_STREAM_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_STREAM';
36
+ export const PROVIDER_LINEAR_CHILD_LANE_PURPOSE_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PURPOSE';
37
+ export const PROVIDER_LINEAR_CHILD_LANE_INSTRUCTIONS_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_INSTRUCTIONS';
38
+ export const PROVIDER_LINEAR_CHILD_LANE_FILES_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_FILES';
39
+ export const PROVIDER_LINEAR_CHILD_LANE_PHASES_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PHASES';
40
+ export const PROVIDER_LINEAR_CHILD_LANE_PARENT_WORKSPACE_PATH_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PARENT_WORKSPACE_PATH';
41
+ export const PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_BASE_SHA_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_BASE_SHA';
42
+ export const PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_UPDATED_AT_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_UPDATED_AT';
43
+ export const PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE';
44
+ export const PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_TYPE_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_TYPE';
45
+ export const PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_CAPTURED_AT_ENV = 'CODEX_PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_CAPTURED_AT';
46
+ function normalizeOptionalString(value) {
47
+ if (typeof value !== 'string') {
48
+ return null;
49
+ }
50
+ const trimmed = value.trim();
51
+ return trimmed.length > 0 ? trimmed : null;
52
+ }
53
+ function isRecord(value) {
54
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
55
+ }
56
+ function getTomlParser() {
57
+ if (tomlParser) {
58
+ return tomlParser;
59
+ }
60
+ if (tomlParser === null) {
61
+ throw new Error('Failed to load @iarna/toml.');
62
+ }
63
+ try {
64
+ tomlParser = require('@iarna/toml');
65
+ return tomlParser;
66
+ }
67
+ catch (error) {
68
+ tomlParser = null;
69
+ throw error;
70
+ }
71
+ }
72
+ function normalizeProjectPath(value) {
73
+ const resolved = resolve(value);
74
+ const root = parsePath(resolved).root;
75
+ let normalized = resolved;
76
+ while (normalized.length > root.length && /[\\/]$/u.test(normalized)) {
77
+ normalized = normalized.slice(0, -1);
78
+ }
79
+ return normalized;
80
+ }
81
+ function isPathAncestorOf(ancestor, candidate) {
82
+ const relativePath = relative(ancestor, candidate);
83
+ return relativePath === '' || (!relativePath.startsWith('..') && !isAbsolute(relativePath));
84
+ }
85
+ function pathContainsSegment(path, segment) {
86
+ return normalizeProjectPath(path).split(/[\\/]+/u).includes(segment);
87
+ }
88
+ function isTrustedProjectEntry(value) {
89
+ return isRecord(value) && normalizeOptionalString(value.trust_level)?.toLowerCase() === 'trusted';
90
+ }
91
+ function decodeTomlQuotedString(raw) {
92
+ if (raw.startsWith('"') && raw.endsWith('"')) {
93
+ return JSON.parse(raw);
94
+ }
95
+ return raw.slice(1, -1);
96
+ }
97
+ function isProjectsTableKeyPath(keyPath) {
98
+ return keyPath === 'projects' || keyPath === '"projects"' || keyPath === '\'projects\'';
99
+ }
100
+ function parseProjectTableHeader(line) {
101
+ const keyPath = parseTomlTableKeyPath(line);
102
+ if (!keyPath) {
103
+ return null;
104
+ }
105
+ const match = keyPath.match(/^(?:"projects"|'projects'|projects)\s*\.\s*("(?:[^"\\]|\\.)*"|'[^']*')\s*$/u);
106
+ if (!match) {
107
+ return null;
108
+ }
109
+ return normalizeProjectPath(decodeTomlQuotedString(match[1]));
110
+ }
111
+ function parseTomlTableKeyPath(line) {
112
+ const match = line
113
+ .trim()
114
+ .match(/^(?:\[\[((?:[^"'\\\]]+|"(?:[^"\\]|\\.)*"|'[^']*')+)\]\]|\[((?:[^"'\\\]]+|"(?:[^"\\]|\\.)*"|'[^']*')+)\])\s*(?:#.*)?$/u);
115
+ return (match?.[1] ?? match?.[2] ?? null)?.trim() ?? null;
116
+ }
117
+ function parseProjectNamespaceHeader(line) {
118
+ const keyPath = parseTomlTableKeyPath(line);
119
+ if (!keyPath) {
120
+ return null;
121
+ }
122
+ const match = keyPath.match(/^(?:"projects"|'projects'|projects)\s*\.\s*("(?:[^"\\]|\\.)*"|'[^']*')(?:\s*\.\s*|$)/u);
123
+ if (!match) {
124
+ return null;
125
+ }
126
+ return normalizeProjectPath(decodeTomlQuotedString(match[1]));
127
+ }
128
+ function parseInlineProjectEntry(line, currentTableKeyPath) {
129
+ const trimmed = line.trim();
130
+ const inlineKeyPattern = /^("(?:[^"\\]|\\.)*"|'[^']*')\s*=\s*\{.*\}\s*(?:#.*)?$/u;
131
+ const dottedInlineKeyPattern = /^(?:"projects"|'projects'|projects)\s*\.\s*("(?:[^"\\]|\\.)*"|'[^']*')\s*=\s*\{.*\}\s*(?:#.*)?$/u;
132
+ const inlineMatch = isProjectsTableKeyPath(currentTableKeyPath)
133
+ ? trimmed.match(inlineKeyPattern)
134
+ : currentTableKeyPath === null
135
+ ? trimmed.match(dottedInlineKeyPattern)
136
+ : null;
137
+ if (inlineMatch) {
138
+ return normalizeProjectPath(decodeTomlQuotedString(inlineMatch[1]));
139
+ }
140
+ const dottedAssignmentPattern = /^("(?:[^"\\]|\\.)*"|'[^']*')\s*\.\s*.+?=\s*(.+)$/u;
141
+ const topLevelDottedAssignmentPattern = /^(?:"projects"|'projects'|projects)\s*\.\s*("(?:[^"\\]|\\.)*"|'[^']*')\s*\.\s*.+?=\s*(.+)$/u;
142
+ const dottedMatch = isProjectsTableKeyPath(currentTableKeyPath)
143
+ ? trimmed.match(dottedAssignmentPattern)
144
+ : currentTableKeyPath === null
145
+ ? trimmed.match(topLevelDottedAssignmentPattern)
146
+ : null;
147
+ if (!dottedMatch) {
148
+ return null;
149
+ }
150
+ const value = dottedMatch[2].trim();
151
+ if (advanceTomlMultilineStringState(value, null) !== null || advanceTomlArrayDepth(value) > 0) {
152
+ return null;
153
+ }
154
+ return normalizeProjectPath(decodeTomlQuotedString(dottedMatch[1]));
155
+ }
156
+ function isBackslashEscaped(line, index) {
157
+ let backslashCount = 0;
158
+ for (let cursor = index - 1; cursor >= 0 && line[cursor] === '\\'; cursor -= 1) {
159
+ backslashCount += 1;
160
+ }
161
+ return backslashCount % 2 === 1;
162
+ }
163
+ function advanceTomlArrayDepth(line, initialDepth = 0, multilineStringState = null) {
164
+ let arrayDepth = initialDepth;
165
+ let stringState = multilineStringState;
166
+ for (let index = 0; index < line.length; index += 1) {
167
+ if (stringState === 'basic') {
168
+ if (line.startsWith('"""', index) && !isBackslashEscaped(line, index)) {
169
+ stringState = null;
170
+ index += 2;
171
+ }
172
+ continue;
173
+ }
174
+ if (stringState === 'literal') {
175
+ if (line.startsWith("'''", index)) {
176
+ stringState = null;
177
+ index += 2;
178
+ }
179
+ continue;
180
+ }
181
+ const character = line[index];
182
+ if (character === '#')
183
+ break;
184
+ if (line.startsWith('"""', index) && !isBackslashEscaped(line, index)) {
185
+ stringState = 'basic';
186
+ index += 2;
187
+ continue;
188
+ }
189
+ if (line.startsWith("'''", index)) {
190
+ stringState = 'literal';
191
+ index += 2;
192
+ continue;
193
+ }
194
+ if (character === '"' && !isBackslashEscaped(line, index)) {
195
+ for (index += 1; index < line.length && (line[index] !== '"' || isBackslashEscaped(line, index)); index += line[index] === '\\' ? 2 : 1)
196
+ ;
197
+ continue;
198
+ }
199
+ if (character === '\'') {
200
+ for (index += 1; index < line.length && line[index] !== '\''; index += 1)
201
+ ;
202
+ continue;
203
+ }
204
+ if (character === '[')
205
+ arrayDepth += 1;
206
+ if (character === ']')
207
+ arrayDepth = Math.max(0, arrayDepth - 1);
208
+ }
209
+ return arrayDepth;
210
+ }
211
+ function advanceTomlMultilineStringState(line, state) {
212
+ let nextState = state;
213
+ let index = 0;
214
+ while (index < line.length) {
215
+ if (nextState === 'basic') {
216
+ if (line.startsWith('"""', index) && !isBackslashEscaped(line, index)) {
217
+ nextState = null;
218
+ index += 3;
219
+ continue;
220
+ }
221
+ index += line[index] === '\\' ? 2 : 1;
222
+ continue;
223
+ }
224
+ if (nextState === 'literal') {
225
+ if (line.startsWith("'''", index)) {
226
+ nextState = null;
227
+ index += 3;
228
+ continue;
229
+ }
230
+ index += 1;
231
+ continue;
232
+ }
233
+ if (line[index] === '#') {
234
+ break;
235
+ }
236
+ if (line.startsWith('"""', index) && !isBackslashEscaped(line, index)) {
237
+ nextState = 'basic';
238
+ index += 3;
239
+ continue;
240
+ }
241
+ if (line.startsWith("'''", index)) {
242
+ nextState = 'literal';
243
+ index += 3;
244
+ continue;
245
+ }
246
+ if (line[index] === '"' && !isBackslashEscaped(line, index)) {
247
+ index += 1;
248
+ while (index < line.length) {
249
+ if (line[index] === '\\') {
250
+ index += 2;
251
+ continue;
252
+ }
253
+ if (line[index] === '"') {
254
+ index += 1;
255
+ break;
256
+ }
257
+ index += 1;
258
+ }
259
+ continue;
260
+ }
261
+ if (line[index] === '\'') {
262
+ const literalEnd = line.indexOf('\'', index + 1);
263
+ index = literalEnd === -1 ? line.length : literalEnd + 1;
264
+ continue;
265
+ }
266
+ index += 1;
267
+ }
268
+ return nextState;
269
+ }
270
+ function findTrustedAncestorProject(projects, laneWorkspacePath) {
271
+ const normalizedLaneWorkspacePath = normalizeProjectPath(laneWorkspacePath);
272
+ return Object.entries(projects)
273
+ .map(([path, value]) => ({ path: normalizeProjectPath(path), value }))
274
+ .filter(({ path, value }) => path !== normalizedLaneWorkspacePath
275
+ && isTrustedProjectEntry(value)
276
+ && !pathContainsSegment(path, '.child-lanes')
277
+ && isPathAncestorOf(path, normalizedLaneWorkspacePath))
278
+ .sort((left, right) => right.path.length - left.path.length)
279
+ .map(({ path }) => path)[0] ?? null;
280
+ }
281
+ function hasTrustedProjectEntry(projects, candidatePath) {
282
+ const normalizedCandidatePath = normalizeProjectPath(candidatePath);
283
+ return Object.entries(projects).some(([path, value]) => normalizeProjectPath(path) === normalizedCandidatePath && isTrustedProjectEntry(value));
284
+ }
285
+ function removeProjectTablesFromRawConfig(rawConfig, removableProjects) {
286
+ const lines = rawConfig.split(/\r?\n/u);
287
+ const keptLines = [];
288
+ let skippingProjectTable = null;
289
+ let currentTableKeyPath = null;
290
+ let multilineStringState = null;
291
+ let multilineArrayDepth = 0;
292
+ for (const line of lines) {
293
+ const tableHeaderPath = multilineStringState || multilineArrayDepth > 0 ? null : parseTomlTableKeyPath(line);
294
+ if (skippingProjectTable) {
295
+ if (!tableHeaderPath || parseProjectNamespaceHeader(line) === skippingProjectTable) {
296
+ multilineArrayDepth = advanceTomlArrayDepth(line, multilineArrayDepth, multilineStringState);
297
+ multilineStringState = advanceTomlMultilineStringState(line, multilineStringState);
298
+ continue;
299
+ }
300
+ skippingProjectTable = null;
301
+ }
302
+ const projectHeaderPath = tableHeaderPath ? parseProjectTableHeader(line) : null;
303
+ if (projectHeaderPath && removableProjects.has(projectHeaderPath)) {
304
+ skippingProjectTable = projectHeaderPath;
305
+ multilineStringState = advanceTomlMultilineStringState(line, multilineStringState);
306
+ continue;
307
+ }
308
+ const inlineProjectPath = tableHeaderPath || multilineStringState
309
+ ? null
310
+ : parseInlineProjectEntry(line, currentTableKeyPath);
311
+ if (inlineProjectPath && removableProjects.has(inlineProjectPath)) {
312
+ multilineArrayDepth = advanceTomlArrayDepth(line, multilineArrayDepth, multilineStringState);
313
+ multilineStringState = advanceTomlMultilineStringState(line, multilineStringState);
314
+ continue;
315
+ }
316
+ keptLines.push(line);
317
+ multilineArrayDepth = advanceTomlArrayDepth(line, multilineArrayDepth, multilineStringState);
318
+ multilineStringState = advanceTomlMultilineStringState(line, multilineStringState);
319
+ if (tableHeaderPath) {
320
+ currentTableKeyPath = tableHeaderPath.trim();
321
+ }
322
+ }
323
+ const nextConfig = keptLines.join('\n');
324
+ return rawConfig.endsWith('\n') && !nextConfig.endsWith('\n') ? `${nextConfig}\n` : nextConfig;
325
+ }
326
+ function planTrustedProjectCleanup(input) {
327
+ const parsed = getTomlParser().parse(input.rawConfig);
328
+ if (!isRecord(parsed) || !isRecord(parsed.projects)) {
329
+ return {
330
+ configPath: input.configPath,
331
+ anchorProject: null,
332
+ removedProjects: [],
333
+ changed: false,
334
+ nextConfig: null
335
+ };
336
+ }
337
+ const projects = parsed.projects;
338
+ const anchorProject = findTrustedAncestorProject(projects, input.laneWorkspacePath);
339
+ if (!anchorProject) {
340
+ return {
341
+ configPath: input.configPath,
342
+ anchorProject: null,
343
+ removedProjects: [],
344
+ changed: false,
345
+ nextConfig: null
346
+ };
347
+ }
348
+ const normalizedLaneWorkspacePath = normalizeProjectPath(input.laneWorkspacePath);
349
+ const removedProjects = hasTrustedProjectEntry(projects, normalizedLaneWorkspacePath)
350
+ ? [normalizedLaneWorkspacePath]
351
+ : [];
352
+ if (removedProjects.length === 0) {
353
+ return {
354
+ configPath: input.configPath,
355
+ anchorProject,
356
+ removedProjects: [],
357
+ changed: false,
358
+ nextConfig: null
359
+ };
360
+ }
361
+ const nextConfig = removeProjectTablesFromRawConfig(input.rawConfig, new Set(removedProjects));
362
+ return {
363
+ configPath: input.configPath,
364
+ anchorProject,
365
+ removedProjects,
366
+ changed: nextConfig !== input.rawConfig,
367
+ nextConfig
368
+ };
369
+ }
370
+ async function compactRedundantTrustedChildLaneProjects(input) {
371
+ const configPath = join(resolveCodexHome(input.env), 'config.toml');
372
+ const lockPath = `${configPath}.lock`;
373
+ const lock = await acquireLockWithRetry({
374
+ taskId: configPath,
375
+ lockPath,
376
+ retry: PROVIDER_LINEAR_CHILD_LANE_TRUSTED_PROJECT_CONFIG_LOCK_RETRY,
377
+ ensureDirectory: async () => {
378
+ await mkdir(dirname(lockPath), { recursive: true });
379
+ },
380
+ createError: (_taskId, attempts) => new Error(`Failed to acquire provider-linear-child-lane trusted-project config lock after ${attempts} attempts.`)
381
+ });
382
+ try {
383
+ let rawConfig;
384
+ try {
385
+ rawConfig = await readFile(configPath, 'utf8');
386
+ }
387
+ catch (error) {
388
+ if (error.code === 'ENOENT') {
389
+ return {
390
+ configPath,
391
+ anchorProject: null,
392
+ removedProjects: [],
393
+ changed: false,
394
+ nextConfig: null
395
+ };
396
+ }
397
+ throw error;
398
+ }
399
+ const plan = planTrustedProjectCleanup({
400
+ rawConfig,
401
+ laneWorkspacePath: input.laneWorkspacePath,
402
+ configPath
403
+ });
404
+ if (plan.changed && plan.nextConfig !== null) {
405
+ await writeAtomicFile(configPath, plan.nextConfig, { ensureDir: true, encoding: 'utf8' });
406
+ }
407
+ return plan;
408
+ }
409
+ finally {
410
+ await lock.release();
411
+ }
412
+ }
413
+ async function compactRedundantTrustedChildLaneProjectsBestEffort(input) {
414
+ try {
415
+ const cleanup = await compactRedundantTrustedChildLaneProjects(input);
416
+ if (cleanup.removedProjects.length > 0) {
417
+ logger.info(`[provider-linear-child-lane-trust] removed ${cleanup.removedProjects.length} child-lane trusted project entr${cleanup.removedProjects.length === 1 ? 'y' : 'ies'} from ${cleanup.configPath} using ancestor ${cleanup.anchorProject}.`);
418
+ }
419
+ }
420
+ catch (error) {
421
+ logger.warn(`provider-linear-child-lane warning: failed to compact redundant trusted project entries in ${join(resolveCodexHome(input.env), 'config.toml')}: ${error instanceof Error ? error.message : String(error)}`);
422
+ }
423
+ }
424
+ function normalizeStringArrayFromEnv(value) {
425
+ if (!value) {
426
+ return [];
427
+ }
428
+ try {
429
+ const parsed = JSON.parse(value);
430
+ if (!Array.isArray(parsed)) {
431
+ return [];
432
+ }
433
+ return parsed
434
+ .map((entry) => normalizeOptionalString(entry))
435
+ .filter((entry) => entry !== null);
436
+ }
437
+ catch {
438
+ return [];
439
+ }
440
+ }
441
+ function ensurePathWithinRoot(root, candidate) {
442
+ const resolvedRoot = resolve(root);
443
+ const resolvedCandidate = resolve(candidate);
444
+ const relativePath = relative(resolvedRoot, resolvedCandidate);
445
+ if (relativePath.startsWith('..') || isAbsolute(relativePath)) {
446
+ throw new Error(`Path escapes parent workspace boundary: ${candidate}`);
447
+ }
448
+ return resolvedCandidate;
449
+ }
450
+ function deriveLatestTurnSessionId(input) {
451
+ if (!input.threadId || !input.turnId) {
452
+ return { sessionId: null, source: null };
453
+ }
454
+ return {
455
+ sessionId: `${input.threadId}-${input.turnId}`,
456
+ source: 'derived_from_thread_and_turn'
457
+ };
458
+ }
459
+ function buildChildLanePromptHeader(issueIdentifier) {
460
+ return `You are a bounded same-issue child lane for Linear issue ${issueIdentifier}.`;
461
+ }
462
+ function buildChildLanePrompt(context) {
463
+ const scopeLines = [
464
+ context.scope.files.length > 0
465
+ ? `- File scope: ${context.scope.files.join(', ')}`
466
+ : '- File scope: none declared',
467
+ context.scope.phases.length > 0
468
+ ? `- Phase scope: ${context.scope.phases.join(', ')}`
469
+ : '- Phase scope: none declared'
470
+ ];
471
+ return [
472
+ buildChildLanePromptHeader(context.issueIdentifier),
473
+ '',
474
+ 'Constraints:',
475
+ '- Work only inside this lane workspace. The parent lane owns the authoritative issue workspace, Linear state, workpad, and PR lifecycle.',
476
+ '- Stay strictly inside the declared scope below. Do not edit files outside the declared file or phase scope.',
477
+ '- If the change cannot be completed within that scope, stop and report back to the parent lane so it can relaunch with widened ownership.',
478
+ '- Do not call Linear mutation helpers. Parent-owned integration happens by patch artifact only.',
479
+ '- Do not run full repo validation suites. Keep checks tightly scoped to the touched area when needed.',
480
+ '- If the lane is advisory/read-only and no file changes are needed, finish with a concise evidence summary. The parent will classify a zero-byte patch as no-output advisory evidence, not as an applicable patch.',
481
+ '',
482
+ `Purpose: ${context.purpose}`,
483
+ ...scopeLines,
484
+ ...(context.runMemoryPromptLines.length > 0 ? ['', ...context.runMemoryPromptLines] : []),
485
+ '',
486
+ context.instructions ? `Additional instructions:\n${context.instructions}` : 'Additional instructions: none.',
487
+ '',
488
+ 'Finish by leaving the lane workspace changes in place for patch export. Do not commit.'
489
+ ].join('\n');
490
+ }
491
+ function buildProviderLinearChildLaneSessionPromptNeedles(context) {
492
+ return [buildChildLanePromptHeader(context.issueIdentifier)];
493
+ }
494
+ function buildProviderLinearChildLaneRecentSessionDayDirs(sessionRoot, referenceDates) {
495
+ const results = [];
496
+ const seen = new Set();
497
+ for (const referenceDate of referenceDates) {
498
+ for (const dayOffset of [0, -1]) {
499
+ const current = new Date(referenceDate.getTime());
500
+ current.setDate(current.getDate() + dayOffset);
501
+ const dir = join(sessionRoot, String(current.getFullYear()), String(current.getMonth() + 1).padStart(2, '0'), String(current.getDate()).padStart(2, '0'));
502
+ if (!seen.has(dir)) {
503
+ seen.add(dir);
504
+ results.push(dir);
505
+ }
506
+ }
507
+ }
508
+ return results;
509
+ }
510
+ function providerLinearChildLaneSessionLogPathMatchesThreadId(path, threadId) {
511
+ return basename(path, '.jsonl').endsWith(`-${threadId}`);
512
+ }
513
+ async function readProviderLinearChildLaneFilePrefix(path, maxBytes) {
514
+ const handle = await open(path, 'r');
515
+ try {
516
+ const buffer = Buffer.alloc(maxBytes);
517
+ const { bytesRead } = await handle.read(buffer, 0, maxBytes, 0);
518
+ return buffer.toString('utf8', 0, bytesRead);
519
+ }
520
+ finally {
521
+ await handle.close();
522
+ }
523
+ }
524
+ function parseProviderLinearChildLaneSessionJsonlLine(line) {
525
+ const trimmed = line.trim();
526
+ if (!trimmed.startsWith('{')) {
527
+ return null;
528
+ }
529
+ try {
530
+ const parsed = JSON.parse(trimmed);
531
+ return typeof parsed === 'object' && parsed !== null ? parsed : null;
532
+ }
533
+ catch {
534
+ return null;
535
+ }
536
+ }
537
+ function tokenizeShellCommandForScopeDrift(command) {
538
+ const normalized = stripShellCommandHeredocBodies(command);
539
+ return normalized.match(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\n|&&|\|\||[;&|]|[^\s;&|]+/gu) ?? [];
540
+ }
541
+ function stripShellCommandHeredocBodies(command) {
542
+ const normalized = command.replace(/\r\n/gu, '\n');
543
+ const lines = normalized.split('\n');
544
+ const heredocDelimiters = [];
545
+ const output = [];
546
+ for (const line of lines) {
547
+ if (heredocDelimiters.length > 0) {
548
+ const active = heredocDelimiters[0];
549
+ if (active) {
550
+ const candidate = active.stripLeadingTabs ? line.replace(/^\t+/u, '') : line;
551
+ if (lineClosesShellCommandHeredoc(candidate, active.delimiter)) {
552
+ output.push(line);
553
+ heredocDelimiters.shift();
554
+ }
555
+ else {
556
+ output.push('');
557
+ }
558
+ continue;
559
+ }
560
+ }
561
+ output.push(line);
562
+ for (const match of line.matchAll(/<<(-)?\s*(?:(['"])(.*?)\2|([^\s<>&|;]+))/gu)) {
563
+ const delimiter = match[3] ?? match[4];
564
+ if (!delimiter) {
565
+ continue;
566
+ }
567
+ heredocDelimiters.push({
568
+ delimiter,
569
+ stripLeadingTabs: match[1] === '-'
570
+ });
571
+ }
572
+ }
573
+ return output.join('\n');
574
+ }
575
+ function lineClosesShellCommandHeredoc(line, delimiter) {
576
+ if (line === delimiter) {
577
+ return true;
578
+ }
579
+ if (!line.startsWith(delimiter)) {
580
+ return false;
581
+ }
582
+ const remainder = line.slice(delimiter.length);
583
+ return /^["']+(?:\s*(?:&&|\|\||[;&|]).*)?$/u.test(remainder);
584
+ }
585
+ function stripShellCommandTokenQuotes(token) {
586
+ return token.replace(/^['"]|['"]$/gu, '');
587
+ }
588
+ function shellOptionConsumesNextValue(token, optionsWithValues) {
589
+ return optionsWithValues.has(token) && !token.includes('=');
590
+ }
591
+ function advancePastShellCommandEnvWrappers(tokens, segmentStart, segmentEnd) {
592
+ const envAssignmentPattern = /^[A-Za-z_][A-Za-z0-9_]*=.*/u;
593
+ const envOptionsWithValues = new Set([
594
+ '-u',
595
+ '--unset',
596
+ '-C',
597
+ '--chdir',
598
+ '-S',
599
+ '--split-string',
600
+ '--default-signal',
601
+ '--ignore-signal',
602
+ '--block-signal'
603
+ ]);
604
+ let index = segmentStart;
605
+ while (index < segmentEnd) {
606
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
607
+ if (!token) {
608
+ index += 1;
609
+ continue;
610
+ }
611
+ if (envAssignmentPattern.test(token)) {
612
+ index += 1;
613
+ continue;
614
+ }
615
+ if (basename(token) === 'env') {
616
+ index += 1;
617
+ while (index < segmentEnd) {
618
+ const envToken = stripShellCommandTokenQuotes(tokens[index] ?? '');
619
+ if (!envToken) {
620
+ index += 1;
621
+ continue;
622
+ }
623
+ if (envToken === '--') {
624
+ index += 1;
625
+ break;
626
+ }
627
+ if (envAssignmentPattern.test(envToken)) {
628
+ index += 1;
629
+ continue;
630
+ }
631
+ if (envToken.startsWith('-')) {
632
+ if (shellOptionConsumesNextValue(envToken, envOptionsWithValues)) {
633
+ index += 1;
634
+ }
635
+ index += 1;
636
+ continue;
637
+ }
638
+ break;
639
+ }
640
+ continue;
641
+ }
642
+ break;
643
+ }
644
+ return index;
645
+ }
646
+ function advancePastShellCommandExecutionWrappers(tokens, segmentStart, segmentEnd) {
647
+ let index = advancePastShellCommandEnvWrappers(tokens, segmentStart, segmentEnd);
648
+ while (index < segmentEnd) {
649
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
650
+ if (!token) {
651
+ index += 1;
652
+ continue;
653
+ }
654
+ if (basename(token) !== 'command') {
655
+ break;
656
+ }
657
+ index += 1;
658
+ while (index < segmentEnd) {
659
+ const commandToken = stripShellCommandTokenQuotes(tokens[index] ?? '');
660
+ if (!commandToken) {
661
+ index += 1;
662
+ continue;
663
+ }
664
+ if (commandToken === '--') {
665
+ index += 1;
666
+ break;
667
+ }
668
+ if (commandToken === '-p') {
669
+ index += 1;
670
+ continue;
671
+ }
672
+ if (commandToken.startsWith('-')) {
673
+ return segmentEnd;
674
+ }
675
+ break;
676
+ }
677
+ }
678
+ return index;
679
+ }
680
+ function findShellCommandSegmentEnd(tokens, segmentStart, commandSeparators) {
681
+ let index = segmentStart;
682
+ while (index < tokens.length) {
683
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
684
+ if (token && commandSeparators.has(token)) {
685
+ break;
686
+ }
687
+ index += 1;
688
+ }
689
+ return index;
690
+ }
691
+ function segmentShowsParentOwnedOrchestratorScopeDrift(tokens, start, end) {
692
+ for (let index = start; index < end; index += 1) {
693
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
694
+ if (!token) {
695
+ continue;
696
+ }
697
+ if (token === 'linear' || token === 'pr' || token === 'review' || token.startsWith('provider-linear-')) {
698
+ return true;
699
+ }
700
+ }
701
+ return false;
702
+ }
703
+ function tokenInvokesCodexOrchestrator(token) {
704
+ return /^(?:codex-orchestrator(?:\.js)?|codex-orchestrator@.+)$/u.test(basename(token));
705
+ }
706
+ function packageExecSegmentShowsParentOwnedScopeDrift(tokens, commandStart, segmentEnd) {
707
+ const packageExecOptionsWithValues = new Set(['-c', '--call', '-p', '--package', '--shell', '--node-options']);
708
+ for (let index = commandStart; index < segmentEnd; index += 1) {
709
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
710
+ if (!token) {
711
+ continue;
712
+ }
713
+ if (token === '--') {
714
+ continue;
715
+ }
716
+ if (token === '-c' || token === '--call') {
717
+ const nestedCommand = stripShellCommandTokenQuotes(tokens[index + 1] ?? '');
718
+ return nestedCommand ? commandShowsParentOwnedScopeDrift(nestedCommand) : false;
719
+ }
720
+ if (token.startsWith('-')) {
721
+ if (shellOptionConsumesNextValue(token, packageExecOptionsWithValues)) {
722
+ index += 1;
723
+ }
724
+ continue;
725
+ }
726
+ if (!tokenInvokesCodexOrchestrator(token)) {
727
+ return false;
728
+ }
729
+ return segmentShowsParentOwnedOrchestratorScopeDrift(tokens, index + 1, segmentEnd);
730
+ }
731
+ return false;
732
+ }
733
+ function npmExecSegmentShowsParentOwnedScopeDrift(tokens, commandStart, segmentEnd) {
734
+ const npmOptionsWithValues = new Set(['-C', '--prefix', '-w', '--workspace', '--userconfig', '--cache', '--loglevel']);
735
+ for (let index = commandStart; index < segmentEnd; index += 1) {
736
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
737
+ if (!token) {
738
+ continue;
739
+ }
740
+ if (token === '--') {
741
+ continue;
742
+ }
743
+ if (token === 'exec' || token === 'x') {
744
+ return packageExecSegmentShowsParentOwnedScopeDrift(tokens, index + 1, segmentEnd);
745
+ }
746
+ if (token.startsWith('-')) {
747
+ if (shellOptionConsumesNextValue(token, npmOptionsWithValues)) {
748
+ index += 1;
749
+ }
750
+ continue;
751
+ }
752
+ return false;
753
+ }
754
+ return false;
755
+ }
756
+ function commandSegmentShowsParentOwnedScopeDrift(tokens, segmentStart, segmentEnd) {
757
+ const shellCommandWrappers = new Set(['bash', 'sh', 'zsh']);
758
+ const gitOptionsWithValues = new Set([
759
+ '-c',
760
+ '-C',
761
+ '--exec-path',
762
+ '--git-dir',
763
+ '--work-tree',
764
+ '--namespace',
765
+ '--super-prefix',
766
+ '--config-env'
767
+ ]);
768
+ const commandIndex = advancePastShellCommandExecutionWrappers(tokens, segmentStart, segmentEnd);
769
+ if (commandIndex >= segmentEnd) {
770
+ return false;
771
+ }
772
+ const commandToken = stripShellCommandTokenQuotes(tokens[commandIndex] ?? '');
773
+ const commandBase = basename(commandToken);
774
+ if (commandBase === 'eval') {
775
+ const nestedCommandTokens = [];
776
+ for (let index = commandIndex + 1; index < segmentEnd; index += 1) {
777
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
778
+ if (!token) {
779
+ continue;
780
+ }
781
+ if (nestedCommandTokens.length === 0 && token === '--') {
782
+ continue;
783
+ }
784
+ nestedCommandTokens.push(token);
785
+ }
786
+ return nestedCommandTokens.length > 0 ? commandShowsParentOwnedScopeDrift(nestedCommandTokens.join(' ')) : false;
787
+ }
788
+ if (shellCommandWrappers.has(commandBase)) {
789
+ const shellOptionsWithValues = new Set(['-o', '-O', '--rcfile', '--init-file']);
790
+ for (let index = commandIndex + 1; index < segmentEnd; index += 1) {
791
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
792
+ if (!token) {
793
+ continue;
794
+ }
795
+ if (/^-[^-]*c[^-]*$/u.test(token) || token === '-c') {
796
+ const nestedCommand = stripShellCommandTokenQuotes(tokens[index + 1] ?? '');
797
+ return nestedCommand ? commandShowsParentOwnedScopeDrift(nestedCommand) : false;
798
+ }
799
+ if (shellOptionConsumesNextValue(token, shellOptionsWithValues)) {
800
+ index += 1;
801
+ continue;
802
+ }
803
+ if (!token.startsWith('-')) {
804
+ return false;
805
+ }
806
+ }
807
+ return false;
808
+ }
809
+ if (commandBase === 'gh') {
810
+ return true;
811
+ }
812
+ if (commandBase === 'npx') {
813
+ return packageExecSegmentShowsParentOwnedScopeDrift(tokens, commandIndex + 1, segmentEnd);
814
+ }
815
+ if (commandBase === 'npm') {
816
+ return npmExecSegmentShowsParentOwnedScopeDrift(tokens, commandIndex + 1, segmentEnd);
817
+ }
818
+ if (tokenInvokesCodexOrchestrator(commandToken)) {
819
+ return segmentShowsParentOwnedOrchestratorScopeDrift(tokens, commandIndex + 1, segmentEnd);
820
+ }
821
+ if (commandBase === 'node' || commandBase === 'bun') {
822
+ const runtimeOptionsWithValues = new Set([
823
+ '-r',
824
+ '--require',
825
+ '--import',
826
+ '--loader',
827
+ '--experimental-loader',
828
+ '--conditions'
829
+ ]);
830
+ for (let index = commandIndex + 1; index < segmentEnd; index += 1) {
831
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
832
+ if (!token) {
833
+ continue;
834
+ }
835
+ if (token.startsWith('-')) {
836
+ if (shellOptionConsumesNextValue(token, runtimeOptionsWithValues)) {
837
+ index += 1;
838
+ }
839
+ continue;
840
+ }
841
+ if (!tokenInvokesCodexOrchestrator(token)) {
842
+ return false;
843
+ }
844
+ return segmentShowsParentOwnedOrchestratorScopeDrift(tokens, index + 1, segmentEnd);
845
+ }
846
+ return false;
847
+ }
848
+ if (commandBase !== 'git') {
849
+ return false;
850
+ }
851
+ for (let index = commandIndex + 1; index < segmentEnd; index += 1) {
852
+ const token = stripShellCommandTokenQuotes(tokens[index] ?? '');
853
+ if (!token) {
854
+ continue;
855
+ }
856
+ if (token === 'commit' || token === 'push') {
857
+ return true;
858
+ }
859
+ if (!token.startsWith('-')) {
860
+ return false;
861
+ }
862
+ if (shellOptionConsumesNextValue(token, gitOptionsWithValues)) {
863
+ index += 1;
864
+ }
865
+ }
866
+ return false;
867
+ }
868
+ function commandShowsParentOwnedScopeDrift(command) {
869
+ const tokens = tokenizeShellCommandForScopeDrift(command);
870
+ const commandSeparators = new Set(['\n', '&&', '||', ';', '|', '&']);
871
+ let segmentStart = 0;
872
+ while (segmentStart < tokens.length) {
873
+ const segmentEnd = findShellCommandSegmentEnd(tokens, segmentStart, commandSeparators);
874
+ if (commandSegmentShowsParentOwnedScopeDrift(tokens, segmentStart, segmentEnd)) {
875
+ return true;
876
+ }
877
+ segmentStart = segmentEnd + 1;
878
+ }
879
+ return false;
880
+ }
881
+ function queryShowsParentOwnedScopeDrift(query) {
882
+ if (/\bpull requests?\b/iu.test(query) &&
883
+ /\b(?:open|opened|close|closed|merge|merged|comment|comments|review|reviews|check|checks|status|list|view|repo|repository)\b/iu.test(query)) {
884
+ return true;
885
+ }
886
+ if (/\bgithub\b/iu.test(query) &&
887
+ /\b(?:prs?\b|issue|issues|comment|comments|review|reviews|check|checks|status|merge|merged|open|opened|close|closed)\b/iu.test(query)) {
888
+ return true;
889
+ }
890
+ if (/\bprs?\b/iu.test(query) &&
891
+ (/\bpr\s*#?\d+\b/iu.test(query) ||
892
+ /\b(?:comment|comments|review|reviews|check|checks|status|merge|merged|open|opened|close|closed)\b/iu.test(query))) {
893
+ return true;
894
+ }
895
+ return (/\blinear\b/iu.test(query) &&
896
+ /\b(?:issue|issues|ticket|tickets|project|projects|comment|comments|status|state|workflow)\b/iu.test(query));
897
+ }
898
+ function functionNameShowsParentOwnedScopeDrift(functionName) {
899
+ const tokens = functionName
900
+ .toLowerCase()
901
+ .split(/[^a-z0-9]+/u)
902
+ .filter((token) => token.length > 0);
903
+ if (tokens.includes('github') || tokens.includes('linear')) {
904
+ return true;
905
+ }
906
+ if (tokens.includes('pull') && tokens.includes('request')) {
907
+ return true;
908
+ }
909
+ return (tokens.includes('pr') &&
910
+ tokens.some((token) => ['open', 'make', 'create', 'update', 'close', 'merge', 'view', 'list', 'comment', 'review'].includes(token)));
911
+ }
912
+ function formatProviderLinearChildLaneScopeDriftEvidence(timestamp, detail) {
913
+ return timestamp ? `${timestamp} ${detail}` : detail;
914
+ }
915
+ function truncateProviderLinearChildLaneScopeDriftText(value, maxLength = 140) {
916
+ const normalized = value.replace(/\s+/gu, ' ').trim();
917
+ if (normalized.length <= maxLength) {
918
+ return normalized;
919
+ }
920
+ return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}...`;
921
+ }
922
+ function extractProviderLinearChildLaneScopeDriftEvidenceFromRecord(record) {
923
+ const timestamp = normalizeOptionalString(record.timestamp);
924
+ if (normalizeOptionalString(record.type) !== 'response_item') {
925
+ return [];
926
+ }
927
+ const payload = typeof record.payload === 'object' && record.payload !== null
928
+ ? record.payload
929
+ : null;
930
+ if (!payload) {
931
+ return [];
932
+ }
933
+ const payloadType = normalizeOptionalString(payload.type);
934
+ if (payloadType === 'tool_search_call') {
935
+ const argumentsValue = typeof payload.arguments === 'object' && payload.arguments !== null
936
+ ? payload.arguments
937
+ : null;
938
+ const query = normalizeOptionalString(argumentsValue?.query);
939
+ if (query && queryShowsParentOwnedScopeDrift(query)) {
940
+ return [
941
+ formatProviderLinearChildLaneScopeDriftEvidence(timestamp, `tool_search ${truncateProviderLinearChildLaneScopeDriftText(query)}`)
942
+ ];
943
+ }
944
+ return [];
945
+ }
946
+ if (payloadType !== 'function_call') {
947
+ return [];
948
+ }
949
+ const functionName = normalizeOptionalString(payload.name);
950
+ if (!functionName) {
951
+ return [];
952
+ }
953
+ if (functionNameShowsParentOwnedScopeDrift(functionName)) {
954
+ return [
955
+ formatProviderLinearChildLaneScopeDriftEvidence(timestamp, `function_call ${functionName}`)
956
+ ];
957
+ }
958
+ if (functionName !== 'exec_command') {
959
+ return [];
960
+ }
961
+ const rawArguments = normalizeOptionalString(payload.arguments);
962
+ if (!rawArguments) {
963
+ return [];
964
+ }
965
+ try {
966
+ const parsed = JSON.parse(rawArguments);
967
+ const command = normalizeOptionalString(parsed.cmd);
968
+ if (!command || !commandShowsParentOwnedScopeDrift(command)) {
969
+ return [];
970
+ }
971
+ return [
972
+ formatProviderLinearChildLaneScopeDriftEvidence(timestamp, `exec_command ${truncateProviderLinearChildLaneScopeDriftText(command)}`)
973
+ ];
974
+ }
975
+ catch {
976
+ return [];
977
+ }
978
+ }
979
+ async function scanProviderLinearChildLaneSessionLogForParentScopeDrift(sessionLogPath, startedAt = null) {
980
+ const raw = await readFile(sessionLogPath, 'utf8');
981
+ const evidence = new Set();
982
+ const startedAtMs = startedAt ? Date.parse(startedAt) : Number.NaN;
983
+ let withinLaunchWindow = !Number.isFinite(startedAtMs);
984
+ for (const line of raw.split(/\r?\n/u)) {
985
+ const parsed = parseProviderLinearChildLaneSessionJsonlLine(line);
986
+ if (!parsed) {
987
+ continue;
988
+ }
989
+ if (!withinLaunchWindow) {
990
+ const timestampMs = typeof parsed.timestamp === 'string' ? Date.parse(parsed.timestamp) : Number.NaN;
991
+ if (!Number.isFinite(timestampMs) || timestampMs < startedAtMs) {
992
+ continue;
993
+ }
994
+ withinLaunchWindow = true;
995
+ }
996
+ for (const detail of extractProviderLinearChildLaneScopeDriftEvidenceFromRecord(parsed)) {
997
+ evidence.add(detail);
998
+ if (evidence.size >= 3) {
999
+ return [...evidence];
1000
+ }
1001
+ }
1002
+ }
1003
+ return [...evidence];
1004
+ }
1005
+ function buildProviderLinearChildLaneScopeDriftMessage(input) {
1006
+ const renderedEvidence = input.evidence.map((entry) => `"${entry}"`).join('; ');
1007
+ return `Appserver child lane drifted into parent-owned GitHub/Linear/PR lifecycle work for ${input.context.issueIdentifier}. Session log ${basename(input.sessionLogPath)} captured ${renderedEvidence}. Invalidate the lane and relaunch with tighter bounded scope; parent-owned Linear/GitHub/PR handling must stay in the provider worker.`;
1008
+ }
1009
+ async function waitForProviderLinearChildLaneScopeDrift(input) {
1010
+ const readScopeDriftMessage = async () => {
1011
+ const evidence = await scanProviderLinearChildLaneSessionLogForParentScopeDrift(input.sessionLogPath, input.startedAt ?? null).catch((error) => [
1012
+ formatProviderLinearChildLaneScopeDriftEvidence(null, `drift_monitor_unreadable ${basename(input.sessionLogPath)}: ${error instanceof Error ? error.message : String(error)}`)
1013
+ ]);
1014
+ if (evidence.length === 0) {
1015
+ return null;
1016
+ }
1017
+ return buildProviderLinearChildLaneScopeDriftMessage({
1018
+ context: input.context,
1019
+ sessionLogPath: input.sessionLogPath,
1020
+ evidence
1021
+ });
1022
+ };
1023
+ while (!input.isExecSettled()) {
1024
+ const driftMessage = await readScopeDriftMessage();
1025
+ if (driftMessage) {
1026
+ return driftMessage;
1027
+ }
1028
+ await input.deps.sleep(PROVIDER_LINEAR_CHILD_LANE_SCOPE_DRIFT_POLL_INTERVAL_MS);
1029
+ }
1030
+ return await readScopeDriftMessage();
1031
+ }
1032
+ function valueContainsProviderLinearChildLaneSessionNeedle(value, needle) {
1033
+ if (typeof value === 'string') {
1034
+ return value.includes(needle);
1035
+ }
1036
+ if (Array.isArray(value)) {
1037
+ return value.some((item) => valueContainsProviderLinearChildLaneSessionNeedle(item, needle));
1038
+ }
1039
+ if (typeof value !== 'object' || value === null) {
1040
+ return false;
1041
+ }
1042
+ return Object.values(value).some((item) => valueContainsProviderLinearChildLaneSessionNeedle(item, needle));
1043
+ }
1044
+ function valueEqualsProviderLinearChildLaneSessionNeedle(value, needle) {
1045
+ if (typeof value === 'string') {
1046
+ return value === needle;
1047
+ }
1048
+ if (Array.isArray(value)) {
1049
+ return value.some((item) => valueEqualsProviderLinearChildLaneSessionNeedle(item, needle));
1050
+ }
1051
+ if (typeof value !== 'object' || value === null) {
1052
+ return false;
1053
+ }
1054
+ return Object.values(value).some((item) => valueEqualsProviderLinearChildLaneSessionNeedle(item, needle));
1055
+ }
1056
+ function prefixContainsProviderLinearChildLaneSessionHeader(prefix, workspacePath, promptNeedles) {
1057
+ let hasExactWorkspacePath = false;
1058
+ let hasPromptNeedle = promptNeedles.some((needle) => prefix.includes(needle));
1059
+ for (const line of prefix.split(/\r?\n/u)) {
1060
+ const parsed = parseProviderLinearChildLaneSessionJsonlLine(line);
1061
+ const payload = parsed?.type === 'session_meta' && parsed.payload && typeof parsed.payload === 'object'
1062
+ ? parsed.payload
1063
+ : parsed?.payload && typeof parsed.payload === 'object'
1064
+ ? parsed.payload
1065
+ : null;
1066
+ if (!payload) {
1067
+ continue;
1068
+ }
1069
+ hasExactWorkspacePath =
1070
+ hasExactWorkspacePath || valueEqualsProviderLinearChildLaneSessionNeedle(payload, workspacePath);
1071
+ if (!hasPromptNeedle) {
1072
+ hasPromptNeedle = promptNeedles.some((needle) => valueContainsProviderLinearChildLaneSessionNeedle(payload, needle));
1073
+ }
1074
+ if (hasExactWorkspacePath && hasPromptNeedle) {
1075
+ return true;
1076
+ }
1077
+ }
1078
+ return false;
1079
+ }
1080
+ function prefixHasProviderLinearChildLaneSessionTimestampAtOrAfter(prefix, startedAtMs) {
1081
+ if (!Number.isFinite(startedAtMs)) {
1082
+ return false;
1083
+ }
1084
+ for (const line of prefix.split(/\r?\n/u)) {
1085
+ const parsed = parseProviderLinearChildLaneSessionJsonlLine(line);
1086
+ if (parsed?.type !== 'session_meta' && parsed?.type !== 'turn_context') {
1087
+ continue;
1088
+ }
1089
+ const timestamp = typeof parsed?.timestamp === 'string' ? Date.parse(parsed.timestamp) : Number.NaN;
1090
+ if (Number.isFinite(timestamp) && timestamp >= startedAtMs) {
1091
+ return true;
1092
+ }
1093
+ }
1094
+ return false;
1095
+ }
1096
+ async function discoverProviderLinearChildLaneSessionLogPath(input) {
1097
+ const sessionRoot = join(resolveCodexHome(input.env), 'sessions');
1098
+ const startedAtMs = Date.parse(input.startedAt);
1099
+ const referenceDate = Number.isFinite(startedAtMs) ? new Date(startedAtMs) : new Date();
1100
+ const currentDate = new Date();
1101
+ const cutoffMs = Number.isFinite(startedAtMs)
1102
+ ? startedAtMs - PROVIDER_LINEAR_CHILD_LANE_SESSION_LOG_DISCOVERY_WINDOW_MS
1103
+ : Date.now() - PROVIDER_LINEAR_CHILD_LANE_SESSION_LOG_DISCOVERY_WINDOW_MS;
1104
+ const threadIdHint = normalizeOptionalString(input.env.CODEX_THREAD_ID);
1105
+ const sessionMetaNeedle = threadIdHint ? `"id":"${threadIdHint}"` : null;
1106
+ const candidates = [];
1107
+ for (const dayDir of buildProviderLinearChildLaneRecentSessionDayDirs(sessionRoot, [
1108
+ currentDate,
1109
+ referenceDate
1110
+ ])) {
1111
+ let entries;
1112
+ try {
1113
+ entries = await readdir(dayDir);
1114
+ }
1115
+ catch {
1116
+ continue;
1117
+ }
1118
+ for (const entry of entries) {
1119
+ if (!entry.startsWith('rollout-') || !entry.endsWith('.jsonl')) {
1120
+ continue;
1121
+ }
1122
+ const candidatePath = join(dayDir, entry);
1123
+ let fileStat;
1124
+ try {
1125
+ fileStat = await stat(candidatePath);
1126
+ }
1127
+ catch {
1128
+ continue;
1129
+ }
1130
+ if (!fileStat.isFile() || fileStat.mtimeMs < cutoffMs) {
1131
+ continue;
1132
+ }
1133
+ candidates.push({ path: candidatePath, mtimeMs: fileStat.mtimeMs });
1134
+ }
1135
+ }
1136
+ candidates.sort((left, right) => right.mtimeMs - left.mtimeMs);
1137
+ for (const requireThreadHint of threadIdHint ? [true, false] : [false]) {
1138
+ for (const candidate of candidates) {
1139
+ let prefix;
1140
+ try {
1141
+ prefix = await readProviderLinearChildLaneFilePrefix(candidate.path, PROVIDER_LINEAR_CHILD_LANE_SESSION_LOG_HEADER_BYTES);
1142
+ }
1143
+ catch {
1144
+ continue;
1145
+ }
1146
+ const matchesThreadHint = !threadIdHint ||
1147
+ providerLinearChildLaneSessionLogPathMatchesThreadId(candidate.path, threadIdHint) ||
1148
+ (sessionMetaNeedle !== null && prefix.includes(sessionMetaNeedle));
1149
+ if (requireThreadHint && !matchesThreadHint) {
1150
+ continue;
1151
+ }
1152
+ if (!requireThreadHint && Number.isFinite(startedAtMs) && candidate.mtimeMs < startedAtMs) {
1153
+ const mtimeWithinSkewWindow = candidate.mtimeMs + PROVIDER_LINEAR_CHILD_LANE_SESSION_LOG_MTIME_SKEW_MS >= startedAtMs;
1154
+ if (!mtimeWithinSkewWindow ||
1155
+ !prefixHasProviderLinearChildLaneSessionTimestampAtOrAfter(prefix, startedAtMs)) {
1156
+ continue;
1157
+ }
1158
+ }
1159
+ if (prefixContainsProviderLinearChildLaneSessionHeader(prefix, input.workspacePath, input.promptNeedles)) {
1160
+ return candidate.path;
1161
+ }
1162
+ }
1163
+ }
1164
+ return null;
1165
+ }
1166
+ function buildProviderLinearChildLaneAppserverStartupTimeoutMessage(context, timeoutMs) {
1167
+ const timeoutSeconds = Math.max(1, Math.floor(timeoutMs / 1000));
1168
+ return `Appserver child lane startup stalled after runtime selection for ${timeoutSeconds}s without matching session-log startup evidence. Invalidate the lane and relaunch under CLI, or inspect appserver session startup for ${context.issueIdentifier}.`;
1169
+ }
1170
+ async function waitForProviderLinearChildLaneAppserverStartup(input) {
1171
+ const promptNeedles = buildProviderLinearChildLaneSessionPromptNeedles(input.context);
1172
+ const currentClockMs = () => {
1173
+ const parsed = Date.parse(input.deps.now());
1174
+ return Number.isFinite(parsed) ? parsed : Date.now();
1175
+ };
1176
+ const startClockMs = currentClockMs();
1177
+ const startupDeadlineMs = startClockMs + PROVIDER_LINEAR_CHILD_LANE_APPSERVER_STARTUP_TIMEOUT_MS;
1178
+ for (;;) {
1179
+ if (input.isExecSettled()) {
1180
+ return null;
1181
+ }
1182
+ const remainingBeforeDiscoveryMs = startupDeadlineMs - currentClockMs();
1183
+ if (remainingBeforeDiscoveryMs < 0) {
1184
+ break;
1185
+ }
1186
+ const sessionLogPath = await input.deps.discoverStartupSessionLogPath({
1187
+ env: input.env,
1188
+ workspacePath: input.laneWorkspacePath,
1189
+ promptNeedles,
1190
+ startedAt: input.startedAt
1191
+ });
1192
+ if (sessionLogPath) {
1193
+ return sessionLogPath;
1194
+ }
1195
+ const remainingAfterDiscoveryMs = startupDeadlineMs - currentClockMs();
1196
+ if (remainingAfterDiscoveryMs <= 0) {
1197
+ break;
1198
+ }
1199
+ const nextSleepMs = Math.min(PROVIDER_LINEAR_CHILD_LANE_APPSERVER_STARTUP_POLL_INTERVAL_MS, remainingAfterDiscoveryMs);
1200
+ await input.deps.sleep(nextSleepMs);
1201
+ }
1202
+ throw new Error(buildProviderLinearChildLaneAppserverStartupTimeoutMessage(input.context, PROVIDER_LINEAR_CHILD_LANE_APPSERVER_STARTUP_TIMEOUT_MS));
1203
+ }
1204
+ async function recoverProviderLinearChildLaneExecResultAfterAbort(input) {
1205
+ if (!input.execSettled) {
1206
+ input.abortController.abort(input.error);
1207
+ }
1208
+ if (!input.execPromise) {
1209
+ return null;
1210
+ }
1211
+ try {
1212
+ return await input.execPromise;
1213
+ }
1214
+ catch {
1215
+ return null;
1216
+ }
1217
+ }
1218
+ async function resolveChildLaneRuntimeContext(env, repoRoot, runId) {
1219
+ const requestedMode = parseRuntimeMode(env.CODEX_ORCHESTRATOR_RUNTIME_MODE_ACTIVE ?? env.CODEX_ORCHESTRATOR_RUNTIME_MODE ?? null);
1220
+ return await createRuntimeCodexCommandContext({
1221
+ requestedMode,
1222
+ executionMode: 'mcp',
1223
+ repoRoot,
1224
+ env: { ...process.env, ...env },
1225
+ runId
1226
+ });
1227
+ }
1228
+ async function loadProviderLinearChildLaneContext(env = process.env) {
1229
+ const manifestPath = normalizeOptionalString(env.CODEX_ORCHESTRATOR_MANIFEST_PATH);
1230
+ if (!manifestPath) {
1231
+ throw new Error('CODEX_ORCHESTRATOR_MANIFEST_PATH is required for provider-linear-child-lane.');
1232
+ }
1233
+ const rawManifest = JSON.parse(await readFile(resolve(manifestPath), 'utf8'));
1234
+ const runDir = dirname(resolve(manifestPath));
1235
+ const repoRoot = normalizeOptionalString(env.CODEX_ORCHESTRATOR_ROOT) ?? process.cwd();
1236
+ const runId = normalizeOptionalString(rawManifest.run_id) ?? normalizeOptionalString(env.CODEX_ORCHESTRATOR_RUN_ID);
1237
+ const taskId = normalizeOptionalString(rawManifest.task_id) ?? normalizeOptionalString(env.CODEX_ORCHESTRATOR_TASK_ID);
1238
+ const parentRunId = normalizeOptionalString(rawManifest.parent_run_id);
1239
+ const issueId = normalizeOptionalString(rawManifest.issue_id);
1240
+ const issueIdentifier = normalizeOptionalString(rawManifest.issue_identifier);
1241
+ const stream = normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_STREAM_ENV]);
1242
+ const purpose = normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_PURPOSE_ENV]);
1243
+ const parentWorkspacePath = normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_PARENT_WORKSPACE_PATH_ENV]);
1244
+ const rawScope = {
1245
+ files: normalizeStringArrayFromEnv(env[PROVIDER_LINEAR_CHILD_LANE_FILES_ENV]),
1246
+ phases: normalizeStringArrayFromEnv(env[PROVIDER_LINEAR_CHILD_LANE_PHASES_ENV])
1247
+ };
1248
+ let scope;
1249
+ try {
1250
+ scope = resolveProviderLinearChildLaneScopeContract(rawScope);
1251
+ }
1252
+ catch (error) {
1253
+ throw new Error(`provider-linear-child-lane scope is invalid: ${error instanceof Error ? error.message : String(error)}`);
1254
+ }
1255
+ if (!runId ||
1256
+ !taskId ||
1257
+ !parentRunId ||
1258
+ !issueId ||
1259
+ !issueIdentifier ||
1260
+ !stream ||
1261
+ !purpose ||
1262
+ !parentWorkspacePath ||
1263
+ (rawScope.files.length === 0 && rawScope.phases.length === 0)) {
1264
+ throw new Error('provider-linear-child-lane context is missing required manifest or env fields.');
1265
+ }
1266
+ const capturedAt = new Date().toISOString();
1267
+ return {
1268
+ manifestPath: resolve(manifestPath),
1269
+ runDir,
1270
+ repoRoot: resolve(repoRoot),
1271
+ runId,
1272
+ taskId,
1273
+ parentRunId,
1274
+ issueId,
1275
+ issueIdentifier,
1276
+ stream,
1277
+ purpose,
1278
+ instructions: normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_INSTRUCTIONS_ENV]),
1279
+ scope,
1280
+ runMemoryPromptLines: buildRunMemoryPromptLines(selectRunMemoryForRole({
1281
+ role: 'delegate',
1282
+ manifest: rawManifest,
1283
+ hints: [purpose, ...scope.files, ...scope.phases]
1284
+ })),
1285
+ parentWorkspacePath: resolve(parentWorkspacePath),
1286
+ parentSnapshot: {
1287
+ base_sha: normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_BASE_SHA_ENV]),
1288
+ issue_updated_at: normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_UPDATED_AT_ENV]),
1289
+ issue_state: normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_ENV]),
1290
+ issue_state_type: normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_ISSUE_STATE_TYPE_ENV]),
1291
+ captured_at: normalizeOptionalString(env[PROVIDER_LINEAR_CHILD_LANE_PARENT_SNAPSHOT_CAPTURED_AT_ENV]) ?? capturedAt
1292
+ }
1293
+ };
1294
+ }
1295
+ function sanitizeChildLaneStreamSegment(stream) {
1296
+ const collapsed = stream.trim().replaceAll('\\', '/').split('/').map((segment) => segment.trim()).filter(Boolean).join('-');
1297
+ const sanitized = collapsed
1298
+ .replace(/[^A-Za-z0-9._-]+/gu, '-')
1299
+ .replace(/\.{2,}/gu, '-')
1300
+ .replace(/^-+/u, '')
1301
+ .replace(/-+$/u, '')
1302
+ .replace(/^\.+/u, '')
1303
+ .replace(/\.+$/u, '');
1304
+ return sanitized.length > 0 ? sanitized : 'lane';
1305
+ }
1306
+ async function prepareLaneWorkspace(context) {
1307
+ const safeStream = sanitizeChildLaneStreamSegment(context.stream);
1308
+ const laneWorkspacePath = ensurePathWithinRoot(context.parentWorkspacePath, join(context.parentWorkspacePath, '.child-lanes', `${safeStream}-${context.runId}`));
1309
+ const laneBranch = `child-lane/${safeStream}-${context.runId}`.slice(0, 120);
1310
+ await rm(laneWorkspacePath, { recursive: true, force: true });
1311
+ await mkdir(dirname(laneWorkspacePath), { recursive: true });
1312
+ await execFileAsync('git', ['clone', '--local', context.parentWorkspacePath, laneWorkspacePath]);
1313
+ const baseSha = context.parentSnapshot.base_sha ?? 'HEAD';
1314
+ await execFileAsync('git', ['-C', laneWorkspacePath, 'checkout', '--detach', baseSha]);
1315
+ await execFileAsync('git', ['-C', laneWorkspacePath, 'switch', '-c', laneBranch]);
1316
+ const remotes = (await execFileAsync('git', ['-C', laneWorkspacePath, 'remote'], {
1317
+ maxBuffer: 1024 * 1024
1318
+ })).stdout
1319
+ .split(/\r?\n/u)
1320
+ .map((entry) => normalizeOptionalString(entry))
1321
+ .filter((entry) => entry !== null);
1322
+ for (const remote of remotes) {
1323
+ await execFileAsync('git', [
1324
+ '-C',
1325
+ laneWorkspacePath,
1326
+ 'remote',
1327
+ 'set-url',
1328
+ '--push',
1329
+ remote,
1330
+ 'no_push://provider-linear-child-lane'
1331
+ ]);
1332
+ }
1333
+ return { laneWorkspacePath, laneBranch };
1334
+ }
1335
+ async function createPatchArtifact(laneWorkspacePath, runDir, baselineRef = 'HEAD', targetRef = null, currentHeadSha = null) {
1336
+ await execFileAsync('git', ['-C', laneWorkspacePath, 'add', '-N', '.']);
1337
+ const workspaceDiff = await execFileAsync('git', ['-C', laneWorkspacePath, 'diff', '--binary', '--no-ext-diff', baselineRef, '--', '.'], {
1338
+ maxBuffer: 20 * 1024 * 1024
1339
+ });
1340
+ const committedDiff = targetRef !== null
1341
+ ? await execFileAsync('git', ['-C', laneWorkspacePath, 'diff', '--binary', '--no-ext-diff', baselineRef, targetRef, '--', '.'], {
1342
+ maxBuffer: 20 * 1024 * 1024
1343
+ })
1344
+ : null;
1345
+ const shouldComposeCommittedAndWorkspaceDiff = committedDiff !== null &&
1346
+ committedDiff.stdout.length > 0 &&
1347
+ workspaceDiff.stdout.length > 0 &&
1348
+ (currentHeadSha === baselineRef || !currentHeadSha);
1349
+ let diffOutput;
1350
+ if (shouldComposeCommittedAndWorkspaceDiff) {
1351
+ if (!targetRef) {
1352
+ throw new Error(`Child-lane patch export failed closed while composing ${baselineRef}: missing transient child commit ref`);
1353
+ }
1354
+ const compositionRoot = await mkdtemp(join(tmpdir(), 'provider-linear-child-lane-compose-'));
1355
+ const compositionWorkspacePath = join(compositionRoot, 'workspace');
1356
+ const workspacePatchPath = join(compositionRoot, 'workspace.patch');
1357
+ let compositionWorktreeCreated = false;
1358
+ try {
1359
+ await execFileAsync('git', ['-C', laneWorkspacePath, 'worktree', 'add', '--detach', compositionWorkspacePath, baselineRef], {
1360
+ maxBuffer: 20 * 1024 * 1024
1361
+ });
1362
+ compositionWorktreeCreated = true;
1363
+ await writeFile(workspacePatchPath, workspaceDiff.stdout, 'utf8');
1364
+ await execFileAsync('git', ['-C', compositionWorkspacePath, 'apply', '--whitespace=nowarn', workspacePatchPath], {
1365
+ maxBuffer: 20 * 1024 * 1024
1366
+ });
1367
+ await execFileAsync('git', ['-C', compositionWorkspacePath, 'add', '-A'], {
1368
+ maxBuffer: 20 * 1024 * 1024
1369
+ });
1370
+ const workspaceSnapshotTree = normalizeOptionalString((await execFileAsync('git', ['-C', compositionWorkspacePath, 'write-tree'], {
1371
+ maxBuffer: 20 * 1024 * 1024
1372
+ })).stdout);
1373
+ if (!workspaceSnapshotTree) {
1374
+ throw new Error('missing temporary workspace snapshot tree');
1375
+ }
1376
+ const workspaceSnapshotCommit = normalizeOptionalString((await execFileAsync('git', [
1377
+ '-C',
1378
+ compositionWorkspacePath,
1379
+ 'commit-tree',
1380
+ workspaceSnapshotTree,
1381
+ '-p',
1382
+ baselineRef,
1383
+ '-m',
1384
+ 'provider-linear-child-lane workspace snapshot'
1385
+ ], {
1386
+ maxBuffer: 20 * 1024 * 1024,
1387
+ env: {
1388
+ ...process.env,
1389
+ GIT_AUTHOR_NAME: 'Codex',
1390
+ GIT_AUTHOR_EMAIL: 'codex@example.com',
1391
+ GIT_COMMITTER_NAME: 'Codex',
1392
+ GIT_COMMITTER_EMAIL: 'codex@example.com'
1393
+ }
1394
+ })).stdout);
1395
+ if (!workspaceSnapshotCommit) {
1396
+ throw new Error('missing temporary workspace snapshot commit');
1397
+ }
1398
+ await execFileAsync('git', ['-C', compositionWorkspacePath, 'checkout', '--detach', workspaceSnapshotCommit], {
1399
+ maxBuffer: 20 * 1024 * 1024
1400
+ });
1401
+ await execFileAsync('git', ['-C', compositionWorkspacePath, 'merge', '--no-commit', '--no-ff', targetRef], {
1402
+ maxBuffer: 20 * 1024 * 1024
1403
+ });
1404
+ await execFileAsync('git', ['-C', compositionWorkspacePath, 'add', '-N', '.'], {
1405
+ maxBuffer: 20 * 1024 * 1024
1406
+ });
1407
+ const composedDiff = await execFileAsync('git', ['-C', compositionWorkspacePath, 'diff', '--binary', '--no-ext-diff', baselineRef, '--', '.'], {
1408
+ maxBuffer: 20 * 1024 * 1024
1409
+ });
1410
+ diffOutput = composedDiff.stdout;
1411
+ }
1412
+ catch (error) {
1413
+ const detail = error instanceof Error ? error.message : String(error);
1414
+ throw new Error(`Child-lane patch export failed closed while composing ${baselineRef}${targetRef ? ` with transient child commit ${targetRef}` : ''} and live workspace changes: ${detail}`);
1415
+ }
1416
+ finally {
1417
+ if (compositionWorktreeCreated) {
1418
+ await execFileAsync('git', ['-C', laneWorkspacePath, 'worktree', 'remove', '--force', compositionWorkspacePath], {
1419
+ maxBuffer: 20 * 1024 * 1024
1420
+ }).catch(() => undefined);
1421
+ }
1422
+ await rm(compositionRoot, { recursive: true, force: true }).catch(() => undefined);
1423
+ }
1424
+ }
1425
+ else {
1426
+ const diffChunks = [];
1427
+ if (committedDiff && (currentHeadSha === baselineRef || !currentHeadSha)) {
1428
+ diffChunks.push(committedDiff.stdout);
1429
+ }
1430
+ if (workspaceDiff.stdout.length > 0 || diffChunks.length === 0) {
1431
+ diffChunks.push(workspaceDiff.stdout);
1432
+ }
1433
+ diffOutput = diffChunks.join('');
1434
+ }
1435
+ const patchArtifactPath = join(runDir, 'provider-linear-child-lane.patch');
1436
+ await writeFile(patchArtifactPath, diffOutput, 'utf8');
1437
+ return {
1438
+ patchArtifactPath,
1439
+ patchBytes: Buffer.byteLength(diffOutput, 'utf8')
1440
+ };
1441
+ }
1442
+ async function readProviderLinearChildLaneHeadSha(laneWorkspacePath) {
1443
+ const result = await execFileAsync('git', ['-C', laneWorkspacePath, 'rev-parse', 'HEAD'], {
1444
+ maxBuffer: 1024 * 1024
1445
+ });
1446
+ return normalizeOptionalString(result.stdout);
1447
+ }
1448
+ async function countProviderLinearChildLaneReflogEntries(laneWorkspacePath) {
1449
+ const result = await execFileAsync('git', ['-C', laneWorkspacePath, 'reflog', '--format=%H'], {
1450
+ maxBuffer: 1024 * 1024
1451
+ });
1452
+ return result.stdout
1453
+ .split(/\r?\n/u)
1454
+ .map((line) => normalizeOptionalString(line))
1455
+ .filter((line) => line !== null).length;
1456
+ }
1457
+ async function detectProviderLinearChildLaneCreatedCommitShas(laneWorkspacePath, startingHeadSha, startingReflogEntryCount = 0) {
1458
+ if (!startingHeadSha) {
1459
+ return [];
1460
+ }
1461
+ const result = await execFileAsync('git', ['-C', laneWorkspacePath, 'reflog', '--format=%H%x09%gs'], {
1462
+ maxBuffer: 1024 * 1024
1463
+ });
1464
+ const reflogEntries = result.stdout.split(/\r?\n/u).filter((line) => line.trim().length > 0);
1465
+ const newEntryCount = Math.max(0, reflogEntries.length - Math.max(0, startingReflogEntryCount));
1466
+ const createdCommitShas = [];
1467
+ const seen = new Set();
1468
+ for (const line of reflogEntries.slice(0, newEntryCount)) {
1469
+ const [rawSha, rawSummary = ''] = line.split('\t', 2);
1470
+ const sha = normalizeOptionalString(rawSha);
1471
+ const summary = normalizeOptionalString(rawSummary);
1472
+ if (!sha ||
1473
+ !summary ||
1474
+ sha === startingHeadSha ||
1475
+ seen.has(sha) ||
1476
+ !/^(?:am|commit(?:\s+\([^)]*\))?|cherry-pick|merge(?:\s+[^:]*)?|revert|rebase(?:\s+-i)?\s+\((?:pick|reword|edit|squash|fixup|continue|finish)\)):/u.test(summary)) {
1477
+ continue;
1478
+ }
1479
+ seen.add(sha);
1480
+ createdCommitShas.push(sha);
1481
+ }
1482
+ return createdCommitShas;
1483
+ }
1484
+ function resolveProviderLinearChildLaneUnauthorizedCommitMessage(input) {
1485
+ if (input.createdCommitShas.length === 0) {
1486
+ if (!input.expectedBaseSha || !input.currentHeadSha || input.expectedBaseSha === input.currentHeadSha) {
1487
+ return null;
1488
+ }
1489
+ return `Child lane created commit ${input.currentHeadSha} from parent base ${input.expectedBaseSha} for ${input.context.issueIdentifier} instead of returning an uncommitted patch artifact. Invalidate the lane and relaunch; parent acceptance owns integration and branch updates.`;
1490
+ }
1491
+ const renderedCreatedCommitShas = input.createdCommitShas.slice(0, 3).join(', ');
1492
+ const currentHeadSuffix = input.expectedBaseSha && input.currentHeadSha === input.expectedBaseSha
1493
+ ? ' and reset HEAD back to the parent base'
1494
+ : input.currentHeadSha
1495
+ ? ` and left HEAD at ${input.currentHeadSha}`
1496
+ : '';
1497
+ if (!input.expectedBaseSha) {
1498
+ return `Child lane created commit(s) ${renderedCreatedCommitShas} for ${input.context.issueIdentifier} instead of returning an uncommitted patch artifact${currentHeadSuffix}. Invalidate the lane and relaunch; parent acceptance owns integration and branch updates.`;
1499
+ }
1500
+ return `Child lane created commit(s) ${renderedCreatedCommitShas} from parent base ${input.expectedBaseSha} for ${input.context.issueIdentifier} instead of returning an uncommitted patch artifact${currentHeadSuffix}. Invalidate the lane and relaunch; parent acceptance owns integration and branch updates.`;
1501
+ }
1502
+ async function writeChildLaneProof(runDir, proof) {
1503
+ await writeFile(join(runDir, PROVIDER_LINEAR_CHILD_LANE_PROOF_FILENAME), `${JSON.stringify(proof, null, 2)}\n`, 'utf8');
1504
+ }
1505
+ async function writeProviderLinearChildLaneDiagnostics(context, patch) {
1506
+ const diagnosticsPath = join(context.runDir, PROVIDER_LINEAR_CHILD_LANE_DIAGNOSTICS_FILENAME);
1507
+ try {
1508
+ let existing = {};
1509
+ try {
1510
+ const parsed = JSON.parse(await readFile(diagnosticsPath, 'utf8'));
1511
+ existing = isRecord(parsed) ? parsed : {};
1512
+ }
1513
+ catch {
1514
+ existing = {};
1515
+ }
1516
+ await writeAtomicFile(diagnosticsPath, `${JSON.stringify({
1517
+ ...existing,
1518
+ issue_id: context.issueId,
1519
+ issue_identifier: context.issueIdentifier,
1520
+ task_id: context.taskId,
1521
+ run_id: context.runId,
1522
+ parent_run_id: context.parentRunId,
1523
+ stream: context.stream,
1524
+ ...patch
1525
+ }, null, 2)}\n`, { ensureDir: true, encoding: 'utf8' });
1526
+ }
1527
+ catch (error) {
1528
+ logger.warn(`[provider-linear-child-lane-diagnostics] failed to persist ${basename(diagnosticsPath)} at ${diagnosticsPath}: ${error instanceof Error ? error.message : String(error)}`);
1529
+ }
1530
+ }
1531
+ function buildFailedChildLaneProof(input) {
1532
+ return {
1533
+ issue_id: input.context.issueId,
1534
+ issue_identifier: input.context.issueIdentifier,
1535
+ task_id: input.context.taskId,
1536
+ run_id: input.context.runId,
1537
+ parent_run_id: input.context.parentRunId,
1538
+ stream: input.context.stream,
1539
+ purpose: input.context.purpose,
1540
+ instructions: input.context.instructions,
1541
+ scope: input.context.scope,
1542
+ parent_snapshot: input.context.parentSnapshot,
1543
+ lane_workspace_path: input.laneWorkspacePath,
1544
+ lane_branch: input.laneBranch,
1545
+ patch_artifact_path: input.patchArtifactPath ?? join(input.context.runDir, 'provider-linear-child-lane.patch'),
1546
+ patch_bytes: input.patchBytes ?? 0,
1547
+ thread_id: input.parsed?.threadId ?? null,
1548
+ latest_turn_id: input.parsed?.turnId ?? null,
1549
+ latest_session_id: input.session?.sessionId ?? null,
1550
+ latest_session_id_source: input.session?.source ?? null,
1551
+ last_event: input.parsed?.lastEvent ?? null,
1552
+ last_message: input.lastMessage,
1553
+ last_event_at: input.parsed?.lastEventAt ?? null,
1554
+ tokens: input.parsed?.tokens ?? buildEmptyProviderLinearWorkerTokenUsage(),
1555
+ rate_limits: input.parsed?.rateLimits ?? null,
1556
+ status: 'failed',
1557
+ updated_at: input.updatedAt
1558
+ };
1559
+ }
1560
+ export async function runProviderLinearChildLane(env = process.env, dependencyOverrides = {}) {
1561
+ const deps = {
1562
+ now: () => new Date().toISOString(),
1563
+ sleep: async (ms) => {
1564
+ await new Promise((resolvePromise) => {
1565
+ setTimeout(resolvePromise, ms);
1566
+ });
1567
+ },
1568
+ execRunner: defaultExecRunner,
1569
+ discoverStartupSessionLogPath: discoverProviderLinearChildLaneSessionLogPath,
1570
+ ...dependencyOverrides
1571
+ };
1572
+ const context = await loadProviderLinearChildLaneContext(env);
1573
+ const runnerStartedAt = deps.now();
1574
+ await writeProviderLinearChildLaneDiagnostics(context, {
1575
+ provider_linear_child_lane_runner_entrypoint: PROVIDER_LINEAR_CHILD_LANE_RUNNER_ENTRYPOINT,
1576
+ provider_linear_child_lane_runner_pid: process.pid,
1577
+ provider_linear_child_lane_runner_started_at: runnerStartedAt,
1578
+ provider_linear_child_lane_runtime_event: 'runner_started',
1579
+ provider_linear_child_lane_runtime_event_at: runnerStartedAt
1580
+ });
1581
+ const { laneWorkspacePath, laneBranch } = await prepareLaneWorkspace(context);
1582
+ const startingHeadSha = await readProviderLinearChildLaneHeadSha(laneWorkspacePath).catch(() => null);
1583
+ const startingReflogEntryCount = await countProviderLinearChildLaneReflogEntries(laneWorkspacePath).catch(() => 0);
1584
+ try {
1585
+ const runtimeContext = await resolveChildLaneRuntimeContext(env, laneWorkspacePath, context.runId);
1586
+ logger.info(`[provider-linear-child-lane-runtime] ${formatRuntimeSelectionSummary(runtimeContext.runtime)}`);
1587
+ await writeProviderLinearChildLaneDiagnostics(context, {
1588
+ provider_linear_child_lane_runtime_requested_mode: runtimeContext.runtime.requested_mode,
1589
+ provider_linear_child_lane_runtime_selected_mode: runtimeContext.runtime.selected_mode,
1590
+ provider_linear_child_lane_runtime_source: runtimeContext.runtime.source,
1591
+ provider_linear_child_lane_runtime_provider: runtimeContext.runtime.provider,
1592
+ provider_linear_child_lane_runtime_session_id: runtimeContext.runtime.runtime_session_id,
1593
+ provider_linear_child_lane_runtime_fallback_occurred: runtimeContext.runtime.fallback.occurred,
1594
+ provider_linear_child_lane_runtime_fallback_code: runtimeContext.runtime.fallback.code,
1595
+ provider_linear_child_lane_runtime_fallback_reason: runtimeContext.runtime.fallback.reason,
1596
+ provider_linear_child_lane_runtime_fallback_from_mode: runtimeContext.runtime.fallback.from_mode,
1597
+ provider_linear_child_lane_runtime_fallback_to_mode: runtimeContext.runtime.fallback.to_mode,
1598
+ provider_linear_child_lane_runtime_fallback_checked_at: runtimeContext.runtime.fallback.checked_at,
1599
+ provider_linear_child_lane_runtime_event: 'runtime_selected',
1600
+ provider_linear_child_lane_runtime_event_at: deps.now()
1601
+ });
1602
+ const childEnv = { ...process.env, ...env, ...runtimeContext.env };
1603
+ childEnv.CODEX_NON_INTERACTIVE = '1';
1604
+ childEnv.CODEX_NO_INTERACTIVE = '1';
1605
+ childEnv.CODEX_INTERACTIVE = '0';
1606
+ delete childEnv.CODEX_THREAD_ID;
1607
+ const prompt = buildChildLanePrompt(context);
1608
+ const { command, args } = resolveRuntimeCodexCommand(['exec', '--json', prompt], runtimeContext);
1609
+ const startedAt = deps.now();
1610
+ const execAbortController = new AbortController();
1611
+ let execSettled = false;
1612
+ let execPromise = null;
1613
+ let scopeDriftMessage = null;
1614
+ let execResult = null;
1615
+ try {
1616
+ execPromise = deps.execRunner({
1617
+ command,
1618
+ args,
1619
+ cwd: laneWorkspacePath,
1620
+ env: childEnv,
1621
+ mirrorOutput: false,
1622
+ abortSignal: execAbortController.signal
1623
+ });
1624
+ void execPromise.then(() => {
1625
+ execSettled = true;
1626
+ }, () => {
1627
+ execSettled = true;
1628
+ });
1629
+ if (runtimeContext.runtime.selected_mode === 'appserver') {
1630
+ const startupRace = await Promise.race([
1631
+ execPromise.then((result) => ({ kind: 'exec', result })),
1632
+ waitForProviderLinearChildLaneAppserverStartup({
1633
+ context,
1634
+ laneWorkspacePath,
1635
+ env: childEnv,
1636
+ startedAt,
1637
+ isExecSettled: () => execSettled,
1638
+ deps
1639
+ }).then((sessionLogPath) => ({ kind: 'startup', sessionLogPath }))
1640
+ ]);
1641
+ if (startupRace.kind === 'exec') {
1642
+ execResult = startupRace.result;
1643
+ }
1644
+ else {
1645
+ if (startupRace.sessionLogPath) {
1646
+ logger.info(`[provider-linear-child-lane-runtime] appserver startup observed via session log ${basename(startupRace.sessionLogPath)}`);
1647
+ const startupObservedAt = deps.now();
1648
+ await writeProviderLinearChildLaneDiagnostics(context, {
1649
+ provider_linear_child_lane_runtime_event: 'appserver_startup_observed',
1650
+ provider_linear_child_lane_runtime_event_at: startupObservedAt,
1651
+ provider_linear_child_lane_appserver_startup_observed: true,
1652
+ provider_linear_child_lane_appserver_startup_observed_at: startupObservedAt,
1653
+ provider_linear_child_lane_appserver_session_log: basename(startupRace.sessionLogPath)
1654
+ });
1655
+ }
1656
+ const execOrDriftRace = startupRace.sessionLogPath
1657
+ ? await Promise.race([
1658
+ execPromise.then((result) => ({ kind: 'exec', result })),
1659
+ waitForProviderLinearChildLaneScopeDrift({
1660
+ context,
1661
+ sessionLogPath: startupRace.sessionLogPath,
1662
+ startedAt,
1663
+ isExecSettled: () => execSettled,
1664
+ deps
1665
+ }).then((message) => ({ kind: 'drift', message }))
1666
+ ])
1667
+ : ({ kind: 'exec', result: await execPromise });
1668
+ if (execOrDriftRace.kind === 'exec') {
1669
+ execResult = execOrDriftRace.result;
1670
+ }
1671
+ else {
1672
+ scopeDriftMessage = execOrDriftRace.message;
1673
+ if (scopeDriftMessage) {
1674
+ execResult = await recoverProviderLinearChildLaneExecResultAfterAbort({
1675
+ abortController: execAbortController,
1676
+ error: new Error(scopeDriftMessage),
1677
+ execPromise,
1678
+ execSettled
1679
+ });
1680
+ if (!execResult) {
1681
+ throw new Error(scopeDriftMessage);
1682
+ }
1683
+ }
1684
+ else {
1685
+ execResult = await execPromise;
1686
+ }
1687
+ }
1688
+ }
1689
+ }
1690
+ else {
1691
+ execResult = await execPromise;
1692
+ }
1693
+ }
1694
+ catch (error) {
1695
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
1696
+ execResult = await recoverProviderLinearChildLaneExecResultAfterAbort({
1697
+ abortController: execAbortController,
1698
+ error: normalizedError,
1699
+ execPromise,
1700
+ execSettled
1701
+ });
1702
+ if (execResult) {
1703
+ execSettled = true;
1704
+ }
1705
+ else {
1706
+ const failedProof = buildFailedChildLaneProof({
1707
+ context,
1708
+ laneWorkspacePath,
1709
+ laneBranch,
1710
+ lastMessage: normalizedError.message,
1711
+ updatedAt: deps.now()
1712
+ });
1713
+ await writeChildLaneProof(context.runDir, failedProof);
1714
+ throw normalizedError;
1715
+ }
1716
+ }
1717
+ if (!execResult) {
1718
+ throw new Error('provider-linear-child-lane completed without an exec result');
1719
+ }
1720
+ await writeProviderLinearChildLaneDiagnostics(context, {
1721
+ provider_linear_child_lane_runtime_event: 'codex_exec_completed',
1722
+ provider_linear_child_lane_runtime_event_at: deps.now(),
1723
+ provider_linear_child_lane_exec_exit_code: execResult.exitCode
1724
+ });
1725
+ const parsed = parseProviderLinearWorkerJsonl(execResult.stdout);
1726
+ const session = deriveLatestTurnSessionId({
1727
+ threadId: parsed.threadId,
1728
+ turnId: parsed.turnId
1729
+ });
1730
+ const currentHeadSha = await readProviderLinearChildLaneHeadSha(laneWorkspacePath).catch(() => null);
1731
+ const createdCommitShas = await detectProviderLinearChildLaneCreatedCommitShas(laneWorkspacePath, startingHeadSha, startingReflogEntryCount).catch(() => []);
1732
+ const unauthorizedCommitMessage = resolveProviderLinearChildLaneUnauthorizedCommitMessage({
1733
+ context,
1734
+ expectedBaseSha: context.parentSnapshot.base_sha,
1735
+ currentHeadSha,
1736
+ createdCommitShas
1737
+ });
1738
+ const patchTargetRef = createdCommitShas[0] ?? null;
1739
+ const patchBaselineRef = context.parentSnapshot.base_sha &&
1740
+ (patchTargetRef !== null || (currentHeadSha !== null && context.parentSnapshot.base_sha !== currentHeadSha))
1741
+ ? context.parentSnapshot.base_sha
1742
+ : 'HEAD';
1743
+ const forcedFailureMessage = scopeDriftMessage ?? unauthorizedCommitMessage;
1744
+ let patchArtifactPath = join(context.runDir, 'provider-linear-child-lane.patch');
1745
+ let patchBytes = 0;
1746
+ let proof;
1747
+ try {
1748
+ ({ patchArtifactPath, patchBytes } = await createPatchArtifact(laneWorkspacePath, context.runDir, patchBaselineRef, patchTargetRef, currentHeadSha));
1749
+ proof = {
1750
+ issue_id: context.issueId,
1751
+ issue_identifier: context.issueIdentifier,
1752
+ task_id: context.taskId,
1753
+ run_id: context.runId,
1754
+ parent_run_id: context.parentRunId,
1755
+ stream: context.stream,
1756
+ purpose: context.purpose,
1757
+ instructions: context.instructions,
1758
+ scope: context.scope,
1759
+ parent_snapshot: context.parentSnapshot,
1760
+ lane_workspace_path: laneWorkspacePath,
1761
+ lane_branch: laneBranch,
1762
+ patch_artifact_path: patchArtifactPath,
1763
+ patch_bytes: patchBytes,
1764
+ thread_id: parsed.threadId,
1765
+ latest_turn_id: parsed.turnId,
1766
+ latest_session_id: session.sessionId,
1767
+ latest_session_id_source: session.source,
1768
+ last_event: parsed.lastEvent,
1769
+ last_message: forcedFailureMessage ?? parsed.finalMessage,
1770
+ last_event_at: parsed.lastEventAt,
1771
+ tokens: parsed.tokens,
1772
+ rate_limits: parsed.rateLimits,
1773
+ status: execResult.exitCode === 0 && !forcedFailureMessage ? 'succeeded' : 'failed',
1774
+ updated_at: deps.now()
1775
+ };
1776
+ await writeChildLaneProof(context.runDir, proof);
1777
+ }
1778
+ catch (error) {
1779
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
1780
+ const failedProof = buildFailedChildLaneProof({
1781
+ context,
1782
+ laneWorkspacePath,
1783
+ laneBranch,
1784
+ lastMessage: normalizedError.message,
1785
+ updatedAt: deps.now(),
1786
+ parsed,
1787
+ session,
1788
+ patchArtifactPath,
1789
+ patchBytes
1790
+ });
1791
+ try {
1792
+ await writeChildLaneProof(context.runDir, failedProof);
1793
+ }
1794
+ catch (proofWriteError) {
1795
+ logger.warn(`[provider-linear-child-lane-proof] failed to persist failure proof after post-exec export error: ${proofWriteError instanceof Error ? proofWriteError.message : String(proofWriteError)}`);
1796
+ }
1797
+ throw normalizedError;
1798
+ }
1799
+ if (proof.status !== 'succeeded') {
1800
+ throw new Error(proof.last_message ?? `provider-linear-child-lane exited with code ${execResult.exitCode ?? 'unknown'}`);
1801
+ }
1802
+ return proof;
1803
+ }
1804
+ finally {
1805
+ await compactRedundantTrustedChildLaneProjectsBestEffort({
1806
+ env,
1807
+ laneWorkspacePath
1808
+ });
1809
+ }
1810
+ }
1811
+ async function main() {
1812
+ await runProviderLinearChildLane();
1813
+ }
1814
+ const entry = process.argv[1] ? resolve(process.argv[1]) : null;
1815
+ const self = resolve(fileURLToPath(import.meta.url));
1816
+ if (entry && entry === self) {
1817
+ main().catch((error) => {
1818
+ logger.error(error instanceof Error ? error.message : String(error));
1819
+ process.exitCode = 1;
1820
+ });
1821
+ }
1822
+ export const __test__ = {
1823
+ buildChildLanePrompt,
1824
+ buildProviderLinearChildLaneAppserverStartupTimeoutMessage,
1825
+ createPatchArtifact,
1826
+ detectProviderLinearChildLaneCreatedCommitShas,
1827
+ discoverProviderLinearChildLaneSessionLogPath,
1828
+ planTrustedProjectCleanup,
1829
+ extractProviderLinearChildLaneScopeDriftEvidenceFromRecord,
1830
+ recoverProviderLinearChildLaneExecResultAfterAbort,
1831
+ resolveProviderLinearChildLaneUnauthorizedCommitMessage,
1832
+ scanProviderLinearChildLaneSessionLogForParentScopeDrift,
1833
+ waitForProviderLinearChildLaneAppserverStartup,
1834
+ waitForProviderLinearChildLaneScopeDrift
1835
+ };