@scotthuang/agent-knock-knock 0.12.11 → 0.12.13

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 (344) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +43 -30
  3. package/dist/src/approval-policy.d.ts +11 -2
  4. package/dist/src/approval-policy.js +33 -7
  5. package/dist/src/approval-policy.js.map +1 -1
  6. package/dist/src/callback-cli-adapter.d.ts +47 -0
  7. package/dist/src/callback-cli-adapter.js +156 -0
  8. package/dist/src/callback-cli-adapter.js.map +1 -0
  9. package/dist/src/callback-outbox-policy.d.ts +95 -0
  10. package/dist/src/callback-outbox-policy.js +149 -0
  11. package/dist/src/callback-outbox-policy.js.map +1 -0
  12. package/dist/src/callback-outbox-service.d.ts +247 -0
  13. package/dist/src/callback-outbox-service.js +1053 -0
  14. package/dist/src/callback-outbox-service.js.map +1 -0
  15. package/dist/src/callback-outbox-settlement.d.ts +54 -0
  16. package/dist/src/callback-outbox-settlement.js +241 -0
  17. package/dist/src/callback-outbox-settlement.js.map +1 -0
  18. package/dist/src/canonical-json.d.ts +1 -0
  19. package/dist/src/canonical-json.js +14 -0
  20. package/dist/src/canonical-json.js.map +1 -0
  21. package/dist/src/claude-lifecycle-compatibility.js +15 -0
  22. package/dist/src/claude-lifecycle-compatibility.js.map +1 -1
  23. package/dist/src/claude-local-transcript-provider.d.ts +82 -1
  24. package/dist/src/claude-local-transcript-provider.js +873 -23
  25. package/dist/src/claude-local-transcript-provider.js.map +1 -1
  26. package/dist/src/cli-command-runtime.d.ts +14 -0
  27. package/dist/src/cli-command-runtime.js +164 -0
  28. package/dist/src/cli-command-runtime.js.map +1 -0
  29. package/dist/src/cli-core.d.ts +4 -42
  30. package/dist/src/cli-core.js +958 -28684
  31. package/dist/src/cli-core.js.map +1 -1
  32. package/dist/src/cli-runtime-context.d.ts +57 -0
  33. package/dist/src/cli-runtime-context.js +118 -0
  34. package/dist/src/cli-runtime-context.js.map +1 -0
  35. package/dist/src/codex-lifecycle-compatibility.js +2 -1
  36. package/dist/src/codex-lifecycle-compatibility.js.map +1 -1
  37. package/dist/src/codex-local-session-provider.d.ts +18 -0
  38. package/dist/src/codex-local-session-provider.js +67 -0
  39. package/dist/src/codex-local-session-provider.js.map +1 -1
  40. package/dist/src/codex-session-provider.js +1 -3
  41. package/dist/src/codex-session-provider.js.map +1 -1
  42. package/dist/src/conversation-trace.d.ts +30 -0
  43. package/dist/src/conversation-trace.js +185 -0
  44. package/dist/src/conversation-trace.js.map +1 -0
  45. package/dist/src/deferred-foreground-application-service.d.ts +84 -0
  46. package/dist/src/deferred-foreground-application-service.js +742 -0
  47. package/dist/src/deferred-foreground-application-service.js.map +1 -0
  48. package/dist/src/deferred-foreground-authority-cli-adapter.d.ts +78 -0
  49. package/dist/src/deferred-foreground-authority-cli-adapter.js +795 -0
  50. package/dist/src/deferred-foreground-authority-cli-adapter.js.map +1 -0
  51. package/dist/src/deferred-foreground-boundary.d.ts +61 -0
  52. package/dist/src/deferred-foreground-boundary.js +2 -0
  53. package/dist/src/deferred-foreground-boundary.js.map +1 -0
  54. package/dist/src/deferred-foreground-capability.d.ts +4 -0
  55. package/dist/src/deferred-foreground-capability.js +184 -0
  56. package/dist/src/deferred-foreground-capability.js.map +1 -0
  57. package/dist/src/deferred-foreground-preparation-cli-adapter.d.ts +53 -0
  58. package/dist/src/deferred-foreground-preparation-cli-adapter.js +210 -0
  59. package/dist/src/deferred-foreground-preparation-cli-adapter.js.map +1 -0
  60. package/dist/src/deferred-foreground-preparation-service.d.ts +72 -0
  61. package/dist/src/deferred-foreground-preparation-service.js +179 -0
  62. package/dist/src/deferred-foreground-preparation-service.js.map +1 -0
  63. package/dist/src/deferred-foreground-recovery-cli-adapter.d.ts +139 -0
  64. package/dist/src/deferred-foreground-recovery-cli-adapter.js +1125 -0
  65. package/dist/src/deferred-foreground-recovery-cli-adapter.js.map +1 -0
  66. package/dist/src/deferred-foreground-recovery-service.d.ts +48 -0
  67. package/dist/src/deferred-foreground-recovery-service.js +91 -0
  68. package/dist/src/deferred-foreground-recovery-service.js.map +1 -0
  69. package/dist/src/deferred-foreground-transfer-policy.d.ts +2 -0
  70. package/dist/src/deferred-foreground-transfer-policy.js +10 -0
  71. package/dist/src/deferred-foreground-transfer-policy.js.map +1 -0
  72. package/dist/src/deferred-foreground-transfer.js +46 -105
  73. package/dist/src/deferred-foreground-transfer.js.map +1 -1
  74. package/dist/src/doctor-capabilities.d.ts +9 -0
  75. package/dist/src/doctor-capabilities.js +22 -0
  76. package/dist/src/doctor-capabilities.js.map +1 -1
  77. package/dist/src/durable-json-file.d.ts +22 -0
  78. package/dist/src/durable-json-file.js +127 -0
  79. package/dist/src/durable-json-file.js.map +1 -0
  80. package/dist/src/file-lock-cli-adapter.d.ts +43 -0
  81. package/dist/src/file-lock-cli-adapter.js +150 -0
  82. package/dist/src/file-lock-cli-adapter.js.map +1 -0
  83. package/dist/src/herdr-terminal-control-provider.js +1 -3
  84. package/dist/src/herdr-terminal-control-provider.js.map +1 -1
  85. package/dist/src/install-doctor-command-adapter.d.ts +17 -0
  86. package/dist/src/install-doctor-command-adapter.js +225 -0
  87. package/dist/src/install-doctor-command-adapter.js.map +1 -0
  88. package/dist/src/live-lifecycle-evidence.js +76 -46
  89. package/dist/src/live-lifecycle-evidence.js.map +1 -1
  90. package/dist/src/live-lifecycle-smoke.js +74 -50
  91. package/dist/src/live-lifecycle-smoke.js.map +1 -1
  92. package/dist/src/managed-session.d.ts +2 -0
  93. package/dist/src/managed-session.js +24 -0
  94. package/dist/src/managed-session.js.map +1 -1
  95. package/dist/src/managed-turn-recovery-service.d.ts +86 -0
  96. package/dist/src/managed-turn-recovery-service.js +145 -0
  97. package/dist/src/managed-turn-recovery-service.js.map +1 -0
  98. package/dist/src/mutation-transaction.d.ts +48 -0
  99. package/dist/src/mutation-transaction.js +73 -0
  100. package/dist/src/mutation-transaction.js.map +1 -0
  101. package/dist/src/native-thread-lifecycle-cli-adapter.d.ts +154 -0
  102. package/dist/src/native-thread-lifecycle-cli-adapter.js +786 -0
  103. package/dist/src/native-thread-lifecycle-cli-adapter.js.map +1 -0
  104. package/dist/src/native-thread-lifecycle-ledger-cli-adapter.d.ts +25 -0
  105. package/dist/src/native-thread-lifecycle-ledger-cli-adapter.js +50 -0
  106. package/dist/src/native-thread-lifecycle-ledger-cli-adapter.js.map +1 -0
  107. package/dist/src/native-thread-lifecycle-query-service.d.ts +75 -0
  108. package/dist/src/native-thread-lifecycle-query-service.js +297 -0
  109. package/dist/src/native-thread-lifecycle-query-service.js.map +1 -0
  110. package/dist/src/native-thread-lifecycle-recovery-adapter.d.ts +45 -0
  111. package/dist/src/native-thread-lifecycle-recovery-adapter.js +154 -0
  112. package/dist/src/native-thread-lifecycle-recovery-adapter.js.map +1 -0
  113. package/dist/src/native-thread-lifecycle-recovery-service.d.ts +211 -0
  114. package/dist/src/native-thread-lifecycle-recovery-service.js +1093 -0
  115. package/dist/src/native-thread-lifecycle-recovery-service.js.map +1 -0
  116. package/dist/src/native-thread-resume-snapshot-policy.d.ts +73 -0
  117. package/dist/src/native-thread-resume-snapshot-policy.js +218 -0
  118. package/dist/src/native-thread-resume-snapshot-policy.js.map +1 -0
  119. package/dist/src/native-thread-resume-snapshot.d.ts +3 -61
  120. package/dist/src/native-thread-resume-snapshot.js +2 -143
  121. package/dist/src/native-thread-resume-snapshot.js.map +1 -1
  122. package/dist/src/native-thread-transition-application.d.ts +147 -0
  123. package/dist/src/native-thread-transition-application.js +974 -0
  124. package/dist/src/native-thread-transition-application.js.map +1 -0
  125. package/dist/src/native-thread-transition-policy.d.ts +127 -0
  126. package/dist/src/native-thread-transition-policy.js +154 -0
  127. package/dist/src/native-thread-transition-policy.js.map +1 -0
  128. package/dist/src/native-thread-transition-resource-adapter.d.ts +12 -0
  129. package/dist/src/native-thread-transition-resource-adapter.js +44 -0
  130. package/dist/src/native-thread-transition-resource-adapter.js.map +1 -0
  131. package/dist/src/native-thread-transition-settlement-service.d.ts +94 -0
  132. package/dist/src/native-thread-transition-settlement-service.js +134 -0
  133. package/dist/src/native-thread-transition-settlement-service.js.map +1 -0
  134. package/dist/src/native-thread-transition-verification-adapter.d.ts +62 -0
  135. package/dist/src/native-thread-transition-verification-adapter.js +451 -0
  136. package/dist/src/native-thread-transition-verification-adapter.js.map +1 -0
  137. package/dist/src/openclaw-callback-transport.d.ts +69 -0
  138. package/dist/src/openclaw-callback-transport.js +583 -0
  139. package/dist/src/openclaw-callback-transport.js.map +1 -0
  140. package/dist/src/openclaw-plugin-callback-adapter.d.ts +1 -0
  141. package/dist/src/openclaw-plugin-callback-adapter.js +423 -0
  142. package/dist/src/openclaw-plugin-callback-adapter.js.map +1 -0
  143. package/dist/src/openclaw-plugin-command-adapter.d.ts +16 -0
  144. package/dist/src/openclaw-plugin-command-adapter.js +1868 -0
  145. package/dist/src/openclaw-plugin-command-adapter.js.map +1 -0
  146. package/dist/src/openclaw-plugin-helpers.d.ts +27 -4
  147. package/dist/src/openclaw-plugin-helpers.js +356 -81
  148. package/dist/src/openclaw-plugin-helpers.js.map +1 -1
  149. package/dist/src/openclaw-plugin-schemas.d.ts +358 -0
  150. package/dist/src/openclaw-plugin-schemas.js +366 -0
  151. package/dist/src/openclaw-plugin-schemas.js.map +1 -0
  152. package/dist/src/openclaw-plugin-supervisor.d.ts +6 -0
  153. package/dist/src/openclaw-plugin-supervisor.js +123 -0
  154. package/dist/src/openclaw-plugin-supervisor.js.map +1 -0
  155. package/dist/src/openclaw-plugin.js +7 -2212
  156. package/dist/src/openclaw-plugin.js.map +1 -1
  157. package/dist/src/openclaw-private-authority-offers.d.ts +22 -0
  158. package/dist/src/openclaw-private-authority-offers.js +177 -0
  159. package/dist/src/openclaw-private-authority-offers.js.map +1 -0
  160. package/dist/src/protocol.d.ts +5 -0
  161. package/dist/src/protocol.js +59 -3
  162. package/dist/src/protocol.js.map +1 -1
  163. package/dist/src/session-store.d.ts +1 -0
  164. package/dist/src/session-store.js +84 -106
  165. package/dist/src/session-store.js.map +1 -1
  166. package/dist/src/store.d.ts +1 -0
  167. package/dist/src/store.js +5 -2
  168. package/dist/src/store.js.map +1 -1
  169. package/dist/src/terminal-acceptance-application-service.d.ts +65 -0
  170. package/dist/src/terminal-acceptance-application-service.js +63 -0
  171. package/dist/src/terminal-acceptance-application-service.js.map +1 -0
  172. package/dist/src/terminal-acceptance-cli-adapter.d.ts +210 -0
  173. package/dist/src/terminal-acceptance-cli-adapter.js +957 -0
  174. package/dist/src/terminal-acceptance-cli-adapter.js.map +1 -0
  175. package/dist/src/terminal-action-projection.d.ts +309 -0
  176. package/dist/src/terminal-action-projection.js +376 -0
  177. package/dist/src/terminal-action-projection.js.map +1 -0
  178. package/dist/src/terminal-agent-bridge.d.ts +3 -0
  179. package/dist/src/terminal-agent-bridge.js +29 -8
  180. package/dist/src/terminal-agent-bridge.js.map +1 -1
  181. package/dist/src/terminal-authority-policy.d.ts +141 -0
  182. package/dist/src/terminal-authority-policy.js +367 -0
  183. package/dist/src/terminal-authority-policy.js.map +1 -0
  184. package/dist/src/terminal-binding-authority.d.ts +118 -0
  185. package/dist/src/terminal-binding-authority.js +245 -0
  186. package/dist/src/terminal-binding-authority.js.map +1 -0
  187. package/dist/src/terminal-binding-reconciliation-service.d.ts +75 -0
  188. package/dist/src/terminal-binding-reconciliation-service.js +73 -0
  189. package/dist/src/terminal-binding-reconciliation-service.js.map +1 -0
  190. package/dist/src/terminal-command-cli-adapter.d.ts +380 -0
  191. package/dist/src/terminal-command-cli-adapter.js +3288 -0
  192. package/dist/src/terminal-command-cli-adapter.js.map +1 -0
  193. package/dist/src/terminal-control-ref.d.ts +4 -0
  194. package/dist/src/terminal-control-ref.js +11 -8
  195. package/dist/src/terminal-control-ref.js.map +1 -1
  196. package/dist/src/terminal-delegate-cli-adapter.d.ts +41 -0
  197. package/dist/src/terminal-delegate-cli-adapter.js +242 -0
  198. package/dist/src/terminal-delegate-cli-adapter.js.map +1 -0
  199. package/dist/src/terminal-dispatch-abort.d.ts +22 -0
  200. package/dist/src/terminal-dispatch-abort.js +30 -0
  201. package/dist/src/terminal-dispatch-abort.js.map +1 -0
  202. package/dist/src/terminal-dispatch-application.d.ts +115 -0
  203. package/dist/src/terminal-dispatch-application.js +478 -0
  204. package/dist/src/terminal-dispatch-application.js.map +1 -0
  205. package/dist/src/terminal-dispatch-capability.d.ts +63 -0
  206. package/dist/src/terminal-dispatch-capability.js +133 -0
  207. package/dist/src/terminal-dispatch-capability.js.map +1 -0
  208. package/dist/src/terminal-dispatch-completion-cli-adapter.d.ts +22 -0
  209. package/dist/src/terminal-dispatch-completion-cli-adapter.js +96 -0
  210. package/dist/src/terminal-dispatch-completion-cli-adapter.js.map +1 -0
  211. package/dist/src/terminal-dispatch-composition.d.ts +79 -0
  212. package/dist/src/terminal-dispatch-composition.js +2 -0
  213. package/dist/src/terminal-dispatch-composition.js.map +1 -0
  214. package/dist/src/terminal-dispatch-execution.d.ts +290 -0
  215. package/dist/src/terminal-dispatch-execution.js +916 -0
  216. package/dist/src/terminal-dispatch-execution.js.map +1 -0
  217. package/dist/src/terminal-dispatch-ledger-codec.d.ts +110 -0
  218. package/dist/src/terminal-dispatch-ledger-codec.js +399 -0
  219. package/dist/src/terminal-dispatch-ledger-codec.js.map +1 -0
  220. package/dist/src/terminal-dispatch-policy.d.ts +93 -0
  221. package/dist/src/terminal-dispatch-policy.js +122 -0
  222. package/dist/src/terminal-dispatch-policy.js.map +1 -0
  223. package/dist/src/terminal-dispatch-presenter.d.ts +65 -0
  224. package/dist/src/terminal-dispatch-presenter.js +258 -0
  225. package/dist/src/terminal-dispatch-presenter.js.map +1 -0
  226. package/dist/src/terminal-dispatch-receipt.d.ts +79 -0
  227. package/dist/src/terminal-dispatch-receipt.js +314 -0
  228. package/dist/src/terminal-dispatch-receipt.js.map +1 -0
  229. package/dist/src/terminal-dispatch-recovery-cli-adapter.d.ts +132 -0
  230. package/dist/src/terminal-dispatch-recovery-cli-adapter.js +1330 -0
  231. package/dist/src/terminal-dispatch-recovery-cli-adapter.js.map +1 -0
  232. package/dist/src/terminal-dispatch-recovery-service.d.ts +271 -0
  233. package/dist/src/terminal-dispatch-recovery-service.js +374 -0
  234. package/dist/src/terminal-dispatch-recovery-service.js.map +1 -0
  235. package/dist/src/terminal-dispatch-repository-cli-adapter.d.ts +35 -0
  236. package/dist/src/terminal-dispatch-repository-cli-adapter.js +483 -0
  237. package/dist/src/terminal-dispatch-repository-cli-adapter.js.map +1 -0
  238. package/dist/src/terminal-handoff-application-service.d.ts +7 -0
  239. package/dist/src/terminal-handoff-application-service.js +18 -0
  240. package/dist/src/terminal-handoff-application-service.js.map +1 -0
  241. package/dist/src/terminal-handoff-cli-adapter.d.ts +229 -0
  242. package/dist/src/terminal-handoff-cli-adapter.js +1389 -0
  243. package/dist/src/terminal-handoff-cli-adapter.js.map +1 -0
  244. package/dist/src/terminal-handoff-facts.d.ts +12 -0
  245. package/dist/src/terminal-handoff-facts.js +16 -0
  246. package/dist/src/terminal-handoff-facts.js.map +1 -0
  247. package/dist/src/terminal-identity-authority-cli-adapter.d.ts +318 -0
  248. package/dist/src/terminal-identity-authority-cli-adapter.js +1072 -0
  249. package/dist/src/terminal-identity-authority-cli-adapter.js.map +1 -0
  250. package/dist/src/terminal-identity-authority-service.d.ts +48 -0
  251. package/dist/src/terminal-identity-authority-service.js +45 -0
  252. package/dist/src/terminal-identity-authority-service.js.map +1 -0
  253. package/dist/src/terminal-list-cli-adapter.d.ts +274 -0
  254. package/dist/src/terminal-list-cli-adapter.js +2444 -0
  255. package/dist/src/terminal-list-cli-adapter.js.map +1 -0
  256. package/dist/src/terminal-list-renderer.d.ts +34 -0
  257. package/dist/src/terminal-list-renderer.js +643 -0
  258. package/dist/src/terminal-list-renderer.js.map +1 -0
  259. package/dist/src/terminal-maintenance-cli-adapter.d.ts +102 -0
  260. package/dist/src/terminal-maintenance-cli-adapter.js +1059 -0
  261. package/dist/src/terminal-maintenance-cli-adapter.js.map +1 -0
  262. package/dist/src/terminal-monitor-application-service.d.ts +275 -0
  263. package/dist/src/terminal-monitor-application-service.js +982 -0
  264. package/dist/src/terminal-monitor-application-service.js.map +1 -0
  265. package/dist/src/terminal-monitor-cli-adapter.d.ts +130 -0
  266. package/dist/src/terminal-monitor-cli-adapter.js +442 -0
  267. package/dist/src/terminal-monitor-cli-adapter.js.map +1 -0
  268. package/dist/src/terminal-monitor-decision-policy.d.ts +98 -0
  269. package/dist/src/terminal-monitor-decision-policy.js +246 -0
  270. package/dist/src/terminal-monitor-decision-policy.js.map +1 -0
  271. package/dist/src/terminal-monitor-launch-plan.d.ts +45 -0
  272. package/dist/src/terminal-monitor-launch-plan.js +94 -0
  273. package/dist/src/terminal-monitor-launch-plan.js.map +1 -0
  274. package/dist/src/terminal-monitor-ownership-policy.d.ts +31 -0
  275. package/dist/src/terminal-monitor-ownership-policy.js +64 -0
  276. package/dist/src/terminal-monitor-ownership-policy.js.map +1 -0
  277. package/dist/src/terminal-monitor-poll-policy.d.ts +48 -0
  278. package/dist/src/terminal-monitor-poll-policy.js +67 -0
  279. package/dist/src/terminal-monitor-poll-policy.js.map +1 -0
  280. package/dist/src/terminal-monitor-reconciliation-eligibility.d.ts +53 -0
  281. package/dist/src/terminal-monitor-reconciliation-eligibility.js +114 -0
  282. package/dist/src/terminal-monitor-reconciliation-eligibility.js.map +1 -0
  283. package/dist/src/terminal-monitor-state-cli-adapter.d.ts +106 -0
  284. package/dist/src/terminal-monitor-state-cli-adapter.js +1492 -0
  285. package/dist/src/terminal-monitor-state-cli-adapter.js.map +1 -0
  286. package/dist/src/terminal-monitor-state-reconciliation-service.d.ts +87 -0
  287. package/dist/src/terminal-monitor-state-reconciliation-service.js +106 -0
  288. package/dist/src/terminal-monitor-state-reconciliation-service.js.map +1 -0
  289. package/dist/src/terminal-monitor-supervision-cli-adapter.d.ts +122 -0
  290. package/dist/src/terminal-monitor-supervision-cli-adapter.js +685 -0
  291. package/dist/src/terminal-monitor-supervision-cli-adapter.js.map +1 -0
  292. package/dist/src/terminal-process-facts.d.ts +2 -0
  293. package/dist/src/terminal-process-facts.js +19 -0
  294. package/dist/src/terminal-process-facts.js.map +1 -0
  295. package/dist/src/terminal-process-source.d.ts +6 -4
  296. package/dist/src/terminal-process-source.js +25 -20
  297. package/dist/src/terminal-process-source.js.map +1 -1
  298. package/dist/src/terminal-runtime-cli-adapter.d.ts +80 -0
  299. package/dist/src/terminal-runtime-cli-adapter.js +488 -0
  300. package/dist/src/terminal-runtime-cli-adapter.js.map +1 -0
  301. package/dist/src/terminal-scoped-approval-authority.d.ts +62 -0
  302. package/dist/src/terminal-scoped-approval-authority.js +281 -0
  303. package/dist/src/terminal-scoped-approval-authority.js.map +1 -0
  304. package/dist/src/terminal-selector-projection-service.d.ts +26 -0
  305. package/dist/src/terminal-selector-projection-service.js +81 -0
  306. package/dist/src/terminal-selector-projection-service.js.map +1 -0
  307. package/dist/src/terminal-status-cli-adapter.d.ts +126 -0
  308. package/dist/src/terminal-status-cli-adapter.js +577 -0
  309. package/dist/src/terminal-status-cli-adapter.js.map +1 -0
  310. package/dist/src/terminal-status-facts.d.ts +56 -0
  311. package/dist/src/terminal-status-facts.js +199 -0
  312. package/dist/src/terminal-status-facts.js.map +1 -0
  313. package/dist/src/terminal-submission-acceptance.d.ts +62 -145
  314. package/dist/src/terminal-submission-acceptance.js +555 -222
  315. package/dist/src/terminal-submission-acceptance.js.map +1 -1
  316. package/dist/src/terminal-submission-facts.d.ts +123 -0
  317. package/dist/src/terminal-submission-facts.js +205 -0
  318. package/dist/src/terminal-submission-facts.js.map +1 -0
  319. package/dist/src/terminal-turn-binding-authority-cli-adapter.d.ts +14 -0
  320. package/dist/src/terminal-turn-binding-authority-cli-adapter.js +90 -0
  321. package/dist/src/terminal-turn-binding-authority-cli-adapter.js.map +1 -0
  322. package/dist/src/terminal-watch-callback-cli-adapter.d.ts +20 -0
  323. package/dist/src/terminal-watch-callback-cli-adapter.js +55 -0
  324. package/dist/src/terminal-watch-callback-cli-adapter.js.map +1 -0
  325. package/dist/src/terminal-watch-cli-adapter.d.ts +64 -0
  326. package/dist/src/terminal-watch-cli-adapter.js +508 -0
  327. package/dist/src/terminal-watch-cli-adapter.js.map +1 -0
  328. package/dist/src/terminal-watch-service.d.ts +97 -0
  329. package/dist/src/terminal-watch-service.js +714 -0
  330. package/dist/src/terminal-watch-service.js.map +1 -0
  331. package/dist/src/terminal-watch-store.d.ts +149 -0
  332. package/dist/src/terminal-watch-store.js +861 -0
  333. package/dist/src/terminal-watch-store.js.map +1 -0
  334. package/dist/src/value-guards.d.ts +4 -0
  335. package/dist/src/value-guards.js +12 -0
  336. package/dist/src/value-guards.js.map +1 -0
  337. package/dist/src/verified-dead-agent-policy.d.ts +192 -0
  338. package/dist/src/verified-dead-agent-policy.js +262 -0
  339. package/dist/src/verified-dead-agent-policy.js.map +1 -0
  340. package/docs/quickstart-herdr.md +8 -0
  341. package/docs/quickstart-tmux.md +33 -6
  342. package/openclaw.plugin.json +11 -3
  343. package/package.json +3 -1
  344. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +58 -40
