@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,22 @@
1
+ import { createControlServerBootstrapLifecycle } from './controlServerBootstrapLifecycle.js';
2
+ import { createControlTelegramBridgeLifecycle } from './controlTelegramBridgeLifecycle.js';
3
+ import { createControlTelegramBridgeOversightFacadeFactory } from './controlTelegramBridgeOversightFacadeFactory.js';
4
+ export function createControlTelegramBridgeBootstrapLifecycle(context) {
5
+ const telegramBridgeLifecycle = createControlTelegramBridgeLifecycle({
6
+ runDir: context.paths.runDir,
7
+ createOversightFacade: createControlTelegramBridgeOversightFacadeFactory({
8
+ requestContextShared: context.requestContextShared,
9
+ getExpiryLifecycle: () => context.getExpiryLifecycle(),
10
+ emitDispatchPilotAuditEvents: context.emitDispatchPilotAuditEvents
11
+ })
12
+ });
13
+ return createControlServerBootstrapLifecycle({
14
+ paths: {
15
+ controlAuthPath: context.paths.controlAuthPath,
16
+ controlEndpointPath: context.paths.controlEndpointPath
17
+ },
18
+ persistControl: context.persistControl,
19
+ startExpiryLifecycle: context.startExpiryLifecycle,
20
+ telegramBridgeLifecycle
21
+ });
22
+ }
@@ -0,0 +1,67 @@
1
+ import { logger } from '../../logger.js';
2
+ import { startTelegramOversightBridge } from './telegramOversightBridge.js';
3
+ export function createControlTelegramBridgeLifecycle(options) {
4
+ return new ControlTelegramBridgeLifecycleRuntime(options);
5
+ }
6
+ class ControlTelegramBridgeLifecycleRuntime {
7
+ runDir;
8
+ createOversightFacade;
9
+ startTelegramBridgeImpl;
10
+ telegramBridge = null;
11
+ unsubscribeTelegramBridge = null;
12
+ lifecycleOperation = Promise.resolve();
13
+ constructor(options) {
14
+ this.runDir = options.runDir;
15
+ this.createOversightFacade = options.createOversightFacade;
16
+ this.startTelegramBridgeImpl = options.startTelegramBridgeImpl ?? startTelegramOversightBridge;
17
+ }
18
+ async start(options) {
19
+ await this.enqueueLifecycleOperation(async () => {
20
+ await this.closeActiveBridge();
21
+ const oversightFacade = this.createOversightFacade();
22
+ const bridge = await this.startTelegramBridgeImpl({
23
+ runDir: this.runDir,
24
+ readAdapter: oversightFacade,
25
+ baseUrl: options.baseUrl,
26
+ controlToken: options.controlToken
27
+ });
28
+ if (!bridge) {
29
+ return;
30
+ }
31
+ await this.attachTelegramBridge(bridge, oversightFacade);
32
+ });
33
+ }
34
+ async close() {
35
+ await this.enqueueLifecycleOperation(async () => {
36
+ await this.closeActiveBridge();
37
+ });
38
+ }
39
+ enqueueLifecycleOperation(operation) {
40
+ const nextOperation = this.lifecycleOperation.then(operation, operation);
41
+ this.lifecycleOperation = nextOperation.then(() => undefined, () => undefined);
42
+ return nextOperation;
43
+ }
44
+ async closeActiveBridge() {
45
+ this.unsubscribeTelegramBridge?.();
46
+ this.unsubscribeTelegramBridge = null;
47
+ const bridge = this.telegramBridge;
48
+ this.telegramBridge = null;
49
+ if (bridge) {
50
+ await bridge.close().catch((error) => {
51
+ logger.warn(`Failed to close Telegram oversight bridge: ${error?.message ?? String(error)}`);
52
+ });
53
+ }
54
+ }
55
+ async attachTelegramBridge(bridge, oversightFacade) {
56
+ try {
57
+ this.unsubscribeTelegramBridge = oversightFacade.subscribe((input) => bridge.notifyProjectionDelta(input));
58
+ this.telegramBridge = bridge;
59
+ }
60
+ catch (error) {
61
+ await bridge.close().catch((closeError) => {
62
+ logger.warn(`Failed to close Telegram oversight bridge: ${closeError?.message ?? String(closeError)}`);
63
+ });
64
+ throw error;
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,8 @@
1
+ import { createControlOversightFacade } from './controlOversightFacade.js';
2
+ export function createControlTelegramBridgeOversightFacadeFactory(context) {
3
+ return () => createControlOversightFacade({
4
+ ...context.requestContextShared,
5
+ expiryLifecycle: context.getExpiryLifecycle(),
6
+ emitDispatchPilotAuditEvents: context.emitDispatchPilotAuditEvents
7
+ });
8
+ }
@@ -0,0 +1,49 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ export function createControlTelegramCommandController(input) {
3
+ return {
4
+ async dispatchMutatingCommand({ command, updateId, chatId, user }) {
5
+ switch (command) {
6
+ case '/pause':
7
+ case '/resume':
8
+ return applyControlCommand(command.slice(1), {
9
+ updateId,
10
+ chatId,
11
+ user,
12
+ mutationsEnabled: input.mutationsEnabled,
13
+ controlActionClient: input.controlActionClient
14
+ });
15
+ default:
16
+ return null;
17
+ }
18
+ }
19
+ };
20
+ }
21
+ async function applyControlCommand(action, input) {
22
+ if (!input.mutationsEnabled) {
23
+ return `${capitalize(action)} is disabled for this Telegram bridge.`;
24
+ }
25
+ const nonce = `telegram:${input.chatId}:${input.updateId}:${action}:${randomBytes(4).toString('hex')}`;
26
+ const nonceExpiresAt = new Date(Date.now() + 60 * 1000).toISOString();
27
+ const actorId = input.user?.id ? `telegram.user.${input.user.id}` : `telegram.chat.${input.chatId}`;
28
+ const body = {
29
+ action,
30
+ requested_by: 'telegram',
31
+ request_id: `telegram-${action}-${input.updateId}`,
32
+ intent_id: `telegram-${action}-${input.updateId}`,
33
+ reason: `telegram_command_${action}`,
34
+ transport: 'telegram',
35
+ actor_id: actorId,
36
+ actor_source: 'telegram.bot.polling',
37
+ transport_principal: `telegram:chat:${input.chatId}`,
38
+ transport_nonce: nonce,
39
+ transport_nonce_expires_at: nonceExpiresAt
40
+ };
41
+ const payload = await input.controlActionClient.postAction(body);
42
+ if (payload.error) {
43
+ return `${capitalize(action)} failed: ${payload.error}`;
44
+ }
45
+ return `${capitalize(action)} requested. Control decision: ${payload.traceability?.decision ?? 'applied'}${typeof payload.control_seq === 'number' ? ` (seq ${payload.control_seq})` : ''}.`;
46
+ }
47
+ function capitalize(value) {
48
+ return value.length === 0 ? value : `${value[0].toUpperCase()}${value.slice(1)}`;
49
+ }
@@ -0,0 +1,40 @@
1
+ import { buildControlInternalContext } from './controlRequestContext.js';
2
+ import { readDispatchExtension } from './observabilitySurface.js';
3
+ export async function readControlTelegramDispatch(context) {
4
+ const internalContext = buildControlInternalContext(context);
5
+ const runtimeSnapshot = internalContext.runtime.snapshot();
6
+ const result = await readDispatchExtension({
7
+ readDispatchEvaluation: () => runtimeSnapshot.readDispatchEvaluation()
8
+ });
9
+ await context.emitDispatchPilotAuditEvents(internalContext, {
10
+ surface: 'telegram_dispatch',
11
+ evaluation: result.evaluation,
12
+ issueIdentifier: result.issueIdentifier
13
+ });
14
+ return buildTelegramOversightDispatchPayload(result);
15
+ }
16
+ function buildTelegramOversightDispatchPayload(result) {
17
+ if (result.kind === 'ok') {
18
+ const payload = result.payload;
19
+ return {
20
+ dispatch_pilot: payload.dispatch_pilot && typeof payload.dispatch_pilot === 'object'
21
+ ? payload.dispatch_pilot
22
+ : result.evaluation.summary,
23
+ recommendation: payload.recommendation && typeof payload.recommendation === 'object'
24
+ ? payload.recommendation
25
+ : null
26
+ };
27
+ }
28
+ const dispatchPilot = result.details.dispatch_pilot && typeof result.details.dispatch_pilot === 'object'
29
+ ? result.details.dispatch_pilot
30
+ : result.evaluation.summary;
31
+ return {
32
+ dispatch_pilot: dispatchPilot,
33
+ error: {
34
+ code: result.failure.code,
35
+ details: {
36
+ dispatch_pilot: dispatchPilot
37
+ }
38
+ }
39
+ };
40
+ }
@@ -0,0 +1,89 @@
1
+ import { logger } from '../../logger.js';
2
+ const DEFAULT_POLL_TIMEOUT_SECONDS = 20;
3
+ export function createControlTelegramPollingController(input) {
4
+ let activeController = null;
5
+ return {
6
+ abort() {
7
+ activeController?.abort();
8
+ activeController = null;
9
+ },
10
+ async run(runtime) {
11
+ while (!runtime.isClosed()) {
12
+ try {
13
+ const updates = await fetchUpdates({
14
+ pollIntervalMs: input.pollIntervalMs,
15
+ telegramClient: input.telegramClient,
16
+ offset: runtime.readNextUpdateId(),
17
+ setActiveController: (controller) => {
18
+ activeController = controller;
19
+ },
20
+ clearActiveController: (controller) => {
21
+ if (activeController === controller) {
22
+ activeController = null;
23
+ }
24
+ }
25
+ });
26
+ if (updates.length > 0) {
27
+ await handleUpdates({
28
+ updates,
29
+ readNextUpdateId: runtime.readNextUpdateId,
30
+ persistNextUpdateId: runtime.persistNextUpdateId,
31
+ readBotUsername: runtime.readBotUsername,
32
+ updateHandler: input.updateHandler
33
+ });
34
+ }
35
+ }
36
+ catch (error) {
37
+ if (runtime.isClosed() || isAbortError(error)) {
38
+ break;
39
+ }
40
+ logger.warn(`[telegram-oversight] polling failed: ${error?.message ?? String(error)}`);
41
+ }
42
+ if (runtime.isClosed()) {
43
+ break;
44
+ }
45
+ await delay(input.pollIntervalMs);
46
+ }
47
+ }
48
+ };
49
+ }
50
+ async function fetchUpdates(input) {
51
+ const controller = new AbortController();
52
+ input.setActiveController(controller);
53
+ try {
54
+ const timeout = Math.max(DEFAULT_POLL_TIMEOUT_SECONDS, Math.ceil((input.pollIntervalMs + 500) / 1_000));
55
+ return input.telegramClient.getUpdates({
56
+ offset: input.offset,
57
+ timeoutSeconds: timeout,
58
+ signal: controller.signal
59
+ });
60
+ }
61
+ finally {
62
+ input.clearActiveController(controller);
63
+ }
64
+ }
65
+ async function handleUpdates(input) {
66
+ const initialNextUpdateId = input.readNextUpdateId();
67
+ let nextUpdateId = initialNextUpdateId;
68
+ for (const update of input.updates) {
69
+ nextUpdateId = Math.max(nextUpdateId, update.update_id + 1);
70
+ try {
71
+ await input.updateHandler.handleUpdate({
72
+ update,
73
+ botUsername: input.readBotUsername()
74
+ });
75
+ }
76
+ catch (error) {
77
+ logger.warn(`[telegram-oversight] failed to handle update ${update.update_id}: ${error?.message ?? String(error)}`);
78
+ }
79
+ }
80
+ if (nextUpdateId !== initialNextUpdateId) {
81
+ await input.persistNextUpdateId(nextUpdateId, new Date().toISOString());
82
+ }
83
+ }
84
+ function delay(ms) {
85
+ return new Promise((resolve) => setTimeout(resolve, ms));
86
+ }
87
+ function isAbortError(error) {
88
+ return error instanceof Error && error.name === 'AbortError';
89
+ }
@@ -0,0 +1,29 @@
1
+ import { computeTelegramProjectionStateTransition } from './controlTelegramPushState.js';
2
+ export function createControlTelegramProjectionNotificationController(input) {
3
+ return {
4
+ async notifyProjectionDelta({ pushState, eventSeq }) {
5
+ const nowMs = input.nowMs?.() ?? Date.now();
6
+ const projection = await input.renderProjectionDeltaMessage();
7
+ const transition = computeTelegramProjectionStateTransition({
8
+ pushState,
9
+ projectionHash: projection.projectionHash,
10
+ eventSeq,
11
+ nowMs,
12
+ pushCooldownMs: input.pushCooldownMs
13
+ });
14
+ if (transition.kind !== 'send') {
15
+ return {
16
+ delivery: transition.kind,
17
+ statePatch: transition.statePatch
18
+ };
19
+ }
20
+ for (const chatId of input.allowedChatIds) {
21
+ await input.sendMessage(chatId, projection.text);
22
+ }
23
+ return {
24
+ delivery: 'send',
25
+ statePatch: transition.statePatch
26
+ };
27
+ }
28
+ };
29
+ }
@@ -0,0 +1,63 @@
1
+ export function createDefaultTelegramOversightState() {
2
+ return {
3
+ next_update_id: 0,
4
+ updated_at: new Date(0).toISOString(),
5
+ push: {
6
+ last_sent_projection_hash: null,
7
+ last_sent_at: null,
8
+ last_event_seq: null,
9
+ pending_projection_hash: null,
10
+ pending_projection_observed_at: null
11
+ }
12
+ };
13
+ }
14
+ export function computeTelegramProjectionStateTransition(input) {
15
+ const nextEventSeq = typeof input.eventSeq === 'number' && Number.isFinite(input.eventSeq)
16
+ ? Math.floor(input.eventSeq)
17
+ : input.pushState.last_event_seq;
18
+ const nowIso = new Date(input.nowMs).toISOString();
19
+ if (!input.projectionHash || input.projectionHash === input.pushState.last_sent_projection_hash) {
20
+ return {
21
+ kind: 'skip',
22
+ statePatch: {
23
+ updated_at: nowIso,
24
+ push: {
25
+ ...input.pushState,
26
+ last_event_seq: nextEventSeq,
27
+ pending_projection_hash: null,
28
+ pending_projection_observed_at: null
29
+ }
30
+ }
31
+ };
32
+ }
33
+ const lastSentAtMs = input.pushState.last_sent_at ? Date.parse(input.pushState.last_sent_at) : Number.NaN;
34
+ if (Number.isFinite(lastSentAtMs) && input.nowMs - lastSentAtMs < input.pushCooldownMs) {
35
+ return {
36
+ kind: 'pending',
37
+ statePatch: {
38
+ updated_at: nowIso,
39
+ push: {
40
+ ...input.pushState,
41
+ last_event_seq: nextEventSeq,
42
+ pending_projection_hash: input.projectionHash,
43
+ pending_projection_observed_at: input.projectionHash === input.pushState.pending_projection_hash
44
+ ? input.pushState.pending_projection_observed_at ?? nowIso
45
+ : nowIso
46
+ }
47
+ }
48
+ };
49
+ }
50
+ return {
51
+ kind: 'send',
52
+ statePatch: {
53
+ updated_at: nowIso,
54
+ push: {
55
+ last_sent_projection_hash: input.projectionHash,
56
+ last_sent_at: nowIso,
57
+ last_event_seq: nextEventSeq,
58
+ pending_projection_hash: null,
59
+ pending_projection_observed_at: null
60
+ }
61
+ }
62
+ };
63
+ }
@@ -0,0 +1,13 @@
1
+ import { createControlQuestionChildResolutionAdapter } from './controlQuestionChildResolution.js';
2
+ import { buildControlInternalContext } from './controlRequestContext.js';
3
+ import { runQuestionReadSequence } from './questionReadSequence.js';
4
+ export async function readControlTelegramQuestions(context) {
5
+ const internalContext = buildControlInternalContext(context);
6
+ const questionChildResolutionAdapter = createControlQuestionChildResolutionAdapter(internalContext);
7
+ const result = await runQuestionReadSequence({
8
+ listQuestions: () => internalContext.questionQueue.list(),
9
+ expireQuestions: () => internalContext.expiryLifecycle?.expireQuestions(questionChildResolutionAdapter) ?? Promise.resolve()
10
+ });
11
+ questionChildResolutionAdapter.queueQuestionResolutions(result.retryCandidates);
12
+ return { questions: result.questions };
13
+ }
@@ -0,0 +1,216 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { buildSelectedRunQuestionSummaryPayload, buildSelectedRunRuntimeFingerprintInput } from './observabilityReadModel.js';
3
+ export function createControlTelegramReadController(input) {
4
+ return {
5
+ async dispatchReadCommand(command) {
6
+ switch (command) {
7
+ case '/start':
8
+ return 'CO oversight is connected. Use /help for commands.';
9
+ case '/help':
10
+ return buildHelpMessage(input.mutationsEnabled);
11
+ case '/status':
12
+ return renderStatus(input.readAdapter);
13
+ case '/issue':
14
+ return renderIssue(input.readAdapter);
15
+ case '/dispatch':
16
+ return renderDispatch(input.readAdapter);
17
+ case '/questions':
18
+ return renderQuestions(input.readAdapter);
19
+ default:
20
+ return null;
21
+ }
22
+ },
23
+ async renderProjectionDeltaMessage() {
24
+ const snapshot = await input.readAdapter.readSelectedRun();
25
+ return {
26
+ projectionHash: buildProjectionHash(snapshot),
27
+ text: buildStatusMessage(snapshot)
28
+ };
29
+ }
30
+ };
31
+ }
32
+ async function renderStatus(readAdapter) {
33
+ return buildStatusMessage(await readAdapter.readSelectedRun());
34
+ }
35
+ async function renderIssue(readAdapter) {
36
+ const snapshot = await readAdapter.readSelectedRun();
37
+ const selected = snapshot.selected ?? null;
38
+ if (!selected?.issueIdentifier) {
39
+ return 'No issue identifier is available for the current run.';
40
+ }
41
+ const trackedLinear = selected.tracked?.linear ?? snapshot.tracked?.linear ?? null;
42
+ const latestEvent = selected.latestEvent ?? null;
43
+ const displayStatus = selected.displayStatus ?? 'unknown';
44
+ const questionSummary = buildSelectedRunQuestionSummaryPayload(selected.questionSummary);
45
+ return [
46
+ `Issue ${selected.issueIdentifier}`,
47
+ formatStateLine(displayStatus, selected.rawStatus ?? null, 'Status'),
48
+ selected.statusReason ? `Reason: ${selected.statusReason}` : null,
49
+ trackedLinear?.identifier
50
+ ? `Linear: ${trackedLinear.identifier}${trackedLinear.title ? ` - ${truncateLine(trackedLinear.title, 120)}` : ''}`
51
+ : null,
52
+ trackedLinear?.state ? `Linear state: ${trackedLinear.state}` : null,
53
+ trackedLinear?.url ? `Linear URL: ${trackedLinear.url}` : null,
54
+ latestEvent?.event ? `Latest event: ${latestEvent.event}` : null,
55
+ latestEvent?.message
56
+ ? `Latest summary: ${truncateLine(latestEvent.message, 180)}`
57
+ : selected.summary
58
+ ? `Latest summary: ${truncateLine(selected.summary, 180)}`
59
+ : null,
60
+ formatQuestionSummary(questionSummary),
61
+ formatDispatchSummary(snapshot.dispatchPilot ?? null)
62
+ ]
63
+ .filter(Boolean)
64
+ .join('\n');
65
+ }
66
+ async function renderDispatch(readAdapter) {
67
+ const payload = await readAdapter.readDispatch();
68
+ const dispatchPilot = payload.dispatch_pilot ?? payload.error?.details?.dispatch_pilot ?? null;
69
+ const trackedIssue = payload.recommendation?.tracked_issue ?? null;
70
+ return [
71
+ 'Dispatch advisory',
72
+ formatDispatchSummary(dispatchPilot),
73
+ payload.recommendation?.summary ? `Summary: ${truncateLine(payload.recommendation.summary, 180)}` : null,
74
+ payload.recommendation?.rationale ? `Rationale: ${truncateLine(payload.recommendation.rationale, 180)}` : null,
75
+ payload.recommendation?.confidence !== undefined && payload.recommendation?.confidence !== null
76
+ ? `Confidence: ${payload.recommendation.confidence}`
77
+ : null,
78
+ trackedIssue?.identifier
79
+ ? `Tracked issue: ${trackedIssue.identifier}${trackedIssue.title ? ` - ${truncateLine(trackedIssue.title, 120)}` : ''}`
80
+ : null,
81
+ trackedIssue?.url ? `Tracked URL: ${trackedIssue.url}` : null,
82
+ payload.error?.code ? `Status: ${payload.error.code}` : null
83
+ ]
84
+ .filter(Boolean)
85
+ .join('\n');
86
+ }
87
+ async function renderQuestions(readAdapter) {
88
+ const payload = await readAdapter.readQuestions();
89
+ const queued = (payload.questions ?? []).filter((question) => question.status === 'queued');
90
+ if (queued.length === 0) {
91
+ return 'No queued questions.';
92
+ }
93
+ return [
94
+ `Queued questions: ${queued.length}`,
95
+ ...queued.slice(0, 3).map((question) => {
96
+ const urgency = question.urgency ? ` [${question.urgency}]` : '';
97
+ return `${question.question_id ?? 'question'}${urgency}: ${truncateLine(question.prompt ?? '', 140)}`;
98
+ })
99
+ ].join('\n');
100
+ }
101
+ function buildStatusMessage(snapshot) {
102
+ const selected = snapshot.selected ?? null;
103
+ const dispatch = snapshot.dispatchPilot ?? null;
104
+ const trackedLinear = selected?.tracked?.linear ?? snapshot.tracked?.linear ?? null;
105
+ const providerIntake = snapshot.providerIntake ?? null;
106
+ if (!selected) {
107
+ return [
108
+ 'CO status',
109
+ 'No active running projection.',
110
+ formatProviderIntakeSummary(providerIntake),
111
+ trackedLinear?.identifier
112
+ ? `Linear: ${trackedLinear.identifier}${trackedLinear.title ? ` - ${truncateLine(trackedLinear.title, 120)}` : ''}`
113
+ : null,
114
+ trackedLinear?.state ? `Linear state: ${trackedLinear.state}` : null,
115
+ formatDispatchSummary(dispatch)
116
+ ]
117
+ .filter(Boolean)
118
+ .join('\n');
119
+ }
120
+ const issueIdentifier = selected.issueIdentifier ?? 'n/a';
121
+ const sessionId = selected.runId ?? null;
122
+ const displayStatus = selected.displayStatus ?? 'unknown';
123
+ const rawStatus = selected.rawStatus ?? null;
124
+ const statusReason = selected.statusReason ?? null;
125
+ const latestEvent = selected.latestEvent ?? null;
126
+ const questionSummary = buildSelectedRunQuestionSummaryPayload(selected.questionSummary);
127
+ const summary = latestEvent?.message ?? selected.summary ?? null;
128
+ return [
129
+ 'CO status',
130
+ `Issue: ${issueIdentifier}`,
131
+ formatStateLine(displayStatus, rawStatus),
132
+ statusReason ? `Reason: ${statusReason}` : null,
133
+ formatProviderIntakeSummary(providerIntake),
134
+ sessionId ? `Session: ${sessionId}` : null,
135
+ latestEvent?.event ? `Last event: ${latestEvent.event}` : null,
136
+ summary ? `Summary: ${truncateLine(summary, 180)}` : null,
137
+ formatQuestionSummary(questionSummary),
138
+ trackedLinear?.identifier
139
+ ? `Linear: ${trackedLinear.identifier}${trackedLinear.title ? ` - ${truncateLine(trackedLinear.title, 120)}` : ''}`
140
+ : null,
141
+ trackedLinear?.state ? `Linear state: ${trackedLinear.state}` : null,
142
+ formatDispatchSummary(dispatch)
143
+ ]
144
+ .filter(Boolean)
145
+ .join('\n');
146
+ }
147
+ function buildHelpMessage(mutationsEnabled) {
148
+ return [
149
+ 'Commands:',
150
+ '/start',
151
+ '/help',
152
+ '/status',
153
+ '/issue',
154
+ '/dispatch',
155
+ '/questions',
156
+ mutationsEnabled ? '/pause' : '/pause (disabled)',
157
+ mutationsEnabled ? '/resume' : '/resume (disabled)'
158
+ ].join('\n');
159
+ }
160
+ function formatDispatchSummary(dispatchPilot) {
161
+ if (!dispatchPilot) {
162
+ return null;
163
+ }
164
+ const status = dispatchPilot.status ?? 'unknown';
165
+ const sourceStatus = dispatchPilot.source_status ?? 'unknown';
166
+ const reason = dispatchPilot.reason ? ` (${dispatchPilot.reason})` : '';
167
+ return `Dispatch: ${status}/${sourceStatus}${reason}`;
168
+ }
169
+ function formatProviderIntakeSummary(providerIntake) {
170
+ if (!providerIntake) {
171
+ return null;
172
+ }
173
+ const claim = providerIntake.selected_claim;
174
+ const runId = claim.run_id ? ` -> ${claim.run_id}` : '';
175
+ const reason = claim.reason ? ` (${claim.reason})` : '';
176
+ if (providerIntake.summary_scope === 'selected_claim') {
177
+ return `Intake: selected claim ${claim.issue_identifier} of ${providerIntake.active_claim_count} active / ${providerIntake.running_claim_count} running -> ${claim.task_id}${runId}${reason}`;
178
+ }
179
+ return `Intake: ${claim.state} ${claim.issue_identifier} -> ${claim.task_id}${runId}${reason}`;
180
+ }
181
+ function formatStateLine(displayStatus, rawStatus, label = 'State') {
182
+ const normalizedDisplay = displayStatus && displayStatus.trim().length > 0 ? displayStatus.trim() : 'unknown';
183
+ const normalizedRaw = rawStatus && rawStatus.trim().length > 0 ? rawStatus.trim() : null;
184
+ if (!normalizedRaw || normalizedRaw === normalizedDisplay) {
185
+ return `${label}: ${normalizedDisplay}`;
186
+ }
187
+ return `${label}: ${normalizedDisplay} (raw ${normalizedRaw})`;
188
+ }
189
+ function formatQuestionSummary(summary) {
190
+ if (!summary || typeof summary.queued_count !== 'number' || summary.queued_count <= 0) {
191
+ return null;
192
+ }
193
+ const latestQuestion = summary.latest_question ?? null;
194
+ const latestPrompt = latestQuestion?.prompt && latestQuestion.prompt.trim().length > 0
195
+ ? truncateLine(latestQuestion.prompt, 120)
196
+ : null;
197
+ const urgency = latestQuestion?.urgency && latestQuestion.urgency.trim().length > 0 ? ` [${latestQuestion.urgency}]` : '';
198
+ if (latestQuestion?.question_id) {
199
+ return `Queued questions: ${summary.queued_count} (latest ${latestQuestion.question_id}${urgency}${latestPrompt ? `: ${latestPrompt}` : ''})`;
200
+ }
201
+ return `Queued questions: ${summary.queued_count}`;
202
+ }
203
+ function truncateLine(value, maxLength) {
204
+ const normalized = value.replace(/\s+/g, ' ').trim();
205
+ if (normalized.length <= maxLength) {
206
+ return normalized;
207
+ }
208
+ return `${normalized.slice(0, Math.max(maxLength - 3, 1))}...`;
209
+ }
210
+ function buildProjectionHash(snapshot) {
211
+ const fingerprint = buildSelectedRunRuntimeFingerprintInput(snapshot);
212
+ if (!fingerprint) {
213
+ return null;
214
+ }
215
+ return createHash('sha256').update(JSON.stringify(fingerprint)).digest('hex');
216
+ }
@@ -0,0 +1,63 @@
1
+ import { logger } from '../../logger.js';
2
+ export function createControlTelegramUpdateHandler(input) {
3
+ return {
4
+ async handleUpdate({ update, botUsername }) {
5
+ const message = update.message;
6
+ if (!message?.chat) {
7
+ return;
8
+ }
9
+ const chatId = String(message.chat.id);
10
+ if (!input.allowedChatIds.has(chatId)) {
11
+ logger.warn(`[telegram-oversight] ignoring unauthorized chat ${chatId}`);
12
+ return;
13
+ }
14
+ const rawText = typeof message.text === 'string' ? message.text.trim() : '';
15
+ if (!rawText.startsWith('/')) {
16
+ await input.sendMessage(chatId, 'Use /help for available commands.');
17
+ return;
18
+ }
19
+ const command = normalizeTelegramCommand(rawText, botUsername ?? null);
20
+ const response = await dispatchCommand({
21
+ command,
22
+ updateId: update.update_id,
23
+ chatId,
24
+ user: message.from ?? null,
25
+ readController: input.readController,
26
+ commandController: input.commandController
27
+ });
28
+ await input.sendMessage(chatId, response);
29
+ }
30
+ };
31
+ }
32
+ async function dispatchCommand(input) {
33
+ const readResponse = await input.readController.dispatchReadCommand(input.command);
34
+ if (readResponse !== null) {
35
+ return readResponse;
36
+ }
37
+ const mutatingResponse = await input.commandController.dispatchMutatingCommand({
38
+ command: input.command,
39
+ updateId: input.updateId,
40
+ chatId: input.chatId,
41
+ user: input.user
42
+ });
43
+ if (mutatingResponse !== null) {
44
+ return mutatingResponse;
45
+ }
46
+ return 'Unknown command. Use /help for commands.';
47
+ }
48
+ function normalizeTelegramCommand(input, botUsername) {
49
+ const token = input.trim().split(/\s+/, 1)[0] ?? '';
50
+ const normalized = token.toLowerCase();
51
+ if (!normalized.startsWith('/')) {
52
+ return normalized;
53
+ }
54
+ const atIndex = normalized.indexOf('@');
55
+ if (atIndex === -1) {
56
+ return normalized;
57
+ }
58
+ const suffix = normalized.slice(atIndex + 1);
59
+ if (!botUsername || suffix === botUsername.toLowerCase()) {
60
+ return normalized.slice(0, atIndex);
61
+ }
62
+ return normalized;
63
+ }