@ashx-j/lunr 0.2.25 → 0.2.26

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 (220) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/dist/builtin-extensions/index.d.ts.map +1 -1
  3. package/dist/builtin-extensions/index.js +1 -0
  4. package/dist/builtin-extensions/index.js.map +1 -1
  5. package/dist/builtin-extensions/lunr-computer-use.d.ts +3 -0
  6. package/dist/builtin-extensions/lunr-computer-use.d.ts.map +1 -0
  7. package/dist/builtin-extensions/lunr-computer-use.js +179 -0
  8. package/dist/builtin-extensions/lunr-computer-use.js.map +1 -0
  9. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  10. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +1 -1
  11. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  12. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -4
  13. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +8 -5
  15. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  16. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts +1 -0
  17. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +11 -2
  19. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
  20. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +3 -3
  22. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  23. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +15 -1
  25. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.d.ts +1 -0
  27. package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.d.ts.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.js +5 -0
  29. package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.js.map +1 -1
  30. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +1 -1
  31. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -1
  32. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +2 -0
  33. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -1
  34. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -1
  35. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +1 -1
  36. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -1
  37. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +1 -0
  38. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +5 -3
  40. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  41. package/dist/core/computer-use/adapter.d.ts +28 -0
  42. package/dist/core/computer-use/adapter.d.ts.map +1 -0
  43. package/dist/core/computer-use/adapter.js +133 -0
  44. package/dist/core/computer-use/adapter.js.map +1 -0
  45. package/dist/core/computer-use/image.d.ts +27 -0
  46. package/dist/core/computer-use/image.d.ts.map +1 -0
  47. package/dist/core/computer-use/image.js +72 -0
  48. package/dist/core/computer-use/image.js.map +1 -0
  49. package/dist/core/computer-use/lease.d.ts +18 -0
  50. package/dist/core/computer-use/lease.d.ts.map +1 -0
  51. package/dist/core/computer-use/lease.js +129 -0
  52. package/dist/core/computer-use/lease.js.map +1 -0
  53. package/dist/core/computer-use/macos-runtime.d.ts +14 -0
  54. package/dist/core/computer-use/macos-runtime.d.ts.map +1 -0
  55. package/dist/core/computer-use/macos-runtime.js +148 -0
  56. package/dist/core/computer-use/macos-runtime.js.map +1 -0
  57. package/dist/core/computer-use/policy.d.ts +19 -0
  58. package/dist/core/computer-use/policy.d.ts.map +1 -0
  59. package/dist/core/computer-use/policy.js +67 -0
  60. package/dist/core/computer-use/policy.js.map +1 -0
  61. package/dist/core/computer-use/release.generated.d.ts +31 -0
  62. package/dist/core/computer-use/release.generated.d.ts.map +1 -0
  63. package/dist/core/computer-use/release.generated.js +36 -0
  64. package/dist/core/computer-use/release.generated.js.map +1 -0
  65. package/dist/core/computer-use/runtime.d.ts +13 -0
  66. package/dist/core/computer-use/runtime.d.ts.map +1 -0
  67. package/dist/core/computer-use/runtime.js +158 -0
  68. package/dist/core/computer-use/runtime.js.map +1 -0
  69. package/dist/core/computer-use/schemas.d.ts +100 -0
  70. package/dist/core/computer-use/schemas.d.ts.map +1 -0
  71. package/dist/core/computer-use/schemas.js +79 -0
  72. package/dist/core/computer-use/schemas.js.map +1 -0
  73. package/dist/core/computer-use/windows-desktop.d.ts +3 -0
  74. package/dist/core/computer-use/windows-desktop.d.ts.map +1 -0
  75. package/dist/core/computer-use/windows-desktop.js +48 -0
  76. package/dist/core/computer-use/windows-desktop.js.map +1 -0
  77. package/dist/core/computer-use/workflow.d.ts +38 -0
  78. package/dist/core/computer-use/workflow.d.ts.map +1 -0
  79. package/dist/core/computer-use/workflow.js +560 -0
  80. package/dist/core/computer-use/workflow.js.map +1 -0
  81. package/dist/core/extensions/loader.d.ts.map +1 -1
  82. package/dist/core/extensions/loader.js +4 -0
  83. package/dist/core/extensions/loader.js.map +1 -1
  84. package/dist/core/permissions.d.ts +1 -1
  85. package/dist/core/permissions.d.ts.map +1 -1
  86. package/dist/core/permissions.js +14 -3
  87. package/dist/core/permissions.js.map +1 -1
  88. package/dist/core/plan-mode.d.ts.map +1 -1
  89. package/dist/core/plan-mode.js +9 -0
  90. package/dist/core/plan-mode.js.map +1 -1
  91. package/dist/core/settings-manager.d.ts +6 -0
  92. package/dist/core/settings-manager.d.ts.map +1 -1
  93. package/dist/core/settings-manager.js +19 -0
  94. package/dist/core/settings-manager.js.map +1 -1
  95. package/dist/core/subagent-event-transport.d.ts +3 -0
  96. package/dist/core/subagent-event-transport.d.ts.map +1 -0
  97. package/dist/core/subagent-event-transport.js +61 -0
  98. package/dist/core/subagent-event-transport.js.map +1 -0
  99. package/dist/gateway/adapters/discord.d.ts.map +1 -1
  100. package/dist/gateway/adapters/discord.js +2 -2
  101. package/dist/gateway/adapters/discord.js.map +1 -1
  102. package/dist/gateway/approval.d.ts.map +1 -1
  103. package/dist/gateway/approval.js +3 -3
  104. package/dist/gateway/approval.js.map +1 -1
  105. package/dist/gateway/authz.d.ts +4 -4
  106. package/dist/gateway/authz.d.ts.map +1 -1
  107. package/dist/gateway/authz.js +8 -12
  108. package/dist/gateway/authz.js.map +1 -1
  109. package/dist/gateway/commands.d.ts.map +1 -1
  110. package/dist/gateway/commands.js +2 -6
  111. package/dist/gateway/commands.js.map +1 -1
  112. package/dist/gateway/cron.d.ts.map +1 -1
  113. package/dist/gateway/cron.js +20 -6
  114. package/dist/gateway/cron.js.map +1 -1
  115. package/dist/gateway/index.d.ts.map +1 -1
  116. package/dist/gateway/index.js +3 -3
  117. package/dist/gateway/index.js.map +1 -1
  118. package/dist/gateway/mobile-commands.d.ts.map +1 -1
  119. package/dist/gateway/mobile-commands.js +8 -8
  120. package/dist/gateway/mobile-commands.js.map +1 -1
  121. package/dist/gateway/presenter.d.ts.map +1 -1
  122. package/dist/gateway/presenter.js +3 -3
  123. package/dist/gateway/presenter.js.map +1 -1
  124. package/dist/gateway/router.d.ts.map +1 -1
  125. package/dist/gateway/router.js +5 -7
  126. package/dist/gateway/router.js.map +1 -1
  127. package/dist/gateway/setup.d.ts.map +1 -1
  128. package/dist/gateway/setup.js +6 -4
  129. package/dist/gateway/setup.js.map +1 -1
  130. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  131. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  132. package/dist/modes/interactive/components/settings-selector.js +20 -0
  133. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  134. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  135. package/dist/modes/interactive/interactive-mode.js +8 -0
  136. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  137. package/dist/modes/print-mode.d.ts.map +1 -1
  138. package/dist/modes/print-mode.js +9 -1
  139. package/dist/modes/print-mode.js.map +1 -1
  140. package/dist/node-runtime/adapter-VFG7WNPX.js +17 -0
  141. package/dist/node-runtime/{agent-session-services-YXXFCP5J.js → agent-session-services-5YXS2PLF.js} +10 -8
  142. package/dist/node-runtime/{builtin-extensions-ZLAX7TUH.js → builtin-extensions-I2HIFEMY.js} +3 -2
  143. package/dist/node-runtime/{chunk-3XPLBUEM.js → chunk-2CFDTH5B.js} +7 -3
  144. package/dist/node-runtime/chunk-2IDTZAG5.js +1415 -0
  145. package/dist/node-runtime/{chunk-QTU6AKNJ.js → chunk-3MISGG4S.js} +11 -15
  146. package/dist/node-runtime/chunk-4SBQAI4T.js +2185 -0
  147. package/dist/node-runtime/{chunk-TORR5XBV.js → chunk-5B5QN3ZQ.js} +12 -12
  148. package/dist/node-runtime/chunk-5B6VKFEV.js +180 -0
  149. package/dist/node-runtime/{chunk-AD6VXAO7.js → chunk-5Q4A37RB.js} +15 -104
  150. package/dist/node-runtime/{chunk-4TLO4PO2.js → chunk-7IQGBKBJ.js} +7 -1401
  151. package/dist/node-runtime/{chunk-OCVIXVTZ.js → chunk-D5UCKPBQ.js} +12 -1
  152. package/dist/node-runtime/{chunk-7S3T6YEA.js → chunk-DVQSHCVP.js} +1 -1
  153. package/dist/node-runtime/{chunk-HFVZUPFJ.js → chunk-E75WFZ33.js} +2 -2
  154. package/dist/node-runtime/chunk-FY4A63RK.js +73 -0
  155. package/dist/node-runtime/{chunk-6XL67VVY.js → chunk-I74LN5JG.js} +15 -0
  156. package/dist/node-runtime/chunk-IKU6Y7DL.js +287 -0
  157. package/dist/node-runtime/{chunk-WF7PGWRZ.js → chunk-L24TPBS4.js} +5 -4
  158. package/dist/node-runtime/{chunk-VQFSUJJG.js → chunk-LJTIVM7I.js} +7 -7
  159. package/dist/node-runtime/{chunk-DSIKTUPW.js → chunk-LWJXTA6Z.js} +274 -2433
  160. package/dist/node-runtime/{chunk-E4D3IGP2.js → chunk-P7XBVXGT.js} +6 -7
  161. package/dist/node-runtime/{chunk-OVX6X377.js → chunk-PTFBPO3C.js} +1 -1
  162. package/dist/node-runtime/{chunk-RC7DMV45.js → chunk-RCR3XAQY.js} +34 -6
  163. package/dist/node-runtime/chunk-RGQAEOM5.js +81 -0
  164. package/dist/node-runtime/{chunk-YCUZEGJG.js → chunk-SN2KSMPQ.js} +6 -3
  165. package/dist/node-runtime/{chunk-NRKGMJYU.js → chunk-SPVDBUOS.js} +1 -1
  166. package/dist/node-runtime/{chunk-IJIFHRTB.js → chunk-T4DA4XE7.js} +19 -19
  167. package/dist/node-runtime/chunk-U5F4IC7R.js +53 -0
  168. package/dist/node-runtime/{chunk-KWIYUUZK.js → chunk-UVWCDQYF.js} +27 -18
  169. package/dist/node-runtime/{chunk-ZXSGTGJ6.js → chunk-WIF24I7G.js} +21 -5
  170. package/dist/node-runtime/{chunk-2HHLJWGD.js → chunk-X3PGBLQ7.js} +2 -2
  171. package/dist/node-runtime/chunk-XHIRAZ26.js +108 -0
  172. package/dist/node-runtime/{chunk-YDO2F2IA.js → chunk-YWOJIGFY.js} +1 -1
  173. package/dist/node-runtime/{command-6WDOYKS6.js → command-FSBU2EVZ.js} +3 -3
  174. package/dist/node-runtime/{commands-NZLSOHPE.js → commands-EMBQQVVT.js} +4 -2
  175. package/dist/node-runtime/{commands-QC6VUZJQ.js → commands-NAAL7KNT.js} +5 -4
  176. package/dist/node-runtime/{direct-tool-executor-77GW4F5P.js → direct-tool-executor-4D7UXYU4.js} +7 -4
  177. package/dist/node-runtime/{gateway-INAYBF4Q.js → gateway-DQM333YV.js} +18 -19
  178. package/dist/node-runtime/index.js +23 -19
  179. package/dist/node-runtime/{init-HS6NQXSK.js → init-P5AUV77I.js} +4 -2
  180. package/dist/node-runtime/{install-cli-KL4UDDAD.js → install-cli-NN4YAU44.js} +1 -1
  181. package/dist/node-runtime/{interactive-mode-Z5M7WYYZ.js → interactive-mode-YOHZVMKX.js} +11 -9
  182. package/dist/node-runtime/lunr-computer-use-Y23CCDIJ.js +158 -0
  183. package/dist/node-runtime/{lunr-cron-LWIZJM2N.js → lunr-cron-USHC4LXH.js} +6 -4
  184. package/dist/node-runtime/main.js +16 -14
  185. package/dist/node-runtime/{mcp-auth-flow-QIXHW6QN.js → mcp-auth-flow-QVLFVLEO.js} +2 -1
  186. package/dist/node-runtime/{mobile-commands-J7OJEKFO.js → mobile-commands-O5LCHL32.js} +4 -3
  187. package/dist/node-runtime/{package-manager-cli-VYZM5WHN.js → package-manager-cli-Q7BL6KZO.js} +7 -6
  188. package/dist/node-runtime/{pi-mcp-adapter-5UKBZP44.js → pi-mcp-adapter-3PHF4KZ4.js} +5 -5
  189. package/dist/node-runtime/{pi-subagents-DNY7EAIG.js → pi-subagents-7IBSSGEW.js} +24 -18
  190. package/dist/node-runtime/{print-mode-XSFM26EL.js → print-mode-XQ76CYMT.js} +2 -1
  191. package/dist/node-runtime/{proxy-modes-LGEUYD7R.js → proxy-modes-5FAPSZEZ.js} +7 -4
  192. package/dist/node-runtime/rpc-entry.js +16 -14
  193. package/dist/node-runtime/runtime-EFPPD2UW.js +21 -0
  194. package/dist/node-runtime/{runtime-bridges-VRDDR73P.js → runtime-bridges-7WVCLI76.js} +3 -2
  195. package/dist/node-runtime/{settings-manager-J4SPQPDJ.js → settings-manager-DJDM5AHM.js} +2 -1
  196. package/dist/node-runtime/{setup-CQ2NLVK5.js → setup-PFBWRNUI.js} +10 -9
  197. package/dist/node-runtime/{subagent-executor-KZZQGAKV.js → subagent-executor-LPZ4BHWE.js} +29 -11
  198. package/dist/node-runtime/{update-cli-GTFJC7XK.js → update-cli-HNMOTNGX.js} +2 -1
  199. package/dist/node-runtime/workflow-OHPBEFO4.js +637 -0
  200. package/dist/utils/image-resize-core.d.ts +2 -0
  201. package/dist/utils/image-resize-core.d.ts.map +1 -1
  202. package/dist/utils/image-resize-core.js +10 -0
  203. package/dist/utils/image-resize-core.js.map +1 -1
  204. package/docs/computer-use.md +362 -0
  205. package/docs/features.md +8 -6
  206. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  207. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  208. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  209. package/examples/extensions/gondolin/package-lock.json +2 -2
  210. package/examples/extensions/gondolin/package.json +1 -1
  211. package/examples/extensions/sandbox/package-lock.json +2 -2
  212. package/examples/extensions/sandbox/package.json +1 -1
  213. package/examples/extensions/with-deps/package-lock.json +2 -2
  214. package/examples/extensions/with-deps/package.json +1 -1
  215. package/install-lock/package-lock.json +3841 -0
  216. package/install-lock/package.json +18 -0
  217. package/native/computer-use/LICENSE.md +21 -0
  218. package/npm-shrinkwrap.json +3822 -0
  219. package/package.json +15 -9
  220. package/dist/node-runtime/{chunk-LQP3RB67.js → chunk-RAK2QA2B.js} +3 -3