@@ -0,0 +1,1125 @@
1
+ import { createHash } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { managedSessionBindingToken, managedSessionRevision } from "./managed-session.js";
5
+ import { executorForConversation, sessionIdForConversation, turnIdForConversation } from "./protocol.js";
6
+ import { loadManagedSession } from "./session-store.js";
7
+ import { isCompleteNativeRollout, terminalControlsShareIncarnation } from "./terminal-authority-policy.js";
8
+ import { terminalControlEvidenceMatches } from "./terminal-control-ref.js";
9
+ import { terminalSubmissionPayload } from "./terminal-dispatch-execution.js";
10
+ import { terminalDispatchLedgerLooksLifecycle, terminalDispatchReceiptHistory as terminalLedgerReceiptHistory } from "./terminal-dispatch-ledger-codec.js";
11
+ import { terminalBridgeRequestFingerprint, terminalBridgeSubmission } from "./terminal-dispatch-receipt.js";
12
+ import { detectCodexCandidateSetRolloutAcceptance, detectCodexRolloutAcceptance, validateCodexRolloutAcceptanceAnchor, validateTerminalSubmissionAcceptanceEvidence } from "./terminal-submission-acceptance.js";
13
+ import { loadState, pathsForConversation, pathsForConversationDir, saveState } from "./store.js";
14
+ import { isRecord, nonBlankString as stringValue } from "./value-guards.js";
15
+ import { cliEnv, cliExit, cliNow, cliRuntimeLog as runtimeLog } from "./cli-runtime-context.js";
16
+ const TERMINAL_INPUT_EVIDENCE_FIELDS = [
17
+ "text_injected_at",
18
+ "enter_dispatched_at",
19
+ "submitted_at",
20
+ "agent_accepted_at",
21
+ "not_accepted_at",
22
+ "uncertain_at",
23
+ "acceptance_evidence"
24
+ ];
25
+ const DEFERRED_INPUT_EVIDENCE_FIELDS = [
26
+ "dispatch_started_at",
27
+ ...TERMINAL_INPUT_EVIDENCE_FIELDS
28
+ ];
29
+ const DEFERRED_ACCEPTANCE_RECOVERY_STATUSES = new Set([
30
+ "prepared",
31
+ "text_injected",
32
+ "enter_dispatched",
33
+ "uncertain",
34
+ "agent_accepted"
35
+ ]);
36
+ function required(value, message) {
37
+ if (value === undefined || value === null || value === "") {
38
+ throw new Error(message);
39
+ }
40
+ return value;
41
+ }
42
+ export function deferredCodexBoundaryFromTransfer(ports, { terminal, transfer }) {
43
+ const liveIncarnation = ports.native.processIncarnation(terminal.pid);
44
+ if (terminal.agent !== "codex" ||
45
+ transfer.terminal_id !== terminal.conversationId ||
46
+ transfer.process_pid !== terminal.pid ||
47
+ transfer.process_uuid !== liveIncarnation.processUuid ||
48
+ transfer.process_birth !== liveIncarnation.processBirth ||
49
+ path.resolve(transfer.workspace) !== path.resolve(terminal.terminalControl.currentPath ?? "") ||
50
+ !terminalControlEvidenceMatches(transfer.terminal_endpoint, terminal.terminalControl)) {
51
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} no longer ` +
52
+ "matches the exact terminal incarnation");
53
+ }
54
+ return {
55
+ terminal,
56
+ transferId: transfer.transfer_id,
57
+ targetSessionId: transfer.target_session_id,
58
+ sourceSessionId: transfer.source_session_id,
59
+ sourceBoundRevision: transfer.source_expected_revision,
60
+ sourceBoundBindingToken: transfer.source_binding_token,
61
+ processUuid: transfer.process_uuid,
62
+ processBirth: transfer.process_birth,
63
+ previousDispatchSnapshot: {
64
+ status: transfer.previous_dispatch_status,
65
+ fingerprint: transfer.previous_dispatch_fingerprint
66
+ },
67
+ sourceKind: transfer.version === 1
68
+ ? "status_card_only"
69
+ : required(transfer.source_kind, "deferred foreground source kind is unavailable"),
70
+ sourceRolloutAuthority: transfer.source_rollout_authority ?? "present",
71
+ ...(transfer.source_abandonment_fingerprint
72
+ ? {
73
+ sourceAbandonmentFingerprint: transfer.source_abandonment_fingerprint
74
+ }
75
+ : {}),
76
+ ...(transfer.source_turn_history
77
+ ? { sourceTurnHistory: transfer.source_turn_history }
78
+ : {}),
79
+ ...(transfer.source_previous_last_transition_id
80
+ ? {
81
+ sourcePreviousLastTransitionId: transfer.source_previous_last_transition_id
82
+ }
83
+ : {}),
84
+ sourceReservedRevision: transfer.source_expected_revision + 1,
85
+ sourceReservedBindingToken: managedSessionBindingToken({
86
+ session_id: transfer.source_session_id,
87
+ status: "transitioning",
88
+ binding: transfer.source_before_binding
89
+ }),
90
+ targetPreparedRevision: transfer.target_prepared_revision,
91
+ targetPreparedBindingToken: transfer.target_prepared_binding_token
92
+ };
93
+ }
94
+ export function loadDeferredForegroundTurnAuthority(ports, { storeDir, terminal, transfer, scope }) {
95
+ if (scope)
96
+ assertActiveTurnRoute(scope, transfer);
97
+ const statePath = canonicalDeferredTurnStatePath(storeDir, transfer);
98
+ const canonical = pathsForConversationDir(path.dirname(statePath));
99
+ const conversation = loadState(statePath);
100
+ const takeover = isRecord(conversation.native_session_takeover)
101
+ ? conversation.native_session_takeover
102
+ : undefined;
103
+ const submission = terminalBridgeSubmission(conversation);
104
+ const terminalControl = ports.turn.terminalControl(takeover);
105
+ const anchor = validatedDeferredAnchor(takeover?.codex_rollout_acceptance_anchor);
106
+ const target = loadManagedSession(storeDir, transfer.target_session_id);
107
+ const turnNativeThreadId = stringValue(conversation.native_thread_id);
108
+ const takeoverNativeThreadId = stringValue(takeover?.terminal_agent_session_id);
109
+ const submissionNativeThreadId = stringValue(submission?.native_thread_id);
110
+ const context = {
111
+ ports,
112
+ storeDir,
113
+ terminal,
114
+ transfer,
115
+ conversation,
116
+ statePath,
117
+ takeover,
118
+ submission,
119
+ terminalControl,
120
+ target,
121
+ targetBefore: transfer.target_before_binding,
122
+ anchor,
123
+ prebindingTurn: turnNativeThreadId === undefined &&
124
+ takeoverNativeThreadId === undefined &&
125
+ submissionNativeThreadId === undefined &&
126
+ takeover?.terminal_agent_rollout === undefined,
127
+ acceptedTurn: exactAcceptedDeferredTurn({
128
+ transfer,
129
+ submission,
130
+ turnNativeThreadId,
131
+ takeoverNativeThreadId,
132
+ submissionNativeThreadId,
133
+ turnRollout: takeover?.terminal_agent_rollout
134
+ }),
135
+ precommitTargetAuthority: exactPrecommitTarget(transfer, target),
136
+ committedTargetAuthority: exactCommittedTarget(transfer, target)
137
+ };
138
+ if (!deferredTurnAuthorityMatches(context)) {
139
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} Turn authority ` +
140
+ "does not match its exact request/terminal/process fence");
141
+ }
142
+ return {
143
+ conversation,
144
+ statePath,
145
+ logPath: canonical.logPath,
146
+ takeover: takeover,
147
+ submission: submission,
148
+ anchor: anchor
149
+ };
150
+ }
151
+ function canonicalDeferredTurnStatePath(storeDir, transfer) {
152
+ const statePath = path.resolve(required(transfer.state_path, "deferred foreground Turn state path is unavailable"));
153
+ const canonical = pathsForConversationDir(path.dirname(statePath));
154
+ if (path.resolve(canonical.storeDir) !== path.resolve(storeDir) ||
155
+ path.resolve(canonical.statePath) !== statePath) {
156
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has a noncanonical ` +
157
+ "Turn state path");
158
+ }
159
+ return statePath;
160
+ }
161
+ function assertActiveTurnRoute(scope, transfer) {
162
+ if (!scope.transferBelongsToTurn(transfer)) {
163
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} escaped its ` +
164
+ "active Turn state capability");
165
+ }
166
+ }
167
+ function validatedDeferredAnchor(value) {
168
+ try {
169
+ return validateCodexRolloutAcceptanceAnchor(value);
170
+ }
171
+ catch {
172
+ return undefined;
173
+ }
174
+ }
175
+ function exactPrecommitTarget(transfer, target) {
176
+ return Boolean(!["committed", "resolved"].includes(transfer.status) &&
177
+ target.status === "transitioning" &&
178
+ target.last_transition_id === transfer.transfer_id);
179
+ }
180
+ function exactCommittedTarget(transfer, target) {
181
+ const binding = transfer.target_accepted_binding;
182
+ if (!binding || !["committed", "resolved"].includes(transfer.status)) {
183
+ return false;
184
+ }
185
+ const transitioning = target.status === "transitioning" &&
186
+ target.last_transition_id === transfer.transfer_id &&
187
+ managedSessionRevision(target) === transfer.target_accepted_revision &&
188
+ managedSessionBindingToken(target) ===
189
+ transfer.target_accepted_binding_token;
190
+ const bound = target.status === "bound" &&
191
+ !target.last_transition_id &&
192
+ managedSessionRevision(target) ===
193
+ Number(transfer.target_accepted_revision) + 1 &&
194
+ managedSessionBindingToken(target) === managedSessionBindingToken({
195
+ session_id: transfer.target_session_id,
196
+ status: "bound",
197
+ binding
198
+ });
199
+ return (transitioning || bound) &&
200
+ JSON.stringify(target.binding) === JSON.stringify(binding);
201
+ }
202
+ function exactAcceptedDeferredTurn(input) {
203
+ if (!input.turnNativeThreadId ||
204
+ input.takeoverNativeThreadId !== input.turnNativeThreadId ||
205
+ input.submissionNativeThreadId !== input.turnNativeThreadId ||
206
+ !isCompleteNativeRollout(input.turnRollout) ||
207
+ String(input.submission?.status) !== "agent_accepted") {
208
+ return false;
209
+ }
210
+ try {
211
+ validateTerminalSubmissionAcceptanceEvidence(input.submission?.acceptance_evidence, {
212
+ source: "codex_rollout",
213
+ nativeThreadId: input.turnNativeThreadId,
214
+ requestHash: input.transfer.request_hash
215
+ });
216
+ return true;
217
+ }
218
+ catch {
219
+ return false;
220
+ }
221
+ }
222
+ function deferredTurnAuthorityMatches(context) {
223
+ return deferredTurnTerminalMatches(context) &&
224
+ deferredTurnStorageMatches(context) &&
225
+ deferredTurnRequestMatches(context) &&
226
+ deferredTurnBindingMatches(context) &&
227
+ deferredTargetMatches(context) &&
228
+ exactDeferredAcceptanceAnchor(context.anchor, context.transfer);
229
+ }
230
+ function deferredTurnTerminalMatches(context) {
231
+ const { terminalControl, terminal, conversation, transfer } = context;
232
+ return Boolean(context.takeover && context.submission && terminalControl &&
233
+ context.targetBefore &&
234
+ terminalControlsShareIncarnation(terminalControl, terminal.terminalControl) &&
235
+ terminalControlEvidenceMatches(context.takeover.terminal_endpoint ?? terminalControl, terminal.terminalControl) &&
236
+ executorForConversation(conversation).kind === "codex" &&
237
+ conversation.conversation_id === transfer.turn_id &&
238
+ sessionIdForConversation(conversation) === transfer.target_session_id &&
239
+ turnIdForConversation(conversation) === transfer.turn_id);
240
+ }
241
+ function deferredTurnStorageMatches(context) {
242
+ const { ports, storeDir, conversation, statePath, takeover, transfer } = context;
243
+ return Boolean(path.resolve(required(stringValue(conversation.state_path), "deferred foreground Turn state path is missing")) === statePath &&
244
+ path.resolve(pathsForConversation(conversation.conversation_id, storeDir).statePath) === statePath &&
245
+ path.resolve(required(ports.turn.storeDir(conversation), "deferred foreground Turn Store is missing")) === path.resolve(storeDir) &&
246
+ stringValue(takeover.deferred_foreground_transfer_id) ===
247
+ transfer.transfer_id &&
248
+ stringValue(takeover.terminal_bridge_message_id) === transfer.message_id);
249
+ }
250
+ function deferredTurnRequestMatches(context) {
251
+ const { storeDir, conversation, takeover, submission, transfer } = context;
252
+ const messageBodyHash = stringValue(submission.message_body_hash);
253
+ const requestText = stringValue(takeover.terminal_bridge_request_text);
254
+ return Boolean(stringValue(submission.session_id) === transfer.target_session_id &&
255
+ stringValue(submission.turn_id) === transfer.turn_id &&
256
+ stringValue(submission.message_id) === transfer.message_id &&
257
+ stringValue(submission.message_type) === "task" &&
258
+ stringValue(submission.executor_kind) === "codex" &&
259
+ messageBodyHash && /^[0-9a-f]{64}$/u.test(messageBodyHash) &&
260
+ createHash("sha256").update(String(conversation.user_request)).digest("hex") ===
261
+ messageBodyHash &&
262
+ terminalBridgeRequestFingerprint(terminalSubmissionPayload(String(conversation.user_request))) === transfer.request_hash &&
263
+ stringValue(takeover.terminal_bridge_request_hash) ===
264
+ transfer.request_hash &&
265
+ stringValue(submission.request_hash) === transfer.request_hash &&
266
+ requestText &&
267
+ terminalBridgeRequestFingerprint(requestText) === transfer.request_hash &&
268
+ path.resolve(required(stringValue(submission.store_dir), "deferred foreground submission Store is missing")) === path.resolve(storeDir));
269
+ }
270
+ function deferredTurnBindingMatches(context) {
271
+ const { conversation, takeover, submission, targetBefore, transfer } = context;
272
+ if (!targetBefore)
273
+ return false;
274
+ const bindingAuthority = stringValue(conversation.terminal_binding_id) === targetBefore.binding_id &&
275
+ Number(conversation.terminal_binding_generation) === targetBefore.generation &&
276
+ stringValue(takeover.terminal_binding_id) === targetBefore.binding_id &&
277
+ Number(takeover.terminal_binding_generation) === targetBefore.generation &&
278
+ stringValue(submission.binding_id) === targetBefore.binding_id &&
279
+ Number(submission.binding_generation) === targetBefore.generation;
280
+ return bindingAuthority && (context.prebindingTurn || context.acceptedTurn) &&
281
+ stringValue(takeover.terminal_agent_expected_session_id) === undefined &&
282
+ Number(takeover.terminal_agent_pid) === transfer.process_pid &&
283
+ stringValue(takeover.terminal_agent_process_uuid) ===
284
+ transfer.process_uuid &&
285
+ stringValue(takeover.terminal_agent_process_birth) ===
286
+ transfer.process_birth;
287
+ }
288
+ function deferredTargetMatches(context) {
289
+ const { target, targetBefore, transfer } = context;
290
+ if (!targetBefore)
291
+ return false;
292
+ return Boolean(target.session_id === transfer.target_session_id &&
293
+ (context.precommitTargetAuthority || context.committedTargetAuthority) &&
294
+ target.lineage.transition_id === transfer.transfer_id &&
295
+ target.lineage.previous_session_id === transfer.source_session_id &&
296
+ target.binding &&
297
+ target.binding.binding_id === targetBefore.binding_id &&
298
+ target.binding.generation === targetBefore.generation &&
299
+ target.binding.terminal_id === targetBefore.terminal_id &&
300
+ terminalControlsShareIncarnation(target.binding.terminal_control, targetBefore.terminal_control) &&
301
+ target.binding.native_process.pid === transfer.process_pid &&
302
+ target.binding.native_process.process_uuid === transfer.process_uuid &&
303
+ target.binding.native_process.process_birth === transfer.process_birth);
304
+ }
305
+ function exactDeferredAcceptanceAnchor(anchor, transfer) {
306
+ if (!anchor || anchor.process_uuid !== transfer.process_uuid ||
307
+ anchor.process_birth !== transfer.process_birth) {
308
+ return false;
309
+ }
310
+ if (anchor.version === 2) {
311
+ return anchor.mode === "pre_materialization" &&
312
+ anchor.native_thread_binding === "post_submission" &&
313
+ anchor.file_existed === false && anchor.offset_bytes === 0 &&
314
+ anchor.expected_empty_native_session === true;
315
+ }
316
+ return anchor.version === 3 && anchor.mode === "candidate_set" &&
317
+ anchor.inventory_pid === transfer.process_pid &&
318
+ path.resolve(anchor.inventory_cwd ?? "") === path.resolve(transfer.workspace) &&
319
+ anchor.candidate_rollouts.length > 0;
320
+ }
321
+ export function assertDeferredForegroundLedgerAuthority(ports, { storeDir, terminal, transfer, ledger, statePath, expectedMessageBodyHash }) {
322
+ const targetBefore = transfer.target_before_binding;
323
+ const ledgerMessageBodyHash = stringValue(ledger.message_body_hash);
324
+ const exactCommittedAcceptance = exactCommittedLedgerAcceptance(transfer, ledger);
325
+ const exactPostDispatchPending = exactPostDispatchPendingLedger(transfer, ledger);
326
+ const matches = targetBefore && ledgerIdentityMatches({
327
+ ports,
328
+ storeDir,
329
+ terminal,
330
+ transfer,
331
+ ledger,
332
+ statePath,
333
+ expectedMessageBodyHash,
334
+ ledgerMessageBodyHash,
335
+ targetBefore,
336
+ exactCommittedAcceptance,
337
+ exactPostDispatchPending
338
+ });
339
+ if (!matches) {
340
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} dispatch ledger ` +
341
+ "does not match its exact Turn authority");
342
+ }
343
+ }
344
+ function exactCommittedLedgerAcceptance(transfer, ledger) {
345
+ if (!["committed", "resolved"].includes(transfer.status) ||
346
+ ledger.status !== "agent_accepted" ||
347
+ stringValue(ledger.native_thread_id) !== transfer.target_native_thread_id ||
348
+ ledger.dispatcher_pid !== null ||
349
+ stringValue(ledger.agent_accepted_at) !== transfer.agent_accepted_at ||
350
+ !transfer.target_native_thread_id) {
351
+ return false;
352
+ }
353
+ try {
354
+ validateTerminalSubmissionAcceptanceEvidence(ledger.acceptance_evidence, {
355
+ source: "codex_rollout",
356
+ nativeThreadId: transfer.target_native_thread_id,
357
+ requestHash: transfer.request_hash
358
+ });
359
+ return true;
360
+ }
361
+ catch {
362
+ return false;
363
+ }
364
+ }
365
+ function exactPostDispatchPendingLedger(transfer, ledger) {
366
+ return transfer.status === "dispatch_started" &&
367
+ transfer.input_stage === "enter_dispatched" &&
368
+ ledger.status === "enter_dispatched" &&
369
+ ledger.dispatcher_pid === null &&
370
+ stringValue(ledger.prepared_at) === transfer.prepared_at &&
371
+ stringValue(ledger.text_injected_at) === transfer.text_injected_at &&
372
+ stringValue(ledger.enter_dispatched_at) === transfer.enter_dispatched_at &&
373
+ ledger.agent_accepted_at === undefined &&
374
+ ledger.not_accepted_at === undefined &&
375
+ ledger.uncertain_at === undefined &&
376
+ ledger.acceptance_evidence === undefined &&
377
+ ledger.safe_to_retry !== true;
378
+ }
379
+ function ledgerIdentityMatches(context) {
380
+ return ledgerOwnerFieldsMatch(context) && ledgerRouteMatches(context) &&
381
+ ledgerDispatchFenceMatches(context);
382
+ }
383
+ function ledgerOwnerFieldsMatch(context) {
384
+ const { ports, terminal, transfer, ledger, ledgerMessageBodyHash } = context;
385
+ return !terminalDispatchLedgerLooksLifecycle(ledger) &&
386
+ ports.ledger.matchesControl(ledger, terminal.terminalControl) &&
387
+ stringValue(ledger.deferred_foreground_transfer_id) ===
388
+ transfer.transfer_id &&
389
+ stringValue(ledger.generation_id) === transfer.message_id &&
390
+ stringValue(ledger.conversation_id) === transfer.turn_id &&
391
+ stringValue(ledger.session_id) === transfer.target_session_id &&
392
+ stringValue(ledger.turn_id) === transfer.turn_id &&
393
+ stringValue(ledger.message_id) === transfer.message_id &&
394
+ stringValue(ledger.message_type) === "task" &&
395
+ stringValue(ledger.executor_kind) === "codex" &&
396
+ Boolean(ledgerMessageBodyHash) &&
397
+ /^[0-9a-f]{64}$/u.test(ledgerMessageBodyHash) &&
398
+ (context.expectedMessageBodyHash === undefined ||
399
+ ledgerMessageBodyHash === context.expectedMessageBodyHash) &&
400
+ stringValue(ledger.request_hash) === transfer.request_hash;
401
+ }
402
+ function ledgerRouteMatches(context) {
403
+ const { storeDir, transfer, ledger, statePath, targetBefore } = context;
404
+ const nativeThreadId = stringValue(ledger.native_thread_id);
405
+ const nativeAuthority = context.exactCommittedAcceptance
406
+ ? nativeThreadId === transfer.target_native_thread_id
407
+ : nativeThreadId === undefined;
408
+ return stringValue(ledger.binding_id) === targetBefore.binding_id &&
409
+ Number(ledger.binding_generation) === targetBefore.generation &&
410
+ nativeAuthority &&
411
+ path.resolve(required(ledger.state_path, "dispatch state path is missing")) ===
412
+ statePath &&
413
+ path.resolve(required(ledger.store_dir, "dispatch Store is missing")) ===
414
+ path.resolve(storeDir);
415
+ }
416
+ function ledgerDispatchFenceMatches(context) {
417
+ const { transfer, ledger } = context;
418
+ return ledger.status === "resolved" || context.exactCommittedAcceptance ||
419
+ context.exactPostDispatchPending ||
420
+ Number(ledger.dispatcher_pid) === transfer.dispatcher_pid;
421
+ }
422
+ export function assertDeferredForegroundResolvedZeroInputLedger(ports, { storeDir, terminal, transfer, ledger, statePath }) {
423
+ assertDeferredForegroundLedgerAuthority(ports, {
424
+ storeDir,
425
+ terminal,
426
+ transfer,
427
+ ledger,
428
+ statePath
429
+ });
430
+ const abortedAt = stringValue(ledger.aborted_at);
431
+ const resolvedAt = stringValue(ledger.resolved_at);
432
+ if (ledger.status !== "resolved" ||
433
+ ledger.safe_to_retry !== true ||
434
+ !abortedAt ||
435
+ !resolvedAt ||
436
+ !Number.isFinite(Date.parse(abortedAt)) ||
437
+ !Number.isFinite(Date.parse(resolvedAt)) ||
438
+ Date.parse(resolvedAt) < Date.parse(abortedAt) ||
439
+ DEFERRED_INPUT_EVIDENCE_FIELDS.some((field) => ledger[field] !== undefined)) {
440
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} resolved ledger ` +
441
+ "does not prove a zero-input abort");
442
+ }
443
+ // Validate the whole history for malformed/duplicate identities, then
444
+ // require the append-only copy of this exact generation. The top-level
445
+ // resolved record alone is insufficient because it can later be replaced.
446
+ terminalLedgerReceiptHistory(ledger);
447
+ const rawHistory = ledger.terminal_submission_receipts;
448
+ if (!Array.isArray(rawHistory)) {
449
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} resolved ledger ` +
450
+ "has no append-only abort receipt");
451
+ }
452
+ const ownReceipts = rawHistory.filter((receipt) => isRecord(receipt) &&
453
+ stringValue(receipt.message_id) === transfer.message_id);
454
+ if (ownReceipts.length !== 1) {
455
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} resolved ledger ` +
456
+ "does not have one exact append-only abort receipt");
457
+ }
458
+ const ownReceipt = ownReceipts[0];
459
+ assertDeferredForegroundLedgerAuthority(ports, {
460
+ storeDir,
461
+ terminal,
462
+ transfer,
463
+ // A receipt uses `aborted`, while the same exact owner fields at the
464
+ // top-level use `resolved`. Validate its authority in that same domain.
465
+ ledger: { ...ownReceipt, status: "resolved" },
466
+ statePath
467
+ });
468
+ if (ownReceipt.status !== "aborted" ||
469
+ ownReceipt.safe_to_retry !== true ||
470
+ stringValue(ownReceipt.aborted_at) !== abortedAt ||
471
+ stringValue(ownReceipt.resolved_at) !== resolvedAt ||
472
+ DEFERRED_INPUT_EVIDENCE_FIELDS.some((field) => ownReceipt[field] !== undefined)) {
473
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} append-only ` +
474
+ "receipt does not prove a zero-input abort");
475
+ }
476
+ }
477
+ export function deferredCodexDurableInputNotStartedAt(_ports, scope, transfer) {
478
+ if (transfer.status !== "dispatch_started" ||
479
+ transfer.input_stage !== "dispatch_started" ||
480
+ !transfer.state_path) {
481
+ return undefined;
482
+ }
483
+ assertActiveTurnRoute(scope, transfer);
484
+ const conversation = loadState(path.resolve(transfer.state_path));
485
+ const submission = terminalBridgeSubmission(conversation);
486
+ const abortedAt = stringValue(submission?.aborted_at);
487
+ if (submission?.status !== "aborted" ||
488
+ submission.safe_to_retry !== true ||
489
+ !abortedAt ||
490
+ !Number.isFinite(Date.parse(abortedAt)) ||
491
+ stringValue(submission.text_injected_at) !== undefined ||
492
+ stringValue(submission.enter_dispatched_at) !== undefined ||
493
+ stringValue(submission.agent_accepted_at) !== undefined) {
494
+ return undefined;
495
+ }
496
+ return abortedAt;
497
+ }
498
+ export function abortPreparedDeferredForegroundTurn(ports, input) {
499
+ const { options, scope, storeDir, terminal, transfer, boundary, terminalInputNotStartedAt } = input;
500
+ assertActiveTurnRoute(scope, transfer);
501
+ const dispatchIntentWasProvedNotStarted = assertAbortInputProof(transfer, terminalInputNotStartedAt);
502
+ const observedLedger = ports.ledger.load(terminal.terminalControl);
503
+ const previousDispatchStillCurrent = ports.ledger.previousSnapshotMatches({
504
+ transfer,
505
+ terminalControl: terminal.terminalControl,
506
+ ledger: observedLedger
507
+ });
508
+ const ledger = deferredTransferLedger(transfer, observedLedger, previousDispatchStillCurrent);
509
+ if (abortBeforeTurnPreparation(ports, input, ledger))
510
+ return;
511
+ const statePath = canonicalDeferredTurnStatePath(storeDir, transfer);
512
+ if (abortMissingDeferredTurn(ports, input, {
513
+ ledger,
514
+ statePath,
515
+ dispatchIntentWasProvedNotStarted
516
+ }))
517
+ return;
518
+ persistDeferredTurnAbortReceipts(ports, input, {
519
+ ledger,
520
+ dispatchIntentWasProvedNotStarted
521
+ });
522
+ if (cliEnv().AKK_TEST_EXIT_AFTER_DEFERRED_PREINPUT_ABORT_RECEIPTS === "1") {
523
+ // Both exact zero-input receipts are durable. A second writer may finish
524
+ // only the Store rollback and must never replay terminal input.
525
+ cliExit(86);
526
+ }
527
+ ports.application.abortBeforeInput({
528
+ options,
529
+ scope,
530
+ boundary,
531
+ reason: "recovered exact prepared Turn with zero terminal input",
532
+ terminalInputNotStartedAt
533
+ });
534
+ }
535
+ function assertAbortInputProof(transfer, terminalInputNotStartedAt) {
536
+ const dispatchIntentWasProvedNotStarted = transfer.status === "dispatch_started" &&
537
+ transfer.input_stage === "dispatch_started" &&
538
+ terminalInputNotStartedAt !== undefined &&
539
+ Number.isFinite(Date.parse(terminalInputNotStartedAt));
540
+ if (terminalInputNotStartedAt !== undefined &&
541
+ !dispatchIntentWasProvedNotStarted) {
542
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} cannot attach ` +
543
+ "terminal-input-not-started proof to its current stage");
544
+ }
545
+ return dispatchIntentWasProvedNotStarted;
546
+ }
547
+ function deferredTransferLedger(transfer, observedLedger, previousDispatchStillCurrent) {
548
+ // Before this transfer publishes its own ordinary dispatch ledger, the
549
+ // terminal may still carry the exact resolved history that was snapshot into
550
+ // the immutable transfer receipt. Treat only that exact fingerprint (or the
551
+ // exact persisted `none`) as no new dispatch; every other change must prove
552
+ // this transfer's own ledger below or fail closed.
553
+ if (!previousDispatchStillCurrent && !observedLedger) {
554
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} previous dispatch ` +
555
+ "snapshot disappeared before its own ledger was published");
556
+ }
557
+ return previousDispatchStillCurrent
558
+ ? undefined
559
+ : observedLedger;
560
+ }
561
+ function abortBeforeTurnPreparation(ports, input, ledger) {
562
+ const { options, scope, transfer, boundary } = input;
563
+ if (!transfer.state_path) {
564
+ if (ledger) {
565
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has a dispatch ` +
566
+ "before its Turn authority was prepared");
567
+ }
568
+ ports.application.abortBeforeInput({
569
+ options,
570
+ scope,
571
+ boundary,
572
+ reason: "recovered before target Turn preparation"
573
+ });
574
+ return true;
575
+ }
576
+ return false;
577
+ }
578
+ function abortMissingDeferredTurn(ports, input, facts) {
579
+ const { options, scope, storeDir, terminal, transfer, boundary } = input;
580
+ const { ledger, statePath, dispatchIntentWasProvedNotStarted } = facts;
581
+ if (!fs.existsSync(statePath)) {
582
+ if (dispatchIntentWasProvedNotStarted) {
583
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} lost its Turn ` +
584
+ "before terminal-input-not-started proof became durable");
585
+ }
586
+ if (ledger) {
587
+ // runTerminalControlSend publishes the exact prepared terminal ledger
588
+ // before its Turn state. A crash in that narrow window still proves
589
+ // zero input, provided every immutable ledger field matches this
590
+ // transfer. Resolve that owner before aborting/restoring the Sessions.
591
+ assertDeferredForegroundLedgerAuthority(ports, {
592
+ storeDir,
593
+ terminal,
594
+ transfer,
595
+ ledger,
596
+ statePath
597
+ });
598
+ if (!["prepared", "resolved"].includes(String(ledger.status))) {
599
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has ` +
600
+ `${String(ledger.status)} transport evidence but no exact Turn state`);
601
+ }
602
+ if (ledger.status === "prepared") {
603
+ const abortedAt = cliNow().toISOString();
604
+ ports.ledger.save(terminal.terminalControl, {
605
+ ...ledger,
606
+ status: "resolved",
607
+ aborted_at: abortedAt,
608
+ safe_to_retry: true,
609
+ resolved_at: abortedAt,
610
+ dispatcher_pid: null,
611
+ reason: "deferred dispatcher exited after ledger prepare and before Turn persistence"
612
+ });
613
+ }
614
+ else {
615
+ assertDeferredForegroundResolvedZeroInputLedger(ports, {
616
+ storeDir,
617
+ terminal,
618
+ transfer,
619
+ ledger,
620
+ statePath
621
+ });
622
+ }
623
+ if (cliEnv().AKK_TEST_EXIT_AFTER_DEFERRED_LEDGER_ABORT_WITHOUT_STATE === "1") {
624
+ // The zero-input top-level and append-only ledger receipts are both
625
+ // durable, while the transfer still fences both Sessions. A second
626
+ // writer must accept this exact resolved form and finish Store-only
627
+ // rollback without creating or replaying a Turn.
628
+ cliExit(86);
629
+ }
630
+ }
631
+ ports.application.abortBeforeInput({
632
+ options,
633
+ scope,
634
+ boundary,
635
+ reason: ledger
636
+ ? "recovered exact prepared ledger before target Turn state became durable"
637
+ : "recovered before target Turn state became durable"
638
+ });
639
+ return true;
640
+ }
641
+ return false;
642
+ }
643
+ function persistDeferredTurnAbortReceipts(ports, input, facts) {
644
+ const { storeDir, terminal, transfer, terminalInputNotStartedAt } = input;
645
+ const authority = loadDeferredForegroundTurnAuthority(ports, {
646
+ storeDir,
647
+ terminal,
648
+ transfer,
649
+ scope: input.scope
650
+ });
651
+ const submissionStatus = String(authority.submission.status);
652
+ assertAbortLedger(ports, input, authority, facts.ledger, submissionStatus);
653
+ const durableNotStartedAt = reconcileTurnAbortProof(transfer, authority.submission, submissionStatus, terminalInputNotStartedAt, facts.dispatchIntentWasProvedNotStarted);
654
+ persistTurnAbort(ports, transfer, authority, submissionStatus, durableNotStartedAt);
655
+ assertResolvedAbortLedgerProof(transfer, facts.ledger, durableNotStartedAt, facts.dispatchIntentWasProvedNotStarted);
656
+ persistAbortLedger(ports, terminal, facts.ledger, durableNotStartedAt);
657
+ }
658
+ function assertAbortLedger(ports, input, authority, ledger, submissionStatus) {
659
+ const { storeDir, terminal, transfer } = input;
660
+ if (!ledger && submissionStatus !== "aborted") {
661
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has prepared Turn ` +
662
+ "state without its exact terminal ledger");
663
+ }
664
+ if (!ledger)
665
+ return;
666
+ assertDeferredForegroundLedgerAuthority(ports, {
667
+ storeDir,
668
+ terminal,
669
+ transfer,
670
+ ledger,
671
+ statePath: authority.statePath,
672
+ expectedMessageBodyHash: stringValue(authority.submission.message_body_hash)
673
+ });
674
+ if (!["prepared", "resolved"].includes(String(ledger.status))) {
675
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has ` +
676
+ `${String(ledger.status)} transport evidence and cannot be aborted`);
677
+ }
678
+ }
679
+ function reconcileTurnAbortProof(transfer, submission, submissionStatus, terminalInputNotStartedAt, dispatchIntentWasProvedNotStarted) {
680
+ if (!dispatchIntentWasProvedNotStarted || submissionStatus !== "aborted") {
681
+ return terminalInputNotStartedAt;
682
+ }
683
+ const existingAbortedAt = stringValue(submission.aborted_at);
684
+ if (submission.safe_to_retry !== true || !existingAbortedAt ||
685
+ !Number.isFinite(Date.parse(existingAbortedAt)) ||
686
+ stringValue(submission.text_injected_at) !== undefined ||
687
+ stringValue(submission.enter_dispatched_at) !== undefined ||
688
+ stringValue(submission.agent_accepted_at) !== undefined ||
689
+ (terminalInputNotStartedAt !== undefined &&
690
+ terminalInputNotStartedAt !== existingAbortedAt)) {
691
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has ` +
692
+ "inconsistent terminal-input-not-started Turn proof");
693
+ }
694
+ return existingAbortedAt;
695
+ }
696
+ function persistTurnAbort(ports, transfer, authority, submissionStatus, durableNotStartedAt) {
697
+ if (submissionStatus !== "prepared") {
698
+ if (submissionStatus === "aborted")
699
+ return;
700
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} Turn has ` +
701
+ `${submissionStatus} input evidence and cannot be aborted`);
702
+ }
703
+ const abortedAt = durableNotStartedAt ?? cliNow().toISOString();
704
+ const aborted = ports.turn.withSubmission({
705
+ conversation: {
706
+ ...authority.conversation,
707
+ status: "failed",
708
+ failed_at: abortedAt,
709
+ failure_reason: "dispatcher exited before the deferred terminal-input boundary",
710
+ updated_at: abortedAt
711
+ },
712
+ messageId: transfer.message_id,
713
+ messageType: "task",
714
+ requestText: String(authority.takeover.terminal_bridge_request_text ?? ""),
715
+ status: "aborted",
716
+ preparedAt: stringValue(authority.submission.prepared_at) ?? abortedAt,
717
+ abortedAt,
718
+ error: "dispatcher exited before terminal input",
719
+ safeToRetry: true
720
+ });
721
+ saveState(authority.statePath, aborted);
722
+ }
723
+ function assertResolvedAbortLedgerProof(transfer, ledger, durableNotStartedAt, dispatchIntentWasProvedNotStarted) {
724
+ if (!dispatchIntentWasProvedNotStarted || ledger?.status !== "resolved") {
725
+ return;
726
+ }
727
+ if (ledger.safe_to_retry !== true ||
728
+ stringValue(ledger.aborted_at) !== durableNotStartedAt ||
729
+ stringValue(ledger.text_injected_at) !== undefined ||
730
+ stringValue(ledger.enter_dispatched_at) !== undefined ||
731
+ stringValue(ledger.agent_accepted_at) !== undefined) {
732
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has ` +
733
+ "inconsistent terminal-input-not-started ledger proof");
734
+ }
735
+ }
736
+ function persistAbortLedger(ports, terminal, ledger, durableNotStartedAt) {
737
+ if (!ledger || ledger.status === "resolved")
738
+ return;
739
+ const abortedAt = durableNotStartedAt ?? cliNow().toISOString();
740
+ ports.ledger.save(terminal.terminalControl, {
741
+ ...ledger,
742
+ status: "resolved",
743
+ aborted_at: abortedAt,
744
+ safe_to_retry: true,
745
+ resolved_at: abortedAt,
746
+ dispatcher_pid: null,
747
+ reason: "deferred dispatcher exited before the durable terminal-input boundary"
748
+ });
749
+ }
750
+ export async function recoverAcceptedDeferredForegroundDispatch(ports, input) {
751
+ const { options, scope, storeDir, terminal, transfer, boundary } = input;
752
+ assertActiveTurnRoute(scope, transfer);
753
+ path.resolve(required(transfer.state_path, "deferred foreground Turn state path is unavailable"));
754
+ const authority = loadDeferredForegroundTurnAuthority(ports, {
755
+ storeDir,
756
+ terminal,
757
+ transfer,
758
+ scope
759
+ });
760
+ const ledger = required(ports.ledger.load(terminal.terminalControl), `deferred foreground transfer ${transfer.transfer_id} has no exact ` +
761
+ "terminal dispatch ledger for acceptance recovery");
762
+ assertAcceptanceRecoveryAuthority(ports, input, authority, ledger);
763
+ const recovered = await observeRecoveredAcceptance(ports, input, authority.anchor);
764
+ if (!recovered)
765
+ return false;
766
+ validateAcceptedLedger(ledger, transfer, recovered.identity);
767
+ const acceptedAt = cliNow().toISOString();
768
+ const acceptedConversation = acceptedDeferredConversation(ports, authority, transfer, recovered, acceptedAt);
769
+ let acceptedStatePersisted = false;
770
+ // Turn acceptance is stronger than every Session/ledger write that follows.
771
+ saveState(authority.statePath, acceptedConversation);
772
+ acceptedStatePersisted = true;
773
+ if (cliEnv().AKK_TEST_EXIT_AFTER_DEFERRED_ACCEPTED_TURN === "1")
774
+ cliExit(86);
775
+ return commitRecoveredAcceptance(ports, input, {
776
+ authority,
777
+ ledger,
778
+ recovered,
779
+ acceptedAt,
780
+ acceptedConversation,
781
+ acceptedStatePersisted
782
+ });
783
+ }
784
+ function assertAcceptanceRecoveryAuthority(ports, input, authority, ledger) {
785
+ const { storeDir, terminal, transfer } = input;
786
+ assertDeferredForegroundLedgerAuthority(ports, {
787
+ storeDir,
788
+ terminal,
789
+ transfer,
790
+ ledger,
791
+ statePath: authority.statePath,
792
+ expectedMessageBodyHash: stringValue(authority.submission.message_body_hash)
793
+ });
794
+ ports.authority.assertFrozen({
795
+ storeDir,
796
+ transfer,
797
+ terminalControl: terminal.terminalControl
798
+ });
799
+ if (!DEFERRED_ACCEPTANCE_RECOVERY_STATUSES.has(String(ledger.status))) {
800
+ throw new Error(`deferred foreground transfer ${transfer.transfer_id} has invalid ` +
801
+ `${String(ledger.status)} dispatch evidence for acceptance recovery`);
802
+ }
803
+ }
804
+ async function observeRecoveredAcceptance(ports, input, anchor) {
805
+ const { options, terminal, transfer } = input;
806
+ if (anchor.version === 3) {
807
+ const inventory = await ports.native.inventory({
808
+ options,
809
+ pid: transfer.process_pid,
810
+ cwd: terminal.terminalControl.currentPath
811
+ });
812
+ const result = detectCodexCandidateSetRolloutAcceptance({
813
+ anchor,
814
+ currentInventory: inventory,
815
+ requestHash: transfer.request_hash
816
+ });
817
+ if (result.status === "uncertain") {
818
+ throw new Error(`Codex candidate-set recovery is uncertain (${result.code}): ` +
819
+ result.reason);
820
+ }
821
+ return result.status === "accepted"
822
+ ? { identity: result.identity, evidence: result.evidence }
823
+ : undefined;
824
+ }
825
+ const identity = await ports.native.identity({
826
+ options,
827
+ agent: "codex",
828
+ pid: transfer.process_pid,
829
+ cwd: terminal.terminalControl.currentPath
830
+ });
831
+ if (!identity)
832
+ return undefined;
833
+ const evidence = detectCodexRolloutAcceptance({
834
+ anchor,
835
+ currentIdentity: identity,
836
+ requestHash: transfer.request_hash
837
+ });
838
+ return evidence ? { identity, evidence } : undefined;
839
+ }
840
+ function validateAcceptedLedger(ledger, transfer, identity) {
841
+ if (ledger.status !== "agent_accepted")
842
+ return;
843
+ validateTerminalSubmissionAcceptanceEvidence(ledger.acceptance_evidence, {
844
+ source: "codex_rollout",
845
+ nativeThreadId: identity.sessionId,
846
+ requestHash: transfer.request_hash
847
+ });
848
+ }
849
+ function acceptedDeferredConversation(ports, authority, transfer, recovered, acceptedAt) {
850
+ return ports.turn.withSubmission({
851
+ conversation: ports.turn.withIdentity(authority.conversation, recovered.identity),
852
+ messageId: transfer.message_id,
853
+ messageType: "task",
854
+ requestText: String(authority.takeover.terminal_bridge_request_text ?? ""),
855
+ status: "agent_accepted",
856
+ preparedAt: stringValue(authority.submission.prepared_at) ??
857
+ transfer.prepared_at,
858
+ textInjectedAt: stringValue(authority.submission.text_injected_at) ??
859
+ transfer.text_injected_at ?? transfer.dispatch_started_at,
860
+ enterDispatchedAt: stringValue(authority.submission.enter_dispatched_at) ??
861
+ transfer.enter_dispatched_at ?? transfer.dispatch_started_at,
862
+ agentAcceptedAt: acceptedAt,
863
+ acceptanceEvidence: recovered.evidence
864
+ });
865
+ }
866
+ async function commitRecoveredAcceptance(ports, input, facts) {
867
+ let transferCommitted = false;
868
+ try {
869
+ await ports.application.commit({
870
+ options: input.options,
871
+ scope: input.scope,
872
+ boundary: input.boundary,
873
+ identity: facts.recovered.identity,
874
+ acceptedAt: facts.acceptedAt
875
+ });
876
+ transferCommitted = true;
877
+ ports.authority.assertTurnIdentity({
878
+ conversation: facts.acceptedConversation,
879
+ currentIdentity: facts.recovered.identity,
880
+ operation: "recover deferred foreground binding for"
881
+ });
882
+ saveRecoveredAcceptanceLedger(ports, input, facts);
883
+ return true;
884
+ }
885
+ catch (error) {
886
+ recordRecoveredAcceptanceFailure(ports, input, facts, transferCommitted, error);
887
+ throw error;
888
+ }
889
+ }
890
+ function saveRecoveredAcceptanceLedger(ports, input, facts) {
891
+ const { terminal, transfer } = input;
892
+ ports.ledger.save(terminal.terminalControl, {
893
+ ...facts.ledger,
894
+ ...ports.ledger.bindingFields(facts.acceptedConversation),
895
+ status: "agent_accepted",
896
+ generation_id: transfer.message_id,
897
+ conversation_id: facts.acceptedConversation.conversation_id,
898
+ session_id: transfer.target_session_id,
899
+ turn_id: transfer.turn_id,
900
+ message_id: transfer.message_id,
901
+ message_type: "task",
902
+ request_hash: transfer.request_hash,
903
+ prepared_at: transfer.prepared_at,
904
+ text_injected_at: transfer.text_injected_at ?? transfer.dispatch_started_at,
905
+ enter_dispatched_at: transfer.enter_dispatched_at ?? transfer.dispatch_started_at,
906
+ agent_accepted_at: facts.acceptedAt,
907
+ acceptance_evidence: facts.recovered.evidence,
908
+ dispatcher_pid: null,
909
+ state_path: facts.authority.statePath,
910
+ event_log_path: facts.authority.logPath,
911
+ callback_expected: Boolean(facts.acceptedConversation.gateway_method),
912
+ reason: "recovered exact deferred foreground request acceptance"
913
+ });
914
+ }
915
+ function recordRecoveredAcceptanceFailure(ports, input, facts, transferCommitted, error) {
916
+ if (transferCommitted && !facts.acceptedStatePersisted) {
917
+ saveMissingAcceptedStateFailure(ports, input, facts, error);
918
+ }
919
+ else if (transferCommitted) {
920
+ saveAcceptedBookkeepingFailure(ports, input, facts, error);
921
+ }
922
+ }
923
+ function saveMissingAcceptedStateFailure(ports, input, facts, error) {
924
+ const uncertainAt = cliNow().toISOString();
925
+ const reason = "deferred Session transfer resolved but exact Turn identity " +
926
+ `bookkeeping failed: ${error instanceof Error ? error.message : String(error)}`;
927
+ const uncertainConversation = ports.turn.withSubmission({
928
+ conversation: {
929
+ ...facts.authority.conversation,
930
+ status: "stalled",
931
+ stalled_at: uncertainAt,
932
+ stalled_reason: reason,
933
+ updated_at: uncertainAt
934
+ },
935
+ messageId: input.transfer.message_id,
936
+ messageType: "task",
937
+ requestText: String(facts.authority.takeover.terminal_bridge_request_text ?? ""),
938
+ status: "uncertain",
939
+ preparedAt: stringValue(facts.authority.submission.prepared_at) ??
940
+ input.transfer.prepared_at,
941
+ textInjectedAt: stringValue(facts.authority.submission.text_injected_at) ??
942
+ input.transfer.text_injected_at ?? input.transfer.dispatch_started_at,
943
+ enterDispatchedAt: stringValue(facts.authority.submission.enter_dispatched_at) ??
944
+ input.transfer.enter_dispatched_at ?? input.transfer.dispatch_started_at,
945
+ uncertainAt,
946
+ error: reason,
947
+ lastProvenStage: "enter_dispatched",
948
+ safeToRetry: false
949
+ });
950
+ saveState(facts.authority.statePath, uncertainConversation);
951
+ ports.ledger.save(input.terminal.terminalControl, {
952
+ ...facts.ledger,
953
+ ...ports.ledger.bindingFields(uncertainConversation),
954
+ status: "uncertain",
955
+ uncertain_at: uncertainAt,
956
+ dispatcher_pid: null,
957
+ callback_expected: false,
958
+ reason
959
+ });
960
+ }
961
+ function saveAcceptedBookkeepingFailure(ports, input, facts, error) {
962
+ const stalledAt = cliNow().toISOString();
963
+ const reason = "deferred transfer resolved, but exact accepted Turn bookkeeping " +
964
+ `failed: ${error instanceof Error ? error.message : String(error)}`;
965
+ saveState(facts.authority.statePath, {
966
+ ...facts.acceptedConversation,
967
+ status: "stalled",
968
+ stalled_at: stalledAt,
969
+ stalled_reason: reason,
970
+ updated_at: stalledAt
971
+ });
972
+ try {
973
+ ports.ledger.save(input.terminal.terminalControl, {
974
+ ...facts.ledger,
975
+ ...ports.ledger.bindingFields(facts.acceptedConversation),
976
+ status: "uncertain",
977
+ uncertain_at: stalledAt,
978
+ last_proven_stage: "agent_accepted",
979
+ acceptance_evidence: facts.recovered.evidence,
980
+ dispatcher_pid: null,
981
+ callback_expected: false,
982
+ reason
983
+ });
984
+ }
985
+ catch {
986
+ // The exact accepted Turn remains authoritative if ledger bookkeeping fails.
987
+ }
988
+ runtimeLog("error", "deferred_acceptance_ledger_bookkeeping_failed", {
989
+ transfer_id: input.transfer.transfer_id,
990
+ turn_id: input.transfer.turn_id,
991
+ state_path: facts.authority.statePath,
992
+ error: error instanceof Error ? error.message : String(error)
993
+ });
994
+ }
995
+ export async function persistCommittedDeferredForegroundTurnAcceptance(ports, input) {
996
+ const { options, scope, storeDir, terminal, transfer } = input;
997
+ const current = scope.loadTransfer(transfer.transfer_id);
998
+ assertActiveTurnRoute(scope, current);
999
+ const identity = committedDeferredIdentity(current, transfer.transfer_id);
1000
+ path.resolve(required(current.state_path, "deferred foreground Turn state path is unavailable"));
1001
+ const authority = loadDeferredForegroundTurnAuthority(ports, {
1002
+ storeDir,
1003
+ terminal,
1004
+ transfer: current,
1005
+ scope
1006
+ });
1007
+ const ledger = required(ports.ledger.load(terminal.terminalControl), `deferred foreground transfer ${current.transfer_id} has no exact ` +
1008
+ "terminal dispatch ledger for committed recovery");
1009
+ assertCommittedRecoveryLedger(ports, input, current, authority, ledger);
1010
+ const acceptance = await observeCommittedAcceptance(ports, { ...input, transfer: current }, authority.anchor, identity);
1011
+ validateAcceptedLedger(ledger, current, identity);
1012
+ const acceptedConversation = acceptedDeferredConversation(ports, authority, current, { identity, evidence: acceptance }, current.agent_accepted_at);
1013
+ saveState(authority.statePath, acceptedConversation);
1014
+ saveCommittedAcceptanceLedger(ports, {
1015
+ terminal,
1016
+ transfer: current,
1017
+ authority,
1018
+ ledger,
1019
+ acceptance,
1020
+ acceptedConversation
1021
+ });
1022
+ return { conversation: acceptedConversation, identity };
1023
+ }
1024
+ function committedDeferredIdentity(transfer, expectedTransferId) {
1025
+ const binding = transfer.target_accepted_binding;
1026
+ if (transfer.status !== "committed" || !binding ||
1027
+ !transfer.target_native_thread_id || !transfer.agent_accepted_at) {
1028
+ throw new Error(`deferred foreground transfer ${expectedTransferId} has no exact ` +
1029
+ "committed acceptance authority");
1030
+ }
1031
+ const rollout = binding.native_process.rollout;
1032
+ const processUuid = binding.native_process.process_uuid;
1033
+ const processBirth = binding.native_process.process_birth;
1034
+ if (binding.native_thread_id !== transfer.target_native_thread_id ||
1035
+ processUuid !== transfer.process_uuid ||
1036
+ processBirth !== transfer.process_birth ||
1037
+ !isCompleteNativeRollout(rollout)) {
1038
+ throw new Error(`deferred foreground transfer ${expectedTransferId} committed binding ` +
1039
+ "is incomplete");
1040
+ }
1041
+ return {
1042
+ sessionId: transfer.target_native_thread_id,
1043
+ processUuid,
1044
+ processBirth,
1045
+ rollout,
1046
+ evidence: binding.native_process.evidence
1047
+ };
1048
+ }
1049
+ function assertCommittedRecoveryLedger(ports, input, current, authority, ledger) {
1050
+ assertDeferredForegroundLedgerAuthority(ports, {
1051
+ storeDir: input.storeDir,
1052
+ terminal: input.terminal,
1053
+ transfer: current,
1054
+ ledger,
1055
+ statePath: authority.statePath,
1056
+ expectedMessageBodyHash: stringValue(authority.submission.message_body_hash)
1057
+ });
1058
+ if (!DEFERRED_ACCEPTANCE_RECOVERY_STATUSES.has(String(ledger.status))) {
1059
+ throw new Error(`deferred foreground transfer ${current.transfer_id} has invalid ` +
1060
+ `${String(ledger.status)} dispatch evidence for committed recovery`);
1061
+ }
1062
+ }
1063
+ async function observeCommittedAcceptance(ports, input, anchor, identity) {
1064
+ let acceptance;
1065
+ if (anchor.version === 3) {
1066
+ const inventory = await ports.native.inventory({
1067
+ options: input.options,
1068
+ pid: input.transfer.process_pid,
1069
+ cwd: input.terminal.terminalControl.currentPath
1070
+ });
1071
+ const result = detectCodexCandidateSetRolloutAcceptance({
1072
+ anchor,
1073
+ currentInventory: inventory,
1074
+ requestHash: input.transfer.request_hash
1075
+ });
1076
+ if (result.status === "uncertain") {
1077
+ throw new Error(`Codex committed candidate acceptance is uncertain (${result.code}): ` +
1078
+ result.reason);
1079
+ }
1080
+ if (result.status === "accepted") {
1081
+ if (result.identity.sessionId !== identity.sessionId) {
1082
+ throw new Error("committed candidate acceptance resolved to a different native thread");
1083
+ }
1084
+ acceptance = result.evidence;
1085
+ }
1086
+ }
1087
+ else {
1088
+ acceptance = detectCodexRolloutAcceptance({
1089
+ anchor,
1090
+ currentIdentity: identity,
1091
+ requestHash: input.transfer.request_hash
1092
+ });
1093
+ }
1094
+ if (!acceptance) {
1095
+ throw new Error(`deferred foreground transfer ${input.transfer.transfer_id} cannot re-prove ` +
1096
+ "its exact request acceptance");
1097
+ }
1098
+ return acceptance;
1099
+ }
1100
+ function saveCommittedAcceptanceLedger(ports, facts) {
1101
+ const { terminal, transfer, authority, ledger, acceptance, acceptedConversation } = facts;
1102
+ ports.ledger.save(terminal.terminalControl, {
1103
+ ...ledger,
1104
+ ...ports.ledger.bindingFields(acceptedConversation),
1105
+ status: "agent_accepted",
1106
+ generation_id: transfer.message_id,
1107
+ conversation_id: acceptedConversation.conversation_id,
1108
+ session_id: transfer.target_session_id,
1109
+ turn_id: transfer.turn_id,
1110
+ message_id: transfer.message_id,
1111
+ message_type: "task",
1112
+ request_hash: transfer.request_hash,
1113
+ prepared_at: transfer.prepared_at,
1114
+ text_injected_at: transfer.text_injected_at ?? transfer.dispatch_started_at,
1115
+ enter_dispatched_at: transfer.enter_dispatched_at ?? transfer.dispatch_started_at,
1116
+ agent_accepted_at: transfer.agent_accepted_at,
1117
+ acceptance_evidence: acceptance,
1118
+ dispatcher_pid: null,
1119
+ state_path: authority.statePath,
1120
+ event_log_path: authority.logPath,
1121
+ callback_expected: Boolean(acceptedConversation.gateway_method),
1122
+ reason: "recovered committed deferred foreground request acceptance"
1123
+ });
1124
+ }
1125
+ //# sourceMappingURL=deferred-foreground-recovery-cli-adapter.js.map