@cydm/pie 2.7.3 → 2.7.5

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.
@@ -48,6 +48,31 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
48
48
  mod
49
49
  ));
50
50
 
51
+ // vendor/computer-use-axi/src/test-backend-guard.ts
52
+ function requireFakeBackend(env = process.env) {
53
+ return env.PIE_COMPUTER_USE_REQUIRE_FAKE_BACKEND === "1";
54
+ }
55
+ function assertNativeBackendAllowed() {
56
+ if (requireFakeBackend()) throw new Error("Required fake backend: native desktop access is forbidden (backend not installed in this module instance).");
57
+ }
58
+ function resolveTestOnlyBackend(env = process.env) {
59
+ if (requireFakeBackend(env) && (env.PIE_COMPUTER_USE_FAKE_BACKEND !== "1" || env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS !== "1")) {
60
+ throw new Error("Required fake backend needs PIE_COMPUTER_USE_FAKE_BACKEND=1 and PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS=1.");
61
+ }
62
+ if (env.PIE_COMPUTER_USE_FAKE_BACKEND !== "1") return { enabled: false };
63
+ if (env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS !== "1") {
64
+ return {
65
+ enabled: false,
66
+ warning: "PIE_COMPUTER_USE_FAKE_BACKEND is test-only and was ignored: it requires PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS=1 as well."
67
+ };
68
+ }
69
+ return { enabled: true };
70
+ }
71
+ var init_test_backend_guard = __esm({
72
+ "vendor/computer-use-axi/src/test-backend-guard.ts"() {
73
+ }
74
+ });
75
+
51
76
  // vendor/computer-use-axi/src/platform/coerce.ts
