@agimon-ai/po-computer-use 0.0.0-alpha.107 → 0.0.0-alpha.108

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.
@@ -26,6 +26,7 @@ let node_child_process = require("node:child_process");
26
26
  let node_fs_promises = require("node:fs/promises");
27
27
  let node_module = require("node:module");
28
28
  let node_crypto = require("node:crypto");
29
+ let _agimon_ai_po_core_inputTemplate = require("@agimon-ai/po-core/inputTemplate");
29
30
  let _agimon_ai_po_core_packageApi = require("@agimon-ai/po-core/packageApi");
30
31
  //#region src/constants/computerUse.ts
31
32
  const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]
@@ -479,6 +480,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
479
480
  closed = false;
480
481
  desktop;
481
482
  beforeActivate;
483
+ profileRuntime;
484
+ nativeTarget;
485
+ resolvingInput = false;
486
+ inputController;
487
+ sensitiveInput = false;
482
488
  listeners = /* @__PURE__ */ new Set();
483
489
  unsubscribeDesktop;
484
490
  static DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
@@ -490,7 +496,9 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
490
496
  this.requestTimeoutMs = options.requestTimeoutMs ?? ComputerUseRequestBroker.DEFAULT_REQUEST_TIMEOUT_MS;
491
497
  this.desktop = options.desktop;
492
498
  this.beforeActivate = options.beforeActivate;
