@cydm/pie 2.6.12 → 2.7.1

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 (35) hide show
  1. package/README.md +85 -3
  2. package/dist/builtin/extensions/ask-user/index.js +3 -3
  3. package/dist/builtin/extensions/plan-mode/index.js +130 -21
  4. package/dist/builtin/extensions/subagent/index.js +15 -6
  5. package/dist/builtin/extensions/todo/index.js +3 -3
  6. package/dist/builtin/skills/computer-use-axi/SKILL.md +172 -0
  7. package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-broker.js} +2122 -708
  8. package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
  9. package/dist/builtin/skills/computer-use-axi/computer-use-axi-runtime.js +728 -0
  10. package/dist/builtin/skills/computer-use-axi/package.json +11 -0
  11. package/dist/chunks/{chunk-PPEWRUMQ.js → chunk-M44CWVDZ.js} +1249 -752
  12. package/dist/chunks/{chunk-HHNOENEH.js → chunk-NJFPBU36.js} +14 -1
  13. package/dist/chunks/{chunk-AAEBH6KX.js → chunk-W74NRSRV.js} +239 -231
  14. package/dist/chunks/{chunk-7B4IIBVS.js → chunk-XUROMYTT.js} +1747 -14
  15. package/dist/chunks/{src-OWQI5M6W.js → src-C4KA4G75.js} +2 -2
  16. package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-A5ZELKNG.js} +1 -1
  17. package/dist/cli.js +863 -305
  18. package/models.schema.json +57 -0
  19. package/package.json +3 -3
  20. package/dist/builtin/extensions/computer-use/package.json +0 -14
  21. package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
  22. package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
  23. package/dist/chunks/chunk-5353DEEC.js +0 -130
  24. package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
  25. package/dist/code-intel-worker.cjs +0 -211227
  26. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
  27. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
  28. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
  29. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
  30. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
  31. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
  32. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
  33. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
  34. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
  35. /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
@@ -1,15 +1,40 @@
1
+ #!/usr/bin/env node
1
2
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
- import {
3
- getConfigDir
4
- } from "../../../chunks/chunk-5353DEEC.js";
5
- import {
6
- Type
7
- } from "../../../chunks/chunk-XXGYUYXI.js";
8
- import {
9
- __commonJS,
10
- __require,
11
- __toESM
12
- } from "../../../chunks/chunk-LZQXQOPJ.js";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
10
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
11
+ }) : x)(function(x) {
12
+ if (typeof require !== "undefined") return require.apply(this, arguments);
13
+ throw Error('Dynamic require of "' + x + '" is not supported');
14
+ });
15
+ var __commonJS = (cb, mod) => function __require2() {
16
+ try {
17
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18
+ } catch (e) {
19
+ throw mod = 0, e;
20
+ }
21
+ };
22
+ var __copyProps = (to, from, except, desc) => {
23
+ if (from && typeof from === "object" || typeof from === "function") {
24
+ for (let key of __getOwnPropNames(from))
25
+ if (!__hasOwnProp.call(to, key) && key !== except)
26
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
27
+ }
28
+ return to;
29
+ };
30
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
31
+ // If the importer is in node compatibility mode or this is not an ESM
32
+ // file that has been converted to a CommonJS file using a Babel-
33
+ // compatible transform (i.e. "__esModule" has not been set), then set
34
+ // "default" to the CommonJS "module.exports" for node compatibility.
35
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
36
+ mod
37
+ ));
13
38
 
14
39
  // ../../node_modules/ws/lib/constants.js
