@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,1059 @@
1
+ // Raw CLI composition for renew, cancel, and close maintenance commands.
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import path from "node:path";
4
+ import { withCanonicalMutationLocks } from "./mutation-transaction.js";
5
+ import { budgetAction, executorForConversation, sessionIdForConversation, isSessionSendBlockingStatus, turnIdForConversation } from "./protocol.js";
6
+ import { appendEvent, loadState, logPathForStatePath, pathsForConversationDir, saveState, withStoreWriterLeaseAsync } from "./store.js";
7
+ import { loadManagedSession, tryLoadManagedSession } from "./session-store.js";
8
+ import { TerminalControlUnavailableError } from "./terminal-control-provider.js";
9
+ import { terminalControlsShareIncarnation } from "./terminal-authority-policy.js";
10
+ import { terminalControlEvidenceMatches } from "./terminal-control-ref.js";
11
+ import { terminalControlFromTakeover } from "./terminal-runtime-cli-adapter.js";
12
+ import { terminalBridgeSubmission } from "./terminal-dispatch-receipt.js";
13
+ import { terminalDispatchLedgerLooksLifecycle } from "./terminal-dispatch-ledger-codec.js";
14
+ import { loadDeferredForegroundTransfer } from "./deferred-foreground-transfer.js";
15
+ import { isFinalDeferredForegroundTransferStatus } from "./deferred-foreground-transfer-policy.js";
16
+ import { isRecoverableTerminalDispatchStatus } from "./terminal-dispatch-policy.js";
17
+ import { decideVerifiedDeadAgentProcess } from "./verified-dead-agent-policy.js";
18
+ import { terminalMonitorDeadlineAt as deadlineAt } from "./terminal-monitor-decision-policy.js";
19
+ import { writeCliJson as printJson } from "./cli-command-runtime.js";
20
+ import { cliCwd, cliEnv, cliExit, cliNow, cliNowMs, cliRuntimeLog as runtimeLog } from "./cli-runtime-context.js";
21
+ import { isRecord, nonBlankString as stringValue } from "./value-guards.js";
22
+ const terminalMaintenanceContext = new AsyncLocalStorage();
23
+ function terminalMaintenanceRuntime() {
24
+ const runtime = terminalMaintenanceContext.getStore();
25
+ if (!runtime) {
26
+ throw new Error("Terminal maintenance facade runtime is unavailable");
27
+ }
28
+ return runtime;
29
+ }
30
+ function contextualPort(group, name) {
31
+ return ((...arguments_) => {
32
+ const operation = terminalMaintenanceRuntime().dependencies[group][name];
33
+ return operation(...arguments_);
34
+ });
35
+ }
36
+ function required(value, message) {
37
+ if (value === undefined || value === "")
38
+ throw new Error(message);
39
+ return value;
40
+ }
41
+ const loadConversationFromOptions = contextualPort("runtime", "loadConversation");
42
+ const storeDirFromOptions = contextualPort("runtime", "storeDir");
43
+ const createTerminalControlProvider = contextualPort("runtime", "createControlProvider");
44
+ const createTerminalAgentBridge = contextualPort("runtime", "createBridge");
45
+ const startTerminalBridgeMonitorForConversation = contextualPort("runtime", "startMonitor");
46
+ const positiveMinutes = contextualPort("runtime", "positiveMinutes");
47
+ const textSummary = contextualPort("runtime", "textSummary");
48
+ const resolveTerminalConversationFromOptions = contextualPort("identity", "resolveTerminalConversationFromOptions");
49
+ const migrateLegacyTerminalAgentIdentity = contextualPort("identity", "migrateLegacyTerminalAgentIdentity");
50
+ const terminalRuntimeIdentityForConversation = contextualPort("identity", "terminalRuntimeIdentityForConversation");
51
+ const codexAllowedCompanionSetForManagedSession = contextualPort("identity", "codexAllowedCompanionSetForManagedSession");
52
+ const managedBindingConflictKindForResolvedTerminal = contextualPort("identity", "managedBindingConflictKindForResolvedTerminal");
53
+ const observeBoundTerminalAgentProcess = contextualPort("identity", "observeBoundTerminalAgentProcess");
54
+ const resolveCurrentNativeAgentSessionIdentity = contextualPort("identity", "resolveNativeIdentity");
55
+ const observeCurrentNativeAgentSessionIdentity = contextualPort("identity", "observeNativeIdentity");
56
+ const assertConversationHasNoNonterminalDeferredForegroundTransfer = contextualPort("authority", "assertConversationHasNoNonterminalDeferredForegroundTransfer");
57
+ const assertTerminalHasNoNonterminalDeferredForegroundTransfer = contextualPort("authority", "assertTerminalHasNoNonterminalDeferredForegroundTransfer");
58
+ const observedExternalHandoffIdentity = contextualPort("authority", "observedExternalHandoffIdentity");
59
+ const observedHandoffAuthorityToken = contextualPort("authority", "observedHandoffAuthorityToken");
60
+ const observedHandoffTargetResolution = contextualPort("authority", "observedHandoffTargetResolution");
61
+ const activeTurnHandoffDecisionToken = contextualPort("authority", "activeTurnHandoffDecisionToken");
62
+ const assertTurnBindingCurrent = contextualPort("authority", "assertTurnBindingCurrent");
63
+ const assertManagedTerminalDispatchOwner = contextualPort("authority", "assertManagedTerminalDispatchOwner");
64
+ const loadTerminalDispatchLedgerOwner = contextualPort("authority", "loadTerminalDispatchLedgerOwner");
65
+ const terminalListCliFacade = Object.freeze({
66
+ managedSessionHasUnresolvedNativeTransition: contextualPort("authority", "hasUnresolvedNativeTransition")
67
+ });
68
+ const nativeThreadLifecycleFacade = Object.freeze({
69
+ assertExclusive: contextualPort("authority", "assertExclusive")
70
+ });
71
+ const acquireFileLock = contextualPort("repository", "acquireFileLock");
72
+ const acquireTerminalBridgeSendLock = contextualPort("repository", "acquireTerminalLock");
73
+ const withStoreWriterLease = contextualPort("repository", "withStoreWriterLease");
74
+ const resolveTerminalBridgeDispatchLedger = contextualPort("repository", "resolveDispatch");
75
+ const terminalWriterMutationLocks = contextualPort("repository", "terminalWriterLocks");
76
+ const terminalWriterStateMutationLocks = contextualPort("repository", "terminalWriterStateLocks");
77
+ const mutationConversationStore = Object.freeze({
78
+ load: contextualPort("repository", "conversationLoad"),
79
+ save: contextualPort("repository", "conversationSave"),
80
+ appendEvent: contextualPort("repository", "conversationAppendEvent")
81
+ });
82
+ const mutationManagedSessions = Object.freeze({
83
+ load: contextualPort("repository", "sessionLoad")
84
+ });
85
+ const mutationDispatchLedger = Object.freeze({
86
+ load: contextualPort("repository", "ledgerLoad"),
87
+ save: contextualPort("repository", "ledgerSave"),
88
+ resolve: contextualPort("repository", "ledgerResolve"),
89
+ reconcileIncarnation: contextualPort("repository", "ledgerReconcileIncarnation"),
90
+ reconcile: contextualPort("repository", "ledgerReconcile")
91
+ });
92
+ const isVerifiedDeadTerminalAgentProcess = contextualPort("repository", "isVerifiedDead");
93
+ const exactVerifiedDeadTerminalAgentProcessAuthority = contextualPort("repository", "exactVerifiedDeadAuthority");
94
+ const ensureVerifiedDeadTerminalAgentProcessEvent = contextualPort("repository", "ensureVerifiedDeadEvent");
95
+ const ensureVerifiedDeadConversationClosedEvent = contextualPort("repository", "ensureVerifiedDeadClosedEvent");
96
+ const assertVerifiedDeadTerminalBridgeDispatchAuthority = contextualPort("repository", "assertVerifiedDeadDispatch");
97
+ const resolveVerifiedDeadTerminalBridgeDispatchLedger = contextualPort("repository", "resolveVerifiedDeadDispatch");
98
+ async function runRenew(options) {
99
+ const loaded = loadConversationFromOptions(options);
100
+ const { statePath, logPath } = loaded;
101
+ const conversation = await migrateLegacyTerminalAgentIdentity({
102
+ ...loaded,
103
+ options
104
+ });
105
+ if (conversation.status === "closed") {
106
+ throw new Error(`cannot renew ${conversation.conversation_id}; conversation is closed`);
107
+ }
108
+ if (conversation.status !== "stalled") {
109
+ throw new Error(`cannot renew ${conversation.conversation_id}; conversation is ${conversation.status}, not stalled`);
110
+ }
111
+ if (isVerifiedDeadTerminalAgentProcess(conversation)) {
112
+ throw new Error(`cannot renew ${conversation.conversation_id}; its bound terminal agent ` +
113
+ "process is verified dead. Close this orphaned Turn instead.");
114
+ }
115
+ if (terminalBridgeSubmission(conversation)?.status === "uncertain") {
116
+ throw new Error(`cannot renew ${conversation.conversation_id}; its terminal submission ` +
117
+ "is uncertain and cannot be attributed by monitoring. Inspect the pane " +
118
+ "and explicitly close the Turn to abandon the unresolved result.");
119
+ }
120
+ const nativeTakeover = isRecord(conversation.native_session_takeover)
121
+ ? conversation.native_session_takeover
122
+ : undefined;
123
+ const terminalControl = terminalControlFromTakeover(nativeTakeover);
124
+ if (!terminalControl || nativeTakeover?.["terminal_bridge"] !== true) {
125
+ throw new Error(`cannot renew ${conversation.conversation_id}; conversation is not a terminal bridge task`);
126
+ }
127
+ const terminalProvider = createTerminalControlProvider(options);
128
+ try {
129
+ await terminalProvider.resolve(terminalProvider.endpoint(terminalControl));
130
+ }
131
+ catch {
132
+ throw new Error(`cannot renew ${conversation.conversation_id}; terminal ${terminalControl.target} is no longer available`);
133
+ }
134
+ const expectedMessageId = stringValue(nativeTakeover?.terminal_bridge_message_id);
135
+ const expectedStartedAt = stringValue(nativeTakeover?.terminal_bridge_started_at);
136
+ let renewed = conversation;
137
+ let renewedTerminalControl = terminalControl;
138
+ let inactivityTimeoutMinutes = 0;
139
+ let hardTimeoutMinutes = 0;
140
+ const releaseStateLock = acquireFileLock(`${statePath}.lock`);
141
+ try {
142
+ const current = loadState(statePath);
143
+ if (current.status !== "stalled") {
144
+ throw new Error(`cannot renew ${current.conversation_id}; conversation is ${current.status}, not stalled`);
145
+ }
146
+ if (isVerifiedDeadTerminalAgentProcess(current)) {
147
+ throw new Error(`cannot renew ${current.conversation_id}; its bound terminal agent ` +
148
+ "process is verified dead");
149
+ }
150
+ if (terminalBridgeSubmission(current)?.status === "uncertain") {
151
+ throw new Error(`cannot renew ${current.conversation_id}; its terminal submission is uncertain`);
152
+ }
153
+ const currentTakeover = isRecord(current.native_session_takeover)
154
+ ? current.native_session_takeover
155
+ : undefined;
156
+ const currentControl = terminalControlFromTakeover(currentTakeover);
157
+ if (!currentControl || currentTakeover?.terminal_bridge !== true) {
158
+ throw new Error(`cannot renew ${current.conversation_id}; conversation is not a terminal bridge task`);
159
+ }
160
+ if (current.conversation_id !== conversation.conversation_id ||
161
+ !terminalControlsShareIncarnation(currentControl, terminalControl) ||
162
+ stringValue(currentTakeover.terminal_bridge_message_id) !== expectedMessageId ||
163
+ stringValue(currentTakeover.terminal_bridge_started_at) !== expectedStartedAt) {
164
+ throw new Error("conversation changed while waiting to renew; refresh status and retry");
165
+ }
166
+ assertTurnBindingCurrent(current, "renew");
167
+ renewedTerminalControl = currentControl;
168
+ inactivityTimeoutMinutes = positiveMinutes(options.minutes ??
169
+ options.agentTimeoutMinutes ??
170
+ currentTakeover.terminal_bridge_inactivity_timeout_minutes ??
171
+ terminalMaintenanceRuntime().dependencies.runtime
172
+ .defaultAgentTimeoutMinutes, "--minutes");
173
+ hardTimeoutMinutes = positiveMinutes(currentTakeover.terminal_bridge_hard_timeout_minutes ??
174
+ terminalMaintenanceRuntime().dependencies.runtime
175
+ .defaultAgentHardTimeoutMinutes, "--agent-hard-timeout-minutes");
176
+ const startedAt = stringValue(currentTakeover.terminal_bridge_started_at);
177
+ const startedAtMs = startedAt ? Date.parse(startedAt) : NaN;
178
+ if (Number.isFinite(startedAtMs) &&
179
+ cliNowMs() - startedAtMs >= hardTimeoutMinutes * 60 * 1000) {
180
+ throw new Error(`cannot renew ${current.conversation_id}; terminal bridge hard lifetime of ${hardTimeoutMinutes} minutes has elapsed`);
181
+ }
182
+ const now = cliNow().toISOString();
183
+ const hardDeadline = deadlineAt(startedAt ?? now, hardTimeoutMinutes) ??
184
+ new Date(cliNowMs() + hardTimeoutMinutes * 60 * 1000).toISOString();
185
+ const inactivityDeadline = deadlineAt(now, inactivityTimeoutMinutes) ??
186
+ new Date(cliNowMs() + inactivityTimeoutMinutes * 60 * 1000).toISOString();
187
+ renewed = {
188
+ ...current,
189
+ status: "waiting_for_agent",
190
+ native_session_takeover: {
191
+ ...currentTakeover,
192
+ terminal_bridge_monitor_lock_version: terminalMaintenanceRuntime().dependencies.runtime.monitorLockVersion,
193
+ terminal_bridge_monitor_started_at: now,
194
+ terminal_bridge_last_activity_at: now,
195
+ terminal_bridge_inactivity_timeout_minutes: inactivityTimeoutMinutes,
196
+ terminal_bridge_hard_timeout_minutes: hardTimeoutMinutes,
197
+ terminal_bridge_inactivity_deadline_at: inactivityDeadline,
198
+ terminal_bridge_hard_deadline_at: hardDeadline,
199
+ terminal_bridge_renewed_at: now
200
+ },
201
+ updated_at: now
202
+ };
203
+ Reflect.deleteProperty(renewed, "stalled_at");
204
+ Reflect.deleteProperty(renewed, "stalled_reason");
205
+ Reflect.deleteProperty(renewed, "stalled_notification_sent_at");
206
+ Reflect.deleteProperty(renewed, "stalled_notification_message_id");
207
+ saveState(statePath, renewed);
208
+ appendEvent(logPath, {
209
+ ts: now,
210
+ conversation_id: current.conversation_id,
211
+ event: "terminal_bridge_renewed",
212
+ previous_status: current.status,
213
+ terminal_control: currentControl,
214
+ agent_timeout_minutes: inactivityTimeoutMinutes,
215
+ agent_hard_timeout_minutes: hardTimeoutMinutes,
216
+ last_activity_at: now
217
+ });
218
+ runtimeLog("info", "terminal_bridge_renewed", {
219
+ conversation_id: current.conversation_id,
220
+ terminal_target: currentControl.target,
221
+ agent_timeout_minutes: inactivityTimeoutMinutes,
222
+ agent_hard_timeout_minutes: hardTimeoutMinutes
223
+ });
224
+ }
225
+ finally {
226
+ releaseStateLock();
227
+ }
228
+ const monitor = startTerminalBridgeMonitorForConversation({
229
+ conversation: renewed,
230
+ statePath,
231
+ logPath,
232
+ options: {
233
+ ...options,
234
+ agentTimeoutMinutes: inactivityTimeoutMinutes,
235
+ agentHardTimeoutMinutes: hardTimeoutMinutes
236
+ }
237
+ });
238
+ if (monitor) {
239
+ appendEvent(logPath, {
240
+ ts: cliNow().toISOString(),
241
+ conversation_id: renewed.conversation_id,
242
+ event: "terminal_bridge_monitor_launch",
243
+ pid: monitor.pid ?? null,
244
+ terminal_control: renewedTerminalControl,
245
+ reason: "renewal",
246
+ agent_timeout_minutes: inactivityTimeoutMinutes,
247
+ agent_hard_timeout_minutes: hardTimeoutMinutes
248
+ });
249
+ }
250
+ printJson({
251
+ conversation: renewed,
252
+ renewed: true,
253
+ terminal_control: renewedTerminalControl,
254
+ agent_timeout_minutes: inactivityTimeoutMinutes,
255
+ agent_hard_timeout_minutes: hardTimeoutMinutes,
256
+ monitor_pid: monitor?.pid ?? null
257
+ });
258
+ }
259
+ async function runCancel(options) {
260
+ const terminalConversation = await resolveTerminalConversationFromOptions(options);
261
+ if (terminalConversation) {
262
+ await runTerminalConversationCancel({
263
+ options,
264
+ conversationId: terminalConversation.conversationId,
265
+ agent: terminalConversation.agent,
266
+ terminalControl: terminalConversation.terminalControl,
267
+ pid: terminalConversation.pid
268
+ });
269
+ return;
270
+ }
271
+ const loaded = loadConversationFromOptions(options);
272
+ const { statePath, logPath } = loaded;
273
+ const conversation = await migrateLegacyTerminalAgentIdentity({
274
+ ...loaded,
275
+ options
276
+ });
277
+ if (!["waiting_for_agent", "waiting_for_openclaw"].includes(conversation.status)) {
278
+ throw new Error(`cannot cancel ${conversation.conversation_id}; conversation is ${conversation.status}`);
279
+ }
280
+ const nativeTakeover = isRecord(conversation.native_session_takeover)
281
+ ? conversation.native_session_takeover
282
+ : undefined;
283
+ const terminalControl = terminalControlFromTakeover(nativeTakeover);
284
+ if (terminalControl) {
285
+ await runTerminalControlCancel({
286
+ options,
287
+ statePath,
288
+ logPath,
289
+ agent: executorForConversation(conversation).kind,
290
+ terminalControl
291
+ });
292
+ return;
293
+ }
294
+ throw new Error(`conversation ${conversation.conversation_id} is not attached to a live terminal`);
295
+ }
296
+ async function runTerminalConversationCancel({ options, conversationId, agent, terminalControl, pid }) {
297
+ const storeDir = storeDirFromOptions(options);
298
+ await withCanonicalMutationLocks(terminalWriterMutationLocks(storeDir, terminalControl), async () => {
299
+ assertTerminalHasNoNonterminalDeferredForegroundTransfer({
300
+ storeDir,
301
+ pid,
302
+ terminalControl,
303
+ action: "cancel"
304
+ });
305
+ const cancellation = await createTerminalAgentBridge(options).cancel(agent, terminalControl, {
306
+ runtime: {
307
+ pid,
308
+ cwd: terminalControl.currentPath,
309
+ terminalTarget: terminalControl.target
310
+ },
311
+ scrollbackLines: Number(options.scrollbackLines ?? 120)
312
+ });
313
+ runtimeLog("info", "terminal_cancel_requested", {
314
+ conversation_id: conversationId,
315
+ agent,
316
+ terminal_target: terminalControl.target,
317
+ key: cancellation.key,
318
+ keys: cancellation.keys,
319
+ denied_approval: cancellation.deniedApproval,
320
+ request_id: cancellation.requestId,
321
+ cancel_requested: cancellation.cancelRequested,
322
+ reason: cancellation.reason
323
+ });
324
+ printJson({
325
+ conversation_id: conversationId,
326
+ source: "terminal_control",
327
+ cancel_requested: cancellation.cancelRequested,
328
+ reason: cancellation.reason,
329
+ terminal_control: terminalControl,
330
+ key: cancellation.key,
331
+ keys: cancellation.keys,
332
+ denied_approval: cancellation.deniedApproval,
333
+ request_id: cancellation.requestId
334
+ });
335
+ });
336
+ }
337
+ async function runTerminalControlCancel({ options, statePath, logPath, agent, terminalControl }) {
338
+ const releaseTerminalLock = acquireTerminalBridgeSendLock(storeDirFromOptions(options), terminalControl, { timeoutMs: 30000 });
339
+ let releaseStateLock;
340
+ try {
341
+ releaseStateLock = acquireFileLock(`${statePath}.lock`);
342
+ const writerStoreDir = pathsForConversationDir(path.dirname(statePath)).storeDir;
343
+ return await withStoreWriterLease(writerStoreDir, async () => {
344
+ const currentConversation = loadState(statePath);
345
+ if (!["waiting_for_agent", "waiting_for_openclaw"].includes(currentConversation.status)) {
346
+ throw new Error(`cannot cancel ${currentConversation.conversation_id}; conversation is ${currentConversation.status}`);
347
+ }
348
+ const currentTakeover = isRecord(currentConversation.native_session_takeover)
349
+ ? currentConversation.native_session_takeover
350
+ : undefined;
351
+ const currentControl = terminalControlFromTakeover(currentTakeover);
352
+ if (!currentControl ||
353
+ !terminalControlsShareIncarnation(currentControl, terminalControl)) {
354
+ throw new Error("terminal control changed while waiting to cancel; refresh status and retry");
355
+ }
356
+ assertManagedTerminalDispatchOwner({
357
+ storeDir: writerStoreDir,
358
+ conversation: currentConversation,
359
+ terminalControl: currentControl,
360
+ action: "cancel"
361
+ });
362
+ const cancellation = await createTerminalAgentBridge(options).cancel(agent, currentControl, {
363
+ runtime: terminalRuntimeIdentityForConversation(currentConversation, currentControl),
364
+ scrollbackLines: Number(options.scrollbackLines ?? 120)
365
+ });
366
+ if (!cancellation.cancelRequested) {
367
+ printJson({
368
+ conversation: currentConversation,
369
+ cancel_requested: false,
370
+ reason: cancellation.reason,
371
+ terminal_control: currentControl,
372
+ budget: budgetAction(currentConversation)
373
+ });
374
+ return;
375
+ }
376
+ const now = cliNow().toISOString();
377
+ appendEvent(logPath, {
378
+ ts: now,
379
+ conversation_id: currentConversation.conversation_id,
380
+ event: "terminal_cancel_requested",
381
+ terminal_control: currentControl,
382
+ key: cancellation.key,
383
+ keys: cancellation.keys,
384
+ denied_approval: cancellation.deniedApproval,
385
+ request_id: cancellation.requestId
386
+ });
387
+ runtimeLog("info", "terminal_cancel_requested", {
388
+ conversation_id: currentConversation.conversation_id,
389
+ agent,
390
+ terminal_target: currentControl.target,
391
+ key: cancellation.key,
392
+ keys: cancellation.keys,
393
+ denied_approval: cancellation.deniedApproval,
394
+ request_id: cancellation.requestId
395
+ });
396
+ const nextConversation = {
397
+ ...currentConversation,
398
+ status: "cancelled",
399
+ cancelled_at: now,
400
+ terminal_cancel_requested_at: now,
401
+ updated_at: now
402
+ };
403
+ saveState(statePath, nextConversation);
404
+ printJson({
405
+ conversation: nextConversation,
406
+ cancel_requested: true,
407
+ terminal_control: currentControl,
408
+ key: cancellation.key,
409
+ keys: cancellation.keys,
410
+ denied_approval: cancellation.deniedApproval,
411
+ request_id: cancellation.requestId,
412
+ budget: budgetAction(nextConversation)
413
+ });
414
+ });
415
+ }
416
+ finally {
417
+ try {
418
+ releaseStateLock?.();
419
+ }
420
+ finally {
421
+ releaseTerminalLock();
422
+ }
423
+ }
424
+ }
425
+ async function runObservedHandoffClose({ options, statePath, logPath, initialConversation }) {
426
+ const expectedToken = required(stringValue(options.expectedHandoffToken), "--expected-handoff-token is required");
427
+ if (stringValue(options.expectedMessageId) ||
428
+ stringValue(options.expectedTransitionId)) {
429
+ throw new Error("--expected-handoff-token cannot be combined with dispatch or lifecycle recovery tokens");
430
+ }
431
+ if (stringValue(options.reason) !== "superseded_by_human_context_switch") {
432
+ throw new Error("a handoff close requires reason superseded_by_human_context_switch");
433
+ }
434
+ const storeDir = pathsForConversationDir(path.dirname(statePath)).storeDir;
435
+ const sourceSessionId = sessionIdForConversation(initialConversation);
436
+ const initialSource = loadManagedSession(storeDir, sourceSessionId);
437
+ if (!initialSource.binding || initialSource.status !== "bound") {
438
+ throw new Error("handoff source Session is no longer bound; refresh list");
439
+ }
440
+ const terminal = await createTerminalAgentBridge(options).resolveStoredTerminal(initialSource.agent, initialSource.binding.native_process.pid, initialSource.binding.terminal_control, { pid: initialSource.binding.native_process.pid });
441
+ await withCanonicalMutationLocks(terminalWriterStateMutationLocks(storeDir, terminal.terminalControl, statePath, logPath), async (scopes, resources) => {
442
+ const conversation = mutationConversationStore.load(scopes, resources);
443
+ const turnId = turnIdForConversation(conversation);
444
+ if (conversation.conversation_id !== initialConversation.conversation_id ||
445
+ sessionIdForConversation(conversation) !== sourceSessionId ||
446
+ !isSessionSendBlockingStatus(conversation.status)) {
447
+ throw new Error("active handoff Turn changed after it was listed; refresh AKK list");
448
+ }
449
+ const source = mutationManagedSessions.load(scopes, resources, sourceSessionId);
450
+ if (source.status !== "bound" ||
451
+ !source.binding ||
452
+ terminalListCliFacade.managedSessionHasUnresolvedNativeTransition(storeDir, source)) {
453
+ throw new Error("handoff source Session changed after it was listed; refresh AKK list");
454
+ }
455
+ const companions = codexAllowedCompanionSetForManagedSession({
456
+ storeDir,
457
+ session: source
458
+ });
459
+ const resolved = await resolveCurrentNativeAgentSessionIdentity({
460
+ options,
461
+ agent: terminal.agent,
462
+ pid: terminal.pid,
463
+ cwd: terminal.terminalControl.currentPath,
464
+ preferredSessionId: companions.primary
465
+ ? source.binding.native_thread_id
466
+ : undefined,
467
+ allowedCompanionIdentity: companions.primary,
468
+ allowedAdditionalIdentities: companions.additional
469
+ });
470
+ const observed = await observedExternalHandoffIdentity({
471
+ options,
472
+ terminal,
473
+ sourceSession: source,
474
+ resolvedIdentity: resolved
475
+ });
476
+ if (!observed.identity ||
477
+ managedBindingConflictKindForResolvedTerminal({
478
+ storeDir,
479
+ session: source,
480
+ terminal,
481
+ identity: observed.identity
482
+ }) !== "live_external_thread_change") {
483
+ throw new Error("live native thread no longer matches the listed handoff; refresh AKK list");
484
+ }
485
+ const targetNativeThreadId = observed.identity.sessionId.toLowerCase();
486
+ const target = observedHandoffTargetResolution({
487
+ storeDir,
488
+ agent: terminal.agent,
489
+ workspace: terminal.terminalControl.currentPath ?? cliCwd(),
490
+ nativeThreadId: targetNativeThreadId,
491
+ sourceSessionId
492
+ });
493
+ if (target.status !== "eligible") {
494
+ throw new Error("handoff target Session changed after it was listed; refresh AKK list");
495
+ }
496
+ await nativeThreadLifecycleFacade.assertExclusive({
497
+ options,
498
+ agent: terminal.agent,
499
+ currentPid: terminal.pid,
500
+ nativeThreadId: targetNativeThreadId,
501
+ storeDir,
502
+ terminalControl: terminal.terminalControl,
503
+ excludedManagedSessionId: target.snapshot.state === "detached"
504
+ ? target.snapshot.session_id
505
+ : undefined
506
+ });
507
+ const handoffToken = observedHandoffAuthorityToken({
508
+ terminal,
509
+ identity: observed.identity,
510
+ sourceSession: source,
511
+ target: target.snapshot
512
+ });
513
+ const takeover = isRecord(conversation.native_session_takeover)
514
+ ? conversation.native_session_takeover
515
+ : undefined;
516
+ const expectedMessageId = stringValue(takeover?.terminal_bridge_message_id) ?? stringValue(terminalBridgeSubmission(conversation)?.message_id);
517
+ const ledger = mutationDispatchLedger.load(scopes, resources);
518
+ const exactDispatchGeneration = Boolean(expectedMessageId &&
519
+ ledger &&
520
+ !terminalDispatchLedgerLooksLifecycle(ledger) &&
521
+ stringValue(ledger.conversation_id) ===
522
+ conversation.conversation_id &&
523
+ stringValue(ledger.session_id) === sourceSessionId &&
524
+ stringValue(ledger.turn_id) === turnId &&
525
+ stringValue(ledger.message_id) === expectedMessageId);
526
+ const exactNoLedgerGeneration = Boolean(!expectedMessageId &&
527
+ (!ledger || ledger.status === "resolved"));
528
+ if (!exactDispatchGeneration && !exactNoLedgerGeneration) {
529
+ throw new Error("active handoff dispatch generation changed; refresh AKK list");
530
+ }
531
+ const freshToken = activeTurnHandoffDecisionToken({
532
+ handoffToken,
533
+ turn: conversation,
534
+ ledger
535
+ });
536
+ if (freshToken !== expectedToken) {
537
+ throw new Error("active handoff snapshot changed; refresh AKK list before closing");
538
+ }
539
+ const now = cliNow().toISOString();
540
+ const closed = {
541
+ ...conversation,
542
+ status: "closed",
543
+ closed_at: now,
544
+ close_reason: "superseded_by_human_context_switch",
545
+ disposition: "superseded_by_human_context_switch",
546
+ updated_at: now
547
+ };
548
+ mutationConversationStore.save(scopes, resources, closed);
549
+ const dispatchResolved = expectedMessageId
550
+ ? mutationDispatchLedger.resolve(scopes, resources, {
551
+ conversation: closed,
552
+ expectedMessageId,
553
+ reason: "Turn superseded by a verified human context switch"
554
+ })
555
+ : false;
556
+ if (expectedMessageId && !dispatchResolved) {
557
+ throw new Error("active handoff dispatch changed during close; inspect before retrying");
558
+ }
559
+ mutationConversationStore.appendEvent(scopes, resources, {
560
+ ts: now,
561
+ conversation_id: conversation.conversation_id,
562
+ event: "conversation_closed",
563
+ status: "closed",
564
+ reason: "superseded_by_human_context_switch",
565
+ disposition: "superseded_by_human_context_switch",
566
+ handoff_native_thread_id: targetNativeThreadId
567
+ });
568
+ runtimeLog("info", "conversation_closed", {
569
+ conversation_id: conversation.conversation_id,
570
+ status: "closed",
571
+ reason: "superseded_by_human_context_switch",
572
+ disposition: "superseded_by_human_context_switch",
573
+ state_path: statePath,
574
+ event_log_path: logPath
575
+ });
576
+ printJson({
577
+ conversation: closed,
578
+ closed: true,
579
+ terminal_dispatch_resolved: dispatchResolved,
580
+ handoff_disposition: "superseded_by_human_context_switch",
581
+ next_action: "refresh list and use its follow-current send"
582
+ });
583
+ });
584
+ }
585
+ async function runClose(options) {
586
+ const terminalConversation = await resolveTerminalConversationFromOptions(options);
587
+ if (terminalConversation) {
588
+ if (stringValue(options.expectedHandoffToken)) {
589
+ throw new Error("--expected-handoff-token cannot be used with raw terminal close");
590
+ }
591
+ await runTerminalDispatchClose({
592
+ options,
593
+ terminalConversation
594
+ });
595
+ return;
596
+ }
597
+ const loaded = loadConversationFromOptions(options);
598
+ if (stringValue(options.expectedHandoffToken)) {
599
+ await runObservedHandoffClose({
600
+ options,
601
+ statePath: loaded.statePath,
602
+ logPath: loaded.logPath,
603
+ initialConversation: loaded.conversation
604
+ });
605
+ return;
606
+ }
607
+ if (stringValue(options.reason) === "superseded_by_human_context_switch") {
608
+ throw new Error("reason superseded_by_human_context_switch requires the fresh " +
609
+ "expected_handoff_token advertised by AKK list");
610
+ }
611
+ const { statePath, logPath } = loaded;
612
+ const closeStoreDir = pathsForConversationDir(path.dirname(statePath)).storeDir;
613
+ const nativeTakeover = isRecord(loaded.conversation.native_session_takeover)
614
+ ? loaded.conversation.native_session_takeover
615
+ : undefined;
616
+ const terminalControl = terminalControlFromTakeover(nativeTakeover);
617
+ const releaseTerminalLock = terminalControl
618
+ ? acquireTerminalBridgeSendLock(closeStoreDir, terminalControl, { timeoutMs: 30000 })
619
+ : () => { };
620
+ const closeWithFreshState = async () => {
621
+ const releaseStateLock = acquireFileLock(`${statePath}.lock`);
622
+ try {
623
+ const conversation = loadState(statePath);
624
+ let verifiedDeadProcess;
625
+ assertConversationHasNoNonterminalDeferredForegroundTransfer({
626
+ storeDir: closeStoreDir,
627
+ conversation,
628
+ action: "close"
629
+ });
630
+ const currentTakeover = isRecord(conversation.native_session_takeover)
631
+ ? conversation.native_session_takeover
632
+ : undefined;
633
+ const currentTerminalControl = terminalControlFromTakeover(currentTakeover);
634
+ if (terminalControl &&
635
+ !terminalControlsShareIncarnation(currentTerminalControl, terminalControl)) {
636
+ throw new Error("terminal control changed after the close action was listed; refresh AKK list");
637
+ }
638
+ if (conversation.status === "closed" && currentTerminalControl) {
639
+ const recoveredAuthority = exactVerifiedDeadTerminalAgentProcessAuthority({
640
+ conversation,
641
+ storeDir: closeStoreDir,
642
+ terminalControl: currentTerminalControl,
643
+ logPath
644
+ });
645
+ const recoveredDecision = decideVerifiedDeadAgentProcess({
646
+ persistedAuthority: recoveredAuthority
647
+ });
648
+ if (recoveredDecision.status === "invalid") {
649
+ throw new Error(`cannot finish close recovery for ${conversation.conversation_id}; ` +
650
+ recoveredDecision.reason);
651
+ }
652
+ if (recoveredDecision.status === "verified_dead") {
653
+ const audit = ensureVerifiedDeadTerminalAgentProcessEvent({
654
+ logPath,
655
+ proof: recoveredDecision.proof,
656
+ action: "managed_close"
657
+ });
658
+ const expectedMessageId = required(stringValue(currentTakeover?.terminal_bridge_message_id), "verified-dead close recovery has no terminal message id");
659
+ const dispatchLedgerResolved = resolveVerifiedDeadTerminalBridgeDispatchLedger({
660
+ terminalControl: currentTerminalControl,
661
+ conversation,
662
+ storeDir: closeStoreDir,
663
+ statePath,
664
+ logPath,
665
+ expectedMessageId,
666
+ reason: "conversation explicitly closed by request"
667
+ });
668
+ ensureVerifiedDeadConversationClosedEvent({
669
+ logPath,
670
+ conversation,
671
+ evidenceId: audit.evidenceId
672
+ });
673
+ printJson({
674
+ conversation,
675
+ closed: true,
676
+ recovered: true,
677
+ terminal_dispatch_resolved: dispatchLedgerResolved
678
+ });
679
+ return;
680
+ }
681
+ }
682
+ if (terminalControl && currentTerminalControl) {
683
+ verifiedDeadProcess =
684
+ await assertGenericCloseDoesNotBypassObservedHandoff({
685
+ options,
686
+ storeDir: closeStoreDir,
687
+ conversation,
688
+ terminalControl: currentTerminalControl
689
+ });
690
+ }
691
+ const now = cliNow().toISOString();
692
+ const closeReason = stringValue(options.reason) ?? "closed by request";
693
+ const verifiedDeadAudit = verifiedDeadProcess
694
+ ? ensureVerifiedDeadTerminalAgentProcessEvent({
695
+ logPath,
696
+ proof: verifiedDeadProcess,
697
+ action: "managed_close"
698
+ })
699
+ : undefined;
700
+ const verifiedDeadMessageId = verifiedDeadAudit
701
+ ? required(stringValue(currentTakeover?.terminal_bridge_message_id), "verified-dead close has no terminal message id")
702
+ : undefined;
703
+ if (verifiedDeadAudit && currentTerminalControl) {
704
+ assertVerifiedDeadTerminalBridgeDispatchAuthority({
705
+ terminalControl: currentTerminalControl,
706
+ conversation,
707
+ storeDir: closeStoreDir,
708
+ statePath,
709
+ logPath,
710
+ expectedMessageId: verifiedDeadMessageId
711
+ });
712
+ }
713
+ const closed = {
714
+ ...conversation,
715
+ status: "closed",
716
+ closed_at: now,
717
+ close_reason: closeReason,
718
+ ...(verifiedDeadAudit
719
+ ? {
720
+ terminal_agent_process_disposition: {
721
+ status: "verified_dead",
722
+ proof: verifiedDeadAudit.proof,
723
+ evidence_id: verifiedDeadAudit.evidenceId,
724
+ recorded_at: verifiedDeadAudit.recordedAt
725
+ }
726
+ }
727
+ : {}),
728
+ updated_at: now
729
+ };
730
+ saveState(statePath, closed);
731
+ if (verifiedDeadAudit &&
732
+ cliEnv().AKK_TEST_EXIT_AFTER_VERIFIED_DEAD_CLOSE_STATE === "1") {
733
+ cliExit(86);
734
+ }
735
+ let dispatchLedgerResolved = false;
736
+ let dispatchLedgerWarning;
737
+ if (currentTerminalControl) {
738
+ try {
739
+ dispatchLedgerResolved = verifiedDeadAudit
740
+ ? resolveVerifiedDeadTerminalBridgeDispatchLedger({
741
+ terminalControl: currentTerminalControl,
742
+ conversation: closed,
743
+ storeDir: closeStoreDir,
744
+ statePath,
745
+ logPath,
746
+ expectedMessageId: verifiedDeadMessageId,
747
+ reason: "conversation explicitly closed by request"
748
+ })
749
+ : resolveTerminalBridgeDispatchLedger(currentTerminalControl, {
750
+ conversation: closed,
751
+ expectedMessageId: stringValue(currentTakeover?.terminal_bridge_message_id),
752
+ reason: "conversation explicitly closed by request"
753
+ });
754
+ }
755
+ catch (error) {
756
+ dispatchLedgerWarning =
757
+ error instanceof Error ? error.message : String(error);
758
+ runtimeLog("error", "terminal_dispatch_ledger_resolve_failed", {
759
+ conversation_id: closed.conversation_id,
760
+ terminal_target: currentTerminalControl.target,
761
+ error: dispatchLedgerWarning
762
+ });
763
+ }
764
+ }
765
+ if (verifiedDeadAudit) {
766
+ ensureVerifiedDeadConversationClosedEvent({
767
+ logPath,
768
+ conversation: closed,
769
+ evidenceId: verifiedDeadAudit.evidenceId
770
+ });
771
+ }
772
+ else {
773
+ appendEvent(logPath, {
774
+ ts: now,
775
+ conversation_id: conversation.conversation_id,
776
+ event: "conversation_closed",
777
+ status: "closed",
778
+ reason: closed.close_reason
779
+ });
780
+ }
781
+ runtimeLog("info", "conversation_closed", {
782
+ conversation_id: conversation.conversation_id,
783
+ status: "closed",
784
+ reason: closed.close_reason,
785
+ state_path: statePath,
786
+ event_log_path: logPath
787
+ });
788
+ printJson({
789
+ conversation: closed,
790
+ closed: true,
791
+ terminal_dispatch_resolved: dispatchLedgerResolved,
792
+ ...(dispatchLedgerWarning
793
+ ? {
794
+ terminal_dispatch_warning: textSummary(dispatchLedgerWarning),
795
+ do_not_retry: true
796
+ }
797
+ : {})
798
+ });
799
+ }
800
+ finally {
801
+ releaseStateLock();
802
+ }
803
+ };
804
+ try {
805
+ if (terminalControl) {
806
+ await withStoreWriterLeaseAsync(closeStoreDir, closeWithFreshState);
807
+ }
808
+ else {
809
+ await closeWithFreshState();
810
+ }
811
+ }
812
+ finally {
813
+ releaseTerminalLock();
814
+ }
815
+ }
816
+ async function assertGenericCloseDoesNotBypassObservedHandoff({ options, storeDir, conversation, terminalControl }) {
817
+ if (!isSessionSendBlockingStatus(conversation.status)) {
818
+ return;
819
+ }
820
+ const sourceSession = tryLoadManagedSession(storeDir, sessionIdForConversation(conversation));
821
+ if (sourceSession?.status !== "bound" ||
822
+ !sourceSession.binding ||
823
+ !terminalControlsShareIncarnation(sourceSession.binding.terminal_control, terminalControl)) {
824
+ return;
825
+ }
826
+ const storedProof = exactVerifiedDeadTerminalAgentProcessAuthority({
827
+ conversation,
828
+ storeDir,
829
+ terminalControl,
830
+ logPath: stringValue(conversation.event_log_path) ??
831
+ logPathForStatePath(required(stringValue(conversation.state_path), "managed Turn state path is unavailable"))
832
+ });
833
+ const persistedDecision = decideVerifiedDeadAgentProcess({
834
+ persistedAuthority: storedProof
835
+ });
836
+ if (persistedDecision.status === "verified_dead") {
837
+ return persistedDecision.proof;
838
+ }
839
+ if (persistedDecision.status === "invalid") {
840
+ throw new Error(`cannot close ${conversation.conversation_id}; ${persistedDecision.reason}`);
841
+ }
842
+ const takeover = isRecord(conversation.native_session_takeover)
843
+ ? conversation.native_session_takeover
844
+ : undefined;
845
+ const pid = Number(takeover?.terminal_agent_pid);
846
+ if (!Number.isSafeInteger(pid) || pid <= 1) {
847
+ return;
848
+ }
849
+ const bridge = createTerminalAgentBridge(options);
850
+ let terminal;
851
+ try {
852
+ terminal = await bridge.resolveStoredTerminal(sourceSession.agent, pid, terminalControl, { pid });
853
+ }
854
+ catch (error) {
855
+ if (error instanceof TerminalControlUnavailableError) {
856
+ // An unavailable terminal cannot prove a live A -> B handoff. Preserve the
857
+ // explicit Store-only close path used to retire unavailable Turn history.
858
+ return;
859
+ }
860
+ const processObservation = await observeBoundTerminalAgentProcess({
861
+ options,
862
+ conversation,
863
+ terminalControl
864
+ });
865
+ const processDecision = decideVerifiedDeadAgentProcess({
866
+ persistedAuthority: { status: "absent" },
867
+ observation: processObservation
868
+ });
869
+ if (processDecision.status === "verified_dead") {
870
+ return processDecision.proof;
871
+ }
872
+ if (processDecision.status === "unverifiable") {
873
+ throw new Error(`cannot close ${conversation.conversation_id}; the bound agent process ` +
874
+ `death is unverifiable: ${processDecision.reason}`);
875
+ }
876
+ throw error;
877
+ }
878
+ const companions = sourceSession.agent === "codex"
879
+ ? codexAllowedCompanionSetForManagedSession({
880
+ storeDir,
881
+ session: sourceSession
882
+ })
883
+ : { additional: [] };
884
+ const identityObservation = await observeCurrentNativeAgentSessionIdentity({
885
+ options,
886
+ agent: terminal.agent,
887
+ pid: terminal.pid,
888
+ cwd: terminal.terminalControl.currentPath,
889
+ preferredSessionId: companions.primary
890
+ ? sourceSession.binding.native_thread_id
891
+ : undefined,
892
+ allowedCompanionIdentity: companions.primary,
893
+ allowedAdditionalIdentities: companions.additional
894
+ });
895
+ const resolvedIdentity = identityObservation.status === "resolved"
896
+ ? identityObservation.identity
897
+ : undefined;
898
+ const observed = await observedExternalHandoffIdentity({
899
+ options,
900
+ terminal,
901
+ sourceSession,
902
+ resolvedIdentity,
903
+ requireSafeTerminal: false
904
+ });
905
+ if (managedBindingConflictKindForResolvedTerminal({
906
+ storeDir,
907
+ session: sourceSession,
908
+ terminal,
909
+ identity: observed.identity
910
+ }) === "live_external_thread_change") {
911
+ throw new Error(`terminal ${terminalControl.target} changed native thread after the ` +
912
+ "generic close action was listed; refresh AKK list and use only its " +
913
+ "fresh snapshot-bound handoff_decision");
914
+ }
915
+ }
916
+ async function runTerminalDispatchClose({ options, terminalConversation }) {
917
+ const terminalControl = terminalConversation.terminalControl;
918
+ const storeDir = storeDirFromOptions(options);
919
+ return withCanonicalMutationLocks(terminalWriterMutationLocks(storeDir, terminalControl), async (scopes, resources) => {
920
+ let ledger = mutationDispatchLedger.reconcileIncarnation(scopes, resources);
921
+ if (!ledger || ledger.status === "resolved") {
922
+ throw new Error(`terminal ${terminalControl.target} has no unresolved AKK dispatch fence`);
923
+ }
924
+ const deferredTransferId = stringValue(ledger.deferred_foreground_transfer_id);
925
+ if (deferredTransferId) {
926
+ const ledgerStatePath = path.resolve(required(stringValue(ledger.state_path), "deferred terminal dispatch state path is unavailable"));
927
+ const ledgerStoreDir = path.resolve(required(stringValue(ledger.store_dir), "deferred terminal dispatch Store is unavailable"));
928
+ const canonicalLedgerStoreDir = path.resolve(pathsForConversationDir(path.dirname(ledgerStatePath)).storeDir);
929
+ if (ledgerStoreDir !== path.resolve(storeDir) ||
930
+ canonicalLedgerStoreDir !== ledgerStoreDir) {
931
+ throw new Error(`terminal ${terminalControl.target} deferred dispatch belongs to ` +
932
+ "another or noncanonical Store; generic terminal close cannot resolve it");
933
+ }
934
+ const transfer = loadDeferredForegroundTransfer(storeDir, deferredTransferId);
935
+ if (transfer.state_path === undefined ||
936
+ path.resolve(transfer.state_path) !== ledgerStatePath ||
937
+ transfer.terminal_id !== terminalConversation.conversationId ||
938
+ !terminalControlEvidenceMatches(transfer.terminal_endpoint, terminalControl)) {
939
+ throw new Error(`terminal ${terminalControl.target} deferred dispatch authority ` +
940
+ "does not match its exact Store/terminal transfer");
941
+ }
942
+ if (!isFinalDeferredForegroundTransferStatus(transfer.status)) {
943
+ throw new Error(`terminal ${terminalControl.target} dispatch is fenced by deferred ` +
944
+ `foreground transfer ${transfer.transfer_id} (${transfer.status}); ` +
945
+ "generic terminal close cannot resolve it");
946
+ }
947
+ }
948
+ if (!isRecoverableTerminalDispatchStatus(String(ledger.status))) {
949
+ throw new Error(`terminal ${terminalControl.target} has an invalid dispatch status: ` +
950
+ String(ledger.status));
951
+ }
952
+ if (terminalDispatchLedgerLooksLifecycle(ledger)) {
953
+ const expectedTransitionId = required(stringValue(options.expectedTransitionId), "--expected-transition-id is required to recover a lifecycle transition");
954
+ const currentTransitionId = stringValue(ledger.transition_id);
955
+ if (!currentTransitionId ||
956
+ stringValue(ledger.generation_id) !== currentTransitionId ||
957
+ expectedTransitionId !== currentTransitionId) {
958
+ throw new Error("lifecycle transition identity changed; run AKK list again and use " +
959
+ "the current expected-transition-id");
960
+ }
961
+ ledger = await mutationDispatchLedger.reconcile(scopes, resources, options, terminalConversation, ledger, {
962
+ kind: "manual",
963
+ expectedTransitionId
964
+ });
965
+ if (ledger.status !== "resolved") {
966
+ printJson({
967
+ source: "terminal_control",
968
+ conversation_id: terminalConversation.conversationId,
969
+ terminal_control: terminalControl,
970
+ closed: false,
971
+ terminal_dispatch_resolved: false,
972
+ transition_id: expectedTransitionId,
973
+ previous_dispatch_status: ledger.status,
974
+ blocked: true,
975
+ do_not_retry: true,
976
+ reason: stringValue(ledger.reason) ??
977
+ "the live terminal cannot prove the recorded lifecycle outcome",
978
+ recovery_required: {
979
+ action: "inspect the pane and restore an exact recorded before/after native identity, then rerun the list-provided close action",
980
+ expected_transition_id: expectedTransitionId
981
+ },
982
+ coding_agent_stopped: false,
983
+ tmux_pane_closed: false
984
+ });
985
+ return;
986
+ }
987
+ printJson({
988
+ source: "terminal_control",
989
+ conversation_id: terminalConversation.conversationId,
990
+ terminal_control: terminalControl,
991
+ closed: false,
992
+ terminal_dispatch_resolved: true,
993
+ transition_id: expectedTransitionId,
994
+ reason: stringValue(ledger.reason),
995
+ coding_agent_stopped: false,
996
+ tmux_pane_closed: false
997
+ });
998
+ return;
999
+ }
1000
+ const owner = loadTerminalDispatchLedgerOwner(ledger);
1001
+ if (owner) {
1002
+ throw new Error(`terminal ${terminalControl.target} dispatch is owned by AKK ` +
1003
+ `conversation ${owner.conversation_id} (${owner.status}); close that ` +
1004
+ "managed conversation instead");
1005
+ }
1006
+ const expectedMessageId = required(stringValue(options.expectedMessageId), "--expected-message-id is required to resolve an orphaned terminal dispatch");
1007
+ const ownerMessageId = stringValue(ledger.message_id);
1008
+ if (!ownerMessageId || expectedMessageId !== ownerMessageId) {
1009
+ throw new Error("terminal dispatch identity changed; run AKK list again and use the " +
1010
+ "current orphaned dispatch message id");
1011
+ }
1012
+ const resolvedAt = cliNow().toISOString();
1013
+ const reason = stringValue(options.reason) ??
1014
+ "terminal dispatch explicitly resolved after operator inspection";
1015
+ mutationDispatchLedger.save(scopes, resources, {
1016
+ ...ledger,
1017
+ status: "resolved",
1018
+ resolved_at: resolvedAt,
1019
+ reason,
1020
+ resolved_by_terminal_conversation_id: terminalConversation.conversationId
1021
+ });
1022
+ runtimeLog("info", "terminal_dispatch_explicitly_resolved", {
1023
+ terminal_target: terminalControl.target,
1024
+ terminal_conversation_id: terminalConversation.conversationId,
1025
+ owner_conversation_id: stringValue(ledger.conversation_id),
1026
+ owner_message_id: stringValue(ledger.message_id),
1027
+ previous_status: ledger.status,
1028
+ reason
1029
+ });
1030
+ printJson({
1031
+ source: "terminal_control",
1032
+ conversation_id: terminalConversation.conversationId,
1033
+ terminal_control: terminalControl,
1034
+ closed: false,
1035
+ terminal_dispatch_resolved: true,
1036
+ previous_dispatch_status: ledger.status,
1037
+ owner_conversation_id: stringValue(ledger.conversation_id),
1038
+ owner_message_id: stringValue(ledger.message_id),
1039
+ reason,
1040
+ coding_agent_stopped: false,
1041
+ tmux_pane_closed: false
1042
+ });
1043
+ });
1044
+ }
1045
+ const terminalMaintenanceOperations = {
1046
+ runRenew,
1047
+ runCancel,
1048
+ runClose
1049
+ };
1050
+ export function createTerminalMaintenanceCliFacade(dependencies) {
1051
+ const runtime = Object.freeze({ dependencies });
1052
+ const call = (operation) => terminalMaintenanceContext.run(runtime, operation);
1053
+ return Object.freeze({
1054
+ runRenew: (options) => call(() => runRenew(options)),
1055
+ runCancel: (options) => call(() => runCancel(options)),
1056
+ runClose: (options) => call(() => runClose(options))
1057
+ });
1058
+ }
1059
+ //# sourceMappingURL=terminal-maintenance-cli-adapter.js.map