@agimon-ai/doompi-computer-use 0.0.1-alpha.13 → 0.0.1-alpha.14

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 (207) hide show
  1. package/README.md +5 -1
  2. package/dist/api-contracts.cjs +1 -0
  3. package/dist/api-contracts.d.cts +2 -0
  4. package/dist/api-contracts.d.mts +2 -0
  5. package/dist/api-contracts.mjs +1 -0
  6. package/dist/constants/computerUse.cjs +3 -0
  7. package/dist/constants/computerUse.cjs.map +1 -0
  8. package/dist/{adapters/pi/extension.d.cts → constants/computerUse.d.cts} +3 -10
  9. package/dist/constants/computerUse.d.cts.map +1 -0
  10. package/dist/{adapters/pi/extension.d.mts → constants/computerUse.d.mts} +3 -10
  11. package/dist/constants/computerUse.d.mts.map +1 -0
  12. package/dist/constants/computerUse.mjs +3 -0
  13. package/dist/constants/computerUse.mjs.map +1 -0
  14. package/dist/controllers/computerUseApi.cjs +2 -0
  15. package/dist/controllers/computerUseApi.cjs.map +1 -0
  16. package/dist/controllers/computerUseApi.mjs +2 -0
  17. package/dist/controllers/computerUseApi.mjs.map +1 -0
  18. package/dist/controllers/computerUseCommand.cjs +2 -0
  19. package/dist/controllers/computerUseCommand.cjs.map +1 -0
  20. package/dist/controllers/computerUseCommand.mjs +2 -0
  21. package/dist/controllers/computerUseCommand.mjs.map +1 -0
  22. package/dist/controllers/computerUseRuntime.cjs +2 -0
  23. package/dist/controllers/computerUseRuntime.cjs.map +1 -0
  24. package/dist/controllers/computerUseRuntime.mjs +2 -0
  25. package/dist/controllers/computerUseRuntime.mjs.map +1 -0
  26. package/dist/controllers/computerUseServer.cjs +3 -0
  27. package/dist/controllers/computerUseServer.cjs.map +1 -0
  28. package/dist/controllers/computerUseServer.mjs +3 -0
  29. package/dist/controllers/computerUseServer.mjs.map +1 -0
  30. package/dist/controllers/webComputerUseChannel.cjs +2 -0
  31. package/dist/controllers/webComputerUseChannel.cjs.map +1 -0
  32. package/dist/controllers/webComputerUseChannel.mjs +2 -0
  33. package/dist/controllers/webComputerUseChannel.mjs.map +1 -0
  34. package/dist/extensions/pi.cjs +2 -1
  35. package/dist/extensions/pi.cjs.map +1 -0
  36. package/dist/extensions/pi.d.cts +6 -2
  37. package/dist/extensions/pi.d.cts.map +1 -0
  38. package/dist/extensions/pi.d.mts +6 -2
  39. package/dist/extensions/pi.d.mts.map +1 -0
  40. package/dist/extensions/pi.mjs +2 -1
  41. package/dist/extensions/pi.mjs.map +1 -0
  42. package/dist/extensions/server.cjs +2 -0
  43. package/dist/extensions/server.cjs.map +1 -0
  44. package/dist/extensions/server.d.cts +5 -0
  45. package/dist/extensions/server.d.cts.map +1 -0
  46. package/dist/extensions/server.d.mts +5 -0
  47. package/dist/extensions/server.d.mts.map +1 -0
  48. package/dist/extensions/server.mjs +2 -0
  49. package/dist/extensions/server.mjs.map +1 -0
  50. package/dist/index.cjs +1 -1
  51. package/dist/index.d.cts +9 -9
  52. package/dist/index.d.mts +9 -9
  53. package/dist/index.mjs +1 -1
  54. package/dist/models/computerUseMode.cjs +2 -0
  55. package/dist/models/computerUseMode.cjs.map +1 -0
  56. package/dist/models/computerUseMode.mjs +2 -0
  57. package/dist/models/computerUseMode.mjs.map +1 -0
  58. package/dist/{services/sessionController.cjs → models/computerUseState.cjs} +1 -1
  59. package/dist/models/computerUseState.cjs.map +1 -0
  60. package/dist/{services/sessionController.d.cts → models/computerUseState.d.cts} +2 -2
  61. package/dist/models/computerUseState.d.cts.map +1 -0
  62. package/dist/{services/sessionController.d.mts → models/computerUseState.d.mts} +2 -2
  63. package/dist/models/computerUseState.d.mts.map +1 -0
  64. package/dist/{services/sessionController.mjs → models/computerUseState.mjs} +1 -1
  65. package/dist/models/computerUseState.mjs.map +1 -0
  66. package/dist/schemas/apiContracts.cjs +2 -0
  67. package/dist/schemas/apiContracts.cjs.map +1 -0
  68. package/dist/schemas/apiContracts.d.cts +53 -0
  69. package/dist/schemas/apiContracts.d.cts.map +1 -0
  70. package/dist/schemas/apiContracts.d.mts +53 -0
  71. package/dist/schemas/apiContracts.d.mts.map +1 -0
  72. package/dist/schemas/apiContracts.mjs +2 -0
  73. package/dist/schemas/apiContracts.mjs.map +1 -0
  74. package/dist/{adapters/pi/computerScriptRunner.cjs → services/computerScriptRunner/index.cjs} +1 -1
  75. package/dist/{adapters/pi/computerScriptRunner.mjs.map → services/computerScriptRunner/index.cjs.map} +1 -1
  76. package/dist/{adapters/pi/computerScriptRunner.d.cts → services/computerScriptRunner/index.d.cts} +2 -2
  77. package/dist/services/computerScriptRunner/index.d.cts.map +1 -0
  78. package/dist/{adapters/pi/computerScriptRunner.d.mts → services/computerScriptRunner/index.d.mts} +2 -2
  79. package/dist/services/computerScriptRunner/index.d.mts.map +1 -0
  80. package/dist/{adapters/pi/computerScriptRunner.mjs → services/computerScriptRunner/index.mjs} +1 -1
  81. package/dist/services/computerScriptRunner/index.mjs.map +1 -0
  82. package/dist/services/dependencies/index.cjs +2 -0
  83. package/dist/services/dependencies/index.cjs.map +1 -0
  84. package/dist/services/dependencies/index.d.cts +6 -0
  85. package/dist/services/dependencies/index.d.cts.map +1 -0
  86. package/dist/services/dependencies/index.d.mts +6 -0
  87. package/dist/services/dependencies/index.d.mts.map +1 -0
  88. package/dist/services/dependencies/index.mjs +2 -0
  89. package/dist/services/dependencies/index.mjs.map +1 -0
  90. package/dist/services/{extensionService.cjs → extensionService/index.cjs} +1 -1
  91. package/dist/services/extensionService/index.cjs.map +1 -0
  92. package/dist/services/{extensionService.d.mts → extensionService/index.d.cts} +4 -4
  93. package/dist/services/extensionService/index.d.cts.map +1 -0
  94. package/dist/services/{extensionService.d.cts → extensionService/index.d.mts} +4 -4
  95. package/dist/services/extensionService/index.d.mts.map +1 -0
  96. package/dist/services/{extensionService.mjs → extensionService/index.mjs} +1 -1
  97. package/dist/services/extensionService/index.mjs.map +1 -0
  98. package/dist/services/sessionApiClient/index.cjs +2 -0
  99. package/dist/services/sessionApiClient/index.cjs.map +1 -0
  100. package/dist/services/sessionApiClient/index.d.cts +15 -0
  101. package/dist/services/sessionApiClient/index.d.cts.map +1 -0
  102. package/dist/services/sessionApiClient/index.d.mts +15 -0
  103. package/dist/services/sessionApiClient/index.d.mts.map +1 -0
  104. package/dist/services/sessionApiClient/index.mjs +2 -0
  105. package/dist/services/sessionApiClient/index.mjs.map +1 -0
  106. package/dist/services/{traceRedaction.cjs → traceRedaction/index.cjs} +1 -1
  107. package/dist/services/{traceRedaction.cjs.map → traceRedaction/index.cjs.map} +1 -1
  108. package/dist/services/{traceRedaction.d.cts → traceRedaction/index.d.cts} +3 -3
  109. package/dist/services/traceRedaction/index.d.cts.map +1 -0
  110. package/dist/services/{traceRedaction.d.mts → traceRedaction/index.d.mts} +3 -3
  111. package/dist/services/traceRedaction/index.d.mts.map +1 -0
  112. package/dist/services/{traceRedaction.mjs → traceRedaction/index.mjs} +1 -1
  113. package/dist/services/{traceRedaction.mjs.map → traceRedaction/index.mjs.map} +1 -1
  114. package/dist/services/webComputerUseAvailability/index.cjs +2 -0
  115. package/dist/services/webComputerUseAvailability/index.cjs.map +1 -0
  116. package/dist/services/webComputerUseAvailability/index.mjs +2 -0
  117. package/dist/services/webComputerUseAvailability/index.mjs.map +1 -0
  118. package/dist/types/computerScript.d.cts +1 -1
  119. package/dist/types/computerScript.d.mts +1 -1
  120. package/dist/types/computerUseApi.cjs.map +1 -1
  121. package/dist/types/computerUseApi.d.cts +1 -1
  122. package/dist/types/computerUseApi.d.mts +1 -1
  123. package/dist/types/computerUseApi.mjs.map +1 -1
  124. package/dist/types/extension.d.cts +1 -1
  125. package/dist/types/extension.d.mts +1 -1
  126. package/package.json +29 -21
  127. package/src/extensions/web.ts +51 -0
  128. package/src/types/computerUseApi.ts +2 -2
  129. package/src/web/components/ComputerActionToolCard.tsx +3 -2
  130. package/src/web/components/ComputerExecToolCard.tsx +3 -2
  131. package/src/web/components/ComputerStateToolCard.tsx +3 -2
  132. package/src/web/components/ComputerUsePanel.tsx +4 -3
  133. package/src/web/lib/computerActionToolRender.ts +1 -1
  134. package/src/web/lib/computerExecToolRender.ts +1 -1
  135. package/src/web/lib/computerStateToolRender.ts +1 -1
  136. package/src/web/lib/computerUseSettings.ts +1 -1
  137. package/src/web/stores/computerUseStore.ts +4 -3
  138. package/src/web/tsconfig.json +1 -7
  139. package/dist/adapters/computerUseApi.cjs +0 -2
  140. package/dist/adapters/computerUseApi.cjs.map +0 -1
  141. package/dist/adapters/computerUseApi.d.cts +0 -41
  142. package/dist/adapters/computerUseApi.d.cts.map +0 -1
  143. package/dist/adapters/computerUseApi.d.mts +0 -41
  144. package/dist/adapters/computerUseApi.d.mts.map +0 -1
  145. package/dist/adapters/computerUseApi.mjs +0 -2
  146. package/dist/adapters/computerUseApi.mjs.map +0 -1
  147. package/dist/adapters/pi/computerScriptRunner.cjs.map +0 -1
  148. package/dist/adapters/pi/computerScriptRunner.d.cts.map +0 -1
  149. package/dist/adapters/pi/computerScriptRunner.d.mts.map +0 -1
  150. package/dist/adapters/pi/extension.cjs +0 -3
  151. package/dist/adapters/pi/extension.cjs.map +0 -1
  152. package/dist/adapters/pi/extension.d.cts.map +0 -1
  153. package/dist/adapters/pi/extension.d.mts.map +0 -1
  154. package/dist/adapters/pi/extension.mjs +0 -3
  155. package/dist/adapters/pi/extension.mjs.map +0 -1
  156. package/dist/adapters/pi/sessionApiClient.cjs +0 -2
  157. package/dist/adapters/pi/sessionApiClient.cjs.map +0 -1
  158. package/dist/adapters/pi/sessionApiClient.d.cts +0 -25
  159. package/dist/adapters/pi/sessionApiClient.d.cts.map +0 -1
  160. package/dist/adapters/pi/sessionApiClient.d.mts +0 -25
  161. package/dist/adapters/pi/sessionApiClient.d.mts.map +0 -1
  162. package/dist/adapters/pi/sessionApiClient.mjs +0 -2
  163. package/dist/adapters/pi/sessionApiClient.mjs.map +0 -1
  164. package/dist/adapters/webComputerUseAvailability.cjs +0 -2
  165. package/dist/adapters/webComputerUseAvailability.cjs.map +0 -1
  166. package/dist/adapters/webComputerUseAvailability.mjs +0 -2
  167. package/dist/adapters/webComputerUseAvailability.mjs.map +0 -1
  168. package/dist/adapters/webComputerUseChannel.cjs +0 -2
  169. package/dist/adapters/webComputerUseChannel.cjs.map +0 -1
  170. package/dist/adapters/webComputerUseChannel.d.cts +0 -10
  171. package/dist/adapters/webComputerUseChannel.d.cts.map +0 -1
  172. package/dist/adapters/webComputerUseChannel.d.mts +0 -10
  173. package/dist/adapters/webComputerUseChannel.d.mts.map +0 -1
  174. package/dist/adapters/webComputerUseChannel.mjs +0 -2
  175. package/dist/adapters/webComputerUseChannel.mjs.map +0 -1
  176. package/dist/commands/computerUseCommand.cjs +0 -2
  177. package/dist/commands/computerUseCommand.cjs.map +0 -1
  178. package/dist/commands/computerUseCommand.mjs +0 -2
  179. package/dist/commands/computerUseCommand.mjs.map +0 -1
  180. package/dist/container/index.cjs +0 -2
  181. package/dist/container/index.cjs.map +0 -1
  182. package/dist/container/index.d.cts +0 -6
  183. package/dist/container/index.d.cts.map +0 -1
  184. package/dist/container/index.d.mts +0 -6
  185. package/dist/container/index.d.mts.map +0 -1
  186. package/dist/container/index.mjs +0 -2
  187. package/dist/container/index.mjs.map +0 -1
  188. package/dist/services/extensionService.cjs.map +0 -1
  189. package/dist/services/extensionService.d.cts.map +0 -1
  190. package/dist/services/extensionService.d.mts.map +0 -1
  191. package/dist/services/extensionService.mjs.map +0 -1
  192. package/dist/services/sessionController.cjs.map +0 -1
  193. package/dist/services/sessionController.d.cts.map +0 -1
  194. package/dist/services/sessionController.d.mts.map +0 -1
  195. package/dist/services/sessionController.mjs.map +0 -1
  196. package/dist/services/traceRedaction.d.cts.map +0 -1
  197. package/dist/services/traceRedaction.d.mts.map +0 -1
  198. package/dist/sessionApi.cjs +0 -1
  199. package/dist/sessionApi.d.cts +0 -2
  200. package/dist/sessionApi.d.mts +0 -2
  201. package/dist/sessionApi.mjs +0 -1
  202. package/dist/webHub.cjs +0 -1
  203. package/dist/webHub.d.cts +0 -3
  204. package/dist/webHub.d.mts +0 -3
  205. package/dist/webHub.mjs +0 -1
  206. package/src/exports/webClient.ts +0 -2
  207. package/src/web/index.ts +0 -47
package/README.md CHANGED
@@ -36,7 +36,7 @@ All three tools and their model guidance remain unavailable during setup and are
36
36
  import { activateComputerUseExtension, createComputerUseSessionClient } from '@agimon-ai/doompi-computer-use';
37
37
  ```
38
38
 
39
- The session API entry is available at `@agimon-ai/doompi-computer-use/session-api`. Its agent and hub routes use separate host-issued context tokens. Grants remain opaque and session-bound inside the request broker.
39
+ The session-scoped server facet owns the agent and hub routes. Their host-issued context tokens remain opaque and session-bound inside the request broker.
40
40
 
41
41
  ## Development
42
42
 
@@ -50,3 +50,7 @@ pnpm build
50
50
  ## License
51
51
 
52
52
  MIT
53
+
54
+ Direct plugin entries live in `src/extensions`. Controllers coordinate host APIs, commands, and mode actions. Models own computer-use state and projections; named services own Desktop transport, scripts, and configuration dependencies. Flat `src/exports` exposes reusable helpers and types.
55
+
56
+ The Pi entry declares a live minor-mode collection so the global opt-in controls catalog presence. Its tool restriction is reactive and the helper owns all registration changes. Session startup begins availability polling; `onStop` cancels the timer and final disposal clears status. The server declares its session mode, activity, tools, commands, and API alongside hub channel factories.
@@ -0,0 +1 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./schemas/apiContracts.cjs");exports.apiContracts=e.apiContracts,exports.default=e.apiContracts;
@@ -0,0 +1,2 @@
1
+ import { apiContracts } from "./schemas/apiContracts.cjs";
2
+ export { apiContracts, apiContracts as default };
@@ -0,0 +1,2 @@
1
+ import { apiContracts } from "./schemas/apiContracts.mjs";
2
+ export { apiContracts, apiContracts as default };
@@ -0,0 +1 @@
1
+ import{apiContracts as e}from"./schemas/apiContracts.mjs";export{e as apiContracts,e as default};
@@ -0,0 +1,3 @@
1
+ const e=[`computer_state`,`computer_action`,`computer_exec`];exports.COMMAND_DESCRIPTION=`Inspect or manage the session computer use mode`,exports.COMMAND_NAME=`computer-use`,exports.COMPUTER_USE_GUIDANCE=`[COMPUTER USE ACTIVE]
2
+ Use computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.`,exports.COMPUTER_USE_TOOL_NAMES=e;
3
+ //# sourceMappingURL=computerUse.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUse.cjs","names":[],"sources":["../../src/constants/computerUse.ts"],"sourcesContent":["export const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.`;\nexport const COMMAND_NAME = 'computer-use';\nexport const COMMAND_DESCRIPTION = 'Inspect or manage the session computer use mode';\n\nexport const COMPUTER_USE_TOOL_NAMES = ['computer_state', 'computer_action', 'computer_exec'] as const;\n"],"mappings":"AAAA,MAKa,EAA0B,CAAC,iBAAkB,kBAAmB,eAAe"}
@@ -1,12 +1,5 @@
1
- import { COMPUTER_USE_MODE_ID } from "../../types/computerUseApi.cjs";
2
- import { ComputerUseExtensionDependencies } from "../../types/extension.cjs";
3
- import "@agimon-ai/doompi-extension-contracts/mode";
4
- import "@deepseek-ai/cordis";
5
- import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
- //#region src/adapters/pi/extension.d.ts
7
- export declare const COMPUTER_USE_TOOL_NAMES: readonly ['computer_state', 'computer_action', 'computer_exec'];
1
+ //#region src/constants/computerUse.d.ts
8
2
  export declare const COMPUTER_USE_GUIDANCE = "[COMPUTER USE ACTIVE]\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.";
