@scotthuang/agent-knock-knock 0.13.17 → 0.14.0

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 (291) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/CONTRIBUTING.md +212 -0
  3. package/README.md +105 -166
  4. package/connectors/deepseek-harness/LICENSE +21 -0
  5. package/connectors/deepseek-harness/README.md +406 -0
  6. package/connectors/pi/LICENSE +21 -0
  7. package/connectors/pi/README.md +446 -0
  8. package/dist/src/backend-recovery-semantic.d.ts +16 -0
  9. package/dist/src/backend-recovery-semantic.js +113 -0
  10. package/dist/src/backend-recovery-semantic.js.map +1 -0
  11. package/dist/src/backend-task-recovery.d.ts +103 -0
  12. package/dist/src/backend-task-recovery.js +142 -0
  13. package/dist/src/backend-task-recovery.js.map +1 -0
  14. package/dist/src/callback-transport.d.ts +8 -0
  15. package/dist/src/callback-transport.js +14 -0
  16. package/dist/src/callback-transport.js.map +1 -1
  17. package/dist/src/cli-core.js +18 -8
  18. package/dist/src/cli-core.js.map +1 -1
  19. package/dist/src/cli-runtime-context.d.ts +5 -0
  20. package/dist/src/cli-runtime-context.js.map +1 -1
  21. package/dist/src/codex-async-question-adapter.js +14 -4
  22. package/dist/src/codex-async-question-adapter.js.map +1 -1
  23. package/dist/src/codex-lifecycle-compatibility.d.ts +1 -1
  24. package/dist/src/codex-lifecycle-compatibility.js +9 -3
  25. package/dist/src/codex-lifecycle-compatibility.js.map +1 -1
  26. package/dist/src/codex-native-cli-adapter.d.ts +6 -0
  27. package/dist/src/codex-native-cli-adapter.js +273 -0
  28. package/dist/src/codex-native-cli-adapter.js.map +1 -0
  29. package/dist/src/codex-native-client-interactions.d.ts +6 -0
  30. package/dist/src/codex-native-client-interactions.js +124 -0
  31. package/dist/src/codex-native-client-interactions.js.map +1 -0
  32. package/dist/src/codex-native-client-rpc.d.ts +21 -0
  33. package/dist/src/codex-native-client-rpc.js +137 -0
  34. package/dist/src/codex-native-client-rpc.js.map +1 -0
  35. package/dist/src/codex-native-client.d.ts +42 -0
  36. package/dist/src/codex-native-client.js +326 -0
  37. package/dist/src/codex-native-client.js.map +1 -0
  38. package/dist/src/codex-native-identity.d.ts +6 -0
  39. package/dist/src/codex-native-identity.js +42 -0
  40. package/dist/src/codex-native-identity.js.map +1 -0
  41. package/dist/src/codex-native-monitor.d.ts +4 -0
  42. package/dist/src/codex-native-monitor.js +92 -0
  43. package/dist/src/codex-native-monitor.js.map +1 -0
  44. package/dist/src/codex-native-outbox.d.ts +16 -0
  45. package/dist/src/codex-native-outbox.js +120 -0
  46. package/dist/src/codex-native-outbox.js.map +1 -0
  47. package/dist/src/codex-native-public-projection.d.ts +545 -0
  48. package/dist/src/codex-native-public-projection.js +182 -0
  49. package/dist/src/codex-native-public-projection.js.map +1 -0
  50. package/dist/src/codex-native-record-store.d.ts +27 -0
  51. package/dist/src/codex-native-record-store.js +111 -0
  52. package/dist/src/codex-native-record-store.js.map +1 -0
  53. package/dist/src/codex-native-response-service.d.ts +69 -0
  54. package/dist/src/codex-native-response-service.js +244 -0
  55. package/dist/src/codex-native-response-service.js.map +1 -0
  56. package/dist/src/codex-native-runtime.d.ts +46 -0
  57. package/dist/src/codex-native-runtime.js +112 -0
  58. package/dist/src/codex-native-runtime.js.map +1 -0
  59. package/dist/src/codex-native-semantic.d.ts +17 -0
  60. package/dist/src/codex-native-semantic.js +175 -0
  61. package/dist/src/codex-native-semantic.js.map +1 -0
  62. package/dist/src/codex-native-snapshot.d.ts +19 -0
  63. package/dist/src/codex-native-snapshot.js +160 -0
  64. package/dist/src/codex-native-snapshot.js.map +1 -0
  65. package/dist/src/codex-native-state-store.d.ts +61 -0
  66. package/dist/src/codex-native-state-store.js +132 -0
  67. package/dist/src/codex-native-state-store.js.map +1 -0
  68. package/dist/src/codex-native-task-service.d.ts +71 -0
  69. package/dist/src/codex-native-task-service.js +502 -0
  70. package/dist/src/codex-native-task-service.js.map +1 -0
  71. package/dist/src/codex-native-types.d.ts +92 -0
  72. package/dist/src/codex-native-types.js +15 -0
  73. package/dist/src/codex-native-types.js.map +1 -0
  74. package/dist/src/codex-permission-surface.d.ts +1 -1
  75. package/dist/src/codex-permission-surface.js +1 -1
  76. package/dist/src/codex-permission-surface.js.map +1 -1
  77. package/dist/src/codex-terminal-agent-adapter.js +3 -1
  78. package/dist/src/codex-terminal-agent-adapter.js.map +1 -1
  79. package/dist/src/conversation-list.d.ts +12 -0
  80. package/dist/src/conversation-list.js +30 -0
  81. package/dist/src/conversation-list.js.map +1 -0
  82. package/dist/src/conversation-route-dispatch.d.ts +13 -0
  83. package/dist/src/conversation-route-dispatch.js +66 -0
  84. package/dist/src/conversation-route-dispatch.js.map +1 -0
  85. package/dist/src/conversation-route-legacy.d.ts +18 -0
  86. package/dist/src/conversation-route-legacy.js +54 -0
  87. package/dist/src/conversation-route-legacy.js.map +1 -0
  88. package/dist/src/conversation-route-store.d.ts +51 -0
  89. package/dist/src/conversation-route-store.js +126 -0
  90. package/dist/src/conversation-route-store.js.map +1 -0
  91. package/dist/src/conversation-routing-cli-adapter.d.ts +12 -0
  92. package/dist/src/conversation-routing-cli-adapter.js +211 -0
  93. package/dist/src/conversation-routing-cli-adapter.js.map +1 -0
  94. package/dist/src/conversation-routing-commands.d.ts +11 -0
  95. package/dist/src/conversation-routing-commands.js +85 -0
  96. package/dist/src/conversation-routing-commands.js.map +1 -0
  97. package/dist/src/conversation-routing-home.d.ts +26 -0
  98. package/dist/src/conversation-routing-home.js +105 -0
  99. package/dist/src/conversation-routing-home.js.map +1 -0
  100. package/dist/src/conversation-routing-identity.d.ts +40 -0
  101. package/dist/src/conversation-routing-identity.js +174 -0
  102. package/dist/src/conversation-routing-identity.js.map +1 -0
  103. package/dist/src/conversation-runtime-route-store.d.ts +11 -0
  104. package/dist/src/conversation-runtime-route-store.js +118 -0
  105. package/dist/src/conversation-runtime-route-store.js.map +1 -0
  106. package/dist/src/desktop-async-interactions.d.ts +15 -0
  107. package/dist/src/desktop-async-interactions.js +88 -0
  108. package/dist/src/desktop-async-interactions.js.map +1 -0
  109. package/dist/src/desktop-async-state.d.ts +5 -0
  110. package/dist/src/desktop-async-state.js +53 -0
  111. package/dist/src/desktop-async-state.js.map +1 -0
  112. package/dist/src/desktop-cli-adapter.d.ts +7 -0
  113. package/dist/src/desktop-cli-adapter.js +322 -0
  114. package/dist/src/desktop-cli-adapter.js.map +1 -0
  115. package/dist/src/desktop-cli-controls.d.ts +9 -0
  116. package/dist/src/desktop-cli-controls.js +45 -0
  117. package/dist/src/desktop-cli-controls.js.map +1 -0
  118. package/dist/src/desktop-command-presentation.d.ts +2 -0
  119. package/dist/src/desktop-command-presentation.js +31 -0
  120. package/dist/src/desktop-command-presentation.js.map +1 -0
  121. package/dist/src/desktop-control-semantic.d.ts +8 -0
  122. package/dist/src/desktop-control-semantic.js +68 -0
  123. package/dist/src/desktop-control-semantic.js.map +1 -0
  124. package/dist/src/desktop-identity.d.ts +5 -0
  125. package/dist/src/desktop-identity.js +40 -0
  126. package/dist/src/desktop-identity.js.map +1 -0
  127. package/dist/src/desktop-interaction-projection.d.ts +57 -0
  128. package/dist/src/desktop-interaction-projection.js +196 -0
  129. package/dist/src/desktop-interaction-projection.js.map +1 -0
  130. package/dist/src/desktop-interaction-state.d.ts +3 -0
  131. package/dist/src/desktop-interaction-state.js +48 -0
  132. package/dist/src/desktop-interaction-state.js.map +1 -0
  133. package/dist/src/desktop-ipc-async-answer.d.ts +9 -0
  134. package/dist/src/desktop-ipc-async-answer.js +71 -0
  135. package/dist/src/desktop-ipc-async-answer.js.map +1 -0
  136. package/dist/src/desktop-ipc-client.d.ts +47 -0
  137. package/dist/src/desktop-ipc-client.js +400 -0
  138. package/dist/src/desktop-ipc-client.js.map +1 -0
  139. package/dist/src/desktop-ipc-native-operations.d.ts +11 -0
  140. package/dist/src/desktop-ipc-native-operations.js +126 -0
  141. package/dist/src/desktop-ipc-native-operations.js.map +1 -0
  142. package/dist/src/desktop-ipc-transport.d.ts +13 -0
  143. package/dist/src/desktop-ipc-transport.js +123 -0
  144. package/dist/src/desktop-ipc-transport.js.map +1 -0
  145. package/dist/src/desktop-list.d.ts +25 -0
  146. package/dist/src/desktop-list.js +55 -0
  147. package/dist/src/desktop-list.js.map +1 -0
  148. package/dist/src/desktop-metadata-reader.d.ts +30 -0
  149. package/dist/src/desktop-metadata-reader.js +182 -0
  150. package/dist/src/desktop-metadata-reader.js.map +1 -0
  151. package/dist/src/desktop-monitor.d.ts +4 -0
  152. package/dist/src/desktop-monitor.js +101 -0
  153. package/dist/src/desktop-monitor.js.map +1 -0
  154. package/dist/src/desktop-public-projection.d.ts +6 -0
  155. package/dist/src/desktop-public-projection.js +134 -0
  156. package/dist/src/desktop-public-projection.js.map +1 -0
  157. package/dist/src/desktop-request-interactions.d.ts +14 -0
  158. package/dist/src/desktop-request-interactions.js +144 -0
  159. package/dist/src/desktop-request-interactions.js.map +1 -0
  160. package/dist/src/desktop-response-dispatch.d.ts +14 -0
  161. package/dist/src/desktop-response-dispatch.js +19 -0
  162. package/dist/src/desktop-response-dispatch.js.map +1 -0
  163. package/dist/src/desktop-response-evidence.d.ts +4 -0
  164. package/dist/src/desktop-response-evidence.js +19 -0
  165. package/dist/src/desktop-response-evidence.js.map +1 -0
  166. package/dist/src/desktop-response-service.d.ts +11 -0
  167. package/dist/src/desktop-response-service.js +188 -0
  168. package/dist/src/desktop-response-service.js.map +1 -0
  169. package/dist/src/desktop-response-store.d.ts +35 -0
  170. package/dist/src/desktop-response-store.js +58 -0
  171. package/dist/src/desktop-response-store.js.map +1 -0
  172. package/dist/src/desktop-response-types.d.ts +20 -0
  173. package/dist/src/desktop-response-types.js +2 -0
  174. package/dist/src/desktop-response-types.js.map +1 -0
  175. package/dist/src/desktop-response-value.d.ts +6 -0
  176. package/dist/src/desktop-response-value.js +31 -0
  177. package/dist/src/desktop-response-value.js.map +1 -0
  178. package/dist/src/desktop-runtime.d.ts +153 -0
  179. package/dist/src/desktop-runtime.js +88 -0
  180. package/dist/src/desktop-runtime.js.map +1 -0
  181. package/dist/src/desktop-semantic.d.ts +21 -0
  182. package/dist/src/desktop-semantic.js +140 -0
  183. package/dist/src/desktop-semantic.js.map +1 -0
  184. package/dist/src/desktop-session-catalog.d.ts +68 -0
  185. package/dist/src/desktop-session-catalog.js +225 -0
  186. package/dist/src/desktop-session-catalog.js.map +1 -0
  187. package/dist/src/desktop-session-controls.d.ts +145 -0
  188. package/dist/src/desktop-session-controls.js +176 -0
  189. package/dist/src/desktop-session-controls.js.map +1 -0
  190. package/dist/src/desktop-sidebar-metadata.d.ts +27 -0
  191. package/dist/src/desktop-sidebar-metadata.js +83 -0
  192. package/dist/src/desktop-sidebar-metadata.js.map +1 -0
  193. package/dist/src/desktop-sidebar-projects.d.ts +10 -0
  194. package/dist/src/desktop-sidebar-projects.js +31 -0
  195. package/dist/src/desktop-sidebar-projects.js.map +1 -0
  196. package/dist/src/desktop-sidebar-selection.d.ts +28 -0
  197. package/dist/src/desktop-sidebar-selection.js +85 -0
  198. package/dist/src/desktop-sidebar-selection.js.map +1 -0
  199. package/dist/src/desktop-snapshot-details.d.ts +4 -0
  200. package/dist/src/desktop-snapshot-details.js +116 -0
  201. package/dist/src/desktop-snapshot-details.js.map +1 -0
  202. package/dist/src/desktop-snapshot.d.ts +11 -0
  203. package/dist/src/desktop-snapshot.js +276 -0
  204. package/dist/src/desktop-snapshot.js.map +1 -0
  205. package/dist/src/desktop-state-store.d.ts +72 -0
  206. package/dist/src/desktop-state-store.js +269 -0
  207. package/dist/src/desktop-state-store.js.map +1 -0
  208. package/dist/src/desktop-task-interactions.d.ts +10 -0
  209. package/dist/src/desktop-task-interactions.js +93 -0
  210. package/dist/src/desktop-task-interactions.js.map +1 -0
  211. package/dist/src/desktop-task-recovery.d.ts +38 -0
  212. package/dist/src/desktop-task-recovery.js +171 -0
  213. package/dist/src/desktop-task-recovery.js.map +1 -0
  214. package/dist/src/desktop-task-service.d.ts +54 -0
  215. package/dist/src/desktop-task-service.js +441 -0
  216. package/dist/src/desktop-task-service.js.map +1 -0
  217. package/dist/src/desktop-types.d.ts +281 -0
  218. package/dist/src/desktop-types.js +13 -0
  219. package/dist/src/desktop-types.js.map +1 -0
  220. package/dist/src/host-monitor-reconciliation.js +36 -4
  221. package/dist/src/host-monitor-reconciliation.js.map +1 -1
  222. package/dist/src/host-profile-runtime.js +7 -3
  223. package/dist/src/host-profile-runtime.js.map +1 -1
  224. package/dist/src/local-codex-cli-adapter.d.ts +7 -0
  225. package/dist/src/local-codex-cli-adapter.js +13 -0
  226. package/dist/src/local-codex-cli-adapter.js.map +1 -0
  227. package/dist/src/openclaw-callback-transport.js +2 -1
  228. package/dist/src/openclaw-callback-transport.js.map +1 -1
  229. package/dist/src/semantic-conversation-target.d.ts +4 -0
  230. package/dist/src/semantic-conversation-target.js +20 -0
  231. package/dist/src/semantic-conversation-target.js.map +1 -0
  232. package/dist/src/semantic-permission-control.js +47 -9
  233. package/dist/src/semantic-permission-control.js.map +1 -1
  234. package/dist/src/semantic-private-authority-offers.d.ts +1 -1
  235. package/dist/src/semantic-private-authority-offers.js +3 -1
  236. package/dist/src/semantic-private-authority-offers.js.map +1 -1
  237. package/dist/src/semantic-tool-command-helpers.d.ts +6 -0
  238. package/dist/src/semantic-tool-command-helpers.js +199 -78
  239. package/dist/src/semantic-tool-command-helpers.js.map +1 -1
  240. package/dist/src/semantic-tool-descriptions.d.ts +2 -1
  241. package/dist/src/semantic-tool-descriptions.js +81 -35
  242. package/dist/src/semantic-tool-descriptions.js.map +1 -1
  243. package/dist/src/semantic-tool-list-projection.js +66 -2
  244. package/dist/src/semantic-tool-list-projection.js.map +1 -1
  245. package/dist/src/semantic-tool-presentation.js +76 -7
  246. package/dist/src/semantic-tool-presentation.js.map +1 -1
  247. package/dist/src/semantic-tool-runtime.js +129 -29
  248. package/dist/src/semantic-tool-runtime.js.map +1 -1
  249. package/dist/src/semantic-tool-schemas.d.ts +410 -27
  250. package/dist/src/semantic-tool-schemas.js +176 -88
  251. package/dist/src/semantic-tool-schemas.js.map +1 -1
  252. package/dist/src/terminal-action-contracts.js +10 -6
  253. package/dist/src/terminal-action-contracts.js.map +1 -1
  254. package/dist/src/terminal-list-cli-adapter.d.ts +1 -0
  255. package/dist/src/terminal-list-cli-adapter.js +6 -3
  256. package/dist/src/terminal-list-cli-adapter.js.map +1 -1
  257. package/dist/src/terminal-model-control-profile.d.ts +3 -1
  258. package/dist/src/terminal-model-control-profile.js +15 -7
  259. package/dist/src/terminal-model-control-profile.js.map +1 -1
  260. package/dist/src/terminal-monitor-decision-policy.d.ts +1 -1
  261. package/dist/src/terminal-native-inspection-profile.js +4 -0
  262. package/dist/src/terminal-native-inspection-profile.js.map +1 -1
  263. package/dist/src/terminal-permission-control-list-projection.d.ts +1 -1
  264. package/dist/src/terminal-permission-control.js +5 -1
  265. package/dist/src/terminal-permission-control.js.map +1 -1
  266. package/dist/src/terminal-questionnaire-adapter.js +5 -2
  267. package/dist/src/terminal-questionnaire-adapter.js.map +1 -1
  268. package/dist/src/terminal-user-send-intent.d.ts +2 -0
  269. package/dist/src/terminal-user-send-intent.js +11 -3
  270. package/dist/src/terminal-user-send-intent.js.map +1 -1
  271. package/docs/architecture/current-architecture.md +313 -0
  272. package/docs/architecture/interactive-terminal-response.md +276 -0
  273. package/docs/architecture/issue-126-final-report.md +248 -0
  274. package/docs/architecture/orchestration-refactor-history.md +2987 -0
  275. package/docs/architecture/orchestration-refactor.md +21 -0
  276. package/docs/backend-task-recovery.md +89 -0
  277. package/docs/bidirectional-agent-protocol.md +260 -0
  278. package/docs/codex-0.160.0-compatibility.md +126 -0
  279. package/docs/codex-cli-native-compatibility.md +246 -0
  280. package/docs/codex-desktop-compatibility.md +414 -0
  281. package/docs/codex-permissions.md +12 -1
  282. package/docs/openclaw-operations.md +281 -0
  283. package/docs/openclaw-session-turn-delivery-requirement.md +45 -0
  284. package/docs/operator-guide.md +543 -0
  285. package/docs/storage-and-logging.md +91 -0
  286. package/docs/test-performance-issue-108.md +80 -0
  287. package/docs/test-performance-issue-120.md +226 -0
  288. package/docs/testing.md +628 -0
  289. package/openclaw.plugin.json +7 -3
  290. package/package.json +6 -12
  291. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +69 -18