15
40
  var require_constants = __commonJS({
@@ -2248,9 +2273,9 @@ var require_websocket = __commonJS({
2248
2273
  var EventEmitter = __require("events");
2249
2274
  var https = __require("https");
2250
2275
  var http = __require("http");
2251
- var net3 = __require("net");
2276
+ var net4 = __require("net");
2252
2277
  var tls = __require("tls");
2253
- var { randomBytes, createHash } = __require("crypto");
2278
+ var { randomBytes, createHash: createHash4 } = __require("crypto");
2254
2279
  var { Duplex, Readable } = __require("stream");
2255
2280
  var { URL: URL2 } = __require("url");
2256
2281
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -2931,7 +2956,7 @@ var require_websocket = __commonJS({
2931
2956
  abortHandshake(websocket, socket, "Invalid Upgrade header");
2932
2957
  return;
2933
2958
  }
2934
- const digest = createHash("sha1").update(key + GUID).digest("base64");
2959
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
2935
2960
  if (res.headers["sec-websocket-accept"] !== digest) {
2936
2961
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2937
2962
  return;
@@ -3005,12 +3030,12 @@ var require_websocket = __commonJS({
3005
3030
  }
3006
3031
  function netConnect(options) {
3007
3032
  options.path = options.socketPath;
3008
- return net3.connect(options);
3033
+ return net4.connect(options);
3009
3034
  }
3010
3035
  function tlsConnect(options) {
3011
3036
  options.path = void 0;
3012
3037
  if (!options.servername && options.servername !== "") {
3013
- options.servername = net3.isIP(options.host) ? "" : options.host;
3038
+ options.servername = net4.isIP(options.host) ? "" : options.host;
3014
3039
  }
3015
3040
  return tls.connect(options);
3016
3041
  }
@@ -3300,7 +3325,7 @@ var require_websocket_server = __commonJS({
3300
3325
  var EventEmitter = __require("events");
3301
3326
  var http = __require("http");
3302
3327
  var { Duplex } = __require("stream");
3303
- var { createHash } = __require("crypto");
3328
+ var { createHash: createHash4 } = __require("crypto");
3304
3329
  var extension2 = require_extension();
3305
3330
  var PerMessageDeflate2 = require_permessage_deflate();
3306
3331
  var subprotocol2 = require_subprotocol();
@@ -3607,7 +3632,7 @@ var require_websocket_server = __commonJS({
3607
3632
  );
3608
3633
  }
3609
3634
  if (this._state > RUNNING) return abortHandshake(socket, 503);
3610
- const digest = createHash("sha1").update(key + GUID).digest("base64");
3635
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
3611
3636
  const headers = [
3612
3637
  "HTTP/1.1 101 Switching Protocols",
3613
3638
  "Upgrade: websocket",
@@ -3694,16 +3719,834 @@ var require_websocket_server = __commonJS({
3694
3719
  }
3695
3720
  });
3696
3721
 
3697
- // builtin/extensions/computer-use/src/bridge.ts
3722
+ // vendor/computer-use-axi/src/broker-server.ts
3723
+ import { createHash as createHash3, randomUUID as randomUUID8 } from "node:crypto";
3724
+ import { chmodSync as chmodSync2, lstatSync as lstatSync4, readFileSync as readFileSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
3725
+ import net3 from "node:net";
3726
+ import path14 from "node:path";
3727
+
3728
+ // vendor/computer-use-axi/src/artifact-store.ts
3729
+ import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
3730
+ import { closeSync, existsSync as existsSync2, lstatSync as lstatSync3, mkdirSync as mkdirSync4, openSync, readdirSync as readdirSync2, rmdirSync, unlinkSync as unlinkSync2, writeSync } from "node:fs";
3731
+ import path3 from "node:path";
3732
+
3733
+ // vendor/computer-use-axi/src/broker-protocol.ts
3734
+ import { createHash, randomUUID } from "node:crypto";
3735
+ import { chmodSync, lstatSync as lstatSync2, mkdirSync as mkdirSync3 } from "node:fs";
3736
+ import path2 from "node:path";
3737
+
3738
+ // vendor/computer-use-axi/src/persist.ts
3739
+ import { lstatSync, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "node:fs";
3740
+ import path from "node:path";
3741
+
3742
+ // src/config.ts
3743
+ import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
3744
+ import { homedir } from "os";
3745
+ import { dirname, join } from "path";
3746
+ import { fileURLToPath } from "url";
3747
+ var __filename = fileURLToPath(import.meta.url);
3748
+ var __dirname = dirname(__filename);
3749
+ var isBunRuntime = !!process.versions.bun;
3750
+ function getPackageDir() {
3751
+ const envDir = process.env.PIE_PACKAGE_DIR;
3752
+ if (envDir) {
3753
+ if (envDir === "~") return homedir();
3754
+ if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
3755
+ return envDir;
3756
+ }
3757
+ let dir = __dirname;
3758
+ while (dir !== dirname(dir)) {
3759
+ if (existsSync(join(dir, "package.json"))) {
3760
+ return dir;
3761
+ }
3762
+ dir = dirname(dir);
3763
+ }
3764
+ return __dirname;
3765
+ }
3766
+ function getPackageJsonPath() {
3767
+ return join(getPackageDir(), "package.json");
3768
+ }
3769
+ var pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
3770
+ var CONFIG_DIR_NAME = ".pie";
3771
+ var VERSION = pkg.version;
3772
+ var ENV_AGENT_DIR = "PIE_CODING_AGENT_DIR";
3773
+ function getConfigDir() {
3774
+ const envDir = process.env[ENV_AGENT_DIR];
3775
+ if (envDir) {
3776
+ if (envDir === "~") return homedir();
3777
+ if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
3778
+ return envDir;
3779
+ }
3780
+ return join(homedir(), CONFIG_DIR_NAME);
3781
+ }
3782
+
3783
+ // vendor/computer-use-axi/src/persist.ts
3784
+ function stateRootDir(env = process.env) {
3785
+ const override = env.PIE_COMPUTER_USE_STATE_DIR?.trim();
3786
+ if (override) return override;
3787
+ return path.join(getConfigDir(), "computer-use");
3788
+ }
3789
+ function statesDir(env = process.env) {
3790
+ return path.join(stateRootDir(env), "states");
3791
+ }
3792
+ function outputsDir(env = process.env) {
3793
+ return path.join(stateRootDir(env), "outputs");
3794
+ }
3795
+ function runtimeStatePath(env = process.env) {
3796
+ return path.join(stateRootDir(env), "runtime.json");
3797
+ }
3798
+ function brokerStateDir(env = process.env) {
3799
+ return path.join(stateRootDir(env), "broker");
3800
+ }
3801
+ function brokerManifestPath(env = process.env) {
3802
+ return path.join(brokerStateDir(env), "manifest.json");
3803
+ }
3804
+ function loadBrokerManifest(env = process.env) {
3805
+ const manifest = readJsonFile(brokerManifestPath(env));
3806
+ if (!manifest || typeof manifest.generation !== "string") return void 0;
3807
+ return {
3808
+ generation: manifest.generation,
3809
+ helperGeneration: typeof manifest.helperGeneration === "string" ? manifest.helperGeneration : "",
3810
+ stateIds: Array.isArray(manifest.stateIds) ? manifest.stateIds.filter((id) => typeof id === "string" && /^[A-Za-z0-9-]{1,128}$/.test(id)).slice(0, 256) : [],
3811
+ updatedAt: Number.isFinite(manifest.updatedAt) ? manifest.updatedAt : 0
3812
+ };
3813
+ }
3814
+ function saveBrokerManifest(manifest, env = process.env) {
3815
+ mkdirSync2(brokerStateDir(env), { recursive: true, mode: 448 });
3816
+ writeJsonAtomic(brokerManifestPath(env), { ...manifest, stateIds: manifest.stateIds.slice(0, 256) });
3817
+ }
3818
+ function brokerDrainMarkerPath(env = process.env) {
3819
+ return path.join(brokerStateDir(env), "draining.json");
3820
+ }
3821
+ function loadDrainMarker(env = process.env) {
3822
+ const marker = readJsonFile(brokerDrainMarkerPath(env));
3823
+ if (!marker || typeof marker !== "object" || !Number.isFinite(marker.pid)) return void 0;
3824
+ return {
3825
+ pid: Math.trunc(marker.pid),
3826
+ startedAt: Number.isFinite(marker.startedAt) ? marker.startedAt : 0,
3827
+ deadlineAt: Number.isFinite(marker.deadlineAt) ? marker.deadlineAt : 0
3828
+ };
3829
+ }
3830
+ function saveDrainMarker(marker, env = process.env) {
3831
+ mkdirSync2(brokerStateDir(env), { recursive: true, mode: 448 });
3832
+ writeJsonAtomic(brokerDrainMarkerPath(env), marker);
3833
+ }
3834
+ function clearDrainMarker(env = process.env) {
3835
+ try {
3836
+ const stats = lstatSync(brokerDrainMarkerPath(env));
3837
+ if (stats.isFile() && !stats.isSymbolicLink()) unlinkSync(brokerDrainMarkerPath(env));
3838
+ } catch {
3839
+ }
3840
+ }
3841
+ function cleanupLegacyBrokerCache(env = process.env) {
3842
+ let runtimeFile = false;
3843
+ let states = 0;
3844
+ let outputs2 = 0;
3845
+ const runtime = runtimeStatePath(env);
3846
+ try {
3847
+ const stats = lstatSync(runtime);
3848
+ if (stats.isFile() && !stats.isSymbolicLink()) {
3849
+ unlinkSync(runtime);
3850
+ runtimeFile = true;
3851
+ }
3852
+ } catch {
3853
+ }
3854
+ const statesDirPath = statesDir(env);
3855
+ try {
3856
+ for (const name of readdirSync(statesDirPath).slice(0, 512)) {
3857
+ if (!/^[A-Za-z0-9-]+\.json$/.test(name)) continue;
3858
+ const target = path.join(statesDirPath, name);
3859
+ try {
3860
+ const stats = lstatSync(target);
3861
+ if (!stats.isFile() || stats.isSymbolicLink()) continue;
3862
+ unlinkSync(target);
3863
+ states += 1;
3864
+ } catch {
3865
+ }
3866
+ }
3867
+ } catch {
3868
+ }
3869
+ const oldOutputs = outputsDir(env);
3870
+ try {
3871
+ for (const name of readdirSync(oldOutputs).slice(0, 512)) {
3872
+ if (!/^o\d+\.(txt|meta\.json)$/.test(name)) continue;
3873
+ const target = path.join(oldOutputs, name);
3874
+ try {
3875
+ const stats = lstatSync(target);
3876
+ if (!stats.isFile() || stats.isSymbolicLink()) continue;
3877
+ unlinkSync(target);
3878
+ outputs2 += 1;
3879
+ } catch {
3880
+ }
3881
+ }
3882
+ } catch {
3883
+ }
3884
+ return { runtimeFile, states, outputs: outputs2 };
3885
+ }
3886
+ function writeJsonAtomic(filePath, value) {
3887
+ mkdirSync2(path.dirname(filePath), { recursive: true });
3888
+ const temp = `${filePath}.${process.pid}.tmp`;
3889
+ writeFileSync(temp, JSON.stringify(value), "utf8");
3890
+ renameSync2(temp, filePath);
3891
+ }
3892
+ function readJsonFile(filePath) {
3893
+ try {
3894
+ return JSON.parse(readFileSync2(filePath, "utf8"));
3895
+ } catch {
3896
+ return void 0;
3897
+ }
3898
+ }
3899
+
3900
+ // src/runtime/computer-use-owner.ts
3901
+ var COMPUTER_USE_STANDALONE_OWNER = "standalone";
3902
+ var OWNER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:@-]{0,255}$/;
3903
+ function normalizeComputerUseOwner(value) {
3904
+ if (typeof value !== "string") return COMPUTER_USE_STANDALONE_OWNER;
3905
+ const trimmed = value.trim();
3906
+ if (!trimmed) return COMPUTER_USE_STANDALONE_OWNER;
3907
+ return OWNER_PATTERN.test(trimmed) ? trimmed : COMPUTER_USE_STANDALONE_OWNER;
3908
+ }
3909
+
3910
+ // vendor/computer-use-axi/src/broker-protocol.ts
3911
+ var BROKER_PROTOCOL_VERSION = 1;
3912
+ var BROKER_ENGINE_VERSION = 1;
3913
+ var BROKER_PACKAGE_VERSION = "0.5.1-pie.1";
3914
+ var BROKER_MAX_FRAME_BYTES = 4 * 1024 * 1024;
3915
+ var BROKER_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
3916
+ var BROKER_MAX_QUEUED_REQUESTS = 64;
3917
+ var BROKER_MAX_CONCURRENT_REQUESTS = 16;
3918
+ var BROKER_DEFAULT_REQUEST_BUDGET_MS = 12e4;
3919
+ var BROKER_MAX_REQUEST_BUDGET_MS = 15 * 6e4;
3920
+ var BROKER_IDLE_EXIT_MS = 30 * 6e4;
3921
+ var BROKER_DRAIN_MAX_MS = 3e4;
3922
+ var ENGINE_COMMANDS = [
3923
+ "find_roots",
3924
+ "observe_ui",
3925
+ "search_ui",
3926
+ "expand_ui",
3927
+ "inspect_ui",
3928
+ "read_text",
3929
+ "wait_for",
3930
+ "act_ui",
3931
+ "launch_browser",
3932
+ "navigate_browser",
3933
+ "evaluate_browser"
3934
+ ];
3935
+ var CONTROL_COMMANDS = ["status", "stop", "debug_restart_helper"];
3936
+ function isEngineCommand(value) {
3937
+ return ENGINE_COMMANDS.includes(value);
3938
+ }
3939
+ function isControlCommand(value) {
3940
+ return CONTROL_COMMANDS.includes(value);
3941
+ }
3942
+ function computeBuildIdentity() {
3943
+ const seed = `${BROKER_PROTOCOL_VERSION}:${BROKER_ENGINE_VERSION}:${BROKER_PACKAGE_VERSION}`;
3944
+ return {
3945
+ version: BROKER_PACKAGE_VERSION,
3946
+ identity: createHash("sha256").update(seed).digest("hex").slice(0, 16)
3947
+ };
3948
+ }
3949
+ var BROKER_BUILD = computeBuildIdentity();
3950
+ var BrokerProtocolError = class extends Error {
3951
+ constructor(code, message) {
3952
+ super(message);
3953
+ this.code = code;
3954
+ this.name = "BrokerProtocolError";
3955
+ }
3956
+ code;
3957
+ };
3958
+ function isRecord(value) {
3959
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3960
+ }
3961
+ function assertPlainRecord(value, label2) {
3962
+ if (!isRecord(value)) throw new BrokerProtocolError("invalid_frame", `${label2} must be an object.`);
3963
+ for (const key of Object.keys(value)) {
3964
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
3965
+ throw new BrokerProtocolError("invalid_frame", `${label2} contains a forbidden key '${key}'.`);
3966
+ }
3967
+ }
3968
+ }
3969
+ var REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
3970
+ var STATE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9-]{0,127}$/;
3971
+ var ROOT_REF_PATTERN = /^@r\d{1,6}$/;
3972
+ var ELEMENT_REF_PATTERN = /^@e\d{1,6}$/;
3973
+ var OUTPUT_REF_PATTERN = /^@o\d{1,9}$/;
3974
+ function boundedString(value, label2, maxBytes) {
3975
+ if (typeof value !== "string") throw new BrokerProtocolError("invalid_params", `${label2} must be a string.`);
3976
+ if (Buffer.byteLength(value, "utf8") > maxBytes) throw new BrokerProtocolError("invalid_params", `${label2} is too large.`);
3977
+ return value;
3978
+ }
3979
+ function boundedNumber(value, label2, min, max) {
3980
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new BrokerProtocolError("invalid_params", `${label2} must be a finite number.`);
3981
+ if (value < min || value > max) throw new BrokerProtocolError("invalid_params", `${label2} is out of range.`);
3982
+ return value;
3983
+ }
3984
+ function oneOf(value, label2, allowed) {
3985
+ if (typeof value !== "string" || !allowed.includes(value)) {
3986
+ throw new BrokerProtocolError("invalid_params", `${label2} must be one of ${allowed.join(", ")}.`);
3987
+ }
3988
+ return value;
3989
+ }
3990
+ function assertKeys(value, label2, allowed) {
3991
+ for (const key of Object.keys(value)) {
3992
+ if (!allowed.includes(key)) throw new BrokerProtocolError("invalid_params", `${label2} has unknown field '${key}'.`);
3993
+ }
3994
+ }
3995
+ function stateId(value, label2 = "stateId") {
3996
+ if (typeof value !== "string" || !STATE_ID_PATTERN.test(value)) {
3997
+ throw new BrokerProtocolError("invalid_params", `${label2} is not a valid state id.`);
3998
+ }
3999
+ return value;
4000
+ }
4001
+ function elementOrOutputRef(value, label2) {
4002
+ if (typeof value !== "string" || !ELEMENT_REF_PATTERN.test(value) && !OUTPUT_REF_PATTERN.test(value)) {
4003
+ throw new BrokerProtocolError("invalid_params", `${label2} must be an @e or @o ref.`);
4004
+ }
4005
+ return value;
4006
+ }
4007
+ function elementRef(value, label2) {
4008
+ if (typeof value !== "string" || !ELEMENT_REF_PATTERN.test(value)) {
4009
+ throw new BrokerProtocolError("invalid_params", `${label2} must be an @e ref.`);
4010
+ }
4011
+ return value;
4012
+ }
4013
+ function httpUrl(value, label2) {
4014
+ const url = boundedString(value, label2, 2048);
4015
+ if (!/^https?:\/\//i.test(url)) throw new BrokerProtocolError("invalid_params", `${label2} must be an absolute HTTP(S) URL.`);
4016
+ return url;
4017
+ }
4018
+ function validateCondition(value, label2) {
4019
+ assertPlainRecord(value, label2);
4020
+ assertKeys(value, label2, ["ref", "scopeRef", "text", "role", "value", "until", "timeoutMs"]);
4021
+ const condition = {};
4022
+ if (value.ref !== void 0) condition.ref = elementRef(value.ref, `${label2}.ref`);
4023
+ if (value.scopeRef !== void 0) condition.scopeRef = elementRef(value.scopeRef, `${label2}.scopeRef`);
4024
+ if (value.text !== void 0) condition.text = boundedString(value.text, `${label2}.text`, 8192);
4025
+ if (value.role !== void 0) condition.role = boundedString(value.role, `${label2}.role`, 256);
4026
+ if (value.value !== void 0) condition.value = boundedString(value.value, `${label2}.value`, 8192);
4027
+ if (value.until !== void 0) condition.until = oneOf(value.until, `${label2}.until`, ["present", "absent"]);
4028
+ if (value.timeoutMs !== void 0) condition.timeoutMs = boundedNumber(value.timeoutMs, `${label2}.timeoutMs`, 1, 6e4);
4029
+ return condition;
4030
+ }
4031
+ function validateAction(value, index) {
4032
+ const label2 = `actions[${index}]`;
4033
+ assertPlainRecord(value, label2);
4034
+ assertKeys(value, label2, ["action", "ref", "x", "y", "text", "keys", "scrollX", "scrollY", "path", "button", "clickCount"]);
4035
+ const action = {
4036
+ action: oneOf(value.action, `${label2}.action`, ["press", "click", "setText", "typeText", "keypress", "scroll", "drag", "moveMouse"])
4037
+ };
4038
+ if (value.ref !== void 0) action.ref = elementRef(value.ref, `${label2}.ref`);
4039
+ if (value.x !== void 0) action.x = boundedNumber(value.x, `${label2}.x`, -1e6, 1e6);
4040
+ if (value.y !== void 0) action.y = boundedNumber(value.y, `${label2}.y`, -1e6, 1e6);
4041
+ if (value.text !== void 0) action.text = boundedString(value.text, `${label2}.text`, 64 * 1024);
4042
+ if (value.keys !== void 0) {
4043
+ if (!Array.isArray(value.keys) || value.keys.length === 0 || value.keys.length > 32) {
4044
+ throw new BrokerProtocolError("invalid_params", `${label2}.keys must be a non-empty array of at most 32 keys.`);
4045
+ }
4046
+ action.keys = value.keys.map((key, keyIndex) => boundedString(key, `${label2}.keys[${keyIndex}]`, 64));
4047
+ }
4048
+ if (value.scrollX !== void 0) action.scrollX = boundedNumber(value.scrollX, `${label2}.scrollX`, -1e6, 1e6);
4049
+ if (value.scrollY !== void 0) action.scrollY = boundedNumber(value.scrollY, `${label2}.scrollY`, -1e6, 1e6);
4050
+ if (value.path !== void 0) {
4051
+ if (!Array.isArray(value.path) || value.path.length > 256) {
4052
+ throw new BrokerProtocolError("invalid_params", `${label2}.path must be an array of at most 256 points.`);
4053
+ }
4054
+ action.path = value.path.map((point, pointIndex) => {
4055
+ if (Array.isArray(point)) {
4056
+ if (point.length !== 2) throw new BrokerProtocolError("invalid_params", `${label2}.path[${pointIndex}] must be [x,y].`);
4057
+ return [boundedNumber(point[0], `${label2}.path[${pointIndex}][0]`, -1e6, 1e6), boundedNumber(point[1], `${label2}.path[${pointIndex}][1]`, -1e6, 1e6)];
4058
+ }
4059
+ assertPlainRecord(point, `${label2}.path[${pointIndex}]`);
4060
+ assertKeys(point, `${label2}.path[${pointIndex}]`, ["x", "y"]);
4061
+ return {
4062
+ x: boundedNumber(point.x, `${label2}.path[${pointIndex}].x`, -1e6, 1e6),
4063
+ y: boundedNumber(point.y, `${label2}.path[${pointIndex}].y`, -1e6, 1e6)
4064
+ };
4065
+ });
4066
+ }
4067
+ if (value.button !== void 0) action.button = oneOf(value.button, `${label2}.button`, ["left", "right", "middle"]);
4068
+ if (value.clickCount !== void 0) action.clickCount = Math.trunc(boundedNumber(value.clickCount, `${label2}.clickCount`, 1, 3));
4069
+ const hasRef = typeof action.ref === "string";
4070
+ const hasX = action.x !== void 0;
4071
+ const hasY = action.y !== void 0;
4072
+ if (hasX !== hasY) throw new BrokerProtocolError("invalid_params", `${label2} coordinates require both x and y.`);
4073
+ const hasPoint = hasX && hasY;
4074
+ if ((action.action === "click" || action.action === "moveMouse") && hasRef === hasPoint) {
4075
+ throw new BrokerProtocolError("invalid_params", `${label2}.${String(action.action)} requires exactly one target: ref or x/y coordinates.`);
4076
+ }
4077
+ if (action.action === "press" && !hasRef) throw new BrokerProtocolError("invalid_params", `${label2}.press requires an actionable ref.`);
4078
+ if (action.action === "keypress" && !Array.isArray(action.keys)) throw new BrokerProtocolError("invalid_params", `${label2}.keypress requires keys.`);
4079
+ if (action.action === "drag" && !Array.isArray(action.path)) throw new BrokerProtocolError("invalid_params", `${label2}.drag requires path.`);
4080
+ if (action.action === "scroll" && (action.scrollX ?? 0) === 0 && (action.scrollY ?? 0) === 0) {
4081
+ throw new BrokerProtocolError("invalid_params", `${label2}.scroll requires a non-zero scrollX or scrollY delta.`);
4082
+ }
4083
+ if ((action.action === "setText" || action.action === "typeText") && typeof action.text !== "string") {
4084
+ throw new BrokerProtocolError("invalid_params", `${label2}.${String(action.action)} requires text.`);
4085
+ }
4086
+ return action;
4087
+ }
4088
+ function validateCommandParams(command, raw) {
4089
+ if (command === "status" || command === "stop") {
4090
+ if (raw === void 0 || raw === null) return {};
4091
+ assertPlainRecord(raw, "params");
4092
+ assertKeys(raw, "params", []);
4093
+ return {};
4094
+ }
4095
+ if (command === "debug_restart_helper") {
4096
+ if (raw === void 0 || raw === null) return {};
4097
+ assertPlainRecord(raw, "params");
4098
+ assertKeys(raw, "params", []);
4099
+ return {};
4100
+ }
4101
+ assertPlainRecord(raw, "params");
4102
+ const params = raw;
4103
+ switch (command) {
4104
+ case "find_roots": {
4105
+ assertKeys(params, "params", ["text", "app", "bundleId", "pid", "kind"]);
4106
+ const out = {};
4107
+ if (params.text !== void 0) out.text = boundedString(params.text, "text", 512);
4108
+ if (params.app !== void 0) out.app = boundedString(params.app, "app", 512);
4109
+ if (params.bundleId !== void 0) out.bundleId = boundedString(params.bundleId, "bundleId", 512);
4110
+ if (params.pid !== void 0) out.pid = Math.trunc(boundedNumber(params.pid, "pid", 1, 2 ** 31 - 1));
4111
+ if (params.kind !== void 0) out.kind = oneOf(params.kind, "kind", ["window", "menu", "sheet", "popover", "dialog", "browser_page"]);
4112
+ return out;
4113
+ }
4114
+ case "observe_ui": {
4115
+ assertKeys(params, "params", ["root", "mode", "readText"]);
4116
+ const out = {};
4117
+ if (params.root !== void 0) {
4118
+ if (typeof params.root !== "string" || !ROOT_REF_PATTERN.test(params.root)) throw new BrokerProtocolError("invalid_params", "root must be an @r ref.");
4119
+ out.root = params.root;
4120
+ }
4121
+ if (params.mode !== void 0) out.mode = oneOf(params.mode, "mode", ["semantic", "visual", "fused"]);
4122
+ if (params.readText !== void 0) out.readText = oneOf(params.readText, "readText", ["auto", "always", "never"]);
4123
+ return out;
4124
+ }
4125
+ case "search_ui": {
4126
+ assertKeys(params, "params", ["stateId", "text", "role", "capability"]);
4127
+ const out = { stateId: stateId(params.stateId) };
4128
+ let matchers = 0;
4129
+ if (params.text !== void 0) {
4130
+ out.text = boundedString(params.text, "text", 512);
4131
+ matchers += 1;
4132
+ }
4133
+ if (params.role !== void 0) {
4134
+ out.role = boundedString(params.role, "role", 128);
4135
+ matchers += 1;
4136
+ }
4137
+ if (params.capability !== void 0) {
4138
+ out.capability = boundedString(params.capability, "capability", 128);
4139
+ matchers += 1;
4140
+ }
4141
+ if (matchers === 0) throw new BrokerProtocolError("invalid_params", "search_ui requires text, role, or capability.");
4142
+ return out;
4143
+ }
4144
+ case "expand_ui": {
4145
+ assertKeys(params, "params", ["stateId", "ref", "depth"]);
4146
+ const out = { stateId: stateId(params.stateId), ref: elementRef(params.ref, "ref") };
4147
+ if (params.depth !== void 0) out.depth = Math.trunc(boundedNumber(params.depth, "depth", 1, 8));
4148
+ return out;
4149
+ }
4150
+ case "inspect_ui": {
4151
+ assertKeys(params, "params", ["stateId", "ref"]);
4152
+ return { stateId: stateId(params.stateId), ref: elementRef(params.ref, "ref") };
4153
+ }
4154
+ case "read_text": {
4155
+ assertKeys(params, "params", ["stateId", "ref", "offset"]);
4156
+ const out = { ref: elementOrOutputRef(params.ref, "ref") };
4157
+ if (typeof out.ref === "string" && out.ref.startsWith("@e")) out.stateId = stateId(params.stateId);
4158
+ else if (params.stateId !== void 0) out.stateId = stateId(params.stateId);
4159
+ if (params.offset !== void 0) out.offset = Math.trunc(boundedNumber(params.offset, "offset", 0, 2 ** 31));
4160
+ return out;
4161
+ }
4162
+ case "wait_for": {
4163
+ assertKeys(params, "params", ["stateId", "text", "role", "value", "ref", "scopeRef", "until", "timeoutMs"]);
4164
+ const out = { stateId: stateId(params.stateId) };
4165
+ if (params.ref !== void 0) out.ref = elementRef(params.ref, "ref");
4166
+ if (params.scopeRef !== void 0) out.scopeRef = elementRef(params.scopeRef, "scopeRef");
4167
+ if (params.text !== void 0) out.text = boundedString(params.text, "text", 8192);
4168
+ if (params.role !== void 0) out.role = boundedString(params.role, "role", 256);
4169
+ if (params.value !== void 0) out.value = boundedString(params.value, "value", 8192);
4170
+ if (params.until !== void 0) out.until = oneOf(params.until, "until", ["present", "absent"]);
4171
+ if (params.timeoutMs !== void 0) out.timeoutMs = boundedNumber(params.timeoutMs, "timeoutMs", 100, 6e4);
4172
+ return out;
4173
+ }
4174
+ case "act_ui": {
4175
+ assertKeys(params, "params", ["stateId", "actions", "expect"]);
4176
+ if (!Array.isArray(params.actions) || params.actions.length === 0 || params.actions.length > 20) {
4177
+ throw new BrokerProtocolError("invalid_params", "actions must be a non-empty array of at most 20 actions.");
4178
+ }
4179
+ const out = {
4180
+ stateId: stateId(params.stateId),
4181
+ actions: params.actions.map((action, index) => validateAction(action, index))
4182
+ };
4183
+ if (params.expect !== void 0) out.expect = validateCondition(params.expect, "expect");
4184
+ return out;
4185
+ }
4186
+ case "launch_browser": {
4187
+ assertKeys(params, "params", ["url"]);
4188
+ const out = {};
4189
+ if (params.url !== void 0) out.url = httpUrl(params.url, "url");
4190
+ return out;
4191
+ }
4192
+ case "navigate_browser": {
4193
+ assertKeys(params, "params", ["stateId", "url"]);
4194
+ return { stateId: stateId(params.stateId), url: httpUrl(params.url, "url") };
4195
+ }
4196
+ case "evaluate_browser": {
4197
+ assertKeys(params, "params", ["stateId", "expression"]);
4198
+ const expression = boundedString(params.expression, "expression", 256 * 1024);
4199
+ if (!expression.trim()) throw new BrokerProtocolError("invalid_params", "expression must be non-empty.");
4200
+ return { stateId: stateId(params.stateId), expression };
4201
+ }
4202
+ default:
4203
+ throw new BrokerProtocolError("unknown_command", `Unknown command '${String(command)}'.`);
4204
+ }
4205
+ }
4206
+ function validateRequest(value) {
4207
+ assertPlainRecord(value, "request");
4208
+ if (value.type !== "request") throw new BrokerProtocolError("invalid_frame", "Expected a request frame.");
4209
+ const commandCandidate = typeof value.command === "string" ? value.command : "";
4210
+ if (value.protocolVersion !== BROKER_PROTOCOL_VERSION && commandCandidate !== "stop") {
4211
+ throw new BrokerProtocolError("protocol_mismatch", `Protocol mismatch: broker ${BROKER_PROTOCOL_VERSION}, client ${String(value.protocolVersion)}.`);
4212
+ }
4213
+ if (typeof value.requestId !== "string" || !REQUEST_ID_PATTERN.test(value.requestId)) {
4214
+ throw new BrokerProtocolError("invalid_request", "requestId is missing or malformed.");
4215
+ }
4216
+ const ownerId = normalizeComputerUseOwner(value.ownerId);
4217
+ if (typeof value.ownerId === "string" && value.ownerId.trim() && ownerId === COMPUTER_USE_STANDALONE_OWNER && value.ownerId.trim() !== COMPUTER_USE_STANDALONE_OWNER) {
4218
+ throw new BrokerProtocolError("invalid_request", "ownerId is malformed.");
4219
+ }
4220
+ if (!isEngineCommand(commandCandidate) && !isControlCommand(commandCandidate)) {
4221
+ throw new BrokerProtocolError("unknown_command", `Unknown command '${commandCandidate}'.`);
4222
+ }
4223
+ const command = commandCandidate;
4224
+ if (command === "debug_restart_helper" && value.params !== void 0 && value.params !== null) {
4225
+ assertPlainRecord(value.params, "params");
4226
+ }
4227
+ const params = validateCommandParams(command, value.params);
4228
+ const cwd = value.cwd === void 0 ? process.cwd() : boundedString(value.cwd, "cwd", 4096);
4229
+ if (!path2.isAbsolute(cwd)) throw new BrokerProtocolError("invalid_request", "cwd must be absolute.");
4230
+ const budgetMs = value.budgetMs === void 0 ? BROKER_DEFAULT_REQUEST_BUDGET_MS : Math.trunc(boundedNumber(value.budgetMs, "budgetMs", 100, BROKER_MAX_REQUEST_BUDGET_MS));
4231
+ return {
4232
+ requestId: value.requestId,
4233
+ ownerId,
4234
+ executionId: value.executionId === void 0 ? void 0 : boundedString(value.executionId, "executionId", 256),
4235
+ generation: value.generation === void 0 ? void 0 : boundedString(value.generation, "generation", 128),
4236
+ command,
4237
+ params,
4238
+ cwd,
4239
+ budgetMs
4240
+ };
4241
+ }
4242
+ function validateHello(value) {
4243
+ assertPlainRecord(value, "hello");
4244
+ if (value.type !== "hello") throw new BrokerProtocolError("invalid_frame", "Expected a hello frame.");
4245
+ if (value.protocolVersion !== BROKER_PROTOCOL_VERSION) {
4246
+ throw new BrokerProtocolError("protocol_mismatch", `Protocol mismatch: broker ${BROKER_PROTOCOL_VERSION}, client ${String(value.protocolVersion)}.`);
4247
+ }
4248
+ return {
4249
+ type: "hello",
4250
+ protocolVersion: value.protocolVersion,
4251
+ clientVersion: value.clientVersion === void 0 ? void 0 : boundedString(value.clientVersion, "clientVersion", 128)
4252
+ };
4253
+ }
4254
+ function encodeFrame(value, maxBytes = BROKER_MAX_FRAME_BYTES) {
4255
+ let json;
4256
+ try {
4257
+ json = JSON.stringify(value);
4258
+ } catch (error) {
4259
+ throw new BrokerProtocolError("encode_failed", error instanceof Error ? error.message : String(error));
4260
+ }
4261
+ const bytes = Buffer.byteLength(json, "utf8");
4262
+ if (bytes > maxBytes) throw new BrokerProtocolError("frame_too_large", `Frame of ${bytes} bytes exceeds the ${maxBytes}-byte limit.`);
4263
+ return Buffer.from(`${json}
4264
+ `, "utf8");
4265
+ }
4266
+ var FrameDecoder = class {
4267
+ constructor(maxBytes = BROKER_MAX_FRAME_BYTES) {
4268
+ this.maxBytes = maxBytes;
4269
+ }
4270
+ maxBytes;
4271
+ buffer = Buffer.alloc(0);
4272
+ push(chunk) {
4273
+ this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
4274
+ const frames = [];
4275
+ for (; ; ) {
4276
+ const newline = this.buffer.indexOf(10);
4277
+ if (newline < 0) break;
4278
+ const line = this.buffer.subarray(0, newline).toString("utf8").trim();
4279
+ this.buffer = this.buffer.subarray(newline + 1);
4280
+ if (!line) continue;
4281
+ let parsed;
4282
+ try {
4283
+ parsed = JSON.parse(line);
4284
+ } catch {
4285
+ throw new BrokerProtocolError("invalid_json", "Frame is not valid JSON.");
4286
+ }
4287
+ frames.push(parsed);
4288
+ }
4289
+ if (this.buffer.length > this.maxBytes) {
4290
+ throw new BrokerProtocolError("frame_too_large", `Unterminated frame exceeds the ${this.maxBytes}-byte limit.`);
4291
+ }
4292
+ return frames;
4293
+ }
4294
+ };
4295
+ function resolveBrokerEndpoint(env = process.env) {
4296
+ const socketOverride = env.PIE_COMPUTER_USE_BROKER_SOCKET?.trim();
4297
+ if (process.platform === "win32") {
4298
+ const seed = socketOverride || stateRootDir(env);
4299
+ const key = createHash("sha256").update(seed).digest("hex").slice(0, 16);
4300
+ return { kind: "named-pipe", path: `\\\\.\\pipe\\pie-computer-use-axi-${key}` };
4301
+ }
4302
+ const socketPath = socketOverride || path2.join(stateRootDir(env), "run", "broker.sock");
4303
+ if (Buffer.byteLength(socketPath, "utf8") > 100) {
4304
+ throw new BrokerProtocolError("endpoint_too_long", `Unix socket path is ${Buffer.byteLength(socketPath)} bytes (limit ~104): ${socketPath}. Set PIE_COMPUTER_USE_BROKER_SOCKET to a shorter path.`);
4305
+ }
4306
+ return { kind: "unix-socket", path: socketPath, directory: path2.dirname(socketPath) };
4307
+ }
4308
+ function ensurePrivateDirectory(directory) {
4309
+ mkdirSync3(directory, { recursive: true, mode: 448 });
4310
+ const stats = lstatSync2(directory);
4311
+ if (stats.isSymbolicLink()) throw new BrokerProtocolError("unsafe_path", `Refusing symlinked private directory: ${directory}`);
4312
+ if (!stats.isDirectory()) throw new BrokerProtocolError("unsafe_path", `Not a directory: ${directory}`);
4313
+ if (process.platform !== "win32") chmodSync(directory, 448);
4314
+ }
4315
+ function canonicalize(value) {
4316
+ if (Array.isArray(value)) return value.map(canonicalize);
4317
+ if (value && typeof value === "object") {
4318
+ const record = value;
4319
+ const sorted = {};
4320
+ for (const key of Object.keys(record).sort()) sorted[key] = canonicalize(record[key]);
4321
+ return sorted;
4322
+ }
4323
+ return value;
4324
+ }
4325
+ function requestFingerprint(command, params, cwd) {
4326
+ const seed = JSON.stringify({ command, params: canonicalize(params), cwd });
4327
+ return createHash("sha256").update(seed).digest("hex").slice(0, 32);
4328
+ }
4329
+
4330
+ // vendor/computer-use-axi/src/artifact-store.ts
4331
+ var SAFE_COMPONENT = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
4332
+ function safeComponent(value, label2) {
4333
+ if (!SAFE_COMPONENT.test(value)) throw new Error(`Unsafe artifact ${label2}: ${value}`);
4334
+ return value;
4335
+ }
4336
+ function extensionFor(mimeType) {
4337
+ return mimeType === "image/png" ? "png" : "jpg";
4338
+ }
4339
+ var ArtifactStore = class {
4340
+ constructor(options) {
4341
+ this.options = options;
4342
+ this.maxCount = options.maxCount ?? 128;
4343
+ this.maxBytes = options.maxBytes ?? 128 * 1024 * 1024;
4344
+ this.maxAgeMs = options.maxAgeMs ?? 30 * 6e4;
4345
+ this.now = options.now ?? Date.now;
4346
+ }
4347
+ options;
4348
+ records = /* @__PURE__ */ new Map();
4349
+ pins = /* @__PURE__ */ new Map();
4350
+ maxCount;
4351
+ maxBytes;
4352
+ maxAgeMs;
4353
+ now;
4354
+ totalBytes = 0;
4355
+ /** Absolute path for one owner/generation, created 0700 and symlink-checked. */
4356
+ directoryFor(owner, generation = this.options.generation) {
4357
+ const root = path3.join(this.options.root, safeComponent(generation, "generation"));
4358
+ const ownerDir = path3.join(root, safeComponent(normalizeComputerUseOwner(owner), "owner"));
4359
+ ensurePrivateDirectory(this.options.root);
4360
+ ensurePrivateDirectory(root);
4361
+ ensurePrivateDirectory(ownerDir);
4362
+ return ownerDir;
4363
+ }
4364
+ put(input) {
4365
+ const generation = input.generation ?? this.options.generation;
4366
+ const directory = this.directoryFor(input.owner, generation);
4367
+ const artifactId = randomUUID2();
4368
+ const absolutePath = path3.join(directory, `${artifactId}.${extensionFor(input.mimeType)}`);
4369
+ const fd = openSync(absolutePath, "wx", 384);
4370
+ try {
4371
+ let offset = 0;
4372
+ while (offset < input.bytes.byteLength) {
4373
+ offset += writeSync(fd, input.bytes, offset, input.bytes.byteLength - offset);
4374
+ }
4375
+ } finally {
4376
+ closeSync(fd);
4377
+ }
4378
+ const record = {
4379
+ artifactId,
4380
+ stateId: input.stateId,
4381
+ owner: normalizeComputerUseOwner(input.owner),
4382
+ generation,
4383
+ mimeType: input.mimeType,
4384
+ width: Math.max(1, Math.trunc(input.width)),
4385
+ height: Math.max(1, Math.trunc(input.height)),
4386
+ hash: createHash2("sha256").update(input.bytes).digest("hex"),
4387
+ bytes: input.bytes.byteLength,
4388
+ absolutePath,
4389
+ createdAt: this.now()
4390
+ };
4391
+ this.records.set(artifactId, record);
4392
+ this.totalBytes += record.bytes;
4393
+ this.pin(artifactId);
4394
+ this.sweep();
4395
+ return record;
4396
+ }
4397
+ pin(artifactId) {
4398
+ this.pins.set(artifactId, (this.pins.get(artifactId) ?? 0) + 1);
4399
+ }
4400
+ unpin(artifactId) {
4401
+ const current = this.pins.get(artifactId) ?? 0;
4402
+ if (current <= 1) this.pins.delete(artifactId);
4403
+ else this.pins.set(artifactId, current - 1);
4404
+ this.sweep();
4405
+ }
4406
+ get(artifactId) {
4407
+ return this.records.get(artifactId);
4408
+ }
4409
+ /** Delete all artifacts belonging to one state (state eviction). */
4410
+ dropForState(stateId2) {
4411
+ let removed = 0;
4412
+ for (const record of [...this.records.values()]) {
4413
+ if (record.stateId !== stateId2) continue;
4414
+ this.remove(record);
4415
+ removed += 1;
4416
+ }
4417
+ return removed;
4418
+ }
4419
+ stats() {
4420
+ return { count: this.records.size, bytes: this.totalBytes, pinned: this.pins.size, maxCount: this.maxCount, maxBytes: this.maxBytes };
4421
+ }
4422
+ /** Drop expired entries first, then oldest until count/byte bounds hold. */
4423
+ sweep() {
4424
+ const now = this.now();
4425
+ for (const record of [...this.records.values()]) {
4426
+ if (this.isPinned(record.artifactId)) continue;
4427
+ if (now - record.createdAt <= this.maxAgeMs) continue;
4428
+ this.remove(record);
4429
+ this.options.onEvict?.(record.stateId, "age");
4430
+ }
4431
+ const evictOldest = (reason) => {
4432
+ for (const record of this.records.values()) {
4433
+ if (this.isPinned(record.artifactId)) continue;
4434
+ this.remove(record);
4435
+ this.options.onEvict?.(record.stateId, reason);
4436
+ return true;
4437
+ }
4438
+ return false;
4439
+ };
4440
+ while (this.records.size > this.maxCount && evictOldest("count")) {
4441
+ }
4442
+ while (this.totalBytes > this.maxBytes && evictOldest("bytes")) {
4443
+ }
4444
+ }
4445
+ /** Remove files for a generation that no longer owns the broker. */
4446
+ cleanupGeneration(generation) {
4447
+ if (!SAFE_COMPONENT.test(generation)) return 0;
4448
+ const directory = path3.join(this.options.root, generation);
4449
+ if (!existsSync2(directory)) return 0;
4450
+ const stats = lstatSync3(directory);
4451
+ if (stats.isSymbolicLink() || !stats.isDirectory()) return 0;
4452
+ let removed = 0;
4453
+ for (const name of readdirSync2(directory)) {
4454
+ const ownerDir = path3.join(directory, name);
4455
+ let ownerStats;
4456
+ try {
4457
+ ownerStats = lstatSync3(ownerDir);
4458
+ } catch {
4459
+ continue;
4460
+ }
4461
+ if (ownerStats.isSymbolicLink() || !ownerStats.isDirectory()) continue;
4462
+ for (const file of readdirSync2(ownerDir)) {
4463
+ const target = path3.join(ownerDir, file);
4464
+ let fileStats;
4465
+ try {
4466
+ fileStats = lstatSync3(target);
4467
+ } catch {
4468
+ continue;
4469
+ }
4470
+ if (fileStats.isSymbolicLink() || !fileStats.isFile()) continue;
4471
+ unlinkSync2(target);
4472
+ removed += 1;
4473
+ }
4474
+ try {
4475
+ rmdirSync(ownerDir);
4476
+ } catch {
4477
+ }
4478
+ }
4479
+ try {
4480
+ rmdirSync(directory);
4481
+ } catch {
4482
+ }
4483
+ return removed;
4484
+ }
4485
+ /**
4486
+ * Remove every generation directory except the current one. A SIGKILLed
4487
+ * broker never gets to clean up after itself, so multiple stale generations
4488
+ * can accumulate; startup sweeps them with a strict bound and refuses to
4489
+ * follow symlinked or unrecognized entries.
4490
+ */
4491
+ cleanupOtherGenerations(currentGeneration, maxGenerations = 32) {
4492
+ const current = safeComponent(currentGeneration, "generation");
4493
+ let names;
4494
+ try {
4495
+ names = readdirSync2(this.options.root);
4496
+ } catch {
4497
+ return 0;
4498
+ }
4499
+ let removed = 0;
4500
+ let scanned = 0;
4501
+ for (const name of names) {
4502
+ if (scanned >= maxGenerations) break;
4503
+ if (name === current || !SAFE_COMPONENT.test(name)) continue;
4504
+ const directory = path3.join(this.options.root, name);
4505
+ let stats;
4506
+ try {
4507
+ stats = lstatSync3(directory);
4508
+ } catch {
4509
+ continue;
4510
+ }
4511
+ if (stats.isSymbolicLink() || !stats.isDirectory()) continue;
4512
+ scanned += 1;
4513
+ removed += this.cleanupGeneration(name);
4514
+ }
4515
+ return removed;
4516
+ }
4517
+ close() {
4518
+ this.records.clear();
4519
+ this.pins.clear();
4520
+ this.totalBytes = 0;
4521
+ }
4522
+ isPinned(artifactId) {
4523
+ return (this.pins.get(artifactId) ?? 0) > 0;
4524
+ }
4525
+ remove(record) {
4526
+ this.records.delete(record.artifactId);
4527
+ this.totalBytes = Math.max(0, this.totalBytes - record.bytes);
4528
+ try {
4529
+ unlinkSync2(record.absolutePath);
4530
+ } catch {
4531
+ }
4532
+ }
4533
+ };
4534
+ function artifactsRoot(env = process.env) {
4535
+ const base = env.PIE_COMPUTER_USE_ARTIFACTS_DIR?.trim();
4536
+ if (base) return path3.resolve(base);
4537
+ return path3.join(stateRootDir(env), "artifacts");
4538
+ }
4539
+
4540
+ // vendor/computer-use-axi/src/bridge.ts
3698
4541
  import { spawn as spawn4 } from "node:child_process";
3699
- import { randomUUID as randomUUID5 } from "node:crypto";
3700
- import { constants as fsConstants5, mkdtempSync as mkdtempSync2 } from "node:fs";
4542
+ import { randomUUID as randomUUID7 } from "node:crypto";
4543
+ import { constants as fsConstants5, mkdtempSync } from "node:fs";
3701
4544
  import { access as access4 } from "node:fs/promises";
3702
4545
  import net2 from "node:net";
3703
- import os5 from "node:os";
3704
- import path10 from "node:path";
4546
+ import os4 from "node:os";
4547
+ import path13 from "node:path";
3705
4548
 
3706
- // builtin/extensions/computer-use/src/platform/coerce.ts
4549
+ // vendor/computer-use-axi/src/platform/coerce.ts
3707
4550
  function toBoolean(value) {
3708
4551
  return value === true || value === "true" || value === 1;
3709
4552
  }
@@ -3719,7 +4562,7 @@ function toOptionalString(value) {
3719
4562
  return typeof value === "string" && value.length > 0 ? value : void 0;
3720
4563
  }
3721
4564
 
3722
- // builtin/extensions/computer-use/src/actions.ts
4565
+ // vendor/computer-use-axi/src/actions.ts
3723
4566
  function mouseButton(value) {
3724
4567
  return value === "right" || value === "middle" ? value : "left";
3725
4568
  }
@@ -3733,11 +4576,11 @@ function keys(value) {
3733
4576
  if (!Array.isArray(value) || value.length === 0) throw new Error("keypress.keys must contain at least one key.");
3734
4577
  return value.map((key) => String(key));
3735
4578
  }
3736
- function path(value, env) {
4579
+ function path4(value, env) {
3737
4580
  if (!Array.isArray(value) || value.length < 2) throw new Error("drag.path must contain at least two points.");
3738
- return value.map((point2, index) => {
3739
- const x = Array.isArray(point2) ? toFiniteNumber(point2[0], NaN) : toFiniteNumber(point2?.x, NaN);
3740
- const y = Array.isArray(point2) ? toFiniteNumber(point2[1], NaN) : toFiniteNumber(point2?.y, NaN);
4581
+ return value.map((point, index) => {
4582
+ const x = Array.isArray(point) ? toFiniteNumber(point[0], NaN) : toFiniteNumber(point?.x, NaN);
4583
+ const y = Array.isArray(point) ? toFiniteNumber(point[1], NaN) : toFiniteNumber(point?.y, NaN);
3741
4584
  env.validatePoint(x, y, `Drag point ${index + 1}`);
3742
4585
  return { x, y };
3743
4586
  });
@@ -3747,17 +4590,17 @@ function nativeTarget(action, operation, env) {
3747
4590
  const node = env.node(action.ref.trim());
3748
4591
  const semanticClick = operation === "click" || operation === "press";
3749
4592
  if (semanticClick && node.isTextInput) {
3750
- const point3 = env.center(node);
3751
- env.validatePoint(point3.x, point3.y);
3752
- return point3;
4593
+ const point2 = env.center(node);
4594
+ env.validatePoint(point2.x, point2.y);
4595
+ return point2;
3753
4596
  }
3754
4597
  const onlyIncidentalActions = node.actions.every((candidate) => candidate === "AXShowMenu" || candidate === "AXScrollToVisible");
3755
4598
  if (node.wireRef && !node.pictureOnly && (!semanticClick || node.canPress || node.canFocus || node.canSetValue || !onlyIncidentalActions)) {
3756
4599
  return { ref: node.wireRef };
3757
4600
  }
3758
- const point2 = env.center(node);
3759
- env.validatePoint(point2.x, point2.y);
3760
- return point2;
4601
+ const point = env.center(node);
4602
+ env.validatePoint(point.x, point.y);
4603
+ return point;
3761
4604
  }
3762
4605
  const x = toFiniteNumber(action.x, NaN);
3763
4606
  const y = toFiniteNumber(action.y, NaN);
@@ -3765,7 +4608,7 @@ function nativeTarget(action, operation, env) {
3765
4608
  env.validatePoint(x, y);
3766
4609
  return { x, y };
3767
4610
  }
3768
- if (operation === "drag" && action.path?.length) return path(action.path, env)[0];
4611
+ if (operation === "drag" && action.path?.length) return path4(action.path, env)[0];
3769
4612
  throw new Error(`${operation} requires either ref or both x and y.`);
3770
4613
  }
3771
4614
  function focusedTarget(env) {
@@ -3835,7 +4678,7 @@ function prepareAction(action, state, env) {
3835
4678
  case "scroll":
3836
4679
  return { action: operation, target, params: { scrollX: scrollDelta(action.scrollX), scrollY: scrollDelta(action.scrollY) }, usesCurrentFocus: false, needsForeground: false };
3837
4680
  case "drag":
3838
- return { action: operation, target, params: { path: path(action.path, env) }, usesCurrentFocus: false, needsForeground: false };
4681
+ return { action: operation, target, params: { path: path4(action.path, env) }, usesCurrentFocus: false, needsForeground: false };
3839
4682
  case "moveMouse":
3840
4683
  return { action: operation, target, params: {}, usesCurrentFocus: false, needsForeground: false };
3841
4684
  }
@@ -3860,8 +4703,8 @@ function outcomeAfterObservedValues(current, actions, valueForRef) {
3860
4703
  return matches ? "worked" : current;
3861
4704
  }
3862
4705
 
3863
- // builtin/extensions/computer-use/src/cdp.ts
3864
- import { randomUUID } from "node:crypto";
4706
+ // vendor/computer-use-axi/src/cdp.ts
4707
+ import { randomUUID as randomUUID3 } from "node:crypto";
3865
4708
 
3866
4709
  // ../../node_modules/ws/wrapper.mjs
3867
4710
  var import_stream = __toESM(require_stream(), 1);
@@ -3874,9 +4717,9 @@ var import_websocket = __toESM(require_websocket(), 1);
3874
4717
  var import_websocket_server = __toESM(require_websocket_server(), 1);
3875
4718
  var wrapper_default = import_websocket.default;
3876
4719
 
3877
- // builtin/extensions/computer-use/src/outline.ts
4720
+ // vendor/computer-use-axi/src/outline.ts
3878
4721
  var DEFAULT_BUDGET = { maxDepth: 2, maxNodes: 150 };
3879
- function isRecord(value) {
4722
+ function isRecord2(value) {
3880
4723
  return typeof value === "object" && value !== null;
3881
4724
  }
3882
4725
  function toString(value) {
@@ -3894,7 +4737,7 @@ function toBoolean2(value) {
3894
4737
  return value === true;
3895
4738
  }
3896
4739
  function parseRect(raw) {
3897
- const rect = isRecord(raw) ? raw : {};
4740
+ const rect = isRecord2(raw) ? raw : {};
3898
4741
  return {
3899
4742
  x: toNumber(rect.x),
3900
4743
  y: toNumber(rect.y),
@@ -3905,7 +4748,7 @@ function parseRect(raw) {
3905
4748
  function parseText(raw) {
3906
4749
  if (!Array.isArray(raw)) return [];
3907
4750
  return raw.map((item) => {
3908
- if (!isRecord(item)) return void 0;
4751
+ if (!isRecord2(item)) return void 0;
3909
4752
  const string = toString(item.string);
3910
4753
  if (!string) return void 0;
3911
4754
  return {
@@ -3916,7 +4759,7 @@ function parseText(raw) {
3916
4759
  }).filter((item) => Boolean(item));
3917
4760
  }
3918
4761
  function parseNode(raw, parent) {
3919
- const record = isRecord(raw) ? raw : {};
4762
+ const record = isRecord2(raw) ? raw : {};
3920
4763
  const wireRef = toString(record.ref) || void 0;
3921
4764
  const node = {
3922
4765
  ref: "",
@@ -3940,7 +4783,7 @@ function parseNode(raw, parent) {
3940
4783
  offscreen: toBoolean2(record.offscreen),
3941
4784
  pictureOnly: toBoolean2(record.pictureOnly),
3942
4785
  truncated: toBoolean2(record.truncated),
3943
- scrollExtent: isRecord(record.scrollExtent) ? { seen: Math.max(0, Math.trunc(toNumber(record.scrollExtent.seen))), total: Math.max(0, Math.trunc(toNumber(record.scrollExtent.total))) } : void 0,
4786
+ scrollExtent: isRecord2(record.scrollExtent) ? { seen: Math.max(0, Math.trunc(toNumber(record.scrollExtent.seen))), total: Math.max(0, Math.trunc(toNumber(record.scrollExtent.total))) } : void 0,
3944
4787
  text: parseText(record.text),
3945
4788
  children: [],
3946
4789
  parent
@@ -3949,12 +4792,12 @@ function parseNode(raw, parent) {
3949
4792
  return node;
3950
4793
  }
3951
4794
  function parseLookResponse(raw) {
3952
- const record = isRecord(raw) ? raw : {};
3953
- const image = isRecord(record.image) ? record.image : void 0;
3954
- const window = isRecord(record.window) ? record.window : {};
3955
- const metadata = isRecord(window.metadata) ? window.metadata : void 0;
4795
+ const record = isRecord2(raw) ? raw : {};
4796
+ const image = isRecord2(record.image) ? record.image : void 0;
4797
+ const window = isRecord2(record.window) ? record.window : {};
4798
+ const metadata = isRecord2(window.metadata) ? window.metadata : void 0;
3956
4799
  const outline = buildOutline(toString(record.lookId), parseNode(record.outline));
3957
- const readText = isRecord(record.readText) ? record.readText : void 0;
4800
+ const readText = isRecord2(record.readText) ? record.readText : void 0;
3958
4801
  const requestedReadText = readText?.requested === "auto" || readText?.requested === "always" || readText?.requested === "never" ? readText.requested : void 0;
3959
4802
  const look = {
3960
4803
  lookId: toString(record.lookId),
@@ -3977,7 +4820,7 @@ function parseLookResponse(raw) {
3977
4820
  height: Math.max(1, Math.trunc(toNumber(image.height, 1)))
3978
4821
  } : void 0,
3979
4822
  outline: outline.root,
3980
- timings: isRecord(record.timings) ? Object.fromEntries(Object.entries(record.timings).map(([key, value]) => [key, toNumber(value)])) : {},
4823
+ timings: isRecord2(record.timings) ? Object.fromEntries(Object.entries(record.timings).map(([key, value]) => [key, toNumber(value)])) : {},
3981
4824
  readText: readText ? { requested: requestedReadText, executed: toBoolean2(readText.executed) } : void 0,
3982
4825
  parsedOutline: outline
3983
4826
  };
@@ -4336,7 +5179,7 @@ function graftScopedOutline(outline, targetRef, scoped) {
4336
5179
  return target;
4337
5180
  }
4338
5181
 
4339
- // builtin/extensions/computer-use/src/cdp.ts
5182
+ // vendor/computer-use-axi/src/cdp.ts
4340
5183
  var COMMAND_TIMEOUT_MS = 5e3;
4341
5184
  var CDP_CONTEXT_PREFIX = "browser:";
4342
5185
  var NAVIGATE_LOAD_TIMEOUT_MS = 1e4;
@@ -4367,11 +5210,11 @@ var CdpTab = class _CdpTab {
4367
5210
  const ws = new wrapper_default(wsUrl);
4368
5211
  connectingSockets.add(ws);
4369
5212
  try {
4370
- await new Promise((resolve, reject) => {
5213
+ await new Promise((resolve2, reject) => {
4371
5214
  const timer = setTimeout(() => reject(new Error(`Timed out connecting to CDP target at ${wsUrl}`)), COMMAND_TIMEOUT_MS);
4372
5215
  ws.onopen = () => {
4373
5216
  clearTimeout(timer);
4374
- resolve();
5217
+ resolve2();
4375
5218
  };
4376
5219
  ws.onerror = () => {
4377
5220
  clearTimeout(timer);
@@ -4419,14 +5262,14 @@ var CdpTab = class _CdpTab {
4419
5262
  this.loadFired = void 0;
4420
5263
  this.rejectAllPending(new Error("CDP connection closed."));
4421
5264
  if (this.ws.readyState === wrapper_default.CLOSED) return;
4422
- await new Promise((resolve) => {
5265
+ await new Promise((resolve2) => {
4423
5266
  const timer = setTimeout(() => {
4424
5267
  this.ws.terminate();
4425
- resolve();
5268
+ resolve2();
4426
5269
  }, 500);
4427
5270
  this.ws.once("close", () => {
4428
5271
  clearTimeout(timer);
4429
- resolve();
5272
+ resolve2();
4430
5273
  });
4431
5274
  if (this.ws.readyState === wrapper_default.CONNECTING) this.ws.terminate();
4432
5275
  else this.ws.close();
@@ -4446,13 +5289,13 @@ var CdpTab = class _CdpTab {
4446
5289
  }
4447
5290
  async navigate(url) {
4448
5291
  let timer;
4449
- const loaded = new Promise((resolve) => {
4450
- this.loadFired = resolve;
5292
+ const loaded = new Promise((resolve2) => {
5293
+ this.loadFired = resolve2;
4451
5294
  });
4452
5295
  try {
4453
5296
  await this.send("Page.navigate", { url });
4454
- await Promise.race([loaded, new Promise((resolve) => {
4455
- timer = setTimeout(resolve, NAVIGATE_LOAD_TIMEOUT_MS);
5297
+ await Promise.race([loaded, new Promise((resolve2) => {
5298
+ timer = setTimeout(resolve2, NAVIGATE_LOAD_TIMEOUT_MS);
4456
5299
  })]);
4457
5300
  } finally {
4458
5301
  clearTimeout(timer);
@@ -4489,11 +5332,11 @@ var CdpTab = class _CdpTab {
4489
5332
  async mouseAt(x, y, type, button = "left", clickCount2 = 1) {
4490
5333
  await this.send("Input.dispatchMouseEvent", { type, x, y, button: type === "mouseMoved" ? "none" : button, clickCount: clickCount2 });
4491
5334
  }
4492
- async dragPath(path11) {
4493
- if (path11.length < 2) throw new Error("CDP drag requires at least two points.");
4494
- await this.mouseAt(path11[0].x, path11[0].y, "mousePressed");
4495
- for (const point2 of path11.slice(1)) await this.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: point2.x, y: point2.y, button: "left", buttons: 1 });
4496
- const end = path11[path11.length - 1];
5335
+ async dragPath(path15) {
5336
+ if (path15.length < 2) throw new Error("CDP drag requires at least two points.");
5337
+ await this.mouseAt(path15[0].x, path15[0].y, "mousePressed");
5338
+ for (const point of path15.slice(1)) await this.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: point.x, y: point.y, button: "left", buttons: 1 });
5339
+ const end = path15[path15.length - 1];
4497
5340
  await this.mouseAt(end.x, end.y, "mouseReleased");
4498
5341
  }
4499
5342
  async withBackendNode(backendNodeId, functionDeclaration, args = []) {
@@ -4524,7 +5367,7 @@ var CdpTab = class _CdpTab {
4524
5367
  }
4525
5368
  send(method, params = {}) {
4526
5369
  const id = this.nextId++;
4527
- return new Promise((resolve, reject) => {
5370
+ return new Promise((resolve2, reject) => {
4528
5371
  const timer = setTimeout(() => {
4529
5372
  this.pending.delete(id);
4530
5373
  reject(new Error(`CDP command '${method}' timed out after ${COMMAND_TIMEOUT_MS}ms.`));
@@ -4532,7 +5375,7 @@ var CdpTab = class _CdpTab {
4532
5375
  this.pending.set(id, {
4533
5376
  resolve: (result) => {
4534
5377
  clearTimeout(timer);
4535
- resolve(result);
5378
+ resolve2(result);
4536
5379
  },
4537
5380
  reject: (error) => {
4538
5381
  clearTimeout(timer);
@@ -4712,9 +5555,9 @@ async function cdpMouseForContext(contextId, x, y, type, button = "left", clickC
4712
5555
  return true;
4713
5556
  }) === true;
4714
5557
  }
4715
- async function cdpDragForContext(contextId, path11) {
5558
+ async function cdpDragForContext(contextId, path15) {
4716
5559
  return await withCdpContextTab(contextId, async (tab) => {
4717
- await tab.dragPath(path11);
5560
+ await tab.dragPath(path15);
4718
5561
  return true;
4719
5562
  }) === true;
4720
5563
  }
@@ -4748,7 +5591,7 @@ async function cdpSnapshotForContext(contextId) {
4748
5591
  tab.accessibilityTree().catch(() => [])
4749
5592
  ]);
4750
5593
  assertConnectionEpoch(epoch);
4751
- const snapshotId = randomUUID();
5594
+ const snapshotId = randomUUID3();
4752
5595
  const { targets, outline } = cdpSnapshotOutline(snapshotId, nodes);
4753
5596
  return {
4754
5597
  contextId,
@@ -4818,7 +5661,7 @@ function cdpSnapshotOutline(snapshotId, nodes) {
4818
5661
  }
4819
5662
  const targets = [];
4820
5663
  const build = (raw, seen) => {
4821
- const nodeId = String(raw?.nodeId ?? randomUUID());
5664
+ const nodeId = String(raw?.nodeId ?? randomUUID3());
4822
5665
  if (seen.has(nodeId)) return void 0;
4823
5666
  seen.add(nodeId);
4824
5667
  const role = axString(raw?.role);
@@ -4944,16 +5787,16 @@ function titlesMatch(tabTitle, windowTitle) {
4944
5787
  return tab === win || win.startsWith(tab) || tab.startsWith(win);
4945
5788
  }
4946
5789
 
4947
- // builtin/extensions/computer-use/src/config.ts
4948
- import { existsSync, readFileSync } from "node:fs";
4949
- import path2 from "node:path";
5790
+ // vendor/computer-use-axi/src/config.ts
5791
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
5792
+ import path5 from "node:path";
4950
5793
 
4951
- // builtin/extensions/computer-use/host.ts
5794
+ // vendor/computer-use-axi/host.ts
4952
5795
  function getAgentDir() {
4953
5796
  return getConfigDir();
4954
5797
  }
4955
5798
 
4956
- // builtin/extensions/computer-use/src/config.ts
5799
+ // vendor/computer-use-axi/src/config.ts
4957
5800
  var DEFAULT_CONFIG = {
4958
5801
  browser_use: true,
4959
5802
  headless: false,
@@ -4986,9 +5829,9 @@ function normalizePartial(raw) {
4986
5829
  return out;
4987
5830
  }
4988
5831
  function readConfigFile(filePath) {
4989
- if (!existsSync(filePath)) return { path: filePath, exists: false };
5832
+ if (!existsSync3(filePath)) return { path: filePath, exists: false };
4990
5833
  try {
4991
- const parsed = JSON.parse(readFileSync(filePath, "utf-8"));
5834
+ const parsed = JSON.parse(readFileSync3(filePath, "utf-8"));
4992
5835
  return { path: filePath, exists: true, values: normalizePartial(parsed) };
4993
5836
  } catch (error) {
4994
5837
  return { path: filePath, exists: true, error: error instanceof Error ? error.message : String(error) };
@@ -5008,8 +5851,8 @@ function readEnv() {
5008
5851
  }
5009
5852
  function loadComputerUseConfig(cwd) {
5010
5853
  const sources = [
5011
- readConfigFile(path2.join(getAgentDir(), "extensions", "computer-use.json")),
5012
- readConfigFile(path2.join(cwd, ".pie", "computer-use.json"))
5854
+ readConfigFile(path5.join(getAgentDir(), "extensions", "computer-use.json")),
5855
+ readConfigFile(path5.join(cwd, ".pie", "computer-use.json"))
5013
5856
  ];
5014
5857
  const env = readEnv();
5015
5858
  const config = { ...DEFAULT_CONFIG };
@@ -5024,9 +5867,6 @@ function loadComputerUseConfig(cwd) {
5024
5867
  function getComputerUseConfig() {
5025
5868
  return activeConfig;
5026
5869
  }
5027
- function getLoadedComputerUseConfig() {
5028
- return activeLoadedConfig;
5029
- }
5030
5870
  function isHeadlessMode() {
5031
5871
  return activeConfig.headless;
5032
5872
  }
@@ -5034,7 +5874,7 @@ function isBrowserUseEnabled() {
5034
5874
  return activeConfig.browser_use;
5035
5875
  }
5036
5876
 
5037
- // builtin/extensions/computer-use/src/note.ts
5877
+ // vendor/computer-use-axi/src/note.ts
5038
5878
  function normalizedLabel(value) {
5039
5879
  return value.toLowerCase().replace(/\s+/g, " ").trim();
5040
5880
  }
@@ -5186,10 +6026,9 @@ function renderNote(note) {
5186
6026
  \u2026 note byte budget reached`;
5187
6027
  }
5188
6028
 
5189
- // builtin/extensions/computer-use/src/output.ts
5190
- import { closeSync, mkdtempSync, openSync, readSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
5191
- import os from "node:os";
5192
- import path3 from "node:path";
6029
+ // vendor/computer-use-axi/src/output.ts
6030
+ import { closeSync as closeSync2, mkdirSync as mkdirSync5, openSync as openSync2, readSync, readdirSync as readdirSync3, statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
6031
+ import path6 from "node:path";
5193
6032
  var MODEL_TEXT_MAX_BYTES = 48 * 1024;
5194
6033
  var MODEL_TEXT_MAX_LINES = 2e3;
5195
6034
  var OUTPUT_PAGE_BYTES = 16 * 1024;
@@ -5198,9 +6037,13 @@ var MODEL_PREVIEW_BYTES = 16 * 1024;
5198
6037
  var OUTPUT_ENTRY_MAX_BYTES = 16 * 1024 * 1024;
5199
6038
  var OUTPUT_STORE_MAX_BYTES = 64 * 1024 * 1024;
5200
6039
  var outputs = /* @__PURE__ */ new Map();
5201
- var outputDirectory;
5202
- var outputBytes = 0;
5203
6040
  var nextOutputId = 1;
6041
+ var outputBytes = 0;
6042
+ function outputDirectoryFor(owner) {
6043
+ const dir = path6.join(outputsDir(), "owners", normalizeComputerUseOwner(owner));
6044
+ mkdirSync5(dir, { recursive: true, mode: 448 });
6045
+ return dir;
6046
+ }
5204
6047
  function utf8Prefix(bytes, maxBytes) {
5205
6048
  if (bytes.byteLength <= maxBytes) return bytes;
5206
6049
  let end = Math.max(0, maxBytes);
@@ -5212,14 +6055,14 @@ function boundedPrefix(value, maxBytes, maxLines) {
5212
6055
  const lineBounded = lines.length > maxLines ? lines.slice(0, maxLines).join("\n") : value;
5213
6056
  return new TextDecoder().decode(utf8Prefix(new TextEncoder().encode(lineBounded), maxBytes));
5214
6057
  }
5215
- function storeOutput(value) {
6058
+ function storeOutput(value, owner) {
5216
6059
  const encoded = new TextEncoder().encode(value);
5217
6060
  const stored = encoded.byteLength > OUTPUT_ENTRY_MAX_BYTES ? utf8Prefix(encoded, OUTPUT_ENTRY_MAX_BYTES) : encoded;
5218
- outputDirectory ??= mkdtempSync(path3.join(os.tmpdir(), "pie-computer-use-output-"));
6061
+ const directory = outputDirectoryFor(owner);
5219
6062
  const ref = `@o${nextOutputId++}`;
5220
- const filePath = path3.join(outputDirectory, `${ref.slice(2)}.txt`);
5221
- writeFileSync(filePath, stored, { mode: 384 });
5222
- const entry = { ref, filePath, storedBytes: stored.byteLength, totalBytes: encoded.byteLength, complete: stored.byteLength === encoded.byteLength };
6063
+ const filePath = path6.join(directory, `${ref.slice(2)}.txt`);
6064
+ writeFileSync2(filePath, stored, { mode: 384 });
6065
+ const entry = { ref, owner: normalizeComputerUseOwner(owner), filePath, storedBytes: stored.byteLength, totalBytes: encoded.byteLength, complete: stored.byteLength === encoded.byteLength };
5223
6066
  outputs.set(entry.ref, entry);
5224
6067
  outputBytes += entry.storedBytes;
5225
6068
  while (outputBytes > OUTPUT_STORE_MAX_BYTES && outputs.size > 1) {
@@ -5229,7 +6072,7 @@ function storeOutput(value) {
5229
6072
  outputs.delete(oldestRef);
5230
6073
  outputBytes -= oldest.storedBytes;
5231
6074
  try {
5232
- unlinkSync(oldest.filePath);
6075
+ unlinkSync3(oldest.filePath);
5233
6076
  } catch {
5234
6077
  }
5235
6078
  }
@@ -5242,16 +6085,16 @@ function refinementFor(tool) {
5242
6085
  if (tool === "observe_ui" || tool === "expand_ui") return "use search_ui or expand a more specific ref";
5243
6086
  return "request a smaller or more focused result";
5244
6087
  }
5245
- function applyOutputEnvelope(tool, result) {
6088
+ function applyOutputEnvelope(tool, result, owner = COMPUTER_USE_STANDALONE_OWNER) {
5246
6089
  const textParts = result.content.filter((part) => part.type === "text");
5247
6090
  const combined = textParts.map((part) => part.text).join("\n");
5248
6091
  const bytes = new TextEncoder().encode(combined).byteLength;
5249
6092
  const lines = combined === "" ? 0 : combined.split("\n").length;
5250
6093
  if (bytes <= MODEL_TEXT_MAX_BYTES && lines <= MODEL_TEXT_MAX_LINES) return result;
5251
- const entry = storeOutput(combined);
6094
+ const entry = storeOutput(combined, owner);
5252
6095
  const preview = boundedPrefix(combined, MODEL_PREVIEW_BYTES, MODEL_TEXT_MAX_LINES - 4);
5253
6096
  const returnedBytes = new TextEncoder().encode(preview).byteLength;
5254
- const availability = entry.complete ? `continue: read_text({ ref: "${entry.ref}", offset: ${returnedBytes} })` : `continue: read_text({ ref: "${entry.ref}", offset: ${returnedBytes} }); only the first ${entry.storedBytes} bytes were stored, so refine for the remainder`;
6097
+ const availability = entry.complete ? `continue: computer-use-axi read --ref "${entry.ref}" --offset ${returnedBytes}` : `continue: computer-use-axi read --ref "${entry.ref}" --offset ${returnedBytes}; only the first ${entry.storedBytes} bytes were stored, so refine for the remainder`;
5255
6098
  const trailer = [
5256
6099
  `output truncated: returned ${returnedBytes} of ${entry.totalBytes} utf-8 bytes`,
5257
6100
  `refine: ${refinementFor(tool)}`,
@@ -5262,12 +6105,12 @@ function applyOutputEnvelope(tool, result) {
5262
6105
 
5263
6106
  ${trailer}` }, ...images] };
5264
6107
  }
5265
- function boundToolError(tool, error) {
6108
+ function boundToolError(tool, error, owner = COMPUTER_USE_STANDALONE_OWNER) {
5266
6109
  const message = error instanceof Error ? error.message : String(error);
5267
6110
  const bytes = new TextEncoder().encode(message).byteLength;
5268
6111
  const lines = message.split("\n").length;
5269
6112
  if (bytes <= MODEL_TEXT_MAX_BYTES && lines <= MODEL_TEXT_MAX_LINES) return error instanceof Error ? error : new Error(message);
5270
- const entry = storeOutput(message);
6113
+ const entry = storeOutput(message, owner);
5271
6114
  const preview = boundedPrefix(message, MODEL_PREVIEW_BYTES, MODEL_TEXT_MAX_LINES - 4);
5272
6115
  const returnedBytes = new TextEncoder().encode(preview).byteLength;
5273
6116
  const storageNote = entry.complete ? "" : `; only the first ${entry.storedBytes} bytes were stored`;
@@ -5275,19 +6118,19 @@ function boundToolError(tool, error) {
5275
6118
 
5276
6119
  error truncated: returned ${returnedBytes} of ${entry.totalBytes} utf-8 bytes
5277
6120
  refine: ${refinementFor(tool)}
5278
- continue: read_text({ ref: "${entry.ref}", offset: ${returnedBytes} })${storageNote}`);
6121
+ continue: computer-use-axi read --ref "${entry.ref}" --offset ${returnedBytes}${storageNote}`);
5279
6122
  }
5280
- function readStoredOutput(ref, offsetValue) {
6123
+ function readStoredOutput(ref, offsetValue, owner = COMPUTER_USE_STANDALONE_OWNER) {
5281
6124
  const entry = outputs.get(ref);
5282
- if (!entry) return void 0;
6125
+ if (!entry || entry.owner !== normalizeComputerUseOwner(owner)) return void 0;
5283
6126
  let offset = Math.min(entry.storedBytes, Math.max(0, Math.trunc(typeof offsetValue === "number" && Number.isFinite(offsetValue) ? offsetValue : 0)));
5284
6127
  const requestedBytes = Math.min(entry.storedBytes - offset, OUTPUT_PAGE_BYTES + 4);
5285
6128
  const buffer = new Uint8Array(Math.max(0, requestedBytes));
5286
- const fd = openSync(entry.filePath, "r");
6129
+ const fd = openSync2(entry.filePath, "r");
5287
6130
  try {
5288
6131
  if (buffer.byteLength > 0) readSync(fd, buffer, 0, buffer.byteLength, offset);
5289
6132
  } finally {
5290
- closeSync(fd);
6133
+ closeSync2(fd);
5291
6134
  }
5292
6135
  let start = 0;
5293
6136
  while (start < buffer.byteLength && (buffer[start] & 192) === 128) start += 1;
@@ -5303,56 +6146,52 @@ function readStoredOutput(ref, offsetValue) {
5303
6146
  complete: entry.complete
5304
6147
  };
5305
6148
  }
5306
- function clearStoredOutputs() {
5307
- outputs.clear();
5308
- if (outputDirectory) {
6149
+ function clearStoredOutputs(owner) {
6150
+ if (owner === void 0) {
6151
+ for (const entry of outputs.values()) {
6152
+ try {
6153
+ unlinkSync3(entry.filePath);
6154
+ } catch {
6155
+ }
6156
+ }
6157
+ outputs.clear();
6158
+ outputBytes = 0;
6159
+ return;
6160
+ }
6161
+ const normalized = normalizeComputerUseOwner(owner);
6162
+ for (const [ref, entry] of [...outputs.entries()]) {
6163
+ if (entry.owner !== normalized) continue;
6164
+ outputs.delete(ref);
6165
+ outputBytes = Math.max(0, outputBytes - entry.storedBytes);
5309
6166
  try {
5310
- rmSync(outputDirectory, { recursive: true, force: true });
6167
+ unlinkSync3(entry.filePath);
5311
6168
  } catch {
5312
6169
  }
5313
6170
  }
5314
- outputDirectory = void 0;
5315
- outputBytes = 0;
5316
- nextOutputId = 1;
5317
6171
  }
5318
6172
 
5319
- // builtin/extensions/computer-use/src/contract.ts
5320
- var AGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
5321
- "find_roots",
5322
- "read_text",
5323
- "wait_for",
5324
- "observe_ui",
5325
- "search_ui",
5326
- "expand_ui",
5327
- "inspect_ui",
5328
- "act_ui",
5329
- "navigate_browser",
5330
- "evaluate_browser",
5331
- "launch_browser"
5332
- ]);
5333
-
5334
- // builtin/extensions/computer-use/src/platform/macos/helper.ts
6173
+ // vendor/computer-use-axi/src/platform/macos/helper.ts
5335
6174
  import { spawn } from "node:child_process";
5336
6175
  import { constants as fsConstants2 } from "node:fs";
5337
6176
  import { access, mkdir, realpath } from "node:fs/promises";
5338
6177
  import net from "node:net";
5339
- import os3 from "node:os";
5340
- import path6 from "node:path";
5341
-
5342
- // builtin/extensions/computer-use/src/platform/macos/helper-path.mjs
5343
- import { accessSync, constants as fsConstants, existsSync as existsSync2 } from "node:fs";
5344
6178
  import os2 from "node:os";
5345
- import path4 from "node:path";
6179
+ import path9 from "node:path";
6180
+
6181
+ // vendor/computer-use-axi/src/platform/macos/helper-path.mjs
6182
+ import { accessSync, constants as fsConstants, existsSync as existsSync4 } from "node:fs";
6183
+ import os from "node:os";
6184
+ import path7 from "node:path";
5346
6185
  var HELPER_APP_NAME = "pie-computer-use.app";
5347
- var SYSTEM_HELPER_APP_PATH = path4.join("/Applications", HELPER_APP_NAME);
6186
+ var SYSTEM_HELPER_APP_PATH = path7.join("/Applications", HELPER_APP_NAME);
5348
6187
  function resolveMacosHelperAppPath(options = {}) {
5349
6188
  const env = options.env ?? process.env;
5350
6189
  const explicitPath = env.PIE_COMPUTER_USE_HELPER_APP_PATH?.trim();
5351
- if (explicitPath) return path4.resolve(explicitPath);
5352
- const homeDir = options.homeDir ?? os2.homedir();
6190
+ if (explicitPath) return path7.resolve(explicitPath);
6191
+ const homeDir = options.homeDir ?? os.homedir();
5353
6192
  const configDir = options.configDir ?? resolvePieConfigDir(env, homeDir);
5354
6193
  const systemHelperAppPath = options.systemHelperAppPath ?? SYSTEM_HELPER_APP_PATH;
5355
- const fileExists = options.fileExists ?? existsSync2;
6194
+ const fileExists = options.fileExists ?? existsSync4;
5356
6195
  const directoryIsWritable = options.directoryIsWritable ?? ((directoryPath) => {
5357
6196
  try {
5358
6197
  accessSync(directoryPath, fsConstants.W_OK);
@@ -5361,10 +6200,10 @@ function resolveMacosHelperAppPath(options = {}) {
5361
6200
  return false;
5362
6201
  }
5363
6202
  });
5364
- if (fileExists(systemHelperAppPath) && directoryIsWritable(path4.dirname(systemHelperAppPath))) {
6203
+ if (fileExists(systemHelperAppPath) && directoryIsWritable(path7.dirname(systemHelperAppPath))) {
5365
6204
  return systemHelperAppPath;
5366
6205
  }
5367
- return path4.join(configDir, "computer-use", HELPER_APP_NAME);
6206
+ return path7.join(configDir, "computer-use", HELPER_APP_NAME);
5368
6207
  }
5369
6208
  function resolvePieConfigDir(env, homeDir) {
5370
6209
  const envDir = env.PIE_CODING_AGENT_DIR;
@@ -5373,37 +6212,37 @@ function resolvePieConfigDir(env, homeDir) {
5373
6212
  if (envDir.startsWith("~/")) return homeDir + envDir.slice(1);
5374
6213
  return envDir;
5375
6214
  }
5376
- return path4.join(homeDir, ".pie");
6215
+ return path7.join(homeDir, ".pie");
5377
6216
  }
5378
6217
 
5379
- // builtin/extensions/computer-use/src/platform/package-root.ts
5380
- import { existsSync as existsSync3 } from "node:fs";
5381
- import path5 from "node:path";
5382
- import { fileURLToPath } from "node:url";
6218
+ // vendor/computer-use-axi/src/platform/package-root.ts
6219
+ import { existsSync as existsSync5 } from "node:fs";
6220
+ import path8 from "node:path";
6221
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
5383
6222
  function resolveExtensionRoot(moduleUrl) {
5384
6223
  const override = process.env.PIE_COMPUTER_USE_PACKAGE_ROOT?.trim();
5385
- if (override) return path5.resolve(override);
5386
- let dir = path5.dirname(fileURLToPath(moduleUrl));
6224
+ if (override) return path8.resolve(override);
6225
+ let dir = path8.dirname(fileURLToPath2(moduleUrl));
5387
6226
  for (let depth = 0; depth < 12; depth += 1) {
5388
- if (existsSync3(path5.join(dir, "scripts", "setup-helper.mjs"))) return dir;
5389
- const parent = path5.dirname(dir);
6227
+ if (existsSync5(path8.join(dir, "scripts", "setup-helper.mjs"))) return dir;
6228
+ const parent = path8.dirname(dir);
5390
6229
  if (parent === dir) break;
5391
6230
  dir = parent;
5392
6231
  }
5393
- throw new Error(`computer-use: could not locate extension root (scripts/setup-helper.mjs) above ${path5.dirname(fileURLToPath(moduleUrl))}. Set PIE_COMPUTER_USE_PACKAGE_ROOT.`);
6232
+ throw new Error(`computer-use: could not locate extension root (scripts/setup-helper.mjs) above ${path8.dirname(fileURLToPath2(moduleUrl))}. Set PIE_COMPUTER_USE_PACKAGE_ROOT.`);
5394
6233
  }
5395
6234
 
5396
- // builtin/extensions/computer-use/src/platform/macos/helper.ts
6235
+ // vendor/computer-use-axi/src/platform/macos/helper.ts
5397
6236
  var COMMAND_TIMEOUT_MS2 = 15e3;
5398
6237
  var HELPER_PROTOCOL_VERSION = 6;
5399
6238
  var HELPER_SETUP_TIMEOUT_MS = 6e4;
5400
6239
  var HELPER_APP_PATH = resolveMacosHelperAppPath();
5401
- var HELPER_APP_EXECUTABLE_PATH = path6.join(HELPER_APP_PATH, "Contents", "MacOS", "pie-computer-use");
5402
- var DEFAULT_HELPER_SOCKET_PATH = path6.join(os3.homedir(), "Library", "Caches", "pie-computer-use", "bridge.sock");
6240
+ var HELPER_APP_EXECUTABLE_PATH = path9.join(HELPER_APP_PATH, "Contents", "MacOS", "pie-computer-use");
6241
+ var DEFAULT_HELPER_SOCKET_PATH = path9.join(os2.homedir(), "Library", "Caches", "pie-computer-use", "bridge.sock");
5403
6242
  var HELPER_SOCKET_PATH = process.env.PIE_COMPUTER_USE_SOCKET_PATH ?? DEFAULT_HELPER_SOCKET_PATH;
5404
6243
  var usingExternalHelperSocket = HELPER_SOCKET_PATH !== DEFAULT_HELPER_SOCKET_PATH;
5405
6244
  var PACKAGE_ROOT = resolveExtensionRoot(import.meta.url);
5406
- var SETUP_HELPER_SCRIPT = path6.join(PACKAGE_ROOT, "scripts", "setup-helper.mjs");
6245
+ var SETUP_HELPER_SCRIPT = path9.join(PACKAGE_ROOT, "scripts", "setup-helper.mjs");
5407
6246
  var HelperTransportError = class extends Error {
5408
6247
  constructor(message) {
5409
6248
  super(message);
@@ -5423,8 +6262,8 @@ function throwIfAborted(signal) {
5423
6262
  }
5424
6263
  async function sleep(ms, signal) {
5425
6264
  throwIfAborted(signal);
5426
- await new Promise((resolve, reject) => {
5427
- const timer = setTimeout(resolve, ms);
6265
+ await new Promise((resolve2, reject) => {
6266
+ const timer = setTimeout(resolve2, ms);
5428
6267
  const onAbort = () => {
5429
6268
  clearTimeout(timer);
5430
6269
  reject(new Error("Operation aborted."));
@@ -5443,14 +6282,14 @@ async function isExecutable(filePath) {
5443
6282
  async function isResolvedHelperExecutable(filePath) {
5444
6283
  if (!filePath) return true;
5445
6284
  const [actualPath, expectedPath] = await Promise.all([
5446
- realpath(filePath).catch(() => path6.resolve(filePath)),
5447
- realpath(HELPER_APP_EXECUTABLE_PATH).catch(() => path6.resolve(HELPER_APP_EXECUTABLE_PATH))
6285
+ realpath(filePath).catch(() => path9.resolve(filePath)),
6286
+ realpath(HELPER_APP_EXECUTABLE_PATH).catch(() => path9.resolve(HELPER_APP_EXECUTABLE_PATH))
5448
6287
  ]);
5449
6288
  return actualPath === expectedPath;
5450
6289
  }
5451
6290
  async function runProcess(command, args, timeoutMs, signal, env) {
5452
6291
  throwIfAborted(signal);
5453
- await new Promise((resolve, reject) => {
6292
+ await new Promise((resolve2, reject) => {
5454
6293
  const child = spawn(command, args, {
5455
6294
  stdio: ["ignore", "pipe", "pipe"],
5456
6295
  env
@@ -5484,7 +6323,7 @@ async function runProcess(command, args, timeoutMs, signal, env) {
5484
6323
  child.on("close", (code) => {
5485
6324
  cleanup();
5486
6325
  if (code === 0) {
5487
- resolve();
6326
+ resolve2();
5488
6327
  return;
5489
6328
  }
5490
6329
  const output = [stderr.trim(), stdout.trim()].filter(Boolean).join("\n");
@@ -5517,11 +6356,11 @@ var MacosHelperClient = class {
5517
6356
  }
5518
6357
  async launchDaemon(signal) {
5519
6358
  if (usingExternalHelperSocket) throw new HelperTransportError(`External helper socket is unavailable at ${HELPER_SOCKET_PATH}.`);
5520
- await mkdir(path6.dirname(HELPER_SOCKET_PATH), { recursive: true });
6359
+ await mkdir(path9.dirname(HELPER_SOCKET_PATH), { recursive: true });
5521
6360
  await runProcess("open", ["-n", "-g", HELPER_APP_PATH, "--args", "serve", "--socket", HELPER_SOCKET_PATH], COMMAND_TIMEOUT_MS2, signal);
5522
6361
  }
5523
6362
  async daemonCommand(cmd, args, timeoutMs, signal) {
5524
- return await new Promise((resolve, reject) => {
6363
+ return await new Promise((resolve2, reject) => {
5525
6364
  const id = `req_${++this.requestSequence}`;
5526
6365
  const socket = net.createConnection(HELPER_SOCKET_PATH);
5527
6366
  let buffer = "";
@@ -5550,7 +6389,7 @@ var MacosHelperClient = class {
5550
6389
  socket.end();
5551
6390
  try {
5552
6391
  const parsed = JSON.parse(buffer.slice(0, newline));
5553
- if (parsed.ok === true) resolve(parsed.result);
6392
+ if (parsed.ok === true) resolve2(parsed.result);
5554
6393
  else reject(new HelperCommandError(parsed?.error?.message ?? `Daemon command '${cmd}' failed.`, parsed?.error?.code));
5555
6394
  } catch (error) {
5556
6395
  reject(error);
@@ -5640,7 +6479,7 @@ var MacosHelperClient = class {
5640
6479
  };
5641
6480
  var macosHelper = new MacosHelperClient();
5642
6481
 
5643
- // builtin/extensions/computer-use/src/platform/macos/backend.ts
6482
+ // vendor/computer-use-axi/src/platform/macos/backend.ts
5644
6483
  function parseApps(result) {
5645
6484
  const array = Array.isArray(result) ? result : result?.apps;
5646
6485
  if (!Array.isArray(array)) return [];
@@ -5751,7 +6590,7 @@ var macosBackend = {
5751
6590
  }
5752
6591
  };
5753
6592
 
5754
- // builtin/extensions/computer-use/src/platform/macos/browser.ts
6593
+ // vendor/computer-use-axi/src/platform/macos/browser.ts
5755
6594
  var BROWSER_WINDOW_OPEN_TIMEOUT_MS = 1e4;
5756
6595
  var BROWSER_BUNDLE_IDS = /* @__PURE__ */ new Set([
5757
6596
  "com.apple.Safari",
@@ -5849,7 +6688,7 @@ async function openBrowserLocationWithAppleScript(target, url, signal) {
5849
6688
  }
5850
6689
  }
5851
6690
 
5852
- // builtin/extensions/computer-use/src/permissions.ts
6691
+ // vendor/computer-use-axi/src/permissions.ts
5853
6692
  function throwIfAborted2(signal) {
5854
6693
  if (signal?.aborted) throw new Error("Operation aborted.");
5855
6694
  }
@@ -5892,7 +6731,7 @@ async function ensurePermissions(ctx, bridge, helperPath, signal) {
5892
6731
  return status;
5893
6732
  }
5894
6733
 
5895
- // builtin/extensions/computer-use/src/platform/architecture.ts
6734
+ // vendor/computer-use-axi/src/platform/architecture.ts
5896
6735
  var PLATFORM_ARCHITECTURE_VERSION = 1;
5897
6736
  var REQUIRED_PLATFORM_INVARIANTS = [
5898
6737
  "state-scoped-observations",
@@ -5914,7 +6753,7 @@ function assertPlatformArchitecture(platform, diagnostics) {
5914
6753
  }
5915
6754
  }
5916
6755
 
5917
- // builtin/extensions/computer-use/src/platform/macos/permissions.ts
6756
+ // vendor/computer-use-axi/src/platform/macos/permissions.ts
5918
6757
  var GRANT_INSTRUCTIONS = "Grant Accessibility and Screen Recording to pie-computer-use.app in System Settings \u2192 Privacy & Security. Screen Recording lets the agent see the window; Accessibility lets it interact with the window.";
5919
6758
  var SIGNING_MIGRATION_WARNING = "If these permissions were enabled before this install/update, macOS invalidated the old grants because pie-computer-use.app was re-signed. Re-enable both toggles for the newly signed helper. If a toggle is already on, switch it off and on again.";
5920
6759
  var macosPermissionKinds = [
@@ -6033,18 +6872,18 @@ Helper path: ${helperPath}`,
6033
6872
  return { permissionStatus, lastPermissionCheckAt, helperDiagnostics };
6034
6873
  }
6035
6874
 
6036
- // builtin/extensions/computer-use/src/platform/linux/helper.ts
6875
+ // vendor/computer-use-axi/src/platform/linux/helper.ts
6037
6876
  import { spawn as spawn2 } from "node:child_process";
6038
- import { randomUUID as randomUUID2 } from "node:crypto";
6877
+ import { randomUUID as randomUUID4 } from "node:crypto";
6039
6878
  import { constants as fsConstants3 } from "node:fs";
6040
6879
  import { access as access2 } from "node:fs/promises";
6041
- import path7 from "node:path";
6880
+ import path10 from "node:path";
6042
6881
  var PACKAGE_ROOT2 = resolveExtensionRoot(import.meta.url);
6043
- var SETUP_HELPER_SCRIPT2 = path7.join(PACKAGE_ROOT2, "scripts", "setup-helper.mjs");
6882
+ var SETUP_HELPER_SCRIPT2 = path10.join(PACKAGE_ROOT2, "scripts", "setup-helper.mjs");
6044
6883
  var HELPER_SETUP_TIMEOUT_MS2 = 6e4;
6045
6884
  var COMMAND_TIMEOUT_MS3 = 15e3;
6046
6885
  var LINUX_HELPER_PROTOCOL_VERSION = 4;
6047
- var LINUX_HELPER_PATH = process.env.PIE_COMPUTER_USE_LINUX_HELPER_PATH || path7.join(getAgentDir(), "helpers", "computer-use", "linux-bridge");
6886
+ var LINUX_HELPER_PATH = process.env.PIE_COMPUTER_USE_LINUX_HELPER_PATH || path10.join(getAgentDir(), "helpers", "computer-use", "linux-bridge");
6048
6887
  async function isExecutable2(filePath) {
6049
6888
  try {
6050
6889
  await access2(filePath, fsConstants3.X_OK);
@@ -6055,7 +6894,7 @@ async function isExecutable2(filePath) {
6055
6894
  }
6056
6895
  async function runProcess2(command, args, timeoutMs, signal, env) {
6057
6896
  if (signal?.aborted) throw new Error("Operation aborted.");
6058
- await new Promise((resolve, reject) => {
6897
+ await new Promise((resolve2, reject) => {
6059
6898
  const child = spawn2(command, args, { stdio: ["ignore", "pipe", "pipe"], env });
6060
6899
  let stdout = "";
6061
6900
  let stderr = "";
@@ -6066,7 +6905,7 @@ async function runProcess2(command, args, timeoutMs, signal, env) {
6066
6905
  clearTimeout(timer);
6067
6906
  signal?.removeEventListener("abort", onAbort);
6068
6907
  if (error) reject(error);
6069
- else resolve();
6908
+ else resolve2();
6070
6909
  };
6071
6910
  const timer = setTimeout(() => {
6072
6911
  child.kill("SIGTERM");
@@ -6095,13 +6934,13 @@ ${output}`.trim()));
6095
6934
  async function waitForShared(promise, signal) {
6096
6935
  if (!signal) return await promise;
6097
6936
  if (signal.aborted) throw new Error("Operation aborted.");
6098
- return await new Promise((resolve, reject) => {
6937
+ return await new Promise((resolve2, reject) => {
6099
6938
  const onAbort = () => reject(new Error("Operation aborted."));
6100
6939
  signal.addEventListener("abort", onAbort, { once: true });
6101
6940
  promise.then(
6102
6941
  (value) => {
6103
6942
  signal.removeEventListener("abort", onAbort);
6104
- resolve(value);
6943
+ resolve2(value);
6105
6944
  },
6106
6945
  (error) => {
6107
6946
  signal.removeEventListener("abort", onAbort);
@@ -6203,8 +7042,8 @@ var LinuxHelperClient = class {
6203
7042
  });
6204
7043
  this.child = child;
6205
7044
  this.buffer = "";
6206
- return await new Promise((resolve, reject) => {
6207
- child.once("spawn", () => resolve(child));
7045
+ return await new Promise((resolve2, reject) => {
7046
+ child.once("spawn", () => resolve2(child));
6208
7047
  child.once("error", reject);
6209
7048
  });
6210
7049
  }
@@ -6239,9 +7078,9 @@ var LinuxHelperClient = class {
6239
7078
  }
6240
7079
  async command(cmd, args = {}, options) {
6241
7080
  const child = await this.process(options?.signal);
6242
- const id = randomUUID2();
7081
+ const id = randomUUID4();
6243
7082
  const timeoutMs = options?.timeoutMs ?? COMMAND_TIMEOUT_MS3;
6244
- return await new Promise((resolve, reject) => {
7083
+ return await new Promise((resolve2, reject) => {
6245
7084
  const onAbort = () => {
6246
7085
  this.pending.delete(id);
6247
7086
  clearTimeout(timer);
@@ -6255,7 +7094,7 @@ var LinuxHelperClient = class {
6255
7094
  this.pending.set(id, {
6256
7095
  resolve: (value) => {
6257
7096
  options?.signal?.removeEventListener("abort", onAbort);
6258
- resolve(value);
7097
+ resolve2(value);
6259
7098
  },
6260
7099
  reject: (error) => {
6261
7100
  options?.signal?.removeEventListener("abort", onAbort);
@@ -6277,7 +7116,7 @@ var LinuxHelperClient = class {
6277
7116
  };
6278
7117
  var linuxHelper = new LinuxHelperClient();
6279
7118
 
6280
- // builtin/extensions/computer-use/src/platform/linux/backend.ts
7119
+ // vendor/computer-use-axi/src/platform/linux/backend.ts
6281
7120
  function normalizedProcessName(appName) {
6282
7121
  return appName.toLowerCase().split("/").pop().replace(/\.desktop$/i, "");
6283
7122
  }
@@ -6433,18 +7272,18 @@ var linuxBackend = {
6433
7272
  }
6434
7273
  };
6435
7274
 
6436
- // builtin/extensions/computer-use/src/platform/windows/helper.ts
7275
+ // vendor/computer-use-axi/src/platform/windows/helper.ts
6437
7276
  import { spawn as spawn3 } from "node:child_process";
6438
- import { randomUUID as randomUUID3 } from "node:crypto";
7277
+ import { randomUUID as randomUUID5 } from "node:crypto";
6439
7278
  import { constants as fsConstants4 } from "node:fs";
6440
7279
  import { access as access3 } from "node:fs/promises";
6441
- import path8 from "node:path";
7280
+ import path11 from "node:path";
6442
7281
  var PACKAGE_ROOT3 = resolveExtensionRoot(import.meta.url);
6443
- var SETUP_HELPER_SCRIPT3 = path8.join(PACKAGE_ROOT3, "scripts", "setup-helper.mjs");
7282
+ var SETUP_HELPER_SCRIPT3 = path11.join(PACKAGE_ROOT3, "scripts", "setup-helper.mjs");
6444
7283
  var HELPER_SETUP_TIMEOUT_MS3 = 6e4;
6445
7284
  var COMMAND_TIMEOUT_MS4 = 15e3;
6446
7285
  var WINDOWS_HELPER_PROTOCOL_VERSION = 4;
6447
- var WINDOWS_HELPER_PATH = process.env.PIE_COMPUTER_USE_WINDOWS_HELPER_PATH || path8.join(getAgentDir(), "helpers", "computer-use", "windows-bridge.exe");
7286
+ var WINDOWS_HELPER_PATH = process.env.PIE_COMPUTER_USE_WINDOWS_HELPER_PATH || path11.join(getAgentDir(), "helpers", "computer-use", "windows-bridge.exe");
6448
7287
  async function isExecutable3(filePath) {
6449
7288
  try {
6450
7289
  await access3(filePath, fsConstants4.X_OK);
@@ -6455,7 +7294,7 @@ async function isExecutable3(filePath) {
6455
7294
  }
6456
7295
  async function runProcess3(command, args, timeoutMs, signal, env) {
6457
7296
  if (signal?.aborted) throw new Error("Operation aborted.");
6458
- await new Promise((resolve, reject) => {
7297
+ await new Promise((resolve2, reject) => {
6459
7298
  const child = spawn3(command, args, { stdio: ["ignore", "pipe", "pipe"], env });
6460
7299
  let stdout = "";
6461
7300
  let stderr = "";
@@ -6485,7 +7324,7 @@ async function runProcess3(command, args, timeoutMs, signal, env) {
6485
7324
  });
6486
7325
  child.on("close", (code) => {
6487
7326
  cleanup();
6488
- if (code === 0) return resolve();
7327
+ if (code === 0) return resolve2();
6489
7328
  const output = [stderr.trim(), stdout.trim()].filter(Boolean).join("\n");
6490
7329
  reject(new Error(`Command failed (${code}): ${command} ${args.join(" ")}
6491
7330
  ${output}`.trim()));
@@ -6570,14 +7409,14 @@ var WindowsHelperClient = class {
6570
7409
  }
6571
7410
  async command(cmd, args = {}, options) {
6572
7411
  const child = await this.process(options?.signal);
6573
- const id = randomUUID3();
7412
+ const id = randomUUID5();
6574
7413
  const timeoutMs = options?.timeoutMs ?? COMMAND_TIMEOUT_MS4;
6575
- return await new Promise((resolve, reject) => {
7414
+ return await new Promise((resolve2, reject) => {
6576
7415
  const timer = setTimeout(() => {
6577
7416
  this.pending.delete(id);
6578
7417
  reject(new Error(`Helper command '${cmd}' timed out after ${timeoutMs}ms.`));
6579
7418
  }, timeoutMs);
6580
- this.pending.set(id, { resolve, reject, timer });
7419
+ this.pending.set(id, { resolve: resolve2, reject, timer });
6581
7420
  child.stdin.write(`${JSON.stringify({ protocolVersion: WINDOWS_HELPER_PROTOCOL_VERSION, id, cmd, args })}
6582
7421
  `, (error) => {
6583
7422
  if (!error) return;
@@ -6590,7 +7429,7 @@ var WindowsHelperClient = class {
6590
7429
  };
6591
7430
  var windowsHelper = new WindowsHelperClient();
6592
7431
 
6593
- // builtin/extensions/computer-use/src/platform/windows/backend.ts
7432
+ // vendor/computer-use-axi/src/platform/windows/backend.ts
6594
7433
  function normalizedProcessName2(appName) {
6595
7434
  return appName.toLowerCase().replace(/\.exe$/i, "");
6596
7435
  }
@@ -6726,7 +7565,7 @@ var windowsBackend = {
6726
7565
  }
6727
7566
  };
6728
7567
 
6729
- // builtin/extensions/computer-use/src/platform/index.ts
7568
+ // vendor/computer-use-axi/src/platform/index.ts
6730
7569
  var macosPlatformBackend = {
6731
7570
  name: "macos",
6732
7571
  ensureReady: ensureMacosReady,
@@ -6797,9 +7636,14 @@ function platformBackendForRuntime(platform = process.platform) {
6797
7636
  return new UnsupportedPlatformBackend(platform);
6798
7637
  }
6799
7638
  var currentPlatformBackend = platformBackendForRuntime();
7639
+ var backendOverrideInstalled = false;
7640
+ function setPlatformBackend(backend) {
7641
+ currentPlatformBackend = backend;
7642
+ backendOverrideInstalled = true;
7643
+ }
6800
7644
 
6801
- // builtin/extensions/computer-use/src/runtime.ts
6802
- import { randomUUID as randomUUID4 } from "node:crypto";
7645
+ // vendor/computer-use-axi/src/runtime.ts
7646
+ import { randomUUID as randomUUID6 } from "node:crypto";
6803
7647
  var StaleResourceStateError = class extends Error {
6804
7648
  constructor(resourceKey, expectedEpoch, actualEpoch) {
6805
7649
  super(`State is stale for ${resourceKey}: expected epoch ${expectedEpoch}, current epoch ${actualEpoch}.`);
@@ -6812,14 +7656,22 @@ var StaleResourceStateError = class extends Error {
6812
7656
  expectedEpoch;
6813
7657
  actualEpoch;
6814
7658
  };
7659
+ var OperationAbortedError = class extends Error {
7660
+ constructor() {
7661
+ super("Operation cancelled before dispatch.");
7662
+ this.name = "OperationAbortedError";
7663
+ }
7664
+ };
6815
7665
  var StateStore = class {
6816
- constructor(limit = 128) {
7666
+ constructor(limit = 128, onEvict) {
6817
7667
  this.limit = limit;
7668
+ this.onEvict = onEvict;
6818
7669
  }
6819
7670
  limit;
7671
+ onEvict;
6820
7672
  records = /* @__PURE__ */ new Map();
6821
- create(resourceKey, epoch, value) {
6822
- const record = { stateId: randomUUID4(), resourceKey, epoch, value };
7673
+ create(resourceKey, epoch, value, meta = {}) {
7674
+ const record = { stateId: randomUUID6(), resourceKey, epoch, value, ...meta };
6823
7675
  this.set(record);
6824
7676
  return record;
6825
7677
  }
@@ -6829,12 +7681,25 @@ var StateStore = class {
6829
7681
  while (this.records.size > this.limit) {
6830
7682
  const oldest = this.records.keys().next().value;
6831
7683
  if (!oldest) break;
7684
+ const evicted = this.records.get(oldest);
6832
7685
  this.records.delete(oldest);
7686
+ if (evicted) this.onEvict?.(evicted);
6833
7687
  }
6834
7688
  }
6835
7689
  get(stateId2) {
6836
7690
  return this.records.get(stateId2);
6837
7691
  }
7692
+ ids() {
7693
+ return [...this.records.keys()];
7694
+ }
7695
+ /** Owner probes exist only to distinguish "expired for this owner" from
7696
+ * "unknown id" in diagnostics; they never return the value. */
7697
+ ownerOf(stateId2) {
7698
+ return this.records.get(stateId2)?.owner;
7699
+ }
7700
+ drop(stateId2) {
7701
+ return this.records.delete(stateId2);
7702
+ }
6838
7703
  clear() {
6839
7704
  this.records.clear();
6840
7705
  }
@@ -6843,8 +7708,15 @@ var StateStore = class {
6843
7708
  }
6844
7709
  };
6845
7710
  var ResourceScheduler = class {
7711
+ constructor(hooks = {}) {
7712
+ this.hooks = hooks;
7713
+ }
7714
+ hooks;
6846
7715
  resources = /* @__PURE__ */ new Map();
6847
7716
  closed = false;
7717
+ epochs() {
7718
+ return [...this.resources.entries()].map(([key, record]) => [key, record.epoch]);
7719
+ }
6848
7720
  epoch(resourceKey) {
6849
7721
  return this.resource(resourceKey).epoch;
6850
7722
  }
@@ -6852,22 +7724,23 @@ var ResourceScheduler = class {
6852
7724
  const record = this.resource(resourceKey);
6853
7725
  record.epoch = Math.max(record.epoch, Math.max(0, Math.trunc(epoch)));
6854
7726
  }
6855
- async read(resourceKey, work) {
6856
- return await this.enqueue(resourceKey, async (record) => ({ value: await work(record.epoch), epoch: record.epoch }));
7727
+ async read(resourceKey, work, signal) {
7728
+ return await this.enqueue(resourceKey, async (record) => ({ value: await work(record.epoch), epoch: record.epoch }), signal);
6857
7729
  }
6858
- async readAt(resourceKey, expectedEpoch, work) {
7730
+ async readAt(resourceKey, expectedEpoch, work, signal) {
6859
7731
  return await this.enqueue(resourceKey, async (record) => {
6860
7732
  if (record.epoch !== expectedEpoch) throw new StaleResourceStateError(resourceKey, expectedEpoch, record.epoch);
6861
7733
  return { value: await work(record.epoch), epoch: record.epoch };
6862
- });
7734
+ }, signal);
6863
7735
  }
6864
- async write(resourceKey, baseEpoch, work) {
7736
+ async write(resourceKey, baseEpoch, work, signal) {
6865
7737
  return await this.enqueue(resourceKey, async (record) => {
6866
7738
  if (record.epoch !== baseEpoch) throw new StaleResourceStateError(resourceKey, baseEpoch, record.epoch);
6867
7739
  const nextEpoch = record.epoch + 1;
6868
7740
  record.epoch = nextEpoch;
7741
+ this.hooks.onEpochChange?.(resourceKey, nextEpoch);
6869
7742
  return { value: await work(nextEpoch), epoch: nextEpoch };
6870
- });
7743
+ }, signal);
6871
7744
  }
6872
7745
  async drain() {
6873
7746
  await Promise.all([...this.resources.values()].map((record) => record.tail.catch(() => void 0)));
@@ -6885,17 +7758,22 @@ var ResourceScheduler = class {
6885
7758
  }
6886
7759
  return record;
6887
7760
  }
6888
- async enqueue(resourceKey, work) {
7761
+ async enqueue(resourceKey, work, signal) {
6889
7762
  if (this.closed) throw new Error("Computer-use session is shutting down.");
6890
7763
  const record = this.resource(resourceKey);
6891
7764
  const previous = record.tail;
6892
7765
  let release;
6893
- const next = new Promise((resolve) => {
6894
- release = resolve;
7766
+ const next = new Promise((resolve2) => {
7767
+ release = resolve2;
6895
7768
  });
6896
7769
  record.tail = previous.catch(() => void 0).then(() => next);
6897
- await previous.catch(() => void 0);
7770
+ if (signal?.aborted) {
7771
+ release();
7772
+ throw new OperationAbortedError();
7773
+ }
6898
7774
  try {
7775
+ await previous.catch(() => void 0);
7776
+ if (signal?.aborted) throw new OperationAbortedError();
6899
7777
  if (this.closed) throw new Error("Computer-use session is shutting down.");
6900
7778
  return await work(record);
6901
7779
  } finally {
@@ -6903,28 +7781,108 @@ var ResourceScheduler = class {
6903
7781
  }
6904
7782
  }
6905
7783
  };
6906
-
6907
- // builtin/extensions/computer-use/src/browser-owner.ts
6908
- import { execFile } from "node:child_process";
6909
- import { rm } from "node:fs/promises";
6910
- import os4 from "node:os";
6911
- import path9 from "node:path";
6912
- async function requestBrowserClose(port) {
6913
- const response = await fetch(`http://127.0.0.1:${port}/json/version`, { signal: AbortSignal.timeout(500) });
6914
- const data = await response.json();
6915
- if (!data.webSocketDebuggerUrl) return;
6916
- const url = new URL(data.webSocketDebuggerUrl);
6917
- if (url.hostname !== "127.0.0.1" && url.hostname !== "localhost") throw new Error("Owned browser exposed a non-local debugger.");
6918
- if (url.port !== port) throw new Error("Owned browser debugger port changed.");
6919
- await new Promise((resolve) => {
6920
- const ws = new wrapper_default(url);
6921
- let done = false;
6922
- const finish = () => {
6923
- if (done) return;
7784
+ var OwnerScopedMap = class {
7785
+ constructor(scope) {
7786
+ this.scope = scope;
7787
+ }
7788
+ scope;
7789
+ maps = /* @__PURE__ */ new Map();
7790
+ owner() {
7791
+ const owner = this.scope.currentOwner();
7792
+ return owner || COMPUTER_USE_STANDALONE_OWNER;
7793
+ }
7794
+ map() {
7795
+ const owner = this.owner();
7796
+ let map = this.maps.get(owner);
7797
+ if (!map) {
7798
+ map = /* @__PURE__ */ new Map();
7799
+ this.maps.set(owner, map);
7800
+ }
7801
+ return map;
7802
+ }
7803
+ get(key) {
7804
+ return this.map().get(key);
7805
+ }
7806
+ has(key) {
7807
+ return this.map().has(key);
7808
+ }
7809
+ set(key, value) {
7810
+ this.map().set(key, value);
7811
+ return this;
7812
+ }
7813
+ delete(key) {
7814
+ return this.map().delete(key);
7815
+ }
7816
+ values() {
7817
+ return this.map().values();
7818
+ }
7819
+ entries() {
7820
+ return this.map().entries();
7821
+ }
7822
+ clear() {
7823
+ this.map().clear();
7824
+ }
7825
+ clearAll() {
7826
+ this.maps.clear();
7827
+ }
7828
+ owners() {
7829
+ return [...this.maps.keys()];
7830
+ }
7831
+ };
7832
+ var OwnerScopedCounter = class {
7833
+ constructor(scope, initial = 1) {
7834
+ this.scope = scope;
7835
+ this.initial = initial;
7836
+ }
7837
+ scope;
7838
+ initial;
7839
+ counters = /* @__PURE__ */ new Map();
7840
+ owner() {
7841
+ const owner = this.scope.currentOwner();
7842
+ return owner || COMPUTER_USE_STANDALONE_OWNER;
7843
+ }
7844
+ next() {
7845
+ const owner = this.owner();
7846
+ const value = this.counters.get(owner) ?? this.initial;
7847
+ this.counters.set(owner, value + 1);
7848
+ return value;
7849
+ }
7850
+ current() {
7851
+ return this.counters.get(this.owner()) ?? this.initial;
7852
+ }
7853
+ raiseAtLeast(value) {
7854
+ const owner = this.owner();
7855
+ this.counters.set(owner, Math.max(this.counters.get(owner) ?? this.initial, Math.trunc(value)));
7856
+ }
7857
+ clear() {
7858
+ this.counters.delete(this.owner());
7859
+ }
7860
+ clearAll() {
7861
+ this.counters.clear();
7862
+ }
7863
+ };
7864
+
7865
+ // vendor/computer-use-axi/src/browser-owner.ts
7866
+ import { execFile } from "node:child_process";
7867
+ import { rm } from "node:fs/promises";
7868
+ import os3 from "node:os";
7869
+ import path12 from "node:path";
7870
+ async function requestBrowserClose(port) {
7871
+ const response = await fetch(`http://127.0.0.1:${port}/json/version`, { signal: AbortSignal.timeout(500) });
7872
+ const data = await response.json();
7873
+ if (!data.webSocketDebuggerUrl) return;
7874
+ const url = new URL(data.webSocketDebuggerUrl);
7875
+ if (url.hostname !== "127.0.0.1" && url.hostname !== "localhost") throw new Error("Owned browser exposed a non-local debugger.");
7876
+ if (url.port !== port) throw new Error("Owned browser debugger port changed.");
7877
+ await new Promise((resolve2) => {
7878
+ const ws = new wrapper_default(url);
7879
+ let done = false;
7880
+ const finish = () => {
7881
+ if (done) return;
6924
7882
  done = true;
6925
7883
  clearTimeout(timer);
6926
7884
  ws.terminate();
6927
- resolve();
7885
+ resolve2();
6928
7886
  };
6929
7887
  const timer = setTimeout(finish, 700);
6930
7888
  ws.on("open", () => ws.send(JSON.stringify({ id: 1, method: "Browser.close" })));
@@ -6935,15 +7893,15 @@ async function requestBrowserClose(port) {
6935
7893
  }
6936
7894
  async function waitForExit(child, timeoutMs) {
6937
7895
  if (child.exitCode !== null || child.signalCode !== null) return true;
6938
- return new Promise((resolve) => {
7896
+ return new Promise((resolve2) => {
6939
7897
  const finish = () => {
6940
7898
  clearTimeout(timer);
6941
7899
  child.off("exit", finish);
6942
- resolve(true);
7900
+ resolve2(true);
6943
7901
  };
6944
7902
  const timer = setTimeout(() => {
6945
7903
  child.off("exit", finish);
6946
- resolve(false);
7904
+ resolve2(false);
6947
7905
  }, timeoutMs);
6948
7906
  child.once("exit", finish);
6949
7907
  });
@@ -6954,11 +7912,11 @@ async function releaseOwnedBrowser(child, port, profile) {
6954
7912
  if (!await waitForExit(child, 700)) {
6955
7913
  if (process.platform === "win32" && child.pid) {
6956
7914
  const pid = child.pid;
6957
- await new Promise((resolve) => {
7915
+ await new Promise((resolve2) => {
6958
7916
  execFile("taskkill.exe", ["/PID", String(pid), "/T", "/F"], {
6959
7917
  windowsHide: true,
6960
7918
  timeout: 2e3
6961
- }, () => resolve());
7919
+ }, () => resolve2());
6962
7920
  });
6963
7921
  if (!await waitForExit(child, 1500)) {
6964
7922
  try {
@@ -6979,8 +7937,8 @@ async function releaseOwnedBrowser(child, port, profile) {
6979
7937
  }
6980
7938
  }
6981
7939
  if (profile) {
6982
- const resolved = path9.resolve(profile);
6983
- if (path9.dirname(resolved) !== path9.resolve(os4.tmpdir()) || !/^pie-(chrome|helium)-cdp-/.test(path9.basename(resolved))) {
7940
+ const resolved = path12.resolve(profile);
7941
+ if (path12.dirname(resolved) !== path12.resolve(os3.tmpdir()) || !/^pie-(chrome|helium)-cdp-/.test(path12.basename(resolved))) {
6984
7942
  throw new Error("Refusing to remove a profile outside the owned temporary browser directory.");
6985
7943
  }
6986
7944
  await rm(resolved, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
@@ -6992,7 +7950,7 @@ async function releaseOwnedBrowserState(owner) {
6992
7950
  owner.managedBrowserProfileDir = void 0;
6993
7951
  }
6994
7952
 
6995
- // builtin/extensions/computer-use/src/root-selection.ts
7953
+ // vendor/computer-use-axi/src/root-selection.ts
6996
7954
  function scoreWindow(window) {
6997
7955
  let score = 0;
6998
7956
  if (window.isModal) score += 180;
@@ -7011,11 +7969,14 @@ function shouldPreferForegroundModalWindow(current, candidate) {
7011
7969
  return candidateIsInFront && scoreWindow(candidate) >= scoreWindow(current);
7012
7970
  }
7013
7971
 
7014
- // builtin/extensions/computer-use/src/state.ts
7972
+ // vendor/computer-use-axi/src/state.ts
7015
7973
  import { AsyncLocalStorage } from "node:async_hooks";
7016
7974
  var SavedStates = class {
7017
- store = new StateStore(128);
7975
+ store;
7018
7976
  operations = new AsyncLocalStorage();
7977
+ constructor(store = new StateStore(128)) {
7978
+ this.store = store;
7979
+ }
7019
7980
  current() {
7020
7981
  const state = this.operations.getStore();
7021
7982
  if (!state) throw new Error("Computer-use operation state is unavailable.");
@@ -7047,6 +8008,9 @@ var SavedStates = class {
7047
8008
  currentOutline: outline2,
7048
8009
  resourceKey: record.resourceKey,
7049
8010
  epoch: record.epoch,
8011
+ owner: record.owner,
8012
+ generation: record.generation,
8013
+ helperGeneration: record.helperGeneration,
7050
8014
  browserSnapshot: record.value.snapshot,
7051
8015
  contextId: record.value.snapshot.contextId
7052
8016
  };
@@ -7061,7 +8025,10 @@ var SavedStates = class {
7061
8025
  currentOutline: outline,
7062
8026
  currentNote: record.value.note ? structuredClone(record.value.note) : void 0,
7063
8027
  resourceKey: record.resourceKey,
7064
- epoch: record.epoch
8028
+ epoch: record.epoch,
8029
+ owner: record.owner,
8030
+ generation: record.generation,
8031
+ helperGeneration: record.helperGeneration
7065
8032
  };
7066
8033
  }
7067
8034
  saveDesktop(state, resourceKey, epoch) {
@@ -7070,6 +8037,9 @@ var SavedStates = class {
7070
8037
  stateId: state.currentCapture.stateId,
7071
8038
  resourceKey,
7072
8039
  epoch,
8040
+ owner: state.owner,
8041
+ generation: state.generation,
8042
+ helperGeneration: state.helperGeneration,
7073
8043
  value: {
7074
8044
  kind: "desktop",
7075
8045
  target: { ...state.currentTarget },
@@ -7090,7 +8060,7 @@ var SavedStates = class {
7090
8060
  }
7091
8061
  };
7092
8062
 
7093
- // builtin/extensions/computer-use/src/view.ts
8063
+ // vendor/computer-use-axi/src/view.ts
7094
8064
  function numericRef(ref) {
7095
8065
  const match = /^@e(\d+)$/.exec(ref);
7096
8066
  return match ? Number(match[1]) : 0;
@@ -7226,7 +8196,7 @@ function renderChanges(changes) {
7226
8196
  }).join("\n");
7227
8197
  }
7228
8198
 
7229
- // builtin/extensions/computer-use/src/bridge.ts
8199
+ // vendor/computer-use-axi/src/bridge.ts
7230
8200
  var MISSING_TARGET_ERROR = "No current controlled window. Call observe_ui first to choose a target window.";
7231
8201
  var CURRENT_TARGET_GONE_ERROR = "The current controlled window is no longer available. Call observe_ui to choose a new target window.";
7232
8202
  var COMMAND_TIMEOUT_MS5 = 15e3;
@@ -7237,17 +8207,51 @@ var MANAGED_BROWSER_READY_TIMEOUT_MS = 15e3;
7237
8207
  var AUTO_IMAGE_MAX_DIMENSION = 900;
7238
8208
  var EXPLICIT_IMAGE_MAX_DIMENSION = 1600;
7239
8209
  var BROWSER_TRANSACTION_ACTIONS = /* @__PURE__ */ new Set(["press", "click", "setText", "typeText", "keypress", "scroll", "drag", "moveMouse"]);
8210
+ var ownerScope = {
8211
+ currentOwner: () => savedStates.operations.getStore()?.owner ?? COMPUTER_USE_STANDALONE_OWNER
8212
+ };
7240
8213
  var runtimeState = {
7241
8214
  lastPermissionCheckAt: 0,
7242
- windowRefs: /* @__PURE__ */ new Map(),
7243
- windowRefByIdentity: /* @__PURE__ */ new Map(),
7244
- browserRootByContext: /* @__PURE__ */ new Map(),
7245
- browserContextByRoot: /* @__PURE__ */ new Map(),
7246
- nextRootRefIndex: 1
8215
+ windowRefs: new OwnerScopedMap(ownerScope),
8216
+ windowRefByIdentity: new OwnerScopedMap(ownerScope),
8217
+ browserRootByContext: new OwnerScopedMap(ownerScope),
8218
+ browserContextByRoot: new OwnerScopedMap(ownerScope),
8219
+ nextRootRefIndex: new OwnerScopedCounter(ownerScope, 1)
7247
8220
  };
7248
- var savedStates = new SavedStates();
8221
+ var engineGeneration = "";
8222
+ var helperGeneration = "";
8223
+ var engineArtifacts;
8224
+ function createStateStore() {
8225
+ return new StateStore(128, (record) => {
8226
+ engineArtifacts?.dropForState(record.stateId);
8227
+ });
8228
+ }
8229
+ var savedStates = new SavedStates(createStateStore());
7249
8230
  var resourceScheduler = new ResourceScheduler();
7250
8231
  var shutdownInFlight;
8232
+ function configureEngineRuntime(options) {
8233
+ engineGeneration = options.generation;
8234
+ if (options.helperGeneration !== void 0) helperGeneration = options.helperGeneration;
8235
+ engineArtifacts = options.artifacts;
8236
+ expiredStateIds = new Set(options.expiredStateIds ?? []);
8237
+ previousBrokerGeneration = options.previousGeneration ?? "";
8238
+ }
8239
+ function bumpHelperGeneration() {
8240
+ helperGeneration = randomUUID7();
8241
+ return helperGeneration;
8242
+ }
8243
+ function expireStatesAfterHelperRestart(reason = "the native helper restarted") {
8244
+ const ids = savedStates.store.ids?.() ?? [];
8245
+ for (const id of ids) expiredStateReasons.set(id, reason);
8246
+ savedStates.clear();
8247
+ return ids;
8248
+ }
8249
+ function expireStateForArtifactEviction(stateId2) {
8250
+ expiredStateReasons.set(stateId2, "its image artifact was evicted");
8251
+ savedStates.store.drop?.(stateId2);
8252
+ }
8253
+ function persistRuntimeBridgeState() {
8254
+ }
7251
8255
  function operationState() {
7252
8256
  return savedStates.current();
7253
8257
  }
@@ -7289,11 +8293,11 @@ async function releaseComputerUseSession() {
7289
8293
  }
7290
8294
  savedStates.clear();
7291
8295
  clearStoredOutputs();
7292
- runtimeState.windowRefs.clear();
7293
- runtimeState.windowRefByIdentity.clear();
7294
- runtimeState.browserRootByContext.clear();
7295
- runtimeState.browserContextByRoot.clear();
7296
- runtimeState.nextRootRefIndex = 1;
8296
+ runtimeState.windowRefs.clearAll();
8297
+ runtimeState.windowRefByIdentity.clearAll();
8298
+ runtimeState.browserRootByContext.clearAll();
8299
+ runtimeState.browserContextByRoot.clearAll();
8300
+ runtimeState.nextRootRefIndex.clearAll();
7297
8301
  runtimeState.permissionStatus = void 0;
7298
8302
  runtimeState.helperDiagnostics = void 0;
7299
8303
  runtimeState.lastPermissionCheckAt = 0;
@@ -7341,10 +8345,10 @@ function throwIfAborted3(signal) {
7341
8345
  async function sleep2(ms, signal) {
7342
8346
  if (ms <= 0) return;
7343
8347
  throwIfAborted3(signal);
7344
- await new Promise((resolve, reject) => {
8348
+ await new Promise((resolve2, reject) => {
7345
8349
  const timer = setTimeout(() => {
7346
8350
  cleanup();
7347
- resolve();
8351
+ resolve2();
7348
8352
  }, ms);
7349
8353
  const onAbort = () => {
7350
8354
  cleanup();
@@ -7364,8 +8368,9 @@ async function withWindowWriteLock(target, work) {
7364
8368
  const result = await resourceScheduler.write(key, baseEpoch, async (nextEpoch) => {
7365
8369
  state.resourceKey = key;
7366
8370
  state.epoch = nextEpoch;
8371
+ state.onDispatch?.();
7367
8372
  return await work();
7368
- });
8373
+ }, state.signal);
7369
8374
  return result.value;
7370
8375
  }
7371
8376
  function trimOrUndefined(value) {
@@ -7376,9 +8381,6 @@ function trimOrUndefined(value) {
7376
8381
  function normalizeText2(value) {
7377
8382
  return (value ?? "").trim().toLowerCase();
7378
8383
  }
7379
- function toBoolean3(value) {
7380
- return value === true;
7381
- }
7382
8384
  function outlineNodeCenter(node) {
7383
8385
  if (!node.rect) {
7384
8386
  throw new Error(`Outline ref '${node.ref}' has no full-look coordinates after scoped expansion. Re-observe for coordinates.`);
@@ -7546,18 +8548,20 @@ function storeWindowRef(record) {
7546
8548
  return updated;
7547
8549
  }
7548
8550
  }
7549
- const ref = `@r${runtimeState.nextRootRefIndex++}`;
8551
+ const ref = `@r${runtimeState.nextRootRefIndex.next()}`;
7550
8552
  const stored = { ...record, ref };
7551
8553
  runtimeState.windowRefByIdentity.set(identity, ref);
7552
8554
  runtimeState.windowRefs.set(ref, stored);
8555
+ persistRuntimeBridgeState();
7553
8556
  return stored;
7554
8557
  }
7555
8558
  function storeBrowserRootRef(contextId) {
7556
8559
  const existing = runtimeState.browserRootByContext.get(contextId);
7557
8560
  if (existing) return existing;
7558
- const ref = `@r${runtimeState.nextRootRefIndex++}`;
8561
+ const ref = `@r${runtimeState.nextRootRefIndex.next()}`;
7559
8562
  runtimeState.browserRootByContext.set(contextId, ref);
7560
8563
  runtimeState.browserContextByRoot.set(ref, contextId);
8564
+ persistRuntimeBridgeState();
7561
8565
  return ref;
7562
8566
  }
7563
8567
  function storeWindowRefForTarget(target) {
@@ -7792,7 +8796,7 @@ async function ensureTargetWindowId(target, signal) {
7792
8796
  }
7793
8797
  function captureForLook(look) {
7794
8798
  return {
7795
- stateId: randomUUID5(),
8799
+ stateId: randomUUID7(),
7796
8800
  width: look.image?.width ?? 0,
7797
8801
  height: look.image?.height ?? 0,
7798
8802
  scaleFactor: look.window.scaleFactor,
@@ -7853,6 +8857,33 @@ async function buildToolResult(tool, summary, result, execution, _signal, imageM
7853
8857
  const folded = foldToBudget(result.outline);
7854
8858
  const renderedNote = renderNote(state.currentNote);
7855
8859
  const failure = tool === "act_ui" ? actionFailureMessage(execution) : void 0;
8860
+ const image = result.look.image;
8861
+ let artifact;
8862
+ if (image?.jpegBase64 && engineArtifacts) {
8863
+ const bytes = Buffer.from(image.jpegBase64, "base64");
8864
+ const record = engineArtifacts.put({
8865
+ owner: state.owner ?? COMPUTER_USE_STANDALONE_OWNER,
8866
+ generation: state.generation ?? engineGeneration,
8867
+ stateId: result.capture.stateId,
8868
+ mimeType: image.mimeType ?? "image/jpeg",
8869
+ width: image.width,
8870
+ height: image.height,
8871
+ bytes
8872
+ });
8873
+ state.artifactIds ??= [];
8874
+ state.artifactIds.push(record.artifactId);
8875
+ artifact = {
8876
+ artifactId: record.artifactId,
8877
+ path: record.absolutePath,
8878
+ mimeType: record.mimeType,
8879
+ width: record.width,
8880
+ height: record.height,
8881
+ sha256: record.hash,
8882
+ bytes: record.bytes,
8883
+ generation: record.generation,
8884
+ stateId: record.stateId
8885
+ };
8886
+ }
7856
8887
  const details = {
7857
8888
  tool,
7858
8889
  target: {
@@ -7870,7 +8901,8 @@ async function buildToolResult(tool, summary, result, execution, _signal, imageM
7870
8901
  height: result.capture.height,
7871
8902
  scaleFactor: result.capture.scaleFactor,
7872
8903
  timestamp: result.capture.timestamp,
7873
- coordinateSpace: "window-relative-screenshot-pixels"
8904
+ coordinateSpace: "window-relative-screenshot-pixels",
8905
+ ...artifact ? { artifact } : {}
7874
8906
  },
7875
8907
  lookId: result.look.lookId,
7876
8908
  view: useDiff ? "diff" : "full",
@@ -7914,12 +8946,15 @@ ${folded.text}`;
7914
8946
  const fallbackText = fallbackReason ? `
7915
8947
 
7916
8948
  ${fallbackReason.message}` : "";
8949
+ const artifactText = artifact ? `
8950
+
8951
+ Image evidence: ${artifact.path} (${artifact.width}x${artifact.height} ${artifact.mimeType}, sha256 ${artifact.sha256}, stateId ${artifact.stateId}, generation ${artifact.generation}). Call read_file on that absolute path before using coordinates; the image belongs only to stateId ${artifact.stateId}.` : "";
7917
8952
  const deltaText = rootDeltaLines(execution).join("\n");
7918
8953
  const outcomeSummary = failure ? `UI action failed (${failure}). Some actions may already have been delivered; do not replay blindly.` : summary;
7919
8954
  const content = [{ type: "text", text: `${outcomeSummary}${deltaText ? `
7920
- ${deltaText}` : ""}${consoleText}${noteText}${outlineText}${fallbackText}` }];
7921
- if (fallbackReason && result.look.image?.jpegBase64) {
7922
- content.push({ type: "image", data: result.look.image.jpegBase64, mimeType: result.look.image.mimeType ?? "image/jpeg" });
8955
+ ${deltaText}` : ""}${consoleText}${noteText}${outlineText}${fallbackText}${artifactText}` }];
8956
+ if (!artifact && fallbackReason && image?.jpegBase64) {
8957
+ content.push({ type: "image", data: image.jpegBase64, mimeType: image.mimeType ?? "image/jpeg" });
7923
8958
  }
7924
8959
  return { content, details, ...failure ? { isError: true } : {} };
7925
8960
  }
@@ -7947,7 +8982,7 @@ function modelRefForRootDelta(delta) {
7947
8982
  for (const record2 of runtimeState.windowRefs.values()) {
7948
8983
  if (record2.nativeWindowRef === delta.ref || record2.ref === delta.ref) return record2.ref;
7949
8984
  }
7950
- const ref = `@r${runtimeState.nextRootRefIndex++}`;
8985
+ const ref = `@r${runtimeState.nextRootRefIndex.next()}`;
7951
8986
  const current = operationState().currentTarget;
7952
8987
  const record = {
7953
8988
  ref,
@@ -7965,6 +9000,7 @@ function modelRefForRootDelta(delta) {
7965
9000
  };
7966
9001
  runtimeState.windowRefs.set(ref, record);
7967
9002
  runtimeState.windowRefByIdentity.set(windowRecordIdentity(record), ref);
9003
+ persistRuntimeBridgeState();
7968
9004
  return ref;
7969
9005
  }
7970
9006
  function executionTraceFromAct(result, policy = currentDeliveryPolicy()) {
@@ -8174,12 +9210,22 @@ async function withBrowserWrite(contextId, work) {
8174
9210
  const result = await resourceScheduler.write(resourceKey, baseEpoch, async (nextEpoch) => {
8175
9211
  state.resourceKey = resourceKey;
8176
9212
  state.epoch = nextEpoch;
9213
+ state.onDispatch?.();
8177
9214
  return await work();
8178
- });
9215
+ }, state.signal);
8179
9216
  return result.value;
8180
9217
  }
8181
9218
  function browserObservationResult(browser, resourceKey, epoch, tool, base) {
8182
- savedStates.set({ stateId: browser.snapshotId, resourceKey, epoch, value: { kind: "browser", snapshot: browser, outline: browser.outline } });
9219
+ const operation = operationState();
9220
+ savedStates.set({
9221
+ stateId: browser.snapshotId,
9222
+ resourceKey,
9223
+ epoch,
9224
+ owner: operation.owner,
9225
+ generation: operation.generation,
9226
+ helperGeneration: operation.helperGeneration,
9227
+ value: { kind: "browser", snapshot: browser, outline: browser.outline }
9228
+ });
8183
9229
  const currentOutline = restoreOutline(browser.outline);
8184
9230
  const transition = base ? changesBetween(restoreOutline(base.outline), currentOutline) : void 0;
8185
9231
  const useDiff = Boolean(transition && !transition.useFullView);
@@ -8215,8 +9261,8 @@ function sliceText(value, offsetValue, _limitValue) {
8215
9261
  async function performReadText(params, signal) {
8216
9262
  const ref = trimOrUndefined(params.ref);
8217
9263
  if (ref?.startsWith("@o")) {
8218
- const page = readStoredOutput(ref, params.offset);
8219
- if (!page) throw new Error(`Output ref '${ref}' is unavailable or was evicted. Rerun the focused query.`);
9264
+ const page = readStoredOutput(ref, params.offset, operationState().owner ?? COMPUTER_USE_STANDALONE_OWNER);
9265
+ if (!page) throw new Error(`Output ref '${ref}' is unavailable, was evicted, or belongs to another session. Rerun the focused query.`);
8220
9266
  const details2 = { tool: "read_text", ref, ...page };
8221
9267
  const suffix = page.hasMore ? `
8222
9268
 
@@ -8269,7 +9315,7 @@ function conditionScopeRef(params) {
8269
9315
  if (ref && scopeRef) throw new Error("A UI condition accepts ref or scopeRef, not both.");
8270
9316
  return ref ?? scopeRef;
8271
9317
  }
8272
- function validateCondition(params) {
9318
+ function validateCondition2(params) {
8273
9319
  const text = trimOrUndefined(params.text);
8274
9320
  const role = trimOrUndefined(params.role);
8275
9321
  const value = trimOrUndefined(params.value);
@@ -8284,7 +9330,7 @@ function expectCondition(expect) {
8284
9330
  const hasMatcher = Boolean(trimOrUndefined(expect.text) ?? trimOrUndefined(expect.role) ?? trimOrUndefined(expect.value));
8285
9331
  const hasScope = Boolean(conditionScopeRef(expect));
8286
9332
  if (!hasMatcher && !hasScope) return void 0;
8287
- return validateCondition(expect);
9333
+ return validateCondition2(expect);
8288
9334
  }
8289
9335
  function nodeWithinScope(node, scopeRef, scopeExact) {
8290
9336
  if (!scopeRef) return true;
@@ -8313,7 +9359,7 @@ function conditionScopeNode(outline, condition) {
8313
9359
  }
8314
9360
  async function performWaitFor(params, signal) {
8315
9361
  const contextId = operationState().contextId;
8316
- const condition = validateCondition(params);
9362
+ const condition = validateCondition2(params);
8317
9363
  const { text, role, value, scopeRef, scopeExact, gone, timeoutMs } = condition;
8318
9364
  if (isBrowserContextId(contextId)) {
8319
9365
  const state2 = operationState();
@@ -8403,7 +9449,7 @@ function sameRootIdentity(a, b) {
8403
9449
  }
8404
9450
  async function performObserve(params, signal) {
8405
9451
  const requestedRoot = typeof params.root === "string" ? params.root : void 0;
8406
- if (requestedRoot && !/^@r\d+$/.test(requestedRoot)) throw new Error("observe_ui.root must be an exact @r ref issued by find_roots.");
9452
+ if (requestedRoot && !/^@r\d+$/.test(requestedRoot)) throw new Error("observe --root must be an exact @r ref issued by roots.");
8407
9453
  const browserContextId = requestedRoot ? runtimeState.browserContextByRoot.get(requestedRoot) : void 0;
8408
9454
  if (isBrowserContextId(browserContextId)) {
8409
9455
  const targetId = browserContextId.slice(BROWSER_CONTEXT_PREFIX.length);
@@ -8809,8 +9855,8 @@ async function performBrowserTransaction(params, actions, signal) {
8809
9855
  return await refreshBrowserSnapshot(contextId, "act_ui", baseView);
8810
9856
  });
8811
9857
  }
8812
- function normalizeActionPath(path11) {
8813
- return (path11 ?? []).map((point2) => Array.isArray(point2) ? { x: toFiniteNumber(point2[0], 0), y: toFiniteNumber(point2[1], 0) } : { x: toFiniteNumber(point2.x, 0), y: toFiniteNumber(point2.y, 0) });
9858
+ function normalizeActionPath(path15) {
9859
+ return (path15 ?? []).map((point) => Array.isArray(point) ? { x: toFiniteNumber(point[0], 0), y: toFiniteNumber(point[1], 0) } : { x: toFiniteNumber(point.x, 0), y: toFiniteNumber(point.y, 0) });
8814
9860
  }
8815
9861
  function validateActionTarget(action) {
8816
9862
  const hasRef = Boolean(trimOrUndefined(action.ref));
@@ -8827,7 +9873,7 @@ function validateActionTarget(action) {
8827
9873
  }
8828
9874
  async function performAct(params, signal) {
8829
9875
  const actions = Array.isArray(params.actions) ? params.actions : [];
8830
- if (actions.length === 0) throw new Error("act_ui.actions must contain at least one action.");
9876
+ if (actions.length === 0) throw new Error("act --actions must contain at least one action.");
8831
9877
  if (actions.length > 20) throw new Error("act_ui supports at most 20 actions per transaction.");
8832
9878
  for (const action of actions) validateActionTarget(action);
8833
9879
  if (operationState().contextId) return await performBrowserTransaction(params, actions, signal);
@@ -8836,25 +9882,25 @@ async function performAct(params, signal) {
8836
9882
  function managedBrowserExecutableCandidates(browser) {
8837
9883
  const overrideName = browser === "helium" ? "PIE_COMPUTER_USE_HELIUM_EXECUTABLE" : "PIE_COMPUTER_USE_CHROME_EXECUTABLE";
8838
9884
  const override = trimOrUndefined(process.env[overrideName]);
8839
- if (override) return [path10.resolve(override)];
9885
+ if (override) return [path13.resolve(override)];
8840
9886
  const platformCandidates = process.platform === "darwin" ? browser === "helium" ? [
8841
9887
  "/Applications/Helium.app/Contents/MacOS/Helium",
8842
- path10.join(os5.homedir(), "Applications", "Helium.app", "Contents", "MacOS", "Helium")
9888
+ path13.join(os4.homedir(), "Applications", "Helium.app", "Contents", "MacOS", "Helium")
8843
9889
  ] : [
8844
9890
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
8845
- path10.join(os5.homedir(), "Applications", "Google Chrome.app", "Contents", "MacOS", "Google Chrome")
9891
+ path13.join(os4.homedir(), "Applications", "Google Chrome.app", "Contents", "MacOS", "Google Chrome")
8846
9892
  ] : process.platform === "win32" ? browser === "helium" ? [
8847
- process.env.LOCALAPPDATA && path10.join(process.env.LOCALAPPDATA, "Helium", "Application", "helium.exe"),
8848
- process.env.PROGRAMFILES && path10.join(process.env.PROGRAMFILES, "Helium", "Application", "helium.exe")
9893
+ process.env.LOCALAPPDATA && path13.join(process.env.LOCALAPPDATA, "Helium", "Application", "helium.exe"),
9894
+ process.env.PROGRAMFILES && path13.join(process.env.PROGRAMFILES, "Helium", "Application", "helium.exe")
8849
9895
  ] : [
8850
- process.env.LOCALAPPDATA && path10.join(process.env.LOCALAPPDATA, "Google", "Chrome", "Application", "chrome.exe"),
8851
- process.env.PROGRAMFILES && path10.join(process.env.PROGRAMFILES, "Google", "Chrome", "Application", "chrome.exe"),
8852
- process.env["PROGRAMFILES(X86)"] && path10.join(process.env["PROGRAMFILES(X86)"], "Google", "Chrome", "Application", "chrome.exe")
9896
+ process.env.LOCALAPPDATA && path13.join(process.env.LOCALAPPDATA, "Google", "Chrome", "Application", "chrome.exe"),
9897
+ process.env.PROGRAMFILES && path13.join(process.env.PROGRAMFILES, "Google", "Chrome", "Application", "chrome.exe"),
9898
+ process.env["PROGRAMFILES(X86)"] && path13.join(process.env["PROGRAMFILES(X86)"], "Google", "Chrome", "Application", "chrome.exe")
8853
9899
  ] : browser === "helium" ? [
8854
9900
  "/usr/bin/helium",
8855
9901
  "/usr/bin/helium-browser",
8856
9902
  "/opt/helium/chrome",
8857
- path10.join(os5.homedir(), ".local", "helium", "chrome")
9903
+ path13.join(os4.homedir(), ".local", "helium", "chrome")
8858
9904
  ] : [
8859
9905
  "/usr/bin/google-chrome",
8860
9906
  "/usr/bin/google-chrome-stable",
@@ -8863,7 +9909,7 @@ function managedBrowserExecutableCandidates(browser) {
8863
9909
  "/snap/bin/chromium"
8864
9910
  ];
8865
9911
  const pathNames = browser === "helium" ? process.platform === "win32" ? ["helium.exe"] : ["helium", "helium-browser"] : process.platform === "win32" ? ["chrome.exe"] : ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"];
8866
- const pathCandidates = (process.env.PATH ?? "").split(path10.delimiter).filter(Boolean).flatMap((directory) => pathNames.map((name) => path10.join(directory, name)));
9912
+ const pathCandidates = (process.env.PATH ?? "").split(path13.delimiter).filter(Boolean).flatMap((directory) => pathNames.map((name) => path13.join(directory, name)));
8867
9913
  return [.../* @__PURE__ */ new Set([...platformCandidates.filter((candidate) => Boolean(candidate)), ...pathCandidates])];
8868
9914
  }
8869
9915
  async function managedBrowserExecutable(browser) {
@@ -8882,13 +9928,13 @@ async function managedBrowserExecutable(browser) {
8882
9928
  throw new Error(`${browser} executable was not found. Set ${overrideName} to its absolute path.`);
8883
9929
  }
8884
9930
  function freeTcpPort() {
8885
- return new Promise((resolve, reject) => {
9931
+ return new Promise((resolve2, reject) => {
8886
9932
  const server = net2.createServer();
8887
9933
  server.on("error", reject);
8888
9934
  server.listen(0, "127.0.0.1", () => {
8889
9935
  const address = server.address();
8890
9936
  const port = typeof address === "object" && address ? address.port : 0;
8891
- server.close(() => port > 0 ? resolve(port) : reject(new Error("Could not allocate a local CDP port.")));
9937
+ server.close(() => port > 0 ? resolve2(port) : reject(new Error("Could not allocate a local CDP port.")));
8892
9938
  });
8893
9939
  });
8894
9940
  }
@@ -8914,7 +9960,7 @@ async function performLaunchBrowser(params, signal) {
8914
9960
  const url = requestedUrl ?? "about:blank";
8915
9961
  await disconnectCdp();
8916
9962
  await releaseOwnedBrowserState(runtimeState);
8917
- const profileDir = mkdtempSync2(path10.join(os5.tmpdir(), `pie-${browser}-cdp-`));
9963
+ const profileDir = mkdtempSync(path13.join(os4.tmpdir(), `pie-${browser}-cdp-`));
8918
9964
  const args = [
8919
9965
  `--remote-debugging-port=${port}`,
8920
9966
  `--user-data-dir=${profileDir}`,
@@ -8925,11 +9971,20 @@ async function performLaunchBrowser(params, signal) {
8925
9971
  if (runtimeState.previousCdpPort === void 0 && runtimeState.managedBrowserCdpPort === void 0) {
8926
9972
  runtimeState.previousCdpPort = process.env.PIE_COMPUTER_USE_CDP_PORT;
8927
9973
  }
8928
- const managedBrowser = spawn4(executable, args, { stdio: "ignore", detached: false });
9974
+ const managedBrowser = spawn4(executable, args, { stdio: "ignore", detached: true });
8929
9975
  managedBrowser.unref();
9976
+ const stalePid = runtimeState.managedBrowserPid;
9977
+ if (stalePid !== void 0 && stalePid !== managedBrowser.pid) {
9978
+ try {
9979
+ process.kill(stalePid, "SIGTERM");
9980
+ } catch {
9981
+ }
9982
+ }
8930
9983
  runtimeState.managedBrowser = managedBrowser;
8931
9984
  runtimeState.managedBrowserCdpPort = String(port);
9985
+ runtimeState.managedBrowserPid = managedBrowser.pid;
8932
9986
  runtimeState.managedBrowserProfileDir = profileDir;
9987
+ persistRuntimeBridgeState();
8933
9988
  process.env.PIE_COMPUTER_USE_CDP_PORT = String(port);
8934
9989
  try {
8935
9990
  await waitForCdpPort(port, signal);
@@ -8986,447 +10041,806 @@ async function performEvaluateBrowser(params) {
8986
10041
  return { content: [...successor.content, { type: "text", text: `Evaluation value: ${JSON.stringify(result.value)}` }], details };
8987
10042
  });
8988
10043
  }
8989
- async function executeTool(tool, ctx, params, signal, run) {
10044
+ var expiredStateIds = /* @__PURE__ */ new Set();
10045
+ var previousBrokerGeneration = "";
10046
+ var expiredStateReasons = /* @__PURE__ */ new Map();
10047
+ function assertStateAccess(stateId2, record, operation) {
10048
+ const owner = operation.owner ?? COMPUTER_USE_STANDALONE_OWNER;
10049
+ if (record.owner !== void 0 && record.owner !== owner) {
10050
+ throw new Error(`State '${stateId2}' is not available to this session. Observe the root again in this session.`);
10051
+ }
10052
+ if (record.generation !== void 0 && operation.generation !== void 0 && record.generation !== operation.generation) {
10053
+ throw new Error(`State '${stateId2}' expired (broker generation changed from ${record.generation} to ${operation.generation}). Observe the root again.`);
10054
+ }
10055
+ if (record.helperGeneration !== void 0 && operation.helperGeneration !== void 0 && record.helperGeneration !== operation.helperGeneration) {
10056
+ throw new Error(`State '${stateId2}' expired after the native helper restarted. Observe the root again.`);
10057
+ }
10058
+ }
10059
+ async function executeTool(tool, ctx, params, signal, run, runtime) {
8990
10060
  if (shutdownInFlight) throw new Error("Computer-use resources are shutting down.");
8991
10061
  const outputRef = tool === "read_text" && trimOrUndefined(params?.ref)?.startsWith("@o") === true;
8992
10062
  const requestedStateId = outputRef ? void 0 : trimOrUndefined(params?.stateId);
8993
10063
  const stateRecord = requestedStateId ? savedStates.get(requestedStateId) : void 0;
8994
10064
  if (requestedStateId && !stateRecord) {
10065
+ const reason = expiredStateReasons.get(requestedStateId);
10066
+ if (reason) {
10067
+ throw new Error(`State '${requestedStateId}' expired because ${reason}. Observe the root again; old state is never replayed.`);
10068
+ }
10069
+ if (expiredStateIds.has(requestedStateId)) {
10070
+ throw new Error(`State '${requestedStateId}' expired (previous broker generation ${previousBrokerGeneration || "unknown"}). Observe the root again; old CLI cache is not restored.`);
10071
+ }
8995
10072
  throw new Error(`State '${requestedStateId}' is unavailable or was evicted. Observe the root again.`);
8996
10073
  }
8997
10074
  const operation = savedStates.hydrate(stateRecord);
10075
+ operation.owner = runtime?.owner ?? operation.owner ?? COMPUTER_USE_STANDALONE_OWNER;
10076
+ operation.generation = runtime?.generation ?? operation.generation ?? engineGeneration;
10077
+ operation.helperGeneration = runtime?.helperGeneration ?? operation.helperGeneration ?? helperGeneration;
10078
+ operation.requestId = runtime?.requestId;
10079
+ operation.signal = signal ?? runtime?.signal;
10080
+ operation.onDispatch = runtime?.onDispatch;
10081
+ if (requestedStateId && stateRecord) assertStateAccess(requestedStateId, stateRecord, operation);
8998
10082
  return await savedStates.operations.run(operation, async () => {
8999
- const browserOnly = operation.contextId || ["launch_browser", "navigate_browser", "evaluate_browser"].includes(tool) || tool === "find_roots" && params.kind === "browser_page" || tool === "observe_ui" && runtimeState.browserContextByRoot.has(params.root ?? "");
9000
- await resourceScheduler.read("session-lifecycle", async () => {
9001
- if (browserOnly || outputRef) {
9002
- loadComputerUseConfig(ctx.cwd);
9003
- if (browserOnly && !outputRef && tool !== "find_roots" && !isBrowserUseEnabled()) {
9004
- throw new Error("Browser use is disabled by computer-use config. Enable browser_use to control browser pages.");
9005
- }
9006
- } else await ensureReady3(ctx, signal);
9007
- });
9008
- throwIfAborted3(signal);
9009
- const result = await run();
9010
- persistOperation(operation);
9011
- return result;
10083
+ try {
10084
+ const browserOnly = operation.contextId || ["launch_browser", "navigate_browser", "evaluate_browser"].includes(tool) || tool === "find_roots" && params.kind === "browser_page" || tool === "observe_ui" && runtimeState.browserContextByRoot.has(params.root ?? "");
10085
+ await resourceScheduler.read("session-lifecycle", async () => {
10086
+ if (browserOnly || outputRef) {
10087
+ loadComputerUseConfig(ctx.cwd);
10088
+ if (browserOnly && !outputRef && tool !== "find_roots" && !isBrowserUseEnabled()) {
10089
+ throw new Error("Browser use is disabled by computer-use config. Enable browser_use to control browser pages.");
10090
+ }
10091
+ } else await ensureReady3(ctx, signal);
10092
+ }, operation.signal);
10093
+ throwIfAborted3(signal);
10094
+ const result = await run();
10095
+ persistOperation(operation);
10096
+ return result;
10097
+ } finally {
10098
+ for (const artifactId of operation.artifactIds ?? []) engineArtifacts?.unpin(artifactId);
10099
+ }
9012
10100
  });
9013
10101
  }
9014
- function makeToolExecutor(tool, perform) {
9015
- return async (_toolCallId, params, signal, _onUpdate, ctx) => {
10102
+ var BROKER_PERFORMERS = {
10103
+ find_roots: performListWindows,
10104
+ observe_ui: performObserve,
10105
+ search_ui: performSearchUi,
10106
+ expand_ui: performExpandUi,
10107
+ inspect_ui: performInspectUi,
10108
+ read_text: performReadText,
10109
+ wait_for: performWaitFor,
10110
+ act_ui: performAct,
10111
+ launch_browser: performLaunchBrowser,
10112
+ navigate_browser: performNavigateBrowser,
10113
+ evaluate_browser: performEvaluateBrowser
10114
+ };
10115
+ async function executeBrokerCommand(command, params, runtime) {
10116
+ const perform = BROKER_PERFORMERS[command];
10117
+ if (!perform) throw new Error(`Unsupported broker command '${String(command)}'.`);
10118
+ const ctx = { cwd: runtime.cwd, getMessages: () => [] };
10119
+ return await executeTool(command, ctx, params, runtime.signal, async () => {
10120
+ const owner = operationState().owner ?? COMPUTER_USE_STANDALONE_OWNER;
9016
10121
  try {
9017
- return applyOutputEnvelope(tool, await executeTool(tool, ctx, params, signal, () => perform(params, signal)));
10122
+ return applyOutputEnvelope(command, await perform(params, runtime.signal), owner);
9018
10123
  } catch (error) {
9019
- throw boundToolError(tool, error);
10124
+ throw boundToolError(command, error, owner);
9020
10125
  }
9021
- };
10126
+ }, runtime);
9022
10127
  }
9023
- var executeFind = makeToolExecutor("find_roots", performListWindows);
9024
- var executeReadText = makeToolExecutor("read_text", performReadText);
9025
- var executeWaitFor = makeToolExecutor("wait_for", performWaitFor);
9026
- var executeObserve = makeToolExecutor("observe_ui", performObserve);
9027
- var executeSearchUi = makeToolExecutor("search_ui", performSearchUi);
9028
- var executeExpandUi = makeToolExecutor("expand_ui", performExpandUi);
9029
- var executeInspectUi = makeToolExecutor("inspect_ui", performInspectUi);
9030
- var executeAct = makeToolExecutor("act_ui", performAct);
9031
- var executeNavigateBrowser = makeToolExecutor("navigate_browser", performNavigateBrowser);
9032
- var executeEvaluateBrowser = makeToolExecutor("evaluate_browser", performEvaluateBrowser);
9033
- var executeLaunchBrowser = makeToolExecutor("launch_browser", performLaunchBrowser);
9034
- function reconstructStateFromBranch(ctx) {
9035
- savedStates.clear();
9036
- clearStoredOutputs();
9037
- runtimeState.windowRefs.clear();
9038
- runtimeState.windowRefByIdentity.clear();
9039
- runtimeState.nextRootRefIndex = 1;
9040
- const restoredResources = /* @__PURE__ */ new Set();
9041
- for (const message of [...ctx.getMessages()].reverse()) {
9042
- if (!message || message.role !== "toolResult") continue;
9043
- if (!AGENT_TOOL_NAMES.has(message.toolName)) continue;
9044
- const rawDetails = message.details;
9045
- if (rawDetails?.tool === "find_roots" && Array.isArray(rawDetails.windows)) {
9046
- for (const window of rawDetails.windows) {
9047
- if (typeof window?.windowRef !== "string" || !Number.isFinite(window?.pid)) continue;
9048
- const record = {
9049
- ref: window.windowRef,
9050
- appName: typeof window.app === "string" ? window.app : "Unknown App",
9051
- bundleId: typeof window.bundleId === "string" ? window.bundleId : void 0,
9052
- pid: Math.trunc(window.pid),
9053
- windowTitle: typeof window.windowTitle === "string" ? window.windowTitle : "(untitled)",
9054
- windowId: Number.isFinite(window.windowId) ? Math.trunc(window.windowId) : void 0,
9055
- nativeWindowRef: typeof window.nativeWindowRef === "string" ? window.nativeWindowRef : void 0,
9056
- framePoints: {
9057
- x: toFiniteNumber(window.framePoints?.x, 0),
9058
- y: toFiniteNumber(window.framePoints?.y, 0),
9059
- w: Math.max(1, toFiniteNumber(window.framePoints?.w, 1)),
9060
- h: Math.max(1, toFiniteNumber(window.framePoints?.h, 1))
9061
- },
9062
- scaleFactor: Math.max(1, toFiniteNumber(window.scaleFactor, 1)),
9063
- isMinimized: toBoolean3(window.isMinimized),
9064
- isOnscreen: toBoolean3(window.isOnscreen),
9065
- isMain: toBoolean3(window.isMain),
9066
- isFocused: toBoolean3(window.isFocused)
9067
- };
9068
- runtimeState.windowRefs.set(record.ref, record);
9069
- runtimeState.windowRefByIdentity.set(windowRecordIdentity(record), record.ref);
9070
- const match = /^@r(\d+)$/.exec(record.ref);
9071
- if (match) runtimeState.nextRootRefIndex = Math.max(runtimeState.nextRootRefIndex, Number(match[1]) + 1);
9072
- }
9073
- continue;
9074
- }
9075
- const details = rawDetails;
9076
- if (!details?.target || !details?.capture) continue;
9077
- const app = typeof details.target.app === "string" ? details.target.app : void 0;
9078
- if (!app) continue;
9079
- if (!Number.isFinite(details.target.pid) || !Number.isFinite(details.target.windowId)) continue;
9080
- if (typeof details.capture.stateId !== "string") continue;
9081
- const target = {
9082
- appName: app,
9083
- bundleId: details.target.bundleId,
9084
- pid: Math.trunc(details.target.pid),
9085
- windowTitle: details.target.windowTitle ?? "(untitled)",
9086
- windowId: Math.trunc(details.target.windowId),
9087
- windowRef: typeof details.target.windowRef === "string" ? details.target.windowRef : void 0,
9088
- nativeWindowRef: typeof details.target.nativeWindowRef === "string" ? details.target.nativeWindowRef : void 0
10128
+
10129
+ // vendor/computer-use-axi/src/broker-server.ts
10130
+ function sleep3(ms) {
10131
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
10132
+ }
10133
+ function isAlive(pid) {
10134
+ if (!Number.isInteger(pid) || pid <= 0) return false;
10135
+ try {
10136
+ process.kill(pid, 0);
10137
+ return true;
10138
+ } catch {
10139
+ return false;
10140
+ }
10141
+ }
10142
+ function acquireBootstrapLock(directory) {
10143
+ ensurePrivateDirectory(directory);
10144
+ const lockPath = path14.join(directory, "broker.lock");
10145
+ for (let attempt = 0; attempt < 100; attempt += 1) {
10146
+ try {
10147
+ writeFileSync3(lockPath, String(process.pid), { flag: "wx", mode: 384 });
10148
+ return () => {
10149
+ try {
10150
+ unlinkSync4(lockPath);
10151
+ } catch {
10152
+ }
10153
+ };
10154
+ } catch (error) {
10155
+ if (error.code !== "EEXIST") throw error;
10156
+ let ownerPid = 0;
10157
+ try {
10158
+ ownerPid = Number.parseInt(readFileSync4(lockPath, "utf8").trim(), 10);
10159
+ } catch {
10160
+ }
10161
+ if (Number.isInteger(ownerPid) && ownerPid > 0 && isAlive(ownerPid)) {
10162
+ const until = Date.now() + 100;
10163
+ while (Date.now() < until) {
10164
+ }
10165
+ continue;
10166
+ }
10167
+ try {
10168
+ unlinkSync4(lockPath);
10169
+ } catch {
10170
+ }
10171
+ }
10172
+ }
10173
+ throw new Error(`Could not acquire the computer-use broker bootstrap lock at ${lockPath}.`);
10174
+ }
10175
+ async function listen(server, endpoint) {
10176
+ if (endpoint.kind === "unix-socket") ensurePrivateDirectory(endpoint.directory);
10177
+ await new Promise((resolve2, reject) => {
10178
+ const onError = (error) => {
10179
+ server.off("listening", onListening);
10180
+ reject(error);
10181
+ };
10182
+ const onListening = () => {
10183
+ server.off("error", onError);
10184
+ resolve2();
9089
10185
  };
9090
- const resourceKey = desktopResourceKey(target);
9091
- if (restoredResources.has(resourceKey)) continue;
9092
- const capture = {
9093
- stateId: details.capture.stateId,
9094
- width: Math.max(1, Math.trunc(toFiniteNumber(details.capture.width, 1))),
9095
- height: Math.max(1, Math.trunc(toFiniteNumber(details.capture.height, 1))),
9096
- scaleFactor: Math.max(1, toFiniteNumber(details.capture.scaleFactor, 1)),
9097
- timestamp: Number.isFinite(details.capture.timestamp) ? details.capture.timestamp : Date.now()
10186
+ server.once("error", onError);
10187
+ server.once("listening", onListening);
10188
+ server.listen(endpoint.path);
10189
+ });
10190
+ if (endpoint.kind === "unix-socket") chmodSync2(endpoint.path, 384);
10191
+ }
10192
+ async function probeBroker(endpoint, timeoutMs = 800) {
10193
+ return await new Promise((resolve2) => {
10194
+ const socket = net3.createConnection(endpoint.path);
10195
+ const decoder = new FrameDecoder();
10196
+ let settled = false;
10197
+ const finish = (result) => {
10198
+ if (settled) return;
10199
+ settled = true;
10200
+ socket.destroy();
10201
+ resolve2(result);
10202
+ };
10203
+ socket.setTimeout(timeoutMs, () => finish({ error: "timeout" }));
10204
+ socket.on("connect", () => {
10205
+ socket.write(encodeFrame({ type: "hello", protocolVersion: BROKER_PROTOCOL_VERSION, clientVersion: "probe" }));
10206
+ });
10207
+ socket.on("data", (chunk) => {
10208
+ try {
10209
+ const frames = decoder.push(chunk);
10210
+ for (const frame of frames) {
10211
+ if (frame && typeof frame === "object" && frame.type === "hello") finish({ live: frame });
10212
+ }
10213
+ } catch (error) {
10214
+ finish({ error: error instanceof Error ? error.message : String(error) });
10215
+ }
10216
+ });
10217
+ socket.on("error", (error) => {
10218
+ if (error.code === "ECONNREFUSED" || error.code === "ENOENT") finish({ dead: true });
10219
+ else finish({ error: error.message });
10220
+ });
10221
+ socket.on("close", () => finish({ error: "closed" }));
10222
+ });
10223
+ }
10224
+ function canProveStaleEndpoint(endpoint) {
10225
+ if (endpoint.kind !== "unix-socket") return false;
10226
+ try {
10227
+ const stats = lstatSync4(endpoint.path);
10228
+ if (!stats.isSocket()) return false;
10229
+ return typeof process.getuid === "function" ? stats.uid === process.getuid() : true;
10230
+ } catch {
10231
+ return false;
10232
+ }
10233
+ }
10234
+ function removeStaleSocket(endpoint) {
10235
+ if (!canProveStaleEndpoint(endpoint)) throw new Error(`Refusing to remove an endpoint that cannot be proven stale: ${endpoint.path}`);
10236
+ unlinkSync4(endpoint.path);
10237
+ }
10238
+ function collectStateIds(value, into) {
10239
+ if (!value || typeof value !== "object") return;
10240
+ const record = value;
10241
+ const details = record.details;
10242
+ const candidate = details?.stateId ?? details?.capture?.stateId;
10243
+ if (typeof candidate === "string" && /^[A-Za-z0-9-]{1,128}$/.test(candidate)) into.add(candidate);
10244
+ }
10245
+ async function startBroker(options = {}) {
10246
+ const endpoint = options.endpoint ?? resolveBrokerEndpoint();
10247
+ const idleExitMs = options.idleExitMs ?? BROKER_IDLE_EXIT_MS;
10248
+ const generation = randomUUID8();
10249
+ const helperGeneration2 = randomUUID8();
10250
+ let liveHelperGeneration = helperGeneration2;
10251
+ const startedAt = Date.now();
10252
+ const legacyCache = cleanupLegacyBrokerCache();
10253
+ const prior = loadBrokerManifest();
10254
+ const artifacts = new ArtifactStore({
10255
+ root: artifactsRoot(),
10256
+ generation,
10257
+ onEvict: (stateId2) => {
10258
+ artifacts.dropForState(stateId2);
10259
+ expireStateForArtifactEviction(stateId2);
10260
+ }
10261
+ });
10262
+ try {
10263
+ artifacts.cleanupOtherGenerations(generation);
10264
+ } catch {
10265
+ }
10266
+ configureEngineRuntime({
10267
+ generation,
10268
+ helperGeneration: helperGeneration2,
10269
+ artifacts,
10270
+ expiredStateIds: prior?.stateIds ?? [],
10271
+ previousGeneration: prior?.generation
10272
+ });
10273
+ saveBrokerManifest({ generation, helperGeneration: helperGeneration2, stateIds: [], updatedAt: Date.now() });
10274
+ const entries = /* @__PURE__ */ new Map();
10275
+ const owners = /* @__PURE__ */ new Set();
10276
+ const knownStateIds = /* @__PURE__ */ new Set();
10277
+ let active = 0;
10278
+ let queued = 0;
10279
+ let lastActivity = Date.now();
10280
+ let drainRequested = false;
10281
+ let stopping = false;
10282
+ let idleTimer;
10283
+ let statusHandle;
10284
+ const persistManifest = () => {
10285
+ try {
10286
+ saveBrokerManifest({ generation, helperGeneration: currentHelperGenerationSafe(), stateIds: [...knownStateIds], updatedAt: Date.now() });
10287
+ } catch {
10288
+ }
10289
+ };
10290
+ const currentHelperGenerationSafe = () => liveHelperGeneration;
10291
+ const send = (socket, frame) => {
10292
+ if (!socket || socket.destroyed) return;
10293
+ try {
10294
+ socket.write(encodeFrame(frame, BROKER_MAX_RESPONSE_BYTES));
10295
+ } catch (error) {
10296
+ const message = error instanceof Error ? error.message : String(error);
10297
+ try {
10298
+ socket.write(encodeFrame({ type: "response", requestId: "broker", ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "frame_too_large", message } }));
10299
+ } catch {
10300
+ }
10301
+ }
10302
+ };
10303
+ const respond = (entry, state, result, error) => {
10304
+ send(entry.socket, {
10305
+ type: "response",
10306
+ requestId: entry.requestId,
10307
+ ok: state === "done" || state === "in-flight",
10308
+ state,
10309
+ generation,
10310
+ helperGeneration: currentHelperGenerationSafe(),
10311
+ ...result === void 0 ? {} : { result },
10312
+ ...error ? { error } : {}
10313
+ });
10314
+ };
10315
+ const waiters = [];
10316
+ const acquireSlot = (entry) => {
10317
+ if (entry.controller.signal.aborted) return Promise.resolve(false);
10318
+ if (active < BROKER_MAX_CONCURRENT_REQUESTS) {
10319
+ active += 1;
10320
+ return Promise.resolve(true);
10321
+ }
10322
+ if (waiters.length >= BROKER_MAX_QUEUED_REQUESTS) return Promise.resolve(false);
10323
+ return new Promise((resolve2) => {
10324
+ const waiter = {
10325
+ start: () => {
10326
+ entry.controller.signal.removeEventListener("abort", waiter.cancel);
10327
+ queued = Math.max(0, queued - 1);
10328
+ resolve2(true);
10329
+ },
10330
+ cancel: () => {
10331
+ const index = waiters.indexOf(waiter);
10332
+ if (index >= 0) waiters.splice(index, 1);
10333
+ queued = Math.max(0, queued - 1);
10334
+ resolve2(false);
10335
+ }
10336
+ };
10337
+ queued += 1;
10338
+ entry.controller.signal.addEventListener("abort", waiter.cancel, { once: true });
10339
+ waiters.push(waiter);
10340
+ });
10341
+ };
10342
+ const releaseSlot = () => {
10343
+ active = Math.max(0, active - 1);
10344
+ const next = waiters.shift();
10345
+ if (next) {
10346
+ active += 1;
10347
+ next.start();
10348
+ }
10349
+ };
10350
+ const finish = (entry, state, result, error) => {
10351
+ if (entry.timer) clearTimeout(entry.timer);
10352
+ entry.timer = void 0;
10353
+ if (entry.finished) {
10354
+ if (state === "done") {
10355
+ entry.state = "done";
10356
+ entry.result = result;
10357
+ entry.error = void 0;
10358
+ if (result !== void 0) collectStateIds(result, knownStateIds);
10359
+ if (knownStateIds.size > 0) persistManifest();
10360
+ }
10361
+ if (entry.slotHeld) {
10362
+ entry.slotHeld = false;
10363
+ releaseSlot();
10364
+ }
10365
+ return;
10366
+ }
10367
+ entry.finished = true;
10368
+ entry.state = state;
10369
+ entry.result = result;
10370
+ entry.error = error;
10371
+ if (result !== void 0) collectStateIds(result, knownStateIds);
10372
+ if (entry.slotHeld) {
10373
+ entry.slotHeld = false;
10374
+ releaseSlot();
10375
+ }
10376
+ respond(entry, state === "unknown" ? "outcome-unknown" : state === "error" ? "error" : "done", result, error);
10377
+ if (knownStateIds.size > 0) persistManifest();
10378
+ };
10379
+ const runEntry = async (entry, request) => {
10380
+ entry.state = "running";
10381
+ entry.dispatched = request.command === "launch_browser";
10382
+ lastActivity = Date.now();
10383
+ try {
10384
+ const result = await executeBrokerCommand(request.command, request.params, {
10385
+ owner: request.ownerId,
10386
+ generation,
10387
+ helperGeneration: currentHelperGenerationSafe(),
10388
+ requestId: request.requestId,
10389
+ cwd: request.cwd,
10390
+ signal: entry.controller.signal,
10391
+ onDispatch: () => {
10392
+ entry.dispatched = true;
10393
+ }
10394
+ });
10395
+ finish(entry, "done", result);
10396
+ } catch (error) {
10397
+ const currentState = entry.state;
10398
+ if (currentState === "unknown" || currentState === "error") return;
10399
+ const message = error instanceof Error ? error.message : String(error);
10400
+ finish(entry, "error", void 0, { code: "engine_error", message, dispatched: entry.dispatched });
10401
+ }
10402
+ };
10403
+ const handleEngineRequest = async (request, socket) => {
10404
+ if (stopping || drainRequested) {
10405
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "broker_draining", message: "The broker is shutting down and draining in-flight work; this request was not accepted. Retry after it exits.", dispatched: false } });
10406
+ return;
10407
+ }
10408
+ const key = request.requestId;
10409
+ const fingerprint = requestFingerprint(request.command, request.params, request.cwd);
10410
+ const existing = entries.get(key);
10411
+ if (existing) {
10412
+ if (existing.ownerId !== request.ownerId || existing.command !== request.command || existing.fingerprint !== fingerprint) {
10413
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "request_id_conflict", message: "This requestId was already used with a different owner, command, params, or cwd. Use a fresh requestId." } });
10414
+ return;
10415
+ }
10416
+ if (existing.state === "done") respond({ ...existing, socket }, "done", existing.result);
10417
+ else if (existing.state === "running" || existing.state === "queued") respond({ ...existing, socket }, "in-flight");
10418
+ else if (existing.state === "unknown") respond({ ...existing, socket }, "outcome-unknown", void 0, existing.error);
10419
+ else respond({ ...existing, socket }, "error", void 0, existing.error);
10420
+ return;
10421
+ }
10422
+ if (request.generation && request.generation !== generation) {
10423
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "generation_mismatch", message: `This state belongs to broker generation ${request.generation}; the live broker is ${generation}. Observe again.` } });
10424
+ return;
10425
+ }
10426
+ if (entries.size >= 256) {
10427
+ for (const [id, candidate] of entries) {
10428
+ if (candidate.state === "done" || candidate.state === "error" || candidate.state === "unknown") {
10429
+ entries.delete(id);
10430
+ break;
10431
+ }
10432
+ }
10433
+ }
10434
+ const entry = {
10435
+ requestId: request.requestId,
10436
+ ownerId: request.ownerId,
10437
+ command: request.command,
10438
+ state: "queued",
10439
+ dispatched: false,
10440
+ finished: false,
10441
+ slotHeld: false,
10442
+ controller: new AbortController(),
10443
+ fingerprint,
10444
+ cwd: request.cwd,
10445
+ socket,
10446
+ startedAt: Date.now()
9098
10447
  };
9099
- if (details.outline?.root && typeof details.outline.lookId === "string") {
9100
- const epoch = 0;
9101
- resourceScheduler.restoreEpoch(resourceKey, epoch);
9102
- savedStates.set({
9103
- stateId: capture.stateId,
9104
- resourceKey,
9105
- epoch,
9106
- value: {
9107
- kind: "desktop",
9108
- target,
9109
- capture,
9110
- outline: details.outline,
9111
- look: {
9112
- lookId: details.outline.lookId,
9113
- capturedAt: details.capture.timestamp / 1e3,
9114
- window: {
9115
- windowId: Math.trunc(details.target.windowId),
9116
- framePoints: { x: 0, y: 0, w: details.capture.width, h: details.capture.height },
9117
- scaleFactor: details.capture.scaleFactor,
9118
- isModal: false,
9119
- role: "",
9120
- subrole: ""
9121
- },
9122
- image: { jpegBase64: "", width: details.capture.width, height: details.capture.height },
9123
- timings: {}
9124
- },
9125
- note: details.note
10448
+ entries.set(key, entry);
10449
+ owners.add(request.ownerId);
10450
+ entry.timer = setTimeout(() => {
10451
+ if (entry.state === "queued") {
10452
+ entry.controller.abort();
10453
+ finish(entry, "error", void 0, { code: "cancelled", message: "Request was cancelled while queued; it was not dispatched.", dispatched: false });
10454
+ return;
10455
+ }
10456
+ if (entry.state === "running") {
10457
+ if (!entry.dispatched) {
10458
+ entry.controller.abort();
10459
+ finish(entry, "error", void 0, { code: "cancelled", message: "Request was cancelled while waiting for the resource lane; it was not dispatched.", dispatched: false });
10460
+ return;
9126
10461
  }
10462
+ finish(entry, "unknown", void 0, { code: "outcome_unknown", message: "The broker did not observe completion within the request budget. The native action may have been dispatched; do not replay it. Observe the resource again to establish a successor state.", dispatched: true });
10463
+ }
10464
+ }, request.budgetMs);
10465
+ const acquired = await acquireSlot(entry);
10466
+ if (!acquired) {
10467
+ if (entry.state === "queued") {
10468
+ finish(entry, "error", void 0, { code: "broker_busy", message: "The broker queue is full; no action was dispatched. Retry later." });
10469
+ }
10470
+ return;
10471
+ }
10472
+ if (entry.controller.signal.aborted) {
10473
+ finish(entry, "error", void 0, { code: "cancelled", message: "Request was cancelled before dispatch.", dispatched: false });
10474
+ return;
10475
+ }
10476
+ entry.slotHeld = true;
10477
+ await runEntry(entry, request);
10478
+ };
10479
+ const handleControl = async (request, socket) => {
10480
+ if ((stopping || drainRequested) && request.command !== "stop") {
10481
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "broker_draining", message: "The broker is shutting down and draining in-flight work; control requests other than 'stop' are unavailable. Retry after it exits." } });
10482
+ return;
10483
+ }
10484
+ if (request.command === "status") {
10485
+ send(socket, { type: "response", requestId: request.requestId, ok: true, state: "done", generation, helperGeneration: currentHelperGenerationSafe(), result: statusHandle?.status() });
10486
+ return;
10487
+ }
10488
+ if (request.command === "debug_restart_helper") {
10489
+ if (!options.testCommands) {
10490
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "unknown_command", message: "Test commands are disabled." } });
10491
+ return;
10492
+ }
10493
+ const helper = bumpHelperGeneration();
10494
+ liveHelperGeneration = helper;
10495
+ expireStatesAfterHelperRestart();
10496
+ const fake = options.restartTestHelper?.();
10497
+ send(socket, { type: "response", requestId: request.requestId, ok: true, state: "done", generation, helperGeneration: helper, result: { helperGeneration: helper, fakeHelperGeneration: fake } });
10498
+ return;
10499
+ }
10500
+ drainRequested = true;
10501
+ lastActivity = Date.now();
10502
+ send(socket, { type: "response", requestId: request.requestId, ok: true, state: "done", generation, helperGeneration: currentHelperGenerationSafe(), result: { stopping: true } });
10503
+ setTimeout(() => {
10504
+ void shutdown("stop");
10505
+ }, 10);
10506
+ };
10507
+ const connections = /* @__PURE__ */ new Set();
10508
+ const server = net3.createServer((socket) => {
10509
+ lastActivity = Date.now();
10510
+ connections.add(socket);
10511
+ const decoder = new FrameDecoder();
10512
+ let helloOk = false;
10513
+ let helloRejected = false;
10514
+ const drainingConnection = stopping || drainRequested;
10515
+ if (drainingConnection) {
10516
+ send(socket, {
10517
+ type: "hello",
10518
+ ok: false,
10519
+ error: { code: "broker_draining", message: "The broker is shutting down and draining in-flight native work. No new request was accepted; retry after it exits." },
10520
+ protocolVersion: BROKER_PROTOCOL_VERSION,
10521
+ build: BROKER_BUILD,
10522
+ generation,
10523
+ pid: process.pid,
10524
+ startedAt
9127
10525
  });
9128
- restoredResources.add(resourceKey);
9129
10526
  }
10527
+ socket.on("error", () => {
10528
+ });
10529
+ socket.on("data", (chunk) => {
10530
+ let frames;
10531
+ try {
10532
+ frames = decoder.push(chunk);
10533
+ } catch (error) {
10534
+ const message = error instanceof Error ? error.message : String(error);
10535
+ send(socket, { type: "hello", ok: false, error: { code: "invalid_frame", message } });
10536
+ socket.destroy();
10537
+ return;
10538
+ }
10539
+ if (drainingConnection) {
10540
+ for (const frame of frames) {
10541
+ let request;
10542
+ try {
10543
+ request = validateRequest(frame);
10544
+ } catch {
10545
+ continue;
10546
+ }
10547
+ if (request.command === "stop") {
10548
+ void handleControl(request, socket);
10549
+ continue;
10550
+ }
10551
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "broker_draining", message: "The broker is shutting down and draining in-flight native work; this request was not accepted. Retry after it exits.", dispatched: false } });
10552
+ }
10553
+ return;
10554
+ }
10555
+ for (const frame of frames) {
10556
+ if (!helloOk) {
10557
+ if (helloRejected) {
10558
+ try {
10559
+ const request2 = validateRequest(frame);
10560
+ if (request2.command === "stop") {
10561
+ void handleControl(request2, socket);
10562
+ continue;
10563
+ }
10564
+ } catch {
10565
+ }
10566
+ send(socket, {
10567
+ type: "hello",
10568
+ ok: false,
10569
+ error: { code: "protocol_mismatch", message: "Only 'stop' is accepted before a compatible handshake." },
10570
+ protocolVersion: BROKER_PROTOCOL_VERSION,
10571
+ build: BROKER_BUILD,
10572
+ generation,
10573
+ pid: process.pid,
10574
+ startedAt
10575
+ });
10576
+ continue;
10577
+ }
10578
+ try {
10579
+ validateHello(frame);
10580
+ helloOk = true;
10581
+ send(socket, {
10582
+ type: "hello",
10583
+ ok: true,
10584
+ protocolVersion: BROKER_PROTOCOL_VERSION,
10585
+ build: BROKER_BUILD,
10586
+ generation,
10587
+ helperGeneration: currentHelperGenerationSafe(),
10588
+ pid: process.pid,
10589
+ startedAt,
10590
+ platform: process.platform,
10591
+ transport: endpoint.kind
10592
+ });
10593
+ } catch (error) {
10594
+ helloRejected = true;
10595
+ send(socket, {
10596
+ type: "hello",
10597
+ ok: false,
10598
+ error: { code: error.code ?? "protocol_mismatch", message: error instanceof Error ? error.message : String(error) },
10599
+ protocolVersion: BROKER_PROTOCOL_VERSION,
10600
+ build: BROKER_BUILD,
10601
+ generation,
10602
+ pid: process.pid,
10603
+ startedAt
10604
+ });
10605
+ }
10606
+ continue;
10607
+ }
10608
+ let request;
10609
+ try {
10610
+ request = validateRequest(frame);
10611
+ } catch (error) {
10612
+ send(socket, {
10613
+ type: "response",
10614
+ requestId: typeof frame?.requestId === "string" ? frame.requestId : "invalid",
10615
+ ok: false,
10616
+ state: "error",
10617
+ generation,
10618
+ helperGeneration: currentHelperGenerationSafe(),
10619
+ error: { code: error.code ?? "invalid_request", message: error instanceof Error ? error.message : String(error) }
10620
+ });
10621
+ continue;
10622
+ }
10623
+ void (request.command === "status" || request.command === "stop" || request.command === "debug_restart_helper" ? handleControl(request, socket) : handleEngineRequest(request, socket));
10624
+ }
10625
+ });
10626
+ socket.on("close", () => {
10627
+ connections.delete(socket);
10628
+ for (const entry of entries.values()) {
10629
+ if (entry.socket !== socket) continue;
10630
+ entry.socket = void 0;
10631
+ if (entry.state === "queued") {
10632
+ entry.controller.abort();
10633
+ }
10634
+ }
10635
+ });
10636
+ });
10637
+ const bootstrapLock = endpoint.kind === "unix-socket" ? acquireBootstrapLock(endpoint.directory) : () => {
10638
+ };
10639
+ try {
10640
+ let drainWaitUntil = 0;
10641
+ const waitForDrain = async () => {
10642
+ if (drainWaitUntil === 0) drainWaitUntil = Date.now() + BROKER_DRAIN_MAX_MS + 1e4;
10643
+ if (Date.now() >= drainWaitUntil) return false;
10644
+ await sleep3(100);
10645
+ return true;
10646
+ };
10647
+ for (let attempt = 0; ; attempt += 1) {
10648
+ try {
10649
+ await listen(server, endpoint);
10650
+ break;
10651
+ } catch (error) {
10652
+ if (error.code !== "EADDRINUSE") throw error;
10653
+ const probe = await probeBroker(endpoint);
10654
+ if (probe.live) {
10655
+ const reply = probe.live;
10656
+ if (reply.ok === false && reply.error.code === "broker_draining") {
10657
+ if (await waitForDrain()) continue;
10658
+ throw new Error(`The computer-use broker at ${endpoint.path} is still draining in-flight work. Refusing to start a second execution authority; retry shortly.`);
10659
+ }
10660
+ const incompatible = reply.ok === false || reply.build?.identity !== BROKER_BUILD.identity || reply.protocolVersion !== BROKER_PROTOCOL_VERSION;
10661
+ if (incompatible) {
10662
+ const detail = reply.ok === false ? reply.error.message : `build ${reply.build?.identity ?? "unknown"}`;
10663
+ throw new Error(`A different computer-use broker is already listening at ${endpoint.path} (${detail}). Run 'computer-use-axi stop' to restart it safely; refusing to start a second execution authority.`);
10664
+ }
10665
+ throw Object.assign(new Error(`Computer-use broker already running (pid ${reply.pid}, generation ${reply.generation}) at ${endpoint.path}.`), { code: "EXISTING_BROKER", generation: reply.generation });
10666
+ }
10667
+ if (probe.dead && canProveStaleEndpoint(endpoint)) {
10668
+ const marker = loadDrainMarker();
10669
+ if (marker && isAlive(marker.pid) && Date.now() < marker.deadlineAt + 1e4) {
10670
+ if (await waitForDrain()) continue;
10671
+ }
10672
+ removeStaleSocket(endpoint);
10673
+ continue;
10674
+ }
10675
+ if (attempt >= 4) throw error;
10676
+ throw new Error(`Computer-use endpoint ${endpoint.path} is in use and its owner cannot be proven stale (${probe.error ?? "no response"}). Refusing to steal it.`);
10677
+ }
10678
+ }
10679
+ } finally {
10680
+ bootstrapLock();
9130
10681
  }
10682
+ const shutdown = async (reason) => {
10683
+ if (stopping) return;
10684
+ stopping = true;
10685
+ drainRequested = true;
10686
+ if (idleTimer) clearInterval(idleTimer);
10687
+ try {
10688
+ saveDrainMarker({ pid: process.pid, startedAt: Date.now(), deadlineAt: Date.now() + BROKER_DRAIN_MAX_MS });
10689
+ } catch {
10690
+ }
10691
+ for (const entry of entries.values()) {
10692
+ if (entry.state === "queued") {
10693
+ entry.controller.abort();
10694
+ if (entry.timer) clearTimeout(entry.timer);
10695
+ entry.socket = void 0;
10696
+ }
10697
+ }
10698
+ const deadline = Date.now() + BROKER_DRAIN_MAX_MS;
10699
+ while ([...entries.values()].some((entry) => entry.state === "running" || entry.state === "unknown") && Date.now() < deadline) {
10700
+ await sleep3(50);
10701
+ }
10702
+ persistManifest();
10703
+ try {
10704
+ await Promise.race([shutdownComputerUseSession(), sleep3(1e4)]);
10705
+ } catch {
10706
+ }
10707
+ artifacts.close();
10708
+ try {
10709
+ artifacts.cleanupGeneration(generation);
10710
+ } catch {
10711
+ }
10712
+ await new Promise((resolve2) => {
10713
+ let settled = false;
10714
+ const done = () => {
10715
+ if (!settled) {
10716
+ settled = true;
10717
+ resolve2();
10718
+ }
10719
+ };
10720
+ server.close(done);
10721
+ const timer = setTimeout(() => {
10722
+ for (const socket of connections) socket.destroy();
10723
+ done();
10724
+ }, 1e3);
10725
+ timer.unref?.();
10726
+ });
10727
+ try {
10728
+ clearDrainMarker();
10729
+ } catch {
10730
+ }
10731
+ if (endpoint.kind === "unix-socket") {
10732
+ try {
10733
+ const stats = lstatSync4(endpoint.path);
10734
+ if (stats.isSocket()) unlinkSync4(endpoint.path);
10735
+ } catch {
10736
+ }
10737
+ }
10738
+ options.onShutdown?.();
10739
+ void reason;
10740
+ };
10741
+ statusHandle = {
10742
+ generation,
10743
+ helperGeneration: helperGeneration2,
10744
+ endpoint,
10745
+ startedAt,
10746
+ status() {
10747
+ const uncertain = [...entries.values()].filter((entry) => entry.state === "unknown").length;
10748
+ return {
10749
+ pid: process.pid,
10750
+ generation,
10751
+ helperGeneration: currentHelperGenerationSafe(),
10752
+ build: BROKER_BUILD,
10753
+ protocolVersion: BROKER_PROTOCOL_VERSION,
10754
+ startedAt,
10755
+ uptimeMs: Date.now() - startedAt,
10756
+ endpoint: { kind: endpoint.kind, path: endpoint.path },
10757
+ transportAcl: endpoint.kind === "unix-socket" ? "unix socket 0600 inside a 0700 directory" : "windows named pipe with the Node process-default DACL (not explicitly SID-scoped; unverified on this host)",
10758
+ active,
10759
+ queued,
10760
+ uncertain,
10761
+ requests: entries.size,
10762
+ ownerCount: owners.size,
10763
+ ownerFingerprints: [...owners].map((owner) => createHash3("sha256").update(owner).digest("hex").slice(0, 12)),
10764
+ artifacts: artifacts.stats(),
10765
+ legacyCache,
10766
+ idleExitMs
10767
+ };
10768
+ },
10769
+ async close() {
10770
+ await shutdown("close");
10771
+ }
10772
+ };
10773
+ idleTimer = setInterval(() => {
10774
+ if (stopping) return;
10775
+ const uncertain = [...entries.values()].some((entry) => entry.state === "running" || entry.state === "unknown" || entry.state === "queued");
10776
+ if (uncertain) return;
10777
+ if (Date.now() - lastActivity < idleExitMs) return;
10778
+ void shutdown("idle");
10779
+ }, Math.min(6e4, Math.max(1e3, Math.floor(idleExitMs / 4))));
10780
+ idleTimer.unref?.();
10781
+ return statusHandle;
9131
10782
  }
9132
10783
 
9133
- // builtin/extensions/computer-use/index.ts
9134
- var stateId = Type.String({ description: "Required state id owning every @e ref used by this operation" });
9135
- var point = { x: Type.Number(), y: Type.Number() };
9136
- var mouseButton2 = Type.Optional(Type.Union([Type.Literal("left"), Type.Literal("right"), Type.Literal("middle")]));
9137
- var clickByRef = Type.Object({ action: Type.Literal("click"), ref: Type.String(), button: mouseButton2, clickCount: Type.Optional(Type.Number({ minimum: 1, maximum: 3 })) });
9138
- var clickByPoint = Type.Object({ action: Type.Literal("click"), ...point, button: mouseButton2, clickCount: Type.Optional(Type.Number({ minimum: 1, maximum: 3 })) });
9139
- var uiAction = Type.Union([
9140
- Type.Object({ action: Type.Literal("press"), ref: Type.String({ description: "Actionable outline ref" }) }),
9141
- clickByRef,
9142
- clickByPoint,
9143
- Type.Object({ action: Type.Literal("setText"), ref: Type.String({ description: "Editable outline ref" }), text: Type.String() }),
9144
- Type.Object({ action: Type.Literal("typeText"), ref: Type.Optional(Type.String({ description: "Omit after a click to type into the focus established by that click" })), text: Type.String() }),
9145
- Type.Object({ action: Type.Literal("keypress"), ref: Type.Optional(Type.String({ description: "Omit to send keys to the focused control" })), keys: Type.Array(Type.String(), { minItems: 1 }) }),
9146
- Type.Object({ action: Type.Literal("scroll"), ref: Type.Optional(Type.String()), scrollX: Type.Optional(Type.Number()), scrollY: Type.Optional(Type.Number()) }),
9147
- Type.Object({ action: Type.Literal("drag"), path: Type.Array(Type.Object(point), { minItems: 2 }) }),
9148
- Type.Object({ action: Type.Literal("moveMouse"), ...point })
9149
- ]);
9150
- var conditionProperties = {
9151
- ref: Type.Optional(Type.String({ description: "Specific @e ref to test", maxLength: 128 })),
9152
- scopeRef: Type.Optional(Type.String({ description: "Restrict matching to this @e subtree", maxLength: 128 })),
9153
- text: Type.Optional(Type.String({ description: "Text that must match", maxLength: 512 })),
9154
- role: Type.Optional(Type.String({ description: "Exact normalized role", maxLength: 128 })),
9155
- value: Type.Optional(Type.String({ description: "Exact normalized value; normally pair with ref" })),
9156
- until: Type.Optional(Type.Union([Type.Literal("present"), Type.Literal("absent")], { description: "Desired condition, default present" })),
9157
- timeoutMs: Type.Optional(Type.Number({ description: "Maximum wait, default 10000ms", minimum: 100, maximum: 6e4 }))
9158
- };
9159
- var OBSERVE_RISK = {
9160
- riskClass: "read_only",
9161
- concurrencySafe: false,
9162
- permissionScope: "host",
9163
- readsHostResource: true,
9164
- allowedForSubagentByDefault: false
9165
- };
9166
- var BROWSER_RISK = {
9167
- riskClass: "external_side_effect",
9168
- concurrencySafe: false,
9169
- requiresPermission: true,
9170
- permissionScope: "host",
9171
- externalSideEffect: true,
9172
- allowedForSubagentByDefault: false
9173
- };
9174
- var ACT_RISK = {
9175
- riskClass: "external_side_effect",
9176
- concurrencySafe: false,
9177
- requiresPermission: true,
9178
- permissionScope: "host",
9179
- writesHostResource: true,
9180
- externalSideEffect: true,
9181
- highRisk: true,
9182
- allowedForSubagentByDefault: false
9183
- };
9184
- function describe(description, ...extra) {
9185
- const lines = [description];
9186
- for (const part of extra) {
9187
- if (!part) continue;
9188
- for (const line of Array.isArray(part) ? part : [part]) lines.push(line);
9189
- }
9190
- return lines.join(" ");
9191
- }
9192
- var findTool = {
9193
- name: "find_roots",
9194
- label: "Find Roots",
9195
- risk: OBSERVE_RISK,
9196
- description: describe(
9197
- "Find a bounded, ranked set of controllable UI roots with refs, geometry, and focus state.",
9198
- "Find a target root before observe_ui when needed. Desktop control is a last resort - prefer API/CLI/web tools when they suffice."
9199
- ),
9200
- parameters: Type.Object({
9201
- text: Type.Optional(Type.String({ description: "Ranked app or title text", maxLength: 256 })),
9202
- app: Type.Optional(Type.String({ description: "Exact normalized app name", maxLength: 256 })),
9203
- bundleId: Type.Optional(Type.String({ description: "Exact bundle id" })),
9204
- pid: Type.Optional(Type.Number({ description: "Exact process id" })),
9205
- kind: Type.Optional(Type.Union([Type.Literal("window"), Type.Literal("menu"), Type.Literal("sheet"), Type.Literal("popover"), Type.Literal("dialog"), Type.Literal("browser_page")], { description: "Exact root kind" }))
9206
- }),
9207
- executor: executeFind
9208
- };
9209
- var observeTool = {
9210
- name: "observe_ui",
9211
- label: "Observe UI",
9212
- risk: OBSERVE_RISK,
9213
- description: describe(
9214
- "Capture the current/frontmost root or one exact @r root and return a bounded UI outline.",
9215
- "Primary UI observation tool. Follow with search_ui, expand_ui, inspect_ui, or act_ui.",
9216
- [
9217
- "Use mode=semantic to skip OCR and images, visual to force them, and fused for automatic selection.",
9218
- "Use @e outline refs from observe_ui/search_ui for act_ui; pictureOnly refs are coordinate-only and blocked by UI-tree-only policy."
9219
- ]
9220
- ),
9221
- parameters: Type.Object({
9222
- root: Type.Optional(Type.String({ description: "Exact @r ref issued by find_roots" })),
9223
- mode: Type.Optional(Type.Union([Type.Literal("semantic"), Type.Literal("visual"), Type.Literal("fused")], { description: "Observation mode, default fused" }))
9224
- }),
9225
- executor: executeObserve
9226
- };
9227
- var searchUiTool = {
9228
- name: "search_ui",
9229
- label: "Search UI",
9230
- risk: OBSERVE_RISK,
9231
- description: describe(
9232
- "Return a bounded, deterministically ranked search of the cached outline. At least one predicate is required.",
9233
- "Find targets not shown in the compact observe_ui output; refine broad searches instead of paging matches."
9234
- ),
9235
- parameters: Type.Object({
9236
- text: Type.Optional(Type.String({ description: "Human-readable text or label", maxLength: 256 })),
9237
- role: Type.Optional(Type.String({ description: "Exact normalized role, e.g. button", maxLength: 128 })),
9238
- capability: Type.Optional(Type.String({ description: "Exact capability, e.g. press", maxLength: 128 })),
9239
- stateId
9240
- }),
9241
- executor: executeSearchUi
9242
- };
9243
- var expandUiTool = {
9244
- name: "expand_ui",
9245
- label: "Expand UI",
9246
- risk: OBSERVE_RISK,
9247
- description: describe(
9248
- "Unfold bounded local outline context for one @e ref.",
9249
- "Expand a specific ref instead of dumping unrelated UI."
9250
- ),
9251
- parameters: Type.Object({ ref: Type.String(), depth: Type.Optional(Type.Number({ minimum: 1, maximum: 8, description: "Subtree depth, default 3" })), stateId }),
9252
- executor: executeExpandUi
9253
- };
9254
- var inspectUiTool = {
9255
- name: "inspect_ui",
9256
- label: "Inspect UI",
9257
- risk: OBSERVE_RISK,
9258
- description: describe(
9259
- "Inspect one exact outline ref with fields, geometry, capabilities, and annotations.",
9260
- "Use when a target's evidence or provenance matters."
9261
- ),
9262
- parameters: Type.Object({ ref: Type.String(), stateId }),
9263
- executor: executeInspectUi
9264
- };
9265
- var actTool = {
9266
- name: "act_ui",
9267
- label: "Act",
9268
- risk: ACT_RISK,
9269
- description: describe(
9270
- "Perform one or more precisely targeted checked actions and return the successor state.",
9271
- "Pass dependent click/type steps together and use expect for observable completion.",
9272
- ["After clicking an editable region, omit ref from typeText/keypress so input follows the established focus."]
9273
- ),
9274
- parameters: Type.Object({ stateId, expect: Type.Optional(Type.Object(conditionProperties)), actions: Type.Array(uiAction, { minItems: 1, maxItems: 20 }) }),
9275
- executor: executeAct
9276
- };
9277
- var readTextTool = {
9278
- name: "read_text",
9279
- label: "Read Text",
9280
- risk: OBSERVE_RISK,
9281
- description: describe(
9282
- "Read a fixed-size page from an @e UI ref or immutable @o truncated-output ref.",
9283
- "Use @e with its stateId; @o continuation refs don't need stateId."
9284
- ),
9285
- parameters: Type.Object({ ref: Type.String(), offset: Type.Optional(Type.Number({ minimum: 0 })), stateId: Type.Optional(stateId) }),
9286
- executor: executeReadText
9287
- };
9288
- var waitForTool = {
9289
- name: "wait_for",
9290
- label: "Wait For",
9291
- risk: OBSERVE_RISK,
9292
- description: describe(
9293
- "Wait for one scoped UI condition and return the successor state.",
9294
- "Use after asynchronous UI changes instead of polling observe_ui."
9295
- ),
9296
- parameters: Type.Object({ ...conditionProperties, stateId }),
9297
- executor: executeWaitFor
9298
- };
9299
- var launchBrowserTool = {
9300
- name: "launch_browser",
9301
- label: "Launch Browser Context",
9302
- risk: BROWSER_RISK,
9303
- description: describe(
9304
- "Launch the configured Pie-managed CDP browser and return an observed browser-page state.",
9305
- "Use for browser work that needs a managed CDP context.",
9306
- ["Prefer curl through bash when the page is directly fetchable."]
9307
- ),
9308
- parameters: Type.Object({ url: Type.Optional(Type.String({ maxLength: 8192 })) }),
9309
- executor: executeLaunchBrowser
9310
- };
9311
- var navigateBrowserTool = {
9312
- name: "navigate_browser",
9313
- label: "Navigate Browser",
9314
- risk: BROWSER_RISK,
9315
- description: describe(
9316
- "Navigate an observed CDP browser-page state to an HTTP(S) URL.",
9317
- "Native browser windows use act_ui; this tool is CDP-only."
9318
- ),
9319
- parameters: Type.Object({ url: Type.String({ maxLength: 8192 }), stateId }),
9320
- executor: executeNavigateBrowser
9321
- };
9322
- var evaluateBrowserTool = {
9323
- name: "evaluate_browser",
9324
- label: "Evaluate Browser",
9325
- risk: BROWSER_RISK,
9326
- description: describe(
9327
- "Evaluate targeted JavaScript in a CDP browser-page state; returned output is strictly bounded.",
9328
- "Prefer observe/search/read; return selected fields, aggregates, or bounded slices."
9329
- ),
9330
- parameters: Type.Object({ stateId, expression: Type.String({ maxLength: 65536 }) }),
9331
- executor: executeEvaluateBrowser
9332
- };
9333
- var OBSERVE_TOOLS = [findTool, observeTool, searchUiTool, expandUiTool, inspectUiTool, readTextTool, waitForTool, launchBrowserTool, navigateBrowserTool, evaluateBrowserTool];
9334
- var ACT_TOOLS = [actTool];
9335
- function summarizeActArgs(args) {
9336
- const actions = args?.actions;
9337
- if (!Array.isArray(actions) || actions.length === 0) return "(no actions)";
9338
- const names = actions.map((action) => action?.action ?? "unknown");
9339
- const unique = [...new Set(names)];
9340
- return `${actions.length} action(s): ${unique.join(", ")}`;
9341
- }
9342
- async function confirmAct(ctx, args) {
9343
- if (ctx.yoloMode) return true;
9344
- if (!ctx.interactions.isAvailable()) return false;
9345
- const response = await ctx.interactions.request({
9346
- type: "confirm",
9347
- id: `computer-use:${Date.now()}`,
9348
- prompt: "Allow computer-use to act on your desktop (click/type/scroll/press)?",
9349
- detail: [
9350
- "Class: computer_use_act",
9351
- `Tool: act_ui \u2014 ${summarizeActArgs(args)}`,
9352
- "",
9353
- "The agent will synthesize real input events on your machine."
9354
- ].join("\n"),
9355
- timeoutMs: 12e4
9356
- }).catch(() => void 0);
9357
- return !!response && response.type === "confirm" && response.confirmed === true;
9358
- }
9359
- function blockedActResult() {
9360
- return {
9361
- content: [{
9362
- type: "text",
9363
- text: "act_ui was blocked: the user did not confirm desktop control (or no interaction handler is available). Do not retry act_ui; explain what you intended to do and ask the user how to proceed."
9364
- }],
9365
- isError: true
9366
- };
10784
+ // vendor/computer-use-axi/src/test-backend-guard.ts
10785
+ function resolveTestOnlyBackend(env = process.env) {
10786
+ if (env.PIE_COMPUTER_USE_FAKE_BACKEND !== "1") return { enabled: false };
10787
+ if (env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS !== "1") {
10788
+ return {
10789
+ enabled: false,
10790
+ warning: "PIE_COMPUTER_USE_FAKE_BACKEND is test-only and was ignored: it requires PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS=1 as well."
10791
+ };
10792
+ }
10793
+ return { enabled: true };
9367
10794
  }
9368
- function registerPieTool(ctx, spec, options = {}) {
9369
- ctx.registerTool({
9370
- name: spec.name,
9371
- label: spec.label,
9372
- description: spec.description,
9373
- parameters: spec.parameters,
9374
- risk: spec.risk,
9375
- execute: async (args, toolContext) => {
9376
- if (options.confirmAct) {
9377
- const approved = await options.confirmAct(args);
9378
- if (!approved) return blockedActResult();
9379
- }
9380
- const result = await spec.executor(toolContext.toolCallId, args, toolContext.signal, void 0, ctx);
9381
- return result;
10795
+
10796
+ // vendor/computer-use-axi/src/broker-main.ts
10797
+ async function loadTestOnlyBackend() {
10798
+ const decision = resolveTestOnlyBackend();
10799
+ if (decision.warning) process.stderr.write(`computer-use-axi broker: ${decision.warning}
10800
+ `);
10801
+ if (!decision.enabled) return void 0;
10802
+ const fakeBackendModule = "./platform/fake-backend.ts";
10803
+ try {
10804
+ const { createFakePlatformBackend } = await import(fakeBackendModule);
10805
+ const fake = createFakePlatformBackend();
10806
+ setPlatformBackend(fake);
10807
+ return fake;
10808
+ } catch (error) {
10809
+ process.stderr.write(
10810
+ `computer-use-axi broker: the test-only fake backend is not available in this build (${error instanceof Error ? error.message : String(error)}); continuing with the real platform backend.
10811
+ `
10812
+ );
10813
+ return void 0;
10814
+ }
10815
+ }
10816
+ async function main() {
10817
+ const fake = await loadTestOnlyBackend();
10818
+ const handle = await startBroker({
10819
+ testCommands: process.env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS === "1",
10820
+ restartTestHelper: fake ? () => fake.fakeControl.restart() : void 0,
10821
+ onShutdown: () => {
10822
+ setTimeout(() => process.exit(0), 50).unref();
9382
10823
  }
9383
10824
  });
9384
- }
9385
- function formatConfigStatus() {
9386
- const loaded = getLoadedComputerUseConfig();
9387
- return [
9388
- "computer-use configuration",
9389
- `browser_use: ${loaded.config.browser_use ? "enabled" : "disabled"}`,
9390
- `managed_browser: ${loaded.config.managed_browser}`,
9391
- `headless: ${loaded.config.headless ? "enabled" : "disabled"}`,
9392
- `cursor_overlay: ${loaded.config.cursor_overlay ? "enabled" : "disabled"}`,
9393
- "",
9394
- "Sources:",
9395
- ...loaded.sources.map((source) => `- ${source.path}: ${source.error ? `error: ${source.error}` : source.exists ? "loaded" : "not found"}`),
9396
- `- env overrides: ${Object.keys(loaded.env).join(", ") || "none"}`
9397
- ].join("\n");
9398
- }
9399
- async function initializeSessionState(ctx) {
9400
- loadComputerUseConfig(ctx.cwd);
9401
- reconstructStateFromBranch(ctx);
9402
- }
9403
- function computerUseExtension(ctx) {
9404
- ctx.registerCleanup?.(() => shutdownComputerUseSession());
9405
- let actApproved = false;
9406
- const confirmActOnce = async (args) => {
9407
- if (actApproved) return true;
9408
- const approved = await confirmAct(ctx, args);
9409
- if (approved) actApproved = true;
9410
- return approved;
10825
+ const stop = () => {
10826
+ void handle.close().catch(() => void 0);
9411
10827
  };
9412
- for (const spec of OBSERVE_TOOLS) registerPieTool(ctx, spec);
9413
- for (const spec of ACT_TOOLS) registerPieTool(ctx, spec, {
9414
- confirmAct: async (args) => await confirmActOnce(args)
10828
+ process.on("SIGTERM", stop);
10829
+ process.on("SIGINT", stop);
10830
+ process.on("SIGHUP", stop);
10831
+ process.on("uncaughtException", (error) => {
10832
+ process.stderr.write(`computer-use-axi broker fatal: ${error instanceof Error ? error.stack ?? error.message : String(error)}
10833
+ `);
10834
+ process.exit(1);
9415
10835
  });
9416
- ctx.registerCommand({
9417
- name: "computer-use",
9418
- description: "Show computer-use configuration",
9419
- handler: (commandCtx) => {
9420
- loadComputerUseConfig(commandCtx.cwd);
9421
- commandCtx.ui.notify(formatConfigStatus(), "info");
9422
- }
9423
- });
9424
- ctx.on("session:changed", async () => {
9425
- actApproved = false;
9426
- await shutdownComputerUseSession().catch(() => void 0);
9427
- await initializeSessionState(ctx);
10836
+ process.on("unhandledRejection", (reason) => {
10837
+ process.stderr.write(`computer-use-axi broker unhandled rejection: ${reason instanceof Error ? reason.stack ?? reason.message : String(reason)}
10838
+ `);
9428
10839
  });
9429
10840
  }
9430
- export {
9431
- computerUseExtension as default
9432
- };
10841
+ main().catch((error) => {
10842
+ const code = error.code;
10843
+ process.stderr.write(`computer-use-axi broker: ${error instanceof Error ? error.message : String(error)}
10844
+ `);
10845
+ process.exit(code === "EXISTING_BROKER" ? 0 : 1);
10846
+ });