@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,994 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import path from "node:path";
3
+ import { callbackDeliveryAttemptOutcome, supersedeUnacceptedCallbackDeliveries } from "./callback-outbox-policy.js";
4
+ import { captureCodexCandidateSetRolloutAcceptanceAnchor } from "./terminal-submission-acceptance.js";
5
+ import { fingerprint } from "./terminal-submission-facts.js";
6
+ import { listDeferredForegroundTransfers } from "./deferred-foreground-transfer.js";
7
+ import { isFinalDeferredForegroundTransferStatus } from "./deferred-foreground-transfer-policy.js";
8
+ import { humanExplicitCallbackDebtDisposition, humanExplicitCallbackDebtManagedTokenMatches, humanExplicitCallbackDebtRetirementDisposition } from "./deferred-foreground-authority-cli-adapter.js";
9
+ import { executorForConversation, sessionIdForConversation, turnIdForConversation } from "./protocol.js";
10
+ import { appendEvent, ensureDir, ensureStoreWritable, listConversations, loadState, pathsForConversation, saveState } from "./store.js";
11
+ import { createManagedSessionId, managedSessionBindingToken, managedSessionRevision } from "./managed-session.js";
12
+ import { listManagedSessions, listNativeThreadTransitions, loadManagedSession, saveManagedSession, tryLoadManagedSession } from "./session-store.js";
13
+ import { rolloutFileIdentityMatches } from "./terminal-binding-authority.js";
14
+ import { codexCompanionsPresentInOpenRootInventory, exactBoundCodexSendSource, isCompleteNativeRollout, nativeIdentityMatchesCodexPreMaterialization, terminalControlAliasMatches } from "./terminal-authority-policy.js";
15
+ import { decideTerminalSendAuthority } from "./terminal-action-projection.js";
16
+ import { withCanonicalMutationLocks } from "./mutation-transaction.js";
17
+ import { assertTerminalDispatchRouteMatches, withExactTerminalDispatchRoute } from "./terminal-dispatch-capability.js";
18
+ import { bindDeferredForegroundApplicationScope, bindDeferredForegroundWriterScope } from "./deferred-foreground-capability.js";
19
+ import { deferredForegroundBoundaryProjection } from "./deferred-foreground-preparation-cli-adapter.js";
20
+ import { assertFreshUserExplicitTerminalSendTargetWhileLocked, assertFreshUserExplicitTerminalSendToken } from "./terminal-human-explicit-send-cli-adapter.js";
21
+ import { isRecord, nonBlankString as stringValue } from "./value-guards.js";
22
+ const managedSendContext = new AsyncLocalStorage();
23
+ function managedSendRuntime() {
24
+ const runtime = managedSendContext.getStore();
25
+ if (!runtime) {
26
+ throw new Error("Terminal managed Send runtime is unavailable");
27
+ }
28
+ return runtime;
29
+ }
30
+ function rawPort(name) {
31
+ return ((...arguments_) => {
32
+ const operation = managedSendRuntime().ports[name];
33
+ return operation(...arguments_);
34
+ });
35
+ }
36
+ const assertExpectedHandoffTokenUsesExactTerminalSelector = rawPort("assertExpectedHandoffTokenUsesExactTerminalSelector");
37
+ const assertManagedSessionCanStartTurn = rawPort("assertManagedSessionCanStartTurn");
38
+ const assertNativeThreadHasExclusiveOwnership = rawPort("assertNativeThreadHasExclusiveOwnership");
39
+ const bindingMatchesLiveTerminal = rawPort("bindingMatchesLiveTerminal");
40
+ const codexAllowedCompanionSetForManagedSession = rawPort("codexAllowedCompanionSetForManagedSession");
41
+ const codexPreMaterializationIdentityForManagedSession = rawPort("codexPreMaterializationIdentityForManagedSession");
42
+ const createBoundManagedSession = rawPort("createBoundManagedSession");
43
+ const createManagedTerminalTurn = rawPort("createManagedTerminalTurn");
44
+ const createTerminalAgentBridge = rawPort("createTerminalAgentBridge");
45
+ const deferredForegroundApplication = rawPort("deferredForegroundApplication");
46
+ const identifyCodexForegroundWhileLocked = rawPort("identifyCodexForegroundWhileLocked");
47
+ const inspectCodexOpenRootRolloutInventory = rawPort("inspectCodexOpenRootRolloutInventory");
48
+ const isDiscoverableTmuxConversation = rawPort("isDiscoverableTmuxConversation");
49
+ const logicalIdentityForManagedSession = rawPort("logicalIdentityForManagedSession");
50
+ const managedTurnsForSession = rawPort("managedTurnsForSession");
51
+ const materializeCurrentManagedSession = rawPort("materializeCurrentManagedSession");
52
+ const maybeAdoptObservedExternalThread = rawPort("maybeAdoptObservedExternalThread");
53
+ const maybeDetachVerifiedEmptyCodexSource = rawPort("maybeDetachVerifiedEmptyCodexSource");
54
+ const observeCurrentNativeAgentSessionIdentity = rawPort("observeCurrentNativeAgentSessionIdentity");
55
+ const prepareDeferredCodexForegroundBinding = rawPort("prepareDeferredCodexForegroundBinding");
56
+ const reattachManagedSessionForNativeIdentity = rawPort("reattachManagedSessionForNativeIdentity");
57
+ const refineManagedSessionNativeIdentity = rawPort("refineManagedSessionNativeIdentity");
58
+ const required = rawPort("required");
59
+ const resolveCurrentNativeAgentSessionIdentity = rawPort("resolveCurrentNativeAgentSessionIdentity");
60
+ const soleBoundManagedSessionClaimForTerminal = rawPort("soleBoundManagedSessionClaimForTerminal");
61
+ const storeDirFromOptions = rawPort("storeDirFromOptions");
62
+ const terminalBridgeRuntimeKey = rawPort("terminalBridgeRuntimeKey");
63
+ const terminalControlFromTakeover = rawPort("terminalControlFromTakeover");
64
+ const terminalWriterMutationLocks = rawPort("terminalWriterMutationLocks");
65
+ const verifyCodexPendingManagedSendStatus = rawPort("verifyCodexPendingManagedSendStatus");
66
+ const withTerminalDispatchStateScope = rawPort("withTerminalDispatchStateScope");
67
+ const mutationDispatchLedger = new Proxy({}, {
68
+ get: (_target, property) => managedSendRuntime().ports.mutationDispatchLedger[property]
69
+ });
70
+ const terminalListCliFacade = new Proxy({}, {
71
+ get: (_target, property) => managedSendRuntime().ports.terminalList[property]
72
+ });
73
+ const foregroundIdentificationAuthority = new Proxy({}, {
74
+ get: (_target, property) => managedSendRuntime().foregroundIdentificationAuthority[property]
75
+ });
76
+ const cliNow = () => managedSendRuntime().runtime.now();
77
+ const replayExactActiveTerminalSubmission = (input) => managedSendRuntime().replayExactActiveTerminalSubmission(input);
78
+ const runTerminalControlSend = (request) => managedSendRuntime().runTerminalControlSend(request);
79
+ const USER_EXPLICIT_MANAGED_LOCK_GRACE_MS = 1_000;
80
+ function captureDetachedCodexCandidateSessionClaims(input) {
81
+ const { inventory, terminal } = input;
82
+ const candidates = new Map(inventory.roots.map((root) => [
83
+ root.sessionId.toLowerCase(),
84
+ root
85
+ ]));
86
+ const claims = listManagedSessions(input.storeDir).flatMap((session) => {
87
+ const binding = session.binding;
88
+ const nativeThreadId = binding?.native_thread_id?.toLowerCase();
89
+ const candidate = nativeThreadId ? candidates.get(nativeThreadId) : undefined;
90
+ if (session.status !== "detached" || session.agent !== "codex" ||
91
+ !binding || !nativeThreadId || !candidate ||
92
+ !isCompleteNativeRollout(binding.native_process.rollout) ||
93
+ path.resolve(session.workspace) !==
94
+ path.resolve(terminal.terminalControl.currentPath ?? "") ||
95
+ binding.native_process.pid !== inventory.pid ||
96
+ binding.native_process.process_uuid !== inventory.processUuid ||
97
+ binding.native_process.process_birth !== inventory.processBirth ||
98
+ candidate.processUuid !== inventory.processUuid ||
99
+ candidate.processBirth !== inventory.processBirth ||
100
+ !terminalControlAliasMatches(binding.terminal_id, binding.terminal_control, terminal.conversationId, terminal.terminalControl) ||
101
+ !rolloutFileIdentityMatches(binding.native_process.rollout, candidate.rollout)) {
102
+ return [];
103
+ }
104
+ return [{
105
+ session_id: session.session_id,
106
+ session_revision: managedSessionRevision(session),
107
+ session_binding_token: managedSessionBindingToken(session),
108
+ binding_id: binding.binding_id,
109
+ binding_generation: binding.generation,
110
+ native_thread_id: nativeThreadId,
111
+ process_uuid: inventory.processUuid,
112
+ process_birth: inventory.processBirth,
113
+ source_rollout: { ...binding.native_process.rollout },
114
+ candidate_rollout: { ...candidate.rollout }
115
+ }];
116
+ }).sort((left, right) => left.native_thread_id.localeCompare(right.native_thread_id) ||
117
+ left.session_id.localeCompare(right.session_id));
118
+ if (claims.length === 0)
119
+ return undefined;
120
+ const base = {
121
+ schema: "agent-knock-knock/codex-detached-candidate-session-claims",
122
+ version: 1,
123
+ anchor_fingerprint: input.anchor.anchor_fingerprint,
124
+ claims
125
+ };
126
+ return { ...base, claims_fingerprint: fingerprint(base) };
127
+ }
128
+ function rawTerminalInitialAuthority({ options, terminal, storeDir }) {
129
+ const claimedSession = soleBoundManagedSessionClaimForTerminal(storeDir, terminal);
130
+ const suppliedExpectedTerminalToken = stringValue(options.expectedTerminalToken);
131
+ const implicitCodexCandidateAuthority = Boolean(terminal.agent === "codex" &&
132
+ suppliedExpectedTerminalToken === undefined &&
133
+ claimedSession?.status === "bound" &&
134
+ isCompleteNativeRollout(claimedSession.binding?.native_process.rollout));
135
+ const knownCodexCompanions = claimedSession
136
+ ? codexAllowedCompanionSetForManagedSession({
137
+ storeDir,
138
+ session: claimedSession
139
+ })
140
+ : { additional: [] };
141
+ return {
142
+ claimedSession,
143
+ suppliedExpectedTerminalToken,
144
+ implicitCodexCandidateAuthority,
145
+ knownCodexCompanions
146
+ };
147
+ }
148
+ function assertRawTerminalCandidateAuthority({ terminal, nativeIdentityObservation, deferredCodexCandidateInventory, implicitCodexCandidateAuthority }) {
149
+ if (implicitCodexCandidateAuthority &&
150
+ !deferredCodexCandidateInventory) {
151
+ throw new Error("rollout-backed Codex terminal send requires a fresh complete " +
152
+ "nonempty open-root inventory; refresh AKK list before sending");
153
+ }
154
+ if (nativeIdentityObservation.status === "unavailable" &&
155
+ !deferredCodexCandidateInventory) {
156
+ throw new Error(`native ${terminal.agent} identity observation is ` +
157
+ `unavailable: ${nativeIdentityObservation.reason}`);
158
+ }
159
+ }
160
+ const USER_EXPLICIT_CALLBACK_SUPERSEDE_REASON = "superseded_by_user_explicit_send";
161
+ function sessionHasUnresolvedForegroundMutation(storeDir, sessionId) {
162
+ try {
163
+ if (listNativeThreadTransitions(storeDir).some((transition) => (transition.source_session_id === sessionId ||
164
+ transition.target_session_id === sessionId) &&
165
+ !["committed", "aborted"].includes(transition.status))) {
166
+ return true;
167
+ }
168
+ return listDeferredForegroundTransfers(storeDir).some((transfer) => (transfer.source_session_id === sessionId ||
169
+ transfer.target_session_id === sessionId) &&
170
+ !isFinalDeferredForegroundTransferStatus(transfer.status));
171
+ }
172
+ catch {
173
+ // Corrupt or unreadable lifecycle evidence must never be bypassed.
174
+ return true;
175
+ }
176
+ }
177
+ async function supersedeExactHumanExplicitCallbackDebt(input) {
178
+ const { options, terminal, session, candidateInventory, storeDir, scopes, resources } = input;
179
+ const expectedManagedToken = stringValue(options.expectedTerminalToken);
180
+ const binding = session?.binding;
181
+ if (terminal.agent !== "codex" ||
182
+ stringValue(options.expectedUserExplicitTerminalToken) === undefined ||
183
+ !session ||
184
+ session.status !== "bound" ||
185
+ !binding ||
186
+ !humanExplicitCallbackDebtManagedTokenMatches(expectedManagedToken, session) ||
187
+ !candidateInventory ||
188
+ !exactBoundCodexSendSource({
189
+ kind: "candidate",
190
+ sourceSession: session,
191
+ context: {
192
+ terminalId: terminal.conversationId,
193
+ terminalControl: terminal.terminalControl,
194
+ pid: terminal.pid,
195
+ workspace: terminal.terminalControl.currentPath,
196
+ liveProcessUuid: candidateInventory.processUuid,
197
+ liveProcessBirth: candidateInventory.processBirth
198
+ },
199
+ inventory: candidateInventory,
200
+ sourceRolloutAuthority: "present"
201
+ }) ||
202
+ sessionHasUnresolvedForegroundMutation(storeDir, session.session_id)) {
203
+ return false;
204
+ }
205
+ const bindingTurns = managedTurnsForSession(storeDir, session.session_id)
206
+ .filter((turn) => turn.terminal_binding_id === binding.binding_id &&
207
+ turn.terminal_binding_generation === binding.generation);
208
+ const dispositions = bindingTurns.map((turn) => ({
209
+ turn,
210
+ disposition: humanExplicitCallbackDebtRetirementDisposition(turn, session)
211
+ }));
212
+ const candidates = dispositions
213
+ .filter(({ disposition }) => disposition === "supersedable")
214
+ .map(({ turn }) => turn);
215
+ if (candidates.length === 0 ||
216
+ dispositions.some(({ disposition }) => disposition === undefined)) {
217
+ return false;
218
+ }
219
+ let superseded = 0;
220
+ for (const candidate of candidates) {
221
+ const paths = pathsForConversation(candidate.conversation_id, storeDir);
222
+ const expectedDelivery = JSON.stringify(candidate.callback_delivery);
223
+ await withTerminalDispatchStateScope(scopes, resources, paths.statePath, paths.logPath, async () => {
224
+ const current = loadState(paths.statePath);
225
+ if (JSON.stringify(current.callback_delivery) !== expectedDelivery ||
226
+ humanExplicitCallbackDebtDisposition(current, session) !==
227
+ "supersedable") {
228
+ return;
229
+ }
230
+ const at = cliNow().toISOString();
231
+ const next = supersedeUnacceptedCallbackDeliveries(current, {
232
+ at,
233
+ reason: USER_EXPLICIT_CALLBACK_SUPERSEDE_REASON
234
+ });
235
+ if (next.callback_delivery === current.callback_delivery)
236
+ return;
237
+ saveState(paths.statePath, next);
238
+ appendEvent(paths.logPath, {
239
+ ts: at,
240
+ conversation_id: current.conversation_id,
241
+ event: "callback_delivery_superseded_by_user_explicit_send",
242
+ status: current.status,
243
+ reason: USER_EXPLICIT_CALLBACK_SUPERSEDE_REASON,
244
+ prior_callback_status: isRecord(current.callback_delivery)
245
+ ? current.callback_delivery.status
246
+ : undefined,
247
+ prior_callback_attempt_disposition: callbackDeliveryAttemptOutcome(current.callback_delivery)
248
+ ?.disposition,
249
+ // An uncertain transport may already have reached the controller.
250
+ // This records that the human-priority Send retired only future
251
+ // callback retries; it never asserts that delivery did not occur.
252
+ human_override_of_uncertain_callback: callbackDeliveryAttemptOutcome(current.callback_delivery)
253
+ ?.disposition === "uncertain",
254
+ terminal_input_sent: false,
255
+ terminal_input_dispatched: false
256
+ });
257
+ superseded += 1;
258
+ });
259
+ }
260
+ return superseded === candidates.length;
261
+ }
262
+ function rawTerminalObservedIdentityForPreparation(input) {
263
+ if (input.atomicForegroundIdentification ||
264
+ input.sourceLessCandidateInventory !== undefined ||
265
+ input.observation.status !== "resolved") {
266
+ return undefined;
267
+ }
268
+ return input.observation.identity;
269
+ }
270
+ async function maybePrepareVerifiedEmptyCodexHandoff(input) {
271
+ if (input.implicitCandidateAuthority ||
272
+ input.atomicForegroundIdentification) {
273
+ return undefined;
274
+ }
275
+ return maybeDetachVerifiedEmptyCodexSource({
276
+ options: input.options,
277
+ terminal: input.terminal,
278
+ sourceSession: input.sourceSession,
279
+ observation: input.observation
280
+ });
281
+ }
282
+ function assertAtomicForegroundCandidateInventory(input) {
283
+ if (!input.enabled || input.claimedSession === undefined)
284
+ return;
285
+ if (input.inventory && input.inventory.roots.length > 0)
286
+ return;
287
+ throw new Error("atomic foreground identification requires a fresh nonempty " +
288
+ "candidate-set acceptance boundary; no task input was sent");
289
+ }
290
+ function assertAtomicForegroundAcceptanceBoundary(input) {
291
+ if (!input.enabled)
292
+ return;
293
+ if (input.deferred?.candidateAcceptanceAnchor || input.postSend)
294
+ return;
295
+ throw new Error("atomic foreground identification could not establish an exact " +
296
+ "task-acceptance boundary; no task input was sent");
297
+ }
298
+ async function prepareRawTerminalDispatchAuthority(input) {
299
+ const { options, messageBody, terminal, storeDir, scopes, resources } = input;
300
+ const atomicForegroundIdentification = options.identifyForeground === true;
301
+ const initialAuthority = rawTerminalInitialAuthority({
302
+ options,
303
+ terminal,
304
+ storeDir
305
+ });
306
+ let { claimedSession, knownCodexCompanions } = initialAuthority;
307
+ const { suppliedExpectedTerminalToken, implicitCodexCandidateAuthority } = initialAuthority;
308
+ const userExplicitTerminalToken = stringValue(options.expectedUserExplicitTerminalToken);
309
+ const nativeIdentityObservation = await observeCurrentNativeAgentSessionIdentity({
310
+ options,
311
+ agent: terminal.agent,
312
+ pid: terminal.pid,
313
+ cwd: terminal.terminalControl.currentPath,
314
+ preferredSessionId: knownCodexCompanions.primary
315
+ ? claimedSession?.binding?.native_thread_id
316
+ : undefined,
317
+ allowedCompanionIdentity: knownCodexCompanions.primary,
318
+ allowedAdditionalIdentities: knownCodexCompanions.additional
319
+ });
320
+ let deferredCodexCandidateInventory;
321
+ if (terminal.agent === "codex" &&
322
+ (userExplicitTerminalToken ||
323
+ suppliedExpectedTerminalToken ||
324
+ implicitCodexCandidateAuthority)) {
325
+ try {
326
+ const inventory = await inspectCodexOpenRootRolloutInventory({
327
+ options,
328
+ pid: terminal.pid,
329
+ cwd: terminal.terminalControl.currentPath
330
+ });
331
+ // An empty set is meaningful only for a source-less human Send: it is
332
+ // the frozen proof that the first accepting rollout must appear after
333
+ // Enter. Preserve the older bound/deferred behavior otherwise.
334
+ if (inventory.roots.length > 0 ||
335
+ (userExplicitTerminalToken !== undefined && claimedSession === undefined)) {
336
+ deferredCodexCandidateInventory = inventory;
337
+ }
338
+ }
339
+ catch (error) {
340
+ if ((userExplicitTerminalToken !== undefined &&
341
+ claimedSession === undefined) ||
342
+ implicitCodexCandidateAuthority ||
343
+ nativeIdentityObservation.status === "unavailable") {
344
+ throw new Error(`native Codex foreground attribution requires a fresh complete ` +
345
+ `open-root inventory: ${error instanceof Error ? error.message : String(error)}`);
346
+ }
347
+ }
348
+ }
349
+ assertRawTerminalCandidateAuthority({
350
+ terminal,
351
+ nativeIdentityObservation,
352
+ deferredCodexCandidateInventory,
353
+ implicitCodexCandidateAuthority
354
+ });
355
+ const sourceLessCodexCandidateInventory = terminal.agent === "codex" &&
356
+ userExplicitTerminalToken !== undefined &&
357
+ claimedSession === undefined
358
+ ? deferredCodexCandidateInventory
359
+ : undefined;
360
+ let currentNativeIdentity = rawTerminalObservedIdentityForPreparation({
361
+ atomicForegroundIdentification,
362
+ sourceLessCandidateInventory: sourceLessCodexCandidateInventory,
363
+ observation: nativeIdentityObservation
364
+ });
365
+ // A fresh nonempty inventory is the stronger physical authority for an
366
+ // implicit candidate send. Do not let an earlier verified-absent
367
+ // observation divert this path into the token-only empty handoff.
368
+ const verifiedEmptyHandoff = await maybePrepareVerifiedEmptyCodexHandoff({
369
+ options,
370
+ terminal,
371
+ sourceSession: claimedSession,
372
+ observation: nativeIdentityObservation,
373
+ implicitCandidateAuthority: implicitCodexCandidateAuthority,
374
+ atomicForegroundIdentification
375
+ });
376
+ if (verifiedEmptyHandoff) {
377
+ // The old rollout is conclusively closed. Never carry it forward as a
378
+ // pre-materialization companion for the new virgin Session.
379
+ claimedSession = undefined;
380
+ knownCodexCompanions = { additional: [] };
381
+ currentNativeIdentity = undefined;
382
+ }
383
+ const physicalNativeIdentityBeforeHandoff = currentNativeIdentity;
384
+ // The status card emitted by identify_foreground is diagnostic evidence,
385
+ // never handoff authority. Let the existing candidate-set/deferred path
386
+ // bind only the rollout that later accepts the exact task request.
387
+ let handoff = atomicForegroundIdentification
388
+ ? { identity: undefined, adopted: false }
389
+ : await maybeAdoptObservedExternalThread({
390
+ options,
391
+ terminal,
392
+ // A no-token raw send to an already managed rollout-backed Codex pane
393
+ // is an internal follow-current delegation, not a sole-root
394
+ // continuation.
395
+ sourceSession: implicitCodexCandidateAuthority
396
+ ? undefined
397
+ : claimedSession,
398
+ resolvedIdentity: sourceLessCodexCandidateInventory
399
+ ? undefined
400
+ : currentNativeIdentity,
401
+ storeDir
402
+ });
403
+ currentNativeIdentity =
404
+ handoff.adopted && terminal.agent === "codex" &&
405
+ !handoff.session?.binding?.native_process.rollout
406
+ ? physicalNativeIdentityBeforeHandoff
407
+ : handoff.identity;
408
+ if (!handoff.adopted) {
409
+ await supersedeExactHumanExplicitCallbackDebt({
410
+ options,
411
+ terminal,
412
+ session: claimedSession,
413
+ candidateInventory: deferredCodexCandidateInventory,
414
+ storeDir,
415
+ scopes,
416
+ resources
417
+ });
418
+ }
419
+ assertAtomicForegroundCandidateInventory({
420
+ enabled: atomicForegroundIdentification,
421
+ claimedSession,
422
+ inventory: deferredCodexCandidateInventory
423
+ });
424
+ const deferredCodexForegroundBinding = !handoff.adopted
425
+ ? await prepareDeferredCodexForegroundBinding({
426
+ options,
427
+ scope: bindDeferredForegroundWriterScope(scopes, resources),
428
+ terminal,
429
+ sourceSession: claimedSession,
430
+ observation: nativeIdentityObservation,
431
+ candidateInventory: deferredCodexCandidateInventory,
432
+ requestText: String(messageBody),
433
+ allowImplicitFreshAuthority: implicitCodexCandidateAuthority
434
+ })
435
+ : undefined;
436
+ const postSendCodexCandidateAnchor = terminal.agent === "codex" &&
437
+ userExplicitTerminalToken !== undefined &&
438
+ sourceLessCodexCandidateInventory !== undefined &&
439
+ verifiedEmptyHandoff === undefined &&
440
+ !handoff.adopted &&
441
+ deferredCodexForegroundBinding === undefined &&
442
+ claimedSession === undefined
443
+ ? captureCodexCandidateSetRolloutAcceptanceAnchor({
444
+ inventory: sourceLessCodexCandidateInventory,
445
+ now: cliNow()
446
+ })
447
+ : undefined;
448
+ const postSendCodexDetachedSessionClaims = postSendCodexCandidateAnchor &&
449
+ sourceLessCodexCandidateInventory
450
+ ? captureDetachedCodexCandidateSessionClaims({
451
+ storeDir,
452
+ terminal,
453
+ inventory: sourceLessCodexCandidateInventory,
454
+ anchor: postSendCodexCandidateAnchor
455
+ })
456
+ : undefined;
457
+ assertAtomicForegroundAcceptanceBoundary({
458
+ enabled: atomicForegroundIdentification,
459
+ deferred: deferredCodexForegroundBinding,
460
+ postSend: postSendCodexCandidateAnchor
461
+ });
462
+ const freshSendAuthority = decideTerminalSendAuthority({
463
+ ownership: "conflict",
464
+ verifiedEmpty: Boolean(verifiedEmptyHandoff),
465
+ externalHandoff: handoff.adopted,
466
+ deferred: Boolean(deferredCodexForegroundBinding)
467
+ });
468
+ if (freshSendAuthority.mode === "deferred" &&
469
+ deferredCodexForegroundBinding) {
470
+ claimedSession = undefined;
471
+ knownCodexCompanions = { additional: [] };
472
+ currentNativeIdentity = undefined;
473
+ handoff = { identity: undefined, adopted: false };
474
+ }
475
+ else if ((userExplicitTerminalToken ||
476
+ suppliedExpectedTerminalToken ||
477
+ implicitCodexCandidateAuthority) &&
478
+ !postSendCodexCandidateAnchor &&
479
+ freshSendAuthority.mode === "conflict") {
480
+ throw new Error("managed continuation authority is unavailable for the current " +
481
+ "terminal context" +
482
+ (userExplicitTerminalToken
483
+ ? "; the physical terminal authority remains valid"
484
+ : "; refresh AKK list before retrying managed delivery"));
485
+ }
486
+ return {
487
+ nativeIdentityObservation,
488
+ knownCodexCompanions,
489
+ currentNativeIdentity,
490
+ verifiedEmptyHandoff,
491
+ handoff,
492
+ deferredCodexForegroundBinding,
493
+ postSendCodexCandidateAnchor,
494
+ postSendCodexDetachedSessionClaims
495
+ };
496
+ }
497
+ async function runManagedRawTerminalSendAttemptInContext(options, messageBody, terminalConversation, deferZeroInputFailurePresentation, attempt) {
498
+ // A token copied from list is authority for exactly the advertised full
499
+ // terminal selector. Reject aliases and implicit/no-selector resolution
500
+ // before taking locks or touching Store state.
501
+ assertExpectedHandoffTokenUsesExactTerminalSelector({
502
+ options,
503
+ terminal: terminalConversation
504
+ });
505
+ if (!options.background) {
506
+ throw new Error("raw terminal sends require --background so AKK can persist and monitor the submission safely");
507
+ }
508
+ const rawStoreDir = storeDirFromOptions(options);
509
+ let controlSendResult;
510
+ const atomicForegroundIdentification = options.identifyForeground === true;
511
+ foregroundIdentificationAuthority.clear(options);
512
+ const userExplicitLockOptions = deferZeroInputFailurePresentation
513
+ ? {
514
+ terminalTimeoutMs: 0,
515
+ storeWriterTimeoutMs: USER_EXPLICIT_MANAGED_LOCK_GRACE_MS
516
+ }
517
+ : undefined;
518
+ const lockOptions = atomicForegroundIdentification
519
+ ? {
520
+ ...userExplicitLockOptions,
521
+ afterTerminalAcquired: async () => {
522
+ const expectedTerminalToken = required(stringValue(options.expectedUserExplicitTerminalToken), "atomic foreground identification requires fresh physical terminal authority");
523
+ const proof = await identifyCodexForegroundWhileLocked({
524
+ options,
525
+ terminal: terminalConversation,
526
+ expectedTerminalToken
527
+ });
528
+ if (proof.terminalId !== terminalConversation.conversationId ||
529
+ proof.pid !== terminalConversation.pid) {
530
+ throw new Error("foreground identification returned evidence for a different terminal");
531
+ }
532
+ foregroundIdentificationAuthority.remember(options, proof);
533
+ }
534
+ }
535
+ : userExplicitLockOptions;
536
+ await withCanonicalMutationLocks(terminalWriterMutationLocks(rawStoreDir, terminalConversation.terminalControl, lockOptions), async (scopes, resources) => {
537
+ await assertFreshUserExplicitTerminalSendTargetWhileLocked(options, terminalConversation);
538
+ await mutationDispatchLedger.beforeMutation(scopes, resources, options, terminalConversation);
539
+ // Upgrade legacy Stores before resolving their Session authority. The
540
+ // protocol migration, rather than mutable Turn recency, is the only code
541
+ // allowed to materialize Session records from existing Turns.
542
+ ensureStoreWritable(rawStoreDir);
543
+ if (replayExactActiveTerminalSubmission({
544
+ options,
545
+ terminalControl: terminalConversation.terminalControl,
546
+ requestText: String(messageBody),
547
+ expectedStoreDir: rawStoreDir,
548
+ expectedMessageType: "task",
549
+ ...(stringValue(options.expectedUserExplicitTerminalToken)
550
+ ? { userExplicitTerminalId: terminalConversation.conversationId }
551
+ : {})
552
+ })) {
553
+ controlSendResult = { outcome: "replayed" };
554
+ attempt.result = controlSendResult;
555
+ return;
556
+ }
557
+ terminalListCliFacade.assertTerminalIncarnationCanStartTurn(rawStoreDir, terminalConversation.terminalControl);
558
+ const { nativeIdentityObservation, knownCodexCompanions, currentNativeIdentity, verifiedEmptyHandoff, handoff, deferredCodexForegroundBinding, postSendCodexCandidateAnchor, postSendCodexDetachedSessionClaims } = await prepareRawTerminalDispatchAuthority({
559
+ options,
560
+ messageBody,
561
+ terminal: terminalConversation,
562
+ storeDir: rawStoreDir,
563
+ scopes,
564
+ resources
565
+ });
566
+ let managedSession = deferredCodexForegroundBinding
567
+ ? undefined
568
+ : handoff.session ??
569
+ materializeCurrentManagedSession({
570
+ options,
571
+ terminal: terminalConversation,
572
+ identity: currentNativeIdentity
573
+ });
574
+ if (!managedSession && currentNativeIdentity) {
575
+ managedSession = await reattachManagedSessionForNativeIdentity({
576
+ options,
577
+ terminal: terminalConversation,
578
+ identity: currentNativeIdentity,
579
+ storeDir: rawStoreDir
580
+ });
581
+ }
582
+ let pendingRawAttachSessionCreate;
583
+ if (!managedSession) {
584
+ if (currentNativeIdentity) {
585
+ await assertNativeThreadHasExclusiveOwnership({
586
+ options,
587
+ agent: terminalConversation.agent,
588
+ currentPid: terminalConversation.pid,
589
+ nativeThreadId: currentNativeIdentity.sessionId,
590
+ storeDir: rawStoreDir,
591
+ terminalControl: terminalConversation.terminalControl
592
+ });
593
+ }
594
+ managedSession = createBoundManagedSession({
595
+ sessionId: deferredCodexForegroundBinding?.targetSessionId ??
596
+ createManagedSessionId(),
597
+ terminal: terminalConversation,
598
+ identity: currentNativeIdentity,
599
+ lineage: deferredCodexForegroundBinding
600
+ ? {
601
+ created_by: "attach",
602
+ previous_session_id: deferredCodexForegroundBinding.sourceSessionId,
603
+ transition_id: deferredCodexForegroundBinding.transferId
604
+ }
605
+ : { created_by: "attach" }
606
+ });
607
+ if (terminalConversation.agent === "codex" &&
608
+ !currentNativeIdentity) {
609
+ if (deferredCodexForegroundBinding) {
610
+ managedSession = {
611
+ ...managedSession,
612
+ // Both endpoints stay fenced from older writers until the
613
+ // dedicated transfer reaches its resolved receipt.
614
+ status: "transitioning",
615
+ last_transition_id: deferredCodexForegroundBinding.transferId
616
+ };
617
+ }
618
+ pendingRawAttachSessionCreate = managedSession;
619
+ }
620
+ else {
621
+ managedSession = saveManagedSession(rawStoreDir, managedSession, { expectedRevision: null });
622
+ }
623
+ }
624
+ const logicalNativeIdentity = logicalIdentityForManagedSession({
625
+ storeDir: rawStoreDir,
626
+ session: managedSession,
627
+ observedIdentity: currentNativeIdentity
628
+ });
629
+ const allowedPreMaterializationIdentity = codexPreMaterializationIdentityForManagedSession({
630
+ storeDir: rawStoreDir,
631
+ session: managedSession,
632
+ observedIdentity: currentNativeIdentity
633
+ }) ?? (currentNativeIdentity === undefined ||
634
+ nativeIdentityMatchesCodexPreMaterialization(currentNativeIdentity, knownCodexCompanions.primary)
635
+ ? knownCodexCompanions.primary
636
+ : undefined);
637
+ const allowedAdditionalIdentities = allowedPreMaterializationIdentity
638
+ ? knownCodexCompanions.additional
639
+ : [];
640
+ const materializedNativeIdentity = currentNativeIdentity?.sessionId === logicalNativeIdentity?.sessionId
641
+ ? currentNativeIdentity
642
+ : undefined;
643
+ if (options.identifyForeground !== true && !(handoff.adopted &&
644
+ terminalConversation.agent === "codex" &&
645
+ !managedSession.binding?.native_process.rollout)) {
646
+ await verifyCodexPendingManagedSendStatus({
647
+ options,
648
+ terminal: terminalConversation,
649
+ session: managedSession,
650
+ logicalIdentity: logicalNativeIdentity,
651
+ allowedPreMaterializationIdentity,
652
+ allowedAdditionalIdentities
653
+ });
654
+ }
655
+ const managedNativeThreadId = logicalNativeIdentity?.sessionId ??
656
+ managedSession.binding?.native_thread_id;
657
+ if (managedNativeThreadId) {
658
+ await assertNativeThreadHasExclusiveOwnership({
659
+ options,
660
+ agent: terminalConversation.agent,
661
+ currentPid: terminalConversation.pid,
662
+ nativeThreadId: managedNativeThreadId,
663
+ storeDir: rawStoreDir,
664
+ terminalControl: terminalConversation.terminalControl,
665
+ excludedManagedSessionId: managedSession.session_id
666
+ });
667
+ }
668
+ managedSession = refineManagedSessionNativeIdentity({
669
+ storeDir: rawStoreDir,
670
+ session: managedSession,
671
+ terminalControl: terminalConversation.terminalControl,
672
+ identity: logicalNativeIdentity
673
+ });
674
+ const sessionTurns = managedTurnsForSession(rawStoreDir, managedSession.session_id);
675
+ const reusableTurn = sessionTurns[0];
676
+ assertManagedSessionCanStartTurn(sessionTurns);
677
+ const managed = createManagedTerminalTurn({
678
+ options,
679
+ conversationId: terminalConversation.conversationId,
680
+ agent: terminalConversation.agent,
681
+ pid: terminalConversation.pid,
682
+ messageBody,
683
+ terminalControl: terminalConversation.terminalControl,
684
+ previousTurn: reusableTurn,
685
+ managedSession,
686
+ nativeAgentIdentity: materializedNativeIdentity,
687
+ deferredForegroundTransferId: deferredCodexForegroundBinding?.transferId
688
+ });
689
+ ensureStoreWritable(managed.conversation.store_dir);
690
+ ensureDir(path.dirname(managed.statePath));
691
+ await withTerminalDispatchStateScope(scopes, resources, managed.statePath, managed.logPath, async (dispatchScopes, dispatchResources) => {
692
+ attempt.terminalControlSendInvoked = true;
693
+ controlSendResult = await runTerminalControlSend({
694
+ transaction: {
695
+ scopes: dispatchScopes,
696
+ resources: dispatchResources
697
+ },
698
+ options,
699
+ conversation: managed.conversation,
700
+ nextConversation: managed.nextConversation,
701
+ executor: managed.executor,
702
+ message: managed.message,
703
+ recordMessageAfterSend: true,
704
+ recordRawAttachmentAfterSend: reusableTurn === undefined,
705
+ deferZeroInputFailurePresentation,
706
+ onTerminalPreflightVerified: async (route) => {
707
+ assertFreshUserExplicitTerminalSendToken(options, {
708
+ ...terminalConversation,
709
+ terminalControl: route.terminalControl
710
+ });
711
+ if (!pendingRawAttachSessionCreate)
712
+ return;
713
+ const exactRoute = withExactTerminalDispatchRoute(route, {
714
+ terminalControl: terminalConversation.terminalControl,
715
+ terminalKey: terminalBridgeRuntimeKey(terminalConversation.terminalControl),
716
+ storeDir: rawStoreDir,
717
+ statePath: managed.statePath,
718
+ logPath: managed.logPath
719
+ }, (boundRoute) => boundRoute);
720
+ let createdSession;
721
+ if (deferredCodexForegroundBinding) {
722
+ const deferredScope = bindDeferredForegroundApplicationScope(dispatchScopes, dispatchResources);
723
+ const reserved = await deferredForegroundApplication(options, deferredCodexForegroundBinding.terminal).reserve({
724
+ scope: deferredScope,
725
+ boundary: deferredForegroundBoundaryProjection(deferredCodexForegroundBinding),
726
+ targetSession: pendingRawAttachSessionCreate,
727
+ messageId: managed.message.id,
728
+ turnId: turnIdForConversation(managed.conversation)
729
+ });
730
+ createdSession = reserved.createdSession;
731
+ managedSession = createdSession;
732
+ pendingRawAttachSessionCreate = undefined;
733
+ return (rollbackRoute) => {
734
+ assertTerminalDispatchRouteMatches(rollbackRoute, exactRoute);
735
+ reserved.rollback(deferredScope);
736
+ };
737
+ }
738
+ createdSession = saveManagedSession(exactRoute.storeDir, pendingRawAttachSessionCreate, {
739
+ expectedRevision: null
740
+ });
741
+ managedSession = createdSession;
742
+ pendingRawAttachSessionCreate = undefined;
743
+ return (rollbackRoute) => {
744
+ assertTerminalDispatchRouteMatches(rollbackRoute, route);
745
+ const current = loadManagedSession(rollbackRoute.storeDir, createdSession.session_id);
746
+ if (current.status !== "bound" ||
747
+ current.revision !== createdSession.revision ||
748
+ managedSessionBindingToken(current) !==
749
+ managedSessionBindingToken(createdSession)) {
750
+ throw new Error(`new raw-attach Session ${createdSession.session_id} changed before pre-transport rollback`);
751
+ }
752
+ const detachedAt = cliNow().toISOString();
753
+ managedSession = saveManagedSession(rollbackRoute.storeDir, {
754
+ ...current,
755
+ status: "detached",
756
+ detached_at: detachedAt,
757
+ updated_at: detachedAt
758
+ }, {
759
+ expectedRevision: current.revision
760
+ });
761
+ };
762
+ },
763
+ allowedPreMaterializationIdentity,
764
+ allowedAdditionalIdentities,
765
+ observedHandoff: handoff.adopted && handoff.transition
766
+ ? {
767
+ terminal: terminalConversation,
768
+ transition: handoff.transition
769
+ }
770
+ : undefined,
771
+ verifiedEmptyCodexHandoff: verifiedEmptyHandoff?.boundary,
772
+ postSendCodexCandidateAnchor,
773
+ postSendCodexDetachedSessionClaims,
774
+ deferredCodexForegroundBinding
775
+ });
776
+ attempt.result = controlSendResult;
777
+ }, deferZeroInputFailurePresentation
778
+ ? { timeoutMs: USER_EXPLICIT_MANAGED_LOCK_GRACE_MS }
779
+ : undefined);
780
+ });
781
+ if (!controlSendResult) {
782
+ throw new Error("managed terminal Send completed without an outcome");
783
+ }
784
+ attempt.result = controlSendResult;
785
+ return controlSendResult;
786
+ }
787
+ async function runManagedSessionSendInContext(options, messageBody) {
788
+ if (stringValue(options.expectedTerminalToken)) {
789
+ throw new Error("--expected-terminal-token cannot be used with a managed Session; " +
790
+ "use the exact full terminal selector advertised by AKK list");
791
+ }
792
+ const sessionId = required(stringValue(options.session ?? options.conversation ?? options.conversationId), "--session is required for an ordinary managed send");
793
+ const storeDir = storeDirFromOptions(options);
794
+ // Read only enough legacy/Session authority to identify the physical
795
+ // terminal. Store migration is deliberately deferred until the terminal
796
+ // lock has reconciled any lifecycle fence.
797
+ let initialSession = tryLoadManagedSession(storeDir, sessionId);
798
+ let initialTurns = managedTurnsForSession(storeDir, sessionId);
799
+ if (!initialSession) {
800
+ const exactTurn = listConversations(storeDir)
801
+ .filter(isDiscoverableTmuxConversation)
802
+ .find((turn) => turnIdForConversation(turn) === sessionId ||
803
+ turn.conversation_id === sessionId);
804
+ if (exactTurn && sessionIdForConversation(exactTurn) !== sessionId) {
805
+ throw new Error(`turn ${sessionId} is an execution identity, not an ordinary send target; ` +
806
+ `send to session ${sessionIdForConversation(exactTurn)} instead`);
807
+ }
808
+ if (initialTurns.length === 0) {
809
+ throw new Error(`managed session ${sessionId} was not found`);
810
+ }
811
+ }
812
+ const legacyBindingTurn = initialTurns[0];
813
+ const legacyTakeover = legacyBindingTurn && isRecord(legacyBindingTurn.native_session_takeover)
814
+ ? legacyBindingTurn.native_session_takeover
815
+ : undefined;
816
+ const rawTerminalId = initialSession?.binding?.terminal_id ??
817
+ stringValue(legacyTakeover?.native_session_id);
818
+ if (!rawTerminalId) {
819
+ throw new Error(`managed Session ${sessionId} has no authoritative terminal binding`);
820
+ }
821
+ const storedTerminalControl = initialSession?.binding?.terminal_control ??
822
+ terminalControlFromTakeover(legacyTakeover);
823
+ const storedAgent = initialSession?.agent ??
824
+ (legacyBindingTurn
825
+ ? executorForConversation(legacyBindingTurn).kind
826
+ : undefined);
827
+ const storedPid = initialSession?.binding?.native_process.pid ??
828
+ Number(legacyTakeover?.terminal_agent_pid);
829
+ const terminalBridge = createTerminalAgentBridge(options);
830
+ const resolvedTerminal = storedTerminalControl && storedAgent &&
831
+ Number.isSafeInteger(storedPid) && storedPid > 1
832
+ ? await terminalBridge.resolveStoredTerminal(storedAgent, storedPid, storedTerminalControl, { pid: storedPid })
833
+ : await terminalBridge.resolveConversationId(rawTerminalId);
834
+ if (!resolvedTerminal) {
835
+ throw new Error(`session ${sessionId} is not attached to a live terminal`);
836
+ }
837
+ await withCanonicalMutationLocks(terminalWriterMutationLocks(storeDir, resolvedTerminal.terminalControl), async (scopes, resources) => {
838
+ const lockedStrictSession = tryLoadManagedSession(storeDir, sessionId);
839
+ if (lockedStrictSession?.agent === "codex" &&
840
+ lockedStrictSession.session_id === sessionId &&
841
+ lockedStrictSession.status === "bound" &&
842
+ isCompleteNativeRollout(lockedStrictSession.binding?.native_process.rollout)) {
843
+ throw new Error(`Codex rollout-backed managed Session ${sessionId} cannot use a ` +
844
+ "strict session_id send because an open rollout does not prove the " +
845
+ "current TUI foreground thread. Refresh AKK list and use its exact " +
846
+ "selector plus expected_terminal_token. No Turn was created and no " +
847
+ "terminal input was sent.");
848
+ }
849
+ await mutationDispatchLedger.beforeMutation(scopes, resources, options, resolvedTerminal);
850
+ // A protocol-1/2 Store materializes authoritative Session records as one
851
+ // atomic migration. Once protocol 3 is active, a missing Session is corrupt
852
+ // state and must not be reconstructed from whichever Turn looks newest.
853
+ ensureStoreWritable(storeDir);
854
+ if (replayExactActiveTerminalSubmission({
855
+ options,
856
+ terminalControl: resolvedTerminal.terminalControl,
857
+ requestText: String(messageBody),
858
+ expectedStoreDir: storeDir,
859
+ expectedSessionId: sessionId,
860
+ expectedMessageType: "task"
861
+ })) {
862
+ return;
863
+ }
864
+ terminalListCliFacade.assertTerminalIncarnationCanStartTurn(storeDir, resolvedTerminal.terminalControl);
865
+ let currentSession = tryLoadManagedSession(storeDir, sessionId);
866
+ let knownCodexCompanions = currentSession
867
+ ? codexAllowedCompanionSetForManagedSession({
868
+ storeDir,
869
+ session: currentSession
870
+ })
871
+ : { additional: [] };
872
+ if (currentSession?.agent === "codex" &&
873
+ knownCodexCompanions.primary) {
874
+ try {
875
+ const inventory = await inspectCodexOpenRootRolloutInventory({
876
+ options,
877
+ pid: resolvedTerminal.pid,
878
+ cwd: resolvedTerminal.terminalControl.currentPath
879
+ });
880
+ knownCodexCompanions = codexCompanionsPresentInOpenRootInventory(knownCodexCompanions, inventory);
881
+ }
882
+ catch {
883
+ // Inventory proof is an optimization only. Preserve the existing
884
+ // closed /status fence when exact open-root membership is unavailable.
885
+ }
886
+ }
887
+ const lockedNativeIdentity = await resolveCurrentNativeAgentSessionIdentity({
888
+ options,
889
+ agent: resolvedTerminal.agent,
890
+ pid: resolvedTerminal.pid,
891
+ cwd: resolvedTerminal.terminalControl.currentPath,
892
+ preferredSessionId: knownCodexCompanions.primary
893
+ ? currentSession?.binding?.native_thread_id
894
+ : undefined,
895
+ allowedCompanionIdentity: knownCodexCompanions.primary,
896
+ allowedAdditionalIdentities: knownCodexCompanions.additional
897
+ });
898
+ if (!currentSession) {
899
+ currentSession = materializeCurrentManagedSession({
900
+ options,
901
+ terminal: resolvedTerminal,
902
+ identity: lockedNativeIdentity
903
+ });
904
+ }
905
+ if (!currentSession ||
906
+ currentSession.session_id !== sessionId ||
907
+ currentSession.status !== "bound" ||
908
+ !currentSession.binding) {
909
+ throw new Error(`managed Session ${sessionId} is no longer bound; refresh list and retry`);
910
+ }
911
+ const currentTurns = managedTurnsForSession(storeDir, sessionId);
912
+ assertManagedSessionCanStartTurn(currentTurns);
913
+ if (!bindingMatchesLiveTerminal(currentSession, resolvedTerminal, lockedNativeIdentity, storeDir)) {
914
+ throw new Error("managed session identity changed while waiting to send; refresh list and retry");
915
+ }
916
+ const logicalLockedNativeIdentity = logicalIdentityForManagedSession({
917
+ storeDir,
918
+ session: currentSession,
919
+ observedIdentity: lockedNativeIdentity
920
+ });
921
+ const allowedPreMaterializationIdentity = codexPreMaterializationIdentityForManagedSession({
922
+ storeDir,
923
+ session: currentSession,
924
+ observedIdentity: lockedNativeIdentity
925
+ }) ?? knownCodexCompanions.primary;
926
+ const allowedAdditionalIdentities = knownCodexCompanions.additional;
927
+ const materializedLockedNativeIdentity = lockedNativeIdentity?.sessionId === logicalLockedNativeIdentity?.sessionId
928
+ ? lockedNativeIdentity
929
+ : undefined;
930
+ await verifyCodexPendingManagedSendStatus({
931
+ options,
932
+ terminal: resolvedTerminal,
933
+ session: currentSession,
934
+ logicalIdentity: logicalLockedNativeIdentity,
935
+ allowedPreMaterializationIdentity,
936
+ allowedAdditionalIdentities
937
+ });
938
+ const managedNativeThreadId = logicalLockedNativeIdentity?.sessionId ??
939
+ currentSession.binding.native_thread_id;
940
+ if (managedNativeThreadId) {
941
+ await assertNativeThreadHasExclusiveOwnership({
942
+ options,
943
+ agent: resolvedTerminal.agent,
944
+ currentPid: resolvedTerminal.pid,
945
+ nativeThreadId: managedNativeThreadId,
946
+ storeDir,
947
+ terminalControl: resolvedTerminal.terminalControl,
948
+ excludedManagedSessionId: currentSession.session_id
949
+ });
950
+ }
951
+ currentSession = refineManagedSessionNativeIdentity({
952
+ storeDir,
953
+ session: currentSession,
954
+ terminalControl: resolvedTerminal.terminalControl,
955
+ identity: logicalLockedNativeIdentity
956
+ });
957
+ const managed = createManagedTerminalTurn({
958
+ options,
959
+ conversationId: resolvedTerminal.conversationId,
960
+ agent: resolvedTerminal.agent,
961
+ pid: resolvedTerminal.pid,
962
+ messageBody,
963
+ terminalControl: resolvedTerminal.terminalControl,
964
+ previousTurn: currentTurns[0],
965
+ managedSession: currentSession,
966
+ nativeAgentIdentity: materializedLockedNativeIdentity
967
+ });
968
+ ensureStoreWritable(managed.conversation.store_dir);
969
+ ensureDir(path.dirname(managed.statePath));
970
+ await withTerminalDispatchStateScope(scopes, resources, managed.statePath, managed.logPath, async (dispatchScopes, dispatchResources) => {
971
+ await runTerminalControlSend({
972
+ transaction: {
973
+ scopes: dispatchScopes,
974
+ resources: dispatchResources
975
+ },
976
+ options,
977
+ conversation: managed.conversation,
978
+ nextConversation: managed.nextConversation,
979
+ executor: managed.executor,
980
+ message: managed.message,
981
+ recordMessageAfterSend: true,
982
+ allowedPreMaterializationIdentity,
983
+ allowedAdditionalIdentities
984
+ });
985
+ });
986
+ });
987
+ }
988
+ export async function runManagedRawTerminalSendAttempt(dependencies, options, messageBody, terminalConversation, deferZeroInputFailurePresentation, attempt) {
989
+ return managedSendContext.run(dependencies, () => runManagedRawTerminalSendAttemptInContext(options, messageBody, terminalConversation, deferZeroInputFailurePresentation, attempt));
990
+ }
991
+ export async function runManagedSessionSend(dependencies, options, messageBody) {
992
+ return managedSendContext.run(dependencies, () => runManagedSessionSendInContext(options, messageBody));
993
+ }
994
+ //# sourceMappingURL=terminal-managed-send-cli-adapter.js.map