499
+ this.profileRuntime = options.profileRuntime;
493
500
  this.unsubscribeDesktop = options.desktop?.subscribe(() => {
501
+ this.inputController?.abort();
494
502
  clearTimeout(this.expiryTimer);
495
503
  if (!options.desktop?.available) {
496
504
  this.rejectPending("Desktop disconnected.");
@@ -548,10 +556,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
548
556
  act: async (action, signal) => {
549
557
  requireDesktop();
550
558
  if (!semanticAction(action)) throw new Error("A valid semantic action is required.");
551
- return result(await this.enqueue("act", action, signal));
559
+ return result(await this.performAction(action, signal));
552
560
  },
553
561
  stop: async (signal) => {
554
562
  signal?.throwIfAborted();
563
+ this.inputController?.abort();
555
564
  if (this.phase !== "inactive" && this.phase !== "failed") {
556
565
  this.phase = "stopping";
557
566
  this.rejectPending("Computer use was stopped.");
@@ -624,7 +633,58 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
624
633
  }
625
634
  this.rejectPending(message);
626
635
  }
636
+ async performAction(action, requestSignal) {
637
+ if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
638
+ if (action.kind !== "set_value" || !(0, _agimon_ai_po_core_inputTemplate.hasInputTemplate)(action.value)) return this.enqueue("act", action, requestSignal);
639
+ this.resolvingInput = true;
640
+ try {
641
+ if (this.phase !== "active" || this.pending || !this.grantId) throw new Error();
642
+ const parts = (0, _agimon_ai_po_core_inputTemplate.parseInputTemplate)(action.value);
643
+ const profile = this.profileRuntime?.();
644
+ if (!profile) throw new Error();
645
+ const snapshot = profile.readSelection();
646
+ const generation = snapshot.generation;
647
+ const grantId = this.grantId;
648
+ const target = this.nativeTarget;
649
+ const usesSecret = parts.some((part) => part.kind === "secret");
650
+ if (usesSecret && (!target || target.scope === "desktop" || typeof target.bundleId !== "string")) throw new Error();
651
+ const controller = new AbortController();
652
+ this.inputController = controller;
653
+ const signal = AbortSignal.any([
654
+ snapshot.signal,
655
+ controller.signal,
656
+ ...requestSignal ? [requestSignal] : []
657
+ ]);
658
+ const value = await (0, _agimon_ai_po_core_inputTemplate.renderInputTemplate)(parts, {
659
+ readEnv: (name) => snapshot.env && Object.hasOwn(snapshot.env, name) ? snapshot.env[name] : void 0,
660
+ resolveSecret: (name) => profile.resolveInputSecret(name, {
661
+ surface: "computer",
662
+ target: target.bundleId,
663
+ signal
664
+ }),
665
+ onResolved: () => {
666
+ this.sensitiveInput = true;
667
+ },
668
+ signal
669
+ });
670
+ signal.throwIfAborted();
671
+ if (this.closed || this.phase !== "active" || this.grantId !== grantId || this.nativeTarget !== target || this.profileRuntime?.() !== profile || profile.readSelection().generation !== generation) throw new Error();
672
+ this.resolvingInput = false;
673
+ return await this.enqueue("act", {
674
+ ...action,
675
+ value,
676
+ ...usesSecret ? { sensitiveBundleId: target.bundleId } : {}
677
+ }, signal);
678
+ } catch {
679
+ return jsonError("Computer input template failed.", 400);
680
+ } finally {
681
+ this.inputController = void 0;
682
+ this.resolvingInput = false;
683
+ }
684
+ }
627
685
  async enqueue(operation, payload, signal) {
686
+ if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
687
+ if (operation === "observe" && this.sensitiveInput) return jsonError("Observations are sealed after sensitive input.", 409);
628
688
  if (this.phase !== "active" || this.grantId === void 0) return jsonError("Computer use is not active.", 409);
629
689
  if (this.pending !== void 0) return jsonError("Another computer-use request is live.", 409);
630
690
  if (signal?.aborted === true) return jsonError("The computer-use request was cancelled.", 499);
@@ -653,9 +713,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
653
713
  });
654
714
  this.changed();
655
715
  try {
656
- return Response.json(await completion);
716
+ const value = await completion;
717
+ return Response.json(this.sensitiveInput ? { applied: true } : value);
657
718
  } catch (error) {
658
- return jsonError(error instanceof Error ? error.message : String(error), 502);
719
+ return jsonError(this.sensitiveInput ? "Sensitive computer input failed." : error instanceof Error ? error.message : String(error), 502);
659
720
  }
660
721
  }
661
722
  async fetch(request) {
@@ -691,9 +752,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
691
752
  if (request.method === "POST" && path === routes.agentAction.path) {
692
753
  const action = await body(request);
693
754
  if (!semanticAction(action)) return jsonError("A valid semantic action is required.", 400);
694
- return this.enqueue("act", action, request.signal);
755
+ return this.performAction(action, request.signal);
695
756
  }
696
757
  if (request.method === "POST" && path === routes.agentStop.path) {
758
+ this.inputController?.abort();
697
759
  if (this.phase !== "active") return jsonError("Computer use is not active.", 409);
698
760
  this.phase = "stopping";
699
761
  this.rejectPending("The computer-use request was stopped.");
@@ -726,6 +788,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
726
788
  return Response.json(this.state());
727
789
  }
728
790
  if (request.method === "POST" && path === routes.hubStop.path) {
791
+ this.inputController?.abort();
729
792
  const input = await body(request);
730
793
  if (this.phase === "activating") {
731
794
  if (typeof input.error === "string") {
@@ -739,6 +802,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
739
802
  const host = record(input.host);
740
803
  if (typeof host?.grantId !== "string" || !Number.isFinite(host.expiresAt) || host.expiresAt <= Date.now()) return jsonError("Desktop did not issue a complete grant.", 502);
741
804
  const selectedTarget = record(host.target);
805
+ this.nativeTarget = selectedTarget === void 0 ? void 0 : Object.freeze({ ...selectedTarget });
742
806
  if (this.activation !== void 0 && selectedTarget !== void 0) this.activation = Object.freeze({
743
807
  ...this.activation,
744
808
  target: Object.freeze({ ...selectedTarget })
@@ -751,6 +815,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
751
815
  this.expiryTimer = setTimeout(() => {
752
816
  if (this.closed || this.phase !== "active") return;
753
817
  this.phase = "stopping";
818
+ this.inputController?.abort();
754
819
  this.rejectPending("The computer-use grant expired.");
755
820
  this.changed();
756
821
  }, Math.max(0, this.expiresAt - Date.now()));
@@ -763,6 +828,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
763
828
  this.grantId = void 0;
764
829
  this.expiresAt = void 0;
765
830
  this.activation = void 0;
831
+ this.nativeTarget = void 0;
766
832
  this.artifact = artifactView(input.artifact) ?? this.artifact;
767
833
  }
768
834
  this.changed();
@@ -773,6 +839,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
773
839
  close() {
774
840
  if (this.closed) return;
775
841
  this.closed = true;
842
+ this.inputController?.abort();
776
843
  clearTimeout(this.expiryTimer);
777
844
  this.unsubscribeDesktop?.();
778
845
  this.listeners.clear();
@@ -1144,4 +1211,4 @@ Object.defineProperty(exports, "routes", {
1144
1211
  }
1145
1212
  });
1146
1213
 
1147
- //# sourceMappingURL=extensionService-BS2Lz9R8.cjs.map
1214
+ //# sourceMappingURL=extensionService-BB08HbHP.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensionService-BB08HbHP.cjs","names":["poApiCallerFrom","randomUUID","hasInputTemplate","parseInputTemplate","renderInputTemplate","realpath","path","createRequire","spawn"],"sources":["../src/constants/computerUse.ts","../src/services/computerScriptWorker/index.ts","../src/types/computerUseApi.ts","../src/types/desktopPermissions.ts","../src/types/apiRoutes.ts","../src/services/computerUseApi/index.ts","../src/services/computerScriptRunner/index.ts","../src/services/extensionService/index.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/** The session artifact storage service and the folder computer-use evidence lands in. */\nexport const COMPUTER_USE_ARTIFACTS_SERVICE = 'po/artifacts';\nexport const COMPUTER_USE_ARTIFACT_DIRECTORY = 'computer-use';\n/** The host recording store's own bounds: its largest recording and its range size. */\nexport const COMPUTER_USE_RECORDING_MAX_BYTES = 128 * 1024 * 1024;\nexport const COMPUTER_USE_RECORDING_CHUNK_BYTES = 1024 * 1024;\nexport const COMPUTER_USE_CODEMODE_GUIDANCE =\n '[COMPUTER USE ACTIVE]\\nUse computer.state() in exec 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. Call computer.stop() when the task is complete. Load codemode-how-to-computer-use for details.';\n","/** Source for an isolated child process. Restricted modules execute in QuickJS, not in Node's realm. */\nexport const COMPUTER_SCRIPT_WORKER_SOURCE = String.raw`\nimport { readFileSync, realpathSync, statSync } from 'node:fs';\nimport path from 'node:path';\nimport { stripTypeScriptTypes } from 'node:module';\nimport { pathToFileURL } from 'node:url';\n\nlet nextRequestId = 0;\nlet started = false;\nconst pending = new Map();\nconst controller = new AbortController();\nprocess.once('SIGTERM', () => controller.abort());\nconst send = (message) => {\n if (process.connected) process.send(message, () => {});\n};\nconst call = (operation, payload) => new Promise((resolve, reject) => {\n if (controller.signal.aborted) return reject(new Error('Computer script was cancelled.'));\n if (pending.size >= 64) return reject(new Error('Too many outstanding program operations.'));\n const id = String(++nextRequestId);\n pending.set(id, { resolve, reject });\n send({ type: 'program', id, operation, payload });\n});\n\nasync function restricted(message) {\n const { getQuickJS } = await import(pathToFileURL(message.quickjsPath).href);\n const QuickJS = await getQuickJS();\n const runtime = QuickJS.newRuntime();\n runtime.setMemoryLimit(32 * 1024 * 1024);\n runtime.setMaxStackSize(512 * 1024);\n const deadline = Date.now() + message.timeoutMs;\n runtime.setInterruptHandler(() => controller.signal.aborted || Date.now() >= deadline);\n const { realpath } = await import('node:fs/promises');\n const root = await realpath(message.scriptRoot);\n const sources = new Map();\n let sourceBytes = 0;\n let moduleFailure;\n // sync: QuickJS invokes module normalization and loading synchronously and cannot await filesystem reads.\n const modulePath = (candidate) => {\n const filename = realpathSync(candidate);\n const relative = path.relative(root, filename);\n if (relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative)) {\n throw new Error('Computer helper escapes the admitted script root.');\n }\n if (!/\\.(ts|js|mjs)$/.test(filename)) throw new Error('Computer helpers must be JavaScript or erasable TypeScript.');\n return filename;\n };\n const entry = modulePath(message.scriptPath);\n runtime.setModuleLoader((filename) => {\n // Preserve a rejected normalization even if the engine subsequently asks to load an empty name.\n if (moduleFailure) throw moduleFailure;\n if (sources.has(filename)) return sources.get(filename);\n if (sources.size >= 32 || statSync(filename).size > 256 * 1024) throw new Error('Computer script module limit exceeded.');\n const source = readFileSync(filename, 'utf8');\n sourceBytes += Buffer.byteLength(source);\n if (sourceBytes > 512 * 1024) throw new Error('Computer script source limit exceeded.');\n const compiled = filename.endsWith('.ts') ? stripTypeScriptTypes(source, { mode: 'strip' }) : source;\n sources.set(filename, compiled);\n return compiled;\n }, (base, name) => {\n try {\n if (name === '__entry__') return entry;\n if (!name.startsWith('./') && !name.startsWith('../')) {\n throw new Error('Restricted computer functions cannot import host or package modules.');\n }\n return modulePath(path.resolve(path.dirname(base), name));\n } catch (error) {\n moduleFailure = error;\n throw error;\n }\n });\n const vm = runtime.newContext();\n let disposed = false;\n const deferreds = new Set();\n const pump = () => {\n if (disposed) return;\n const jobs = runtime.executePendingJobs();\n if (jobs.error) {\n const detail = vm.dump(jobs.error);\n jobs.error.dispose();\n throw new Error(detail?.message ?? String(detail));\n }\n };\n const set = (name, value) => {\n vm.setProp(vm.global, name, value);\n value.dispose();\n };\n set('__input', vm.newString(JSON.stringify(message.input)));\n set('__aborted', vm.newFunction('__aborted', () => controller.signal.aborted ? vm.true : vm.false));\n set('__log', vm.newFunction('__log', (level, text) => {\n send({ type: 'log', level: vm.getString(level), message: vm.getString(text) });\n }));\n set('__call', vm.newFunction('__call', (operationHandle, payloadHandle) => {\n const operation = vm.getString(operationHandle);\n const serialized = vm.getString(payloadHandle);\n if (serialized.length > message.maxOutputBytes) throw new Error('Computer action exceeds the size limit.');\n if (operation !== 'observe' && operation !== 'act') throw new Error('Unsupported program operation.');\n const deferred = vm.newPromise();\n deferreds.add(deferred);\n call(operation, JSON.parse(serialized)).then((value) => {\n if (disposed) return;\n const handle = vm.newString(JSON.stringify(value));\n deferred.resolve(handle);\n handle.dispose();\n }, (error) => {\n if (disposed) return;\n const handle = vm.newError(error.message);\n deferred.reject(handle);\n handle.dispose();\n }).then(() => {\n if (disposed) return;\n deferred.dispose();\n deferreds.delete(deferred);\n pump();\n }).catch((error) => send({ type: 'failed', error: error.message }));\n return deferred.handle.dup();\n }));\n let evaluation;\n try {\n evaluation = vm.unwrapResult(vm.evalCode(\n 'import { run } from \"__entry__\";\\n' +\n 'const invoke = __call; const log = __log; const isAborted = __aborted;\\n' +\n 'const program = Object.freeze({\\n' +\n ' observe: async (options = {}) => JSON.parse(await invoke(\"observe\", JSON.stringify(options))),\\n' +\n ' act: async (action) => JSON.parse(await invoke(\"act\", JSON.stringify(action)))\\n' +\n '});\\n' +\n 'const logger = Object.freeze(Object.fromEntries([\"debug\",\"info\",\"warn\",\"error\"].map(level => [level, value => log(level, String(value))])));\\n' +\n 'const signal = Object.freeze({ get aborted() { return isAborted(); }, throwIfAborted() { if (isAborted()) throw new Error(\"Computer script was cancelled.\"); } });\\n' +\n 'const result = await run({ context: { program }, input: JSON.parse(__input), logger, signal });\\n' +\n 'globalThis.__result = result === undefined ? undefined : JSON.stringify(result);',\n path.join(root, '__computer_entry__.mjs'), { type: 'module' },\n ));\n const completion = vm.resolvePromise(evaluation);\n pump();\n const completed = vm.unwrapResult(await completion);\n completed.dispose();\n const result = vm.getProp(vm.global, '__result');\n const resultJson = vm.dump(result);\n result.dispose();\n return resultJson;\n } finally {\n disposed = true;\n for (const deferred of deferreds) deferred.dispose();\n evaluation?.dispose();\n vm.dispose();\n runtime.dispose();\n }\n}\n\nprocess.on('message', async (message) => {\n if (message?.type === 'response') {\n const request = pending.get(message.id);\n if (!request) return;\n pending.delete(message.id);\n if (message.error) request.reject(new Error(message.error));\n else request.resolve(message.value);\n return;\n }\n if (message?.type !== 'start' || started) return;\n started = true;\n try {\n let resultJson;\n if (message.trusted) {\n const loaded = await import(pathToFileURL(message.scriptPath).href);\n if (typeof loaded.run !== 'function') throw new Error('Computer script must export a named run function.');\n const program = {\n observe: (options = {}) => call('observe', options),\n act: (action) => call('act', action),\n };\n const logger = Object.fromEntries(['debug','info','warn','error'].map(level => [level, value => {\n send({ type: 'log', level, message: String(value) });\n }]));\n const result = await loaded.run({ context: { program }, input: message.input, logger, signal: controller.signal });\n resultJson = result === undefined ? undefined : JSON.stringify(result);\n } else {\n resultJson = await restricted(message);\n }\n if (typeof resultJson === 'string' && Buffer.byteLength(resultJson) > message.maxOutputBytes) {\n throw new Error('Computer script result exceeded the size limit.');\n }\n send({ type: 'complete', resultJson });\n } catch (error) {\n send({ type: 'failed', error: String(error?.message ?? error).slice(0, 1024) });\n }\n});\n`;\n","import type { PoApiCaller } from '@agimon-ai/po-core/packageApi';\n\nexport const API_BASE_PATH = 'computer-use';\nexport const computerUseChannelType = 'computer_use_state';\nexport const COMPUTER_USE_MODE_ID = 'computer-use';\nexport const COMPUTER_USE_STATUS_KEY = 'po-computer-use';\nexport const COMPUTER_USE_MODE_STATUS_KEY = 'po-computer-use-mode';\nexport const COMPUTER_USE_MAX_DURATION_MS = 1_800 * 1_000;\nexport const COMPUTER_USE_DEFAULT_DURATION_MS = 300 * 1_000;\n/** The session lengths a person can pick when granting control, up to the maximum. */\nexport const COMPUTER_USE_DURATION_CHOICES_MS = [\n COMPUTER_USE_DEFAULT_DURATION_MS,\n 900_000,\n COMPUTER_USE_MAX_DURATION_MS,\n] as const;\nexport const COMPUTER_USE_CONFIRMATION_WINDOW_MS = 2 * 60 * 1_000;\n\n/**\n * Every path this API answers on, below its mount.\n *\n * The typed route table in `./apiRoutes` is built from this, the dispatcher\n * reads that table, and the hub channel addresses the broker with these same\n * strings, so a route cannot move on one side alone.\n */\nexport const COMPUTER_USE_ROUTES = {\n activate: '/activate',\n artifact: '/artifact',\n agentState: '/agent/state',\n agentObserve: '/agent/observe',\n agentAction: '/agent/action',\n agentStop: '/agent/stop',\n hubState: '/hub/state',\n hubActivation: '/hub/activation',\n hubAuthorization: '/hub/authorization',\n hubNext: '/hub/next',\n hubComplete: '/hub/complete',\n hubStop: '/hub/stop',\n} as const;\n\nexport const COMPUTER_USE_WAKE_LIMIT = 1_000_000;\n\nexport interface ComputerUseArtifactView {\n readonly artifactId: string;\n readonly status: 'ready' | 'failed';\n readonly sizeBytes?: number;\n readonly downloadUrl?: string;\n readonly previewUrl?: string;\n readonly actionCount?: number;\n readonly completedAt?: string;\n readonly failure?: { readonly code: string; readonly message: string };\n}\n\nexport interface ComputerUseSessionView {\n readonly sessionId: string;\n readonly revision: number;\n readonly wake: number;\n readonly phase: 'inactive' | 'awaiting_confirmation' | 'activating' | 'active' | 'stopping' | 'failed';\n readonly requestId?: string;\n readonly target?: Record<string, unknown>;\n readonly durationMs?: number;\n readonly expiresAt?: number;\n readonly failure?: { readonly code: string; readonly message: string };\n readonly artifact?: ComputerUseArtifactView;\n}\n\nexport interface ComputerUseActivationRequest {\n readonly requestId: string;\n readonly target?: Record<string, unknown>;\n readonly durationSeconds: number;\n readonly createdAt: number;\n readonly confirmationExpiresAt: number;\n /** Set by the session broker only after the person approves the in-app dialog. */\n readonly confirmedAt?: number;\n readonly caller: PoApiCaller;\n}\n\nexport interface ComputerUseBrokerRequest {\n readonly id: string;\n readonly operation: 'observe' | 'act';\n readonly payload?: unknown;\n readonly grantId: string;\n readonly sequence?: number;\n}\n\nexport interface ComputerUseChannelPayload {\n readonly state: ComputerUseSessionView;\n readonly targets: readonly Record<string, unknown>[];\n readonly busy?: true;\n}\n\nexport type ComputerUseBrowserCommand = { readonly action: 'status' | 'targets' | 'stop' | 'artifacts' };\n","/** The mount's only path: GET reads the permission states, POST asks macOS for one. */\nexport const DESKTOP_PERMISSIONS_PATH = '/';\n\n/** The macOS privacy permissions Desktop reports, in the order the settings page shows them. */\nexport const DESKTOP_PERMISSIONS = [\n 'accessibility',\n 'screen-recording',\n 'microphone',\n 'automation',\n 'full-disk-access',\n] as const;\nexport type DesktopPermission = (typeof DESKTOP_PERMISSIONS)[number];\n\n/** `per-app` is Automation: macOS asks once for each app Po controls and reports no overall state. */\nexport type DesktopPermissionState = 'granted' | 'denied' | 'not-determined' | 'per-app';\nexport type DesktopPermissionStates = Record<DesktopPermission, DesktopPermissionState>;\n\nexport interface DesktopPermissionRequest {\n readonly permission: DesktopPermission;\n}\n\nexport function isDesktopPermission(value: unknown): value is DesktopPermission {\n return typeof value === 'string' && (DESKTOP_PERMISSIONS as readonly string[]).includes(value);\n}\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport {\n COMPUTER_USE_ROUTES,\n type ComputerUseActivationRequest,\n type ComputerUseBrokerRequest,\n type ComputerUseSessionView,\n} from './computerUseApi';\nimport { DESKTOP_PERMISSIONS_PATH, type DesktopPermissionStates } from './desktopPermissions';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path: the build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/computer-use/`, so the\n * mount is stated once, by the folder that creates it.\n *\n * The paths come from `COMPUTER_USE_ROUTES` rather than being written out\n * again. That table already addressed the broker from the hub channel and from\n * the broker's own dispatcher, and a second copy here is exactly the\n * disagreement this file exists to prevent. The dispatcher now reads this\n * table, so the page, the broker and the hub all resolve one set of strings.\n *\n * Activation, status, cancellation and recording reads are reachable from a browser. The `/agent/` and `/hub/` routes\n * each demand a host-issued bearer token and answer 404 without one; they are\n * declared here because they are this API's surface, not because a page calls\n * them.\n */\nconst routes = {\n artifact: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.artifact,\n query: ['artifactId', 'offset'],\n raw: true,\n },\n activationState: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.activate,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n cancelActivation: {\n method: 'DELETE',\n path: COMPUTER_USE_ROUTES.activate,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n activate: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.activate,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n agentState: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.agentState,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n /** Answers whatever the admitted Desktop provider returned, which is runtime-defined JSON. */\n agentObserve: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.agentObserve,\n response: undefined as unknown as ApiResponseOf<unknown>,\n },\n agentAction: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.agentAction,\n response: undefined as unknown as ApiResponseOf<unknown>,\n },\n agentStop: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.agentStop,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n hubState: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubState,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n /** Null until a reader has confirmed one; reading it moves the session to `activating`. */\n hubActivation: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubActivation,\n response: undefined as unknown as ApiResponseOf<ComputerUseActivationRequest | null>,\n },\n hubAuthorization: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubAuthorization,\n response: undefined as unknown as ApiResponseOf<{ readonly grantId: string; readonly expiresAt?: number } | null>,\n },\n hubNext: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubNext,\n response: undefined as unknown as ApiResponseOf<ComputerUseBrokerRequest | null>,\n },\n hubComplete: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.hubComplete,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n hubStop: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.hubStop,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n /** Desktop's macOS permission states, served by the hub's `desktop-permissions` mount. */\n desktopPermissions: {\n method: 'GET',\n path: DESKTOP_PERMISSIONS_PATH,\n response: undefined as unknown as ApiResponseOf<DesktopPermissionStates>,\n },\n /** Asks macOS for the body's permission on the Mac running Desktop; answers the states after. */\n requestDesktopPermission: {\n method: 'POST',\n path: DESKTOP_PERMISSIONS_PATH,\n response: undefined as unknown as ApiResponseOf<DesktopPermissionStates>,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","import { randomUUID } from 'node:crypto';\n\nimport type { PoComputerUseSessionAccess, PoDirectEventBus } from '@agimon-ai/po-core/hubChannel';\nimport { hasInputTemplate, parseInputTemplate, renderInputTemplate } from '@agimon-ai/po-core/inputTemplate';\nimport { poApiCallerFrom, type PoApi, type PoApiContext, type PoApiHandler } from '@agimon-ai/po-core/packageApi';\n\nimport routes from '../../types/apiRoutes';\nimport type { ComputerUseAction, ComputerUseObservation, ComputerUseObservationOptions } from '../../types/computerUse';\nimport {\n API_BASE_PATH,\n computerUseChannelType,\n COMPUTER_USE_CONFIRMATION_WINDOW_MS,\n COMPUTER_USE_MAX_DURATION_MS,\n COMPUTER_USE_WAKE_LIMIT,\n type ComputerUseActivationRequest,\n type ComputerUseArtifactView,\n type ComputerUseBrokerRequest,\n type ComputerUseSessionView,\n} from '../../types/computerUseApi';\nimport type { ComputerUseSessionClient } from '../sessionApiClient';\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 allowed = (keys: readonly string[]) => Object.keys(value).every((key) => keys.includes(key));\n if (value.kind === 'launch') return typeof value.app === 'string' && value.app.length > 0 && allowed(['kind', 'app']);\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 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 if (value.kind === 'perform')\n return (\n typeof value.action === 'string' &&\n /^AX[A-Za-z]{1,62}$/u.test(value.action) &&\n allowed(['kind', 'snapshotId', 'elementRef', 'action'])\n );\n return false;\n}\n\n/** Throws on anything but the documented observation options, so every caller shares one check. */\nexport function observationOptions(value: unknown): ComputerUseObservationOptions {\n const options = record(value);\n if (options === undefined) throw new TypeError('Observation options must be an object.');\n for (const [key, entry] of Object.entries(options)) {\n const valid =\n key === 'includeScreenshot'\n ? typeof entry === 'boolean'\n : key === 'root' || key === 'label' || key === 'role'\n ? typeof entry === 'string' && entry.length > 0 && entry.length <= 256\n : key === 'offset'\n ? Number.isInteger(entry) && (entry as number) >= 0 && (entry as number) <= 2_000\n : key === 'limit' && Number.isInteger(entry) && (entry as number) >= 1 && (entry as number) <= 500;\n if (!valid) throw new TypeError(`Invalid observation option \"${key}\".`);\n }\n return options as ComputerUseObservationOptions;\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 ...(typeof input.sizeBytes === 'number' && Number.isSafeInteger(input.sizeBytes) && input.sizeBytes > 0\n ? { sizeBytes: input.sizeBytes }\n : {}),\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 ComputerInputProfile {\n readSelection(): {\n readonly env?: Readonly<Record<string, string>>;\n readonly generation: number;\n readonly signal: AbortSignal;\n };\n resolveInputSecret(name: string, request: { surface: string; target: string; signal?: AbortSignal }): Promise<string>;\n}\n\nexport interface ComputerUseApiOptions {\n readonly sessionId?: string;\n readonly internalToken?: string;\n readonly hubToken?: string;\n readonly directEvents: PoDirectEventBus;\n readonly requestTimeoutMs?: number;\n readonly desktop?: PoComputerUseSessionAccess;\n readonly beforeActivate?: () => Promise<void>;\n readonly profileRuntime?: () => ComputerInputProfile | undefined;\n}\n\nexport class ComputerUseRequestBroker implements PoApiHandler {\n private readonly sessionId: string;\n private readonly internalToken?: string;\n private readonly hubToken?: string;\n private readonly directEvents: PoDirectEventBus;\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 expiryTimer?: ReturnType<typeof setTimeout>;\n private failure?: ComputerUseSessionView['failure'];\n private artifact?: ComputerUseArtifactView;\n private pending?: PendingRequest;\n private closed = false;\n private readonly desktop?: PoComputerUseSessionAccess;\n private readonly beforeActivate?: () => Promise<void>;\n private readonly profileRuntime?: () => ComputerInputProfile | undefined;\n private nativeTarget?: Record<string, unknown>;\n private resolvingInput = false;\n private inputController?: AbortController;\n private sensitiveInput = false;\n private readonly listeners = new Set<(state: ComputerUseSessionView) => void>();\n private readonly unsubscribeDesktop?: () => void;\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 this.desktop = options.desktop;\n this.beforeActivate = options.beforeActivate;\n this.profileRuntime = options.profileRuntime;\n this.unsubscribeDesktop = options.desktop?.subscribe(() => {\n this.inputController?.abort();\n clearTimeout(this.expiryTimer);\n if (!options.desktop?.available) {\n this.rejectPending('Desktop disconnected.');\n this.phase = 'failed';\n this.grantId = undefined;\n this.failure = { code: 'desktop_unavailable', message: 'Desktop disconnected.' };\n } else if (this.phase !== 'inactive' && this.phase !== 'failed') {\n this.phase = 'stopping';\n this.rejectPending('Control was stopped by Desktop.');\n }\n this.changed();\n });\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 /** Tools and the API share this broker. No socket, credential discovery, or second state store. */\n public sessionClient(): ComputerUseSessionClient {\n const result = async <T>(response: Response): Promise<T> => {\n const value = (await response.json()) as T & { error?: string };\n if (!response.ok) throw new Error(value.error ?? `Computer-use request failed (${response.status}).`);\n return value;\n };\n const requireDesktop = (): void => {\n if (this.closed || !this.desktop?.available || this.desktop.enabled === false)\n throw new Error('Desktop computer use is unavailable.');\n };\n return {\n state: async () => this.state(),\n subscribeStatus: (listener) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n },\n observe: async (signal, options = {}) => {\n requireDesktop();\n return result<ComputerUseObservation>(await this.enqueue('observe', observationOptions(options), signal));\n },\n act: async (action: ComputerUseAction, signal) => {\n requireDesktop();\n if (!semanticAction(action as unknown as Record<string, unknown>))\n throw new Error('A valid semantic action is required.');\n return result(await this.performAction(action, signal));\n },\n stop: async (signal) => {\n signal?.throwIfAborted();\n this.inputController?.abort();\n if (this.phase !== 'inactive' && this.phase !== 'failed') {\n this.phase = 'stopping';\n this.rejectPending('Computer use was stopped.');\n this.changed();\n }\n return this.state();\n },\n };\n }\n private changed(): void {\n this.revision += 1;\n this.wake = (this.wake + 1) % COMPUTER_USE_WAKE_LIMIT;\n const state = this.state();\n for (const listener of this.listeners) listener(state);\n this.directEvents.publish(computerUseChannelType, this.sessionId, 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 if (\n !this.desktop?.available ||\n !(this.desktop.authorizeActivation?.(request.headers) ?? this.desktop.authorize(request.headers))\n )\n return jsonError('Not found.', 404);\n if (this.desktop.enabled === false) return jsonError('Enable computer use in global Desktop settings first.', 409);\n // Caller stamps are admitted by the host only after native proof or sealed paired authentication.\n const stamped = poApiCallerFrom(request.headers);\n const caller = stamped?.locality === 'remote' ? stamped : ({ locality: 'local', stepUp: 'not-required' } as const);\n if (this.phase !== 'inactive' && this.phase !== 'failed') return jsonError('Computer use is already busy.', 409);\n const input = await body(request);\n if (input.confirmed !== true) return jsonError('Approve computer control in the in-app dialog first.', 400);\n const target = record(input.target);\n const durationMs = input.durationMs;\n const desktopTarget = target?.scope === 'desktop' && Object.keys(target).length === 1;\n if (\n target === undefined ||\n (!desktopTarget && (typeof target.windowId !== 'string' || typeof target.bundleId !== 'string'))\n )\n return jsonError('An explicit application window or whole-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 try {\n this.desktop.claim(request.headers);\n await this.beforeActivate?.();\n } catch (error) {\n return jsonError(error instanceof Error ? error.message : String(error), 409);\n }\n if (this.closed || !this.desktop.available || (this.phase !== 'inactive' && this.phase !== 'failed')) {\n return jsonError('Computer use is unavailable or already busy.', 409);\n }\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 confirmedAt: createdAt,\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 performAction(action: ComputerUseAction, requestSignal?: AbortSignal): Promise<Response> {\n if (this.resolvingInput) return jsonError('Another computer-use request is live.', 409);\n if (action.kind !== 'set_value' || !hasInputTemplate(action.value))\n return this.enqueue('act', action, requestSignal);\n this.resolvingInput = true;\n try {\n if (this.phase !== 'active' || this.pending || !this.grantId) throw new Error();\n const parts = parseInputTemplate(action.value);\n const profile = this.profileRuntime?.();\n if (!profile) throw new Error();\n const snapshot = profile.readSelection();\n const generation = snapshot.generation;\n const grantId = this.grantId;\n const target = this.nativeTarget;\n const usesSecret = parts.some((part) => part.kind === 'secret');\n if (usesSecret && (!target || target.scope === 'desktop' || typeof target.bundleId !== 'string'))\n throw new Error();\n const controller = new AbortController();\n this.inputController = controller;\n const signal = AbortSignal.any([snapshot.signal, controller.signal, ...(requestSignal ? [requestSignal] : [])]);\n // ponytail: resolved secrets seal observations for this session. A future native redaction boundary may safely reopen them.\n const value = await renderInputTemplate(parts, {\n readEnv: (name) => (snapshot.env && Object.hasOwn(snapshot.env, name) ? snapshot.env[name] : undefined),\n resolveSecret: (name) =>\n profile.resolveInputSecret(name, { surface: 'computer', target: target!.bundleId as string, signal }),\n onResolved: () => {\n this.sensitiveInput = true;\n },\n signal,\n });\n signal.throwIfAborted();\n if (\n this.closed ||\n this.phase !== 'active' ||\n this.grantId !== grantId ||\n this.nativeTarget !== target ||\n this.profileRuntime?.() !== profile ||\n profile.readSelection().generation !== generation\n )\n throw new Error();\n this.resolvingInput = false;\n return await this.enqueue(\n 'act',\n { ...action, value, ...(usesSecret ? { sensitiveBundleId: target!.bundleId } : {}) },\n signal,\n );\n } catch {\n return jsonError('Computer input template failed.', 400);\n } finally {\n this.inputController = undefined;\n this.resolvingInput = false;\n }\n }\n\n private async enqueue(\n operation: ComputerUseBrokerRequest['operation'],\n payload?: unknown,\n signal?: AbortSignal,\n ): Promise<Response> {\n if (this.resolvingInput) return jsonError('Another computer-use request is live.', 409);\n if (operation === 'observe' && this.sensitiveInput)\n return jsonError('Observations are sealed after sensitive input.', 409);\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 const value = await completion;\n return Response.json(this.sensitiveInput ? { applied: true } : value);\n } catch (error) {\n return jsonError(\n this.sensitiveInput\n ? 'Sensitive computer input failed.'\n : error instanceof Error\n ? error.message\n : String(error),\n 502,\n );\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 url = new URL(request.url);\n const path = url.pathname;\n if (request.method === 'GET' && path === routes.artifact.path) {\n if (\n !(this.desktop?.authorizeRecording?.(request.headers) ?? this.desktop?.authorize(request.headers)) ||\n !this.desktop?.fetchRecording\n )\n return jsonError('Not found.', 404);\n const artifactId = url.searchParams.get('artifactId') ?? '';\n const offsetText = url.searchParams.get('offset') ?? '';\n const offset = Number(offsetText);\n if (!/^[0-9]+$/u.test(offsetText) || !Number.isSafeInteger(offset) || offset < 0 || offset > 128 * 1024 * 1024)\n return jsonError('Invalid recording offset.', 400);\n return this.desktop.fetchRecording(artifactId, `bytes=${offset}-${offset + 1024 * 1024 - 1}`);\n }\n if (path === routes.activate.path && request.method === 'GET') {\n if (\n !this.desktop?.authorizePending?.(request.headers) &&\n !(this.desktop?.authorizeRecording?.(request.headers) ?? this.desktop?.authorize(request.headers))\n )\n return jsonError('Not found.', 404);\n return Response.json(this.state());\n }\n if (path === routes.activate.path && request.method === 'DELETE') {\n if (!this.desktop?.authorizePending?.(request.headers)) return jsonError('Not found.', 404);\n if (this.phase !== 'awaiting_confirmation' && this.phase !== 'activating')\n return jsonError('No activation is pending.', 409);\n this.phase = 'stopping';\n this.rejectPending('The activation was cancelled.');\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n if (request.method === 'POST' && path === routes.activate.path) 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 === routes.agentState.path || path === routes.hubState.path))\n return Response.json(this.state());\n if (request.method === 'POST' && path === routes.agentObserve.path)\n return this.enqueue('observe', undefined, request.signal);\n if (request.method === 'POST' && path === routes.agentAction.path) {\n const action = await body(request);\n if (!semanticAction(action)) return jsonError('A valid semantic action is required.', 400);\n return this.performAction(action as unknown as ComputerUseAction, request.signal);\n }\n if (request.method === 'POST' && path === routes.agentStop.path) {\n this.inputController?.abort();\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 === routes.hubActivation.path) {\n if (this.activation?.confirmedAt === undefined || this.phase !== 'awaiting_confirmation')\n return Response.json(null);\n this.phase = 'activating';\n this.changed();\n return Response.json(this.activation);\n }\n if (request.method === 'GET' && path === routes.hubAuthorization.path)\n return Response.json(this.grantId === undefined ? null : { grantId: this.grantId, expiresAt: this.expiresAt });\n if (request.method === 'GET' && path === routes.hubNext.path) return Response.json(this.pending?.request ?? null);\n if (request.method === 'POST' && path === routes.hubComplete.path) {\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 if (typeof input.error === 'string') {\n this.phase = 'stopping';\n pending.reject(new Error(input.error));\n } else pending.resolve(input.result);\n this.changed();\n return Response.json(this.state());\n }\n if (request.method === 'POST' && path === routes.hubStop.path) {\n this.inputController?.abort();\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 (\n typeof host?.grantId !== 'string' ||\n !Number.isFinite(host.expiresAt) ||\n (host.expiresAt as number) <= Date.now()\n )\n return jsonError('Desktop did not issue a complete grant.', 502);\n const selectedTarget = record(host.target);\n this.nativeTarget = selectedTarget === undefined ? undefined : Object.freeze({ ...selectedTarget });\n if (this.activation !== undefined && selectedTarget !== undefined)\n this.activation = Object.freeze({ ...this.activation, target: Object.freeze({ ...selectedTarget }) });\n this.grantId = host.grantId;\n this.expiresAt = host.expiresAt as number;\n this.actionSequence = 0;\n this.phase = 'active';\n clearTimeout(this.expiryTimer);\n this.expiryTimer = setTimeout(\n () => {\n if (this.closed || this.phase !== 'active') return;\n this.phase = 'stopping';\n this.inputController?.abort();\n this.rejectPending('The computer-use grant expired.');\n this.changed();\n },\n Math.max(0, this.expiresAt - Date.now()),\n );\n this.expiryTimer.unref?.();\n }\n } else {\n clearTimeout(this.expiryTimer);\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.nativeTarget = undefined;\n this.artifact = artifactView(input.artifact) ?? this.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 if (this.closed) return;\n this.closed = true;\n this.inputController?.abort();\n clearTimeout(this.expiryTimer);\n this.unsubscribeDesktop?.();\n this.listeners.clear();\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: PoApi = {\n basePath: API_BASE_PATH,\n start(context: PoApiContext): PoApiHandler {\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 desktop: context.computerUse,\n });\n },\n};\n","import { spawn } from 'node:child_process';\nimport { realpath } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport type {\n ComputerScriptExecutionOptions,\n ComputerScriptExecutionResult,\n ComputerScriptRunnerOptions,\n} from '../../types/computerScript';\nimport type {\n ComputerUseAction,\n ComputerUseObservation,\n ComputerUseObservationOptions,\n ComputerUseSessionClient,\n} from '../../types/computerUse';\nimport { COMPUTER_SCRIPT_WORKER_SOURCE } from '../computerScriptWorker';\nimport { observationOptions } from '../computerUseApi';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_OUTPUT_BYTES = 256 * 1024;\nconst MAX_IMAGE_BYTES = 6 * 1024 * 1024;\nconst MAX_PENDING_OPERATIONS = 64;\n\nexport class ComputerScriptExecutionError extends Error {\n constructor(\n message: string,\n readonly completedActions: number,\n readonly outcomeUncertain: boolean,\n ) {\n super(message);\n this.name = 'ComputerScriptExecutionError';\n }\n}\n\ninterface WorkerMessage {\n readonly type?: unknown;\n readonly id?: unknown;\n readonly operation?: unknown;\n readonly payload?: unknown;\n readonly level?: unknown;\n readonly message?: unknown;\n readonly resultJson?: unknown;\n readonly error?: unknown;\n}\n\nexport class ComputerScriptRunner {\n private readonly client: ComputerUseSessionClient;\n private readonly allowedScriptPaths: readonly string[];\n private readonly scriptRoot?: string;\n private readonly timeoutMs: number;\n private readonly maxOutputBytes: number;\n\n constructor(options: ComputerScriptRunnerOptions) {\n this.client = options.client;\n this.allowedScriptPaths = options.allowedScriptPaths;\n this.scriptRoot = options.scriptRoot;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;\n }\n\n async execute(\n scriptPath: string,\n input: unknown,\n signal?: AbortSignal,\n options: ComputerScriptExecutionOptions = {},\n cwd?: string,\n ): Promise<ComputerScriptExecutionResult> {\n signal?.throwIfAborted();\n const resolvedPath = await realpath(path.resolve(this.scriptRoot ?? cwd ?? process.cwd(), scriptPath));\n const allowedPaths = await Promise.all(\n this.allowedScriptPaths.map(async (candidate) => realpath(candidate).catch(() => '')),\n );\n const trusted = options.trusted === true;\n if ((trusted || this.scriptRoot === undefined) && !allowedPaths.includes(resolvedPath)) {\n throw new Error('Computer script path is not explicitly allowed.');\n }\n if (!/\\.(ts|js|mjs)$/u.test(resolvedPath))\n throw new Error('Computer scripts must be JavaScript or erasable TypeScript files.');\n const root = await realpath(this.scriptRoot ?? path.dirname(resolvedPath));\n const relative = path.relative(root, resolvedPath);\n if (!trusted && (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) {\n throw new Error('Computer script escapes the admitted script root.');\n }\n const serializedInput = JSON.stringify(input);\n if (serializedInput === undefined) throw new Error('Computer script input must be JSON serializable.');\n if (Buffer.byteLength(serializedInput) > this.maxOutputBytes)\n throw new Error('Computer script input exceeds the size limit.');\n const quickjsPath = trusted ? undefined : createRequire(import.meta.url).resolve('quickjs-emscripten');\n signal?.throwIfAborted();\n const started = performance.now();\n\n return new Promise((resolve, reject) => {\n const child = spawn(process.execPath, ['--input-type=module', '--eval', COMPUTER_SCRIPT_WORKER_SOURCE], {\n stdio: ['ignore', 'pipe', 'pipe', 'ipc'],\n // Preserve Electron's Node mode, but no host credentials, for restricted workers.\n env: trusted ? process.env : { ELECTRON_RUN_AS_NODE: '1' },\n });\n const controller = new AbortController();\n const logs: string[] = [];\n let outputBytes = 0;\n let completedActions = 0;\n let observations = 0;\n let actionInFlight = false;\n let settled = false;\n let completing = false;\n let outstanding = 0;\n let operation: Promise<void> = Promise.resolve();\n const finish = (error?: Error, value?: ComputerScriptExecutionResult): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n controller.abort();\n child.kill('SIGTERM');\n const killTimer = setTimeout(() => child.kill('SIGKILL'), 250);\n killTimer.unref();\n if (error) reject(new ComputerScriptExecutionError(error.message, completedActions, actionInFlight));\n else resolve(value!);\n };\n const addOutput = (value: string): boolean => {\n outputBytes += Buffer.byteLength(value);\n if (outputBytes <= this.maxOutputBytes) return true;\n finish(new Error('Computer script output exceeded the size limit.'));\n return false;\n };\n const send = (value: object): void => {\n if (settled || !child.connected) return;\n child.send(value, (error) => {\n if (error && !settled) finish(error);\n });\n };\n const onAbort = (): void => finish(new Error('Computer script execution was cancelled.'));\n const timeout = setTimeout(() => finish(new Error('Computer script execution timed out.')), this.timeoutMs);\n timeout.unref();\n signal?.addEventListener('abort', onAbort, { once: true });\n if (signal?.aborted) return onAbort();\n child.stdout?.on('data', (chunk: Buffer) => addOutput(chunk.toString('utf8')));\n child.stderr?.on('data', (chunk: Buffer) => addOutput(chunk.toString('utf8')));\n child.on('error', (error) => finish(error));\n child.on('exit', (code, exitSignal) => {\n if (!settled)\n finish(new Error(`Computer script worker exited before completion (${exitSignal ?? code ?? 'unknown'}).`));\n });\n\n const observe = async (options: ComputerUseObservationOptions): Promise<ComputerUseObservation> => {\n const includeScreenshot = options.includeScreenshot === true;\n const value = await this.client.observe(controller.signal, { ...options, includeScreenshot });\n observations += 1;\n const { screenshot, ...semantic } = value;\n if (Buffer.byteLength(JSON.stringify(semantic)) > this.maxOutputBytes)\n throw new Error('Computer observation exceeds the size limit.');\n if (includeScreenshot && screenshot) {\n if (screenshot.mimeType !== 'image/png' || screenshot.data.length > Math.ceil(MAX_IMAGE_BYTES / 3) * 4) {\n throw new Error('Computer screenshot exceeds the image limit.');\n }\n return { ...semantic, screenshot };\n }\n return semantic;\n };\n\n child.on('message', (raw: WorkerMessage) => {\n if (settled) return;\n if (!raw || typeof raw !== 'object' || Buffer.byteLength(JSON.stringify(raw)) > this.maxOutputBytes + 4096) {\n finish(new Error('Computer worker message exceeds the size limit.'));\n return;\n }\n if (raw.type === 'log' && typeof raw.message === 'string') {\n const line = `[${String(raw.level)}] ${raw.message}`;\n if (addOutput(line)) logs.push(line);\n return;\n }\n if (raw.type === 'program') {\n if (\n completing ||\n typeof raw.id !== 'string' ||\n raw.id.length > 128 ||\n (raw.operation !== 'observe' && raw.operation !== 'act') ||\n outstanding >= MAX_PENDING_OPERATIONS\n ) {\n finish(new Error('Invalid or excessive computer program operations.'));\n return;\n }\n outstanding += 1;\n operation = operation\n .then(async () => {\n if (settled || controller.signal.aborted) return;\n try {\n let value: unknown;\n if (raw.operation === 'observe') {\n value = await observe(observationOptions(raw.payload));\n } else {\n actionInFlight = true;\n value = await this.client.act(raw.payload as ComputerUseAction, controller.signal);\n completedActions += 1;\n actionInFlight = false;\n }\n send({ type: 'response', id: raw.id, value });\n } catch (error) {\n // An action can have taken effect before its transport failed. Never run the remaining chain.\n if (actionInFlight) finish(error instanceof Error ? error : new Error(String(error)));\n else\n send({ type: 'response', id: raw.id, error: error instanceof Error ? error.message : String(error) });\n } finally {\n outstanding -= 1;\n }\n })\n .catch((error: unknown) => finish(error instanceof Error ? error : new Error(String(error))));\n return;\n }\n if (raw.type === 'failed' && typeof raw.error === 'string') {\n finish(new Error(raw.error));\n return;\n }\n if (raw.type === 'complete') {\n if (completing) {\n finish(new Error('Computer worker completed twice.'));\n return;\n }\n completing = true;\n operation = operation\n .then(async () => {\n if (settled) return;\n const resultJson = raw.resultJson;\n if (resultJson !== undefined && typeof resultJson !== 'string')\n throw new Error('Computer script returned an invalid result.');\n if (typeof resultJson === 'string' && !addOutput(resultJson)) return;\n const observation = await observe({ includeScreenshot: options.includeScreenshot === true });\n if (settled || !addOutput(JSON.stringify({ ...observation, screenshot: undefined }))) return;\n finish(undefined, {\n ...(typeof resultJson === 'string' ? { result: JSON.parse(resultJson) as unknown } : {}),\n observation,\n logs,\n metrics: {\n actions: completedActions,\n observations,\n durationMs: Math.round(performance.now() - started),\n outputBytes,\n },\n });\n })\n .catch((error: unknown) => finish(error instanceof Error ? error : new Error(String(error))));\n }\n });\n send({\n type: 'start',\n scriptPath: resolvedPath,\n scriptRoot: root,\n input: JSON.parse(serializedInput) as unknown,\n trusted,\n quickjsPath,\n timeoutMs: this.timeoutMs,\n maxOutputBytes: this.maxOutputBytes,\n });\n });\n }\n}\n","import type { ComputerUseExtensionResult, ComputerUseExtensionService } from '../../types/extension';\nimport type { ComputerUseSessionClient } from '../sessionApiClient';\n\nexport class DefaultComputerUseExtensionService implements ComputerUseExtensionService {\n public constructor(private readonly client?: ComputerUseSessionClient) {}\n\n public async execute(): Promise<ComputerUseExtensionResult> {\n if (this.client === undefined) return { message: 'Computer use requires a Po Desktop session.', level: 'error' };\n const state = await this.client.state();\n return { message: `Computer use is ${state.phase.replaceAll('_', ' ')}.`, level: 'info' };\n }\n}\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import { spawn } from "node:child_process";
4
4
  import { realpath } from "node:fs/promises";
5
5
  import { randomUUID } from "node:crypto";
6
+ import { hasInputTemplate, parseInputTemplate, renderInputTemplate } from "@agimon-ai/po-core/inputTemplate";
6
7
  import { poApiCallerFrom } from "@agimon-ai/po-core/packageApi";
7
8
  //#region src/constants/computerUse.ts
8
9
  const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]
@@ -456,6 +457,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
456
457
  closed = false;
457
458
  desktop;
458
459
  beforeActivate;
460
+ profileRuntime;
461
+ nativeTarget;
462
+ resolvingInput = false;
463
+ inputController;
464
+ sensitiveInput = false;
459
465
  listeners = /* @__PURE__ */ new Set();
460
466
  unsubscribeDesktop;
461
467
  static DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
@@ -467,7 +473,9 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
467
473
  this.requestTimeoutMs = options.requestTimeoutMs ?? ComputerUseRequestBroker.DEFAULT_REQUEST_TIMEOUT_MS;
468
474
  this.desktop = options.desktop;
469
475
  this.beforeActivate = options.beforeActivate;
476
+ this.profileRuntime = options.profileRuntime;
470
477
  this.unsubscribeDesktop = options.desktop?.subscribe(() => {
478
+ this.inputController?.abort();
471
479
  clearTimeout(this.expiryTimer);
472
480
  if (!options.desktop?.available) {
473
481
  this.rejectPending("Desktop disconnected.");
@@ -525,10 +533,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
525
533
  act: async (action, signal) => {
526
534
  requireDesktop();
527
535
  if (!semanticAction(action)) throw new Error("A valid semantic action is required.");
528
- return result(await this.enqueue("act", action, signal));
536
+ return result(await this.performAction(action, signal));
529
537
  },
530
538
  stop: async (signal) => {
531
539
  signal?.throwIfAborted();
540
+ this.inputController?.abort();
532
541
  if (this.phase !== "inactive" && this.phase !== "failed") {
533
542
  this.phase = "stopping";
534
543
  this.rejectPending("Computer use was stopped.");
@@ -601,7 +610,58 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
601
610
  }
602
611
  this.rejectPending(message);
603
612
  }
613
+ async performAction(action, requestSignal) {
614
+ if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
615
+ if (action.kind !== "set_value" || !hasInputTemplate(action.value)) return this.enqueue("act", action, requestSignal);
616
+ this.resolvingInput = true;
617
+ try {
618
+ if (this.phase !== "active" || this.pending || !this.grantId) throw new Error();
619
+ const parts = parseInputTemplate(action.value);
620
+ const profile = this.profileRuntime?.();
621
+ if (!profile) throw new Error();
622
+ const snapshot = profile.readSelection();
623
+ const generation = snapshot.generation;
624
+ const grantId = this.grantId;
625
+ const target = this.nativeTarget;
626
+ const usesSecret = parts.some((part) => part.kind === "secret");
627
+ if (usesSecret && (!target || target.scope === "desktop" || typeof target.bundleId !== "string")) throw new Error();
628
+ const controller = new AbortController();
629
+ this.inputController = controller;
630
+ const signal = AbortSignal.any([
631
+ snapshot.signal,
632
+ controller.signal,
633
+ ...requestSignal ? [requestSignal] : []
634
+ ]);
635
+ const value = await renderInputTemplate(parts, {
636
+ readEnv: (name) => snapshot.env && Object.hasOwn(snapshot.env, name) ? snapshot.env[name] : void 0,
637
+ resolveSecret: (name) => profile.resolveInputSecret(name, {
638
+ surface: "computer",
639
+ target: target.bundleId,
640
+ signal
641
+ }),
642
+ onResolved: () => {
643
+ this.sensitiveInput = true;
644
+ },
645
+ signal
646
+ });
647
+ signal.throwIfAborted();
648
+ if (this.closed || this.phase !== "active" || this.grantId !== grantId || this.nativeTarget !== target || this.profileRuntime?.() !== profile || profile.readSelection().generation !== generation) throw new Error();
649
+ this.resolvingInput = false;
650
+ return await this.enqueue("act", {
651
+ ...action,
652
+ value,
653
+ ...usesSecret ? { sensitiveBundleId: target.bundleId } : {}
654
+ }, signal);
655
+ } catch {
656
+ return jsonError("Computer input template failed.", 400);
657
+ } finally {
658
+ this.inputController = void 0;
659
+ this.resolvingInput = false;
660
+ }
661
+ }
604
662
  async enqueue(operation, payload, signal) {
663
+ if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
664
+ if (operation === "observe" && this.sensitiveInput) return jsonError("Observations are sealed after sensitive input.", 409);
605
665
  if (this.phase !== "active" || this.grantId === void 0) return jsonError("Computer use is not active.", 409);
606
666
  if (this.pending !== void 0) return jsonError("Another computer-use request is live.", 409);
607
667
  if (signal?.aborted === true) return jsonError("The computer-use request was cancelled.", 499);
@@ -630,9 +690,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
630
690
  });
631
691
  this.changed();
632
692
  try {
633
- return Response.json(await completion);
693
+ const value = await completion;
694
+ return Response.json(this.sensitiveInput ? { applied: true } : value);
634
695
  } catch (error) {
635
- return jsonError(error instanceof Error ? error.message : String(error), 502);
696
+ return jsonError(this.sensitiveInput ? "Sensitive computer input failed." : error instanceof Error ? error.message : String(error), 502);
636
697
  }
637
698
  }
638
699
  async fetch(request) {
@@ -668,9 +729,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
668
729
  if (request.method === "POST" && path === routes.agentAction.path) {
669
730
  const action = await body(request);
670
731
  if (!semanticAction(action)) return jsonError("A valid semantic action is required.", 400);
671
- return this.enqueue("act", action, request.signal);
732
+ return this.performAction(action, request.signal);
672
733
  }
673
734
  if (request.method === "POST" && path === routes.agentStop.path) {
735
+ this.inputController?.abort();
674
736
  if (this.phase !== "active") return jsonError("Computer use is not active.", 409);
675
737
  this.phase = "stopping";
676
738
  this.rejectPending("The computer-use request was stopped.");
@@ -703,6 +765,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
703
765
  return Response.json(this.state());
704
766
  }
705
767
  if (request.method === "POST" && path === routes.hubStop.path) {
768
+ this.inputController?.abort();
706
769
  const input = await body(request);
707
770
  if (this.phase === "activating") {
708
771
  if (typeof input.error === "string") {
@@ -716,6 +779,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
716
779
  const host = record(input.host);
717
780
  if (typeof host?.grantId !== "string" || !Number.isFinite(host.expiresAt) || host.expiresAt <= Date.now()) return jsonError("Desktop did not issue a complete grant.", 502);
718
781
  const selectedTarget = record(host.target);
782
+ this.nativeTarget = selectedTarget === void 0 ? void 0 : Object.freeze({ ...selectedTarget });
719
783
  if (this.activation !== void 0 && selectedTarget !== void 0) this.activation = Object.freeze({
720
784
  ...this.activation,
721
785
  target: Object.freeze({ ...selectedTarget })
@@ -728,6 +792,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
728
792
  this.expiryTimer = setTimeout(() => {
729
793
  if (this.closed || this.phase !== "active") return;
730
794
  this.phase = "stopping";
795
+ this.inputController?.abort();
731
796
  this.rejectPending("The computer-use grant expired.");
732
797
  this.changed();
733
798
  }, Math.max(0, this.expiresAt - Date.now()));
@@ -740,6 +805,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
740
805
  this.grantId = void 0;
741
806
  this.expiresAt = void 0;
742
807
  this.activation = void 0;
808
+ this.nativeTarget = void 0;
743
809
  this.artifact = artifactView(input.artifact) ?? this.artifact;
744
810
  }
745
811
  this.changed();
@@ -750,6 +816,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
750
816
  close() {
751
817
  if (this.closed) return;
752
818
  this.closed = true;
819
+ this.inputController?.abort();
753
820
  clearTimeout(this.expiryTimer);
754
821
  this.unsubscribeDesktop?.();
755
822
  this.listeners.clear();
@@ -996,4 +1063,4 @@ var DefaultComputerUseExtensionService = class {
996
1063
  //#endregion
997
1064
  export { COMPUTER_USE_GUIDANCE as _, routes as a, COMPUTER_USE_TOOL_NAMES as b, COMPUTER_USE_MODE_ID as c, computerUseChannelType as d, COMMAND_DESCRIPTION as f, COMPUTER_USE_CODEMODE_GUIDANCE as g, COMPUTER_USE_ARTIFACT_DIRECTORY as h, createComputerUseApi as i, COMPUTER_USE_ROUTES as l, COMPUTER_USE_ARTIFACTS_SERVICE as m, ComputerScriptExecutionError as n, isDesktopPermission as o, COMMAND_NAME as p, ComputerScriptRunner as r, API_BASE_PATH as s, DefaultComputerUseExtensionService as t, COMPUTER_USE_STATUS_KEY as u, COMPUTER_USE_RECORDING_CHUNK_BYTES as v, COMPUTER_USE_RECORDING_MAX_BYTES as y };
998
1065
 
999
- //# sourceMappingURL=extensionService-DGTnZr5E.mjs.map
1066
+ //# sourceMappingURL=extensionService-D8bAAsIN.mjs.map