@scotthuang/agent-knock-knock 0.13.2 → 0.13.4

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 (278) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +27 -6
  3. package/dist/src/callback-outbox-policy.js +27 -6
  4. package/dist/src/callback-outbox-policy.js.map +1 -1
  5. package/dist/src/callback-outbox-service.d.ts +4 -30
  6. package/dist/src/callback-outbox-service.js +21 -154
  7. package/dist/src/callback-outbox-service.js.map +1 -1
  8. package/dist/src/callback-outbox-settlement.js +13 -8
  9. package/dist/src/callback-outbox-settlement.js.map +1 -1
  10. package/dist/src/callback-route-service.d.ts +46 -0
  11. package/dist/src/callback-route-service.js +155 -0
  12. package/dist/src/callback-route-service.js.map +1 -0
  13. package/dist/src/claude-terminal-agent-adapter.js +4 -0
  14. package/dist/src/claude-terminal-agent-adapter.js.map +1 -1
  15. package/dist/src/cli-core.js +9 -1
  16. package/dist/src/cli-core.js.map +1 -1
  17. package/dist/src/codex-process-incarnation.d.ts +8 -0
  18. package/dist/src/codex-process-incarnation.js +36 -0
  19. package/dist/src/codex-process-incarnation.js.map +1 -0
  20. package/dist/src/codex-terminal-agent-adapter.js +4 -0
  21. package/dist/src/codex-terminal-agent-adapter.js.map +1 -1
  22. package/dist/src/deferred-foreground-conflict-policy.d.ts +22 -0
  23. package/dist/src/deferred-foreground-conflict-policy.js +52 -0
  24. package/dist/src/deferred-foreground-conflict-policy.js.map +1 -0
  25. package/dist/src/durable-notification-kernel.d.ts +94 -0
  26. package/dist/src/durable-notification-kernel.js +68 -0
  27. package/dist/src/durable-notification-kernel.js.map +1 -0
  28. package/dist/src/herdr-socket-transport.d.ts +43 -0
  29. package/dist/src/herdr-socket-transport.js +170 -0
  30. package/dist/src/herdr-socket-transport.js.map +1 -0
  31. package/dist/src/herdr-terminal-control-provider.d.ts +2 -45
  32. package/dist/src/herdr-terminal-control-provider.js +8 -173
  33. package/dist/src/herdr-terminal-control-provider.js.map +1 -1
  34. package/dist/src/host-adapter-capabilities.d.ts +35 -0
  35. package/dist/src/host-adapter-capabilities.js +146 -0
  36. package/dist/src/host-adapter-capabilities.js.map +1 -0
  37. package/dist/src/host-adapter.d.ts +9 -3
  38. package/dist/src/host-adapter.js +33 -9
  39. package/dist/src/host-adapter.js.map +1 -1
  40. package/dist/src/host-bridge-tools.d.ts +3 -4
  41. package/dist/src/host-bridge-tools.js +49 -92
  42. package/dist/src/host-bridge-tools.js.map +1 -1
  43. package/dist/src/host-bridge.js +5 -5
  44. package/dist/src/host-bridge.js.map +1 -1
  45. package/dist/src/host-monitor-reconciliation.d.ts +6 -0
  46. package/dist/src/host-monitor-reconciliation.js +96 -0
  47. package/dist/src/host-monitor-reconciliation.js.map +1 -0
  48. package/dist/src/managed-session.js +2 -18
  49. package/dist/src/managed-session.js.map +1 -1
  50. package/dist/src/native-thread-lifecycle-cli-adapter.d.ts +13 -0
  51. package/dist/src/native-thread-lifecycle-cli-adapter.js +635 -3
  52. package/dist/src/native-thread-lifecycle-cli-adapter.js.map +1 -1
  53. package/dist/src/openclaw-list-projection.d.ts +2 -0
  54. package/dist/src/openclaw-list-projection.js +3 -0
  55. package/dist/src/openclaw-list-projection.js.map +1 -0
  56. package/dist/src/openclaw-model-facing-field-policy.d.ts +2 -0
  57. package/dist/src/openclaw-model-facing-field-policy.js +3 -0
  58. package/dist/src/openclaw-model-facing-field-policy.js.map +1 -0
  59. package/dist/src/openclaw-plugin-command-adapter.d.ts +6 -29
  60. package/dist/src/openclaw-plugin-command-adapter.js +7 -2370
  61. package/dist/src/openclaw-plugin-command-adapter.js.map +1 -1
  62. package/dist/src/openclaw-plugin-helpers.d.ts +2 -121
  63. package/dist/src/openclaw-plugin-helpers.js +2 -1164
  64. package/dist/src/openclaw-plugin-helpers.js.map +1 -1
  65. package/dist/src/openclaw-plugin-schemas.d.ts +2 -510
  66. package/dist/src/openclaw-plugin-schemas.js +2 -519
  67. package/dist/src/openclaw-plugin-schemas.js.map +1 -1
  68. package/dist/src/openclaw-plugin-supervisor.d.ts +4 -5
  69. package/dist/src/openclaw-plugin-supervisor.js +5 -94
  70. package/dist/src/openclaw-plugin-supervisor.js.map +1 -1
  71. package/dist/src/openclaw-plugin-value-helpers.d.ts +2 -0
  72. package/dist/src/openclaw-plugin-value-helpers.js +3 -0
  73. package/dist/src/openclaw-plugin-value-helpers.js.map +1 -0
  74. package/dist/src/openclaw-private-authority-offers.d.ts +4 -39
  75. package/dist/src/openclaw-private-authority-offers.js +3 -258
  76. package/dist/src/openclaw-private-authority-offers.js.map +1 -1
  77. package/dist/src/semantic-private-authority-offers.d.ts +41 -0
  78. package/dist/src/semantic-private-authority-offers.js +261 -0
  79. package/dist/src/semantic-private-authority-offers.js.map +1 -0
  80. package/dist/src/semantic-tool-arguments.d.ts +9 -0
  81. package/dist/src/semantic-tool-arguments.js +64 -0
  82. package/dist/src/semantic-tool-arguments.js.map +1 -0
  83. package/dist/src/semantic-tool-catalog.d.ts +48 -0
  84. package/dist/src/semantic-tool-catalog.js +105 -0
  85. package/dist/src/semantic-tool-catalog.js.map +1 -0
  86. package/dist/src/semantic-tool-command-helpers.d.ts +145 -0
  87. package/dist/src/semantic-tool-command-helpers.js +1272 -0
  88. package/dist/src/semantic-tool-command-helpers.js.map +1 -0
  89. package/dist/src/semantic-tool-list-projection.d.ts +10 -0
  90. package/dist/src/semantic-tool-list-projection.js +497 -0
  91. package/dist/src/semantic-tool-list-projection.js.map +1 -0
  92. package/dist/src/semantic-tool-model-facing-field-policy.d.ts +3 -0
  93. package/dist/src/semantic-tool-model-facing-field-policy.js +66 -0
  94. package/dist/src/semantic-tool-model-facing-field-policy.js.map +1 -0
  95. package/dist/src/semantic-tool-presentation.d.ts +37 -0
  96. package/dist/src/semantic-tool-presentation.js +680 -0
  97. package/dist/src/semantic-tool-presentation.js.map +1 -0
  98. package/dist/src/semantic-tool-private-authority.d.ts +39 -0
  99. package/dist/src/semantic-tool-private-authority.js +602 -0
  100. package/dist/src/semantic-tool-private-authority.js.map +1 -0
  101. package/dist/src/semantic-tool-relay.d.ts +16 -0
  102. package/dist/src/semantic-tool-relay.js +175 -0
  103. package/dist/src/semantic-tool-relay.js.map +1 -0
  104. package/dist/src/semantic-tool-runtime.d.ts +10 -0
  105. package/dist/src/semantic-tool-runtime.js +1157 -0
  106. package/dist/src/semantic-tool-runtime.js.map +1 -0
  107. package/dist/src/semantic-tool-schemas.d.ts +563 -0
  108. package/dist/src/semantic-tool-schemas.js +573 -0
  109. package/dist/src/semantic-tool-schemas.js.map +1 -0
  110. package/dist/src/semantic-tool-value-helpers.d.ts +5 -0
  111. package/dist/src/semantic-tool-value-helpers.js +27 -0
  112. package/dist/src/semantic-tool-value-helpers.js.map +1 -0
  113. package/dist/src/store-event-presentation.d.ts +17 -0
  114. package/dist/src/store-event-presentation.js +33 -0
  115. package/dist/src/store-event-presentation.js.map +1 -0
  116. package/dist/src/store.d.ts +3 -16
  117. package/dist/src/store.js +2 -30
  118. package/dist/src/store.js.map +1 -1
  119. package/dist/src/terminal-action-projection.d.ts +3 -17
  120. package/dist/src/terminal-action-projection.js +13 -41
  121. package/dist/src/terminal-action-projection.js.map +1 -1
  122. package/dist/src/terminal-agent-adapter.d.ts +7 -0
  123. package/dist/src/terminal-agent-adapter.js +8 -0
  124. package/dist/src/terminal-agent-adapter.js.map +1 -1
  125. package/dist/src/terminal-agent-bridge.d.ts +35 -332
  126. package/dist/src/terminal-agent-bridge.js +293 -2798
  127. package/dist/src/terminal-agent-bridge.js.map +1 -1
  128. package/dist/src/terminal-approval-cli-adapter.d.ts +17 -0
  129. package/dist/src/terminal-approval-cli-adapter.js +921 -0
  130. package/dist/src/terminal-approval-cli-adapter.js.map +1 -0
  131. package/dist/src/terminal-command-cli-adapter.d.ts +2 -429
  132. package/dist/src/terminal-command-cli-adapter.js +344 -6061
  133. package/dist/src/terminal-command-cli-adapter.js.map +1 -1
  134. package/dist/src/terminal-command-cli-ports.d.ts +443 -0
  135. package/dist/src/terminal-command-cli-ports.js +2 -0
  136. package/dist/src/terminal-command-cli-ports.js.map +1 -0
  137. package/dist/src/terminal-command-dispatch-preparation.d.ts +81 -0
  138. package/dist/src/terminal-command-dispatch-preparation.js +209 -0
  139. package/dist/src/terminal-command-dispatch-preparation.js.map +1 -0
  140. package/dist/src/terminal-command-dispatch-transport.d.ts +35 -0
  141. package/dist/src/terminal-command-dispatch-transport.js +859 -0
  142. package/dist/src/terminal-command-dispatch-transport.js.map +1 -0
  143. package/dist/src/terminal-command-foreground-proof.d.ts +32 -0
  144. package/dist/src/terminal-command-foreground-proof.js +72 -0
  145. package/dist/src/terminal-command-foreground-proof.js.map +1 -0
  146. package/dist/src/terminal-command-send-preflight.d.ts +41 -0
  147. package/dist/src/terminal-command-send-preflight.js +86 -0
  148. package/dist/src/terminal-command-send-preflight.js.map +1 -0
  149. package/dist/src/terminal-composer-classifier.d.ts +55 -0
  150. package/dist/src/terminal-composer-classifier.js +638 -0
  151. package/dist/src/terminal-composer-classifier.js.map +1 -0
  152. package/dist/src/terminal-control-ref.d.ts +23 -0
  153. package/dist/src/terminal-control-ref.js +32 -0
  154. package/dist/src/terminal-control-ref.js.map +1 -1
  155. package/dist/src/terminal-dispatch-recovery-authority.d.ts +56 -0
  156. package/dist/src/terminal-dispatch-recovery-authority.js +251 -0
  157. package/dist/src/terminal-dispatch-recovery-authority.js.map +1 -0
  158. package/dist/src/terminal-dispatch-recovery-cli-adapter.d.ts +1 -9
  159. package/dist/src/terminal-dispatch-recovery-cli-adapter.js +5 -240
  160. package/dist/src/terminal-dispatch-recovery-cli-adapter.js.map +1 -1
  161. package/dist/src/terminal-handoff-cli-adapter.d.ts +1 -11
  162. package/dist/src/terminal-handoff-cli-adapter.js +2 -39
  163. package/dist/src/terminal-handoff-cli-adapter.js.map +1 -1
  164. package/dist/src/terminal-human-explicit-send-cli-adapter.d.ts +25 -0
  165. package/dist/src/terminal-human-explicit-send-cli-adapter.js +903 -0
  166. package/dist/src/terminal-human-explicit-send-cli-adapter.js.map +1 -0
  167. package/dist/src/terminal-identity-authority-cli-adapter.d.ts +1 -6
  168. package/dist/src/terminal-identity-authority-cli-adapter.js +3 -33
  169. package/dist/src/terminal-identity-authority-cli-adapter.js.map +1 -1
  170. package/dist/src/terminal-interaction-cli-adapter.js +209 -210
  171. package/dist/src/terminal-interaction-cli-adapter.js.map +1 -1
  172. package/dist/src/terminal-interaction-core.d.ts +0 -2
  173. package/dist/src/terminal-interaction-core.js +4 -3
  174. package/dist/src/terminal-interaction-core.js.map +1 -1
  175. package/dist/src/terminal-interaction-protocol.d.ts +21 -0
  176. package/dist/src/terminal-interaction-protocol.js +74 -0
  177. package/dist/src/terminal-interaction-protocol.js.map +1 -1
  178. package/dist/src/terminal-interaction-response-bridge.d.ts +126 -0
  179. package/dist/src/terminal-interaction-response-bridge.js +579 -0
  180. package/dist/src/terminal-interaction-response-bridge.js.map +1 -0
  181. package/dist/src/terminal-interaction-response-transaction.d.ts +44 -0
  182. package/dist/src/terminal-interaction-response-transaction.js +56 -0
  183. package/dist/src/terminal-interaction-response-transaction.js.map +1 -0
  184. package/dist/src/terminal-list-action-policy.d.ts +43 -0
  185. package/dist/src/terminal-list-action-policy.js +164 -0
  186. package/dist/src/terminal-list-action-policy.js.map +1 -0
  187. package/dist/src/terminal-list-cli-adapter.d.ts +6 -36
  188. package/dist/src/terminal-list-cli-adapter.js +314 -1711
  189. package/dist/src/terminal-list-cli-adapter.js.map +1 -1
  190. package/dist/src/terminal-list-facts.d.ts +129 -0
  191. package/dist/src/terminal-list-facts.js +179 -0
  192. package/dist/src/terminal-list-facts.js.map +1 -0
  193. package/dist/src/terminal-list-inventory.d.ts +59 -0
  194. package/dist/src/terminal-list-inventory.js +194 -0
  195. package/dist/src/terminal-list-inventory.js.map +1 -0
  196. package/dist/src/terminal-list-ownership-service.d.ts +118 -0
  197. package/dist/src/terminal-list-ownership-service.js +1003 -0
  198. package/dist/src/terminal-list-ownership-service.js.map +1 -0
  199. package/dist/src/terminal-list-projection-service.d.ts +49 -0
  200. package/dist/src/terminal-list-projection-service.js +407 -0
  201. package/dist/src/terminal-list-projection-service.js.map +1 -0
  202. package/dist/src/terminal-list-renderer.d.ts +12 -11
  203. package/dist/src/terminal-list-renderer.js +237 -104
  204. package/dist/src/terminal-list-renderer.js.map +1 -1
  205. package/dist/src/terminal-managed-send-cli-adapter.d.ts +33 -0
  206. package/dist/src/terminal-managed-send-cli-adapter.js +994 -0
  207. package/dist/src/terminal-managed-send-cli-adapter.js.map +1 -0
  208. package/dist/src/terminal-managed-turn-list-action-policy.d.ts +47 -0
  209. package/dist/src/terminal-managed-turn-list-action-policy.js +64 -0
  210. package/dist/src/terminal-managed-turn-list-action-policy.js.map +1 -0
  211. package/dist/src/terminal-model-control-action-policy.d.ts +60 -0
  212. package/dist/src/terminal-model-control-action-policy.js +96 -0
  213. package/dist/src/terminal-model-control-action-policy.js.map +1 -0
  214. package/dist/src/terminal-model-control-availability.d.ts +68 -0
  215. package/dist/src/terminal-model-control-availability.js +157 -0
  216. package/dist/src/terminal-model-control-availability.js.map +1 -0
  217. package/dist/src/terminal-model-control-bridge.d.ts +48 -0
  218. package/dist/src/terminal-model-control-bridge.js +259 -0
  219. package/dist/src/terminal-model-control-bridge.js.map +1 -0
  220. package/dist/src/terminal-model-control-profile.d.ts +55 -0
  221. package/dist/src/terminal-model-control-profile.js +137 -0
  222. package/dist/src/terminal-model-control-profile.js.map +1 -0
  223. package/dist/src/terminal-model-control-subject.d.ts +34 -0
  224. package/dist/src/terminal-model-control-subject.js +58 -0
  225. package/dist/src/terminal-model-control-subject.js.map +1 -0
  226. package/dist/src/terminal-model-control-transaction.d.ts +19 -0
  227. package/dist/src/terminal-model-control-transaction.js +39 -0
  228. package/dist/src/terminal-model-control-transaction.js.map +1 -0
  229. package/dist/src/terminal-model-control.d.ts +331 -0
  230. package/dist/src/terminal-model-control.js +1686 -0
  231. package/dist/src/terminal-model-control.js.map +1 -0
  232. package/dist/src/terminal-monitor-application-service.js +50 -17
  233. package/dist/src/terminal-monitor-application-service.js.map +1 -1
  234. package/dist/src/terminal-native-inspection-bridge.d.ts +211 -0
  235. package/dist/src/terminal-native-inspection-bridge.js +1127 -0
  236. package/dist/src/terminal-native-inspection-bridge.js.map +1 -0
  237. package/dist/src/terminal-runtime-cli-adapter.d.ts +2 -0
  238. package/dist/src/terminal-runtime-cli-adapter.js +59 -17
  239. package/dist/src/terminal-runtime-cli-adapter.js.map +1 -1
  240. package/dist/src/terminal-submission-retry-application.d.ts +24 -0
  241. package/dist/src/terminal-submission-retry-application.js +402 -0
  242. package/dist/src/terminal-submission-retry-application.js.map +1 -0
  243. package/dist/src/terminal-submission-retry-ports.d.ts +30 -0
  244. package/dist/src/terminal-submission-retry-ports.js +2 -0
  245. package/dist/src/terminal-submission-retry-ports.js.map +1 -0
  246. package/dist/src/terminal-submission-retry-reconciliation.d.ts +236 -0
  247. package/dist/src/terminal-submission-retry-reconciliation.js +1130 -0
  248. package/dist/src/terminal-submission-retry-reconciliation.js.map +1 -0
  249. package/dist/src/terminal-submission-retry-transport.d.ts +58 -0
  250. package/dist/src/terminal-submission-retry-transport.js +675 -0
  251. package/dist/src/terminal-submission-retry-transport.js.map +1 -0
  252. package/dist/src/terminal-text-submission-bridge.d.ts +200 -0
  253. package/dist/src/terminal-text-submission-bridge.js +632 -0
  254. package/dist/src/terminal-text-submission-bridge.js.map +1 -0
  255. package/dist/src/terminal-user-explicit-send-policy.d.ts +29 -0
  256. package/dist/src/terminal-user-explicit-send-policy.js +46 -0
  257. package/dist/src/terminal-user-explicit-send-policy.js.map +1 -0
  258. package/dist/src/terminal-watch-cli-adapter.js +91 -143
  259. package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
  260. package/dist/src/terminal-watch-codec.d.ts +9 -0
  261. package/dist/src/terminal-watch-codec.js +1051 -0
  262. package/dist/src/terminal-watch-codec.js.map +1 -0
  263. package/dist/src/terminal-watch-interaction-response-store.d.ts +19 -0
  264. package/dist/src/terminal-watch-interaction-response-store.js +87 -0
  265. package/dist/src/terminal-watch-interaction-response-store.js.map +1 -0
  266. package/dist/src/terminal-watch-record.d.ts +319 -0
  267. package/dist/src/terminal-watch-record.js +742 -0
  268. package/dist/src/terminal-watch-record.js.map +1 -0
  269. package/dist/src/terminal-watch-service.js +48 -27
  270. package/dist/src/terminal-watch-service.js.map +1 -1
  271. package/dist/src/terminal-watch-store.d.ts +3 -279
  272. package/dist/src/terminal-watch-store.js +5 -1779
  273. package/dist/src/terminal-watch-store.js.map +1 -1
  274. package/docs/quickstart-herdr.md +1 -1
  275. package/docs/quickstart-tmux.md +27 -2
  276. package/openclaw.plugin.json +13 -1
  277. package/package.json +7 -2
  278. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +54 -11