9
- export declare function activateComputerUseExtension(pi: ExtensionAPI, dependencies?: ComputerUseExtensionDependencies): Promise<void>;
3
+ export declare const COMPUTER_USE_TOOL_NAMES: readonly ['computer_state', 'computer_action', 'computer_exec'];
10
4
  //#endregion
11
- export { COMPUTER_USE_MODE_ID, activateComputerUseExtension as default };
12
- //# sourceMappingURL=extension.d.cts.map
5
+ //# sourceMappingURL=computerUse.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUse.d.cts","names":[],"sources":["../../src/constants/computerUse.ts"],"mappings":";qBAAa;qBAKA"}
@@ -1,12 +1,5 @@
1
- import { COMPUTER_USE_MODE_ID } from "../../types/computerUseApi.mjs";
2
- import { ComputerUseExtensionDependencies } from "../../types/extension.mjs";
3
- import "@agimon-ai/doompi-extension-contracts/mode";
4
- import "@deepseek-ai/cordis";
5
- import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
- //#region src/adapters/pi/extension.d.ts
7
- export declare const COMPUTER_USE_TOOL_NAMES: readonly ['computer_state', 'computer_action', 'computer_exec'];
1
+ //#region src/constants/computerUse.d.ts
8
2
  export declare const COMPUTER_USE_GUIDANCE = "[COMPUTER USE ACTIVE]\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.";
9
- export declare function activateComputerUseExtension(pi: ExtensionAPI, dependencies?: ComputerUseExtensionDependencies): Promise<void>;
3
+ export declare const COMPUTER_USE_TOOL_NAMES: readonly ['computer_state', 'computer_action', 'computer_exec'];
10
4
  //#endregion