52
77
  function toBoolean(value) {
53
78
  return value === true || value === "true" || value === 1;
@@ -2307,7 +2332,7 @@ var require_websocket = __commonJS({
2307
2332
  var http = __require("http");
2308
2333
  var net4 = __require("net");
2309
2334
  var tls = __require("tls");
2310
- var { randomBytes, createHash: createHash4 } = __require("crypto");
2335
+ var { randomBytes, createHash: createHash5 } = __require("crypto");
2311
2336
  var { Duplex, Readable } = __require("stream");
2312
2337
  var { URL: URL2 } = __require("url");
2313
2338
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -2988,7 +3013,7 @@ var require_websocket = __commonJS({
2988
3013
  abortHandshake(websocket, socket, "Invalid Upgrade header");
2989
3014
  return;
2990
3015
  }
2991
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
3016
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
2992
3017
  if (res.headers["sec-websocket-accept"] !== digest) {
2993
3018
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2994
3019
  return;
@@ -3357,7 +3382,7 @@ var require_websocket_server = __commonJS({
3357
3382
  var EventEmitter = __require("events");
3358
3383
  var http = __require("http");
3359
3384
  var { Duplex } = __require("stream");
3360
- var { createHash: createHash4 } = __require("crypto");
3385
+ var { createHash: createHash5 } = __require("crypto");
3361
3386
  var extension2 = require_extension();
3362
3387
  var PerMessageDeflate2 = require_permessage_deflate();
3363
3388
  var subprotocol2 = require_subprotocol();
@@ -3664,7 +3689,7 @@ var require_websocket_server = __commonJS({
3664
3689
  );
3665
3690
  }
3666
3691
  if (this._state > RUNNING) return abortHandshake(socket, 503);
3667
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
3692
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
3668
3693
  const headers = [
3669
3694
  "HTTP/1.1 101 Switching Protocols",
3670
3695
  "Upgrade: websocket",
@@ -3852,6 +3877,7 @@ async function isResolvedHelperExecutable(filePath) {
3852
3877
  return actualPath === expectedPath;
3853
3878
  }
3854
3879
  async function runProcess(command, args, timeoutMs, signal, env) {
3880
+ assertNativeBackendAllowed();
3855
3881
  throwIfAborted(signal);
3856
3882
  await new Promise((resolve2, reject) => {
3857
3883
  const child = spawn(command, args, {
@@ -3900,6 +3926,7 @@ ${output}`.trim()));
3900
3926
  var COMMAND_TIMEOUT_MS2, HELPER_PROTOCOL_VERSION, HELPER_SETUP_TIMEOUT_MS, HELPER_APP_PATH, HELPER_APP_EXECUTABLE_PATH, DEFAULT_HELPER_SOCKET_PATH, HELPER_SOCKET_PATH, usingExternalHelperSocket, PACKAGE_ROOT, SETUP_HELPER_SCRIPT, HelperTransportError, HelperCommandError, MacosHelperClient, macosHelper;
3901
3927
  var init_helper = __esm({
3902
3928
  "vendor/computer-use-axi/src/platform/macos/helper.ts"() {
3929
+ init_test_backend_guard();
3903
3930
  init_coerce();
3904
3931
  init_helper_path();
3905
3932
  init_package_root();
@@ -3935,6 +3962,7 @@ var init_helper = __esm({
3935
3962
  return this.diagnosticsCache;
3936
3963
  }
3937
3964
  async ensureInstalled(signal) {
3965
+ assertNativeBackendAllowed();
3938
3966
  if (usingExternalHelperSocket) return;
3939
3967
  if (await isExecutable(HELPER_APP_EXECUTABLE_PATH)) {
3940
3968
  return;
@@ -3949,11 +3977,13 @@ var init_helper = __esm({
3949
3977
  }
3950
3978
  }
3951
3979
  async launchDaemon(signal) {
3980
+ assertNativeBackendAllowed();
3952
3981
  if (usingExternalHelperSocket) throw new HelperTransportError(`External helper socket is unavailable at ${HELPER_SOCKET_PATH}.`);
3953
3982
  await mkdir(path9.dirname(HELPER_SOCKET_PATH), { recursive: true });
3954
3983
  await runProcess("open", ["-n", "-g", HELPER_APP_PATH, "--args", "serve", "--socket", HELPER_SOCKET_PATH], COMMAND_TIMEOUT_MS2, signal);
3955
3984
  }
3956
3985
  async daemonCommand(cmd, args, timeoutMs, signal) {
3986
+ assertNativeBackendAllowed();
3957
3987
  return await new Promise((resolve2, reject) => {
3958
3988
  const id = `req_${++this.requestSequence}`;
3959
3989
  const socket = net.createConnection(HELPER_SOCKET_PATH);
@@ -3996,6 +4026,7 @@ var init_helper = __esm({
3996
4026
  });
3997
4027
  }
3998
4028
  async ensureDaemon(signal) {
4029
+ assertNativeBackendAllowed();
3999
4030
  if (this.daemonAvailable) return true;
4000
4031
  try {
4001
4032
  await this.daemonCommand("diagnostics", {}, 1e3, signal);
@@ -4028,6 +4059,7 @@ var init_helper = __esm({
4028
4059
  }
4029
4060
  }
4030
4061
  async restart(signal) {
4062
+ assertNativeBackendAllowed();
4031
4063
  await this.command("shutdown", {}, { signal, timeoutMs: 2e3 }).catch(() => void 0);
4032
4064
  this.daemonAvailable = false;
4033
4065
  await sleep(400, signal);
@@ -4310,23 +4342,25 @@ var init_permissions2 = __esm({
4310
4342
  });
4311
4343
 
4312
4344
  // vendor/computer-use-axi/src/broker-server.ts
4313
- import { createHash as createHash3, randomUUID as randomUUID8 } from "node:crypto";
4345
+ init_test_backend_guard();
4346
+ import { createHash as createHash4, randomUUID as randomUUID8 } from "node:crypto";
4314
4347
  import { chmodSync as chmodSync2, lstatSync as lstatSync4, readFileSync as readFileSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
4315
4348
  import net3 from "node:net";
4316
4349
  import path14 from "node:path";
4317
4350
 
4318
4351
  // vendor/computer-use-axi/src/artifact-store.ts
4319
4352
  import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
4320
- import { closeSync, existsSync as existsSync2, lstatSync as lstatSync3, mkdirSync as mkdirSync4, openSync, readdirSync as readdirSync2, rmdirSync, unlinkSync as unlinkSync2, writeSync } from "node:fs";
4321
- import path3 from "node:path";
4353
+ import { closeSync, existsSync as existsSync3, lstatSync as lstatSync3, mkdirSync as mkdirSync4, openSync, readdirSync as readdirSync2, rmdirSync as rmdirSync2, unlinkSync as unlinkSync2, writeSync } from "node:fs";
4354
+ import path4 from "node:path";
4322
4355
 
4323
4356
  // vendor/computer-use-axi/src/broker-protocol.ts
4324
4357
  import { createHash, randomUUID } from "node:crypto";
4325
4358
  import { chmodSync, lstatSync as lstatSync2, mkdirSync as mkdirSync3 } from "node:fs";
4326
- import path2 from "node:path";
4359
+ import path3 from "node:path";
4327
4360
 
4328
- // vendor/computer-use-axi/src/persist.ts
4329
- import { lstatSync, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "node:fs";
4361
+ // vendor/computer-use-axi/src/config.ts
4362
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
4363
+ import { AsyncLocalStorage } from "node:async_hooks";
4330
4364
  import path from "node:path";
4331
4365
 
4332
4366
  // src/config.ts
@@ -4370,26 +4404,151 @@ function getConfigDir() {
4370
4404
  return join(homedir(), CONFIG_DIR_NAME);
4371
4405
  }
4372
4406
 
4407
+ // vendor/computer-use-axi/host.ts
4408
+ function getAgentDir() {
4409
+ return getConfigDir();
4410
+ }
4411
+
4412
+ // vendor/computer-use-axi/src/config.ts
4413
+ var DEFAULT_CONFIG = {
4414
+ browser_use: true,
4415
+ headless: false,
4416
+ cursor_overlay: true,
4417
+ managed_browser: "chrome"
4418
+ };
4419
+ var REQUEST_ENV_KEYS = ["PIE_COMPUTER_USE_BROWSER_USE", "PIE_COMPUTER_USE_HEADLESS", "PIE_COMPUTER_USE_CURSOR_OVERLAY", "PIE_COMPUTER_USE_MANAGED_BROWSER", "PIE_COMPUTER_USE_HELIUM_EXECUTABLE", "PIE_COMPUTER_USE_CHROME_EXECUTABLE", "PIE_COMPUTER_USE_CDP_PORT", "PIE_COMPUTER_USE_DELIVERY_POLICY", "PIE_COMPUTER_USE_EVENT_DELIVERY"];
4420
+ function captureComputerUseEnvironment(env = process.env) {
4421
+ const out = {};
4422
+ for (const key of REQUEST_ENV_KEYS) {
4423
+ const value = env[key]?.trim();
4424
+ if (!value) continue;
4425
+ if (Buffer.byteLength(value) > 4096 || value.includes("\0")) throw new Error(`Invalid ${key}`);
4426
+ if (["PIE_COMPUTER_USE_BROWSER_USE", "PIE_COMPUTER_USE_HEADLESS", "PIE_COMPUTER_USE_CURSOR_OVERLAY"].includes(key)) {
4427
+ const parsed = parseBoolean(value);
4428
+ if (parsed === void 0) throw new Error(`Invalid ${key}`);
4429
+ out[key] = String(parsed);
4430
+ } else if (key === "PIE_COMPUTER_USE_MANAGED_BROWSER") {
4431
+ if (value !== "helium" && value !== "chrome") throw new Error(`Invalid ${key}`);
4432
+ out[key] = value;
4433
+ } else if (key === "PIE_COMPUTER_USE_DELIVERY_POLICY" || key === "PIE_COMPUTER_USE_EVENT_DELIVERY") {
4434
+ const policy = value.toLowerCase();
4435
+ if (!["default", "background", "pid", "foreground", "hid", "ax_only", "ax-only"].includes(policy)) throw new Error(`Invalid ${key}`);
4436
+ out[key] = policy;
4437
+ } else if (key === "PIE_COMPUTER_USE_CDP_PORT") {
4438
+ if (!/^\d+$/.test(value) || Number(value) < 1 || Number(value) > 65535) throw new Error(`Invalid ${key}`);
4439
+ out[key] = String(Number(value));
4440
+ } else {
4441
+ if (!path.isAbsolute(value)) throw new Error(`Invalid ${key}: expected absolute path`);
4442
+ out[key] = value;
4443
+ }
4444
+ }
4445
+ return Object.freeze(out);
4446
+ }
4447
+ var managedCdpPort;
4448
+ function setManagedCdpPort(port) {
4449
+ managedCdpPort = port;
4450
+ }
4451
+ function getComputerUseEnvironmentValue(key) {
4452
+ return operationConfig.getStore()?.environment[key] ?? (key === "PIE_COMPUTER_USE_CDP_PORT" ? managedCdpPort : void 0);
4453
+ }
4454
+ var operationConfig = new AsyncLocalStorage();
4455
+ var defaultLoaded = Object.freeze({ config: Object.freeze({ ...DEFAULT_CONFIG }), sources: [], env: {}, environment: {} });
4456
+ function withComputerUseConfig(cwd, run, environment) {
4457
+ return operationConfig.run(loadComputerUseConfig(cwd, environment), run);
4458
+ }
4459
+ function parseBoolean(value) {
4460
+ if (typeof value === "boolean") return value;
4461
+ if (typeof value === "number") return value === 1 ? true : value === 0 ? false : void 0;
4462
+ if (typeof value !== "string") return void 0;
4463
+ const normalized = value.trim().toLowerCase();
4464
+ if (["1", "true", "yes", "on", "enabled"].includes(normalized)) return true;
4465
+ if (["0", "false", "no", "off", "disabled"].includes(normalized)) return false;
4466
+ return void 0;
4467
+ }
4468
+ function normalizePartial(raw) {
4469
+ if (!raw || typeof raw !== "object") return {};
4470
+ const source = raw.computer_use && typeof raw.computer_use === "object" ? raw.computer_use : raw;
4471
+ const out = {};
4472
+ const browserUse = parseBoolean(source.browser_use);
4473
+ const headless = parseBoolean(source.headless);
4474
+ const cursorOverlay = parseBoolean(source.cursor_overlay);
4475
+ if (browserUse !== void 0) out.browser_use = browserUse;
4476
+ if (headless !== void 0) out.headless = headless;
4477
+ if (cursorOverlay !== void 0) out.cursor_overlay = cursorOverlay;
4478
+ const managedBrowser = source.managed_browser;
4479
+ if (managedBrowser === "helium" || managedBrowser === "chrome") out.managed_browser = managedBrowser;
4480
+ return out;
4481
+ }
4482
+ function readConfigFile(filePath) {
4483
+ if (!existsSync2(filePath)) return { path: filePath, exists: false };
4484
+ try {
4485
+ const parsed = JSON.parse(readFileSync2(filePath, "utf-8"));
4486
+ return { path: filePath, exists: true, values: normalizePartial(parsed) };
4487
+ } catch (error) {
4488
+ return { path: filePath, exists: true, error: error instanceof Error ? error.message : String(error) };
4489
+ }
4490
+ }
4491
+ function readEnv(environment) {
4492
+ const out = {};
4493
+ const browserUse = parseBoolean(environment.PIE_COMPUTER_USE_BROWSER_USE);
4494
+ const headless = parseBoolean(environment.PIE_COMPUTER_USE_HEADLESS);
4495
+ const cursorOverlay = parseBoolean(environment.PIE_COMPUTER_USE_CURSOR_OVERLAY);
4496
+ if (browserUse !== void 0) out.browser_use = browserUse;
4497
+ if (headless !== void 0) out.headless = headless;
4498
+ if (cursorOverlay !== void 0) out.cursor_overlay = cursorOverlay;
4499
+ const managedBrowser = environment.PIE_COMPUTER_USE_MANAGED_BROWSER;
4500
+ if (managedBrowser === "helium" || managedBrowser === "chrome") out.managed_browser = managedBrowser;
4501
+ return out;
4502
+ }
4503
+ function loadComputerUseConfig(cwd, environment = captureComputerUseEnvironment()) {
4504
+ const sources = [
4505
+ readConfigFile(path.join(getAgentDir(), "extensions", "computer-use.json")),
4506
+ readConfigFile(path.join(cwd, ".pie", "computer-use.json"))
4507
+ ];
4508
+ environment = captureComputerUseEnvironment(environment);
4509
+ const env = readEnv(environment);
4510
+ const config = { ...DEFAULT_CONFIG };
4511
+ for (const source of sources) {
4512
+ if (source.values) Object.assign(config, source.values);
4513
+ }
4514
+ Object.assign(config, env);
4515
+ return Object.freeze({ config: Object.freeze(config), sources, env, environment });
4516
+ }
4517
+ function getComputerUseConfig() {
4518
+ return getLoadedComputerUseConfig().config;
4519
+ }
4520
+ function getLoadedComputerUseConfig() {
4521
+ return operationConfig.getStore() ?? defaultLoaded;
4522
+ }
4523
+ function isHeadlessMode() {
4524
+ return getComputerUseConfig().headless;
4525
+ }
4526
+ function isBrowserUseEnabled() {
4527
+ return getComputerUseConfig().browser_use;
4528
+ }
4529
+
4373
4530
  // vendor/computer-use-axi/src/persist.ts
4531
+ import { lstatSync, mkdirSync as mkdirSync2, opendirSync, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, rmdirSync, unlinkSync, writeFileSync } from "node:fs";
4532
+ import path2 from "node:path";
4374
4533
  function stateRootDir(env = process.env) {
4375
4534
  const override = env.PIE_COMPUTER_USE_STATE_DIR?.trim();
4376
4535
  if (override) return override;
4377
- return path.join(getConfigDir(), "computer-use");
4536
+ return path2.join(getConfigDir(), "computer-use");
4378
4537
  }
4379
4538
  function statesDir(env = process.env) {
4380
- return path.join(stateRootDir(env), "states");
4539
+ return path2.join(stateRootDir(env), "states");
4381
4540
  }
4382
4541
  function outputsDir(env = process.env) {
4383
- return path.join(stateRootDir(env), "outputs");
4542
+ return path2.join(stateRootDir(env), "outputs");
4384
4543
  }
4385
4544
  function runtimeStatePath(env = process.env) {
4386
- return path.join(stateRootDir(env), "runtime.json");
4545
+ return path2.join(stateRootDir(env), "runtime.json");
4387
4546
  }
4388
4547
  function brokerStateDir(env = process.env) {
4389
- return path.join(stateRootDir(env), "broker");
4548
+ return path2.join(stateRootDir(env), "broker");
4390
4549
  }
4391
4550
  function brokerManifestPath(env = process.env) {
4392
- return path.join(brokerStateDir(env), "manifest.json");
4551
+ return path2.join(brokerStateDir(env), "manifest.json");
4393
4552
  }
4394
4553
  function loadBrokerManifest(env = process.env) {
4395
4554
  const manifest = readJsonFile(brokerManifestPath(env));
@@ -4406,7 +4565,7 @@ function saveBrokerManifest(manifest, env = process.env) {
4406
4565
  writeJsonAtomic(brokerManifestPath(env), { ...manifest, stateIds: manifest.stateIds.slice(0, 256) });
4407
4566
  }
4408
4567
  function brokerDrainMarkerPath(env = process.env) {
4409
- return path.join(brokerStateDir(env), "draining.json");
4568
+ return path2.join(brokerStateDir(env), "draining.json");
4410
4569
  }
4411
4570
  function loadDrainMarker(env = process.env) {
4412
4571
  const marker = readJsonFile(brokerDrainMarkerPath(env));
@@ -4445,7 +4604,7 @@ function cleanupLegacyBrokerCache(env = process.env) {
4445
4604
  try {
4446
4605
  for (const name of readdirSync(statesDirPath).slice(0, 512)) {
4447
4606
  if (!/^[A-Za-z0-9-]+\.json$/.test(name)) continue;
4448
- const target = path.join(statesDirPath, name);
4607
+ const target = path2.join(statesDirPath, name);
4449
4608
  try {
4450
4609
  const stats = lstatSync(target);
4451
4610
  if (!stats.isFile() || stats.isSymbolicLink()) continue;
@@ -4460,7 +4619,7 @@ function cleanupLegacyBrokerCache(env = process.env) {
4460
4619
  try {
4461
4620
  for (const name of readdirSync(oldOutputs).slice(0, 512)) {
4462
4621
  if (!/^o\d+\.(txt|meta\.json)$/.test(name)) continue;
4463
- const target = path.join(oldOutputs, name);
4622
+ const target = path2.join(oldOutputs, name);
4464
4623
  try {
4465
4624
  const stats = lstatSync(target);
4466
4625
  if (!stats.isFile() || stats.isSymbolicLink()) continue;
@@ -4471,17 +4630,54 @@ function cleanupLegacyBrokerCache(env = process.env) {
4471
4630
  }
4472
4631
  } catch {
4473
4632
  }
4633
+ outputs2 += cleanupOrphanOwnerOutputs(path2.join(oldOutputs, "owners"));
4474
4634
  return { runtimeFile, states, outputs: outputs2 };
4475
4635
  }
4636
+ function cleanupOrphanOwnerOutputs(root) {
4637
+ try {
4638
+ const stat = lstatSync(root);
4639
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("Unsafe computer-use outputs directory");
4640
+ } catch (error) {
4641
+ if (error.code === "ENOENT") return 0;
4642
+ throw error;
4643
+ }
4644
+ let remaining = 65536;
4645
+ let removed = 0;
4646
+ const visit = (directory, depth) => {
4647
+ const handle = opendirSync(directory);
4648
+ try {
4649
+ for (let entry = handle.readSync(); entry; entry = handle.readSync()) {
4650
+ if (--remaining < 0) throw new Error("Computer-use stale output cleanup budget exceeded; refusing unaccounted output storage");
4651
+ const target = path2.join(directory, entry.name);
4652
+ const stat = lstatSync(target);
4653
+ if (stat.isSymbolicLink()) {
4654
+ unlinkSync(target);
4655
+ continue;
4656
+ }
4657
+ if (stat.isDirectory() && depth === 0) {
4658
+ visit(target, 1);
4659
+ rmdirSync(target);
4660
+ } else if (stat.isFile() && depth === 1 && /^\d+\.txt$/.test(entry.name)) {
4661
+ unlinkSync(target);
4662
+ removed++;
4663
+ } else throw new Error(`Unexpected computer-use output entry: ${target}`);
4664
+ }
4665
+ } finally {
4666
+ handle.closeSync();
4667
+ }
4668
+ };
4669
+ visit(root, 0);
4670
+ return removed;
4671
+ }
4476
4672
  function writeJsonAtomic(filePath, value) {
4477
- mkdirSync2(path.dirname(filePath), { recursive: true });
4673
+ mkdirSync2(path2.dirname(filePath), { recursive: true });
4478
4674
  const temp = `${filePath}.${process.pid}.tmp`;
4479
4675
  writeFileSync(temp, JSON.stringify(value), "utf8");
4480
4676
  renameSync2(temp, filePath);
4481
4677
  }
4482
4678
  function readJsonFile(filePath) {
4483
4679
  try {
4484
- return JSON.parse(readFileSync2(filePath, "utf8"));
4680
+ return JSON.parse(readFileSync3(filePath, "utf8"));
4485
4681
  } catch {
4486
4682
  return void 0;
4487
4683
  }
@@ -4498,8 +4694,8 @@ function normalizeComputerUseOwner(value) {
4498
4694
  }
4499
4695
 
4500
4696
  // vendor/computer-use-axi/src/broker-protocol.ts
4501
- var BROKER_PROTOCOL_VERSION = 1;
4502
- var BROKER_ENGINE_VERSION = 2;
4697
+ var BROKER_PROTOCOL_VERSION = 3;
4698
+ var BROKER_ENGINE_VERSION = 4;
4503
4699
  var BROKER_PACKAGE_VERSION = "0.5.1-pie.1";
4504
4700
  var BROKER_RESULT_CACHE_MAX_ENTRIES = 256;
4505
4701
  var BROKER_REPLAY_LEDGER_MAX_IDS = 65536;
@@ -4825,7 +5021,19 @@ function validateRequest(value) {
4825
5021
  }
4826
5022
  const params = validateCommandParams(command, value.params);
4827
5023
  const cwd = value.cwd === void 0 ? process.cwd() : boundedString(value.cwd, "cwd", 4096);
4828
- if (!path2.isAbsolute(cwd)) throw new BrokerProtocolError("invalid_request", "cwd must be absolute.");
5024
+ if (!path3.isAbsolute(cwd)) throw new BrokerProtocolError("invalid_request", "cwd must be absolute.");
5025
+ const rawEnvironment = value.environment ?? {};
5026
+ assertPlainRecord(rawEnvironment, "environment");
5027
+ assertKeys(rawEnvironment, "environment", REQUEST_ENV_KEYS);
5028
+ for (const entry of Object.values(rawEnvironment)) {
5029
+ if (typeof entry !== "string") throw new BrokerProtocolError("invalid_request", "environment values must be strings.");
5030
+ }
5031
+ let environment;
5032
+ try {
5033
+ environment = captureComputerUseEnvironment(rawEnvironment);
5034
+ } catch (error) {
5035
+ throw new BrokerProtocolError("invalid_request", String(error));
5036
+ }
4829
5037
  const budgetMs = value.budgetMs === void 0 ? BROKER_DEFAULT_REQUEST_BUDGET_MS : Math.trunc(boundedNumber(value.budgetMs, "budgetMs", BROKER_MIN_REQUEST_BUDGET_MS, BROKER_MAX_REQUEST_BUDGET_MS));
4830
5038
  return {
4831
5039
  requestId: value.requestId,
@@ -4835,6 +5043,7 @@ function validateRequest(value) {
4835
5043
  command,
4836
5044
  params,
4837
5045
  cwd,
5046
+ environment,
4838
5047
  budgetMs
4839
5048
  };
4840
5049
  }
@@ -4844,8 +5053,10 @@ function validateHello(value) {
4844
5053
  if (value.protocolVersion !== BROKER_PROTOCOL_VERSION) {
4845
5054
  throw new BrokerProtocolError("protocol_mismatch", `Protocol mismatch: broker ${BROKER_PROTOCOL_VERSION}, client ${String(value.protocolVersion)}.`);
4846
5055
  }
5056
+ if (value.buildIdentity !== BROKER_BUILD.identity) throw new BrokerProtocolError("build_mismatch", "Broker engine build identity differs.");
4847
5057
  return {
4848
5058
  type: "hello",
5059
+ buildIdentity: value.buildIdentity,
4849
5060
  protocolVersion: value.protocolVersion,
4850
5061
  clientVersion: value.clientVersion === void 0 ? void 0 : boundedString(value.clientVersion, "clientVersion", 128)
4851
5062
  };
@@ -4874,6 +5085,7 @@ var FrameDecoder = class {
4874
5085
  for (; ; ) {
4875
5086
  const newline = this.buffer.indexOf(10);
4876
5087
  if (newline < 0) break;
5088
+ if (newline > this.maxBytes) throw new BrokerProtocolError("frame_too_large", `Frame exceeds the ${this.maxBytes}-byte limit.`);
4877
5089
  const line = this.buffer.subarray(0, newline).toString("utf8").trim();
4878
5090
  this.buffer = this.buffer.subarray(newline + 1);
4879
5091
  if (!line) continue;
@@ -4898,11 +5110,11 @@ function resolveBrokerEndpoint(env = process.env) {
4898
5110
  const key = createHash("sha256").update(seed).digest("hex").slice(0, 16);
4899
5111
  return { kind: "named-pipe", path: `\\\\.\\pipe\\pie-computer-use-axi-${key}` };
4900
5112
  }
4901
- const socketPath = socketOverride || path2.join(stateRootDir(env), "run", "broker.sock");
5113
+ const socketPath = socketOverride || path3.join(stateRootDir(env), "run", "broker.sock");
4902
5114
  if (Buffer.byteLength(socketPath, "utf8") > 100) {
4903
5115
  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.`);
4904
5116
  }
4905
- return { kind: "unix-socket", path: socketPath, directory: path2.dirname(socketPath) };
5117
+ return { kind: "unix-socket", path: socketPath, directory: path3.dirname(socketPath) };
4906
5118
  }
4907
5119
  function ensurePrivateDirectory(directory) {
4908
5120
  mkdirSync3(directory, { recursive: true, mode: 448 });
@@ -4921,8 +5133,8 @@ function canonicalize(value) {
4921
5133
  }
4922
5134
  return value;
4923
5135
  }
4924
- function requestFingerprint(command, params, cwd) {
4925
- const seed = JSON.stringify({ command, params: canonicalize(params), cwd });
5136
+ function requestFingerprint(command, params, cwd, environment = {}) {
5137
+ const seed = JSON.stringify({ command, params: canonicalize(params), cwd, environment: canonicalize(environment) });
4926
5138
  return createHash("sha256").update(seed).digest("hex").slice(0, 32);
4927
5139
  }
4928
5140
 
@@ -4953,8 +5165,9 @@ var ArtifactStore = class {
4953
5165
  totalBytes = 0;
4954
5166
  /** Absolute path for one owner/generation, created 0700 and symlink-checked. */
4955
5167
  directoryFor(owner, generation = this.options.generation) {
4956
- const root = path3.join(this.options.root, safeComponent(generation, "generation"));
4957
- const ownerDir = path3.join(root, safeComponent(normalizeComputerUseOwner(owner), "owner"));
5168
+ const root = path4.join(this.options.root, safeComponent(generation, "generation"));
5169
+ const ownerKey = `owner-${createHash2("sha256").update(normalizeComputerUseOwner(owner)).digest("hex")}`;
5170
+ const ownerDir = path4.join(root, ownerKey);
4958
5171
  ensurePrivateDirectory(this.options.root);
4959
5172
  ensurePrivateDirectory(root);
4960
5173
  ensurePrivateDirectory(ownerDir);
@@ -4964,7 +5177,7 @@ var ArtifactStore = class {
4964
5177
  const generation = input.generation ?? this.options.generation;
4965
5178
  const directory = this.directoryFor(input.owner, generation);
4966
5179
  const artifactId = randomUUID2();
4967
- const absolutePath = path3.join(directory, `${artifactId}.${extensionFor(input.mimeType)}`);
5180
+ const absolutePath = path4.join(directory, `${artifactId}.${extensionFor(input.mimeType)}`);
4968
5181
  const fd = openSync(absolutePath, "wx", 384);
4969
5182
  try {
4970
5183
  let offset = 0;
@@ -4993,6 +5206,16 @@ var ArtifactStore = class {
4993
5206
  this.sweep();
4994
5207
  return record;
4995
5208
  }
5209
+ /** Hold existing evidence while a hydrated observation is used. */
5210
+ pinForState(stateId2) {
5211
+ const ids = [];
5212
+ for (const record of this.records.values()) {
5213
+ if (record.stateId !== stateId2) continue;
5214
+ this.pin(record.artifactId);
5215
+ ids.push(record.artifactId);
5216
+ }
5217
+ return ids;
5218
+ }
4996
5219
  pin(artifactId) {
4997
5220
  this.pins.set(artifactId, (this.pins.get(artifactId) ?? 0) + 1);
4998
5221
  }
@@ -5044,13 +5267,13 @@ var ArtifactStore = class {
5044
5267
  /** Remove files for a generation that no longer owns the broker. */
5045
5268
  cleanupGeneration(generation) {
5046
5269
  if (!SAFE_COMPONENT.test(generation)) return 0;
5047
- const directory = path3.join(this.options.root, generation);
5048
- if (!existsSync2(directory)) return 0;
5270
+ const directory = path4.join(this.options.root, generation);
5271
+ if (!existsSync3(directory)) return 0;
5049
5272
  const stats = lstatSync3(directory);
5050
5273
  if (stats.isSymbolicLink() || !stats.isDirectory()) return 0;
5051
5274
  let removed = 0;
5052
5275
  for (const name of readdirSync2(directory)) {
5053
- const ownerDir = path3.join(directory, name);
5276
+ const ownerDir = path4.join(directory, name);
5054
5277
  let ownerStats;
5055
5278
  try {
5056
5279
  ownerStats = lstatSync3(ownerDir);
@@ -5059,7 +5282,7 @@ var ArtifactStore = class {
5059
5282
  }
5060
5283
  if (ownerStats.isSymbolicLink() || !ownerStats.isDirectory()) continue;
5061
5284
  for (const file of readdirSync2(ownerDir)) {
5062
- const target = path3.join(ownerDir, file);
5285
+ const target = path4.join(ownerDir, file);
5063
5286
  let fileStats;
5064
5287
  try {
5065
5288
  fileStats = lstatSync3(target);
@@ -5071,12 +5294,12 @@ var ArtifactStore = class {
5071
5294
  removed += 1;
5072
5295
  }
5073
5296
  try {
5074
- rmdirSync(ownerDir);
5297
+ rmdirSync2(ownerDir);
5075
5298
  } catch {
5076
5299
  }
5077
5300
  }
5078
5301
  try {
5079
- rmdirSync(directory);
5302
+ rmdirSync2(directory);
5080
5303
  } catch {
5081
5304
  }
5082
5305
  return removed;
@@ -5100,7 +5323,7 @@ var ArtifactStore = class {
5100
5323
  for (const name of names) {
5101
5324
  if (scanned >= maxGenerations) break;
5102
5325
  if (name === current || !SAFE_COMPONENT.test(name)) continue;
5103
- const directory = path3.join(this.options.root, name);
5326
+ const directory = path4.join(this.options.root, name);
5104
5327
  let stats;
5105
5328
  try {
5106
5329
  stats = lstatSync3(directory);
@@ -5132,11 +5355,12 @@ var ArtifactStore = class {
5132
5355
  };
5133
5356
  function artifactsRoot(env = process.env) {
5134
5357
  const base = env.PIE_COMPUTER_USE_ARTIFACTS_DIR?.trim();
5135
- if (base) return path3.resolve(base);
5136
- return path3.join(stateRootDir(env), "artifacts");
5358
+ if (base) return path4.resolve(base);
5359
+ return path4.join(stateRootDir(env), "artifacts");
5137
5360
  }
5138
5361
 
5139
5362
  // vendor/computer-use-axi/src/bridge.ts
5363
+ init_test_backend_guard();
5140
5364
  import { spawn as spawn4 } from "node:child_process";
5141
5365
  import { randomUUID as randomUUID7 } from "node:crypto";
5142
5366
  import { constants as fsConstants5, mkdtempSync } from "node:fs";
@@ -5160,7 +5384,7 @@ function keys(value) {
5160
5384
  if (!Array.isArray(value) || value.length === 0) throw new Error("keypress.keys must contain at least one key.");
5161
5385
  return value.map((key) => String(key));
5162
5386
  }
5163
- function path4(value, env) {
5387
+ function path5(value, env) {
5164
5388
  if (!Array.isArray(value) || value.length < 2) throw new Error("drag.path must contain at least two points.");
5165
5389
  return value.map((point, index) => {
5166
5390
  const x = Array.isArray(point) ? toFiniteNumber(point[0], NaN) : toFiniteNumber(point?.x, NaN);
@@ -5192,7 +5416,7 @@ function nativeTarget(action, operation, env) {
5192
5416
  env.validatePoint(x, y);
5193
5417
  return { x, y };
5194
5418
  }
5195
- if (operation === "drag" && action.path?.length) return path4(action.path, env)[0];
5419
+ if (operation === "drag" && action.path?.length) return path5(action.path, env)[0];
5196
5420
  throw new Error(`${operation} requires either ref or both x and y.`);
5197
5421
  }
5198
5422
  function focusedTarget(env) {
@@ -5262,7 +5486,7 @@ function prepareAction(action, state, env) {
5262
5486
  case "scroll":
5263
5487
  return { action: operation, target, params: { scrollX: scrollDelta(action.scrollX), scrollY: scrollDelta(action.scrollY) }, usesCurrentFocus: false, needsForeground: false };
5264
5488
  case "drag":
5265
- return { action: operation, target, params: { path: path4(action.path, env) }, usesCurrentFocus: false, needsForeground: false };
5489
+ return { action: operation, target, params: { path: path5(action.path, env) }, usesCurrentFocus: false, needsForeground: false };
5266
5490
  case "moveMouse":
5267
5491
  return { action: operation, target, params: {}, usesCurrentFocus: false, needsForeground: false };
5268
5492
  }
@@ -5288,6 +5512,7 @@ function outcomeAfterObservedValues(current, actions, valueForRef) {
5288
5512
  }
5289
5513
 
5290
5514
  // vendor/computer-use-axi/src/cdp.ts
5515
+ init_test_backend_guard();
5291
5516
  import { randomUUID as randomUUID3 } from "node:crypto";
5292
5517
 
5293
5518
  // ../../node_modules/ws/wrapper.mjs
@@ -5791,6 +6016,7 @@ var CdpTab = class _CdpTab {
5791
6016
  loadFired;
5792
6017
  static async connect(wsUrl, targetId, title, epoch = connectionEpoch) {
5793
6018
  assertConnectionEpoch(epoch);
6019
+ assertNativeBackendAllowed();
5794
6020
  const ws = new wrapper_default(wsUrl);
5795
6021
  connectingSockets.add(ws);
5796
6022
  try {
@@ -5950,6 +6176,7 @@ var CdpTab = class _CdpTab {
5950
6176
  return entries;
5951
6177
  }
5952
6178
  send(method, params = {}) {
6179
+ assertNativeBackendAllowed();
5953
6180
  const id = this.nextId++;
5954
6181
  return new Promise((resolve2, reject) => {
5955
6182
  const timer = setTimeout(() => {
@@ -6027,7 +6254,7 @@ var CdpTab = class _CdpTab {
6027
6254
  };
6028
6255
  var connectedTabs = /* @__PURE__ */ new Map();
6029
6256
  var connectingTabs = /* @__PURE__ */ new Map();
6030
- var lastConnectFailureAt = 0;
6257
+ var lastConnectFailureAt = /* @__PURE__ */ new Map();
6031
6258
  function disconnectCdp() {
6032
6259
  if (disconnecting) return disconnecting;
6033
6260
  connectionEpoch++;
@@ -6036,62 +6263,64 @@ function disconnectCdp() {
6036
6263
  connectingSockets.clear();
6037
6264
  connectedTabs.clear();
6038
6265
  connectingTabs.clear();
6039
- lastConnectFailureAt = 0;
6266
+ lastConnectFailureAt.clear();
6040
6267
  disconnecting = Promise.all(tabs.map((tab) => tab.close())).then(() => void 0).finally(() => {
6041
6268
  disconnecting = void 0;
6042
6269
  });
6043
6270
  return disconnecting;
6044
6271
  }
6045
- function cdpEnabled() {
6046
- const rawPort = process.env.PIE_COMPUTER_USE_CDP_PORT ?? "";
6272
+ function cdpEnabled(rawPort = getComputerUseEnvironmentValue("PIE_COMPUTER_USE_CDP_PORT") ?? "") {
6047
6273
  if (!/^\d+$/.test(rawPort)) return false;
6048
6274
  const port = Number(rawPort);
6049
6275
  return Number.isInteger(port) && port > 0 && port <= 65535 && typeof wrapper_default !== "undefined";
6050
6276
  }
6051
6277
  async function cdpTabForWindow(windowTitle, frame) {
6052
6278
  const epoch = connectionEpoch;
6053
- if (!cdpEnabled()) return void 0;
6054
- if (Date.now() - lastConnectFailureAt < CONNECT_FAILURE_RETRY_MS) return void 0;
6279
+ const port = getComputerUseEnvironmentValue("PIE_COMPUTER_USE_CDP_PORT") ?? "";
6280
+ if (!cdpEnabled(port)) return void 0;
6281
+ if (Date.now() - (lastConnectFailureAt.get(port) ?? 0) < CONNECT_FAILURE_RETRY_MS) return void 0;
6055
6282
  try {
6056
6283
  assertConnectionEpoch(epoch);
6057
- for (const tab of connectedTabs.values()) {
6284
+ for (const [key2, tab] of connectedTabs) {
6285
+ if (!key2.startsWith(`${port}:`)) continue;
6058
6286
  if (tab.isOpen && titlesMatch(tab.title, windowTitle) && await tabMatchesFrame(tab, frame)) {
6059
6287
  assertConnectionEpoch(epoch);
6060
6288
  if (tab.isOpen) return tab;
6061
6289
  }
6062
6290
  }
6063
- const pages = await cdpPages(epoch);
6291
+ const pages = await cdpPages(epoch, port);
6064
6292
  const match = await pickTab(pages, windowTitle, frame, epoch);
6065
6293
  assertConnectionEpoch(epoch);
6066
6294
  if (!match) return void 0;
6067
- const existing = connectedTabs.get(match.id);
6295
+ const key = `${port}:${match.id}`;
6296
+ const existing = connectedTabs.get(key);
6068
6297
  if (existing?.isOpen) {
6069
6298
  existing.title = match.title;
6070
6299
  return existing;
6071
6300
  }
6072
- let connecting = connectingTabs.get(match.id);
6301
+ let connecting = connectingTabs.get(key);
6073
6302
  if (!connecting) {
6074
6303
  connecting = CdpTab.connect(match.webSocketDebuggerUrl, match.id, match.title, epoch);
6075
- connectingTabs.set(match.id, connecting);
6304
+ connectingTabs.set(key, connecting);
6076
6305
  }
6077
6306
  let connected;
6078
6307
  try {
6079
6308
  connected = await connecting;
6080
6309
  } finally {
6081
- if (connectingTabs.get(match.id) === connecting) connectingTabs.delete(match.id);
6310
+ if (connectingTabs.get(key) === connecting) connectingTabs.delete(key);
6082
6311
  }
6083
6312
  assertConnectionEpoch(epoch);
6084
- connectedTabs.set(match.id, connected);
6313
+ connectedTabs.set(key, connected);
6085
6314
  return connected;
6086
6315
  } catch {
6087
- if (epoch === connectionEpoch && !disconnecting) lastConnectFailureAt = Date.now();
6316
+ if (epoch === connectionEpoch && !disconnecting) lastConnectFailureAt.set(port, Date.now());
6088
6317
  return void 0;
6089
6318
  }
6090
6319
  }
6091
- async function listCdpPageContexts() {
6092
- const pages = await cdpPages();
6320
+ async function listCdpPageContexts(port = getComputerUseEnvironmentValue("PIE_COMPUTER_USE_CDP_PORT")) {
6321
+ const pages = await cdpPages(connectionEpoch, port);
6093
6322
  return pages.map((page) => ({
6094
- contextId: cdpContextId(page.id),
6323
+ contextId: cdpContextId(page.id, port),
6095
6324
  targetId: page.id,
6096
6325
  title: page.title,
6097
6326
  url: page.url ?? ""
@@ -6208,14 +6437,18 @@ async function withCdpContextTab(contextId, run) {
6208
6437
  }
6209
6438
  async function cdpPageForContext(contextId, epoch) {
6210
6439
  if (!contextId.startsWith(CDP_CONTEXT_PREFIX)) return void 0;
6211
- const targetId = contextId.slice(CDP_CONTEXT_PREFIX.length);
6212
- const pages = await cdpPages(epoch);
6440
+ const identity = contextId.slice(CDP_CONTEXT_PREFIX.length);
6441
+ const separator = identity.indexOf(":");
6442
+ if (separator < 1) return void 0;
6443
+ const port = identity.slice(0, separator);
6444
+ const targetId = identity.slice(separator + 1);
6445
+ const pages = await cdpPages(epoch, port);
6213
6446
  return pages.find((candidate) => candidate.id === targetId);
6214
6447
  }
6215
- async function cdpPages(epoch = connectionEpoch) {
6448
+ async function cdpPages(epoch = connectionEpoch, port = getComputerUseEnvironmentValue("PIE_COMPUTER_USE_CDP_PORT")) {
6216
6449
  assertConnectionEpoch(epoch);
6217
- if (!cdpEnabled()) return [];
6218
- const port = process.env.PIE_COMPUTER_USE_CDP_PORT;
6450
+ if (!port || !cdpEnabled(port)) return [];
6451
+ assertNativeBackendAllowed();
6219
6452
  const response = await fetch(`http://127.0.0.1:${port}/json/list`, { signal: AbortSignal.timeout(2e3) });
6220
6453
  const targets = await response.json();
6221
6454
  assertConnectionEpoch(epoch);
@@ -6223,8 +6456,8 @@ async function cdpPages(epoch = connectionEpoch) {
6223
6456
  (target) => target.type === "page" && target.webSocketDebuggerUrl && isLocalDebuggerWebSocket(target.webSocketDebuggerUrl, port)
6224
6457
  );
6225
6458
  }
6226
- function cdpContextId(targetId) {
6227
- return `${CDP_CONTEXT_PREFIX}${targetId}`;
6459
+ function cdpContextId(targetId, port) {
6460
+ return `${CDP_CONTEXT_PREFIX}${port}:${targetId}`;
6228
6461
  }
6229
6462
  function axString(raw) {
6230
6463
  const value = raw?.value ?? raw;
@@ -6371,98 +6604,6 @@ function titlesMatch(tabTitle, windowTitle) {
6371
6604
  return tab === win || win.startsWith(tab) || tab.startsWith(win);
6372
6605
  }
6373
6606
 
6374
- // vendor/computer-use-axi/src/config.ts
6375
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
6376
- import { AsyncLocalStorage } from "node:async_hooks";
6377
- import path5 from "node:path";
6378
-
6379
- // vendor/computer-use-axi/host.ts
6380
- function getAgentDir() {
6381
- return getConfigDir();
6382
- }
6383
-
6384
- // vendor/computer-use-axi/src/config.ts
6385
- var DEFAULT_CONFIG = {
6386
- browser_use: true,
6387
- headless: false,
6388
- cursor_overlay: true,
6389
- managed_browser: "chrome"
6390
- };
6391
- var operationConfig = new AsyncLocalStorage();
6392
- var defaultLoaded = Object.freeze({ config: Object.freeze({ ...DEFAULT_CONFIG }), sources: [], env: {} });
6393
- function withComputerUseConfig(cwd, run) {
6394
- return operationConfig.run(loadComputerUseConfig(cwd), run);
6395
- }
6396
- function parseBoolean(value) {
6397
- if (typeof value === "boolean") return value;
6398
- if (typeof value === "number") return value === 1 ? true : value === 0 ? false : void 0;
6399
- if (typeof value !== "string") return void 0;
6400
- const normalized = value.trim().toLowerCase();
6401
- if (["1", "true", "yes", "on", "enabled"].includes(normalized)) return true;
6402
- if (["0", "false", "no", "off", "disabled"].includes(normalized)) return false;
6403
- return void 0;
6404
- }
6405
- function normalizePartial(raw) {
6406
- if (!raw || typeof raw !== "object") return {};
6407
- const source = raw.computer_use && typeof raw.computer_use === "object" ? raw.computer_use : raw;
6408
- const out = {};
6409
- const browserUse = parseBoolean(source.browser_use);
6410
- const headless = parseBoolean(source.headless);
6411
- const cursorOverlay = parseBoolean(source.cursor_overlay);
6412
- if (browserUse !== void 0) out.browser_use = browserUse;
6413
- if (headless !== void 0) out.headless = headless;
6414
- if (cursorOverlay !== void 0) out.cursor_overlay = cursorOverlay;
6415
- const managedBrowser = source.managed_browser;
6416
- if (managedBrowser === "helium" || managedBrowser === "chrome") out.managed_browser = managedBrowser;
6417
- return out;
6418
- }
6419
- function readConfigFile(filePath) {
6420
- if (!existsSync3(filePath)) return { path: filePath, exists: false };
6421
- try {
6422
- const parsed = JSON.parse(readFileSync3(filePath, "utf-8"));
6423
- return { path: filePath, exists: true, values: normalizePartial(parsed) };
6424
- } catch (error) {
6425
- return { path: filePath, exists: true, error: error instanceof Error ? error.message : String(error) };
6426
- }
6427
- }
6428
- function readEnv() {
6429
- const out = {};
6430
- const browserUse = parseBoolean(process.env.PIE_COMPUTER_USE_BROWSER_USE);
6431
- const headless = parseBoolean(process.env.PIE_COMPUTER_USE_HEADLESS);
6432
- const cursorOverlay = parseBoolean(process.env.PIE_COMPUTER_USE_CURSOR_OVERLAY);
6433
- if (browserUse !== void 0) out.browser_use = browserUse;
6434
- if (headless !== void 0) out.headless = headless;
6435
- if (cursorOverlay !== void 0) out.cursor_overlay = cursorOverlay;
6436
- const managedBrowser = process.env.PIE_COMPUTER_USE_MANAGED_BROWSER;
6437
- if (managedBrowser === "helium" || managedBrowser === "chrome") out.managed_browser = managedBrowser;
6438
- return out;
6439
- }
6440
- function loadComputerUseConfig(cwd) {
6441
- const sources = [
6442
- readConfigFile(path5.join(getAgentDir(), "extensions", "computer-use.json")),
6443
- readConfigFile(path5.join(cwd, ".pie", "computer-use.json"))
6444
- ];
6445
- const env = readEnv();
6446
- const config = { ...DEFAULT_CONFIG };
6447
- for (const source of sources) {
6448
- if (source.values) Object.assign(config, source.values);
6449
- }
6450
- Object.assign(config, env);
6451
- return Object.freeze({ config: Object.freeze(config), sources, env });
6452
- }
6453
- function getComputerUseConfig() {
6454
- return getLoadedComputerUseConfig().config;
6455
- }
6456
- function getLoadedComputerUseConfig() {
6457
- return operationConfig.getStore() ?? defaultLoaded;
6458
- }
6459
- function isHeadlessMode() {
6460
- return getComputerUseConfig().headless;
6461
- }
6462
- function isBrowserUseEnabled() {
6463
- return getComputerUseConfig().browser_use;
6464
- }
6465
-
6466
6607
  // vendor/computer-use-axi/src/note.ts
6467
6608
  function normalizedLabel(value) {
6468
6609
  return value.toLowerCase().replace(/\s+/g, " ").trim();
@@ -6616,8 +6757,9 @@ function renderNote(note) {
6616
6757
  }
6617
6758
 
6618
6759
  // vendor/computer-use-axi/src/output.ts
6619
- import { closeSync as closeSync2, mkdirSync as mkdirSync5, openSync as openSync2, readSync, readdirSync as readdirSync3, statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
6760
+ import { closeSync as closeSync2, openSync as openSync2, readSync, readdirSync as readdirSync3, statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
6620
6761
  import path6 from "node:path";
6762
+ import { createHash as createHash3 } from "node:crypto";
6621
6763
  var MODEL_TEXT_MAX_BYTES = 48 * 1024;
6622
6764
  var MODEL_TEXT_MAX_LINES = 2e3;
6623
6765
  var OUTPUT_PAGE_BYTES = 16 * 1024;
@@ -6629,8 +6771,13 @@ var outputs = /* @__PURE__ */ new Map();
6629
6771
  var nextOutputId = 1;
6630
6772
  var outputBytes = 0;
6631
6773
  function outputDirectoryFor(owner) {
6632
- const dir = path6.join(outputsDir(), "owners", normalizeComputerUseOwner(owner));
6633
- mkdirSync5(dir, { recursive: true, mode: 448 });
6774
+ const root = outputsDir();
6775
+ const owners = path6.join(root, "owners");
6776
+ const ownerKey = `owner-${createHash3("sha256").update(normalizeComputerUseOwner(owner)).digest("hex")}`;
6777
+ const dir = path6.join(owners, ownerKey);
6778
+ ensurePrivateDirectory(root);
6779
+ ensurePrivateDirectory(owners);
6780
+ ensurePrivateDirectory(dir);
6634
6781
  return dir;
6635
6782
  }
6636
6783
  function utf8Prefix(bytes, maxBytes) {
@@ -6762,6 +6909,9 @@ function clearStoredOutputs(owner) {
6762
6909
  // vendor/computer-use-axi/src/bridge.ts
6763
6910
  init_coerce();
6764
6911
 
6912
+ // vendor/computer-use-axi/src/platform/index.ts
6913
+ init_test_backend_guard();
6914
+
6765
6915
  // vendor/computer-use-axi/src/platform/macos/backend.ts
6766
6916
  init_coerce();
6767
6917
  init_helper();
@@ -6982,6 +7132,7 @@ init_architecture();
6982
7132
  init_coerce();
6983
7133
 
6984
7134
  // vendor/computer-use-axi/src/platform/linux/helper.ts
7135
+ init_test_backend_guard();
6985
7136
  init_package_root();
6986
7137
  import { spawn as spawn2 } from "node:child_process";
6987
7138
  import { randomUUID as randomUUID4 } from "node:crypto";
@@ -7005,6 +7156,7 @@ async function isExecutable2(filePath) {
7005
7156
  async function runProcess2(command, args, timeoutMs, signal, env) {
7006
7157
  if (signal?.aborted) throw new Error("Operation aborted.");
7007
7158
  await new Promise((resolve2, reject) => {
7159
+ assertNativeBackendAllowed();
7008
7160
  const child = spawn2(command, args, { stdio: ["ignore", "pipe", "pipe"], env });
7009
7161
  let stdout = "";
7010
7162
  let stderr = "";
@@ -7092,6 +7244,7 @@ var LinuxHelperClient = class {
7092
7244
  this.buffer = "";
7093
7245
  }
7094
7246
  async ensureInstalled(signal) {
7247
+ assertNativeBackendAllowed();
7095
7248
  if (await isExecutable2(this.helperPath) && this.installChecked) return;
7096
7249
  if (!this.installPromise) {
7097
7250
  const installPromise = (async () => {
@@ -7135,6 +7288,7 @@ var LinuxHelperClient = class {
7135
7288
  return await waitForShared(this.processPromise, signal);
7136
7289
  }
7137
7290
  async startProcess() {
7291
+ assertNativeBackendAllowed();
7138
7292
  const child = spawn2(this.helperPath, [], { stdio: ["pipe", "pipe", "pipe"] });
7139
7293
  child.stdout.setEncoding("utf8");
7140
7294
  child.stderr.setEncoding("utf8");
@@ -7187,6 +7341,7 @@ var LinuxHelperClient = class {
7187
7341
  }
7188
7342
  }
7189
7343
  async command(cmd, args = {}, options) {
7344
+ assertNativeBackendAllowed();
7190
7345
  const child = await this.process(options?.signal);
7191
7346
  const id = randomUUID4();
7192
7347
  const timeoutMs = options?.timeoutMs ?? COMMAND_TIMEOUT_MS3;
@@ -7386,6 +7541,7 @@ var linuxBackend = {
7386
7541
  init_coerce();
7387
7542
 
7388
7543
  // vendor/computer-use-axi/src/platform/windows/helper.ts
7544
+ init_test_backend_guard();
7389
7545
  init_package_root();
7390
7546
  import { spawn as spawn3 } from "node:child_process";
7391
7547
  import { randomUUID as randomUUID5 } from "node:crypto";
@@ -7409,6 +7565,7 @@ async function isExecutable3(filePath) {
7409
7565
  async function runProcess3(command, args, timeoutMs, signal, env) {
7410
7566
  if (signal?.aborted) throw new Error("Operation aborted.");
7411
7567
  await new Promise((resolve2, reject) => {
7568
+ assertNativeBackendAllowed();
7412
7569
  const child = spawn3(command, args, { stdio: ["ignore", "pipe", "pipe"], env });
7413
7570
  let stdout = "";
7414
7571
  let stderr = "";
@@ -7469,6 +7626,7 @@ var WindowsHelperClient = class {
7469
7626
  child.unref();
7470
7627
  }
7471
7628
  async ensureInstalled(signal) {
7629
+ assertNativeBackendAllowed();
7472
7630
  if (await isExecutable3(WINDOWS_HELPER_PATH) && this.installChecked) return;
7473
7631
  await runProcess3(process.execPath, [SETUP_HELPER_SCRIPT3, "--platform", "windows", "--runtime"], HELPER_SETUP_TIMEOUT_MS3, signal, { ...process.env, ELECTRON_RUN_AS_NODE: "1", BUN_BE_BUN: "1" });
7474
7632
  this.installChecked = true;
@@ -7477,6 +7635,7 @@ var WindowsHelperClient = class {
7477
7635
  async process(signal) {
7478
7636
  await this.ensureInstalled(signal);
7479
7637
  if (this.child && this.child.exitCode === null && !this.child.killed) return this.child;
7638
+ assertNativeBackendAllowed();
7480
7639
  const child = spawn3(WINDOWS_HELPER_PATH, [], { stdio: ["pipe", "pipe", "pipe"] });
7481
7640
  child.stdout.setEncoding("utf8");
7482
7641
  child.stderr.setEncoding("utf8");
@@ -7522,6 +7681,7 @@ var WindowsHelperClient = class {
7522
7681
  }
7523
7682
  }
7524
7683
  async command(cmd, args = {}, options) {
7684
+ assertNativeBackendAllowed();
7525
7685
  const child = await this.process(options?.signal);
7526
7686
  const id = randomUUID5();
7527
7687
  const timeoutMs = options?.timeoutMs ?? COMMAND_TIMEOUT_MS4;
@@ -7745,10 +7905,17 @@ var UnsupportedPlatformBackend = class {
7745
7905
  }
7746
7906
  };
7747
7907
  function platformBackendForRuntime(platform = process.platform) {
7748
- if (platform === "darwin") return macosPlatformBackend;
7749
- if (platform === "win32") return windowsBackend;
7750
- if (platform === "linux") return linuxBackend;
7751
- return new UnsupportedPlatformBackend(platform);
7908
+ const backend = platform === "darwin" ? macosPlatformBackend : platform === "win32" ? windowsBackend : platform === "linux" ? linuxBackend : new UnsupportedPlatformBackend(platform);
7909
+ return new Proxy(backend, {
7910
+ get(target, property, receiver) {
7911
+ const value = Reflect.get(target, property, receiver);
7912
+ if (typeof value !== "function") return value;
7913
+ return (...args) => {
7914
+ assertNativeBackendAllowed();
7915
+ return Reflect.apply(value, target, args);
7916
+ };
7917
+ }
7918
+ });
7752
7919
  }
7753
7920
  var currentPlatformBackend = platformBackendForRuntime();
7754
7921
  var backendOverrideInstalled = false;
@@ -8377,6 +8544,7 @@ function desktopResourceKey(target) {
8377
8544
  }
8378
8545
  function persistOperation(state) {
8379
8546
  if (!state.currentTarget || !state.currentCapture || !state.currentLook || !state.currentOutline) return;
8547
+ if (expiredStateReasons.has(state.currentCapture.stateId) || state.helperGeneration !== helperGeneration) return;
8380
8548
  const resourceKey = state.resourceKey ?? desktopResourceKey(state.currentTarget);
8381
8549
  const epoch = state.epoch ?? resourceScheduler.epoch(resourceKey);
8382
8550
  savedStates.saveDesktop(state, resourceKey, epoch);
@@ -8400,10 +8568,7 @@ async function releaseComputerUseSession() {
8400
8568
  });
8401
8569
  await attempt("drain scheduler", () => drain);
8402
8570
  await attempt("release owned browser", () => releaseOwnedBrowserState(runtimeState));
8403
- if (runtimeState.managedBrowserCdpPort && process.env.PIE_COMPUTER_USE_CDP_PORT === runtimeState.managedBrowserCdpPort) {
8404
- if (runtimeState.previousCdpPort === void 0) delete process.env.PIE_COMPUTER_USE_CDP_PORT;
8405
- else process.env.PIE_COMPUTER_USE_CDP_PORT = runtimeState.previousCdpPort;
8406
- }
8571
+ setManagedCdpPort(void 0);
8407
8572
  runtimeState.previousCdpPort = void 0;
8408
8573
  if (runtimeState.managedBrowser === void 0) {
8409
8574
  runtimeState.managedBrowserCdpPort = void 0;
@@ -8427,7 +8592,7 @@ function currentRuntimeMode() {
8427
8592
  }
8428
8593
  function currentDeliveryPolicy() {
8429
8594
  if (isHeadlessMode()) return "background";
8430
- const value = (process.env.PIE_COMPUTER_USE_DELIVERY_POLICY ?? process.env.PIE_COMPUTER_USE_EVENT_DELIVERY ?? "default").toLowerCase();
8595
+ const value = (getComputerUseEnvironmentValue("PIE_COMPUTER_USE_DELIVERY_POLICY") ?? getComputerUseEnvironmentValue("PIE_COMPUTER_USE_EVENT_DELIVERY") ?? "default").toLowerCase();
8431
8596
  return value === "background" || value === "pid" ? "background" : value === "foreground" || value === "hid" ? "foreground" : value === "ax_only" || value === "ax-only" ? "ax_only" : "default";
8432
8597
  }
8433
8598
  function nativeInputDelivery(policy = currentDeliveryPolicy()) {
@@ -9358,7 +9523,7 @@ async function refreshBrowserSnapshot(contextId, tool, base) {
9358
9523
  const browser = await cdpSnapshotForContext(contextId);
9359
9524
  if (!browser) throw new Error(`Browser root '${contextId}' is no longer available. Call find_roots and observe_ui again.`);
9360
9525
  const state = operationState();
9361
- const resourceKey = state.resourceKey ?? `cdp:${browser.targetId}`;
9526
+ const resourceKey = state.resourceKey ?? `cdp:${browser.contextId.slice(BROWSER_CONTEXT_PREFIX.length)}`;
9362
9527
  return browserObservationResult(browser, resourceKey, state.epoch ?? resourceScheduler.epoch(resourceKey), tool, base);
9363
9528
  }
9364
9529
  function sliceText(value, offsetValue, _limitValue) {
@@ -9997,7 +10162,7 @@ async function performAct(params, signal) {
9997
10162
  }
9998
10163
  function managedBrowserExecutableCandidates(browser) {
9999
10164
  const overrideName = browser === "helium" ? "PIE_COMPUTER_USE_HELIUM_EXECUTABLE" : "PIE_COMPUTER_USE_CHROME_EXECUTABLE";
10000
- const override = trimOrUndefined(process.env[overrideName]);
10165
+ const override = trimOrUndefined(getComputerUseEnvironmentValue(overrideName));
10001
10166
  if (override) return [path13.resolve(override)];
10002
10167
  const platformCandidates = process.platform === "darwin" ? browser === "helium" ? [
10003
10168
  "/Applications/Helium.app/Contents/MacOS/Helium",
@@ -10038,7 +10203,7 @@ async function managedBrowserExecutable(browser) {
10038
10203
  }
10039
10204
  }
10040
10205
  const overrideName = browser === "helium" ? "PIE_COMPUTER_USE_HELIUM_EXECUTABLE" : "PIE_COMPUTER_USE_CHROME_EXECUTABLE";
10041
- if (trimOrUndefined(process.env[overrideName])) {
10206
+ if (trimOrUndefined(getComputerUseEnvironmentValue(overrideName))) {
10042
10207
  throw new Error(`${browser} executable from ${overrideName} was not found or is not executable: ${candidates[0]}.`);
10043
10208
  }
10044
10209
  throw new Error(`${browser} executable was not found. Set ${overrideName} to its absolute path.`);
@@ -10068,6 +10233,7 @@ async function waitForCdpPort(port, signal) {
10068
10233
  throw new Error(`Managed browser did not expose CDP on port ${port} within ${MANAGED_BROWSER_READY_TIMEOUT_MS}ms.`);
10069
10234
  }
10070
10235
  async function performLaunchBrowser(params, signal) {
10236
+ assertNativeBackendAllowed();
10071
10237
  const browser = getComputerUseConfig().managed_browser;
10072
10238
  const executable = await managedBrowserExecutable(browser);
10073
10239
  const port = await freeTcpPort();
@@ -10084,9 +10250,6 @@ async function performLaunchBrowser(params, signal) {
10084
10250
  "--no-default-browser-check",
10085
10251
  url
10086
10252
  ];
10087
- if (runtimeState.previousCdpPort === void 0 && runtimeState.managedBrowserCdpPort === void 0) {
10088
- runtimeState.previousCdpPort = process.env.PIE_COMPUTER_USE_CDP_PORT;
10089
- }
10090
10253
  const managedBrowser = spawn4(executable, args, { stdio: "ignore", detached: true });
10091
10254
  managedBrowser.unref();
10092
10255
  const stalePid = runtimeState.managedBrowserPid;
@@ -10101,22 +10264,21 @@ async function performLaunchBrowser(params, signal) {
10101
10264
  runtimeState.managedBrowserPid = managedBrowser.pid;
10102
10265
  runtimeState.managedBrowserProfileDir = profileDir;
10103
10266
  persistRuntimeBridgeState();
10104
- process.env.PIE_COMPUTER_USE_CDP_PORT = String(port);
10267
+ setManagedCdpPort(String(port));
10105
10268
  try {
10106
10269
  await waitForCdpPort(port, signal);
10107
10270
  } catch (error) {
10108
10271
  if (runtimeState.managedBrowser === managedBrowser) {
10109
10272
  await releaseOwnedBrowserState(runtimeState);
10110
- if (runtimeState.previousCdpPort === void 0) delete process.env.PIE_COMPUTER_USE_CDP_PORT;
10111
- else process.env.PIE_COMPUTER_USE_CDP_PORT = runtimeState.previousCdpPort;
10273
+ setManagedCdpPort(void 0);
10112
10274
  runtimeState.managedBrowserCdpPort = void 0;
10113
10275
  runtimeState.previousCdpPort = void 0;
10114
10276
  }
10115
10277
  throw error;
10116
10278
  }
10117
- const page = (await listCdpPageContexts())[0];
10279
+ const page = (await listCdpPageContexts(String(port)))[0];
10118
10280
  if (!page) throw new Error("Managed browser launched without a CDP page context.");
10119
- const resourceKey = `cdp:${page.targetId}`;
10281
+ const resourceKey = `cdp:${page.contextId.slice(BROWSER_CONTEXT_PREFIX.length)}`;
10120
10282
  const scheduled = await resourceScheduler.read(resourceKey, async () => await cdpSnapshotForContext(page.contextId));
10121
10283
  if (!scheduled.value) throw new Error("Managed browser page could not be observed after launch.");
10122
10284
  return browserObservationResult(scheduled.value, resourceKey, scheduled.epoch, "launch_browser");
@@ -10177,6 +10339,9 @@ async function executeTool(tool, ctx, params, signal, run, runtime) {
10177
10339
  const outputRef = tool === "read_text" && trimOrUndefined(params?.ref)?.startsWith("@o") === true;
10178
10340
  const requestedStateId = outputRef ? void 0 : trimOrUndefined(params?.stateId);
10179
10341
  const stateRecord = requestedStateId ? savedStates.get(requestedStateId) : void 0;
10342
+ if (requestedStateId && expiredStateReasons.has(requestedStateId)) {
10343
+ throw new Error(`State '${requestedStateId}' expired because ${expiredStateReasons.get(requestedStateId)}. Observe the root again.`);
10344
+ }
10180
10345
  if (requestedStateId && !stateRecord) {
10181
10346
  const reason = expiredStateReasons.get(requestedStateId);
10182
10347
  if (reason) {
@@ -10196,6 +10361,7 @@ async function executeTool(tool, ctx, params, signal, run, runtime) {
10196
10361
  operation.onDispatch = runtime?.onDispatch;
10197
10362
  if (requestedStateId && stateRecord) assertStateAccess(requestedStateId, stateRecord, operation);
10198
10363
  return await withComputerUseConfig(ctx.cwd, () => savedStates.operations.run(operation, async () => {
10364
+ if (requestedStateId) operation.artifactIds = engineArtifacts?.pinForState(requestedStateId) ?? [];
10199
10365
  try {
10200
10366
  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 ?? "");
10201
10367
  await resourceScheduler.read("session-lifecycle", async () => {
@@ -10212,7 +10378,7 @@ async function executeTool(tool, ctx, params, signal, run, runtime) {
10212
10378
  } finally {
10213
10379
  for (const artifactId of operation.artifactIds ?? []) engineArtifacts?.unpin(artifactId);
10214
10380
  }
10215
- }));
10381
+ }), runtime?.environment);
10216
10382
  }
10217
10383
  var BROKER_PERFORMERS = {
10218
10384
  find_roots: performListWindows,
@@ -10317,7 +10483,7 @@ async function probeBroker(endpoint, timeoutMs = 800) {
10317
10483
  };
10318
10484
  socket.setTimeout(timeoutMs, () => finish({ error: "timeout" }));
10319
10485
  socket.on("connect", () => {
10320
- socket.write(encodeFrame({ type: "hello", protocolVersion: BROKER_PROTOCOL_VERSION, clientVersion: "probe" }));
10486
+ socket.write(encodeFrame({ type: "hello", protocolVersion: BROKER_PROTOCOL_VERSION, clientVersion: "probe", buildIdentity: BROKER_BUILD.identity }));
10321
10487
  });
10322
10488
  socket.on("data", (chunk) => {
10323
10489
  try {
@@ -10364,8 +10530,7 @@ async function startBroker(options = {}) {
10364
10530
  const helperGeneration2 = randomUUID8();
10365
10531
  let liveHelperGeneration = helperGeneration2;
10366
10532
  const startedAt = Date.now();
10367
- const legacyCache = cleanupLegacyBrokerCache();
10368
- const prior = loadBrokerManifest();
10533
+ let legacyCache;
10369
10534
  const artifacts = new ArtifactStore({
10370
10535
  root: artifactsRoot(),
10371
10536
  generation,
@@ -10374,18 +10539,6 @@ async function startBroker(options = {}) {
10374
10539
  expireStateForArtifactEviction(stateId2);
10375
10540
  }
10376
10541
  });
10377
- try {
10378
- artifacts.cleanupOtherGenerations(generation);
10379
- } catch {
10380
- }
10381
- configureEngineRuntime({
10382
- generation,
10383
- helperGeneration: helperGeneration2,
10384
- artifacts,
10385
- expiredStateIds: prior?.stateIds ?? [],
10386
- previousGeneration: prior?.generation
10387
- });
10388
- saveBrokerManifest({ generation, helperGeneration: helperGeneration2, stateIds: [], updatedAt: Date.now() });
10389
10542
  const entries = /* @__PURE__ */ new Map();
10390
10543
  const acceptedIds = /* @__PURE__ */ new Set();
10391
10544
  const resultCacheLimit = options.resultCacheLimit ?? BROKER_RESULT_CACHE_MAX_ENTRIES;
@@ -10506,6 +10659,7 @@ async function startBroker(options = {}) {
10506
10659
  helperGeneration: currentHelperGenerationSafe(),
10507
10660
  requestId: request.requestId,
10508
10661
  cwd: request.cwd,
10662
+ environment: request.environment,
10509
10663
  signal: entry.controller.signal,
10510
10664
  onDispatch: () => {
10511
10665
  entry.dispatched = true;
@@ -10529,7 +10683,7 @@ async function startBroker(options = {}) {
10529
10683
  return;
10530
10684
  }
10531
10685
  const key = request.requestId;
10532
- const fingerprint = requestFingerprint(request.command, request.params, request.cwd);
10686
+ const fingerprint = requestFingerprint(request.command, request.params, request.cwd, request.environment);
10533
10687
  const existing = entries.get(key);
10534
10688
  if (existing) {
10535
10689
  if (existing.ownerId !== request.ownerId || existing.command !== request.command || existing.fingerprint !== fingerprint) {
@@ -10741,7 +10895,8 @@ async function startBroker(options = {}) {
10741
10895
  pid: process.pid,
10742
10896
  startedAt,
10743
10897
  platform: process.platform,
10744
- transport: endpoint.kind
10898
+ transport: endpoint.kind,
10899
+ backend: { fakeInstalled: options.fakeBackendInstalled === true, requireFake: requireFakeBackend() }
10745
10900
  });
10746
10901
  } catch (error) {
10747
10902
  helloRejected = true;
@@ -10829,6 +10984,23 @@ async function startBroker(options = {}) {
10829
10984
  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.`);
10830
10985
  }
10831
10986
  }
10987
+ legacyCache = cleanupLegacyBrokerCache();
10988
+ const prior = loadBrokerManifest();
10989
+ try {
10990
+ artifacts.cleanupOtherGenerations(generation);
10991
+ } catch {
10992
+ }
10993
+ configureEngineRuntime({
10994
+ generation,
10995
+ helperGeneration: helperGeneration2,
10996
+ artifacts,
10997
+ expiredStateIds: prior?.stateIds ?? [],
10998
+ previousGeneration: prior?.generation
10999
+ });
11000
+ saveBrokerManifest({ generation, helperGeneration: helperGeneration2, stateIds: [], updatedAt: Date.now() });
11001
+ } catch (error) {
11002
+ if (server.listening) server.close();
11003
+ throw error;
10832
11004
  } finally {
10833
11005
  bootstrapLock();
10834
11006
  }
@@ -10881,13 +11053,6 @@ async function startBroker(options = {}) {
10881
11053
  clearDrainMarker();
10882
11054
  } catch {
10883
11055
  }
10884
- if (endpoint.kind === "unix-socket") {
10885
- try {
10886
- const stats = lstatSync4(endpoint.path);
10887
- if (stats.isSocket()) unlinkSync4(endpoint.path);
10888
- } catch {
10889
- }
10890
- }
10891
11056
  options.onShutdown?.();
10892
11057
  void reason;
10893
11058
  };
@@ -10913,7 +11078,7 @@ async function startBroker(options = {}) {
10913
11078
  uncertain,
10914
11079
  requests: entries.size,
10915
11080
  ownerCount: owners.size,
10916
- ownerFingerprints: [...owners].map((owner) => createHash3("sha256").update(owner).digest("hex").slice(0, 12)),
11081
+ ownerFingerprints: [...owners].map((owner) => createHash4("sha256").update(owner).digest("hex").slice(0, 12)),
10917
11082
  artifacts: artifacts.stats(),
10918
11083
  legacyCache,
10919
11084
  idleExitMs
@@ -10934,19 +11099,8 @@ async function startBroker(options = {}) {
10934
11099
  return statusHandle;
10935
11100
  }
10936
11101
 
10937
- // vendor/computer-use-axi/src/test-backend-guard.ts
10938
- function resolveTestOnlyBackend(env = process.env) {
10939
- if (env.PIE_COMPUTER_USE_FAKE_BACKEND !== "1") return { enabled: false };
10940
- if (env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS !== "1") {
10941
- return {
10942
- enabled: false,
10943
- warning: "PIE_COMPUTER_USE_FAKE_BACKEND is test-only and was ignored: it requires PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS=1 as well."
10944
- };
10945
- }
10946
- return { enabled: true };
10947
- }
10948
-
10949
11102
  // vendor/computer-use-axi/src/broker-main.ts
11103
+ init_test_backend_guard();
10950
11104
  async function loadTestOnlyBackend() {
10951
11105
  const decision = resolveTestOnlyBackend();
10952
11106
  if (decision.warning) process.stderr.write(`computer-use-axi broker: ${decision.warning}
@@ -10959,6 +11113,7 @@ async function loadTestOnlyBackend() {
10959
11113
  setPlatformBackend(fake);
10960
11114
  return fake;
10961
11115
  } catch (error) {
11116
+ if (requireFakeBackend()) throw new Error("Required fake backend failed to load; refusing native fallback.", { cause: error });
10962
11117
  process.stderr.write(
10963
11118
  `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.
10964
11119
  `
@@ -10971,6 +11126,7 @@ async function main() {
10971
11126
  const testCommands = process.env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS === "1";
10972
11127
  const handle = await startBroker({
10973
11128
  testCommands,
11129
+ fakeBackendInstalled: Boolean(fake),
10974
11130
  // Fail-closed capacity contract hooks (tests only; both require the
10975
11131
  // explicit test-command switch and are ignored in every other build).
10976
11132
  resultCacheLimit: testCommands && Number.isFinite(Number(process.env.PIE_COMPUTER_USE_TEST_RESULT_CACHE_LIMIT)) ? Math.trunc(Number(process.env.PIE_COMPUTER_USE_TEST_RESULT_CACHE_LIMIT)) : void 0,