@@ -0,0 +1,903 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { supersedeUnacceptedCallbackDeliveries } from "./callback-outbox-policy.js";
6
+ import { isSessionSendBlockingStatus, sessionIdForConversation, turnIdForConversation } from "./protocol.js";
7
+ import { appendExplicitUserCloseEvent, defaultStoreDir, ensureDir, listConversations, loadState, pathsForConversation, saveExplicitUserCloseState, withStoreWriterLeaseAsync } from "./store.js";
8
+ import { managedSessionRevision, unmanagedTerminalBindingToken } from "./managed-session.js";
9
+ import { listManagedSessions, saveManagedSession } from "./session-store.js";
10
+ import { isExactClaudeNativeInspectionIdleComposer, TerminalInputNotStartedError } from "./terminal-agent-bridge.js";
11
+ import { terminalControlAliasMatches, terminalControlsShareIncarnation } from "./terminal-authority-policy.js";
12
+ import { terminalDispatchLedgerLooksLifecycle } from "./terminal-dispatch-ledger-codec.js";
13
+ import { assertSafeUserExplicitTerminalSend } from "./terminal-command-send-preflight.js";
14
+ import { cleanupDeferredForegroundUserClose } from "./deferred-foreground-user-close.js";
15
+ import { terminalSubmissionPayload } from "./terminal-dispatch-execution.js";
16
+ import { createTerminalUserSendIntentRepository, TerminalUserSendIntentBoundaryConflictError, TerminalUserSendIntentUncertainError } from "./terminal-user-send-intent.js";
17
+ import { terminalUserExplicitFallbackWatchId } from "./terminal-watch-store.js";
18
+ import { terminalSendResultContract } from "./terminal-dispatch-presenter.js";
19
+ import { expandHome } from "./cli-command-runtime.js";
20
+ import { isRecord, nonBlankString as stringValue } from "./value-guards.js";
21
+ const humanExplicitSendContext = new AsyncLocalStorage();
22
+ function humanExplicitSendRuntime() {
23
+ const runtime = humanExplicitSendContext.getStore();
24
+ if (!runtime) {
25
+ throw new Error("Terminal human-explicit Send runtime is unavailable");
26
+ }
27
+ return runtime;
28
+ }
29
+ function rawPort(name) {
30
+ return ((...arguments_) => {
31
+ const operation = humanExplicitSendRuntime().ports[name];
32
+ return operation(...arguments_);
33
+ });
34
+ }
35
+ const acquireFileLock = rawPort("acquireFileLock");
36
+ const acquireTerminalBridgeSendLock = rawPort("acquireTerminalBridgeSendLock");
37
+ const assertExpectedHandoffTokenUsesExactTerminalSelector = rawPort("assertExpectedHandoffTokenUsesExactTerminalSelector");
38
+ const attachUserExplicitFallbackWatch = rawPort("attachUserExplicitFallbackWatch");
39
+ const createTerminalAgentBridge = rawPort("createTerminalAgentBridge");
40
+ const loadTerminalBridgeDispatchLedger = rawPort("loadTerminalBridgeDispatchLedger");
41
+ const loadTerminalDispatchLedgerOwner = rawPort("loadTerminalDispatchLedgerOwner");
42
+ const prepareUserExplicitFallbackWatch = rawPort("prepareUserExplicitFallbackWatch");
43
+ const processIncarnationForPid = rawPort("processIncarnationForPid");
44
+ const required = rawPort("required");
45
+ const resolveTerminalBridgeDispatchLedger = rawPort("resolveTerminalBridgeDispatchLedger");
46
+ const storeDirFromOptions = rawPort("storeDirFromOptions");
47
+ const terminalBridgeRuntimeKey = rawPort("terminalBridgeRuntimeKey");
48
+ const terminalControlFromTakeover = rawPort("terminalControlFromTakeover");
49
+ const terminalDispatchRecordMatchesControl = rawPort("terminalDispatchRecordMatchesControl");
50
+ const terminalRuntimeForLiveIdentity = rawPort("terminalRuntimeForLiveIdentity");
51
+ const textSummary = rawPort("textSummary");
52
+ const userExplicitFallbackWatchReceipt = rawPort("userExplicitFallbackWatchReceipt");
53
+ const cliEnv = () => humanExplicitSendRuntime().runtime.env();
54
+ const cliNow = () => humanExplicitSendRuntime().runtime.now();
55
+ const runtimeLog = (level, event, fields) => humanExplicitSendRuntime().runtime.log(level, event, fields);
56
+ const printJson = (value) => humanExplicitSendRuntime().runtime.printJson(value);
57
+ const durableTerminalInputDispatched = (conversation) => humanExplicitSendRuntime().runtime
58
+ .durableTerminalInputDispatched(conversation);
59
+ const managedSendAttempt = (options, messageBody, terminal, deferZeroInputFailurePresentation, attempt) => humanExplicitSendRuntime().managedSendAttempt(options, messageBody, terminal, deferZeroInputFailurePresentation, attempt);
60
+ function explicitTerminalSendToken(terminal) {
61
+ const processIncarnation = processIncarnationForPid(terminal.pid);
62
+ return unmanagedTerminalBindingToken({
63
+ terminalId: terminal.conversationId,
64
+ terminalControl: terminal.terminalControl,
65
+ agent: terminal.agent,
66
+ pid: terminal.pid,
67
+ workspace: terminal.terminalControl.currentPath ?? "",
68
+ processUuid: processIncarnation.processUuid,
69
+ processBirth: processIncarnation.processBirth
70
+ });
71
+ }
72
+ function explicitSendTurnReference(candidate) {
73
+ try {
74
+ return turnIdForConversation(candidate);
75
+ }
76
+ catch {
77
+ return stringValue(candidate.conversation_id) ?? "unknown";
78
+ }
79
+ }
80
+ function hasFreshExplicitTerminalSendToken(options, terminal) {
81
+ const supplied = stringValue(options.expectedTerminalToken);
82
+ return Boolean(supplied && supplied === explicitTerminalSendToken(terminal));
83
+ }
84
+ function assertFreshUserExplicitTerminalSendToken(options, terminal) {
85
+ const expected = stringValue(options.expectedUserExplicitTerminalToken);
86
+ if (expected && expected !== explicitTerminalSendToken(terminal)) {
87
+ throw new Error("the explicit terminal send token is stale; refresh AKK list");
88
+ }
89
+ }
90
+ async function assertFreshUserExplicitTerminalSendTargetWhileLocked(options, terminal) {
91
+ if (!stringValue(options.expectedUserExplicitTerminalToken))
92
+ return;
93
+ const resolved = await createTerminalAgentBridge(options)
94
+ .resolveConversationId(terminal.conversationId);
95
+ if (!resolved ||
96
+ resolved.agent !== terminal.agent ||
97
+ resolved.pid !== terminal.pid ||
98
+ !terminalControlsShareIncarnation(resolved.terminalControl, terminal.terminalControl)) {
99
+ throw new Error("the explicitly selected terminal is no longer the same live process");
100
+ }
101
+ assertFreshUserExplicitTerminalSendToken(options, resolved);
102
+ }
103
+ function releaseTerminalDispatchForExplicitSend(input) {
104
+ let ledger;
105
+ try {
106
+ ledger = loadTerminalBridgeDispatchLedger(input.terminal.terminalControl);
107
+ }
108
+ catch (error) {
109
+ return {
110
+ checked: false,
111
+ warnings: [
112
+ `terminal dispatch ownership could not be checked before Session ` +
113
+ `release: ${error instanceof Error ? error.message : String(error)}`
114
+ ]
115
+ };
116
+ }
117
+ if (!ledger || ledger.status === "resolved") {
118
+ return { checked: true, warnings: [] };
119
+ }
120
+ if (terminalDispatchLedgerLooksLifecycle(ledger)) {
121
+ return { checked: true, lifecycleLedger: ledger, warnings: [] };
122
+ }
123
+ if (!terminalDispatchRecordMatchesControl(ledger, input.terminal.terminalControl)) {
124
+ return { checked: true, warnings: [] };
125
+ }
126
+ const conversationId = stringValue(ledger.conversation_id);
127
+ const expectedMessageId = stringValue(ledger.message_id);
128
+ if (!conversationId || !expectedMessageId) {
129
+ return {
130
+ checked: true,
131
+ warnings: [
132
+ "orphaned terminal dispatch was kept because its exact conversation " +
133
+ "or message generation could not be verified"
134
+ ]
135
+ };
136
+ }
137
+ if (input.conversations.some((conversation) => conversation.conversation_id === conversationId)) {
138
+ return { checked: true, warnings: [] };
139
+ }
140
+ try {
141
+ if (loadTerminalDispatchLedgerOwner(ledger)) {
142
+ return { checked: true, warnings: [] };
143
+ }
144
+ }
145
+ catch (error) {
146
+ return {
147
+ checked: true,
148
+ warnings: [
149
+ `orphaned terminal dispatch owner could not be checked: ${error instanceof Error ? error.message : String(error)}`
150
+ ]
151
+ };
152
+ }
153
+ try {
154
+ const resolved = resolveTerminalBridgeDispatchLedger(input.terminal.terminalControl, {
155
+ conversation: { conversation_id: conversationId },
156
+ expectedMessageId,
157
+ reason: "orphaned management superseded by explicit user Send"
158
+ });
159
+ return resolved
160
+ ? { checked: true, warnings: [] }
161
+ : {
162
+ checked: true,
163
+ warnings: [
164
+ "orphaned terminal dispatch changed before explicit Send cleanup"
165
+ ]
166
+ };
167
+ }
168
+ catch (error) {
169
+ return {
170
+ checked: true,
171
+ warnings: [
172
+ `orphaned terminal dispatch could not be released: ${error instanceof Error ? error.message : String(error)}`
173
+ ]
174
+ };
175
+ }
176
+ }
177
+ async function bestEffortReleaseTerminalManagementForExplicitSend(input) {
178
+ try {
179
+ return await withStoreWriterLeaseAsync(input.storeDir, async () => releaseTerminalManagementForExplicitSendUnderWriter(input), { timeoutMs: 0 });
180
+ }
181
+ catch (error) {
182
+ return [
183
+ `AKK management writer was unavailable: ${error instanceof Error ? error.message : String(error)}`
184
+ ];
185
+ }
186
+ }
187
+ function releaseTerminalManagementForExplicitSendUnderWriter(input) {
188
+ const warnings = [];
189
+ let conversations;
190
+ try {
191
+ conversations = listConversations(input.storeDir);
192
+ }
193
+ catch (error) {
194
+ return [
195
+ `managed Turn inventory could not be read: ${error instanceof Error ? error.message : String(error)}`
196
+ ];
197
+ }
198
+ for (const candidate of conversations) {
199
+ const reference = explicitSendTurnReference(candidate);
200
+ try {
201
+ if (!isSessionSendBlockingStatus(candidate.status))
202
+ continue;
203
+ const takeover = isRecord(candidate.native_session_takeover)
204
+ ? candidate.native_session_takeover
205
+ : undefined;
206
+ const control = terminalControlFromTakeover(takeover);
207
+ if (!control ||
208
+ !terminalControlsShareIncarnation(control, input.terminal.terminalControl)) {
209
+ continue;
210
+ }
211
+ const paths = pathsForConversation(candidate.conversation_id, input.storeDir);
212
+ const releaseStateLock = acquireFileLock(`${paths.statePath}.lock`, { timeoutMs: 0 });
213
+ try {
214
+ const current = loadState(paths.statePath);
215
+ if (!isSessionSendBlockingStatus(current.status))
216
+ continue;
217
+ const currentTakeover = isRecord(current.native_session_takeover)
218
+ ? current.native_session_takeover
219
+ : undefined;
220
+ const currentControl = terminalControlFromTakeover(currentTakeover);
221
+ if (!currentControl ||
222
+ !terminalControlsShareIncarnation(currentControl, input.terminal.terminalControl)) {
223
+ continue;
224
+ }
225
+ const now = cliNow().toISOString();
226
+ const closed = {
227
+ ...supersedeUnacceptedCallbackDeliveries(current, {
228
+ at: now,
229
+ reason: "superseded_by_user_explicit_send"
230
+ }),
231
+ status: "closed",
232
+ closed_at: now,
233
+ close_reason: "superseded by explicit user Send",
234
+ disposition: "user_abandoned_management",
235
+ callback_expected: false,
236
+ updated_at: now
237
+ };
238
+ delete closed.idle_since;
239
+ saveExplicitUserCloseState(paths.statePath, closed);
240
+ try {
241
+ const transferCleanup = cleanupDeferredForegroundUserClose({
242
+ storeDir: input.storeDir,
243
+ conversation: closed,
244
+ at: now
245
+ });
246
+ warnings.push(...transferCleanup.warnings.map((warning) => `Turn ${explicitSendTurnReference(current)} deferred cleanup: ${warning}`));
247
+ }
248
+ catch (error) {
249
+ warnings.push(`Turn ${explicitSendTurnReference(current)} deferred cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
250
+ }
251
+ try {
252
+ const expectedMessageId = stringValue(currentTakeover?.terminal_bridge_message_id);
253
+ const dispatchResolved = resolveTerminalBridgeDispatchLedger(currentControl, {
254
+ conversation: closed,
255
+ expectedMessageId,
256
+ reason: "management superseded by explicit user Send"
257
+ });
258
+ if (expectedMessageId && !dispatchResolved) {
259
+ warnings.push(`Turn ${explicitSendTurnReference(current)} dispatch cleanup ` +
260
+ "did not match its expected ledger");
261
+ }
262
+ }
263
+ catch (error) {
264
+ warnings.push(`Turn ${explicitSendTurnReference(current)} dispatch cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
265
+ }
266
+ try {
267
+ const terminalInputSent = durableTerminalInputDispatched(current);
268
+ appendExplicitUserCloseEvent(paths.logPath, {
269
+ ts: now,
270
+ conversation_id: current.conversation_id,
271
+ event: "conversation_closed",
272
+ status: "closed",
273
+ reason: closed.close_reason,
274
+ disposition: "user_abandoned_management",
275
+ terminal_input_sent: terminalInputSent,
276
+ terminal_input_dispatched: terminalInputSent,
277
+ coding_agent_stopped: false,
278
+ tmux_pane_closed: false
279
+ });
280
+ }
281
+ catch (error) {
282
+ warnings.push(`Turn ${explicitSendTurnReference(current)} close event failed: ${error instanceof Error ? error.message : String(error)}`);
283
+ }
284
+ }
285
+ finally {
286
+ releaseStateLock();
287
+ }
288
+ }
289
+ catch (error) {
290
+ warnings.push(`Turn ${reference} could not release AKK ` +
291
+ `management: ${error instanceof Error ? error.message : String(error)}`);
292
+ }
293
+ }
294
+ let currentConversations;
295
+ try {
296
+ currentConversations = listConversations(input.storeDir);
297
+ }
298
+ catch (error) {
299
+ warnings.push(`managed Turn inventory could not be rechecked before Session release: ${error instanceof Error ? error.message : String(error)}`);
300
+ return warnings;
301
+ }
302
+ const blockingSessionIds = new Set(currentConversations
303
+ .filter((turn) => isSessionSendBlockingStatus(turn.status))
304
+ .map((turn) => sessionIdForConversation(turn)));
305
+ const dispatchRelease = releaseTerminalDispatchForExplicitSend({
306
+ terminal: input.terminal,
307
+ conversations: currentConversations
308
+ });
309
+ warnings.push(...dispatchRelease.warnings);
310
+ if (!dispatchRelease.checked) {
311
+ return warnings;
312
+ }
313
+ let sessions;
314
+ try {
315
+ sessions = listManagedSessions(input.storeDir);
316
+ }
317
+ catch (error) {
318
+ warnings.push(`managed Session inventory could not be read: ${error instanceof Error ? error.message : String(error)}`);
319
+ return warnings;
320
+ }
321
+ const lifecycleLedger = dispatchRelease.lifecycleLedger;
322
+ for (const session of sessions) {
323
+ try {
324
+ const binding = session.binding;
325
+ if (!["bound", "quarantined", "transitioning"].includes(session.status) ||
326
+ session.agent !== input.terminal.agent ||
327
+ !binding ||
328
+ binding.native_process.pid !== input.terminal.pid ||
329
+ !terminalControlAliasMatches(binding.terminal_id, binding.terminal_control, input.terminal.conversationId, input.terminal.terminalControl) ||
330
+ blockingSessionIds.has(session.session_id)) {
331
+ continue;
332
+ }
333
+ const lifecycleSourceSessionId = stringValue(lifecycleLedger?.source_session_id);
334
+ const lifecycleTargetSessionId = stringValue(lifecycleLedger?.target_session_id);
335
+ const lifecycleTransitionId = stringValue(lifecycleLedger?.transition_id);
336
+ const lifecycleNamesSession = Boolean(lifecycleLedger &&
337
+ (lifecycleSourceSessionId === session.session_id ||
338
+ lifecycleTargetSessionId === session.session_id));
339
+ if (lifecycleNamesSession) {
340
+ const transitionRelationship = session.last_transition_id
341
+ ? lifecycleTransitionId === session.last_transition_id
342
+ ? `transition ${session.last_transition_id}`
343
+ : `a lifecycle transition that drifted from Session marker ` +
344
+ session.last_transition_id
345
+ : `lifecycle transition ${lifecycleTransitionId ?? "with unknown id"}`;
346
+ warnings.push(`Session ${session.session_id} kept AKK management because ` +
347
+ `unresolved ${transitionRelationship} still names it; explicit ` +
348
+ "Send does not prove that transition's native outcome");
349
+ continue;
350
+ }
351
+ const detachedAt = cliNow().toISOString();
352
+ saveManagedSession(input.storeDir, {
353
+ ...session,
354
+ status: "detached",
355
+ detached_at: detachedAt,
356
+ quarantine_reason: undefined,
357
+ updated_at: detachedAt
358
+ }, { expectedRevision: managedSessionRevision(session) });
359
+ }
360
+ catch (error) {
361
+ warnings.push(`Session ${session.session_id} could not release AKK management: ${error instanceof Error ? error.message : String(error)}`);
362
+ }
363
+ }
364
+ return warnings;
365
+ }
366
+ function explicitTerminalSendIntentRuntimeDir() {
367
+ const configured = stringValue(cliEnv().AKK_RUNTIME_DIR);
368
+ return configured
369
+ ? path.resolve(required(expandHome(configured), "AKK runtime directory"))
370
+ : path.join(path.dirname(defaultStoreDir()), "runtime-v2");
371
+ }
372
+ function terminalUserSendIntentContext(options, messageBody, terminal) {
373
+ const messageId = required(stringValue(options.messageId), "explicit terminal Send message id is unavailable");
374
+ const payload = terminalSubmissionPayload(String(messageBody));
375
+ return {
376
+ messageId,
377
+ payload,
378
+ boundary: {
379
+ terminalRuntimeKey: terminalBridgeRuntimeKey(terminal.terminalControl),
380
+ physicalToken: explicitTerminalSendToken(terminal),
381
+ messageId,
382
+ requestHash: createHash("sha256").update(payload).digest("hex")
383
+ },
384
+ repository: createTerminalUserSendIntentRepository({
385
+ runtimeDir: explicitTerminalSendIntentRuntimeDir()
386
+ })
387
+ };
388
+ }
389
+ class TerminalUserSendReplayForbiddenError extends Error {
390
+ constructor(message) {
391
+ super(message);
392
+ this.name = "TerminalUserSendReplayForbiddenError";
393
+ }
394
+ }
395
+ function userExplicitEmergencyTerminalLockPath(terminal) {
396
+ const userScope = createHash("sha256")
397
+ .update(path.dirname(defaultStoreDir()))
398
+ .digest("hex")
399
+ .slice(0, 16);
400
+ const terminalKey = createHash("sha256")
401
+ .update(terminalBridgeRuntimeKey(terminal.terminalControl))
402
+ .digest("hex");
403
+ const directory = path.join(os.tmpdir(), `agent-knock-knock-user-send-${userScope}`);
404
+ ensureDir(directory);
405
+ return path.join(directory, `terminal-${terminalKey}.lock`);
406
+ }
407
+ function acquireUserExplicitTerminalSendLock(options, terminal, warnings) {
408
+ let release;
409
+ try {
410
+ release = acquireTerminalBridgeSendLock(storeDirFromOptions(options), terminal.terminalControl, { timeoutMs: 30_000 });
411
+ }
412
+ catch (error) {
413
+ if (isRecord(error) && error.code === "LOCK_TIMEOUT")
414
+ throw error;
415
+ warnings.push(`primary terminal serialization was unavailable: ${error instanceof Error ? error.message : String(error)}`);
416
+ try {
417
+ release = acquireFileLock(userExplicitEmergencyTerminalLockPath(terminal), { timeoutMs: 30_000 });
418
+ }
419
+ catch (fallbackError) {
420
+ if (isRecord(fallbackError) &&
421
+ fallbackError.code === "LOCK_TIMEOUT") {
422
+ throw fallbackError;
423
+ }
424
+ warnings.push(`emergency terminal serialization was unavailable; proceeding ` +
425
+ `with exact pre-input revalidation: ${fallbackError instanceof Error
426
+ ? fallbackError.message
427
+ : String(fallbackError)}`);
428
+ return () => { };
429
+ }
430
+ }
431
+ return () => {
432
+ try {
433
+ release?.();
434
+ }
435
+ catch (error) {
436
+ const warning = `terminal serialization cleanup failed: ${error instanceof Error ? error.message : String(error)}`;
437
+ warnings.push(warning);
438
+ runtimeLog("warn", "terminal_user_explicit_send_lock_release_failed", {
439
+ terminal_id: terminal.conversationId,
440
+ warning
441
+ });
442
+ }
443
+ };
444
+ }
445
+ function printReplayedUserExplicitSend(options, terminal, intent, deliveryMode) {
446
+ if (deliveryMode === "managed") {
447
+ printJson({
448
+ delivered: true,
449
+ replayed: true,
450
+ status: "submission_pending_acceptance",
451
+ submission_outcome: "pending_acceptance",
452
+ delivery_receipt: "enter_dispatched",
453
+ do_not_retry: true,
454
+ ...terminalSendResultContract({
455
+ terminalInputDispatched: true,
456
+ agentAcceptance: "unproven",
457
+ managementMode: "managed",
458
+ observationMode: "none",
459
+ callbackAvailable: false
460
+ }),
461
+ terminal_id: terminal.conversationId,
462
+ message_id: intent.messageId,
463
+ scope: "terminal_user_explicit"
464
+ });
465
+ return;
466
+ }
467
+ const watchId = terminalUserExplicitFallbackWatchId({
468
+ messageId: intent.messageId,
469
+ physicalToken: intent.boundary.physicalToken,
470
+ requestHash: intent.boundary.requestHash
471
+ });
472
+ const callbackReceipt = userExplicitFallbackWatchReceipt({
473
+ options,
474
+ watchId
475
+ });
476
+ const callbackAvailable = callbackReceipt?.callback_expected === true;
477
+ printJson({
478
+ delivered: true,
479
+ delivered_unmanaged: true,
480
+ delivery_receipt: "enter_dispatched",
481
+ ...(callbackReceipt ?? { callback_expected: false }),
482
+ ...terminalSendResultContract({
483
+ terminalInputDispatched: true,
484
+ agentAcceptance: "unproven",
485
+ managementMode: "unmanaged",
486
+ observationMode: callbackAvailable ? "terminal_watch" : "none",
487
+ callbackAvailable,
488
+ interactionNotificationAvailable: callbackAvailable
489
+ }),
490
+ replayed: true,
491
+ terminal_id: terminal.conversationId,
492
+ message_id: intent.messageId,
493
+ scope: "terminal_user_explicit"
494
+ });
495
+ }
496
+ function reserveUserExplicitSendIntent(options, messageBody, terminal) {
497
+ const intent = terminalUserSendIntentContext(options, messageBody, terminal);
498
+ const routingWarning = stringValue(options.terminalUserSendRoutingWarning);
499
+ const warnings = routingWarning ? [routingWarning] : [];
500
+ let reservation;
501
+ try {
502
+ reservation = intent.repository.reserve(intent.boundary);
503
+ }
504
+ catch (error) {
505
+ if (error instanceof TerminalUserSendIntentBoundaryConflictError ||
506
+ error instanceof TerminalUserSendIntentUncertainError) {
507
+ throw error;
508
+ }
509
+ // Runtime receipts strengthen same-id retry safety; their own damage is
510
+ // never authority to suppress a fresh physical user Send.
511
+ warnings.push(`durable user-Send intent unavailable: ${error instanceof Error ? error.message : String(error)}`);
512
+ return {
513
+ outcome: "proceed",
514
+ lease: { intent, durable: false, warnings }
515
+ };
516
+ }
517
+ // Presentation is outside the durability catch. A completed same-ID intent
518
+ // remains a replay even when stdout fails (for example EPIPE); it must never
519
+ // degrade into a fresh physical Send.
520
+ if (reservation.outcome === "replay") {
521
+ printReplayedUserExplicitSend(options, terminal, intent, required(reservation.intent.delivery_mode, "completed explicit Send delivery mode is unavailable"));
522
+ return { outcome: "replayed" };
523
+ }
524
+ if (reservation.outcome === "uncertain") {
525
+ throw new TerminalUserSendReplayForbiddenError(`explicit terminal Send ${intent.messageId} already reached ` +
526
+ `${reservation.stage}; automatic replay is forbidden`);
527
+ }
528
+ return {
529
+ outcome: "proceed",
530
+ lease: { intent, durable: true, warnings }
531
+ };
532
+ }
533
+ function cancelProvenZeroInputUserExplicitSendIntent(lease, terminal, reason) {
534
+ if (!lease.durable)
535
+ return;
536
+ try {
537
+ lease.intent.repository.cancelProvenZeroInput(lease.intent.boundary);
538
+ lease.durable = false;
539
+ }
540
+ catch (error) {
541
+ const warning = `durable zero-input user-Send reservation cleanup failed: ${error instanceof Error ? error.message : String(error)}`;
542
+ lease.warnings.push(warning);
543
+ runtimeLog("warn", "terminal_user_explicit_send_intent_cancel_failed", {
544
+ terminal_id: terminal.conversationId,
545
+ message_id: lease.intent.messageId,
546
+ zero_input_reason: reason instanceof Error
547
+ ? reason.message
548
+ : String(reason),
549
+ error: warning
550
+ });
551
+ }
552
+ }
553
+ function completeUserExplicitSendIntentWhileLocked(lease, deliveryMode) {
554
+ if (!lease.durable)
555
+ return;
556
+ try {
557
+ lease.intent.repository.complete(lease.intent.boundary, deliveryMode);
558
+ }
559
+ catch (error) {
560
+ lease.durable = false;
561
+ lease.warnings.push(`durable user-Send completion receipt failed: ${error instanceof Error ? error.message : String(error)}`);
562
+ }
563
+ }
564
+ function completeManagedUserExplicitSendIntent(options, terminal, lease) {
565
+ let releaseTerminalLock;
566
+ if (lease.durable) {
567
+ try {
568
+ releaseTerminalLock = acquireTerminalBridgeSendLock(storeDirFromOptions(options), terminal.terminalControl, { timeoutMs: 0 });
569
+ completeUserExplicitSendIntentWhileLocked(lease, "managed");
570
+ }
571
+ catch (error) {
572
+ lease.durable = false;
573
+ lease.warnings.push(`durable managed Send completion receipt failed: ${error instanceof Error ? error.message : String(error)}`);
574
+ }
575
+ finally {
576
+ try {
577
+ releaseTerminalLock?.();
578
+ }
579
+ catch (error) {
580
+ lease.warnings.push(`managed terminal serialization cleanup failed after Send: ${error instanceof Error ? error.message : String(error)}`);
581
+ }
582
+ }
583
+ }
584
+ if (lease.warnings.length > 0) {
585
+ runtimeLog("warn", "terminal_user_explicit_send_intent_warning", {
586
+ terminal_id: terminal.conversationId,
587
+ message_id: lease.intent.messageId,
588
+ warnings: lease.warnings
589
+ });
590
+ }
591
+ }
592
+ async function runUserExplicitTerminalFallback(options, terminal, managedFailure, intentLease) {
593
+ const storeDir = storeDirFromOptions(options);
594
+ let releaseTerminalLock;
595
+ let terminalLockReleased = false;
596
+ try {
597
+ releaseTerminalLock = acquireUserExplicitTerminalSendLock(options, terminal, intentLease.warnings);
598
+ }
599
+ catch (error) {
600
+ // Both the failed managed path and this failed lock acquisition precede
601
+ // fallback input. Release the same-id receipt so the user can retry.
602
+ cancelProvenZeroInputUserExplicitSendIntent(intentLease, terminal, error);
603
+ runtimeLog("warn", "terminal_user_explicit_send_zero_input", {
604
+ terminal_id: terminal.conversationId,
605
+ message_id: intentLease.intent.messageId,
606
+ error: error instanceof Error ? error.message : String(error),
607
+ retry_safe: true,
608
+ intent_warnings: intentLease.warnings
609
+ });
610
+ throw error;
611
+ }
612
+ const releaseTerminalLockOnce = () => {
613
+ if (terminalLockReleased)
614
+ return;
615
+ terminalLockReleased = true;
616
+ releaseTerminalLock();
617
+ };
618
+ try {
619
+ let bridge;
620
+ let fresh;
621
+ let runtime;
622
+ const { payload, messageId } = intentLease.intent;
623
+ const intentWarnings = intentLease.warnings;
624
+ try {
625
+ bridge = createTerminalAgentBridge(options);
626
+ const resolved = await bridge.resolveConversationId(terminal.conversationId);
627
+ if (!resolved ||
628
+ resolved.agent !== terminal.agent ||
629
+ resolved.pid !== terminal.pid ||
630
+ !terminalControlsShareIncarnation(resolved.terminalControl, terminal.terminalControl)) {
631
+ throw new Error("the explicitly selected terminal is no longer the same live process");
632
+ }
633
+ fresh = resolved;
634
+ if (!hasFreshExplicitTerminalSendToken(options, fresh)) {
635
+ throw new Error("the explicit terminal send token is stale; refresh AKK list");
636
+ }
637
+ runtime = terminalRuntimeForLiveIdentity({
638
+ terminal: fresh,
639
+ physicalOnly: true
640
+ });
641
+ const status = await bridge.status(fresh.agent, fresh.terminalControl, { runtime, scrollbackLines: Number(options.scrollbackLines ?? 120) });
642
+ assertSafeUserExplicitTerminalSend(status);
643
+ }
644
+ catch (error) {
645
+ cancelProvenZeroInputUserExplicitSendIntent(intentLease, terminal, error);
646
+ runtimeLog("warn", "terminal_user_explicit_send_zero_input", {
647
+ terminal_id: terminal.conversationId,
648
+ message_id: messageId,
649
+ error: error instanceof Error ? error.message : String(error),
650
+ retry_safe: true,
651
+ intent_warnings: intentWarnings
652
+ });
653
+ throw error;
654
+ }
655
+ let preparedCallbackWatch;
656
+ const callbackWarnings = [];
657
+ try {
658
+ preparedCallbackWatch = await prepareUserExplicitFallbackWatch({
659
+ options,
660
+ terminal: fresh,
661
+ requestHash: intentLease.intent.boundary.requestHash,
662
+ messageId,
663
+ physicalToken: intentLease.intent.boundary.physicalToken
664
+ });
665
+ }
666
+ catch (error) {
667
+ const warning = `automatic callback Watch preparation failed: ${error instanceof Error ? error.message : String(error)}`;
668
+ callbackWarnings.push(warning);
669
+ runtimeLog("warn", "terminal_user_explicit_fallback_watch_prepare_failed", {
670
+ terminal_id: fresh.conversationId,
671
+ message_id: messageId,
672
+ warning
673
+ });
674
+ }
675
+ let composerDisposition = "replaced_current_composer";
676
+ try {
677
+ const revalidatePhysicalMutation = async (terminalControl) => {
678
+ const currentStatus = await bridge.status(fresh.agent, terminalControl, {
679
+ runtime,
680
+ scrollbackLines: Number(options.scrollbackLines ?? 120)
681
+ });
682
+ assertSafeUserExplicitTerminalSend(currentStatus);
683
+ if (fresh.agent !== "codex" &&
684
+ !isExactClaudeNativeInspectionIdleComposer(currentStatus.screen.excerpt ?? "")) {
685
+ throw new Error("the explicitly selected Claude composer is no longer empty");
686
+ }
687
+ };
688
+ if (fresh.agent === "codex") {
689
+ const result = await bridge.sendUserExplicitCodex(fresh.terminalControl, payload, {
690
+ runtime,
691
+ beforeMutationReservation: ({ terminalControl }) => revalidatePhysicalMutation(terminalControl),
692
+ onComposerClearDispatched: () => {
693
+ runtimeLog("info", "terminal_user_explicit_composer_cleared", {
694
+ terminal_id: fresh.conversationId,
695
+ terminal_target: fresh.terminalControl.target,
696
+ message_id: messageId
697
+ });
698
+ }
699
+ });
700
+ composerDisposition = result.disposition;
701
+ }
702
+ else {
703
+ await bridge.send(fresh.agent, fresh.terminalControl, payload, {
704
+ runtime,
705
+ requireExactComposerBeforeEnter: true,
706
+ requireExactEmptyComposerBeforeText: true,
707
+ allowWorkingComposerForUserExplicit: true,
708
+ beforeText: ({ terminalControl }) => revalidatePhysicalMutation(terminalControl)
709
+ });
710
+ }
711
+ completeUserExplicitSendIntentWhileLocked(intentLease, "unmanaged");
712
+ releaseTerminalLockOnce();
713
+ }
714
+ catch (error) {
715
+ // The user-explicit bridge normalizes only failures before its first
716
+ // physical mutation to this type. A draft-clear, text-delivery, or Enter
717
+ // attempt is uncertain and must retain the same-id intent.
718
+ const zeroInput = error instanceof TerminalInputNotStartedError;
719
+ if (zeroInput) {
720
+ cancelProvenZeroInputUserExplicitSendIntent(intentLease, fresh, error);
721
+ }
722
+ runtimeLog(zeroInput ? "warn" : "error", zeroInput
723
+ ? "terminal_user_explicit_send_zero_input"
724
+ : "terminal_user_explicit_send_uncertain", {
725
+ terminal_id: fresh.conversationId,
726
+ terminal_target: fresh.terminalControl.target,
727
+ message_id: messageId,
728
+ error: error instanceof Error ? error.message : String(error),
729
+ ...(zeroInput
730
+ ? { retry_safe: true }
731
+ : { do_not_retry: true }),
732
+ intent_warnings: intentWarnings
733
+ });
734
+ throw error;
735
+ }
736
+ let callbackReceipt;
737
+ if (preparedCallbackWatch) {
738
+ try {
739
+ callbackReceipt = await attachUserExplicitFallbackWatch({
740
+ options,
741
+ prepared: preparedCallbackWatch
742
+ });
743
+ }
744
+ catch (error) {
745
+ const warning = `automatic callback Watch attachment failed: ${error instanceof Error ? error.message : String(error)}`;
746
+ callbackWarnings.push(warning);
747
+ runtimeLog("warn", "terminal_user_explicit_fallback_watch_attach_failed", {
748
+ terminal_id: fresh.conversationId,
749
+ message_id: messageId,
750
+ watch_id: preparedCallbackWatch.watchId,
751
+ warning,
752
+ delivered: true
753
+ });
754
+ }
755
+ }
756
+ let cleanupWarnings;
757
+ try {
758
+ cleanupWarnings = await bestEffortReleaseTerminalManagementForExplicitSend({
759
+ storeDir,
760
+ terminal: fresh
761
+ });
762
+ }
763
+ catch (error) {
764
+ cleanupWarnings = [
765
+ `AKK management release was unavailable: ${error instanceof Error ? error.message : String(error)}`
766
+ ];
767
+ }
768
+ const fallbackReason = managedFailure instanceof Error
769
+ ? managedFailure.message
770
+ : String(managedFailure);
771
+ runtimeLog("warn", "terminal_user_explicit_send_fallback", {
772
+ terminal_id: fresh.conversationId,
773
+ terminal_target: fresh.terminalControl.target,
774
+ message_id: messageId,
775
+ managed_failure: fallbackReason,
776
+ composer_disposition: composerDisposition,
777
+ delivered_unmanaged: true
778
+ });
779
+ const callbackAvailable = callbackReceipt?.callback_expected === true;
780
+ printJson({
781
+ delivered: true,
782
+ delivered_unmanaged: true,
783
+ delivery_receipt: "enter_dispatched",
784
+ cleanup_warnings: cleanupWarnings,
785
+ intent_warnings: intentWarnings,
786
+ callback_warnings: callbackWarnings,
787
+ ...(callbackReceipt ?? { callback_expected: false }),
788
+ terminal_id: fresh.conversationId,
789
+ message_id: messageId,
790
+ scope: "terminal_user_explicit",
791
+ ...terminalSendResultContract({
792
+ terminalInputDispatched: true,
793
+ agentAcceptance: "unproven",
794
+ managementMode: "unmanaged",
795
+ observationMode: callbackAvailable ? "terminal_watch" : "none",
796
+ callbackAvailable,
797
+ interactionNotificationAvailable: callbackAvailable
798
+ }),
799
+ composer_disposition: composerDisposition,
800
+ composer_cleared_before_send: true,
801
+ // Deprecated compatibility alias. The v22 policy always dispatches
802
+ // C-u, so older readers may conservatively treat the prior draft as
803
+ // replaced without controlling the new behavior.
804
+ replaced_existing_draft: true,
805
+ previous_management_release_attempted: true,
806
+ warning: textSummary(`AKK delivered the user's message after managed-state preparation ` +
807
+ `failed (${fallbackReason}). ` +
808
+ (callbackReceipt
809
+ ? `Terminal Watch ${callbackReceipt.watch_id} now provides the ` +
810
+ `completion callback; no managed Turn was claimed.`
811
+ : "No callback Watch could be attached.")),
812
+ next_action: callbackReceipt
813
+ ? `wait for Terminal Watch ${callbackReceipt.watch_id} callback; ` +
814
+ "watch-status remains available for recovery"
815
+ : "refresh AKK list; the live coding agent continues independently of AKK callback state"
816
+ });
817
+ }
818
+ finally {
819
+ releaseTerminalLockOnce();
820
+ }
821
+ }
822
+ async function runRawTerminalSend(options, messageBody, terminalConversation) {
823
+ const identifyForeground = options.identifyForeground === true;
824
+ const suppliedExpectedTerminalToken = stringValue(options.expectedTerminalToken);
825
+ if (identifyForeground && terminalConversation.agent !== "codex") {
826
+ throw new Error("atomic foreground identification currently supports only Codex terminals");
827
+ }
828
+ if (identifyForeground && !suppliedExpectedTerminalToken) {
829
+ throw new Error("atomic foreground identification requires --expected-terminal-token");
830
+ }
831
+ const userExplicitAuthorityRequested = Boolean(suppliedExpectedTerminalToken && options.managedOnly !== true);
832
+ const freshExplicitAuthority = userExplicitAuthorityRequested
833
+ ? hasFreshExplicitTerminalSendToken(options, terminalConversation)
834
+ : false;
835
+ if (userExplicitAuthorityRequested &&
836
+ !freshExplicitAuthority) {
837
+ throw new Error("the explicit terminal send token is stale; refresh AKK list");
838
+ }
839
+ if (!freshExplicitAuthority) {
840
+ await runManagedRawTerminalSend(options, messageBody, terminalConversation);
841
+ return;
842
+ }
843
+ assertExpectedHandoffTokenUsesExactTerminalSelector({
844
+ options,
845
+ terminal: terminalConversation
846
+ });
847
+ const explicitOptions = {
848
+ ...options,
849
+ messageId: stringValue(options.messageId) ?? `user-send-${randomUUID()}`
850
+ };
851
+ const reservation = reserveUserExplicitSendIntent(explicitOptions, messageBody, terminalConversation);
852
+ if (reservation.outcome === "replayed")
853
+ return;
854
+ const intentLease = reservation.lease;
855
+ const managedResult = await runManagedRawTerminalSend({
856
+ ...explicitOptions,
857
+ expectedUserExplicitTerminalToken: suppliedExpectedTerminalToken,
858
+ expectedTerminalToken: stringValue(explicitOptions.expectedManagedTerminalToken),
859
+ expectedManagedTerminalToken: undefined
860
+ }, messageBody, terminalConversation, true);
861
+ if (managedResult.outcome !== "zero_input") {
862
+ if (managedResult.outcome === "replayed" ||
863
+ managedResult.enterDispatched) {
864
+ completeManagedUserExplicitSendIntent(explicitOptions, terminalConversation, intentLease);
865
+ }
866
+ return;
867
+ }
868
+ if (identifyForeground) {
869
+ // The explicit atomic contract never falls back to unmanaged delivery:
870
+ // doing so would discard the very identity/respond capability the caller
871
+ // asked this operation to establish. The task payload is proven unsent,
872
+ // so release its same-id reservation for an explicit later retry.
873
+ cancelProvenZeroInputUserExplicitSendIntent(intentLease, terminalConversation, managedResult.failure);
874
+ throw managedResult.failure;
875
+ }
876
+ return runUserExplicitTerminalFallback(explicitOptions, terminalConversation, managedResult.failure, intentLease);
877
+ }
878
+ async function runManagedRawTerminalSend(options, messageBody, terminalConversation, deferZeroInputFailurePresentation = false) {
879
+ const attempt = {
880
+ terminalControlSendInvoked: false,
881
+ result: undefined
882
+ };
883
+ try {
884
+ return await managedSendAttempt(options, messageBody, terminalConversation, deferZeroInputFailurePresentation, attempt);
885
+ }
886
+ catch (error) {
887
+ if (!deferZeroInputFailurePresentation)
888
+ throw error;
889
+ if (attempt.result)
890
+ return attempt.result;
891
+ if (!attempt.terminalControlSendInvoked) {
892
+ return { outcome: "zero_input", failure: error };
893
+ }
894
+ throw new Error("managed terminal Send may already have started input; refusing an " +
895
+ `automatic unmanaged fallback: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
896
+ }
897
+ }
898
+ export async function runHumanExplicitTerminalSend(dependencies, options, messageBody, terminal) {
899
+ return humanExplicitSendContext.run(dependencies, () => runRawTerminalSend(options, messageBody, terminal));
900
+ }
901
+ export { assertFreshUserExplicitTerminalSendTargetWhileLocked };
902
+ export { assertFreshUserExplicitTerminalSendToken };
903
+ //# sourceMappingURL=terminal-human-explicit-send-cli-adapter.js.map