11
- export { COMPUTER_USE_MODE_ID, activateComputerUseExtension as default };
12
- //# sourceMappingURL=extension.d.mts.map
5
+ //# sourceMappingURL=computerUse.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUse.d.mts","names":[],"sources":["../../src/constants/computerUse.ts"],"mappings":";qBAAa;qBAKA"}
@@ -0,0 +1,3 @@
1
+ const e=`[COMPUTER USE ACTIVE]
2
+ Use computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.`,t=`computer-use`,n=`Inspect or manage the session computer use mode`,r=[`computer_state`,`computer_action`,`computer_exec`];export{n as COMMAND_DESCRIPTION,t as COMMAND_NAME,e as COMPUTER_USE_GUIDANCE,r as COMPUTER_USE_TOOL_NAMES};
3
+ //# sourceMappingURL=computerUse.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUse.mjs","names":[],"sources":["../../src/constants/computerUse.ts"],"sourcesContent":["export const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.`;\nexport const COMMAND_NAME = 'computer-use';\nexport const COMMAND_DESCRIPTION = 'Inspect or manage the session computer use mode';\n\nexport const COMPUTER_USE_TOOL_NAMES = ['computer_state', 'computer_action', 'computer_exec'] as const;\n"],"mappings":"AAAA,MAAa,EAAwB;wdAExB,EAAe,eACf,EAAsB,kDAEtB,EAA0B,CAAC,iBAAkB,kBAAmB,eAAe"}
@@ -0,0 +1,2 @@
1
+ const e=require("../types/computerUseApi.cjs");let t=require("node:crypto"),n=require("@agimon-ai/doompi-core/package-api");function r(e,t){return Response.json({error:e},{status:t})}function i(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:void 0}async function a(e){try{return i(await e.json())??{}}catch{return{}}}function o(e){if(!(typeof e.snapshotId==`string`&&e.snapshotId.length>0&&typeof e.elementRef==`string`&&e.elementRef.length>0))return!1;let t=t=>Object.keys(e).every(e=>t.includes(e));return e.kind===`press`||e.kind===`focus`?t([`kind`,`snapshotId`,`elementRef`]):e.kind===`set_value`?typeof e.value==`string`&&t([`kind`,`snapshotId`,`elementRef`,`value`]):e.kind===`scroll`&&[`up`,`down`,`left`,`right`].includes(e.direction)&&(e.amount===`line`||e.amount===`page`)&&t([`kind`,`snapshotId`,`elementRef`,`direction`,`amount`])}function s(e){let t=i(e);if(typeof t?.artifactId!=`string`||t.status!==`ready`&&t.status!==`failed`)return;let n=e=>typeof e==`string`&&e.startsWith(`/api/`)?e:void 0,r=n(t.downloadUrl),a=n(t.previewUrl),o=i(t.failure),s=typeof o?.code==`string`&&typeof o.message==`string`?{code:o.code.slice(0,128),message:o.message.slice(0,512)}:void 0;return{artifactId:t.artifactId,status:t.status,...r===void 0?{}:{downloadUrl:r},...a===void 0?{}:{previewUrl:a},...typeof t.actionCount==`number`?{actionCount:t.actionCount}:{},...typeof t.completedAt==`string`?{completedAt:t.completedAt}:{},...s===void 0?{}:{failure:s}}}var c=class c{sessionId;internalToken;hubToken;directEvents;requestTimeoutMs;revision=0;wake=0;phase=`inactive`;activation;grantId;expiresAt;actionSequence=0;failure;artifact;pending;closed=!1;static DEFAULT_REQUEST_TIMEOUT_MS=3e4;constructor(e){this.sessionId=e.sessionId??`unknown`,this.internalToken=e.internalToken,this.hubToken=e.hubToken,this.directEvents=e.directEvents,this.requestTimeoutMs=e.requestTimeoutMs??c.DEFAULT_REQUEST_TIMEOUT_MS}state(){return Object.freeze({sessionId:this.sessionId,revision:this.revision,wake:this.wake,phase:this.phase,...this.activation===void 0?{}:{requestId:this.activation.requestId,target:this.activation.target,durationMs:this.activation.durationSeconds*1e3},...this.expiresAt===void 0?{}:{expiresAt:this.expiresAt},...this.failure===void 0?{}:{failure:this.failure},...this.artifact===void 0?{}:{artifact:this.artifact}})}changed(){this.revision+=1,this.wake=(this.wake+1)%e.COMPUTER_USE_WAKE_LIMIT,this.directEvents.publish(e.computerUseChannelType,this.sessionId,this.state())}authorized(e,t){return t!==void 0&&e.headers.get(`authorization`)===`Bearer ${t}`}async requestActivation(o){let s=(0,n.doomApiCallerFrom)(o.headers);if(s===void 0||s.locality===`remote`&&s.stepUp===`not-required`)return r(`Not found.`,404);if(this.phase!==`inactive`&&this.phase!==`failed`)return r(`Computer use is already busy.`,409);let c=await a(o),l=i(c.target),u=c.durationMs;if(l===void 0||typeof l.windowId!=`string`||typeof l.bundleId!=`string`)return r(`A Desktop target is required.`,400);if(typeof u!=`number`||!Number.isInteger(u)||u<1e3||u>18e5)return r(`The requested duration is invalid.`,400);let d=Date.now();return this.activation=Object.freeze({requestId:(0,t.randomUUID)(),target:Object.freeze({...l}),durationSeconds:u/1e3,createdAt:d,confirmationExpiresAt:d+e.COMPUTER_USE_CONFIRMATION_WINDOW_MS,caller:Object.freeze({...s})}),this.phase=`awaiting_confirmation`,this.failure=void 0,this.artifact=void 0,this.changed(),Response.json(this.state(),{status:202})}rejectPending(e){let t=this.pending;t!==void 0&&(this.pending=void 0,t.dispose(),t.reject(Error(e)))}stopAfterUncertainRequest(e){this.phase===`active`&&(this.phase=`stopping`,this.changed()),this.rejectPending(e)}async enqueue(e,n,i){if(this.phase!==`active`||this.grantId===void 0)return r(`Computer use is not active.`,409);if(this.pending!==void 0)return r(`Another computer-use request is live.`,409);if(i?.aborted===!0)return r(`The computer-use request was cancelled.`,499);let a=e===`act`?++this.actionSequence:void 0,o={id:(0,t.randomUUID)(),operation:e,grantId:this.grantId,...a===void 0?{}:{sequence:a},...n===void 0?{}:{payload:n}},s=new Promise((e,t)=>{let n=()=>this.stopAfterUncertainRequest(`The computer-use request was cancelled.`),r=setTimeout(()=>this.stopAfterUncertainRequest(`The computer-use request timed out.`),this.requestTimeoutMs);r.unref?.(),i?.addEventListener(`abort`,n,{once:!0}),this.pending={request:o,resolve:e,reject:t,dispose:()=>{clearTimeout(r),i?.removeEventListener(`abort`,n)}}});this.changed();try{return Response.json(await s)}catch(e){return r(e instanceof Error?e.message:String(e),502)}}async fetch(t){if(this.closed)return r(`Computer-use broker is closed.`,503);let n=new URL(t.url).pathname;if(t.method===`POST`&&n===e.COMPUTER_USE_ROUTES.activate)return this.requestActivation(t);let c=n.startsWith(`/agent/`),l=n.startsWith(`/hub/`);if(c&&!this.authorized(t,this.internalToken)||l&&!this.authorized(t,this.hubToken))return r(`Not found.`,404);if(t.method===`GET`&&(n===e.COMPUTER_USE_ROUTES.agentState||n===e.COMPUTER_USE_ROUTES.hubState))return Response.json(this.state());if(t.method===`POST`&&n===e.COMPUTER_USE_ROUTES.agentObserve)return this.enqueue(`observe`,void 0,t.signal);if(t.method===`POST`&&n===e.COMPUTER_USE_ROUTES.agentAction){let e=await a(t);return o(e)?this.enqueue(`act`,e,t.signal):r(`A valid semantic action is required.`,400)}if(t.method===`POST`&&n===e.COMPUTER_USE_ROUTES.agentStop)return this.phase===`active`?(this.phase=`stopping`,this.rejectPending(`The computer-use request was stopped.`),this.changed(),Response.json(this.state(),{status:202})):r(`Computer use is not active.`,409);if(t.method===`GET`&&n===e.COMPUTER_USE_ROUTES.hubActivation)return this.activation===void 0||this.phase!==`awaiting_confirmation`?Response.json(null):(this.phase=`activating`,this.changed(),Response.json(this.activation));if(t.method===`GET`&&n===e.COMPUTER_USE_ROUTES.hubAuthorization)return Response.json(this.grantId===void 0?null:{grantId:this.grantId,expiresAt:this.expiresAt});if(t.method===`GET`&&n===e.COMPUTER_USE_ROUTES.hubNext)return Response.json(this.pending?.request??null);if(t.method===`POST`&&n===e.COMPUTER_USE_ROUTES.hubComplete){let e=await a(t),n=typeof e.id==`string`?e.id:void 0;if(this.pending===void 0||this.pending.request.id!==n)return r(`The request is stale.`,409);let i=this.pending;return this.pending=void 0,i.dispose(),this.changed(),typeof e.error==`string`?i.reject(Error(e.error)):i.resolve(e.result),Response.json(this.state())}if(t.method===`POST`&&n===e.COMPUTER_USE_ROUTES.hubStop){let e=await a(t);if(this.phase===`activating`){if(typeof e.error==`string`)this.phase=`failed`,this.failure={code:`desktop_unavailable`,message:e.error.slice(0,512)},this.activation=void 0;else{let t=i(e.host);if(typeof t?.grantId!=`string`||!Number.isFinite(t.expiresAt))return r(`Desktop did not issue a complete grant.`,502);this.grantId=t.grantId,this.expiresAt=t.expiresAt,this.actionSequence=0,this.phase=`active`}}else this.rejectPending(`The computer-use session stopped.`),this.phase=`inactive`,this.grantId=void 0,this.expiresAt=void 0,this.activation=void 0,this.artifact=s(e.artifact);return this.changed(),Response.json(this.state())}return r(`Not found.`,404)}close(){this.closed=!0,this.rejectPending(`Computer-use broker closed.`),this.grantId=void 0,this.expiresAt=void 0}};function l(e){return new c(e)}const u={basePath:e.API_BASE_PATH,start(e){if(e.directEvents===void 0)throw Error(`Computer-use API requires the session direct event bus.`);return l({...e.sessionId===void 0?{}:{sessionId:e.sessionId},...e.internalToken===void 0?{}:{internalToken:e.internalToken},...e.hubToken===void 0?{}:{hubToken:e.hubToken},directEvents:e.directEvents})}};exports.ComputerUseRequestBroker=c,exports.api=u,exports.createComputerUseApi=l;
2
+ //# sourceMappingURL=computerUseApi.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseApi.cjs","names":["COMPUTER_USE_WAKE_LIMIT","computerUseChannelType","doomApiCallerFrom","randomUUID","COMPUTER_USE_CONFIRMATION_WINDOW_MS","COMPUTER_USE_ROUTES","API_BASE_PATH"],"sources":["../../src/controllers/computerUseApi.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { DoomDirectEventBus } from '@agimon-ai/doompi-core/hub-channel';\nimport {\n doomApiCallerFrom,\n type DoomApi,\n type DoomApiContext,\n type DoomApiHandler,\n} from '@agimon-ai/doompi-core/package-api';\n\nimport {\n API_BASE_PATH,\n computerUseChannelType,\n COMPUTER_USE_CONFIRMATION_WINDOW_MS,\n COMPUTER_USE_MAX_DURATION_MS,\n COMPUTER_USE_ROUTES,\n COMPUTER_USE_WAKE_LIMIT,\n type ComputerUseActivationRequest,\n type ComputerUseArtifactView,\n type ComputerUseBrokerRequest,\n type ComputerUseSessionView,\n} from '../types/computerUseApi';\n\ninterface PendingRequest {\n readonly request: ComputerUseBrokerRequest;\n readonly dispose: () => void;\n resolve(value: unknown): void;\n reject(error: Error): void;\n}\n\nfunction jsonError(message: string, status: number): Response {\n return Response.json({ error: message }, { status });\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nasync function body(request: Request): Promise<Record<string, unknown>> {\n try {\n return record(await request.json()) ?? {};\n } catch {\n return {};\n }\n}\n\nfunction semanticAction(value: Record<string, unknown>): boolean {\n const base =\n typeof value.snapshotId === 'string' &&\n value.snapshotId.length > 0 &&\n typeof value.elementRef === 'string' &&\n value.elementRef.length > 0;\n if (!base) return false;\n const allowed = (keys: readonly string[]) => Object.keys(value).every((key) => keys.includes(key));\n if (value.kind === 'press' || value.kind === 'focus') return allowed(['kind', 'snapshotId', 'elementRef']);\n if (value.kind === 'set_value')\n return typeof value.value === 'string' && allowed(['kind', 'snapshotId', 'elementRef', 'value']);\n if (value.kind === 'scroll')\n return (\n ['up', 'down', 'left', 'right'].includes(value.direction as string) &&\n (value.amount === 'line' || value.amount === 'page') &&\n allowed(['kind', 'snapshotId', 'elementRef', 'direction', 'amount'])\n );\n return false;\n}\nfunction artifactView(value: unknown): ComputerUseArtifactView | undefined {\n const input = record(value);\n if (typeof input?.artifactId !== 'string' || (input.status !== 'ready' && input.status !== 'failed'))\n return undefined;\n const safeUrl = (candidate: unknown) =>\n typeof candidate === 'string' && candidate.startsWith('/api/') ? candidate : undefined;\n const downloadUrl = safeUrl(input.downloadUrl);\n const previewUrl = safeUrl(input.previewUrl);\n const artifactFailure = record(input.failure);\n const safeFailure =\n typeof artifactFailure?.code === 'string' && typeof artifactFailure.message === 'string'\n ? { code: artifactFailure.code.slice(0, 128), message: artifactFailure.message.slice(0, 512) }\n : undefined;\n return {\n artifactId: input.artifactId,\n status: input.status,\n ...(downloadUrl === undefined ? {} : { downloadUrl }),\n ...(previewUrl === undefined ? {} : { previewUrl }),\n ...(typeof input.actionCount === 'number' ? { actionCount: input.actionCount } : {}),\n ...(typeof input.completedAt === 'string' ? { completedAt: input.completedAt } : {}),\n ...(safeFailure === undefined ? {} : { failure: safeFailure }),\n };\n}\n\nexport interface ComputerUseApiOptions {\n readonly sessionId?: string;\n readonly internalToken?: string;\n readonly hubToken?: string;\n readonly directEvents: DoomDirectEventBus;\n readonly requestTimeoutMs?: number;\n}\n\nexport class ComputerUseRequestBroker implements DoomApiHandler {\n private readonly sessionId: string;\n private readonly internalToken?: string;\n private readonly hubToken?: string;\n private readonly directEvents: DoomDirectEventBus;\n private readonly requestTimeoutMs: number;\n private revision = 0;\n private wake = 0;\n private phase: ComputerUseSessionView['phase'] = 'inactive';\n private activation?: ComputerUseActivationRequest;\n private grantId?: string;\n private expiresAt?: number;\n private actionSequence = 0;\n private failure?: ComputerUseSessionView['failure'];\n private artifact?: ComputerUseArtifactView;\n private pending?: PendingRequest;\n private closed = false;\n\n private static readonly DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n public constructor(options: ComputerUseApiOptions) {\n this.sessionId = options.sessionId ?? 'unknown';\n this.internalToken = options.internalToken;\n this.hubToken = options.hubToken;\n this.directEvents = options.directEvents;\n this.requestTimeoutMs = options.requestTimeoutMs ?? ComputerUseRequestBroker.DEFAULT_REQUEST_TIMEOUT_MS;\n }\n\n public state(): ComputerUseSessionView {\n return Object.freeze({\n sessionId: this.sessionId,\n revision: this.revision,\n wake: this.wake,\n phase: this.phase,\n ...(this.activation === undefined\n ? {}\n : {\n requestId: this.activation.requestId,\n target: this.activation.target,\n durationMs: this.activation.durationSeconds * 1_000,\n }),\n ...(this.expiresAt === undefined ? {} : { expiresAt: this.expiresAt }),\n ...(this.failure === undefined ? {} : { failure: this.failure }),\n ...(this.artifact === undefined ? {} : { artifact: this.artifact }),\n });\n }\n\n private changed(): void {\n this.revision += 1;\n this.wake = (this.wake + 1) % COMPUTER_USE_WAKE_LIMIT;\n this.directEvents.publish(computerUseChannelType, this.sessionId, this.state());\n }\n\n private authorized(request: Request, token: string | undefined): boolean {\n return token !== undefined && request.headers.get('authorization') === `Bearer ${token}`;\n }\n\n private async requestActivation(request: Request): Promise<Response> {\n const caller = doomApiCallerFrom(request.headers);\n if (caller === undefined || (caller.locality === 'remote' && caller.stepUp === 'not-required'))\n return jsonError('Not found.', 404);\n if (this.phase !== 'inactive' && this.phase !== 'failed') return jsonError('Computer use is already busy.', 409);\n const input = await body(request);\n const target = record(input.target);\n const durationMs = input.durationMs;\n if (target === undefined || typeof target.windowId !== 'string' || typeof target.bundleId !== 'string')\n return jsonError('A Desktop target is required.', 400);\n if (\n typeof durationMs !== 'number' ||\n !Number.isInteger(durationMs) ||\n durationMs < 1_000 ||\n durationMs > COMPUTER_USE_MAX_DURATION_MS\n )\n return jsonError('The requested duration is invalid.', 400);\n const createdAt = Date.now();\n this.activation = Object.freeze({\n requestId: randomUUID(),\n target: Object.freeze({ ...target }),\n durationSeconds: durationMs / 1_000,\n createdAt,\n confirmationExpiresAt: createdAt + COMPUTER_USE_CONFIRMATION_WINDOW_MS,\n caller: Object.freeze({ ...caller }),\n });\n this.phase = 'awaiting_confirmation';\n this.failure = undefined;\n this.artifact = undefined;\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n\n private rejectPending(message: string): void {\n const pending = this.pending;\n if (pending === undefined) return;\n this.pending = undefined;\n pending.dispose();\n pending.reject(new Error(message));\n }\n\n private stopAfterUncertainRequest(message: string): void {\n if (this.phase === 'active') {\n this.phase = 'stopping';\n this.changed();\n }\n this.rejectPending(message);\n }\n\n private async enqueue(\n operation: ComputerUseBrokerRequest['operation'],\n payload?: unknown,\n signal?: AbortSignal,\n ): Promise<Response> {\n if (this.phase !== 'active' || this.grantId === undefined) return jsonError('Computer use is not active.', 409);\n if (this.pending !== undefined) return jsonError('Another computer-use request is live.', 409);\n if (signal?.aborted === true) return jsonError('The computer-use request was cancelled.', 499);\n const sequence = operation === 'act' ? ++this.actionSequence : undefined;\n const request: ComputerUseBrokerRequest = {\n id: randomUUID(),\n operation,\n grantId: this.grantId,\n ...(sequence === undefined ? {} : { sequence }),\n ...(payload === undefined ? {} : { payload }),\n };\n const completion = new Promise<unknown>((resolve, reject) => {\n const onAbort = () => this.stopAfterUncertainRequest('The computer-use request was cancelled.');\n const timer = setTimeout(\n () => this.stopAfterUncertainRequest('The computer-use request timed out.'),\n this.requestTimeoutMs,\n );\n timer.unref?.();\n signal?.addEventListener('abort', onAbort, { once: true });\n this.pending = {\n request,\n resolve,\n reject,\n dispose: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n },\n };\n });\n this.changed();\n try {\n return Response.json(await completion);\n } catch (error) {\n return jsonError(error instanceof Error ? error.message : String(error), 502);\n }\n }\n\n public async fetch(request: Request): Promise<Response> {\n if (this.closed) return jsonError('Computer-use broker is closed.', 503);\n const path = new URL(request.url).pathname;\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.activate) return this.requestActivation(request);\n const agent = path.startsWith('/agent/');\n const hub = path.startsWith('/hub/');\n if ((agent && !this.authorized(request, this.internalToken)) || (hub && !this.authorized(request, this.hubToken)))\n return jsonError('Not found.', 404);\n\n if (request.method === 'GET' && (path === COMPUTER_USE_ROUTES.agentState || path === COMPUTER_USE_ROUTES.hubState))\n return Response.json(this.state());\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.agentObserve)\n return this.enqueue('observe', undefined, request.signal);\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.agentAction) {\n const action = await body(request);\n if (!semanticAction(action)) return jsonError('A valid semantic action is required.', 400);\n return this.enqueue('act', action, request.signal);\n }\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.agentStop) {\n if (this.phase !== 'active') return jsonError('Computer use is not active.', 409);\n this.phase = 'stopping';\n this.rejectPending('The computer-use request was stopped.');\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n if (request.method === 'GET' && path === COMPUTER_USE_ROUTES.hubActivation) {\n if (this.activation === undefined || this.phase !== 'awaiting_confirmation') return Response.json(null);\n this.phase = 'activating';\n this.changed();\n return Response.json(this.activation);\n }\n if (request.method === 'GET' && path === COMPUTER_USE_ROUTES.hubAuthorization)\n return Response.json(this.grantId === undefined ? null : { grantId: this.grantId, expiresAt: this.expiresAt });\n if (request.method === 'GET' && path === COMPUTER_USE_ROUTES.hubNext)\n return Response.json(this.pending?.request ?? null);\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.hubComplete) {\n const input = await body(request);\n const id = typeof input.id === 'string' ? input.id : undefined;\n if (this.pending === undefined || this.pending.request.id !== id) return jsonError('The request is stale.', 409);\n const pending = this.pending;\n this.pending = undefined;\n pending.dispose();\n this.changed();\n if (typeof input.error === 'string') pending.reject(new Error(input.error));\n else pending.resolve(input.result);\n return Response.json(this.state());\n }\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.hubStop) {\n const input = await body(request);\n if (this.phase === 'activating') {\n if (typeof input.error === 'string') {\n this.phase = 'failed';\n this.failure = { code: 'desktop_unavailable', message: input.error.slice(0, 512) };\n this.activation = undefined;\n } else {\n const host = record(input.host);\n if (typeof host?.grantId !== 'string' || !Number.isFinite(host.expiresAt))\n return jsonError('Desktop did not issue a complete grant.', 502);\n this.grantId = host.grantId;\n this.expiresAt = host.expiresAt as number;\n this.actionSequence = 0;\n this.phase = 'active';\n }\n } else {\n this.rejectPending('The computer-use session stopped.');\n this.phase = 'inactive';\n this.grantId = undefined;\n this.expiresAt = undefined;\n this.activation = undefined;\n this.artifact = artifactView(input.artifact);\n }\n this.changed();\n return Response.json(this.state());\n }\n return jsonError('Not found.', 404);\n }\n\n public close(): void {\n this.closed = true;\n this.rejectPending('Computer-use broker closed.');\n this.grantId = undefined;\n this.expiresAt = undefined;\n }\n}\n\nexport function createComputerUseApi(options: ComputerUseApiOptions): ComputerUseRequestBroker {\n return new ComputerUseRequestBroker(options);\n}\n\nexport const api: DoomApi = {\n basePath: API_BASE_PATH,\n start(context: DoomApiContext): DoomApiHandler {\n if (context.directEvents === undefined) throw new Error('Computer-use API requires the session direct event bus.');\n return createComputerUseApi({\n ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),\n ...(context.internalToken === undefined ? {} : { internalToken: context.internalToken }),\n ...(context.hubToken === undefined ? {} : { hubToken: context.hubToken }),\n directEvents: context.directEvents,\n });\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{API_BASE_PATH as e,COMPUTER_USE_CONFIRMATION_WINDOW_MS as t,COMPUTER_USE_ROUTES as n,COMPUTER_USE_WAKE_LIMIT as r,computerUseChannelType as i}from"../types/computerUseApi.mjs";import{randomUUID as a}from"node:crypto";import{doomApiCallerFrom as o}from"@agimon-ai/doompi-core/package-api";function s(e,t){return Response.json({error:e},{status:t})}function c(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:void 0}async function l(e){try{return c(await e.json())??{}}catch{return{}}}function u(e){if(!(typeof e.snapshotId==`string`&&e.snapshotId.length>0&&typeof e.elementRef==`string`&&e.elementRef.length>0))return!1;let t=t=>Object.keys(e).every(e=>t.includes(e));return e.kind===`press`||e.kind===`focus`?t([`kind`,`snapshotId`,`elementRef`]):e.kind===`set_value`?typeof e.value==`string`&&t([`kind`,`snapshotId`,`elementRef`,`value`]):e.kind===`scroll`&&[`up`,`down`,`left`,`right`].includes(e.direction)&&(e.amount===`line`||e.amount===`page`)&&t([`kind`,`snapshotId`,`elementRef`,`direction`,`amount`])}function d(e){let t=c(e);if(typeof t?.artifactId!=`string`||t.status!==`ready`&&t.status!==`failed`)return;let n=e=>typeof e==`string`&&e.startsWith(`/api/`)?e:void 0,r=n(t.downloadUrl),i=n(t.previewUrl),a=c(t.failure),o=typeof a?.code==`string`&&typeof a.message==`string`?{code:a.code.slice(0,128),message:a.message.slice(0,512)}:void 0;return{artifactId:t.artifactId,status:t.status,...r===void 0?{}:{downloadUrl:r},...i===void 0?{}:{previewUrl:i},...typeof t.actionCount==`number`?{actionCount:t.actionCount}:{},...typeof t.completedAt==`string`?{completedAt:t.completedAt}:{},...o===void 0?{}:{failure:o}}}var f=class e{sessionId;internalToken;hubToken;directEvents;requestTimeoutMs;revision=0;wake=0;phase=`inactive`;activation;grantId;expiresAt;actionSequence=0;failure;artifact;pending;closed=!1;static DEFAULT_REQUEST_TIMEOUT_MS=3e4;constructor(t){this.sessionId=t.sessionId??`unknown`,this.internalToken=t.internalToken,this.hubToken=t.hubToken,this.directEvents=t.directEvents,this.requestTimeoutMs=t.requestTimeoutMs??e.DEFAULT_REQUEST_TIMEOUT_MS}state(){return Object.freeze({sessionId:this.sessionId,revision:this.revision,wake:this.wake,phase:this.phase,...this.activation===void 0?{}:{requestId:this.activation.requestId,target:this.activation.target,durationMs:this.activation.durationSeconds*1e3},...this.expiresAt===void 0?{}:{expiresAt:this.expiresAt},...this.failure===void 0?{}:{failure:this.failure},...this.artifact===void 0?{}:{artifact:this.artifact}})}changed(){this.revision+=1,this.wake=(this.wake+1)%r,this.directEvents.publish(i,this.sessionId,this.state())}authorized(e,t){return t!==void 0&&e.headers.get(`authorization`)===`Bearer ${t}`}async requestActivation(e){let n=o(e.headers);if(n===void 0||n.locality===`remote`&&n.stepUp===`not-required`)return s(`Not found.`,404);if(this.phase!==`inactive`&&this.phase!==`failed`)return s(`Computer use is already busy.`,409);let r=await l(e),i=c(r.target),u=r.durationMs;if(i===void 0||typeof i.windowId!=`string`||typeof i.bundleId!=`string`)return s(`A Desktop target is required.`,400);if(typeof u!=`number`||!Number.isInteger(u)||u<1e3||u>18e5)return s(`The requested duration is invalid.`,400);let d=Date.now();return this.activation=Object.freeze({requestId:a(),target:Object.freeze({...i}),durationSeconds:u/1e3,createdAt:d,confirmationExpiresAt:d+t,caller:Object.freeze({...n})}),this.phase=`awaiting_confirmation`,this.failure=void 0,this.artifact=void 0,this.changed(),Response.json(this.state(),{status:202})}rejectPending(e){let t=this.pending;t!==void 0&&(this.pending=void 0,t.dispose(),t.reject(Error(e)))}stopAfterUncertainRequest(e){this.phase===`active`&&(this.phase=`stopping`,this.changed()),this.rejectPending(e)}async enqueue(e,t,n){if(this.phase!==`active`||this.grantId===void 0)return s(`Computer use is not active.`,409);if(this.pending!==void 0)return s(`Another computer-use request is live.`,409);if(n?.aborted===!0)return s(`The computer-use request was cancelled.`,499);let r=e===`act`?++this.actionSequence:void 0,i={id:a(),operation:e,grantId:this.grantId,...r===void 0?{}:{sequence:r},...t===void 0?{}:{payload:t}},o=new Promise((e,t)=>{let r=()=>this.stopAfterUncertainRequest(`The computer-use request was cancelled.`),a=setTimeout(()=>this.stopAfterUncertainRequest(`The computer-use request timed out.`),this.requestTimeoutMs);a.unref?.(),n?.addEventListener(`abort`,r,{once:!0}),this.pending={request:i,resolve:e,reject:t,dispose:()=>{clearTimeout(a),n?.removeEventListener(`abort`,r)}}});this.changed();try{return Response.json(await o)}catch(e){return s(e instanceof Error?e.message:String(e),502)}}async fetch(e){if(this.closed)return s(`Computer-use broker is closed.`,503);let t=new URL(e.url).pathname;if(e.method===`POST`&&t===n.activate)return this.requestActivation(e);let r=t.startsWith(`/agent/`),i=t.startsWith(`/hub/`);if(r&&!this.authorized(e,this.internalToken)||i&&!this.authorized(e,this.hubToken))return s(`Not found.`,404);if(e.method===`GET`&&(t===n.agentState||t===n.hubState))return Response.json(this.state());if(e.method===`POST`&&t===n.agentObserve)return this.enqueue(`observe`,void 0,e.signal);if(e.method===`POST`&&t===n.agentAction){let t=await l(e);return u(t)?this.enqueue(`act`,t,e.signal):s(`A valid semantic action is required.`,400)}if(e.method===`POST`&&t===n.agentStop)return this.phase===`active`?(this.phase=`stopping`,this.rejectPending(`The computer-use request was stopped.`),this.changed(),Response.json(this.state(),{status:202})):s(`Computer use is not active.`,409);if(e.method===`GET`&&t===n.hubActivation)return this.activation===void 0||this.phase!==`awaiting_confirmation`?Response.json(null):(this.phase=`activating`,this.changed(),Response.json(this.activation));if(e.method===`GET`&&t===n.hubAuthorization)return Response.json(this.grantId===void 0?null:{grantId:this.grantId,expiresAt:this.expiresAt});if(e.method===`GET`&&t===n.hubNext)return Response.json(this.pending?.request??null);if(e.method===`POST`&&t===n.hubComplete){let t=await l(e),n=typeof t.id==`string`?t.id:void 0;if(this.pending===void 0||this.pending.request.id!==n)return s(`The request is stale.`,409);let r=this.pending;return this.pending=void 0,r.dispose(),this.changed(),typeof t.error==`string`?r.reject(Error(t.error)):r.resolve(t.result),Response.json(this.state())}if(e.method===`POST`&&t===n.hubStop){let t=await l(e);if(this.phase===`activating`){if(typeof t.error==`string`)this.phase=`failed`,this.failure={code:`desktop_unavailable`,message:t.error.slice(0,512)},this.activation=void 0;else{let e=c(t.host);if(typeof e?.grantId!=`string`||!Number.isFinite(e.expiresAt))return s(`Desktop did not issue a complete grant.`,502);this.grantId=e.grantId,this.expiresAt=e.expiresAt,this.actionSequence=0,this.phase=`active`}}else this.rejectPending(`The computer-use session stopped.`),this.phase=`inactive`,this.grantId=void 0,this.expiresAt=void 0,this.activation=void 0,this.artifact=d(t.artifact);return this.changed(),Response.json(this.state())}return s(`Not found.`,404)}close(){this.closed=!0,this.rejectPending(`Computer-use broker closed.`),this.grantId=void 0,this.expiresAt=void 0}};function p(e){return new f(e)}const m={basePath:e,start(e){if(e.directEvents===void 0)throw Error(`Computer-use API requires the session direct event bus.`);return p({...e.sessionId===void 0?{}:{sessionId:e.sessionId},...e.internalToken===void 0?{}:{internalToken:e.internalToken},...e.hubToken===void 0?{}:{hubToken:e.hubToken},directEvents:e.directEvents})}};export{f as ComputerUseRequestBroker,m as api,p as createComputerUseApi};
2
+ //# sourceMappingURL=computerUseApi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseApi.mjs","names":[],"sources":["../../src/controllers/computerUseApi.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { DoomDirectEventBus } from '@agimon-ai/doompi-core/hub-channel';\nimport {\n doomApiCallerFrom,\n type DoomApi,\n type DoomApiContext,\n type DoomApiHandler,\n} from '@agimon-ai/doompi-core/package-api';\n\nimport {\n API_BASE_PATH,\n computerUseChannelType,\n COMPUTER_USE_CONFIRMATION_WINDOW_MS,\n COMPUTER_USE_MAX_DURATION_MS,\n COMPUTER_USE_ROUTES,\n COMPUTER_USE_WAKE_LIMIT,\n type ComputerUseActivationRequest,\n type ComputerUseArtifactView,\n type ComputerUseBrokerRequest,\n type ComputerUseSessionView,\n} from '../types/computerUseApi';\n\ninterface PendingRequest {\n readonly request: ComputerUseBrokerRequest;\n readonly dispose: () => void;\n resolve(value: unknown): void;\n reject(error: Error): void;\n}\n\nfunction jsonError(message: string, status: number): Response {\n return Response.json({ error: message }, { status });\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nasync function body(request: Request): Promise<Record<string, unknown>> {\n try {\n return record(await request.json()) ?? {};\n } catch {\n return {};\n }\n}\n\nfunction semanticAction(value: Record<string, unknown>): boolean {\n const base =\n typeof value.snapshotId === 'string' &&\n value.snapshotId.length > 0 &&\n typeof value.elementRef === 'string' &&\n value.elementRef.length > 0;\n if (!base) return false;\n const allowed = (keys: readonly string[]) => Object.keys(value).every((key) => keys.includes(key));\n if (value.kind === 'press' || value.kind === 'focus') return allowed(['kind', 'snapshotId', 'elementRef']);\n if (value.kind === 'set_value')\n return typeof value.value === 'string' && allowed(['kind', 'snapshotId', 'elementRef', 'value']);\n if (value.kind === 'scroll')\n return (\n ['up', 'down', 'left', 'right'].includes(value.direction as string) &&\n (value.amount === 'line' || value.amount === 'page') &&\n allowed(['kind', 'snapshotId', 'elementRef', 'direction', 'amount'])\n );\n return false;\n}\nfunction artifactView(value: unknown): ComputerUseArtifactView | undefined {\n const input = record(value);\n if (typeof input?.artifactId !== 'string' || (input.status !== 'ready' && input.status !== 'failed'))\n return undefined;\n const safeUrl = (candidate: unknown) =>\n typeof candidate === 'string' && candidate.startsWith('/api/') ? candidate : undefined;\n const downloadUrl = safeUrl(input.downloadUrl);\n const previewUrl = safeUrl(input.previewUrl);\n const artifactFailure = record(input.failure);\n const safeFailure =\n typeof artifactFailure?.code === 'string' && typeof artifactFailure.message === 'string'\n ? { code: artifactFailure.code.slice(0, 128), message: artifactFailure.message.slice(0, 512) }\n : undefined;\n return {\n artifactId: input.artifactId,\n status: input.status,\n ...(downloadUrl === undefined ? {} : { downloadUrl }),\n ...(previewUrl === undefined ? {} : { previewUrl }),\n ...(typeof input.actionCount === 'number' ? { actionCount: input.actionCount } : {}),\n ...(typeof input.completedAt === 'string' ? { completedAt: input.completedAt } : {}),\n ...(safeFailure === undefined ? {} : { failure: safeFailure }),\n };\n}\n\nexport interface ComputerUseApiOptions {\n readonly sessionId?: string;\n readonly internalToken?: string;\n readonly hubToken?: string;\n readonly directEvents: DoomDirectEventBus;\n readonly requestTimeoutMs?: number;\n}\n\nexport class ComputerUseRequestBroker implements DoomApiHandler {\n private readonly sessionId: string;\n private readonly internalToken?: string;\n private readonly hubToken?: string;\n private readonly directEvents: DoomDirectEventBus;\n private readonly requestTimeoutMs: number;\n private revision = 0;\n private wake = 0;\n private phase: ComputerUseSessionView['phase'] = 'inactive';\n private activation?: ComputerUseActivationRequest;\n private grantId?: string;\n private expiresAt?: number;\n private actionSequence = 0;\n private failure?: ComputerUseSessionView['failure'];\n private artifact?: ComputerUseArtifactView;\n private pending?: PendingRequest;\n private closed = false;\n\n private static readonly DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n public constructor(options: ComputerUseApiOptions) {\n this.sessionId = options.sessionId ?? 'unknown';\n this.internalToken = options.internalToken;\n this.hubToken = options.hubToken;\n this.directEvents = options.directEvents;\n this.requestTimeoutMs = options.requestTimeoutMs ?? ComputerUseRequestBroker.DEFAULT_REQUEST_TIMEOUT_MS;\n }\n\n public state(): ComputerUseSessionView {\n return Object.freeze({\n sessionId: this.sessionId,\n revision: this.revision,\n wake: this.wake,\n phase: this.phase,\n ...(this.activation === undefined\n ? {}\n : {\n requestId: this.activation.requestId,\n target: this.activation.target,\n durationMs: this.activation.durationSeconds * 1_000,\n }),\n ...(this.expiresAt === undefined ? {} : { expiresAt: this.expiresAt }),\n ...(this.failure === undefined ? {} : { failure: this.failure }),\n ...(this.artifact === undefined ? {} : { artifact: this.artifact }),\n });\n }\n\n private changed(): void {\n this.revision += 1;\n this.wake = (this.wake + 1) % COMPUTER_USE_WAKE_LIMIT;\n this.directEvents.publish(computerUseChannelType, this.sessionId, this.state());\n }\n\n private authorized(request: Request, token: string | undefined): boolean {\n return token !== undefined && request.headers.get('authorization') === `Bearer ${token}`;\n }\n\n private async requestActivation(request: Request): Promise<Response> {\n const caller = doomApiCallerFrom(request.headers);\n if (caller === undefined || (caller.locality === 'remote' && caller.stepUp === 'not-required'))\n return jsonError('Not found.', 404);\n if (this.phase !== 'inactive' && this.phase !== 'failed') return jsonError('Computer use is already busy.', 409);\n const input = await body(request);\n const target = record(input.target);\n const durationMs = input.durationMs;\n if (target === undefined || typeof target.windowId !== 'string' || typeof target.bundleId !== 'string')\n return jsonError('A Desktop target is required.', 400);\n if (\n typeof durationMs !== 'number' ||\n !Number.isInteger(durationMs) ||\n durationMs < 1_000 ||\n durationMs > COMPUTER_USE_MAX_DURATION_MS\n )\n return jsonError('The requested duration is invalid.', 400);\n const createdAt = Date.now();\n this.activation = Object.freeze({\n requestId: randomUUID(),\n target: Object.freeze({ ...target }),\n durationSeconds: durationMs / 1_000,\n createdAt,\n confirmationExpiresAt: createdAt + COMPUTER_USE_CONFIRMATION_WINDOW_MS,\n caller: Object.freeze({ ...caller }),\n });\n this.phase = 'awaiting_confirmation';\n this.failure = undefined;\n this.artifact = undefined;\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n\n private rejectPending(message: string): void {\n const pending = this.pending;\n if (pending === undefined) return;\n this.pending = undefined;\n pending.dispose();\n pending.reject(new Error(message));\n }\n\n private stopAfterUncertainRequest(message: string): void {\n if (this.phase === 'active') {\n this.phase = 'stopping';\n this.changed();\n }\n this.rejectPending(message);\n }\n\n private async enqueue(\n operation: ComputerUseBrokerRequest['operation'],\n payload?: unknown,\n signal?: AbortSignal,\n ): Promise<Response> {\n if (this.phase !== 'active' || this.grantId === undefined) return jsonError('Computer use is not active.', 409);\n if (this.pending !== undefined) return jsonError('Another computer-use request is live.', 409);\n if (signal?.aborted === true) return jsonError('The computer-use request was cancelled.', 499);\n const sequence = operation === 'act' ? ++this.actionSequence : undefined;\n const request: ComputerUseBrokerRequest = {\n id: randomUUID(),\n operation,\n grantId: this.grantId,\n ...(sequence === undefined ? {} : { sequence }),\n ...(payload === undefined ? {} : { payload }),\n };\n const completion = new Promise<unknown>((resolve, reject) => {\n const onAbort = () => this.stopAfterUncertainRequest('The computer-use request was cancelled.');\n const timer = setTimeout(\n () => this.stopAfterUncertainRequest('The computer-use request timed out.'),\n this.requestTimeoutMs,\n );\n timer.unref?.();\n signal?.addEventListener('abort', onAbort, { once: true });\n this.pending = {\n request,\n resolve,\n reject,\n dispose: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n },\n };\n });\n this.changed();\n try {\n return Response.json(await completion);\n } catch (error) {\n return jsonError(error instanceof Error ? error.message : String(error), 502);\n }\n }\n\n public async fetch(request: Request): Promise<Response> {\n if (this.closed) return jsonError('Computer-use broker is closed.', 503);\n const path = new URL(request.url).pathname;\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.activate) return this.requestActivation(request);\n const agent = path.startsWith('/agent/');\n const hub = path.startsWith('/hub/');\n if ((agent && !this.authorized(request, this.internalToken)) || (hub && !this.authorized(request, this.hubToken)))\n return jsonError('Not found.', 404);\n\n if (request.method === 'GET' && (path === COMPUTER_USE_ROUTES.agentState || path === COMPUTER_USE_ROUTES.hubState))\n return Response.json(this.state());\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.agentObserve)\n return this.enqueue('observe', undefined, request.signal);\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.agentAction) {\n const action = await body(request);\n if (!semanticAction(action)) return jsonError('A valid semantic action is required.', 400);\n return this.enqueue('act', action, request.signal);\n }\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.agentStop) {\n if (this.phase !== 'active') return jsonError('Computer use is not active.', 409);\n this.phase = 'stopping';\n this.rejectPending('The computer-use request was stopped.');\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n if (request.method === 'GET' && path === COMPUTER_USE_ROUTES.hubActivation) {\n if (this.activation === undefined || this.phase !== 'awaiting_confirmation') return Response.json(null);\n this.phase = 'activating';\n this.changed();\n return Response.json(this.activation);\n }\n if (request.method === 'GET' && path === COMPUTER_USE_ROUTES.hubAuthorization)\n return Response.json(this.grantId === undefined ? null : { grantId: this.grantId, expiresAt: this.expiresAt });\n if (request.method === 'GET' && path === COMPUTER_USE_ROUTES.hubNext)\n return Response.json(this.pending?.request ?? null);\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.hubComplete) {\n const input = await body(request);\n const id = typeof input.id === 'string' ? input.id : undefined;\n if (this.pending === undefined || this.pending.request.id !== id) return jsonError('The request is stale.', 409);\n const pending = this.pending;\n this.pending = undefined;\n pending.dispose();\n this.changed();\n if (typeof input.error === 'string') pending.reject(new Error(input.error));\n else pending.resolve(input.result);\n return Response.json(this.state());\n }\n if (request.method === 'POST' && path === COMPUTER_USE_ROUTES.hubStop) {\n const input = await body(request);\n if (this.phase === 'activating') {\n if (typeof input.error === 'string') {\n this.phase = 'failed';\n this.failure = { code: 'desktop_unavailable', message: input.error.slice(0, 512) };\n this.activation = undefined;\n } else {\n const host = record(input.host);\n if (typeof host?.grantId !== 'string' || !Number.isFinite(host.expiresAt))\n return jsonError('Desktop did not issue a complete grant.', 502);\n this.grantId = host.grantId;\n this.expiresAt = host.expiresAt as number;\n this.actionSequence = 0;\n this.phase = 'active';\n }\n } else {\n this.rejectPending('The computer-use session stopped.');\n this.phase = 'inactive';\n this.grantId = undefined;\n this.expiresAt = undefined;\n this.activation = undefined;\n this.artifact = artifactView(input.artifact);\n }\n this.changed();\n return Response.json(this.state());\n }\n return jsonError('Not found.', 404);\n }\n\n public close(): void {\n this.closed = true;\n this.rejectPending('Computer-use broker closed.');\n this.grantId = undefined;\n this.expiresAt = undefined;\n }\n}\n\nexport function createComputerUseApi(options: ComputerUseApiOptions): ComputerUseRequestBroker {\n return new ComputerUseRequestBroker(options);\n}\n\nexport const api: DoomApi = {\n basePath: API_BASE_PATH,\n start(context: DoomApiContext): DoomApiHandler {\n if (context.directEvents === undefined) throw new Error('Computer-use API requires the session direct event bus.');\n return createComputerUseApi({\n ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),\n ...(context.internalToken === undefined ? {} : { internalToken: context.internalToken }),\n ...(context.hubToken === undefined ? {} : { hubToken: context.hubToken }),\n directEvents: context.directEvents,\n });\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../constants/computerUse.cjs");function t(t){return[e.COMMAND_NAME,{description:e.COMMAND_DESCRIPTION,handler:async(e,n)=>{let r=await t.execute();n.hasUI&&n.ui.notify(r.message,r.level)}}]}exports.createComputerUseCommand=t;
2
+ //# sourceMappingURL=computerUseCommand.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseCommand.cjs","names":["COMMAND_NAME","COMMAND_DESCRIPTION"],"sources":["../../src/controllers/computerUseCommand.ts"],"sourcesContent":["// @scaffold-generated\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\nimport { COMMAND_NAME, COMMAND_DESCRIPTION } from '../constants/computerUse';\nimport type { ComputerUseExtensionService } from '../types/extension';\n\nexport function createComputerUseCommand(\n service: ComputerUseExtensionService,\n): Parameters<ExtensionAPI['registerCommand']> {\n return [\n COMMAND_NAME,\n {\n description: COMMAND_DESCRIPTION,\n handler: async (_args, ctx) => {\n const result = await service.execute();\n if (ctx.hasUI) ctx.ui.notify(result.message, result.level);\n },\n },\n ];\n}\n\nexport { COMMAND_NAME, COMMAND_DESCRIPTION } from '../constants/computerUse';\n"],"mappings":"gDAMA,SAAgB,EACd,EAC6C,CAC7C,MAAO,CACLA,EAAAA,aACA,CACE,YAAaC,EAAAA,oBACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,IAAM,EAAS,MAAM,EAAQ,QAAQ,EACjC,EAAI,OAAO,EAAI,GAAG,OAAO,EAAO,QAAS,EAAO,KAAK,CAC3D,CACF,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ import{COMMAND_DESCRIPTION as e,COMMAND_NAME as t}from"../constants/computerUse.mjs";function n(n){return[t,{description:e,handler:async(e,t)=>{let r=await n.execute();t.hasUI&&t.ui.notify(r.message,r.level)}}]}export{n as createComputerUseCommand};
2
+ //# sourceMappingURL=computerUseCommand.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseCommand.mjs","names":[],"sources":["../../src/controllers/computerUseCommand.ts"],"sourcesContent":["// @scaffold-generated\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\nimport { COMMAND_NAME, COMMAND_DESCRIPTION } from '../constants/computerUse';\nimport type { ComputerUseExtensionService } from '../types/extension';\n\nexport function createComputerUseCommand(\n service: ComputerUseExtensionService,\n): Parameters<ExtensionAPI['registerCommand']> {\n return [\n COMMAND_NAME,\n {\n description: COMMAND_DESCRIPTION,\n handler: async (_args, ctx) => {\n const result = await service.execute();\n if (ctx.hasUI) ctx.ui.notify(result.message, result.level);\n },\n },\n ];\n}\n\nexport { COMMAND_NAME, COMMAND_DESCRIPTION } from '../constants/computerUse';\n"],"mappings":"qFAMA,SAAgB,EACd,EAC6C,CAC7C,MAAO,CACL,EACA,CACE,YAAa,EACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,IAAM,EAAS,MAAM,EAAQ,QAAQ,EACjC,EAAI,OAAO,EAAI,GAAG,OAAO,EAAO,QAAS,EAAO,KAAK,CAC3D,CACF,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ const e=require("../constants/computerUse.cjs"),t=require("../types/computerUseApi.cjs"),n=require("./computerUseCommand.cjs"),r=require("../models/computerUseMode.cjs");let i=require("@agimon-ai/doompi-minor-mode");const a=`@agimon-ai/doompi-computer-use`;function o(o,s){let c=o.client,l,u=!1,d=r.computerUseRestriction(!1),f=new Set,p=e=>{d=r.computerUseRestriction(e);for(let e of f)e()},m=!1,h,g=new Set,_,v,y=``,b,x,S=()=>{let e=l?.phase??`inactive`,n=`${u}:${e}:${l?.revision??`none`}`;h!==void 0&&n!==y&&(h.publish(),y=n);let r=l===void 0?void 0:u||e!==`inactive`?e:``;v!==void 0&&r!==b&&(v.ui.setStatus(t.COMPUTER_USE_MODE_STATUS_KEY,r),b=r);let i=u||e!==`inactive`?`computer use: ${e}`:void 0;v!==void 0&&i!==x&&(v.ui.setStatus(t.COMPUTER_USE_STATUS_KEY,i),x=i)},C=async()=>{if(s.aborted)return;let e=!1;try{e=await o.enabled?.()===!0}catch{e=!1}if(!s.aborted){if(e!==m){if(m=e,!m){if(c!==void 0&&l!==void 0&&l.phase!==`inactive`&&l.phase!==`failed`)try{await c.stop()}catch{}u=!1,l=void 0,p(!1)}y=``;for(let e of g)e()}if(!m||c===void 0){l=void 0,p(!1),S();return}try{let e=await c.state(s);if(s.aborted)return;l=e,p(l.phase===`active`),S()}catch{l=void 0,p(!1),S()}}};return h=(0,i.defineMinorMode)({descriptor:{source:a,id:t.COMPUTER_USE_MODE_ID,label:`Computer Use`,description:`Session-scoped semantic control through DoomPi Desktop.`,order:450,actions:[{id:`activate`,label:`Activate`,description:`Open the cockpit activation workflow and native confirmation.`,contexts:[`tui`,`headless`],parameters:[]},{id:`deactivate`,label:`Deactivate`,description:`Stop this session computer-use run.`,contexts:[`tui`,`headless`],parameters:[]},{id:`doctor`,label:`Doctor`,description:`Report Desktop availability and session state.`,contexts:[`tui`,`headless`],parameters:[]}]},state:()=>r.modeState(l,u),async handleAction(e,t,n,r){if(v=r.context,t===`activate`){if(await o.enabled?.()!==!0)throw await C(),Error(`Enable computer use in global settings first.`);if(c===void 0)throw Error(`DoomPi Desktop computer use is unavailable.`);return u=!0,await C(),S(),{message:`Computer use is ready to configure in Activity.`}}if(t===`doctor`)return await C(),{message:c===void 0?`DoomPi Desktop session API is unavailable.`:`Computer use is ${l?.phase.replaceAll(`_`,` `)??`unavailable`}.`};if(t===`deactivate`){if(c===void 0)throw Error(`DoomPi Desktop computer use is unavailable.`);return l!==void 0&&l.phase!==`inactive`&&l.phase!==`failed`&&await c.stop(r.signal),u=!1,await C(),S(),{message:`Computer use is off.`}}throw Error(`Unknown computer-use action: ${t}`)}}).createOwner(void 0),{commands:[n.createComputerUseCommand(o.service)],tools:[{name:`computer_state`,label:`Computer State`,description:`Observe the authorized application window and return its semantic accessibility state.`,promptSnippet:`Observe the authorized application before choosing a semantic action`,parameters:{type:`object`,properties:{},additionalProperties:!1},async execute(e,t,n){if(!m||c===void 0||l?.phase!==`active`)throw Error(`Computer use is not active for this session.`);let r=await c.observe(n);return{content:[{type:`text`,text:JSON.stringify(r,null,2)}],details:r}}},{name:`computer_action`,label:`Computer Action`,description:`Perform one constrained semantic action in the authorized application window.`,promptSnippet:`Perform one action using a current computer_state snapshot and element ref`,parameters:{type:`object`,properties:{kind:{type:`string`,enum:[`press`,`focus`,`set_value`,`scroll`]},snapshotId:{type:`string`},elementRef:{type:`string`},value:{type:`string`},direction:{type:`string`,enum:[`up`,`down`,`left`,`right`]},amount:{type:`string`,enum:[`line`,`page`]}},required:[`kind`,`snapshotId`,`elementRef`],additionalProperties:!1},async execute(e,t,n){if(!m||c===void 0||l?.phase!==`active`)throw Error(`Computer use is not active for this session.`);let r=await c.act(t,n);return{content:[{type:`text`,text:JSON.stringify(r,null,2)}],details:r}}},{name:`computer_exec`,label:`Computer Script`,description:`Run a trusted, explicitly allowed local TypeScript script against the authorized application session.`,promptSnippet:`Run a trusted reusable computer script by its explicitly allowed path and JSON input`,parameters:{type:`object`,properties:{scriptPath:{type:`string`},input:{}},required:[`scriptPath`,`input`],additionalProperties:!1},async execute(e,t,n){if(!m||c===void 0||l?.phase!==`active`)throw Error(`Computer use is not active for this session.`);if(o.scriptRunner===void 0)throw Error(`Computer script execution is unavailable.`);let r=t,i=await o.scriptRunner.execute(r.scriptPath,r.input,n);return{content:[{type:`text`,text:JSON.stringify(i,null,2)}],details:i}}}],services:[(0,i.piMinorModes)({snapshot:()=>m?[h]:[],subscribe(e){return g.add(e),()=>{g.delete(e)}}})],toolRestrictions:[{source:a,restrict:(e,t)=>d(e,t),subscribe(e){return f.add(e),()=>{f.delete(e)}}}],events:{before_agent_start:t=>m&&l?.phase===`active`?{systemPrompt:`${t.systemPrompt}\n\n${e.COMPUTER_USE_GUIDANCE}`}:void 0,session_start:(e,t)=>{s.aborted||(v=t,p(!1),C(),_&&clearInterval(_),_=setInterval(()=>void C(),250),_.unref?.())}},onStop(){_&&clearInterval(_),_=void 0},onDispose(){_&&clearInterval(_),_=void 0,p(!1),v?.ui.setStatus(t.COMPUTER_USE_MODE_STATUS_KEY,void 0),v?.ui.setStatus(t.COMPUTER_USE_STATUS_KEY,void 0),v=void 0}}}exports.COMPUTER_USE_MODE_ID=t.COMPUTER_USE_MODE_ID,exports.createComputerUseRuntime=o;
2
+ //# sourceMappingURL=computerUseRuntime.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseRuntime.cjs","names":["computerUseRestriction","COMPUTER_USE_MODE_STATUS_KEY","COMPUTER_USE_STATUS_KEY","defineMinorMode","COMPUTER_USE_MODE_ID","modeState","createComputerUseCommand","piMinorModes","COMPUTER_USE_GUIDANCE"],"sources":["../../src/controllers/computerUseRuntime.ts"],"sourcesContent":["import { type PiPluginContributions } from '@agimon-ai/doompi-core/pi-extension';\nimport { type DoomToolRestriction } from '@agimon-ai/doompi-core/tool-surface';\nimport { piMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeOwnerActionContext } from '@agimon-ai/doompi-minor-mode';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { COMPUTER_USE_GUIDANCE } from '../constants/computerUse';\nimport type { ComputerUseAction } from '../types/computerUse';\nimport {\n COMPUTER_USE_MODE_ID,\n COMPUTER_USE_MODE_STATUS_KEY,\n COMPUTER_USE_STATUS_KEY,\n type ComputerUseSessionView,\n} from '../types/computerUseApi';\nimport type { ComputerUseExtensionDependencies } from '../types/extension';\nimport { createComputerUseCommand } from './computerUseCommand';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-computer-use';\nexport { COMPUTER_USE_MODE_ID };\nimport { modeState, computerUseRestriction } from '../models/computerUseMode';\n\nexport function createComputerUseRuntime(\n dependencies: ComputerUseExtensionDependencies,\n signal: AbortSignal,\n): PiPluginContributions<ComputerUseExtensionDependencies> & {\n tools: readonly Parameters<ExtensionAPI['registerTool']>[0][];\n} {\n const client = dependencies.client;\n let state: ComputerUseSessionView | undefined;\n let enabled = false;\n let restriction: DoomToolRestriction = computerUseRestriction(false);\n const restrictionListeners = new Set<() => void>();\n const reconcileTools = (active: boolean): void => {\n restriction = computerUseRestriction(active);\n for (const listener of restrictionListeners) listener();\n };\n let globallyEnabled = false;\n let mode: MinorModeOwner<MinorModeOwnerActionContext<ExtensionContext>>;\n const modeListeners = new Set<() => void>();\n let timer: ReturnType<typeof setInterval> | undefined;\n let activeContext: ExtensionContext | undefined;\n let publishedMode = '';\n let publishedModeStatus: string | undefined;\n let publishedActivityStatus: string | undefined;\n const publish = (): void => {\n const phase = state?.phase ?? 'inactive';\n const projection = `${enabled}:${phase}:${state?.revision ?? 'none'}`;\n if (mode !== undefined && projection !== publishedMode) {\n mode.publish();\n publishedMode = projection;\n }\n const modeStatus = state === undefined ? undefined : enabled || phase !== 'inactive' ? phase : '';\n if (activeContext !== undefined && modeStatus !== publishedModeStatus) {\n activeContext.ui.setStatus(COMPUTER_USE_MODE_STATUS_KEY, modeStatus);\n publishedModeStatus = modeStatus;\n }\n const activityStatus = enabled || phase !== 'inactive' ? `computer use: ${phase}` : undefined;\n if (activeContext !== undefined && activityStatus !== publishedActivityStatus) {\n activeContext.ui.setStatus(COMPUTER_USE_STATUS_KEY, activityStatus);\n publishedActivityStatus = activityStatus;\n }\n };\n const refresh = async (): Promise<void> => {\n if (signal.aborted) return;\n let nextGloballyEnabled = false;\n try {\n nextGloballyEnabled = (await dependencies.enabled?.()) === true;\n } catch {\n nextGloballyEnabled = false;\n }\n if (signal.aborted) return;\n if (nextGloballyEnabled !== globallyEnabled) {\n globallyEnabled = nextGloballyEnabled;\n if (!globallyEnabled) {\n if (client !== undefined && state !== undefined && state.phase !== 'inactive' && state.phase !== 'failed') {\n try {\n await client.stop();\n } catch {\n // The global opt-in is still authoritative even when remote cleanup fails.\n }\n }\n enabled = false;\n state = undefined;\n reconcileTools(false);\n }\n publishedMode = '';\n for (const listener of modeListeners) listener();\n }\n if (!globallyEnabled || client === undefined) {\n state = undefined;\n reconcileTools(false);\n publish();\n return;\n }\n try {\n const nextState = await client.state(signal);\n if (signal.aborted) return;\n state = nextState;\n reconcileTools(state.phase === 'active');\n publish();\n } catch {\n state = undefined;\n reconcileTools(false);\n publish();\n }\n };\n mode = defineMinorMode<undefined, MinorModeOwnerActionContext<ExtensionContext>>({\n descriptor: {\n source: PACKAGE_SOURCE,\n id: COMPUTER_USE_MODE_ID,\n label: 'Computer Use',\n description: 'Session-scoped semantic control through DoomPi Desktop.',\n order: 450,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Open the cockpit activation workflow and native confirmation.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Stop this session computer-use run.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n {\n id: 'doctor',\n label: 'Doctor',\n description: 'Report Desktop availability and session state.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(state, enabled),\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n activeContext = execution.context;\n if (actionId === 'activate') {\n if ((await dependencies.enabled?.()) !== true) {\n await refresh();\n throw new Error('Enable computer use in global settings first.');\n }\n if (client === undefined) throw new Error('DoomPi Desktop computer use is unavailable.');\n enabled = true;\n await refresh();\n publish();\n return { message: 'Computer use is ready to configure in Activity.' };\n }\n if (actionId === 'doctor') {\n await refresh();\n return {\n message:\n client === undefined\n ? 'DoomPi Desktop session API is unavailable.'\n : `Computer use is ${state?.phase.replaceAll('_', ' ') ?? 'unavailable'}.`,\n };\n }\n if (actionId === 'deactivate') {\n if (client === undefined) throw new Error('DoomPi Desktop computer use is unavailable.');\n if (state !== undefined && state.phase !== 'inactive' && state.phase !== 'failed')\n await client.stop(execution.signal);\n enabled = false;\n await refresh();\n publish();\n return { message: 'Computer use is off.' };\n }\n throw new Error(`Unknown computer-use action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n commands: [createComputerUseCommand(dependencies.service)],\n tools: [\n {\n name: 'computer_state',\n label: 'Computer State',\n description: 'Observe the authorized application window and return its semantic accessibility state.',\n promptSnippet: 'Observe the authorized application before choosing a semantic action',\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n async execute(_toolCallId, _params, signal) {\n if (!globallyEnabled || client === undefined || state?.phase !== 'active')\n throw new Error('Computer use is not active for this session.');\n const observation = await client.observe(signal);\n return { content: [{ type: 'text', text: JSON.stringify(observation, null, 2) }], details: observation };\n },\n },\n {\n name: 'computer_action',\n label: 'Computer Action',\n description: 'Perform one constrained semantic action in the authorized application window.',\n promptSnippet: 'Perform one action using a current computer_state snapshot and element ref',\n parameters: {\n type: 'object',\n properties: {\n kind: { type: 'string', enum: ['press', 'focus', 'set_value', 'scroll'] },\n snapshotId: { type: 'string' },\n elementRef: { type: 'string' },\n value: { type: 'string' },\n direction: { type: 'string', enum: ['up', 'down', 'left', 'right'] },\n amount: { type: 'string', enum: ['line', 'page'] },\n },\n required: ['kind', 'snapshotId', 'elementRef'],\n additionalProperties: false,\n },\n async execute(_toolCallId, params, signal) {\n if (!globallyEnabled || client === undefined || state?.phase !== 'active')\n throw new Error('Computer use is not active for this session.');\n const result = await client.act(params as unknown as ComputerUseAction, signal);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n },\n {\n name: 'computer_exec',\n label: 'Computer Script',\n description:\n 'Run a trusted, explicitly allowed local TypeScript script against the authorized application session.',\n promptSnippet: 'Run a trusted reusable computer script by its explicitly allowed path and JSON input',\n parameters: {\n type: 'object',\n properties: {\n scriptPath: { type: 'string' },\n input: {},\n },\n required: ['scriptPath', 'input'],\n additionalProperties: false,\n },\n async execute(_toolCallId, params, signal) {\n if (!globallyEnabled || client === undefined || state?.phase !== 'active')\n throw new Error('Computer use is not active for this session.');\n if (dependencies.scriptRunner === undefined) throw new Error('Computer script execution is unavailable.');\n const input = params as { scriptPath: string; input: unknown };\n const result = await dependencies.scriptRunner.execute(input.scriptPath, input.input, signal);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n },\n ],\n services: [\n piMinorModes({\n snapshot: () => (globallyEnabled ? [mode] : []),\n subscribe(listener) {\n modeListeners.add(listener);\n return () => {\n modeListeners.delete(listener);\n };\n },\n }),\n ],\n toolRestrictions: [\n {\n source: PACKAGE_SOURCE,\n restrict: (incoming, available) => restriction(incoming, available),\n subscribe(listener) {\n restrictionListeners.add(listener);\n return () => {\n restrictionListeners.delete(listener);\n };\n },\n },\n ],\n events: {\n before_agent_start: (event) =>\n globallyEnabled && state?.phase === 'active'\n ? { systemPrompt: `${event.systemPrompt}\\n\\n${COMPUTER_USE_GUIDANCE}` }\n : undefined,\n session_start: (_event, context) => {\n if (signal.aborted) return;\n activeContext = context;\n reconcileTools(false);\n void refresh();\n if (timer) clearInterval(timer);\n timer = setInterval(() => void refresh(), 250);\n timer.unref?.();\n },\n },\n onStop() {\n if (timer) clearInterval(timer);\n timer = undefined;\n },\n onDispose() {\n if (timer) clearInterval(timer);\n timer = undefined;\n reconcileTools(false);\n activeContext?.ui.setStatus(COMPUTER_USE_MODE_STATUS_KEY, undefined);\n activeContext?.ui.setStatus(COMPUTER_USE_STATUS_KEY, undefined);\n activeContext = undefined;\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{COMPUTER_USE_GUIDANCE as e}from"../constants/computerUse.mjs";import{COMPUTER_USE_MODE_ID as t,COMPUTER_USE_MODE_STATUS_KEY as n,COMPUTER_USE_STATUS_KEY as r}from"../types/computerUseApi.mjs";import{createComputerUseCommand as i}from"./computerUseCommand.mjs";import{computerUseRestriction as a,modeState as o}from"../models/computerUseMode.mjs";import{defineMinorMode as s,piMinorModes as c}from"@agimon-ai/doompi-minor-mode";const l=`@agimon-ai/doompi-computer-use`;function u(u,d){let f=u.client,p,m=!1,h=a(!1),g=new Set,_=e=>{h=a(e);for(let e of g)e()},v=!1,y,b=new Set,x,S,C=``,w,T,E=()=>{let e=p?.phase??`inactive`,t=`${m}:${e}:${p?.revision??`none`}`;y!==void 0&&t!==C&&(y.publish(),C=t);let i=p===void 0?void 0:m||e!==`inactive`?e:``;S!==void 0&&i!==w&&(S.ui.setStatus(n,i),w=i);let a=m||e!==`inactive`?`computer use: ${e}`:void 0;S!==void 0&&a!==T&&(S.ui.setStatus(r,a),T=a)},D=async()=>{if(d.aborted)return;let e=!1;try{e=await u.enabled?.()===!0}catch{e=!1}if(!d.aborted){if(e!==v){if(v=e,!v){if(f!==void 0&&p!==void 0&&p.phase!==`inactive`&&p.phase!==`failed`)try{await f.stop()}catch{}m=!1,p=void 0,_(!1)}C=``;for(let e of b)e()}if(!v||f===void 0){p=void 0,_(!1),E();return}try{let e=await f.state(d);if(d.aborted)return;p=e,_(p.phase===`active`),E()}catch{p=void 0,_(!1),E()}}};return y=s({descriptor:{source:l,id:t,label:`Computer Use`,description:`Session-scoped semantic control through DoomPi Desktop.`,order:450,actions:[{id:`activate`,label:`Activate`,description:`Open the cockpit activation workflow and native confirmation.`,contexts:[`tui`,`headless`],parameters:[]},{id:`deactivate`,label:`Deactivate`,description:`Stop this session computer-use run.`,contexts:[`tui`,`headless`],parameters:[]},{id:`doctor`,label:`Doctor`,description:`Report Desktop availability and session state.`,contexts:[`tui`,`headless`],parameters:[]}]},state:()=>o(p,m),async handleAction(e,t,n,r){if(S=r.context,t===`activate`){if(await u.enabled?.()!==!0)throw await D(),Error(`Enable computer use in global settings first.`);if(f===void 0)throw Error(`DoomPi Desktop computer use is unavailable.`);return m=!0,await D(),E(),{message:`Computer use is ready to configure in Activity.`}}if(t===`doctor`)return await D(),{message:f===void 0?`DoomPi Desktop session API is unavailable.`:`Computer use is ${p?.phase.replaceAll(`_`,` `)??`unavailable`}.`};if(t===`deactivate`){if(f===void 0)throw Error(`DoomPi Desktop computer use is unavailable.`);return p!==void 0&&p.phase!==`inactive`&&p.phase!==`failed`&&await f.stop(r.signal),m=!1,await D(),E(),{message:`Computer use is off.`}}throw Error(`Unknown computer-use action: ${t}`)}}).createOwner(void 0),{commands:[i(u.service)],tools:[{name:`computer_state`,label:`Computer State`,description:`Observe the authorized application window and return its semantic accessibility state.`,promptSnippet:`Observe the authorized application before choosing a semantic action`,parameters:{type:`object`,properties:{},additionalProperties:!1},async execute(e,t,n){if(!v||f===void 0||p?.phase!==`active`)throw Error(`Computer use is not active for this session.`);let r=await f.observe(n);return{content:[{type:`text`,text:JSON.stringify(r,null,2)}],details:r}}},{name:`computer_action`,label:`Computer Action`,description:`Perform one constrained semantic action in the authorized application window.`,promptSnippet:`Perform one action using a current computer_state snapshot and element ref`,parameters:{type:`object`,properties:{kind:{type:`string`,enum:[`press`,`focus`,`set_value`,`scroll`]},snapshotId:{type:`string`},elementRef:{type:`string`},value:{type:`string`},direction:{type:`string`,enum:[`up`,`down`,`left`,`right`]},amount:{type:`string`,enum:[`line`,`page`]}},required:[`kind`,`snapshotId`,`elementRef`],additionalProperties:!1},async execute(e,t,n){if(!v||f===void 0||p?.phase!==`active`)throw Error(`Computer use is not active for this session.`);let r=await f.act(t,n);return{content:[{type:`text`,text:JSON.stringify(r,null,2)}],details:r}}},{name:`computer_exec`,label:`Computer Script`,description:`Run a trusted, explicitly allowed local TypeScript script against the authorized application session.`,promptSnippet:`Run a trusted reusable computer script by its explicitly allowed path and JSON input`,parameters:{type:`object`,properties:{scriptPath:{type:`string`},input:{}},required:[`scriptPath`,`input`],additionalProperties:!1},async execute(e,t,n){if(!v||f===void 0||p?.phase!==`active`)throw Error(`Computer use is not active for this session.`);if(u.scriptRunner===void 0)throw Error(`Computer script execution is unavailable.`);let r=t,i=await u.scriptRunner.execute(r.scriptPath,r.input,n);return{content:[{type:`text`,text:JSON.stringify(i,null,2)}],details:i}}}],services:[c({snapshot:()=>v?[y]:[],subscribe(e){return b.add(e),()=>{b.delete(e)}}})],toolRestrictions:[{source:l,restrict:(e,t)=>h(e,t),subscribe(e){return g.add(e),()=>{g.delete(e)}}}],events:{before_agent_start:t=>v&&p?.phase===`active`?{systemPrompt:`${t.systemPrompt}\n\n${e}`}:void 0,session_start:(e,t)=>{d.aborted||(S=t,_(!1),D(),x&&clearInterval(x),x=setInterval(()=>void D(),250),x.unref?.())}},onStop(){x&&clearInterval(x),x=void 0},onDispose(){x&&clearInterval(x),x=void 0,_(!1),S?.ui.setStatus(n,void 0),S?.ui.setStatus(r,void 0),S=void 0}}}export{t as COMPUTER_USE_MODE_ID,u as createComputerUseRuntime};
2
+ //# sourceMappingURL=computerUseRuntime.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseRuntime.mjs","names":[],"sources":["../../src/controllers/computerUseRuntime.ts"],"sourcesContent":["import { type PiPluginContributions } from '@agimon-ai/doompi-core/pi-extension';\nimport { type DoomToolRestriction } from '@agimon-ai/doompi-core/tool-surface';\nimport { piMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeOwnerActionContext } from '@agimon-ai/doompi-minor-mode';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { COMPUTER_USE_GUIDANCE } from '../constants/computerUse';\nimport type { ComputerUseAction } from '../types/computerUse';\nimport {\n COMPUTER_USE_MODE_ID,\n COMPUTER_USE_MODE_STATUS_KEY,\n COMPUTER_USE_STATUS_KEY,\n type ComputerUseSessionView,\n} from '../types/computerUseApi';\nimport type { ComputerUseExtensionDependencies } from '../types/extension';\nimport { createComputerUseCommand } from './computerUseCommand';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-computer-use';\nexport { COMPUTER_USE_MODE_ID };\nimport { modeState, computerUseRestriction } from '../models/computerUseMode';\n\nexport function createComputerUseRuntime(\n dependencies: ComputerUseExtensionDependencies,\n signal: AbortSignal,\n): PiPluginContributions<ComputerUseExtensionDependencies> & {\n tools: readonly Parameters<ExtensionAPI['registerTool']>[0][];\n} {\n const client = dependencies.client;\n let state: ComputerUseSessionView | undefined;\n let enabled = false;\n let restriction: DoomToolRestriction = computerUseRestriction(false);\n const restrictionListeners = new Set<() => void>();\n const reconcileTools = (active: boolean): void => {\n restriction = computerUseRestriction(active);\n for (const listener of restrictionListeners) listener();\n };\n let globallyEnabled = false;\n let mode: MinorModeOwner<MinorModeOwnerActionContext<ExtensionContext>>;\n const modeListeners = new Set<() => void>();\n let timer: ReturnType<typeof setInterval> | undefined;\n let activeContext: ExtensionContext | undefined;\n let publishedMode = '';\n let publishedModeStatus: string | undefined;\n let publishedActivityStatus: string | undefined;\n const publish = (): void => {\n const phase = state?.phase ?? 'inactive';\n const projection = `${enabled}:${phase}:${state?.revision ?? 'none'}`;\n if (mode !== undefined && projection !== publishedMode) {\n mode.publish();\n publishedMode = projection;\n }\n const modeStatus = state === undefined ? undefined : enabled || phase !== 'inactive' ? phase : '';\n if (activeContext !== undefined && modeStatus !== publishedModeStatus) {\n activeContext.ui.setStatus(COMPUTER_USE_MODE_STATUS_KEY, modeStatus);\n publishedModeStatus = modeStatus;\n }\n const activityStatus = enabled || phase !== 'inactive' ? `computer use: ${phase}` : undefined;\n if (activeContext !== undefined && activityStatus !== publishedActivityStatus) {\n activeContext.ui.setStatus(COMPUTER_USE_STATUS_KEY, activityStatus);\n publishedActivityStatus = activityStatus;\n }\n };\n const refresh = async (): Promise<void> => {\n if (signal.aborted) return;\n let nextGloballyEnabled = false;\n try {\n nextGloballyEnabled = (await dependencies.enabled?.()) === true;\n } catch {\n nextGloballyEnabled = false;\n }\n if (signal.aborted) return;\n if (nextGloballyEnabled !== globallyEnabled) {\n globallyEnabled = nextGloballyEnabled;\n if (!globallyEnabled) {\n if (client !== undefined && state !== undefined && state.phase !== 'inactive' && state.phase !== 'failed') {\n try {\n await client.stop();\n } catch {\n // The global opt-in is still authoritative even when remote cleanup fails.\n }\n }\n enabled = false;\n state = undefined;\n reconcileTools(false);\n }\n publishedMode = '';\n for (const listener of modeListeners) listener();\n }\n if (!globallyEnabled || client === undefined) {\n state = undefined;\n reconcileTools(false);\n publish();\n return;\n }\n try {\n const nextState = await client.state(signal);\n if (signal.aborted) return;\n state = nextState;\n reconcileTools(state.phase === 'active');\n publish();\n } catch {\n state = undefined;\n reconcileTools(false);\n publish();\n }\n };\n mode = defineMinorMode<undefined, MinorModeOwnerActionContext<ExtensionContext>>({\n descriptor: {\n source: PACKAGE_SOURCE,\n id: COMPUTER_USE_MODE_ID,\n label: 'Computer Use',\n description: 'Session-scoped semantic control through DoomPi Desktop.',\n order: 450,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Open the cockpit activation workflow and native confirmation.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Stop this session computer-use run.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n {\n id: 'doctor',\n label: 'Doctor',\n description: 'Report Desktop availability and session state.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(state, enabled),\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n activeContext = execution.context;\n if (actionId === 'activate') {\n if ((await dependencies.enabled?.()) !== true) {\n await refresh();\n throw new Error('Enable computer use in global settings first.');\n }\n if (client === undefined) throw new Error('DoomPi Desktop computer use is unavailable.');\n enabled = true;\n await refresh();\n publish();\n return { message: 'Computer use is ready to configure in Activity.' };\n }\n if (actionId === 'doctor') {\n await refresh();\n return {\n message:\n client === undefined\n ? 'DoomPi Desktop session API is unavailable.'\n : `Computer use is ${state?.phase.replaceAll('_', ' ') ?? 'unavailable'}.`,\n };\n }\n if (actionId === 'deactivate') {\n if (client === undefined) throw new Error('DoomPi Desktop computer use is unavailable.');\n if (state !== undefined && state.phase !== 'inactive' && state.phase !== 'failed')\n await client.stop(execution.signal);\n enabled = false;\n await refresh();\n publish();\n return { message: 'Computer use is off.' };\n }\n throw new Error(`Unknown computer-use action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n commands: [createComputerUseCommand(dependencies.service)],\n tools: [\n {\n name: 'computer_state',\n label: 'Computer State',\n description: 'Observe the authorized application window and return its semantic accessibility state.',\n promptSnippet: 'Observe the authorized application before choosing a semantic action',\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n async execute(_toolCallId, _params, signal) {\n if (!globallyEnabled || client === undefined || state?.phase !== 'active')\n throw new Error('Computer use is not active for this session.');\n const observation = await client.observe(signal);\n return { content: [{ type: 'text', text: JSON.stringify(observation, null, 2) }], details: observation };\n },\n },\n {\n name: 'computer_action',\n label: 'Computer Action',\n description: 'Perform one constrained semantic action in the authorized application window.',\n promptSnippet: 'Perform one action using a current computer_state snapshot and element ref',\n parameters: {\n type: 'object',\n properties: {\n kind: { type: 'string', enum: ['press', 'focus', 'set_value', 'scroll'] },\n snapshotId: { type: 'string' },\n elementRef: { type: 'string' },\n value: { type: 'string' },\n direction: { type: 'string', enum: ['up', 'down', 'left', 'right'] },\n amount: { type: 'string', enum: ['line', 'page'] },\n },\n required: ['kind', 'snapshotId', 'elementRef'],\n additionalProperties: false,\n },\n async execute(_toolCallId, params, signal) {\n if (!globallyEnabled || client === undefined || state?.phase !== 'active')\n throw new Error('Computer use is not active for this session.');\n const result = await client.act(params as unknown as ComputerUseAction, signal);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n },\n {\n name: 'computer_exec',\n label: 'Computer Script',\n description:\n 'Run a trusted, explicitly allowed local TypeScript script against the authorized application session.',\n promptSnippet: 'Run a trusted reusable computer script by its explicitly allowed path and JSON input',\n parameters: {\n type: 'object',\n properties: {\n scriptPath: { type: 'string' },\n input: {},\n },\n required: ['scriptPath', 'input'],\n additionalProperties: false,\n },\n async execute(_toolCallId, params, signal) {\n if (!globallyEnabled || client === undefined || state?.phase !== 'active')\n throw new Error('Computer use is not active for this session.');\n if (dependencies.scriptRunner === undefined) throw new Error('Computer script execution is unavailable.');\n const input = params as { scriptPath: string; input: unknown };\n const result = await dependencies.scriptRunner.execute(input.scriptPath, input.input, signal);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], details: result };\n },\n },\n ],\n services: [\n piMinorModes({\n snapshot: () => (globallyEnabled ? [mode] : []),\n subscribe(listener) {\n modeListeners.add(listener);\n return () => {\n modeListeners.delete(listener);\n };\n },\n }),\n ],\n toolRestrictions: [\n {\n source: PACKAGE_SOURCE,\n restrict: (incoming, available) => restriction(incoming, available),\n subscribe(listener) {\n restrictionListeners.add(listener);\n return () => {\n restrictionListeners.delete(listener);\n };\n },\n },\n ],\n events: {\n before_agent_start: (event) =>\n globallyEnabled && state?.phase === 'active'\n ? { systemPrompt: `${event.systemPrompt}\\n\\n${COMPUTER_USE_GUIDANCE}` }\n : undefined,\n session_start: (_event, context) => {\n if (signal.aborted) return;\n activeContext = context;\n reconcileTools(false);\n void refresh();\n if (timer) clearInterval(timer);\n timer = setInterval(() => void refresh(), 250);\n timer.unref?.();\n },\n },\n onStop() {\n if (timer) clearInterval(timer);\n timer = undefined;\n },\n onDispose() {\n if (timer) clearInterval(timer);\n timer = undefined;\n reconcileTools(false);\n activeContext?.ui.setStatus(COMPUTER_USE_MODE_STATUS_KEY, undefined);\n activeContext?.ui.setStatus(COMPUTER_USE_STATUS_KEY, undefined);\n activeContext = undefined;\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../constants/computerUse.cjs"),n=require("../services/sessionApiClient/index.cjs"),r=require("../services/computerScriptRunner/index.cjs"),i=require("../services/extensionService/index.cjs"),a=require("../types/computerUseApi.cjs"),o=require("../models/computerUseMode.cjs");let s=require("node:path");s=e.__toESM(s,1);let c=require("@agimon-ai/doompi-minor-mode");const l=`@agimon-ai/doompi-computer-use`;function u(e,t=!1){return{content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e,null,2)}],details:e,...t?{isError:!0}:{}}}function d(e){return{content:[{type:`text`,text:JSON.stringify({...e,screenshot:void 0},null,2)},{type:`image`,data:e.screenshot.data,mimeType:e.screenshot.mimeType}],details:e}}function f(e){let f=n.createComputerUseSessionClient(),p=(e.context.environment.DOOMPI_COMPUTER_USE_SCRIPT_PATHS??``).split(s.default.delimiter).filter(e=>e.length>0),m={client:f,scriptRunner:f===void 0?void 0:new r.ComputerScriptRunner({client:f,allowedScriptPaths:p}),service:new i.DefaultComputerUseExtensionService(f)},h,g,_,v=()=>(e.context.selection.state?.[`minor-mode`]??[]).includes(a.COMPUTER_USE_MODE_ID),y=()=>_?.publish(),b=t=>{h=t,e.context.client.setStatus(l,t===void 0||t.phase===`inactive`?void 0:`computer use: ${t.phase}`),y()},x=async t=>{let n=(e.context.selection.state?.[`minor-mode`]??[]).filter(e=>e!==a.COMPUTER_USE_MODE_ID);await e.changeSelection({axis:`state`,key:`minor-mode`,values:t?[...n,a.COMPUTER_USE_MODE_ID]:n}),y()},S=async e=>{if(!f){b(void 0);return}try{b(await f.state(e))}catch{b(void 0)}},C=()=>{if(!f||h?.phase!==`active`)throw Error(`Computer use is not active for this session.`);return f};return _=(0,c.defineMinorMode)({descriptor:{source:l,id:a.COMPUTER_USE_MODE_ID,label:`Computer Use`,description:`Session-scoped semantic control through DoomPi Desktop.`,order:450,actions:[{id:`activate`,label:`Activate`,description:`Enable computer use for this session.`,contexts:[`headless`],parameters:[]},{id:`deactivate`,label:`Deactivate`,description:`Stop this session computer-use run.`,contexts:[`headless`],parameters:[]},{id:`doctor`,label:`Doctor`,description:`Report Desktop availability and session state.`,contexts:[`headless`],parameters:[]}]},state:()=>o.modeState(h,v()),async handleAction(e,t,n,r){if(r.signal.throwIfAborted(),t===`activate`){if(!f)throw Error(`DoomPi Desktop computer use is unavailable.`);return await x(!0),await S(r.signal),{message:`Computer use activated.`}}if(t===`doctor`)return await S(r.signal),{message:f?`Computer use is ${h?.phase??`unavailable`}.`:`DoomPi Desktop session API is unavailable.`};if(t===`deactivate`)return f&&h?.phase!==void 0&&h.phase!==`inactive`&&h.phase!==`failed`&&await f.stop(r.signal),await x(!1),await S(r.signal),{message:`Computer use deactivated.`};throw Error(`Unknown computer-use action: ${t}`)}}).createOwner(void 0),{services:[(0,c.serverMinorModes)([_])],toolRestrictions:[{when:{state:{"minor-mode":a.COMPUTER_USE_MODE_ID}},allowedTools:[...t.COMPUTER_USE_TOOL_NAMES]}],activities:[{when:{state:{"minor-mode":a.COMPUTER_USE_MODE_ID},attribution:{kind:`minor`,mode:a.COMPUTER_USE_MODE_ID}},name:l,async start(){await S();let e=f?.subscribeStatus?.(b);return g=()=>{e?.(),b(void 0)},()=>{g?.(),g=void 0}}}],tools:[{when:{state:{"minor-mode":a.COMPUTER_USE_MODE_ID},attribution:{kind:`minor`,mode:a.COMPUTER_USE_MODE_ID}},name:`computer_state`,label:`Computer State`,description:`Observe the authorized application window and return semantic accessibility state.`,parameters:{type:`object`,properties:{},additionalProperties:!1},executionMode:`serial`,async execute(e,t,n){try{return d(await C().observe(n))}catch(e){return u(e instanceof Error?e.message:String(e),!0)}}},{when:{state:{"minor-mode":a.COMPUTER_USE_MODE_ID},attribution:{kind:`minor`,mode:a.COMPUTER_USE_MODE_ID}},name:`computer_action`,label:`Computer Action`,description:`Perform one constrained semantic action in the authorized application window.`,parameters:{type:`object`,properties:{kind:{type:`string`,enum:[`press`,`focus`,`set_value`,`scroll`]},snapshotId:{type:`string`,minLength:1},elementRef:{type:`string`,minLength:1},value:{type:`string`},direction:{type:`string`,enum:[`up`,`down`,`left`,`right`]},amount:{type:`string`,enum:[`line`,`page`]}},required:[`kind`,`snapshotId`,`elementRef`],additionalProperties:!1},executionMode:`serial`,async execute(e,t,n){try{let e=await C().act(t,n);return await S(n),u(e)}catch(e){return u(e instanceof Error?e.message:String(e),!0)}}},{when:{state:{"minor-mode":a.COMPUTER_USE_MODE_ID},attribution:{kind:`minor`,mode:a.COMPUTER_USE_MODE_ID}},name:`computer_exec`,label:`Computer Script`,description:`Run a trusted, explicitly allowed local TypeScript script against the authorized application session.`,parameters:{type:`object`,properties:{scriptPath:{type:`string`,minLength:1},input:{}},required:[`scriptPath`,`input`],additionalProperties:!1},executionMode:`serial`,async execute(e,t,n){try{if(!m.scriptRunner)throw Error(`Computer script execution is unavailable.`);let e=t;return u(await m.scriptRunner.execute(e.scriptPath,e.input,n))}catch(e){return u(e instanceof Error?e.message:String(e),!0)}}}],commands:[{name:t.COMMAND_NAME,description:t.COMMAND_DESCRIPTION,async execute(t,n){let r=await m.service.execute();await n.client.notify({body:r.message,level:r.level}),t.trim()===`deactivate`&&f&&h?.phase!==`inactive`&&h?.phase!==`failed`&&(await f.stop(),await e.changeSelection({axis:`state`,key:`minor-mode`,values:(n.selection.state?.[`minor-mode`]??[]).filter(e=>e!==a.COMPUTER_USE_MODE_ID)}),await S())}}],hooks:[{when:{state:{"minor-mode":a.COMPUTER_USE_MODE_ID},attribution:{kind:`minor`,mode:a.COMPUTER_USE_MODE_ID}},event:`before_agent_start`,handle(e){if(h?.phase===`active`)return{systemPrompt:`${typeof e.systemPrompt==`string`?e.systemPrompt:``}\n\n[COMPUTER USE ACTIVE]
2
+ Use computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Never infer coordinates or bypass secure elements.`.trim()}}},{when:{state:{"minor-mode":a.COMPUTER_USE_MODE_ID},attribution:{kind:`minor`,mode:a.COMPUTER_USE_MODE_ID}},event:`session_shutdown`,handle:async()=>{g?.(),f&&h?.phase!==`inactive`&&h?.phase!==`failed`&&await f.stop()}}],onDispose(){g?.(),g=void 0,e.context.client.setStatus(l,void 0)}}}exports.createComputerUseServer=f;
3
+ //# sourceMappingURL=computerUseServer.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseServer.cjs","names":["createComputerUseSessionClient","path","ComputerScriptRunner","DefaultComputerUseExtensionService","COMPUTER_USE_MODE_ID","defineMinorMode","modeState","serverMinorModes","COMPUTER_USE_TOOL_NAMES","COMMAND_NAME","COMMAND_DESCRIPTION"],"sources":["../../src/controllers/computerUseServer.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { type DoomHeadlessToolResult } from '@agimon-ai/doompi-core/headless';\nimport { serverMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport { defineMinorMode, type MinorModeOwner } from '@agimon-ai/doompi-minor-mode';\n\nimport { COMMAND_NAME, COMMAND_DESCRIPTION } from '../constants/computerUse';\nimport { COMPUTER_USE_TOOL_NAMES } from '../constants/computerUse';\nimport { modeState } from '../models/computerUseMode';\nimport { ComputerScriptRunner } from '../services/computerScriptRunner';\nimport { DefaultComputerUseExtensionService } from '../services/extensionService';\nimport { createComputerUseSessionClient } from '../services/sessionApiClient';\nimport type { ComputerUseAction, ComputerUseObservation } from '../types/computerUse';\nimport { COMPUTER_USE_MODE_ID } from '../types/computerUseApi';\nimport type { ComputerUseSessionView } from '../types/computerUseApi';\n\nconst SOURCE = '@agimon-ai/doompi-computer-use';\n\nconst SCRIPT_PATHS_ENV = 'DOOMPI_COMPUTER_USE_SCRIPT_PATHS';\nconst GUIDANCE =\n '[COMPUTER USE ACTIVE]\\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Never infer coordinates or bypass secure elements.';\n\nfunction output(value: unknown, isError = false): DoomHeadlessToolResult {\n return {\n content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n details: value,\n ...(isError ? { isError: true } : {}),\n };\n}\n\nfunction observationOutput(value: ComputerUseObservation): DoomHeadlessToolResult {\n return {\n content: [\n { type: 'text', text: JSON.stringify({ ...value, screenshot: undefined }, null, 2) },\n { type: 'image', data: value.screenshot.data, mimeType: value.screenshot.mimeType },\n ],\n details: value,\n };\n}\n\nimport {\n type DoomHeadlessHostService,\n type DoomHeadlessTool,\n type DoomHeadlessCommand,\n} from '@agimon-ai/doompi-core/headless';\nimport { type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/server-facet';\nexport function createComputerUseServer(host: DoomHeadlessHostService): Omit<\n DoomServerSessionPlugin,\n 'tools' | 'commands'\n> & {\n tools: readonly DoomHeadlessTool[];\n commands: readonly DoomHeadlessCommand[];\n} {\n const client = createComputerUseSessionClient();\n const allowedScriptPaths = (host.context.environment[SCRIPT_PATHS_ENV] ?? '')\n .split(path.delimiter)\n .filter((entry) => entry.length > 0);\n const scriptRunner = client === undefined ? undefined : new ComputerScriptRunner({ client, allowedScriptPaths });\n const service = new DefaultComputerUseExtensionService(client);\n const dependencies = { client, scriptRunner, service };\n let state: ComputerUseSessionView | undefined;\n let stopActivity: (() => void) | undefined;\n let modeOwner: MinorModeOwner | undefined;\n const modeSelected = (): boolean =>\n (host.context.selection.state?.['minor-mode'] ?? []).includes(COMPUTER_USE_MODE_ID);\n const publishMode = (): void => modeOwner?.publish();\n const applyState = (next: ComputerUseSessionView | undefined): void => {\n state = next;\n host.context.client.setStatus(\n SOURCE,\n next === undefined || next.phase === 'inactive' ? undefined : `computer use: ${next.phase}`,\n );\n publishMode();\n };\n const selectMode = async (enabled: boolean): Promise<void> => {\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== COMPUTER_USE_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, COMPUTER_USE_MODE_ID] : modes,\n });\n publishMode();\n };\n const refresh = async (signal?: AbortSignal): Promise<void> => {\n if (!client) {\n applyState(undefined);\n return;\n }\n try {\n applyState(await client.state(signal));\n } catch {\n applyState(undefined);\n }\n };\n const requireActive = (): NonNullable<typeof client> => {\n if (!client || state?.phase !== 'active') throw new Error('Computer use is not active for this session.');\n return client;\n };\n modeOwner = defineMinorMode<undefined>({\n descriptor: {\n source: SOURCE,\n id: COMPUTER_USE_MODE_ID,\n label: 'Computer Use',\n description: 'Session-scoped semantic control through DoomPi Desktop.',\n order: 450,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Enable computer use for this session.',\n contexts: ['headless'],\n parameters: [],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Stop this session computer-use run.',\n contexts: ['headless'],\n parameters: [],\n },\n {\n id: 'doctor',\n label: 'Doctor',\n description: 'Report Desktop availability and session state.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(state, modeSelected()),\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n execution.signal.throwIfAborted();\n if (actionId === 'activate') {\n if (!client) throw new Error('DoomPi Desktop computer use is unavailable.');\n await selectMode(true);\n await refresh(execution.signal);\n return { message: 'Computer use activated.' };\n }\n if (actionId === 'doctor') {\n await refresh(execution.signal);\n return {\n message: client\n ? `Computer use is ${state?.phase ?? 'unavailable'}.`\n : 'DoomPi Desktop session API is unavailable.',\n };\n }\n if (actionId === 'deactivate') {\n if (client && state?.phase !== undefined && state.phase !== 'inactive' && state.phase !== 'failed')\n await client.stop(execution.signal);\n await selectMode(false);\n await refresh(execution.signal);\n return { message: 'Computer use deactivated.' };\n }\n throw new Error(`Unknown computer-use action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [serverMinorModes([modeOwner])],\n toolRestrictions: [\n {\n when: { state: { 'minor-mode': COMPUTER_USE_MODE_ID } },\n allowedTools: [...COMPUTER_USE_TOOL_NAMES],\n },\n ],\n activities: [\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: SOURCE,\n async start() {\n await refresh();\n const unsubscribe = client?.subscribeStatus?.(applyState);\n stopActivity = () => {\n unsubscribe?.();\n applyState(undefined);\n };\n return () => {\n stopActivity?.();\n stopActivity = undefined;\n };\n },\n },\n ],\n tools: [\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: 'computer_state',\n label: 'Computer State',\n description: 'Observe the authorized application window and return semantic accessibility state.',\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n executionMode: 'serial',\n async execute(_toolCallId, _parameters, signal) {\n try {\n const session = requireActive();\n const observation = await session.observe(signal);\n return observationOutput(observation);\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: 'computer_action',\n label: 'Computer Action',\n description: 'Perform one constrained semantic action in the authorized application window.',\n parameters: {\n type: 'object',\n properties: {\n kind: { type: 'string', enum: ['press', 'focus', 'set_value', 'scroll'] },\n snapshotId: { type: 'string', minLength: 1 },\n elementRef: { type: 'string', minLength: 1 },\n value: { type: 'string' },\n direction: { type: 'string', enum: ['up', 'down', 'left', 'right'] },\n amount: { type: 'string', enum: ['line', 'page'] },\n },\n required: ['kind', 'snapshotId', 'elementRef'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal) {\n try {\n const result = await requireActive().act(parameters as unknown as ComputerUseAction, signal);\n await refresh(signal);\n return output(result);\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: 'computer_exec',\n label: 'Computer Script',\n description:\n 'Run a trusted, explicitly allowed local TypeScript script against the authorized application session.',\n parameters: {\n type: 'object',\n properties: { scriptPath: { type: 'string', minLength: 1 }, input: {} },\n required: ['scriptPath', 'input'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal) {\n try {\n if (!dependencies.scriptRunner) throw new Error('Computer script execution is unavailable.');\n const input = parameters as { scriptPath: string; input: unknown };\n return output(await dependencies.scriptRunner.execute(input.scriptPath, input.input, signal));\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n ],\n commands: [\n {\n name: COMMAND_NAME,\n description: COMMAND_DESCRIPTION,\n async execute(args, execution) {\n const result = await dependencies.service.execute();\n await execution.client.notify({ body: result.message, level: result.level });\n if (args.trim() === 'deactivate' && client && state?.phase !== 'inactive' && state?.phase !== 'failed') {\n await client.stop();\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: (execution.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== COMPUTER_USE_MODE_ID),\n });\n await refresh();\n }\n },\n },\n ],\n hooks: [\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n event: 'before_agent_start',\n handle(event) {\n if (state?.phase !== 'active') return undefined;\n const prompt = typeof event.systemPrompt === 'string' ? event.systemPrompt : '';\n return { systemPrompt: `${prompt}\\n\\n${GUIDANCE}`.trim() };\n },\n },\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n event: 'session_shutdown',\n handle: async () => {\n stopActivity?.();\n if (client && state?.phase !== 'inactive' && state?.phase !== 'failed') await client.stop();\n },\n },\n ],\n onDispose() {\n stopActivity?.();\n stopActivity = undefined;\n host.context.client.setStatus(SOURCE, undefined);\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import{COMMAND_DESCRIPTION as e,COMMAND_NAME as t,COMPUTER_USE_TOOL_NAMES as n}from"../constants/computerUse.mjs";import{createComputerUseSessionClient as r}from"../services/sessionApiClient/index.mjs";import{ComputerScriptRunner as i}from"../services/computerScriptRunner/index.mjs";import{DefaultComputerUseExtensionService as a}from"../services/extensionService/index.mjs";import{COMPUTER_USE_MODE_ID as o}from"../types/computerUseApi.mjs";import{modeState as s}from"../models/computerUseMode.mjs";import c from"node:path";import{defineMinorMode as l,serverMinorModes as u}from"@agimon-ai/doompi-minor-mode";const d=`@agimon-ai/doompi-computer-use`;function f(e,t=!1){return{content:[{type:`text`,text:typeof e==`string`?e:JSON.stringify(e,null,2)}],details:e,...t?{isError:!0}:{}}}function p(e){return{content:[{type:`text`,text:JSON.stringify({...e,screenshot:void 0},null,2)},{type:`image`,data:e.screenshot.data,mimeType:e.screenshot.mimeType}],details:e}}function m(m){let h=r(),g=(m.context.environment.DOOMPI_COMPUTER_USE_SCRIPT_PATHS??``).split(c.delimiter).filter(e=>e.length>0),_={client:h,scriptRunner:h===void 0?void 0:new i({client:h,allowedScriptPaths:g}),service:new a(h)},v,y,b,x=()=>(m.context.selection.state?.[`minor-mode`]??[]).includes(o),S=()=>b?.publish(),C=e=>{v=e,m.context.client.setStatus(d,e===void 0||e.phase===`inactive`?void 0:`computer use: ${e.phase}`),S()},w=async e=>{let t=(m.context.selection.state?.[`minor-mode`]??[]).filter(e=>e!==o);await m.changeSelection({axis:`state`,key:`minor-mode`,values:e?[...t,o]:t}),S()},T=async e=>{if(!h){C(void 0);return}try{C(await h.state(e))}catch{C(void 0)}},E=()=>{if(!h||v?.phase!==`active`)throw Error(`Computer use is not active for this session.`);return h};return b=l({descriptor:{source:d,id:o,label:`Computer Use`,description:`Session-scoped semantic control through DoomPi Desktop.`,order:450,actions:[{id:`activate`,label:`Activate`,description:`Enable computer use for this session.`,contexts:[`headless`],parameters:[]},{id:`deactivate`,label:`Deactivate`,description:`Stop this session computer-use run.`,contexts:[`headless`],parameters:[]},{id:`doctor`,label:`Doctor`,description:`Report Desktop availability and session state.`,contexts:[`headless`],parameters:[]}]},state:()=>s(v,x()),async handleAction(e,t,n,r){if(r.signal.throwIfAborted(),t===`activate`){if(!h)throw Error(`DoomPi Desktop computer use is unavailable.`);return await w(!0),await T(r.signal),{message:`Computer use activated.`}}if(t===`doctor`)return await T(r.signal),{message:h?`Computer use is ${v?.phase??`unavailable`}.`:`DoomPi Desktop session API is unavailable.`};if(t===`deactivate`)return h&&v?.phase!==void 0&&v.phase!==`inactive`&&v.phase!==`failed`&&await h.stop(r.signal),await w(!1),await T(r.signal),{message:`Computer use deactivated.`};throw Error(`Unknown computer-use action: ${t}`)}}).createOwner(void 0),{services:[u([b])],toolRestrictions:[{when:{state:{"minor-mode":o}},allowedTools:[...n]}],activities:[{when:{state:{"minor-mode":o},attribution:{kind:`minor`,mode:o}},name:d,async start(){await T();let e=h?.subscribeStatus?.(C);return y=()=>{e?.(),C(void 0)},()=>{y?.(),y=void 0}}}],tools:[{when:{state:{"minor-mode":o},attribution:{kind:`minor`,mode:o}},name:`computer_state`,label:`Computer State`,description:`Observe the authorized application window and return semantic accessibility state.`,parameters:{type:`object`,properties:{},additionalProperties:!1},executionMode:`serial`,async execute(e,t,n){try{return p(await E().observe(n))}catch(e){return f(e instanceof Error?e.message:String(e),!0)}}},{when:{state:{"minor-mode":o},attribution:{kind:`minor`,mode:o}},name:`computer_action`,label:`Computer Action`,description:`Perform one constrained semantic action in the authorized application window.`,parameters:{type:`object`,properties:{kind:{type:`string`,enum:[`press`,`focus`,`set_value`,`scroll`]},snapshotId:{type:`string`,minLength:1},elementRef:{type:`string`,minLength:1},value:{type:`string`},direction:{type:`string`,enum:[`up`,`down`,`left`,`right`]},amount:{type:`string`,enum:[`line`,`page`]}},required:[`kind`,`snapshotId`,`elementRef`],additionalProperties:!1},executionMode:`serial`,async execute(e,t,n){try{let e=await E().act(t,n);return await T(n),f(e)}catch(e){return f(e instanceof Error?e.message:String(e),!0)}}},{when:{state:{"minor-mode":o},attribution:{kind:`minor`,mode:o}},name:`computer_exec`,label:`Computer Script`,description:`Run a trusted, explicitly allowed local TypeScript script against the authorized application session.`,parameters:{type:`object`,properties:{scriptPath:{type:`string`,minLength:1},input:{}},required:[`scriptPath`,`input`],additionalProperties:!1},executionMode:`serial`,async execute(e,t,n){try{if(!_.scriptRunner)throw Error(`Computer script execution is unavailable.`);let e=t;return f(await _.scriptRunner.execute(e.scriptPath,e.input,n))}catch(e){return f(e instanceof Error?e.message:String(e),!0)}}}],commands:[{name:t,description:e,async execute(e,t){let n=await _.service.execute();await t.client.notify({body:n.message,level:n.level}),e.trim()===`deactivate`&&h&&v?.phase!==`inactive`&&v?.phase!==`failed`&&(await h.stop(),await m.changeSelection({axis:`state`,key:`minor-mode`,values:(t.selection.state?.[`minor-mode`]??[]).filter(e=>e!==o)}),await T())}}],hooks:[{when:{state:{"minor-mode":o},attribution:{kind:`minor`,mode:o}},event:`before_agent_start`,handle(e){if(v?.phase===`active`)return{systemPrompt:`${typeof e.systemPrompt==`string`?e.systemPrompt:``}\n\n[COMPUTER USE ACTIVE]
2
+ Use computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Never infer coordinates or bypass secure elements.`.trim()}}},{when:{state:{"minor-mode":o},attribution:{kind:`minor`,mode:o}},event:`session_shutdown`,handle:async()=>{y?.(),h&&v?.phase!==`inactive`&&v?.phase!==`failed`&&await h.stop()}}],onDispose(){y?.(),y=void 0,m.context.client.setStatus(d,void 0)}}}export{m as createComputerUseServer};
3
+ //# sourceMappingURL=computerUseServer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computerUseServer.mjs","names":[],"sources":["../../src/controllers/computerUseServer.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { type DoomHeadlessToolResult } from '@agimon-ai/doompi-core/headless';\nimport { serverMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport { defineMinorMode, type MinorModeOwner } from '@agimon-ai/doompi-minor-mode';\n\nimport { COMMAND_NAME, COMMAND_DESCRIPTION } from '../constants/computerUse';\nimport { COMPUTER_USE_TOOL_NAMES } from '../constants/computerUse';\nimport { modeState } from '../models/computerUseMode';\nimport { ComputerScriptRunner } from '../services/computerScriptRunner';\nimport { DefaultComputerUseExtensionService } from '../services/extensionService';\nimport { createComputerUseSessionClient } from '../services/sessionApiClient';\nimport type { ComputerUseAction, ComputerUseObservation } from '../types/computerUse';\nimport { COMPUTER_USE_MODE_ID } from '../types/computerUseApi';\nimport type { ComputerUseSessionView } from '../types/computerUseApi';\n\nconst SOURCE = '@agimon-ai/doompi-computer-use';\n\nconst SCRIPT_PATHS_ENV = 'DOOMPI_COMPUTER_USE_SCRIPT_PATHS';\nconst GUIDANCE =\n '[COMPUTER USE ACTIVE]\\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Never infer coordinates or bypass secure elements.';\n\nfunction output(value: unknown, isError = false): DoomHeadlessToolResult {\n return {\n content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n details: value,\n ...(isError ? { isError: true } : {}),\n };\n}\n\nfunction observationOutput(value: ComputerUseObservation): DoomHeadlessToolResult {\n return {\n content: [\n { type: 'text', text: JSON.stringify({ ...value, screenshot: undefined }, null, 2) },\n { type: 'image', data: value.screenshot.data, mimeType: value.screenshot.mimeType },\n ],\n details: value,\n };\n}\n\nimport {\n type DoomHeadlessHostService,\n type DoomHeadlessTool,\n type DoomHeadlessCommand,\n} from '@agimon-ai/doompi-core/headless';\nimport { type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/server-facet';\nexport function createComputerUseServer(host: DoomHeadlessHostService): Omit<\n DoomServerSessionPlugin,\n 'tools' | 'commands'\n> & {\n tools: readonly DoomHeadlessTool[];\n commands: readonly DoomHeadlessCommand[];\n} {\n const client = createComputerUseSessionClient();\n const allowedScriptPaths = (host.context.environment[SCRIPT_PATHS_ENV] ?? '')\n .split(path.delimiter)\n .filter((entry) => entry.length > 0);\n const scriptRunner = client === undefined ? undefined : new ComputerScriptRunner({ client, allowedScriptPaths });\n const service = new DefaultComputerUseExtensionService(client);\n const dependencies = { client, scriptRunner, service };\n let state: ComputerUseSessionView | undefined;\n let stopActivity: (() => void) | undefined;\n let modeOwner: MinorModeOwner | undefined;\n const modeSelected = (): boolean =>\n (host.context.selection.state?.['minor-mode'] ?? []).includes(COMPUTER_USE_MODE_ID);\n const publishMode = (): void => modeOwner?.publish();\n const applyState = (next: ComputerUseSessionView | undefined): void => {\n state = next;\n host.context.client.setStatus(\n SOURCE,\n next === undefined || next.phase === 'inactive' ? undefined : `computer use: ${next.phase}`,\n );\n publishMode();\n };\n const selectMode = async (enabled: boolean): Promise<void> => {\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== COMPUTER_USE_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, COMPUTER_USE_MODE_ID] : modes,\n });\n publishMode();\n };\n const refresh = async (signal?: AbortSignal): Promise<void> => {\n if (!client) {\n applyState(undefined);\n return;\n }\n try {\n applyState(await client.state(signal));\n } catch {\n applyState(undefined);\n }\n };\n const requireActive = (): NonNullable<typeof client> => {\n if (!client || state?.phase !== 'active') throw new Error('Computer use is not active for this session.');\n return client;\n };\n modeOwner = defineMinorMode<undefined>({\n descriptor: {\n source: SOURCE,\n id: COMPUTER_USE_MODE_ID,\n label: 'Computer Use',\n description: 'Session-scoped semantic control through DoomPi Desktop.',\n order: 450,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Enable computer use for this session.',\n contexts: ['headless'],\n parameters: [],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Stop this session computer-use run.',\n contexts: ['headless'],\n parameters: [],\n },\n {\n id: 'doctor',\n label: 'Doctor',\n description: 'Report Desktop availability and session state.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: () => modeState(state, modeSelected()),\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n execution.signal.throwIfAborted();\n if (actionId === 'activate') {\n if (!client) throw new Error('DoomPi Desktop computer use is unavailable.');\n await selectMode(true);\n await refresh(execution.signal);\n return { message: 'Computer use activated.' };\n }\n if (actionId === 'doctor') {\n await refresh(execution.signal);\n return {\n message: client\n ? `Computer use is ${state?.phase ?? 'unavailable'}.`\n : 'DoomPi Desktop session API is unavailable.',\n };\n }\n if (actionId === 'deactivate') {\n if (client && state?.phase !== undefined && state.phase !== 'inactive' && state.phase !== 'failed')\n await client.stop(execution.signal);\n await selectMode(false);\n await refresh(execution.signal);\n return { message: 'Computer use deactivated.' };\n }\n throw new Error(`Unknown computer-use action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [serverMinorModes([modeOwner])],\n toolRestrictions: [\n {\n when: { state: { 'minor-mode': COMPUTER_USE_MODE_ID } },\n allowedTools: [...COMPUTER_USE_TOOL_NAMES],\n },\n ],\n activities: [\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: SOURCE,\n async start() {\n await refresh();\n const unsubscribe = client?.subscribeStatus?.(applyState);\n stopActivity = () => {\n unsubscribe?.();\n applyState(undefined);\n };\n return () => {\n stopActivity?.();\n stopActivity = undefined;\n };\n },\n },\n ],\n tools: [\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: 'computer_state',\n label: 'Computer State',\n description: 'Observe the authorized application window and return semantic accessibility state.',\n parameters: { type: 'object', properties: {}, additionalProperties: false },\n executionMode: 'serial',\n async execute(_toolCallId, _parameters, signal) {\n try {\n const session = requireActive();\n const observation = await session.observe(signal);\n return observationOutput(observation);\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: 'computer_action',\n label: 'Computer Action',\n description: 'Perform one constrained semantic action in the authorized application window.',\n parameters: {\n type: 'object',\n properties: {\n kind: { type: 'string', enum: ['press', 'focus', 'set_value', 'scroll'] },\n snapshotId: { type: 'string', minLength: 1 },\n elementRef: { type: 'string', minLength: 1 },\n value: { type: 'string' },\n direction: { type: 'string', enum: ['up', 'down', 'left', 'right'] },\n amount: { type: 'string', enum: ['line', 'page'] },\n },\n required: ['kind', 'snapshotId', 'elementRef'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal) {\n try {\n const result = await requireActive().act(parameters as unknown as ComputerUseAction, signal);\n await refresh(signal);\n return output(result);\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n name: 'computer_exec',\n label: 'Computer Script',\n description:\n 'Run a trusted, explicitly allowed local TypeScript script against the authorized application session.',\n parameters: {\n type: 'object',\n properties: { scriptPath: { type: 'string', minLength: 1 }, input: {} },\n required: ['scriptPath', 'input'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal) {\n try {\n if (!dependencies.scriptRunner) throw new Error('Computer script execution is unavailable.');\n const input = parameters as { scriptPath: string; input: unknown };\n return output(await dependencies.scriptRunner.execute(input.scriptPath, input.input, signal));\n } catch (error) {\n return output(error instanceof Error ? error.message : String(error), true);\n }\n },\n },\n ],\n commands: [\n {\n name: COMMAND_NAME,\n description: COMMAND_DESCRIPTION,\n async execute(args, execution) {\n const result = await dependencies.service.execute();\n await execution.client.notify({ body: result.message, level: result.level });\n if (args.trim() === 'deactivate' && client && state?.phase !== 'inactive' && state?.phase !== 'failed') {\n await client.stop();\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: (execution.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== COMPUTER_USE_MODE_ID),\n });\n await refresh();\n }\n },\n },\n ],\n hooks: [\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n event: 'before_agent_start',\n handle(event) {\n if (state?.phase !== 'active') return undefined;\n const prompt = typeof event.systemPrompt === 'string' ? event.systemPrompt : '';\n return { systemPrompt: `${prompt}\\n\\n${GUIDANCE}`.trim() };\n },\n },\n {\n when: {\n state: { 'minor-mode': COMPUTER_USE_MODE_ID },\n attribution: { kind: 'minor', mode: COMPUTER_USE_MODE_ID },\n },\n event: 'session_shutdown',\n handle: async () => {\n stopActivity?.();\n if (client && state?.phase !== 'inactive' && state?.phase !== 'failed') await client.stop();\n },\n },\n ],\n onDispose() {\n stopActivity?.();\n stopActivity = undefined;\n host.context.client.setStatus(SOURCE, undefined);\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../types/computerUseApi.cjs"),t=require("../services/webComputerUseAvailability/index.cjs");let n=require("node:crypto");function r(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:void 0}function i(e){let t=r(e);return t?.action===`status`||t?.action===`targets`||t?.action===`stop`||t?.action===`artifacts`?{action:t.action}:void 0}async function a(e){let n=await e.json();if(!e.ok)throw t.computerUseSessionApiError(e.status,n);return n}function o(e){let t=r(e);if(typeof t?.sessionId==`string`&&typeof t.revision==`number`&&typeof t.wake==`number`&&[`inactive`,`awaiting_confirmation`,`activating`,`active`,`stopping`,`failed`].includes(t.phase))return t}function s(){let s;return{frameType:e.computerUseChannelType,lifecycle:`hub`,start(c){let l=new Map,u=new Map,d=new Map,f=new Map,p=new Map,m=new Set,h,g=!1,_=async(t,n,r=`GET`,i)=>c.requestSessionApi(t,{basePath:e.API_BASE_PATH,path:n,method:r,...i===void 0?{}:{body:JSON.stringify(i)}}),v=(e,t)=>{t.phase===`active`||t.phase===`activating`||t.phase===`stopping`?h=e.sessionId:h===e.sessionId&&(h=void 0,f.delete(e.sessionId));let n={state:t,targets:d.get(e.sessionId)??[],...h!==void 0&&h!==e.sessionId?{busy:!0}:{}};u.set(e.sessionId,n),c.publish(e.sessionId,n)},y=async t=>{let n=o(await a(await _(t,e.COMPUTER_USE_ROUTES.hubState)));if(n===void 0)throw Error(`Computer-use API returned an invalid session state.`);return v(t,n),n},b=async(t,n)=>{if(!c.computerUse?.available)throw Error(`DoomPi Desktop computer use is unavailable.`);try{let r=await c.computerUse.request(t,{operation:n.operation,payload:n.operation===`act`?{grantId:n.grantId,sequence:n.sequence,action:n.payload}:{grantId:n.grantId}});await a(await _(t,e.COMPUTER_USE_ROUTES.hubComplete,`POST`,{id:n.id,result:r}))}catch(r){await a(await _(t,e.COMPUTER_USE_ROUTES.hubComplete,`POST`,{id:n.id,error:r instanceof Error?r.message:String(r)}))}},x=async t=>{let r=await a(await _(t,e.COMPUTER_USE_ROUTES.hubAuthorization)),i;if(r!==null&&c.computerUse?.available)try{i=await c.computerUse.request(t,{operation:`stop`,payload:{grantId:r.grantId}})}catch(e){let t=e instanceof Error?e.message:String(e);i={artifactId:(0,n.randomUUID)(),status:`failed`,failure:{code:`recording_failed`,message:t.slice(0,512)}},c.onNotice(`computer-use Desktop stop was already unavailable (${t})`)}await a(await _(t,e.COMPUTER_USE_ROUTES.hubStop,`POST`,{artifact:i})),f.delete(t.sessionId),h===t.sessionId&&(h=void 0)},S=async(n,i)=>{if(!(g||m.has(n.sessionId))){m.add(n.sessionId);try{let t=i??await y(n);if(t.phase===`active`){if(!f.has(n.sessionId)){let t=await a(await _(n,e.COMPUTER_USE_ROUTES.hubAuthorization));t!==null&&f.set(n.sessionId,t.grantId)}let i=typeof t.expiresAt==`number`&&t.expiresAt<=Date.now(),o=!1;if(!i&&c.computerUse?.available)try{o=r(await c.computerUse.request(n,{operation:`status`}))?.ownedBySession===!0}catch{o=!0}if(i||!o){await x(n),await y(n);return}}if(t.phase===`awaiting_confirmation`&&(h===void 0||h===n.sessionId)){if(!c.computerUse?.available)throw Error(`DoomPi Desktop computer use is unavailable.`);let t=await a(await _(n,e.COMPUTER_USE_ROUTES.hubActivation));if(t!==null){h=n.sessionId;try{let i=await c.computerUse.request(n,{operation:`activate`,payload:t});await a(await _(n,e.COMPUTER_USE_ROUTES.hubStop,`POST`,{host:i}));let o=r(i)?.grantId;typeof o==`string`&&f.set(n.sessionId,o)}catch(t){h=void 0,await a(await _(n,e.COMPUTER_USE_ROUTES.hubStop,`POST`,{error:t instanceof Error?t.message:String(t)}))}await y(n)}}t.phase===`stopping`&&(await x(n),await y(n));let o=await a(await _(n,e.COMPUTER_USE_ROUTES.hubNext));o!==null&&await b(n,o)}catch(e){e instanceof t.MissingComputerUseApiError?u.delete(n.sessionId):c.onNotice(`computer-use state handling failed for ${n.sessionId} (${e instanceof Error?e.message:String(e)})`)}finally{m.delete(n.sessionId)}}},C=(e,t)=>{let n=o(t);n!==void 0&&n.sessionId===e.sessionId&&(v(e,n),S(e,n))};return s=(e,n)=>{let a=i(n);a!==void 0&&(async()=>{try{if(a.action===`targets`){if(!c.computerUse?.available)throw Error(`DoomPi Desktop computer use is unavailable.`);let t=await c.computerUse.request(e,{operation:`targets`});d.set(e.sessionId,Array.isArray(t)?t.filter(e=>r(e)!==void 0):[])}else a.action===`stop`&&await x(e);await y(e),S(e)}catch(n){n instanceof t.MissingComputerUseApiError?u.delete(e.sessionId):c.onNotice(`computer-use command failed for ${e.sessionId} (${n instanceof Error?n.message:String(n)})`)}})()},{payloadFor:e=>u.get(e.sessionId),sessionAdded(t){l.set(t.sessionId,t);let n=c.directEvents.subscribe(e.computerUseChannelType,t.sessionId,e=>C(t,e),{replayLatest:!0});p.set(t.sessionId,n),S(t)},sessionRemoved(e){let t=l.get(e),n=f.get(e);p.get(e)?.(),p.delete(e),t!==void 0&&n!==void 0&&c.computerUse?.available&&c.computerUse.request(t,{operation:`stop`,payload:{grantId:n}}).catch(e=>c.onNotice(`computer-use session cleanup failed (${e instanceof Error?e.message:String(e)})`)),l.delete(e),u.delete(e),d.delete(e),f.delete(e),m.delete(e),h===e&&(h=void 0)},close(){g=!0;for(let e of p.values())e();if(p.clear(),c.computerUse?.available)for(let[e,t]of f){let n=l.get(e);n!==void 0&&c.computerUse.request(n,{operation:`stop`,payload:{grantId:t}}).catch(()=>void 0)}l.clear(),u.clear(),d.clear(),f.clear()}}},receive(e,t){s?.(e,t)}}}exports.computerUseChannelType=e.computerUseChannelType,exports.createComputerUseChannel=s;
2
+ //# sourceMappingURL=webComputerUseChannel.cjs.map