@@ -0,0 +1,560 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { setTimeout as delay } from "node:timers/promises";
3
+ import { DriverCallError } from "./adapter.js";
4
+ import { prepareComputerImage, screenshotDimensions } from "./image.js";
5
+ import { DesktopLease } from "./lease.js";
6
+ import { computerSchemas } from "./schemas.js";
7
+ export function driverData(reply) {
8
+ if (reply.structuredContent && typeof reply.structuredContent === "object" && !Array.isArray(reply.structuredContent))
9
+ return Object.fromEntries(Object.entries(reply.structuredContent));
10
+ if (Array.isArray(reply.content))
11
+ for (const item of reply.content) {
12
+ if (item.type !== "text" || typeof item.text !== "string")
13
+ continue;
14
+ try {
15
+ const value = JSON.parse(item.text);
16
+ if (value && typeof value === "object" && !Array.isArray(value))
17
+ return Object.fromEntries(Object.entries(value));
18
+ }
19
+ catch { }
20
+ }
21
+ return {};
22
+ }
23
+ function plainLaunchReason(reply) {
24
+ if (reply.structuredContent || !Array.isArray(reply.content))
25
+ return undefined;
26
+ const text = reply.content.find((item) => item.type === "text")?.text;
27
+ if (typeof text !== "string")
28
+ return undefined;
29
+ if (/^App name lookup for .+ is (?:temporarily unavailable|unavailable).+No app was launched;/s.test(text))
30
+ return "app_lookup_unavailable";
31
+ if (/^App .+ was not found in shell:AppsFolder or by Windows PATH\/association lookup:/s.test(text))
32
+ return "app_not_found";
33
+ if (/^Launch of .+ timed out after 15s/s.test(text))
34
+ return "launch_timeout_unknown";
35
+ if (/^(?:Failed to launch|Task error): /s.test(text))
36
+ return "launch_native_error_unknown";
37
+ return undefined;
38
+ }
39
+ export function driverRefused(reply) {
40
+ const data = driverData(reply);
41
+ const acknowledged = data.activated === true || data.success === true || data.verified === true || data.effect === "confirmed";
42
+ const uncertain = [data.status, data.effect].some((value) => value === "partial" || value === "unverifiable");
43
+ return reply.isError === true || plainLaunchReason(reply) !== undefined ||
44
+ (data.refusal !== undefined && data.refusal !== null && data.refusal !== false) ||
45
+ (data.error !== undefined && data.error !== null && data.error !== false) ||
46
+ data.effect === "refused" || data.status === "refused" || data.status === "failed" || data.success === false ||
47
+ ["window_target_mismatch", "window_target_not_found", "background_unavailable", "foreground_unavailable", "type_text_incomplete", "verification_failed"].includes(String(data.code)) ||
48
+ (data.status !== undefined && !acknowledged && !uncertain && !["ok", "success", "completed"].includes(String(data.status))) ||
49
+ (data.code !== undefined && data.code !== 0 && !acknowledged && !uncertain);
50
+ }
51
+ function record(value) {
52
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? Object.fromEntries(Object.entries(value)) : {};
53
+ }
54
+ function select(data, keys) {
55
+ const result = {};
56
+ for (const key of keys) {
57
+ const value = data[key];
58
+ if (["name", "app_name", "title"].includes(key) && typeof value === "string")
59
+ result[key] = value.slice(0, 240);
60
+ else if (["active", "running", "is_on_screen", "minimized"].includes(key) && typeof value === "boolean")
61
+ result[key] = value;
62
+ else if (["pid", "window_id", "x", "y", "width", "height"].includes(key) && typeof value === "number" && Number.isSafeInteger(value))
63
+ result[key] = value;
64
+ }
65
+ return result;
66
+ }
67
+ function typingRecovery(data, text) {
68
+ if (typeof text !== "string")
69
+ return {};
70
+ const requested = data.requested_chars;
71
+ const delivered = data.delivered_chars;
72
+ if (typeof requested !== "number" || !Number.isSafeInteger(requested) || requested < 0 ||
73
+ requested > 20000 || requested !== Array.from(text).length)
74
+ return {};
75
+ const validDelivered = typeof delivered === "number" && Number.isSafeInteger(delivered) && delivered >= 0 && delivered <= requested;
76
+ return {
77
+ requested_chars: requested,
78
+ delivered_chars: validDelivered ? delivered : undefined,
79
+ retryable: validDelivered && data.retry_from_character === delivered && typeof data.retryable === "boolean" ? data.retryable : undefined,
80
+ retry_from_character: validDelivered && data.retry_from_character === delivered ? delivered : undefined,
81
+ };
82
+ }
83
+ const nativeCodes = new Set(["background_unavailable", "background_occluded", "background_uipi_blocked", "window_target_mismatch", "window_target_not_found", "type_text_incomplete", "foreground_unavailable", "foreground_rejected", "stale_target", "target_not_found", "verification_failed", "tool_invocation_failed"]);
84
+ function safeCode(value) {
85
+ return typeof value === "string" && nativeCodes.has(value) ? value : undefined;
86
+ }
87
+ function nativeReason(reply) {
88
+ const data = driverData(reply);
89
+ const code = safeCode(data.code) ?? safeCode(record(data.refusal).code) ?? safeCode(record(data.error).code) ?? safeCode(data.refusal) ?? safeCode(data.error);
90
+ if (code)
91
+ return code;
92
+ if (plainLaunchReason(reply))
93
+ return plainLaunchReason(reply);
94
+ return "native_error_unknown";
95
+ }
96
+ function outcome(reply, text) {
97
+ const data = driverData(reply);
98
+ const refused = driverRefused(reply);
99
+ const partial = data.effect === "partial" || data.status === "partial";
100
+ return {
101
+ phase: refused || partial ? "native_result" : "native_request",
102
+ code: refused || partial ? nativeReason(reply) : undefined,
103
+ native_code: safeCode(data.code) ?? safeCode(record(data.refusal).code) ?? safeCode(record(data.error).code),
104
+ status: typeof data.status === "string" && ["ok", "success", "completed", "partial", "refused", "failed"].includes(data.status) ? data.status : undefined,
105
+ effect: typeof data.effect === "string" && ["confirmed", "partial", "unverifiable", "refused"].includes(data.effect) ? data.effect : undefined,
106
+ verified: typeof data.verified === "boolean" ? data.verified : undefined,
107
+ success: typeof data.success === "boolean" ? data.success : undefined,
108
+ activated: typeof data.activated === "boolean" ? data.activated : undefined,
109
+ escalation: record(data.escalation).recommended === "foreground" ? "foreground" : undefined,
110
+ input: partial && typingRecovery(data, text).delivered_chars !== undefined ? "partial" : refused || partial ? "uncertain" : "dispatched",
111
+ applicationEffect: "unverified",
112
+ ...typingRecovery(data, text),
113
+ };
114
+ }
115
+ function abortable(pending, signal) {
116
+ return new Promise((resolve, reject) => {
117
+ const abort = () => {
118
+ signal.removeEventListener("abort", abort);
119
+ reject(signal.reason ?? new Error("Computer operation cancelled."));
120
+ };
121
+ signal.addEventListener("abort", abort, { once: true });
122
+ pending.then((value) => {
123
+ signal.removeEventListener("abort", abort);
124
+ resolve(value);
125
+ }, (error) => {
126
+ signal.removeEventListener("abort", abort);
127
+ reject(error);
128
+ });
129
+ if (signal.aborted)
130
+ abort();
131
+ });
132
+ }
133
+ const freshActionGuidance = "Get a fresh capture of the exact target before any next action, including window focus. Copy its token exactly. No input was sent by this call; earlier calls may have had an effect.";
134
+ class CaptureError extends Error {
135
+ code;
136
+ constructor(code) { super(code); this.code = code; }
137
+ }
138
+ class ObservationError extends Error {
139
+ code;
140
+ constructor(code, message) {
141
+ super(`Stale observation. ${message}`);
142
+ this.code = code;
143
+ }
144
+ }
145
+ function targetFrom(input) {
146
+ if (input.desktop === true) {
147
+ if (input.pid !== undefined || input.window_id !== undefined)
148
+ throw new Error("Desktop target cannot include pid/window_id.");
149
+ return { desktop: true };
150
+ }
151
+ if (typeof input.pid !== "number" || !Number.isInteger(input.pid) || input.pid < 1 ||
152
+ typeof input.window_id !== "number" || !Number.isInteger(input.window_id) || input.window_id < 1)
153
+ throw new Error("Window target requires positive integer pid and window_id.");
154
+ return { pid: input.pid, window_id: input.window_id };
155
+ }
156
+ function sameTarget(a, b) {
157
+ return a.desktop === true ? b.desktop === true : b.desktop !== true && a.pid === b.pid && a.window_id === b.window_id;
158
+ }
159
+ export class ComputerWorkflow {
160
+ observation;
161
+ lastCapture;
162
+ lastAction;
163
+ abort = new AbortController();
164
+ closing;
165
+ driver;
166
+ lease;
167
+ constructor(driver, lease = new DesktopLease()) {
168
+ this.driver = driver;
169
+ this.lease = lease;
170
+ this.driver.setProcessObserver?.((pid) => this.lease.trackProcess(pid));
171
+ }
172
+ fresh(input, previous) {
173
+ if (!previous)
174
+ throw new ObservationError("observation_unavailable", "No active observation is available.");
175
+ if (previous.token !== input.observation)
176
+ throw new ObservationError("observation_mismatch", "Token does not match the active observation.");
177
+ if (!sameTarget(previous.target, targetFrom(input)))
178
+ throw new ObservationError("observation_target_mismatch", "Token belongs to a different target.");
179
+ if (Date.now() - previous.time > 30000)
180
+ throw new ObservationError("observation_expired", "The active observation is older than 30 seconds.");
181
+ return previous;
182
+ }
183
+ async capture(target, signal, previous, crop) {
184
+ const time = Date.now();
185
+ const reply = await abortable(this.driver.call(target.desktop ? "get_desktop_state" : "get_window_state", target.desktop ? {} : { pid: target.pid, window_id: target.window_id, include_accessibility_tree: false, include_screenshot: true, max_dimension: 2560 }, signal), signal);
186
+ if (driverRefused(reply))
187
+ throw new CaptureError(nativeReason(reply));
188
+ const data = driverData(reply);
189
+ const images = Array.isArray(reply.content) ? reply.content.filter((item) => item.type === "image") : [];
190
+ if (images.length !== 1 || typeof images[0].data !== "string" || typeof images[0].mimeType !== "string")
191
+ throw new CaptureError("screenshot_unavailable");
192
+ const image = { type: "image", data: images[0].data, mimeType: images[0].mimeType };
193
+ let dimensions;
194
+ try {
195
+ dimensions = screenshotDimensions(image);
196
+ }
197
+ catch {
198
+ throw new CaptureError("image_decode_failed");
199
+ }
200
+ if (data.screenshot_frame_valid === false || data.screenshot_error != null || dimensions.width !== data.screenshot_width || dimensions.height !== data.screenshot_height)
201
+ throw new CaptureError("image_frame_invalid");
202
+ const geometry = JSON.stringify(select(record(data.window_bounds), ["x", "y", "width", "height"]));
203
+ if (crop && previous && (previous.sourceWidth !== dimensions.width || previous.sourceHeight !== dimensions.height || previous.geometry !== geometry))
204
+ throw new CaptureError("target_geometry_changed");
205
+ let prepared;
206
+ try {
207
+ prepared = await abortable(prepareComputerImage(image, crop), signal);
208
+ }
209
+ catch (error) {
210
+ if (signal.aborted)
211
+ throw error;
212
+ throw new CaptureError("image_decode_failed");
213
+ }
214
+ signal.throwIfAborted();
215
+ return { ...prepared, token: randomUUID(), target, time, fingerprint: prepared.fingerprint, geometry };
216
+ }
217
+ imageResult(observation, extra = {}) {
218
+ this.observation = observation;
219
+ const { width, height, region, sourceWidth, sourceHeight, scaleX, scaleY, target, token } = observation;
220
+ const failed = extra.failed === true;
221
+ return {
222
+ content: [{ type: "text", text: JSON.stringify({
223
+ ...extra, observation: token, target, captured_at: observation.time, expires_at: observation.time + 30000, image: { width, height },
224
+ mapping: { sourceWidth, sourceHeight, ...region, scaleX, scaleY },
225
+ coordinates: "Use returned-image pixels; mapping is applied automatically.",
226
+ }) }, observation.image],
227
+ details: { observation: token, computer: { failed, workflow: "ready" } }, isError: failed,
228
+ };
229
+ }
230
+ crop(input, previous) {
231
+ const crop = record(input.crop);
232
+ const { x, y, width, height } = crop;
233
+ if (typeof x !== "number" || typeof y !== "number" || typeof width !== "number" || typeof height !== "number" ||
234
+ ![x, y, width, height].every(Number.isFinite) || x < 0 || y < 0 || width <= 0 || height <= 0 ||
235
+ x + width > previous.width || y + height > previous.height || Object.keys(crop).some((key) => !["x", "y", "width", "height"].includes(key)))
236
+ throw new Error("Crop must fit the latest returned image.");
237
+ const left = Math.floor(previous.region.x + x * previous.scaleX);
238
+ const top = Math.floor(previous.region.y + y * previous.scaleY);
239
+ const right = Math.min(previous.sourceWidth, Math.ceil(previous.region.x + (x + width) * previous.scaleX));
240
+ const bottom = Math.min(previous.sourceHeight, Math.ceil(previous.region.y + (y + height) * previous.scaleY));
241
+ return { x: left, y: top, width: right - left, height: bottom - top };
242
+ }
243
+ action(name, input, previous) {
244
+ const args = previous.target.desktop ? { scope: "desktop" } : { pid: previous.target.pid, window_id: previous.target.window_id };
245
+ if (previous.target.desktop && input.foreground !== true)
246
+ throw new Error("Desktop input requires foreground=true.");
247
+ if (name !== "computer_window" && name !== "computer_hover")
248
+ args.delivery_mode = input.foreground === true ? "foreground" : "background";
249
+ for (const key of ["x", "y", "from_x", "from_y", "to_x", "to_y"]) {
250
+ if (name === "computer_window")
251
+ break;
252
+ const value = input[key];
253
+ if (value === undefined)
254
+ continue;
255
+ const horizontal = key.endsWith("x");
256
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value >= (horizontal ? previous.width : previous.height))
257
+ throw new Error("Coordinate outside the observed image.");
258
+ args[key] = (horizontal ? previous.region.x : previous.region.y) + value * (horizontal ? previous.scaleX : previous.scaleY);
259
+ }
260
+ if ((input.x === undefined) !== (input.y === undefined))
261
+ throw new Error("Provide a complete x/y pair.");
262
+ if (previous.target.desktop && ["computer_key", "computer_text"].includes(name) && input.x !== undefined)
263
+ throw new Error("Desktop keyboard input uses the observed focused field. Change focus with a separate grounded click.");
264
+ let operation;
265
+ switch (name) {
266
+ case "computer_hover":
267
+ if (process.platform !== "win32" || !previous.target.desktop || input.desktop !== true || input.foreground !== true ||
268
+ input.x === undefined || input.y === undefined)
269
+ throw new Error("Hover requires a Windows foreground desktop image and x/y coordinates.");
270
+ operation = "move_cursor";
271
+ break;
272
+ case "computer_click":
273
+ case "computer_scroll":
274
+ if (input.x === undefined || input.y === undefined)
275
+ throw new Error("This action requires x/y image coordinates.");
276
+ operation = name === "computer_click" ? "click" : "scroll";
277
+ for (const key of name === "computer_click" ? ["button", "count", "modifier"] : ["direction", "amount", "by"])
278
+ if (input[key] !== undefined)
279
+ args[key] = input[key];
280
+ break;
281
+ case "computer_drag":
282
+ if (!["from_x", "from_y", "to_x", "to_y"].every((key) => typeof args[key] === "number"))
283
+ throw new Error("Drag requires both endpoints.");
284
+ operation = "drag";
285
+ break;
286
+ case "computer_key": {
287
+ if ((input.key === undefined) === (input.keys === undefined))
288
+ throw new Error("Provide key OR keys.");
289
+ const keys = Array.isArray(input.keys) ? input.keys : undefined;
290
+ const last = keys?.at(-1);
291
+ const modifiers = new Set(["ctrl", "control", "shift", "alt", "win", "windows", "cmd", "command"]);
292
+ const foregroundShortcut = process.platform === "win32" && input.foreground === true && input.x === undefined &&
293
+ keys !== undefined && keys.length >= 2 && keys.slice(0, -1).every((key) => typeof key === "string" && modifiers.has(key.toLowerCase())) &&
294
+ typeof last === "string" && !modifiers.has(last.toLowerCase());
295
+ // Pinned Windows hotkey routes XAML through UIA before honoring foreground; press_key honors SendInput.
296
+ operation = input.keys === undefined || foregroundShortcut ? "press_key" : "hotkey";
297
+ if (foregroundShortcut) {
298
+ args.key = last;
299
+ args.modifiers = keys.slice(0, -1);
300
+ }
301
+ else
302
+ args[input.keys === undefined ? "key" : "keys"] = input.keys ?? input.key;
303
+ break;
304
+ }
305
+ case "computer_text":
306
+ operation = "type_text";
307
+ args.text = input.text;
308
+ break;
309
+ case "computer_window":
310
+ if (previous.target.desktop)
311
+ throw new Error("Window management requires an exact window target.");
312
+ if (input.action === "frame") {
313
+ for (const key of ["x", "y", "width", "height"]) {
314
+ const value = input[key];
315
+ if (typeof value !== "number" || !Number.isFinite(value) || (["width", "height"].includes(key) && value <= 0))
316
+ throw new Error("Frame requires valid x/y/width/height.");
317
+ args[key] = value;
318
+ }
319
+ operation = "set_window_frame";
320
+ }
321
+ else if (input.action === "focus" && ["x", "y", "width", "height"].every((key) => input[key] === undefined))
322
+ operation = "bring_to_front";
323
+ else
324
+ throw new Error("Use frame or focus. Minimize/restore uses a fresh image click on the visible control.");
325
+ break;
326
+ default: throw new Error("Unknown computer action.");
327
+ }
328
+ return { operation, args };
329
+ }
330
+ async execute(name, input, signal) {
331
+ const combined = AbortSignal.any([this.abort.signal, this.lease.signal, AbortSignal.timeout(90000), ...(signal ? [signal] : [])]);
332
+ let inputDispatched = false;
333
+ let failureCode = "workflow_unavailable";
334
+ let phase = "validation";
335
+ const currentPhase = () => phase;
336
+ let operationName = name;
337
+ let actionTarget;
338
+ let actionOutcome;
339
+ try {
340
+ const result = await this.lease.run(async () => {
341
+ failureCode = "invalid_arguments";
342
+ const previous = this.observation;
343
+ if (name !== "computer_apps")
344
+ this.observation = undefined;
345
+ if (!Object.hasOwn(computerSchemas, name))
346
+ throw new Error("Unknown computer operation.");
347
+ const schema = computerSchemas[name];
348
+ if (Object.keys(input).some((key) => !Object.hasOwn(schema.properties, key)))
349
+ throw new Error("Unsupported computer argument. Use image coordinates only.");
350
+ if (name === "computer_apps" || name === "computer_launch") {
351
+ const operation = name === "computer_launch" ? "launch_app" : input.pid === undefined ? "list_apps" : "list_windows";
352
+ operationName = operation;
353
+ if (input.include_windows !== undefined && (name !== "computer_apps" || typeof input.include_windows !== "boolean" || (input.include_windows && (input.pid !== undefined || typeof input.query !== "string" || !input.query.trim()))))
354
+ throw new Error("include_windows requires a named app query without pid.");
355
+ if (input.pid !== undefined && (typeof input.pid !== "number" || !Number.isSafeInteger(input.pid) || input.pid < 1))
356
+ throw new Error("Window lookup requires a positive pid.");
357
+ if (name === "computer_launch" && (typeof input.name !== "string" || !input.name.trim() || input.name.length > 500))
358
+ throw new Error("Launch requires a nonblank name.");
359
+ if (input.query !== undefined && (typeof input.query !== "string" || !input.query.trim() || Array.from(input.query).length > 240))
360
+ throw new Error("Discovery query must be a nonblank string of at most 240 characters.");
361
+ const query = typeof input.query === "string" ? input.query.trim() : undefined;
362
+ const needle = query?.toLowerCase();
363
+ const offset = input.offset ?? 0;
364
+ if (typeof offset !== "number" || !Number.isSafeInteger(offset) || offset < 0)
365
+ throw new Error("Discovery offset must be a nonnegative safe integer.");
366
+ const args = name === "computer_launch" ? { name: input.name } : input.pid === undefined ? {} : { pid: input.pid };
367
+ combined.throwIfAborted();
368
+ inputDispatched = name === "computer_launch";
369
+ phase = "native_request";
370
+ failureCode = "discovery_failed";
371
+ const reply = await abortable(this.driver.call(operation, args, combined), combined);
372
+ const data = driverData(reply);
373
+ const discovered = data.apps ?? data.windows;
374
+ const rows = Array.isArray(discovered) && needle ? discovered.filter((row) => {
375
+ const item = record(row);
376
+ return [item.name, item.app_name, item.title].some((value) => typeof value === "string" && value.toLowerCase().includes(needle));
377
+ }) : discovered;
378
+ const metadata = Array.isArray(rows) ? rows.slice(offset, offset + 50).map((row) => {
379
+ const item = record(row);
380
+ return { ...select(item, ["pid", "window_id", "name", "app_name", "title", "active", "running", "is_on_screen", "minimized"]),
381
+ bounds: item.bounds ? select(record(item.bounds), ["x", "y", "width", "height"]) : undefined };
382
+ }) : undefined;
383
+ const remaining = Array.isArray(rows) ? Math.max(0, rows.length - offset - (metadata?.length ?? 0)) : 0;
384
+ const failed = driverRefused(reply);
385
+ const pid = typeof data.pid === "number" && Number.isSafeInteger(data.pid) && data.pid > 0 ? data.pid : undefined;
386
+ const launchWindows = Array.isArray(data.windows) ? data.windows.slice(0, 50).map((row) => {
387
+ const item = record(row);
388
+ return { ...select(item, ["window_id", "title", "is_on_screen", "minimized"]), bounds: item.bounds ? select(record(item.bounds), ["x", "y", "width", "height"]) : undefined };
389
+ }) : [];
390
+ const returnedId = data.window_id ?? (Array.isArray(data.windows) && data.windows.length === 1 ? record(data.windows[0]).window_id : undefined);
391
+ const windowId = typeof returnedId === "number" && Number.isSafeInteger(returnedId) && returnedId > 0 ? returnedId : undefined;
392
+ let windowsByPid;
393
+ let guidance = remaining ? "Pass next_offset as offset with the same pid and query. Lists refresh per call." : input.pid !== undefined
394
+ ? "Use computer_observe({pid,window_id}) for an exact returned window."
395
+ : "App query filters app identities, not every window title. Use computer_apps({pid}) to find windows for a running app.";
396
+ if (name === "computer_apps" && input.include_windows === true && !failed) {
397
+ const pids = [...new Set((Array.isArray(rows) ? rows : []).map((row) => record(row).pid).filter((value) => typeof value === "number" && Number.isSafeInteger(value) && value > 0))];
398
+ if (pids.length > 5)
399
+ guidance = "More than five running processes matched. Narrow the query or choose one positive pid with computer_apps({pid}); no arbitrary process was selected.";
400
+ else {
401
+ windowsByPid = [];
402
+ let budget = 50;
403
+ for (const matchingPid of pids) {
404
+ combined.throwIfAborted();
405
+ try {
406
+ const windowsReply = await abortable(this.driver.call("list_windows", { pid: matchingPid }, combined), combined);
407
+ const windows = driverData(windowsReply).windows;
408
+ if (driverRefused(windowsReply) || !Array.isArray(windows)) {
409
+ windowsByPid.push({ pid: matchingPid, error: driverRefused(windowsReply) ? nativeReason(windowsReply) : "windows_unavailable" });
410
+ continue;
411
+ }
412
+ const subset = windows.slice(0, budget).map((row) => {
413
+ const item = record(row);
414
+ return { ...select(item, ["pid", "window_id", "name", "app_name", "title", "active", "running", "is_on_screen", "minimized"]),
415
+ bounds: item.bounds ? select(record(item.bounds), ["x", "y", "width", "height"]) : undefined };
416
+ });
417
+ const omitted = windows.length - subset.length;
418
+ windowsByPid.push({ pid: matchingPid, windows: subset, omitted: omitted || undefined, next_offset: omitted ? subset.length : undefined });
419
+ budget -= subset.length;
420
+ }
421
+ catch (error) {
422
+ if (combined.aborted)
423
+ throw error;
424
+ if (error instanceof DriverCallError)
425
+ throw error;
426
+ windowsByPid.push({ pid: matchingPid, error: "window_lookup_failed" });
427
+ }
428
+ }
429
+ guidance = "Use computer_observe({pid,window_id}) for a returned window. For omitted windows use computer_apps({pid,offset:next_offset}). Per-PID failures need a targeted lookup.";
430
+ }
431
+ }
432
+ if (name === "computer_launch")
433
+ guidance = pid && windowId && !failed
434
+ ? `Use computer_observe({pid:${pid},window_id:${windowId}}) before input.`
435
+ : `Launch ${failed ? "may have completed despite an unsuccessful reply" : "returned no exact window"}. Use computer_apps({${pid ? `pid:${pid}` : `query:${JSON.stringify(input.name)}`}}) before another launch or input.`;
436
+ return { content: [{ type: "text", text: JSON.stringify({
437
+ kind: name === "computer_launch" ? "launch" : input.pid === undefined ? "apps" : "windows", operation,
438
+ ...(name === "computer_launch" ? outcome(reply) : { phase: "native_result", code: failed ? nativeReason(reply) : undefined }),
439
+ input: name === "computer_launch" ? "not_applicable" : undefined,
440
+ launch: name === "computer_launch" ? plainLaunchReason(reply) === "app_lookup_unavailable" ? "not_started" : failed ? "completion_uncertain" : "acknowledged" : undefined,
441
+ ...select(data, ["pid", "window_id", "name", "title"]), window_id: name === "computer_launch" ? windowId : select(data, ["window_id"]).window_id,
442
+ windows: name === "computer_launch" ? launchWindows : undefined, items: name === "computer_launch" ? undefined : metadata,
443
+ windows_by_pid: windowsByPid, query, offset, total: Array.isArray(rows) ? rows.length : undefined,
444
+ omitted: remaining || undefined, next_offset: remaining ? offset + 50 : undefined, guidance,
445
+ }) }], details: { computer: { failed, workflow: "ready" } }, isError: failed };
446
+ }
447
+ const target = targetFrom(input);
448
+ actionTarget = target;
449
+ if (name === "computer_observe") {
450
+ phase = "observation_capture";
451
+ const crop = input.crop === undefined ? undefined : this.crop(input, this.fresh(input, previous));
452
+ failureCode = "capture_failed";
453
+ const captured = await this.capture(target, combined, previous, crop);
454
+ const unchanged = this.lastCapture?.fingerprint === captured.fingerprint && sameTarget(this.lastCapture.target, target);
455
+ const repeats = crop ? 0 : unchanged ? (this.lastCapture?.repeats ?? 0) + 1 : 1;
456
+ this.lastCapture = { fingerprint: captured.fingerprint, target, repeats };
457
+ if (repeats >= 3)
458
+ return {
459
+ content: [{ type: "text", text: JSON.stringify({ phase: "observation_capture", code: "unchanged_polling_limit", guidance: "Three captures are unchanged. Stop polling and reconsider the target or approach. No input token issued." }) }],
460
+ details: { computer: { failed: true, workflow: "stopped" } }, isError: true,
461
+ };
462
+ return this.imageResult(captured, { unchanged });
463
+ }
464
+ const grounded = this.fresh(input, previous);
465
+ const { operation, args } = this.action(name, input, grounded);
466
+ const { button = "left", count = 1, modifier = [], ...clickArgs } = args;
467
+ const signature = JSON.stringify({ operation, args: operation === "click"
468
+ ? { ...clickArgs, button, count, modifier: Array.isArray(modifier) ? [...new Set(modifier)].sort() : modifier }
469
+ : args });
470
+ if (this.lastAction?.unchanged && this.lastAction.signature === signature && this.lastAction.fingerprint === grounded.fingerprint)
471
+ throw new Error("The identical action had no visible change. Choose a different grounded action; never retry blindly.");
472
+ combined.throwIfAborted();
473
+ inputDispatched = true;
474
+ phase = "native_request";
475
+ operationName = operation;
476
+ const reply = await abortable(this.driver.call(operation, args, combined), combined);
477
+ combined.throwIfAborted();
478
+ actionOutcome = outcome(reply, name === "computer_text" ? input.text : undefined);
479
+ const recoveryGuidance = actionOutcome.retry_from_character !== undefined
480
+ ? "Verify the field in a fresh image before considering any remaining suffix. retry_from_character is a zero-based Unicode code-point offset, not UTF-16. retryable is driver advice, not authorization to retry."
481
+ : undefined;
482
+ const failed = driverRefused(reply) || driverData(reply).effect === "partial" || driverData(reply).status === "partial";
483
+ const backgroundUnavailable = actionOutcome.code === "background_unavailable";
484
+ if (name === "computer_hover")
485
+ await delay(700, undefined, { signal: combined });
486
+ phase = "post_action_capture";
487
+ try {
488
+ const after = await this.capture(target, combined);
489
+ const unchanged = after.fingerprint === grounded.fingerprint;
490
+ this.lastAction = { signature, fingerprint: after.fingerprint, unchanged };
491
+ this.lastCapture = { fingerprint: after.fingerprint, target, repeats: failed && this.lastCapture?.fingerprint === after.fingerprint && sameTarget(this.lastCapture.target, target)
492
+ ? this.lastCapture.repeats : 0 };
493
+ return this.imageResult(after, { kind: "action", operation, target, ...actionOutcome, failed, unchanged,
494
+ guidance: ["Inspect the post-action image before another action. No visible change does not prove failure; never repeat blindly.",
495
+ backgroundUnavailable ? "After this fresh capture, foreground input may be considered if permitted, not another background shortcut." : undefined,
496
+ recoveryGuidance].filter(Boolean).join(" ") });
497
+ }
498
+ catch (error) {
499
+ combined.throwIfAborted();
500
+ if (!(error instanceof CaptureError))
501
+ throw error;
502
+ this.lastAction = { signature, fingerprint: grounded.fingerprint, unchanged: true };
503
+ return { content: [{ type: "text", text: JSON.stringify({ kind: "action", operation, target, ...actionOutcome, phase: "post_action_capture",
504
+ capture_error: error.code, observation: "unavailable", guidance: `Input may have taken effect. ${["target_not_found", "window_target_not_found", "window_target_mismatch"].includes(error.code)
505
+ ? "Use computer_apps({pid}) or observe the desktop to find the target." : "Get a fresh capture of the exact target"} before another action; never repeat blindly. ${recoveryGuidance ?? ""}`,
506
+ }) }], details: { computer: { failed: true, workflow: "ready" } }, isError: true };
507
+ }
508
+ }, combined);
509
+ if (result.details.computer.workflow !== "ready")
510
+ return this.finish(result);
511
+ return result;
512
+ }
513
+ catch (error) {
514
+ if (error instanceof DriverCallError && !(currentPhase() === "post_action_capture" && actionOutcome)) {
515
+ phase = error.phase;
516
+ inputDispatched = error.dispatched;
517
+ }
518
+ const failurePhase = currentPhase();
519
+ const fatal = combined.aborted || this.abort.signal.aborted || this.lease.signal.aborted || error instanceof DriverCallError ||
520
+ !(error instanceof ObservationError || error instanceof CaptureError || failurePhase === "validation" || failurePhase === "observation_capture" && !inputDispatched);
521
+ const code = error instanceof ObservationError || error instanceof CaptureError ? error.code
522
+ : inputDispatched && failurePhase === "post_action_capture" ? "capture_transport_failed"
523
+ : error instanceof DriverCallError ? error.dispatched ? "input_dispatch_failed" : "adapter_preflight_failed"
524
+ : inputDispatched ? "input_dispatch_failed" : failurePhase === "validation" ? "invalid_arguments" : failureCode;
525
+ const message = name === "computer_launch" ? inputDispatched ? "Launch request began; activation may have occurred." : "No launch request was sent by this call."
526
+ : inputDispatched ? "Input may have taken effect; request began." : "No input was sent by this call.";
527
+ const guidance = inputDispatched ? name === "computer_launch"
528
+ ? `Use computer_apps({query:${JSON.stringify(input.name)}) before considering another launch.`
529
+ : `Get a fresh capture of the exact target before another action. Input may have taken effect; inspect the field before deciding and never repeat blindly. ${actionOutcome?.retry_from_character !== undefined ? "Verify the field in a fresh image before considering any remaining suffix. retry_from_character is a zero-based Unicode code-point offset, not UTF-16." : ""}`
530
+ : freshActionGuidance;
531
+ const result = { content: [{ type: "text", text: JSON.stringify({ kind: name === "computer_apps" ? "apps" : name === "computer_launch" ? "launch" : name === "computer_observe" ? "observation" : "action",
532
+ operation: operationName, target: actionTarget, ...actionOutcome, action_outcome: actionOutcome, phase: failurePhase, code,
533
+ input: name === "computer_apps" ? undefined : name === "computer_launch" ? "not_applicable" : inputDispatched ? "uncertain" : "not_dispatched",
534
+ request: name === "computer_launch" ? inputDispatched ? "sent" : "not_sent" : undefined, applicationEffect: "unverified",
535
+ observation: "unavailable", capture_error: failurePhase === "post_action_capture" ? code : undefined, message, guidance }) }], details: { computer: { failed: true, workflow: fatal ? "stopped" : "ready" } }, isError: true };
536
+ return fatal ? this.finish(result) : result;
537
+ }
538
+ }
539
+ async finish(result) {
540
+ try {
541
+ await this.close();
542
+ return { ...result, details: { ...result.details, computer: { failed: result.details.computer.failed, workflow: "stopped" } } };
543
+ }
544
+ catch {
545
+ return { content: [...result.content, { type: "text", text: JSON.stringify({ phase: "cleanup", cleanup: "unconfirmed", guidance: "Desktop ownership retained until shutdown is confirmed." }) }],
546
+ details: { ...result.details, computer: { failed: true, workflow: "cleanup_unconfirmed" } }, isError: true };
547
+ }
548
+ }
549
+ close() {
550
+ this.abort.abort();
551
+ this.observation = undefined;
552
+ this.closing ??= this.stop();
553
+ return this.closing;
554
+ }
555
+ async stop() {
556
+ await this.driver.close();
557
+ await this.lease.close();
558
+ }
559
+ }
560
+ //# sourceMappingURL=workflow.js.map