@@ -0,0 +1,134 @@
1
+ import { backendTaskRecoveryProjection } from "./backend-task-recovery.js";
2
+ import { desktopObservationStopped } from "./desktop-task-recovery.js";
3
+ import { desktopInteractionIsApproval, desktopInteractionProjection } from "./desktop-interaction-projection.js";
4
+ export function desktopSessionProjection(entry, snapshot, writesVerified = false, observationError) {
5
+ const live = snapshot !== undefined;
6
+ const activeTurn = activeDesktopTurn(snapshot);
7
+ const watch = Boolean(activeTurn);
8
+ const send = Boolean(snapshot?.canSend && writesVerified);
9
+ const interactions = writesVerified && activeTurn ? (snapshot?.pendingInteractions ?? snapshot?.asyncQuestions ?? [])
10
+ .filter(item => item.turnId === activeTurn) : [];
11
+ const settings = Boolean(writesVerified && snapshot?.canSend && snapshot.runtimeStatus === "idle");
12
+ const capabilities = { status: true, send, watch, interaction_notify: watch, ...interactionCapabilities(interactions),
13
+ set_permissions: settings, set_model: settings, cancel: writesVerified && watch };
14
+ return {
15
+ id: entry.conversationId, conversation_id: entry.conversationId, source: "codex_desktop", agent: "codex",
16
+ title: snapshot?.title ?? entry.title, cwd: snapshot?.cwd ?? entry.cwd,
17
+ native_thread_id: entry.threadId, host_id: entry.hostId, updated_at: new Date(entry.updatedAtMs).toISOString(),
18
+ catalog_membership: entry.catalogMembership, creator_originator: entry.originator,
19
+ ...(entry.sidebar ? { sidebar_section: entry.sidebar.section, sidebar_project_id: entry.sidebar.projectId,
20
+ sidebar_project_name: entry.sidebar.projectName } : {}),
21
+ connection_state: live ? "live_owner_verified" : "unconfirmed",
22
+ activity_state: snapshot?.runtimeStatus ?? "unknown",
23
+ ...sessionObservation(snapshot, writesVerified),
24
+ ...sessionSendAvailability(snapshot, writesVerified, observationError),
25
+ ...(observationError ? { observation_error: observationError } : {}), capabilities,
26
+ pending_async_count: interactions.filter(item => item.kind === "async_question").length,
27
+ pending_interaction_count: interactions.length,
28
+ interaction_state: interactions.map(item => desktopInteractionProjection(item, entry.conversationId)),
29
+ available_actions: sessionActions(entry.conversationId, { live, send, watch, cancel: writesVerified && watch }, activeTurn)
30
+ };
31
+ }
32
+ function sessionSendAvailability(snapshot, writesVerified, observationError) {
33
+ if (!snapshot)
34
+ return { can_send_reason: observationError ?? "live_owner_not_confirmed",
35
+ ...(observationError === "no_live_owner" ? {
36
+ manual_action: "Open this conversation in Desktop, then refresh AKK List. It is listed but cannot currently receive tasks."
37
+ } : {}) };
38
+ return { can_send_reason: !writesVerified ? "desktop_write_contract_unverified"
39
+ : snapshot.canSend ? "ready" : snapshot.idleBlockedReason ?? "desktop_not_sendable" };
40
+ }
41
+ /** Do not export prompts, internal owner IDs, callback configuration or raw native state. */
42
+ export function desktopTaskProjection(task, writesVerified = true) {
43
+ const terminal = desktopObservationStopped(task) || ["completed", "failed", "interrupted", "timed_out", "cancelled"].includes(task.status);
44
+ const interactions = writesVerified && !terminal ? actionableTaskInteractions(task) : [];
45
+ const notifications = notificationProjection(task);
46
+ const canCancel = writesVerified && !terminal && Boolean(task.native_turn_id);
47
+ const { recovery_actions, ...recovery } = backendTaskRecoveryProjection(task);
48
+ return {
49
+ watch_id: task.watch_id, conversation_id: task.desktop_id, source: "codex_desktop",
50
+ status: task.closed_at ? "closed" : task.status, observation_status: task.status,
51
+ ...recovery,
52
+ observation_mode: task.native_turn_id ? "exact_task" : "pending_acceptance",
53
+ anchor_state: task.native_turn_id ? "verified" : "pending", native_thread_id: task.target.threadId,
54
+ native_turn_id: task.native_turn_id ?? null, created_at: task.created_at, updated_at: task.updated_at,
55
+ observed_at: task.observed_at, observation_error: task.observation_error,
56
+ pending_manual_count: task.pending_manual_count, final_text: task.final_text,
57
+ ...taskInteractionCounts(task, interactions),
58
+ interaction_state: interactions.map(item => desktopInteractionProjection(item, task.desktop_id, task.watch_id)),
59
+ callback_expected: callbackExpected(task, terminal),
60
+ callback_configured: Boolean(task.callback_route), callback_notifications: notifications,
61
+ ...desktopSendReceiptProjection(task.send_intent),
62
+ capabilities: { callback: Boolean(task.callback_route), interaction_notify: Boolean(task.callback_route),
63
+ ...interactionCapabilities(interactions), cancel: canCancel, ...desktopRecoveryCapabilities(task) },
64
+ available_actions: { ...recovery_actions, status: { tool: "agent_knock_knock_status", input: { watch_id: task.watch_id } },
65
+ ...(canCancel ? { cancel: { tool: "agent_knock_knock_cancel", input: { watch_id: task.watch_id } } } : {}) },
66
+ ...(task.pending_manual_count ? { manual_action: terminal
67
+ ? "Handle any remaining question or approval in Desktop; this Watch has stopped."
68
+ : "Answer the question or approval in Desktop; AKK continues watching this task." } : {})
69
+ };
70
+ }
71
+ /** Keep task delivery evidence distinct from current interaction availability. */
72
+ function desktopSendReceiptProjection(intent) {
73
+ if (!intent)
74
+ return {};
75
+ const accepted = intent.state === "accepted";
76
+ return { message_id: intent.message_id, delivery_receipt: accepted ? "native_task_verified"
77
+ : intent.state === "not_sent" ? "not_sent" : "acceptance_unproven",
78
+ delivered: accepted, agent_acceptance: accepted ? "proven" : "unproven",
79
+ send_state: intent.state, send_error: intent.error_code, resend_allowed: false };
80
+ }
81
+ function actionableTaskInteractions(task) {
82
+ const items = task.pending_interactions ?? task.pending_async_interactions ?? [];
83
+ if (!task.observation_error)
84
+ return items;
85
+ // The owner request list is independently fresh even when async turn history is partial.
86
+ return task.observation_error === "desktop_async_questions_incomplete" ? items.filter(item => item.kind !== "async_question") : [];
87
+ }
88
+ function activeDesktopTurn(snapshot) {
89
+ if (!snapshot || snapshot.runtimeStatus !== "active" || !snapshot.tailKnown)
90
+ return undefined;
91
+ const active = snapshot.turns.filter(turn => turn.status === "inProgress");
92
+ return active.length === 1 && snapshot.latestTurnId === active[0].turnId ? active[0].turnId : undefined;
93
+ }
94
+ function interactionCapabilities(interactions) {
95
+ return { interaction_respond: interactions.some(item => !desktopInteractionIsApproval(item)),
96
+ approve: interactions.some(desktopInteractionIsApproval) };
97
+ }
98
+ function sessionObservation(snapshot, writesVerified) {
99
+ if (!snapshot)
100
+ return {};
101
+ const actionable = writesVerified ? (snapshot.pendingInteractions ?? []).filter(item => item.kind !== "async_question").length : 0;
102
+ return { native_turn_id: snapshot.latestTurnId, pending_manual_count: Math.max(0, snapshot.pendingRequestCount - actionable),
103
+ observed_revision: snapshot.revision };
104
+ }
105
+ function sessionActions(id, capabilities, activeTurn) {
106
+ const input = { conversation_id: id };
107
+ return { status: { tool: "agent_knock_knock_status", input },
108
+ ...(capabilities.send ? { send: { tool: "agent_knock_knock_send", input } } : {}),
109
+ ...(capabilities.watch ? { watch: { tool: "agent_knock_knock_watch", input } } : {}),
110
+ ...(capabilities.cancel ? { cancel: { tool: "agent_knock_knock_cancel", input: { ...input, expected_native_turn_id: activeTurn } } } : {}),
111
+ ...(capabilities.live ? { native_inspect: { tool: "agent_knock_knock_native_inspect", input: { ...input, inspection: "status" } },
112
+ permission_options: { tool: "agent_knock_knock_permission_options", input },
113
+ model_options: { tool: "agent_knock_knock_model_options", input } } : {}) };
114
+ }
115
+ function notificationProjection(task) {
116
+ return task.notifications.map(note => ({ id: note.id, notification_id: note.id, status: note.status, attempts: note.attempts,
117
+ ...(note.outcome && "error_code" in note.outcome ? { error_code: note.outcome.error_code } : {}) }));
118
+ }
119
+ function callbackExpected(task, terminal) {
120
+ return Boolean(task.callback_route && !desktopObservationStopped(task) &&
121
+ (!terminal || task.notifications.some(note => ["ready", "retry_wait", "leased"].includes(note.status))));
122
+ }
123
+ function taskInteractionCounts(task, items) {
124
+ return { pending_async_count: task.observation_error ? null : (task.pending_async_interactions ?? []).length,
125
+ async_interactions_state: task.observation_error ? "unknown" : "current",
126
+ pending_interaction_count: task.observation_error ? null : items.length };
127
+ }
128
+ function desktopRecoveryCapabilities(task) {
129
+ const stopped = desktopObservationStopped(task);
130
+ return { close: task.kind === "send" && !task.closed_at, unwatch: !stopped,
131
+ recover: !task.closed_at, renew: !task.closed_at && !["completed", "failed", "interrupted"].includes(task.status),
132
+ retry_callback: !stopped && task.notifications.some(notification => ["failed", "retry_wait"].includes(notification.status) && notification.outcome?.disposition === "retryable_failure") };
133
+ }
134
+ //# sourceMappingURL=desktop-public-projection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktop-public-projection.js","sourceRoot":"","sources":["../../src/desktop-public-projection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type DesktopInteraction, type DesktopRequestInteraction, type DesktopRequestResponse, type DesktopSnapshot, type DesktopTurn } from "./desktop-types.js";
2
+ export declare const desktopObject: (value: unknown) => value is Record<string, unknown>;
3
+ export declare function desktopNativeRequestId(value: unknown): string | number;
4
+ export declare function desktopRequestInteractionId(value: Omit<DesktopRequestInteraction, "id">): string;
5
+ export declare function parseDesktopRequestInteraction(raw: unknown, threadId: string, turns: DesktopTurn[]): DesktopRequestInteraction | null;
6
+ export declare function desktopInteractions(snapshot: DesktopSnapshot, turnId?: string): DesktopInteraction[];
7
+ export declare function desktopRequestResponse(interaction: DesktopRequestInteraction, response: DesktopRequestResponse): Record<string, unknown>;
8
+ export declare function findDesktopRequestEffect(snapshot: DesktopSnapshot, input: {
9
+ interaction: DesktopRequestInteraction;
10
+ response: DesktopRequestResponse;
11
+ }): {
12
+ evidence: "exact_blocking_answer_observed" | "exact_approval_item_advanced";
13
+ itemId: string;
14
+ } | null;
@@ -0,0 +1,144 @@
1
+ import { createHash } from "node:crypto";
2
+ import { isDeepStrictEqual } from "node:util";
3
+ import { desktopAsyncQuestions } from "./desktop-async-interactions.js";
4
+ import { DesktopIpcError } from "./desktop-types.js";
5
+ export const desktopObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
6
+ function invalid(message) { throw new DesktopIpcError("invalid_response", message); }
7
+ function text(value) {
8
+ if (typeof value !== "string" || !value || value.length > 16_384)
9
+ invalid("Invalid Desktop request string");
10
+ return value;
11
+ }
12
+ export function desktopNativeRequestId(value) {
13
+ if (typeof value === "string" && value.length > 0 && value.length <= 512)
14
+ return value;
15
+ if (typeof value === "number" && Number.isSafeInteger(value))
16
+ return value;
17
+ return invalid("Invalid Desktop native request identity");
18
+ }
19
+ export function desktopRequestInteractionId(value) {
20
+ const fields = [value.kind, value.threadId, value.turnId, value.itemId, value.method, value.requestId, value.questions,
21
+ value.command, value.reason, value.cwd, value.availableDecisions, value.approvalId, value.nativeApprovalKind, value.networkApprovalContext];
22
+ return `desktop-request-interaction:${createHash("sha256").update(JSON.stringify(fields)).digest("hex")}`;
23
+ }
24
+ function parseQuestions(value) {
25
+ if (!Array.isArray(value) || !value.length || value.length > 64)
26
+ invalid("Invalid Desktop blocking questions");
27
+ const ids = new Set();
28
+ return value.map(raw => {
29
+ if (!desktopObject(raw))
30
+ invalid("Invalid Desktop blocking question");
31
+ const id = text(raw.id);
32
+ if (ids.has(id))
33
+ invalid("Duplicate Desktop blocking question");
34
+ ids.add(id);
35
+ if (raw.options != null && (!Array.isArray(raw.options) || raw.options.length > 128))
36
+ invalid("Invalid Desktop blocking options");
37
+ const options = (raw.options ?? []).map(option => {
38
+ if (!desktopObject(option))
39
+ invalid("Invalid Desktop blocking option");
40
+ return text(option.label);
41
+ });
42
+ return { id, title: text(raw.question), options, isOther: raw.isOther === true, isSecret: raw.isSecret === true };
43
+ });
44
+ }
45
+ function approvalDetails(params, result) {
46
+ for (const key of ["command", "reason", "cwd", "approvalId"]) {
47
+ const value = params[key];
48
+ if (value == null)
49
+ continue;
50
+ if (typeof value !== "string" || value.length > 16_384)
51
+ invalid("Invalid Desktop approval detail");
52
+ result[key] = value;
53
+ }
54
+ if (params.availableDecisions != null) {
55
+ if (!Array.isArray(params.availableDecisions))
56
+ invalid("Invalid Desktop approval decisions");
57
+ result.availableDecisions = params.availableDecisions.filter((value) => typeof value === "string");
58
+ }
59
+ if (result.kind !== "command_approval")
60
+ return;
61
+ result.nativeApprovalKind = params.kind == null ? "command" : text(params.kind);
62
+ if (params.networkApprovalContext != null) {
63
+ if (!desktopObject(params.networkApprovalContext))
64
+ invalid("Invalid Desktop network approval");
65
+ result.networkApprovalContext = { host: text(params.networkApprovalContext.host), protocol: text(params.networkApprovalContext.protocol) };
66
+ }
67
+ }
68
+ const requestKinds = new Map([
69
+ ["item/commandExecution/requestApproval", "command_approval"], ["item/fileChange/requestApproval", "file_approval"],
70
+ ["item/tool/requestUserInput", "blocking_question"]
71
+ ]);
72
+ export function parseDesktopRequestInteraction(raw, threadId, turns) {
73
+ if (!desktopObject(raw) || typeof raw.method !== "string")
74
+ return null;
75
+ const kind = requestKinds.get(raw.method);
76
+ if (!kind)
77
+ return null;
78
+ if (!desktopObject(raw.params))
79
+ return null;
80
+ const params = raw.params;
81
+ if (params.threadId === undefined || typeof params.turnId !== "string" || typeof params.itemId !== "string")
82
+ return null;
83
+ if (params.threadId !== threadId)
84
+ invalid("Desktop request belongs to a different thread");
85
+ const result = { id: "", kind, method: raw.method, requestId: desktopNativeRequestId(raw.id),
86
+ threadId, turnId: text(params.turnId), itemId: text(params.itemId), questions: kind === "blocking_question" ? parseQuestions(params.questions) : [] };
87
+ approvalDetails(params, result);
88
+ result.id = desktopRequestInteractionId(result);
89
+ const item = turns.find(turn => turn.turnId === result.turnId)?.items.find(item => item.id === result.itemId);
90
+ if (kind === "file_approval" && item?.type === "fileChange" && item.changes)
91
+ result.changes = item.changes;
92
+ return result;
93
+ }
94
+ export function desktopInteractions(snapshot, turnId) {
95
+ const requests = (snapshot.pendingInteractions ?? []).filter((item) => item.kind !== "async_question");
96
+ return [...requests, ...desktopAsyncQuestions(snapshot, turnId)].filter(item => turnId === undefined || item.turnId === turnId);
97
+ }
98
+ export function desktopRequestResponse(interaction, response) {
99
+ if (interaction.kind !== "blocking_question" && "decision" in response && ["accept", "decline", "cancel"].includes(response.decision)) {
100
+ return { decision: response.decision };
101
+ }
102
+ if (interaction.kind !== "blocking_question" || !("answers" in response) || !desktopObject(response.answers)
103
+ || Object.keys(response.answers).length !== interaction.questions.length)
104
+ throw new DesktopIpcError("invalid_argument", "Response does not match Desktop request");
105
+ const answers = Object.create(null);
106
+ for (const question of interaction.questions) {
107
+ answers[question.id] = { answers: blockingAnswer(question, response.answers[question.id]) };
108
+ }
109
+ return { answers };
110
+ }
111
+ function blockingAnswer(question, values) {
112
+ if (!Array.isArray(values) || !values.length || values.length > 100 || values.some(value => typeof value !== "string"
113
+ || !value.trim() || value.length > 16_384 || (!question.isOther && question.options.length > 0 && !question.options.includes(value)))) {
114
+ throw new DesktopIpcError("invalid_argument", "Invalid Desktop blocking answer");
115
+ }
116
+ return values;
117
+ }
118
+ function blockingEffect(turn, interaction, answers) {
119
+ const matches = turn.items.filter(item => item.type === "userInputResponse" && item.completed === true
120
+ && item.requestId === interaction.requestId && item.turnId === interaction.turnId && item.answers !== undefined
121
+ && isDeepStrictEqual(Object.entries(item.answers).sort(), Object.entries(answers).sort()));
122
+ return matches.length === 1 ? matches[0].id : undefined;
123
+ }
124
+ export function findDesktopRequestEffect(snapshot, input) {
125
+ const { interaction, response } = input;
126
+ if (snapshot.threadId !== interaction.threadId)
127
+ return null;
128
+ const turn = snapshot.turns.find(turn => turn.turnId === interaction.turnId);
129
+ if (!turn?.itemsComplete)
130
+ return null;
131
+ if (snapshot.pendingRequests.some(request => request.requestId === interaction.requestId && request.method === interaction.method))
132
+ return null;
133
+ if (interaction.kind === "blocking_question" && "answers" in response) {
134
+ const itemId = blockingEffect(turn, interaction, response.answers);
135
+ return itemId ? { evidence: "exact_blocking_answer_observed", itemId } : null;
136
+ }
137
+ if (!("decision" in response))
138
+ return null;
139
+ const item = turn.items.find(item => item.id === interaction.itemId
140
+ && item.type === (interaction.kind === "command_approval" ? "commandExecution" : "fileChange"));
141
+ const expected = response.decision === "accept" ? ["completed", "failed"] : ["declined"];
142
+ return item?.status && expected.includes(item.status) ? { evidence: "exact_approval_item_advanced", itemId: item.id } : null;
143
+ }
144
+ //# sourceMappingURL=desktop-request-interactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktop-request-interactions.js","sourceRoot":"","sources":["../../src/desktop-request-interactions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,eAAe,EAC+C,MAAM,oBAAoB,CAAC;AAElG,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAc,EAAoC,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACxJ,SAAS,OAAO,CAAC,OAAe,IAAW,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACpG,SAAS,IAAI,CAAC,KAAc;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM;QAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAC5G,OAAO,KAAK,CAAC;AACf,CAAC;AACD,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,KAAK,CAAC;IACvF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3E,OAAO,OAAO,CAAC,yCAAyC,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAA4C;IACtF,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS;QACpH,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC9I,OAAO,+BAA+B,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAC5G,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,CAAC,oCAAoC,CAAC,CAAC;IAC/G,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QACrB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,mCAAmC,CAAC,CAAC;QACtE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO,CAAC,qCAAqC,CAAC,CAAC;QAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7E,IAAI,GAAG,CAAC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC;YAAE,OAAO,CAAC,kCAAkC,CAAC,CAAC;QAClI,MAAM,OAAO,GAAI,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC9D,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;gBAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;YAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACpG,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;IACpH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,MAA+B,EAAE,MAAiC;IACzF,KAAK,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,CAAU,EAAE,CAAC;QACtE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,KAAK,IAAI,IAAI;YAAE,SAAS;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM;YAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;QACnG,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;IACD,IAAI,MAAM,CAAC,kBAAkB,IAAI,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAAE,OAAO,CAAC,oCAAoC,CAAC,CAAC;QAC7F,MAAM,CAAC,kBAAkB,GAAG,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;IACtH,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB;QAAE,OAAO;IAC/C,MAAM,CAAC,kBAAkB,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,MAAM,CAAC,sBAAsB,IAAI,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,sBAAsB,CAAC;YAAE,OAAO,CAAC,kCAAkC,CAAC,CAAC;QAC/F,MAAM,CAAC,sBAAsB,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC7I,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAA4C;IACtE,CAAC,uCAAuC,EAAE,kBAAkB,CAAC,EAAE,CAAC,iCAAiC,EAAE,eAAe,CAAC;IACnH,CAAC,4BAA4B,EAAE,mBAAmB,CAAC;CACpD,CAAC,CAAC;AACH,MAAM,UAAU,8BAA8B,CAAC,GAAY,EAAE,QAAgB,EAAE,KAAoB;IACjG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvE,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAClE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzH,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,CAAC,+CAA+C,CAAC,CAAC;IAC3F,MAAM,MAAM,GAA8B,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,sBAAsB,CAAC,GAAG,CAAC,EAAE,CAAC;QACrH,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACxJ,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9G,IAAI,IAAI,KAAK,eAAe,IAAI,IAAI,EAAE,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC3G,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAyB,EAAE,MAAe;IAC5E,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAqC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;IAC1I,OAAO,CAAC,GAAG,QAAQ,EAAE,GAAG,qBAAqB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AAClI,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,WAAsC,EAAE,QAAgC;IAC7G,IAAI,WAAW,CAAC,IAAI,KAAK,mBAAmB,IAAI,UAAU,IAAI,QAAQ,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtI,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC;IACzC,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,KAAK,mBAAmB,IAAI,CAAC,CAAC,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC;WACvG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,SAAS,CAAC,MAAM;QAAE,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,yCAAyC,CAAC,CAAC;IACrK,MAAM,OAAO,GAA0C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3E,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,SAAS,EAAE,CAAC;QAC7C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC9F,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AACD,SAAS,cAAc,CAAC,QAAyB,EAAE,MAAe;IAChE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ;WAChH,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACxI,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,iCAAiC,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,IAAiB,EAAE,WAAsC,EAAE,OAAiC;IAClH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;WACjG,IAAI,CAAC,SAAS,KAAK,WAAW,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;WAC5G,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7F,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,QAAyB,EAAE,KAEnE;IACC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACxC,IAAI,QAAQ,CAAC,QAAQ,KAAK,WAAW,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC5D,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7E,IAAI,CAAC,IAAI,EAAE,aAAa;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,WAAW,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAChJ,IAAI,WAAW,CAAC,IAAI,KAAK,mBAAmB,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;QACtE,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;QACnE,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,gCAAgC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,WAAW,CAAC,MAAM;WAC9D,IAAI,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;IAClG,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACzF,OAAO,IAAI,EAAE,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,8BAA8B,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/H,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { DesktopResponseDependencies } from "./desktop-response-types.js";
2
+ import type { DesktopResponseRecord } from "./desktop-response-store.js";
3
+ import type { DesktopSnapshot, DesktopThreadIdentity } from "./desktop-types.js";
4
+ interface DispatchOptions {
5
+ threadId: string;
6
+ ownerClientId: string;
7
+ expectedRevision: number;
8
+ expectedTurnId: string;
9
+ interactionId: string;
10
+ beforeDispatch(snapshot: DesktopSnapshot): Promise<void>;
11
+ }
12
+ /** These acknowledgements mean sent; the durable service separately verifies native effects. */
13
+ export declare function dispatchDesktopResponse(deps: DesktopResponseDependencies, target: DesktopThreadIdentity, record: DesktopResponseRecord, options: DispatchOptions): Promise<void>;
14
+ export {};
@@ -0,0 +1,19 @@
1
+ import { DesktopTaskError } from "./desktop-task-service.js";
2
+ /** These acknowledgements mean sent; the durable service separately verifies native effects. */
3
+ export async function dispatchDesktopResponse(deps, target, record, options) {
4
+ if (record.interaction.kind === "async_question") {
5
+ const receipt = await deps.answerAsync(target, { ...options, answer: record.answer, clientUserMessageId: record.client_user_message_id });
6
+ if (receipt.turnId !== record.interaction.turnId || receipt.clientUserMessageId !== record.client_user_message_id) {
7
+ throw new Error("Desktop async response receipt changed exact task identity");
8
+ }
9
+ return;
10
+ }
11
+ if (!deps.respondRequest)
12
+ throw new DesktopTaskError("unsupported_capability", "Desktop request responses are unavailable", "not_sent");
13
+ const receipt = await deps.respondRequest(target, { ...options, operationId: record.operation_id, response: record.response });
14
+ if (receipt.turnId !== record.interaction.turnId || receipt.interactionId !== record.interaction.id ||
15
+ receipt.requestId !== record.interaction.requestId || receipt.acknowledged !== true) {
16
+ throw new Error("Desktop native response receipt changed exact request identity");
17
+ }
18
+ }
19
+ //# sourceMappingURL=desktop-response-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktop-response-dispatch.js","sourceRoot":"","sources":["../../src/desktop-response-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAc7D,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,IAAiC,EAAE,MAA6B,EAC5G,MAA6B,EAAE,OAAwB;IACvD,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAO,EAAE,mBAAmB,EAAE,MAAM,CAAC,sBAAuB,EAAE,CAAC,CAAC;QAC5I,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,OAAO,CAAC,mBAAmB,KAAK,MAAM,CAAC,sBAAsB,EAAE,CAAC;YAClH,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,cAAc;QAAE,MAAM,IAAI,gBAAgB,CAAC,wBAAwB,EAAE,2CAA2C,EAAE,UAAU,CAAC,CAAC;IACxI,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,YAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAS,EAAE,CAAC,CAAC;IACjI,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,OAAO,CAAC,aAAa,KAAK,MAAM,CAAC,WAAW,CAAC,EAAE;QACjG,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC,WAAW,CAAC,SAAS,IAAI,OAAO,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QACtF,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { DesktopResponseRecord } from "./desktop-response-store.js";
2
+ import type { DesktopSnapshot } from "./desktop-types.js";
3
+ /** A transport acknowledgement or disappearing prompt alone never confirms a response. */
4
+ export declare function desktopResponseEvidence(record: DesktopResponseRecord, snapshot: DesktopSnapshot): DesktopResponseRecord["evidence"];
@@ -0,0 +1,19 @@
1
+ import { findDesktopAsyncAnswer } from "./desktop-async-interactions.js";
2
+ import { findDesktopRequestEffect } from "./desktop-request-interactions.js";
3
+ /** A transport acknowledgement or disappearing prompt alone never confirms a response. */
4
+ export function desktopResponseEvidence(record, snapshot) {
5
+ if (record.interaction.kind === "async_question") {
6
+ return findDesktopAsyncAnswer(snapshot, { turnId: record.interaction.turnId, interaction: record.interaction,
7
+ answer: record.answer, clientUserMessageId: record.client_user_message_id }) ? "exact_async_answer_observed" : undefined;
8
+ }
9
+ const effect = findDesktopRequestEffect(snapshot, { interaction: record.interaction, response: record.response });
10
+ if (!effect)
11
+ return undefined;
12
+ if (effect.evidence === "exact_blocking_answer_observed")
13
+ return effect.evidence;
14
+ const turn = snapshot.turns.find(candidate => candidate.turnId === record.interaction.turnId);
15
+ const item = turn?.items.find(candidate => candidate.id === effect.itemId);
16
+ // The item must actually advance after this answer intent, not merely have an old terminal status.
17
+ return item?.status !== undefined && item.status !== record.baseline_item_status ? effect.evidence : undefined;
18
+ }
19
+ //# sourceMappingURL=desktop-response-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktop-response-evidence.js","sourceRoot":"","sources":["../../src/desktop-response-evidence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAI7E,0FAA0F;AAC1F,MAAM,UAAU,uBAAuB,CAAC,MAA6B,EAAE,QAAyB;IAC9F,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACjD,OAAO,sBAAsB,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW;YAC1G,MAAM,EAAE,MAAM,CAAC,MAAO,EAAE,mBAAmB,EAAE,MAAM,CAAC,sBAAuB,EAAE,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/H,CAAC;IACD,MAAM,MAAM,GAAG,wBAAwB,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAS,EAAE,CAAC,CAAC;IACnH,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,MAAM,CAAC,QAAQ,KAAK,gCAAgC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IACjF,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9F,MAAM,IAAI,GAAG,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3E,mGAAmG;IACnG,OAAO,IAAI,EAAE,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AACjH,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type DesktopResponseRecord } from "./desktop-response-store.js";
2
+ import type { DesktopResponseDependencies, DesktopResponseInput } from "./desktop-response-types.js";
3
+ export type { DesktopResponseDependencies, DesktopResponseInput } from "./desktop-response-types.js";
4
+ /** One durable answer per native question, shared across direct and Watch response routes. */
5
+ export declare function createDesktopResponseService(deps: DesktopResponseDependencies): {
6
+ respond: (input: DesktopResponseInput) => Promise<DesktopResponseRecord>;
7
+ reconcile: (id: string) => Promise<DesktopResponseRecord>;
8
+ status: (id: string) => DesktopResponseRecord;
9
+ list: () => DesktopResponseRecord[];
10
+ respondWatch(watchId: string, input: Omit<DesktopResponseInput, "target" | "desktopId">): Promise<DesktopResponseRecord>;
11
+ };
@@ -0,0 +1,188 @@
1
+ import { backendObservationStopped } from "./backend-task-recovery.js";
2
+ import { randomUUID } from "node:crypto";
3
+ import { isDeepStrictEqual } from "node:util";
4
+ import { desktopNonblank } from "./desktop-async-state.js";
5
+ import { desktopInteractions } from "./desktop-request-interactions.js";
6
+ import { assertDesktopInteraction, persistDesktopInteraction } from "./desktop-interaction-state.js";
7
+ import { desktopResponseEvidence } from "./desktop-response-evidence.js";
8
+ import { dispatchDesktopResponse } from "./desktop-response-dispatch.js";
9
+ import { validateDesktopResponseValue } from "./desktop-response-value.js";
10
+ import { assertDesktopResponseIdentity, desktopResponseId } from "./desktop-response-store.js";
11
+ import { DesktopTaskError } from "./desktop-task-service.js";
12
+ function errorCode(error) {
13
+ const code = error?.code;
14
+ return typeof code === "string" && /^[a-zA-Z0-9_-]{1,100}$/.test(code) ? code : "desktop_response_observation_unavailable";
15
+ }
16
+ function currentInteraction(snapshot, input, expectedTurnId) {
17
+ const interactions = desktopInteractions(snapshot).filter(candidate => candidate.id === input.interactionId && candidate.threadId === input.target.threadId);
18
+ const interaction = interactions.length === 1 ? interactions[0] : undefined;
19
+ const active = snapshot.turns.filter(turn => turn.status === "inProgress");
20
+ if (snapshot.threadId !== input.target.threadId || !snapshot.ownerClientId || snapshot.runtimeStatus !== "active" ||
21
+ !snapshot.tailKnown || !interaction || active.length !== 1 || active[0].turnId !== interaction.turnId ||
22
+ snapshot.latestTurnId !== interaction.turnId || expectedTurnId && interaction.turnId !== expectedTurnId) {
23
+ throw new DesktopTaskError("stale_interaction", "The exact Desktop interaction is no longer active", "not_sent");
24
+ }
25
+ assertDesktopInteraction(interaction, input.target, expectedTurnId);
26
+ return interaction;
27
+ }
28
+ function assertInput(input) {
29
+ assertDesktopResponseIdentity(input.desktopId, input.target);
30
+ if (![input.controllerSession, input.interactionId, input.responseId].every(desktopNonblank)) {
31
+ throw new DesktopTaskError("invalid_argument", "Desktop response requires controller, interaction and response ID");
32
+ }
33
+ }
34
+ function assertDuplicate(record, input, expectedTurnId) {
35
+ if (record.controller_session !== input.controllerSession || record.desktop_id !== input.desktopId ||
36
+ record.interaction.id !== input.interactionId || record.answer !== input.answer || !isDeepStrictEqual(record.response, input.response) ||
37
+ expectedTurnId && record.interaction.turnId !== expectedTurnId) {
38
+ throw new DesktopTaskError("desktop_response_conflict", "This Desktop interaction already has a different response intent");
39
+ }
40
+ }
41
+ function itemStatus(snapshot, interaction) {
42
+ return snapshot.turns.find(turn => turn.turnId === interaction.turnId)?.items.find(item => item.id === interaction.itemId)?.status;
43
+ }
44
+ /** One durable answer per native question, shared across direct and Watch response routes. */
45
+ export function createDesktopResponseService(deps) {
46
+ const repo = deps.repository;
47
+ const now = deps.now ?? (() => new Date());
48
+ const uuid = deps.randomUUID ?? randomUUID;
49
+ function status(id) {
50
+ const record = repo.load(id);
51
+ if (!record)
52
+ throw new DesktopTaskError("desktop_response_not_found", "Desktop response was not found");
53
+ return record;
54
+ }
55
+ function update(id, operation) {
56
+ return repo.withLock(id, () => {
57
+ const record = status(id);
58
+ operation(record);
59
+ record.updated_at = now().toISOString();
60
+ return repo.save(record, record.revision);
61
+ });
62
+ }
63
+ async function reconcile(id) {
64
+ const previous = status(id);
65
+ if (["confirmed", "not_sent", "reserved"].includes(previous.state))
66
+ return previous;
67
+ let snapshot;
68
+ try {
69
+ snapshot = await deps.observe(previous.target);
70
+ }
71
+ catch (error) {
72
+ return update(id, record => { if (record.state !== "confirmed")
73
+ record.error_code = errorCode(error); });
74
+ }
75
+ if (snapshot.threadId !== previous.target.threadId)
76
+ throw new DesktopTaskError("desktop_identity_mismatch", "Desktop response observation changed thread");
77
+ const evidence = desktopResponseEvidence(previous, snapshot);
78
+ return update(id, record => {
79
+ if (!evidence || !["sent", "uncertain"].includes(record.state))
80
+ return;
81
+ record.state = "confirmed";
82
+ record.evidence = evidence;
83
+ delete record.error_code;
84
+ });
85
+ }
86
+ function reserve(input, interaction, snapshot) {
87
+ const id = desktopResponseId(input.target, input.interactionId);
88
+ const date = now().toISOString();
89
+ return repo.withLock(id, () => {
90
+ const existing = repo.load(id);
91
+ if (existing) {
92
+ assertDuplicate(existing, input);
93
+ if (existing.state !== "not_sent")
94
+ return { record: existing, claimed: false };
95
+ existing.not_sent_history = [...(existing.not_sent_history ?? []), { attempt: existing.attempts, observed_at: existing.updated_at,
96
+ ...(existing.error_code ? { error_code: existing.error_code } : {}),
97
+ ...(existing.baseline_item_status !== undefined ? { baseline_item_status: existing.baseline_item_status } : {}) }];
98
+ if (interaction.kind !== "async_question")
99
+ existing.baseline_item_status = itemStatus(snapshot, interaction);
100
+ existing.state = "reserved";
101
+ existing.attempts++;
102
+ existing.updated_at = date;
103
+ delete existing.error_code;
104
+ return { record: repo.save(existing, existing.revision), claimed: true };
105
+ }
106
+ const record = { schema: "agent-knock-knock/desktop-response", version: 1, revision: 1, id,
107
+ created_at: date, updated_at: date, target: structuredClone(input.target), desktop_id: input.desktopId,
108
+ controller_session: input.controllerSession, response_id: input.responseId, interaction: persistDesktopInteraction(interaction),
109
+ ...(interaction.kind === "async_question" ? { answer: input.answer, client_user_message_id: uuid() }
110
+ : { response: structuredClone(input.response), operation_id: uuid(), baseline_item_status: itemStatus(snapshot, interaction) }),
111
+ state: "reserved", attempts: 1 };
112
+ return { record: repo.save(record, null), claimed: true };
113
+ });
114
+ }
115
+ function withWatch(watchId, input, operation) {
116
+ if (!watchId)
117
+ return operation();
118
+ return deps.tasks.withLock(watchId, () => {
119
+ const task = deps.tasks.load(watchId);
120
+ if (!task || task.controller_session !== input.controllerSession)
121
+ throw new DesktopTaskError("desktop_controller_mismatch", "Watch response requires its owning controller", "not_sent");
122
+ if (backendObservationStopped(task))
123
+ throw new DesktopTaskError("desktop_watch_stopped", "Desktop Watch observation has stopped", "not_sent");
124
+ return operation();
125
+ });
126
+ }
127
+ async function dispatch(input, snapshot, record, watchId) {
128
+ try {
129
+ const options = { threadId: input.target.threadId, ownerClientId: snapshot.ownerClientId,
130
+ expectedRevision: snapshot.revision, expectedTurnId: record.interaction.turnId, interactionId: record.interaction.id,
131
+ beforeDispatch: async (fresh) => {
132
+ const question = currentInteraction(fresh, input, record.interaction.turnId);
133
+ if (fresh.ownerClientId !== snapshot.ownerClientId || fresh.revision < snapshot.revision || question.id !== record.interaction.id) {
134
+ throw new DesktopTaskError("snapshot_changed", "Desktop interaction changed before response dispatch", "not_sent");
135
+ }
136
+ withWatch(watchId, input, () => update(record.id, current => {
137
+ if (current.state !== "reserved")
138
+ throw new DesktopTaskError("desktop_response_already_claimed", "Desktop response was already dispatched", "not_sent");
139
+ current.state = "uncertain";
140
+ }));
141
+ } };
142
+ await dispatchDesktopResponse(deps, input.target, record, options);
143
+ update(record.id, current => { if (current.state !== "confirmed")
144
+ current.state = "sent"; });
145
+ }
146
+ catch (error) {
147
+ update(record.id, current => {
148
+ if (current.state === "confirmed")
149
+ return;
150
+ current.state = error?.dispatchState === "not_sent" ? "not_sent" : "uncertain";
151
+ current.error_code = errorCode(error);
152
+ });
153
+ }
154
+ }
155
+ async function respond(input, expectedTurnId, watchId) {
156
+ assertInput(input);
157
+ withWatch(watchId, input, () => undefined);
158
+ const id = desktopResponseId(input.target, input.interactionId);
159
+ const previous = repo.load(id);
160
+ if (previous) {
161
+ assertDuplicate(previous, input, expectedTurnId);
162
+ if (previous.state !== "not_sent")
163
+ return reconcile(id);
164
+ }
165
+ const snapshot = await deps.observe(input.target);
166
+ const interaction = currentInteraction(snapshot, input, expectedTurnId);
167
+ validateDesktopResponseValue(interaction, input);
168
+ const reserved = withWatch(watchId, input, () => reserve(input, interaction, snapshot));
169
+ if (!reserved.claimed)
170
+ return reserved.record;
171
+ await dispatch(input, snapshot, reserved.record, watchId);
172
+ return reconcile(id);
173
+ }
174
+ return {
175
+ respond: (input) => respond(input), reconcile, status, list: () => repo.list(),
176
+ async respondWatch(watchId, input) {
177
+ const task = deps.tasks.load(watchId);
178
+ if (!task || task.controller_session !== input.controllerSession)
179
+ throw new DesktopTaskError("desktop_controller_mismatch", "Watch response requires its owning controller");
180
+ if (backendObservationStopped(task))
181
+ throw new DesktopTaskError("desktop_watch_stopped", "Desktop Watch observation has stopped", "not_sent");
182
+ if (!task.native_turn_id)
183
+ throw new DesktopTaskError("stale_interaction", "Desktop Watch has no exact task anchor");
184
+ return respond({ ...input, target: task.target, desktopId: task.desktop_id }, task.native_turn_id, watchId);
185
+ }
186
+ };
187
+ }
188
+ //# sourceMappingURL=desktop-response-service.js.map