@cydm/pie 2.7.1 → 2.7.3

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.
@@ -12,6 +12,14 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
12
12
  if (typeof require !== "undefined") return require.apply(this, arguments);
13
13
  throw Error('Dynamic require of "' + x + '" is not supported');
14
14
  });
15
+ var __esm = (fn, res, err) => function __init() {
16
+ if (err) throw err[0];
17
+ try {
18
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
19
+ } catch (e) {
20
+ throw err = [e], e;
21
+ }
22
+ };
15
23
  var __commonJS = (cb, mod) => function __require2() {
16
24
  try {
17
25
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
@@ -19,6 +27,10 @@ var __commonJS = (cb, mod) => function __require2() {
19
27
  throw mod = 0, e;
20
28
  }
21
29
  };
30
+ var __export = (target, all) => {
31
+ for (var name in all)
32
+ __defProp(target, name, { get: all[name], enumerable: true });
33
+ };
22
34
  var __copyProps = (to, from, except, desc) => {
23
35
  if (from && typeof from === "object" || typeof from === "function") {
24
36
  for (let key of __getOwnPropNames(from))
@@ -36,6 +48,26 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
48
  mod
37
49
  ));
38
50
 
51
+ // vendor/computer-use-axi/src/platform/coerce.ts
52
+ function toBoolean(value) {
53
+ return value === true || value === "true" || value === 1;
54
+ }
55
+ function toFiniteNumber(value, fallback) {
56
+ if (typeof value === "number" && Number.isFinite(value)) return value;
57
+ if (typeof value === "string") {
58
+ const parsed = Number(value);
59
+ if (Number.isFinite(parsed)) return parsed;
60
+ }
61
+ return fallback;
62
+ }
63
+ function toOptionalString(value) {
64
+ return typeof value === "string" && value.length > 0 ? value : void 0;
65
+ }
66
+ var init_coerce = __esm({
67
+ "vendor/computer-use-axi/src/platform/coerce.ts"() {
68
+ }
69
+ });
70
+
39
71
  // ../../node_modules/ws/lib/constants.js
40
72
  var require_constants = __commonJS({
41
73
  "../../node_modules/ws/lib/constants.js"(exports, module) {
@@ -3719,188 +3751,746 @@ var require_websocket_server = __commonJS({
3719
3751
  }
3720
3752
  });
3721
3753
 
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;
3754
+ // vendor/computer-use-axi/src/platform/macos/helper-path.mjs
3755
+ import { accessSync, constants as fsConstants, existsSync as existsSync4 } from "node:fs";
3756
+ import os from "node:os";
3757
+ import path7 from "node:path";
3758
+ function resolveMacosHelperAppPath(options = {}) {
3759
+ const env = options.env ?? process.env;
3760
+ const explicitPath = env.PIE_COMPUTER_USE_HELPER_APP_PATH?.trim();
3761
+ if (explicitPath) return path7.resolve(explicitPath);
3762
+ const homeDir = options.homeDir ?? os.homedir();
3763
+ const configDir = options.configDir ?? resolvePieConfigDir(env, homeDir);
3764
+ const systemHelperAppPath = options.systemHelperAppPath ?? SYSTEM_HELPER_APP_PATH;
3765
+ const fileExists = options.fileExists ?? existsSync4;
3766
+ const directoryIsWritable = options.directoryIsWritable ?? ((directoryPath) => {
3767
+ try {
3768
+ accessSync(directoryPath, fsConstants.W_OK);
3769
+ return true;
3770
+ } catch {
3771
+ return false;
3761
3772
  }
3762
- dir = dirname(dir);
3773
+ });
3774
+ if (fileExists(systemHelperAppPath) && directoryIsWritable(path7.dirname(systemHelperAppPath))) {
3775
+ return systemHelperAppPath;
3763
3776
  }
3764
- return __dirname;
3765
- }
3766
- function getPackageJsonPath() {
3767
- return join(getPackageDir(), "package.json");
3777
+ return path7.join(configDir, "computer-use", HELPER_APP_NAME);
3768
3778
  }
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];
3779
+ function resolvePieConfigDir(env, homeDir) {
3780
+ const envDir = env.PIE_CODING_AGENT_DIR;
3775
3781
  if (envDir) {
3776
- if (envDir === "~") return homedir();
3777
- if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
3782
+ if (envDir === "~") return homeDir;
3783
+ if (envDir.startsWith("~/")) return homeDir + envDir.slice(1);
3778
3784
  return envDir;
3779
3785
  }
3780
- return join(homedir(), CONFIG_DIR_NAME);
3786
+ return path7.join(homeDir, ".pie");
3781
3787
  }
3788
+ var HELPER_APP_NAME, SYSTEM_HELPER_APP_PATH;
3789
+ var init_helper_path = __esm({
3790
+ "vendor/computer-use-axi/src/platform/macos/helper-path.mjs"() {
3791
+ HELPER_APP_NAME = "pie-computer-use.app";
3792
+ SYSTEM_HELPER_APP_PATH = path7.join("/Applications", HELPER_APP_NAME);
3793
+ }
3794
+ });
3782
3795
 
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 {
3796
+ // vendor/computer-use-axi/src/platform/package-root.ts
3797
+ import { existsSync as existsSync5 } from "node:fs";
3798
+ import path8 from "node:path";
3799
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
3800
+ function resolveExtensionRoot(moduleUrl) {
3801
+ const override = process.env.PIE_COMPUTER_USE_PACKAGE_ROOT?.trim();
3802
+ if (override) return path8.resolve(override);
3803
+ let dir = path8.dirname(fileURLToPath2(moduleUrl));
3804
+ for (let depth = 0; depth < 12; depth += 1) {
3805
+ if (existsSync5(path8.join(dir, "scripts", "setup-helper.mjs"))) return dir;
3806
+ const parent = path8.dirname(dir);
3807
+ if (parent === dir) break;
3808
+ dir = parent;
3839
3809
  }
3810
+ 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.`);
3840
3811
  }
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 {
3812
+ var init_package_root = __esm({
3813
+ "vendor/computer-use-axi/src/platform/package-root.ts"() {
3883
3814
  }
3884
- return { runtimeFile, states, outputs: outputs2 };
3815
+ });
3816
+
3817
+ // vendor/computer-use-axi/src/platform/macos/helper.ts
3818
+ import { spawn } from "node:child_process";
3819
+ import { constants as fsConstants2 } from "node:fs";
3820
+ import { access, mkdir, realpath } from "node:fs/promises";
3821
+ import net from "node:net";
3822
+ import os2 from "node:os";
3823
+ import path9 from "node:path";
3824
+ function throwIfAborted(signal) {
3825
+ if (signal?.aborted) throw new Error("Operation aborted.");
3885
3826
  }
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);
3827
+ async function sleep(ms, signal) {
3828
+ throwIfAborted(signal);
3829
+ await new Promise((resolve2, reject) => {
3830
+ const timer = setTimeout(resolve2, ms);
3831
+ const onAbort = () => {
3832
+ clearTimeout(timer);
3833
+ reject(new Error("Operation aborted."));
3834
+ };
3835
+ signal?.addEventListener("abort", onAbort, { once: true });
3836
+ }).finally(() => signal?.throwIfAborted?.());
3891
3837
  }
3892
- function readJsonFile(filePath) {
3838
+ async function isExecutable(filePath) {
3893
3839
  try {
3894
- return JSON.parse(readFileSync2(filePath, "utf8"));
3840
+ await access(filePath, fsConstants2.X_OK);
3841
+ return true;
3895
3842
  } catch {
3896
- return void 0;
3843
+ return false;
3897
3844
  }
3898
3845
  }
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) {
3846
+ async function isResolvedHelperExecutable(filePath) {
3847
+ if (!filePath) return true;
3848
+ const [actualPath, expectedPath] = await Promise.all([
3849
+ realpath(filePath).catch(() => path9.resolve(filePath)),
3850
+ realpath(HELPER_APP_EXECUTABLE_PATH).catch(() => path9.resolve(HELPER_APP_EXECUTABLE_PATH))
3851
+ ]);
3852
+ return actualPath === expectedPath;
3853
+ }
3854
+ async function runProcess(command, args, timeoutMs, signal, env) {
3855
+ throwIfAborted(signal);
3856
+ await new Promise((resolve2, reject) => {
3857
+ const child = spawn(command, args, {
3858
+ stdio: ["ignore", "pipe", "pipe"],
3859
+ env
3860
+ });
3861
+ let stderr = "";
3862
+ let stdout = "";
3863
+ const timer = setTimeout(() => {
3864
+ child.kill("SIGTERM");
3865
+ cleanup();
3866
+ reject(new Error(`Command timed out after ${timeoutMs}ms: ${command} ${args.join(" ")}`));
3867
+ }, timeoutMs);
3868
+ const onAbort = () => {
3869
+ child.kill("SIGTERM");
3870
+ cleanup();
3871
+ reject(new Error("Operation aborted."));
3872
+ };
3873
+ const cleanup = () => {
3874
+ clearTimeout(timer);
3875
+ signal?.removeEventListener("abort", onAbort);
3876
+ };
3877
+ child.stdout.on("data", (chunk) => {
3878
+ stdout += String(chunk);
3879
+ });
3880
+ child.stderr.on("data", (chunk) => {
3881
+ stderr += String(chunk);
3882
+ });
3883
+ child.on("error", (error) => {
3884
+ cleanup();
3885
+ reject(error);
3886
+ });
3887
+ child.on("close", (code) => {
3888
+ cleanup();
3889
+ if (code === 0) {
3890
+ resolve2();
3891
+ return;
3892
+ }
3893
+ const output = [stderr.trim(), stdout.trim()].filter(Boolean).join("\n");
3894
+ reject(new Error(`Command failed (${code}): ${command} ${args.join(" ")}
3895
+ ${output}`.trim()));
3896
+ });
3897
+ signal?.addEventListener("abort", onAbort, { once: true });
3898
+ });
3899
+ }
3900
+ 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
+ var init_helper = __esm({
3902
+ "vendor/computer-use-axi/src/platform/macos/helper.ts"() {
3903
+ init_coerce();
3904
+ init_helper_path();
3905
+ init_package_root();
3906
+ COMMAND_TIMEOUT_MS2 = 15e3;
3907
+ HELPER_PROTOCOL_VERSION = 6;
3908
+ HELPER_SETUP_TIMEOUT_MS = 6e4;
3909
+ HELPER_APP_PATH = resolveMacosHelperAppPath();
3910
+ HELPER_APP_EXECUTABLE_PATH = path9.join(HELPER_APP_PATH, "Contents", "MacOS", "pie-computer-use");
3911
+ DEFAULT_HELPER_SOCKET_PATH = path9.join(os2.homedir(), "Library", "Caches", "pie-computer-use", "bridge.sock");
3912
+ HELPER_SOCKET_PATH = process.env.PIE_COMPUTER_USE_SOCKET_PATH ?? DEFAULT_HELPER_SOCKET_PATH;
3913
+ usingExternalHelperSocket = HELPER_SOCKET_PATH !== DEFAULT_HELPER_SOCKET_PATH;
3914
+ PACKAGE_ROOT = resolveExtensionRoot(import.meta.url);
3915
+ SETUP_HELPER_SCRIPT = path9.join(PACKAGE_ROOT, "scripts", "setup-helper.mjs");
3916
+ HelperTransportError = class extends Error {
3917
+ constructor(message) {
3918
+ super(message);
3919
+ this.name = "HelperTransportError";
3920
+ }
3921
+ };
3922
+ HelperCommandError = class extends Error {
3923
+ code;
3924
+ constructor(message, code) {
3925
+ super(message);
3926
+ this.name = "HelperCommandError";
3927
+ this.code = code;
3928
+ }
3929
+ };
3930
+ MacosHelperClient = class {
3931
+ daemonAvailable = false;
3932
+ requestSequence = 0;
3933
+ diagnosticsCache;
3934
+ get diagnostics() {
3935
+ return this.diagnosticsCache;
3936
+ }
3937
+ async ensureInstalled(signal) {
3938
+ if (usingExternalHelperSocket) return;
3939
+ if (await isExecutable(HELPER_APP_EXECUTABLE_PATH)) {
3940
+ return;
3941
+ }
3942
+ await runProcess(process.execPath, [SETUP_HELPER_SCRIPT, "--runtime"], HELPER_SETUP_TIMEOUT_MS, signal, {
3943
+ ...process.env,
3944
+ ELECTRON_RUN_AS_NODE: "1",
3945
+ BUN_BE_BUN: "1"
3946
+ });
3947
+ if (!await isExecutable(HELPER_APP_EXECUTABLE_PATH)) {
3948
+ throw new Error(`Failed to install pie-computer-use helper app at ${HELPER_APP_PATH}.`);
3949
+ }
3950
+ }
3951
+ async launchDaemon(signal) {
3952
+ if (usingExternalHelperSocket) throw new HelperTransportError(`External helper socket is unavailable at ${HELPER_SOCKET_PATH}.`);
3953
+ await mkdir(path9.dirname(HELPER_SOCKET_PATH), { recursive: true });
3954
+ await runProcess("open", ["-n", "-g", HELPER_APP_PATH, "--args", "serve", "--socket", HELPER_SOCKET_PATH], COMMAND_TIMEOUT_MS2, signal);
3955
+ }
3956
+ async daemonCommand(cmd, args, timeoutMs, signal) {
3957
+ return await new Promise((resolve2, reject) => {
3958
+ const id = `req_${++this.requestSequence}`;
3959
+ const socket = net.createConnection(HELPER_SOCKET_PATH);
3960
+ let buffer = "";
3961
+ const timer = setTimeout(() => {
3962
+ socket.destroy();
3963
+ reject(new HelperTransportError(`Daemon command '${cmd}' timed out after ${timeoutMs}ms.`));
3964
+ }, timeoutMs);
3965
+ const cleanup = () => {
3966
+ clearTimeout(timer);
3967
+ signal?.removeEventListener("abort", onAbort);
3968
+ };
3969
+ const onAbort = () => {
3970
+ socket.destroy();
3971
+ cleanup();
3972
+ reject(new Error("Operation aborted."));
3973
+ };
3974
+ signal?.addEventListener("abort", onAbort, { once: true });
3975
+ socket.setEncoding("utf8");
3976
+ socket.on("connect", () => socket.write(`${JSON.stringify({ id, cmd, ...args })}
3977
+ `));
3978
+ socket.on("data", (chunk) => {
3979
+ buffer += chunk;
3980
+ const newline = buffer.indexOf("\n");
3981
+ if (newline < 0) return;
3982
+ cleanup();
3983
+ socket.end();
3984
+ try {
3985
+ const parsed = JSON.parse(buffer.slice(0, newline));
3986
+ if (parsed.ok === true) resolve2(parsed.result);
3987
+ else reject(new HelperCommandError(parsed?.error?.message ?? `Daemon command '${cmd}' failed.`, parsed?.error?.code));
3988
+ } catch (error) {
3989
+ reject(error);
3990
+ }
3991
+ });
3992
+ socket.on("error", (error) => {
3993
+ cleanup();
3994
+ reject(new HelperTransportError(error.message));
3995
+ });
3996
+ });
3997
+ }
3998
+ async ensureDaemon(signal) {
3999
+ if (this.daemonAvailable) return true;
4000
+ try {
4001
+ await this.daemonCommand("diagnostics", {}, 1e3, signal);
4002
+ this.daemonAvailable = true;
4003
+ return true;
4004
+ } catch {
4005
+ }
4006
+ await this.launchDaemon(signal).catch(() => void 0);
4007
+ for (let index = 0; index < 30; index += 1) {
4008
+ try {
4009
+ await this.daemonCommand("diagnostics", {}, 1e3, signal);
4010
+ this.daemonAvailable = true;
4011
+ return true;
4012
+ } catch {
4013
+ await sleep(100, signal);
4014
+ }
4015
+ }
4016
+ return false;
4017
+ }
4018
+ async command(cmd, args = {}, options) {
4019
+ const timeoutMs = options?.timeoutMs ?? COMMAND_TIMEOUT_MS2;
4020
+ if (!await this.ensureDaemon(options?.signal)) {
4021
+ throw new HelperTransportError(`pie-computer-use helper app daemon is unavailable at ${HELPER_APP_PATH}.`);
4022
+ }
4023
+ try {
4024
+ return await this.daemonCommand(cmd, args, timeoutMs, options?.signal);
4025
+ } catch (error) {
4026
+ this.daemonAvailable = false;
4027
+ throw error instanceof Error ? error : new Error(String(error));
4028
+ }
4029
+ }
4030
+ async restart(signal) {
4031
+ await this.command("shutdown", {}, { signal, timeoutMs: 2e3 }).catch(() => void 0);
4032
+ this.daemonAvailable = false;
4033
+ await sleep(400, signal);
4034
+ if (!await this.ensureDaemon(signal)) {
4035
+ throw new Error(`pie-computer-use helper did not come back after restart. Helper app: ${HELPER_APP_PATH}`);
4036
+ }
4037
+ }
4038
+ async diagnosticsCommand(signal) {
4039
+ const result = await this.command("diagnostics", {}, { signal });
4040
+ const diagnostics = {
4041
+ protocolVersion: Math.trunc(toFiniteNumber(result?.protocolVersion, 0)),
4042
+ architectureVersion: Math.trunc(toFiniteNumber(result?.architectureVersion, 0)),
4043
+ invariants: Array.isArray(result?.invariants) ? result.invariants.filter((value) => typeof value === "string") : [],
4044
+ pid: Math.trunc(toFiniteNumber(result?.pid, 0)),
4045
+ parentPid: Math.trunc(toFiniteNumber(result?.parentPid, 0)) || void 0,
4046
+ parentAppName: toOptionalString(result?.parentAppName),
4047
+ parentBundleId: toOptionalString(result?.parentBundleId),
4048
+ parentPath: toOptionalString(result?.parentPath),
4049
+ executablePath: toOptionalString(result?.executablePath),
4050
+ os: toOptionalString(result?.macOS),
4051
+ arch: toOptionalString(result?.arch),
4052
+ accessibility: toBoolean(result?.accessibility),
4053
+ screenRecording: toBoolean(result?.screenRecording)
4054
+ };
4055
+ this.diagnosticsCache = diagnostics;
4056
+ return diagnostics;
4057
+ }
4058
+ async ensureProtocol(signal) {
4059
+ let diagnostics = await this.diagnosticsCommand(signal);
4060
+ const executableMatches = await isResolvedHelperExecutable(diagnostics.executablePath);
4061
+ if (diagnostics.protocolVersion === HELPER_PROTOCOL_VERSION && executableMatches) return diagnostics;
4062
+ await this.restart(signal);
4063
+ diagnostics = await this.diagnosticsCommand(signal);
4064
+ const relaunchedExecutableMatches = await isResolvedHelperExecutable(diagnostics.executablePath);
4065
+ if (diagnostics.protocolVersion !== HELPER_PROTOCOL_VERSION || !relaunchedExecutableMatches) {
4066
+ this.daemonAvailable = false;
4067
+ throw new Error(
4068
+ `pie-computer-use helper mismatch after relaunch: expected protocol ${HELPER_PROTOCOL_VERSION} and executable ${HELPER_APP_EXECUTABLE_PATH}; got protocol ${diagnostics.protocolVersion} and executable ${diagnostics.executablePath ?? "unknown"}. Reinstall or rebuild the helper app at ${HELPER_APP_PATH}.`
4069
+ );
4070
+ }
4071
+ return diagnostics;
4072
+ }
4073
+ };
4074
+ macosHelper = new MacosHelperClient();
4075
+ }
4076
+ });
4077
+
4078
+ // vendor/computer-use-axi/src/permissions.ts
4079
+ async function runPermissionSetup(bridge, mode, signal) {
4080
+ throwIfAborted2(signal);
4081
+ if (mode === "recheck") await bridge.restartHelper(signal);
4082
+ let status = await bridge.checkPermissions(signal);
4083
+ if (mode === "setup" && !allGranted(status, bridge.kinds)) {
4084
+ await bridge.registerPermissions(signal);
4085
+ for (const kind of missingKinds(status, bridge.kinds)) {
4086
+ throwIfAborted2(signal);
4087
+ await bridge.openPermissionPane(kind, signal);
4088
+ }
4089
+ status = await bridge.checkPermissions(signal);
4090
+ }
4091
+ return status;
4092
+ }
4093
+ function throwIfAborted2(signal) {
4094
+ if (signal?.aborted) throw new Error("Operation aborted.");
4095
+ }
4096
+ function granted(status, kind) {
4097
+ return status[kind] === true;
4098
+ }
4099
+ function allGranted(status, kinds) {
4100
+ return kinds.every(({ kind }) => granted(status, kind));
4101
+ }
4102
+ function missingKinds(status, kinds) {
4103
+ return kinds.flatMap(({ kind }) => granted(status, kind) ? [] : [kind]);
4104
+ }
4105
+ function permissionStatusSuggestsHelperRestart(status) {
4106
+ return status.screenRecordingPreflight === true && status.screenRecording === false;
4107
+ }
4108
+ async function ensurePermissions(ctx, bridge, helperPath, signal) {
4109
+ let status = await bridge.checkPermissions(signal);
4110
+ if (allGranted(status, bridge.kinds)) return status;
4111
+ if (!ctx.hasUI) throw new Error(bridge.copy.nonInteractiveError(helperPath));
4112
+ await bridge.registerPermissions(signal).catch(() => void 0);
4113
+ while (!allGranted(status, bridge.kinds)) {
4114
+ throwIfAborted2(signal);
4115
+ const missing = missingKinds(status, bridge.kinds);
4116
+ const options = bridge.kinds.filter(({ kind }) => missing.includes(kind)).map(({ openOption }) => openOption);
4117
+ options.push("Recheck (restarts helper)", "Cancel");
4118
+ const choice = await ctx.ui.select(bridge.copy.prompt(status, helperPath, bridge.permissionHint), options, { signal });
4119
+ if (!choice || choice === "Cancel") throw new Error(bridge.copy.incompleteError(helperPath));
4120
+ const selected = bridge.kinds.find(({ openOption }) => choice === openOption);
4121
+ if (selected) await bridge.openPermissionPane(selected.kind, signal);
4122
+ if (choice.startsWith("Recheck")) {
4123
+ await bridge.restartHelper(signal);
4124
+ status = await bridge.checkPermissions(signal);
4125
+ if (allGranted(status, bridge.kinds)) {
4126
+ ctx.ui.notify(bridge.copy.readyMessage, "info");
4127
+ } else {
4128
+ ctx.ui.notify(bridge.copy.stillMissing(missingKinds(status, bridge.kinds)), "warning");
4129
+ }
4130
+ }
4131
+ }
4132
+ return status;
4133
+ }
4134
+ var init_permissions = __esm({
4135
+ "vendor/computer-use-axi/src/permissions.ts"() {
4136
+ }
4137
+ });
4138
+
4139
+ // vendor/computer-use-axi/src/platform/architecture.ts
4140
+ function assertPlatformArchitecture(platform, diagnostics) {
4141
+ if (diagnostics.architectureVersion !== PLATFORM_ARCHITECTURE_VERSION) {
4142
+ throw new Error(`${platform} helper architecture mismatch: expected ${PLATFORM_ARCHITECTURE_VERSION}, got ${diagnostics.architectureVersion ?? "unknown"}. Rebuild and restart the helper.`);
4143
+ }
4144
+ const reported = new Set(diagnostics.invariants ?? []);
4145
+ const missing = REQUIRED_PLATFORM_INVARIANTS.filter((invariant) => !reported.has(invariant));
4146
+ if (missing.length > 0) {
4147
+ throw new Error(`${platform} helper does not satisfy the shared computer-use contract: ${missing.join(", ")}.`);
4148
+ }
4149
+ }
4150
+ var PLATFORM_ARCHITECTURE_VERSION, REQUIRED_PLATFORM_INVARIANTS;
4151
+ var init_architecture = __esm({
4152
+ "vendor/computer-use-axi/src/platform/architecture.ts"() {
4153
+ PLATFORM_ARCHITECTURE_VERSION = 1;
4154
+ REQUIRED_PLATFORM_INVARIANTS = [
4155
+ "state-scoped-observations",
4156
+ "bounded-observation-history",
4157
+ "multi-root-forest",
4158
+ "progressive-disclosure",
4159
+ "atomic-physical-input",
4160
+ "concurrent-requests",
4161
+ "transactional-batching"
4162
+ ];
4163
+ }
4164
+ });
4165
+
4166
+ // vendor/computer-use-axi/src/platform/macos/permissions.ts
4167
+ var permissions_exports = {};
4168
+ __export(permissions_exports, {
4169
+ ensureMacosReady: () => ensureMacosReady,
4170
+ setupMacosPermissions: () => setupMacosPermissions
4171
+ });
4172
+ function permissionStatusSummary(status) {
4173
+ const lines = [
4174
+ `Accessibility: ${status.accessibility ? "granted" : "missing"}`,
4175
+ `Screen Recording: ${status.screenRecording ? "granted" : "missing"}`
4176
+ ];
4177
+ if (status.screenRecordingPreflight && !status.screenRecording) {
4178
+ lines.push(
4179
+ "(Screen Recording reads granted in the TCC database but a live capture probe failed \u2014 the grant likely belongs to a different app identity, or the helper needs a restart.)"
4180
+ );
4181
+ }
4182
+ return lines.join("; ");
4183
+ }
4184
+ function permissionPrompt(status, helperPath, hint) {
4185
+ return [
4186
+ "pie-computer-use needs macOS permissions for its helper app.",
4187
+ permissionStatusSummary(status),
4188
+ "",
4189
+ `Helper: pie-computer-use.app (${helperPath})`,
4190
+ hint,
4191
+ "",
4192
+ `Important: ${SIGNING_MIGRATION_WARNING}`,
4193
+ "",
4194
+ "pie-computer-use.app is already listed in the pane(s) \u2014 enable its toggle, then choose Recheck."
4195
+ ].filter(Boolean).join("\n");
4196
+ }
4197
+ function missingPermissionMessage(kinds) {
4198
+ return `Still missing after restart: ${kinds.join(" and ")}. ${SIGNING_MIGRATION_WARNING} Then choose Recheck again.`;
4199
+ }
4200
+ async function checkPermissions(signal) {
4201
+ const result = await macosHelper.command("checkPermissions", {}, { signal });
4202
+ const rawSource = result?.source;
4203
+ return {
4204
+ accessibility: toBoolean(result?.accessibility),
4205
+ // Authoritative: the helper's live ScreenCaptureKit probe.
4206
+ screenRecording: toBoolean(result?.screenRecordingCapturable),
4207
+ // Keep the preflight value separate: disagreement means stale per-process
4208
+ // TCC cache or a grant row belonging to another app identity.
4209
+ screenRecordingPreflight: toBoolean(result?.screenRecordingPreflight),
4210
+ source: rawSource && typeof rawSource === "object" ? {
4211
+ // macOS attributes Accessibility / Screen Recording grants to the
4212
+ // responsible process at the top of the launch chain. "helper-app"
4213
+ // is the canonical installed app via LaunchServices; "caller" means
4214
+ // grants would attach to the launching app instead.
4215
+ attribution: rawSource.attribution === "helper-app" ? "helper-app" : "caller",
4216
+ pid: Math.trunc(toFiniteNumber(rawSource.pid, 0)) || void 0,
4217
+ parentPid: Math.trunc(toFiniteNumber(rawSource.parentPid, 0)) || void 0,
4218
+ executablePath: toOptionalString(rawSource.executablePath),
4219
+ parentPath: toOptionalString(rawSource.parentPath),
4220
+ parentBundleId: toOptionalString(rawSource.parentBundleId),
4221
+ os: toOptionalString(rawSource.macOS)
4222
+ } : void 0
4223
+ };
4224
+ }
4225
+ async function registerPermissions(signal) {
4226
+ const helperPid = macosHelper.diagnostics?.pid;
4227
+ if (helperPid !== void 0 && helperPid === registeredForHelperPid) return;
4228
+ await macosHelper.command("registerPermissions", {}, { signal, timeoutMs: 15e3 });
4229
+ registeredForHelperPid = helperPid;
4230
+ }
4231
+ async function setupMacosPermissions(mode) {
4232
+ await macosHelper.ensureInstalled();
4233
+ if (!await macosHelper.ensureDaemon()) throw new Error(`Helper daemon unavailable: ${HELPER_APP_PATH}`);
4234
+ assertPlatformArchitecture("macOS", await macosHelper.ensureProtocol());
4235
+ return await runPermissionSetup({
4236
+ kinds: macosPermissionKinds,
4237
+ checkPermissions,
4238
+ registerPermissions,
4239
+ openPermissionPane: async (kind, signal) => {
4240
+ await macosHelper.command("openPermissionPane", { kind }, { signal });
4241
+ },
4242
+ restartHelper: (signal) => macosHelper.restart(signal)
4243
+ }, mode);
4244
+ }
4245
+ async function ensureMacosReady(ctx, state, signal) {
4246
+ await macosHelper.ensureInstalled(signal);
4247
+ if (!await macosHelper.ensureDaemon(signal)) {
4248
+ throw new Error(`pie-computer-use helper app daemon did not start. Helper app: ${HELPER_APP_PATH}`);
4249
+ }
4250
+ const helperDiagnostics = await macosHelper.ensureProtocol(signal);
4251
+ assertPlatformArchitecture("macOS", helperDiagnostics);
4252
+ const now = Date.now();
4253
+ const cachedStatus = state.permissionStatus;
4254
+ const canUseCachedPermissions = cachedStatus?.accessibility && cachedStatus.screenRecording && now - state.lastPermissionCheckAt < 2e3;
4255
+ if (canUseCachedPermissions) {
4256
+ return { ...state, helperDiagnostics };
4257
+ }
4258
+ let permissionStatus = await checkPermissions(signal);
4259
+ let lastPermissionCheckAt = now;
4260
+ if (!autoRestartAttempted && permissionStatusSuggestsHelperRestart(permissionStatus)) {
4261
+ autoRestartAttempted = true;
4262
+ await macosHelper.restart(signal).catch(() => void 0);
4263
+ permissionStatus = await checkPermissions(signal);
4264
+ lastPermissionCheckAt = Date.now();
4265
+ }
4266
+ if (!permissionStatus.accessibility || !permissionStatus.screenRecording) {
4267
+ const attributionHint = permissionStatus.source?.attribution === "caller" ? `Warning: the helper is not running as the installed pie-computer-use.app (executable: ${permissionStatus.source?.executablePath ?? "unknown"}). Grants made now would attach to the launching app instead. Restart Pie so the canonical helper is used.` : void 0;
4268
+ permissionStatus = await ensurePermissions(
4269
+ ctx,
4270
+ {
4271
+ kinds: macosPermissionKinds,
4272
+ copy: {
4273
+ nonInteractiveError: (helperPath) => `Run 'computer-use-axi permissions setup' to register the helper and open Settings, grant both permissions, then run 'computer-use-axi permissions recheck'. ${GRANT_INSTRUCTIONS}
4274
+ Helper path: ${helperPath}`,
4275
+ prompt: permissionPrompt,
4276
+ incompleteError: (helperPath) => `pie-computer-use setup is incomplete. ${GRANT_INSTRUCTIONS} Helper path: ${helperPath}`,
4277
+ readyMessage: "pie-computer-use is ready.",
4278
+ stillMissing: missingPermissionMessage
4279
+ },
4280
+ checkPermissions: (permissionSignal) => checkPermissions(permissionSignal ?? signal),
4281
+ registerPermissions: (permissionSignal) => registerPermissions(permissionSignal ?? signal),
4282
+ openPermissionPane: async (kind, permissionSignal) => {
4283
+ await macosHelper.command("openPermissionPane", { kind }, { signal: permissionSignal ?? signal });
4284
+ },
4285
+ restartHelper: (permissionSignal) => macosHelper.restart(permissionSignal ?? signal),
4286
+ permissionHint: attributionHint
4287
+ },
4288
+ HELPER_APP_PATH,
4289
+ signal
4290
+ );
4291
+ lastPermissionCheckAt = Date.now();
4292
+ }
4293
+ return { permissionStatus, lastPermissionCheckAt, helperDiagnostics };
4294
+ }
4295
+ var GRANT_INSTRUCTIONS, SIGNING_MIGRATION_WARNING, macosPermissionKinds, registeredForHelperPid, autoRestartAttempted;
4296
+ var init_permissions2 = __esm({
4297
+ "vendor/computer-use-axi/src/platform/macos/permissions.ts"() {
4298
+ init_permissions();
4299
+ init_coerce();
4300
+ init_helper();
4301
+ init_architecture();
4302
+ 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.";
4303
+ 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.";
4304
+ macosPermissionKinds = [
4305
+ { kind: "accessibility", openOption: "Open Accessibility Settings (missing)" },
4306
+ { kind: "screenRecording", openOption: "Open Screen Recording Settings (missing)" }
4307
+ ];
4308
+ autoRestartAttempted = false;
4309
+ }
4310
+ });
4311
+
4312
+ // vendor/computer-use-axi/src/broker-server.ts
4313
+ import { createHash as createHash3, randomUUID as randomUUID8 } from "node:crypto";
4314
+ import { chmodSync as chmodSync2, lstatSync as lstatSync4, readFileSync as readFileSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
4315
+ import net3 from "node:net";
4316
+ import path14 from "node:path";
4317
+
4318
+ // vendor/computer-use-axi/src/artifact-store.ts
4319
+ 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";
4322
+
4323
+ // vendor/computer-use-axi/src/broker-protocol.ts
4324
+ import { createHash, randomUUID } from "node:crypto";
4325
+ import { chmodSync, lstatSync as lstatSync2, mkdirSync as mkdirSync3 } from "node:fs";
4326
+ import path2 from "node:path";
4327
+
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";
4330
+ import path from "node:path";
4331
+
4332
+ // src/config.ts
4333
+ import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
4334
+ import { homedir } from "os";
4335
+ import { dirname, join } from "path";
4336
+ import { fileURLToPath } from "url";
4337
+ var __filename = fileURLToPath(import.meta.url);
4338
+ var __dirname = dirname(__filename);
4339
+ var isBunRuntime = !!process.versions.bun;
4340
+ function getPackageDir() {
4341
+ const envDir = process.env.PIE_PACKAGE_DIR;
4342
+ if (envDir) {
4343
+ if (envDir === "~") return homedir();
4344
+ if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
4345
+ return envDir;
4346
+ }
4347
+ let dir = __dirname;
4348
+ while (dir !== dirname(dir)) {
4349
+ if (existsSync(join(dir, "package.json"))) {
4350
+ return dir;
4351
+ }
4352
+ dir = dirname(dir);
4353
+ }
4354
+ return __dirname;
4355
+ }
4356
+ function getPackageJsonPath() {
4357
+ return join(getPackageDir(), "package.json");
4358
+ }
4359
+ var pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
4360
+ var CONFIG_DIR_NAME = ".pie";
4361
+ var VERSION = pkg.version;
4362
+ var ENV_AGENT_DIR = "PIE_CODING_AGENT_DIR";
4363
+ function getConfigDir() {
4364
+ const envDir = process.env[ENV_AGENT_DIR];
4365
+ if (envDir) {
4366
+ if (envDir === "~") return homedir();
4367
+ if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
4368
+ return envDir;
4369
+ }
4370
+ return join(homedir(), CONFIG_DIR_NAME);
4371
+ }
4372
+
4373
+ // vendor/computer-use-axi/src/persist.ts
4374
+ function stateRootDir(env = process.env) {
4375
+ const override = env.PIE_COMPUTER_USE_STATE_DIR?.trim();
4376
+ if (override) return override;
4377
+ return path.join(getConfigDir(), "computer-use");
4378
+ }
4379
+ function statesDir(env = process.env) {
4380
+ return path.join(stateRootDir(env), "states");
4381
+ }
4382
+ function outputsDir(env = process.env) {
4383
+ return path.join(stateRootDir(env), "outputs");
4384
+ }
4385
+ function runtimeStatePath(env = process.env) {
4386
+ return path.join(stateRootDir(env), "runtime.json");
4387
+ }
4388
+ function brokerStateDir(env = process.env) {
4389
+ return path.join(stateRootDir(env), "broker");
4390
+ }
4391
+ function brokerManifestPath(env = process.env) {
4392
+ return path.join(brokerStateDir(env), "manifest.json");
4393
+ }
4394
+ function loadBrokerManifest(env = process.env) {
4395
+ const manifest = readJsonFile(brokerManifestPath(env));
4396
+ if (!manifest || typeof manifest.generation !== "string") return void 0;
4397
+ return {
4398
+ generation: manifest.generation,
4399
+ helperGeneration: typeof manifest.helperGeneration === "string" ? manifest.helperGeneration : "",
4400
+ stateIds: Array.isArray(manifest.stateIds) ? manifest.stateIds.filter((id) => typeof id === "string" && /^[A-Za-z0-9-]{1,128}$/.test(id)).slice(0, 256) : [],
4401
+ updatedAt: Number.isFinite(manifest.updatedAt) ? manifest.updatedAt : 0
4402
+ };
4403
+ }
4404
+ function saveBrokerManifest(manifest, env = process.env) {
4405
+ mkdirSync2(brokerStateDir(env), { recursive: true, mode: 448 });
4406
+ writeJsonAtomic(brokerManifestPath(env), { ...manifest, stateIds: manifest.stateIds.slice(0, 256) });
4407
+ }
4408
+ function brokerDrainMarkerPath(env = process.env) {
4409
+ return path.join(brokerStateDir(env), "draining.json");
4410
+ }
4411
+ function loadDrainMarker(env = process.env) {
4412
+ const marker = readJsonFile(brokerDrainMarkerPath(env));
4413
+ if (!marker || typeof marker !== "object" || !Number.isFinite(marker.pid)) return void 0;
4414
+ return {
4415
+ pid: Math.trunc(marker.pid),
4416
+ startedAt: Number.isFinite(marker.startedAt) ? marker.startedAt : 0,
4417
+ deadlineAt: Number.isFinite(marker.deadlineAt) ? marker.deadlineAt : 0
4418
+ };
4419
+ }
4420
+ function saveDrainMarker(marker, env = process.env) {
4421
+ mkdirSync2(brokerStateDir(env), { recursive: true, mode: 448 });
4422
+ writeJsonAtomic(brokerDrainMarkerPath(env), marker);
4423
+ }
4424
+ function clearDrainMarker(env = process.env) {
4425
+ try {
4426
+ const stats = lstatSync(brokerDrainMarkerPath(env));
4427
+ if (stats.isFile() && !stats.isSymbolicLink()) unlinkSync(brokerDrainMarkerPath(env));
4428
+ } catch {
4429
+ }
4430
+ }
4431
+ function cleanupLegacyBrokerCache(env = process.env) {
4432
+ let runtimeFile = false;
4433
+ let states = 0;
4434
+ let outputs2 = 0;
4435
+ const runtime = runtimeStatePath(env);
4436
+ try {
4437
+ const stats = lstatSync(runtime);
4438
+ if (stats.isFile() && !stats.isSymbolicLink()) {
4439
+ unlinkSync(runtime);
4440
+ runtimeFile = true;
4441
+ }
4442
+ } catch {
4443
+ }
4444
+ const statesDirPath = statesDir(env);
4445
+ try {
4446
+ for (const name of readdirSync(statesDirPath).slice(0, 512)) {
4447
+ if (!/^[A-Za-z0-9-]+\.json$/.test(name)) continue;
4448
+ const target = path.join(statesDirPath, name);
4449
+ try {
4450
+ const stats = lstatSync(target);
4451
+ if (!stats.isFile() || stats.isSymbolicLink()) continue;
4452
+ unlinkSync(target);
4453
+ states += 1;
4454
+ } catch {
4455
+ }
4456
+ }
4457
+ } catch {
4458
+ }
4459
+ const oldOutputs = outputsDir(env);
4460
+ try {
4461
+ for (const name of readdirSync(oldOutputs).slice(0, 512)) {
4462
+ if (!/^o\d+\.(txt|meta\.json)$/.test(name)) continue;
4463
+ const target = path.join(oldOutputs, name);
4464
+ try {
4465
+ const stats = lstatSync(target);
4466
+ if (!stats.isFile() || stats.isSymbolicLink()) continue;
4467
+ unlinkSync(target);
4468
+ outputs2 += 1;
4469
+ } catch {
4470
+ }
4471
+ }
4472
+ } catch {
4473
+ }
4474
+ return { runtimeFile, states, outputs: outputs2 };
4475
+ }
4476
+ function writeJsonAtomic(filePath, value) {
4477
+ mkdirSync2(path.dirname(filePath), { recursive: true });
4478
+ const temp = `${filePath}.${process.pid}.tmp`;
4479
+ writeFileSync(temp, JSON.stringify(value), "utf8");
4480
+ renameSync2(temp, filePath);
4481
+ }
4482
+ function readJsonFile(filePath) {
4483
+ try {
4484
+ return JSON.parse(readFileSync2(filePath, "utf8"));
4485
+ } catch {
4486
+ return void 0;
4487
+ }
4488
+ }
4489
+
4490
+ // src/runtime/computer-use-owner.ts
4491
+ var COMPUTER_USE_STANDALONE_OWNER = "standalone";
4492
+ var OWNER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:@-]{0,255}$/;
4493
+ function normalizeComputerUseOwner(value) {
3904
4494
  if (typeof value !== "string") return COMPUTER_USE_STANDALONE_OWNER;
3905
4495
  const trimmed = value.trim();
3906
4496
  if (!trimmed) return COMPUTER_USE_STANDALONE_OWNER;
@@ -3909,14 +4499,17 @@ function normalizeComputerUseOwner(value) {
3909
4499
 
3910
4500
  // vendor/computer-use-axi/src/broker-protocol.ts
3911
4501
  var BROKER_PROTOCOL_VERSION = 1;
3912
- var BROKER_ENGINE_VERSION = 1;
4502
+ var BROKER_ENGINE_VERSION = 2;
3913
4503
  var BROKER_PACKAGE_VERSION = "0.5.1-pie.1";
4504
+ var BROKER_RESULT_CACHE_MAX_ENTRIES = 256;
4505
+ var BROKER_REPLAY_LEDGER_MAX_IDS = 65536;
3914
4506
  var BROKER_MAX_FRAME_BYTES = 4 * 1024 * 1024;
3915
4507
  var BROKER_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
3916
4508
  var BROKER_MAX_QUEUED_REQUESTS = 64;
3917
4509
  var BROKER_MAX_CONCURRENT_REQUESTS = 16;
3918
4510
  var BROKER_DEFAULT_REQUEST_BUDGET_MS = 12e4;
3919
4511
  var BROKER_MAX_REQUEST_BUDGET_MS = 15 * 6e4;
4512
+ var BROKER_MIN_REQUEST_BUDGET_MS = 100;
3920
4513
  var BROKER_IDLE_EXIT_MS = 30 * 6e4;
3921
4514
  var BROKER_DRAIN_MAX_MS = 3e4;
3922
4515
  var ENGINE_COMMANDS = [
@@ -3932,7 +4525,7 @@ var ENGINE_COMMANDS = [
3932
4525
  "navigate_browser",
3933
4526
  "evaluate_browser"
3934
4527
  ];
3935
- var CONTROL_COMMANDS = ["status", "stop", "debug_restart_helper"];
4528
+ var CONTROL_COMMANDS = ["status", "stop", "permissions", "debug_restart_helper"];
3936
4529
  function isEngineCommand(value) {
3937
4530
  return ENGINE_COMMANDS.includes(value);
3938
4531
  }
@@ -4086,6 +4679,12 @@ function validateAction(value, index) {
4086
4679
  return action;
4087
4680
  }
4088
4681
  function validateCommandParams(command, raw) {
4682
+ if (command === "permissions") {
4683
+ assertPlainRecord(raw, "params");
4684
+ assertKeys(raw, "params", ["mode"]);
4685
+ if (raw.mode !== "setup" && raw.mode !== "recheck") throw new BrokerProtocolError("invalid_params", "permissions mode must be setup or recheck");
4686
+ return { mode: raw.mode };
4687
+ }
4089
4688
  if (command === "status" || command === "stop") {
4090
4689
  if (raw === void 0 || raw === null) return {};
4091
4690
  assertPlainRecord(raw, "params");
@@ -4227,7 +4826,7 @@ function validateRequest(value) {
4227
4826
  const params = validateCommandParams(command, value.params);
4228
4827
  const cwd = value.cwd === void 0 ? process.cwd() : boundedString(value.cwd, "cwd", 4096);
4229
4828
  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));
4829
+ 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));
4231
4830
  return {
4232
4831
  requestId: value.requestId,
4233
4832
  ownerId,
@@ -4546,23 +5145,8 @@ import net2 from "node:net";
4546
5145
  import os4 from "node:os";
4547
5146
  import path13 from "node:path";
4548
5147
 
4549
- // vendor/computer-use-axi/src/platform/coerce.ts
4550
- function toBoolean(value) {
4551
- return value === true || value === "true" || value === 1;
4552
- }
4553
- function toFiniteNumber(value, fallback) {
4554
- if (typeof value === "number" && Number.isFinite(value)) return value;
4555
- if (typeof value === "string") {
4556
- const parsed = Number(value);
4557
- if (Number.isFinite(parsed)) return parsed;
4558
- }
4559
- return fallback;
4560
- }
4561
- function toOptionalString(value) {
4562
- return typeof value === "string" && value.length > 0 ? value : void 0;
4563
- }
4564
-
4565
5148
  // vendor/computer-use-axi/src/actions.ts
5149
+ init_coerce();
4566
5150
  function mouseButton(value) {
4567
5151
  return value === "right" || value === "middle" ? value : "left";
4568
5152
  }
@@ -5789,6 +6373,7 @@ function titlesMatch(tabTitle, windowTitle) {
5789
6373
 
5790
6374
  // vendor/computer-use-axi/src/config.ts
5791
6375
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
6376
+ import { AsyncLocalStorage } from "node:async_hooks";
5792
6377
  import path5 from "node:path";
5793
6378
 
5794
6379
  // vendor/computer-use-axi/host.ts
@@ -5803,8 +6388,11 @@ var DEFAULT_CONFIG = {
5803
6388
  cursor_overlay: true,
5804
6389
  managed_browser: "chrome"
5805
6390
  };
5806
- var activeConfig = { ...DEFAULT_CONFIG };
5807
- var activeLoadedConfig = { config: activeConfig, sources: [], env: {} };
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
+ }
5808
6396
  function parseBoolean(value) {
5809
6397
  if (typeof value === "boolean") return value;
5810
6398
  if (typeof value === "number") return value === 1 ? true : value === 0 ? false : void 0;
@@ -5860,18 +6448,19 @@ function loadComputerUseConfig(cwd) {
5860
6448
  if (source.values) Object.assign(config, source.values);
5861
6449
  }
5862
6450
  Object.assign(config, env);
5863
- activeConfig = config;
5864
- activeLoadedConfig = { config, sources, env };
5865
- return activeLoadedConfig;
6451
+ return Object.freeze({ config: Object.freeze(config), sources, env });
5866
6452
  }
5867
6453
  function getComputerUseConfig() {
5868
- return activeConfig;
6454
+ return getLoadedComputerUseConfig().config;
6455
+ }
6456
+ function getLoadedComputerUseConfig() {
6457
+ return operationConfig.getStore() ?? defaultLoaded;
5869
6458
  }
5870
6459
  function isHeadlessMode() {
5871
- return activeConfig.headless;
6460
+ return getComputerUseConfig().headless;
5872
6461
  }
5873
6462
  function isBrowserUseEnabled() {
5874
- return activeConfig.browser_use;
6463
+ return getComputerUseConfig().browser_use;
5875
6464
  }
5876
6465
 
5877
6466
  // vendor/computer-use-axi/src/note.ts
@@ -6106,380 +6695,76 @@ function applyOutputEnvelope(tool, result, owner = COMPUTER_USE_STANDALONE_OWNER
6106
6695
  ${trailer}` }, ...images] };
6107
6696
  }
6108
6697
  function boundToolError(tool, error, owner = COMPUTER_USE_STANDALONE_OWNER) {
6109
- const message = error instanceof Error ? error.message : String(error);
6110
- const bytes = new TextEncoder().encode(message).byteLength;
6111
- const lines = message.split("\n").length;
6112
- if (bytes <= MODEL_TEXT_MAX_BYTES && lines <= MODEL_TEXT_MAX_LINES) return error instanceof Error ? error : new Error(message);
6113
- const entry = storeOutput(message, owner);
6114
- const preview = boundedPrefix(message, MODEL_PREVIEW_BYTES, MODEL_TEXT_MAX_LINES - 4);
6115
- const returnedBytes = new TextEncoder().encode(preview).byteLength;
6116
- const storageNote = entry.complete ? "" : `; only the first ${entry.storedBytes} bytes were stored`;
6117
- return new Error(`${preview}
6118
-
6119
- error truncated: returned ${returnedBytes} of ${entry.totalBytes} utf-8 bytes
6120
- refine: ${refinementFor(tool)}
6121
- continue: computer-use-axi read --ref "${entry.ref}" --offset ${returnedBytes}${storageNote}`);
6122
- }
6123
- function readStoredOutput(ref, offsetValue, owner = COMPUTER_USE_STANDALONE_OWNER) {
6124
- const entry = outputs.get(ref);
6125
- if (!entry || entry.owner !== normalizeComputerUseOwner(owner)) return void 0;
6126
- let offset = Math.min(entry.storedBytes, Math.max(0, Math.trunc(typeof offsetValue === "number" && Number.isFinite(offsetValue) ? offsetValue : 0)));
6127
- const requestedBytes = Math.min(entry.storedBytes - offset, OUTPUT_PAGE_BYTES + 4);
6128
- const buffer = new Uint8Array(Math.max(0, requestedBytes));
6129
- const fd = openSync2(entry.filePath, "r");
6130
- try {
6131
- if (buffer.byteLength > 0) readSync(fd, buffer, 0, buffer.byteLength, offset);
6132
- } finally {
6133
- closeSync2(fd);
6134
- }
6135
- let start = 0;
6136
- while (start < buffer.byteLength && (buffer[start] & 192) === 128) start += 1;
6137
- offset += start;
6138
- const slice = utf8Prefix(buffer.subarray(start), OUTPUT_PAGE_BYTES);
6139
- const actualEnd = offset + slice.byteLength;
6140
- return {
6141
- text: new TextDecoder().decode(slice),
6142
- offset,
6143
- limit: slice.byteLength,
6144
- totalBytes: entry.totalBytes,
6145
- hasMore: actualEnd < entry.storedBytes,
6146
- complete: entry.complete
6147
- };
6148
- }
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);
6166
- try {
6167
- unlinkSync3(entry.filePath);
6168
- } catch {
6169
- }
6170
- }
6171
- }
6172
-
6173
- // vendor/computer-use-axi/src/platform/macos/helper.ts
6174
- import { spawn } from "node:child_process";
6175
- import { constants as fsConstants2 } from "node:fs";
6176
- import { access, mkdir, realpath } from "node:fs/promises";
6177
- import net from "node:net";
6178
- import os2 from "node:os";
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";
6185
- var HELPER_APP_NAME = "pie-computer-use.app";
6186
- var SYSTEM_HELPER_APP_PATH = path7.join("/Applications", HELPER_APP_NAME);
6187
- function resolveMacosHelperAppPath(options = {}) {
6188
- const env = options.env ?? process.env;
6189
- const explicitPath = env.PIE_COMPUTER_USE_HELPER_APP_PATH?.trim();
6190
- if (explicitPath) return path7.resolve(explicitPath);
6191
- const homeDir = options.homeDir ?? os.homedir();
6192
- const configDir = options.configDir ?? resolvePieConfigDir(env, homeDir);
6193
- const systemHelperAppPath = options.systemHelperAppPath ?? SYSTEM_HELPER_APP_PATH;
6194
- const fileExists = options.fileExists ?? existsSync4;
6195
- const directoryIsWritable = options.directoryIsWritable ?? ((directoryPath) => {
6196
- try {
6197
- accessSync(directoryPath, fsConstants.W_OK);
6198
- return true;
6199
- } catch {
6200
- return false;
6201
- }
6202
- });
6203
- if (fileExists(systemHelperAppPath) && directoryIsWritable(path7.dirname(systemHelperAppPath))) {
6204
- return systemHelperAppPath;
6205
- }
6206
- return path7.join(configDir, "computer-use", HELPER_APP_NAME);
6207
- }
6208
- function resolvePieConfigDir(env, homeDir) {
6209
- const envDir = env.PIE_CODING_AGENT_DIR;
6210
- if (envDir) {
6211
- if (envDir === "~") return homeDir;
6212
- if (envDir.startsWith("~/")) return homeDir + envDir.slice(1);
6213
- return envDir;
6214
- }
6215
- return path7.join(homeDir, ".pie");
6216
- }
6217
-
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";
6222
- function resolveExtensionRoot(moduleUrl) {
6223
- const override = process.env.PIE_COMPUTER_USE_PACKAGE_ROOT?.trim();
6224
- if (override) return path8.resolve(override);
6225
- let dir = path8.dirname(fileURLToPath2(moduleUrl));
6226
- for (let depth = 0; depth < 12; depth += 1) {
6227
- if (existsSync5(path8.join(dir, "scripts", "setup-helper.mjs"))) return dir;
6228
- const parent = path8.dirname(dir);
6229
- if (parent === dir) break;
6230
- dir = parent;
6231
- }
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.`);
6233
- }
6234
-
6235
- // vendor/computer-use-axi/src/platform/macos/helper.ts
6236
- var COMMAND_TIMEOUT_MS2 = 15e3;
6237
- var HELPER_PROTOCOL_VERSION = 6;
6238
- var HELPER_SETUP_TIMEOUT_MS = 6e4;
6239
- var HELPER_APP_PATH = resolveMacosHelperAppPath();
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");
6242
- var HELPER_SOCKET_PATH = process.env.PIE_COMPUTER_USE_SOCKET_PATH ?? DEFAULT_HELPER_SOCKET_PATH;
6243
- var usingExternalHelperSocket = HELPER_SOCKET_PATH !== DEFAULT_HELPER_SOCKET_PATH;
6244
- var PACKAGE_ROOT = resolveExtensionRoot(import.meta.url);
6245
- var SETUP_HELPER_SCRIPT = path9.join(PACKAGE_ROOT, "scripts", "setup-helper.mjs");
6246
- var HelperTransportError = class extends Error {
6247
- constructor(message) {
6248
- super(message);
6249
- this.name = "HelperTransportError";
6250
- }
6251
- };
6252
- var HelperCommandError = class extends Error {
6253
- code;
6254
- constructor(message, code) {
6255
- super(message);
6256
- this.name = "HelperCommandError";
6257
- this.code = code;
6258
- }
6259
- };
6260
- function throwIfAborted(signal) {
6261
- if (signal?.aborted) throw new Error("Operation aborted.");
6262
- }
6263
- async function sleep(ms, signal) {
6264
- throwIfAborted(signal);
6265
- await new Promise((resolve2, reject) => {
6266
- const timer = setTimeout(resolve2, ms);
6267
- const onAbort = () => {
6268
- clearTimeout(timer);
6269
- reject(new Error("Operation aborted."));
6270
- };
6271
- signal?.addEventListener("abort", onAbort, { once: true });
6272
- }).finally(() => signal?.throwIfAborted?.());
6273
- }
6274
- async function isExecutable(filePath) {
6275
- try {
6276
- await access(filePath, fsConstants2.X_OK);
6277
- return true;
6278
- } catch {
6279
- return false;
6280
- }
6281
- }
6282
- async function isResolvedHelperExecutable(filePath) {
6283
- if (!filePath) return true;
6284
- const [actualPath, expectedPath] = await Promise.all([
6285
- realpath(filePath).catch(() => path9.resolve(filePath)),
6286
- realpath(HELPER_APP_EXECUTABLE_PATH).catch(() => path9.resolve(HELPER_APP_EXECUTABLE_PATH))
6287
- ]);
6288
- return actualPath === expectedPath;
6289
- }
6290
- async function runProcess(command, args, timeoutMs, signal, env) {
6291
- throwIfAborted(signal);
6292
- await new Promise((resolve2, reject) => {
6293
- const child = spawn(command, args, {
6294
- stdio: ["ignore", "pipe", "pipe"],
6295
- env
6296
- });
6297
- let stderr = "";
6298
- let stdout = "";
6299
- const timer = setTimeout(() => {
6300
- child.kill("SIGTERM");
6301
- cleanup();
6302
- reject(new Error(`Command timed out after ${timeoutMs}ms: ${command} ${args.join(" ")}`));
6303
- }, timeoutMs);
6304
- const onAbort = () => {
6305
- child.kill("SIGTERM");
6306
- cleanup();
6307
- reject(new Error("Operation aborted."));
6308
- };
6309
- const cleanup = () => {
6310
- clearTimeout(timer);
6311
- signal?.removeEventListener("abort", onAbort);
6312
- };
6313
- child.stdout.on("data", (chunk) => {
6314
- stdout += String(chunk);
6315
- });
6316
- child.stderr.on("data", (chunk) => {
6317
- stderr += String(chunk);
6318
- });
6319
- child.on("error", (error) => {
6320
- cleanup();
6321
- reject(error);
6322
- });
6323
- child.on("close", (code) => {
6324
- cleanup();
6325
- if (code === 0) {
6326
- resolve2();
6327
- return;
6328
- }
6329
- const output = [stderr.trim(), stdout.trim()].filter(Boolean).join("\n");
6330
- reject(new Error(`Command failed (${code}): ${command} ${args.join(" ")}
6331
- ${output}`.trim()));
6332
- });
6333
- signal?.addEventListener("abort", onAbort, { once: true });
6334
- });
6335
- }
6336
- var MacosHelperClient = class {
6337
- daemonAvailable = false;
6338
- requestSequence = 0;
6339
- diagnosticsCache;
6340
- get diagnostics() {
6341
- return this.diagnosticsCache;
6342
- }
6343
- async ensureInstalled(signal) {
6344
- if (usingExternalHelperSocket) return;
6345
- if (await isExecutable(HELPER_APP_EXECUTABLE_PATH)) {
6346
- return;
6347
- }
6348
- await runProcess(process.execPath, [SETUP_HELPER_SCRIPT, "--runtime"], HELPER_SETUP_TIMEOUT_MS, signal, {
6349
- ...process.env,
6350
- ELECTRON_RUN_AS_NODE: "1",
6351
- BUN_BE_BUN: "1"
6352
- });
6353
- if (!await isExecutable(HELPER_APP_EXECUTABLE_PATH)) {
6354
- throw new Error(`Failed to install pie-computer-use helper app at ${HELPER_APP_PATH}.`);
6355
- }
6356
- }
6357
- async launchDaemon(signal) {
6358
- if (usingExternalHelperSocket) throw new HelperTransportError(`External helper socket is unavailable at ${HELPER_SOCKET_PATH}.`);
6359
- await mkdir(path9.dirname(HELPER_SOCKET_PATH), { recursive: true });
6360
- await runProcess("open", ["-n", "-g", HELPER_APP_PATH, "--args", "serve", "--socket", HELPER_SOCKET_PATH], COMMAND_TIMEOUT_MS2, signal);
6361
- }
6362
- async daemonCommand(cmd, args, timeoutMs, signal) {
6363
- return await new Promise((resolve2, reject) => {
6364
- const id = `req_${++this.requestSequence}`;
6365
- const socket = net.createConnection(HELPER_SOCKET_PATH);
6366
- let buffer = "";
6367
- const timer = setTimeout(() => {
6368
- socket.destroy();
6369
- reject(new HelperTransportError(`Daemon command '${cmd}' timed out after ${timeoutMs}ms.`));
6370
- }, timeoutMs);
6371
- const cleanup = () => {
6372
- clearTimeout(timer);
6373
- signal?.removeEventListener("abort", onAbort);
6374
- };
6375
- const onAbort = () => {
6376
- socket.destroy();
6377
- cleanup();
6378
- reject(new Error("Operation aborted."));
6379
- };
6380
- signal?.addEventListener("abort", onAbort, { once: true });
6381
- socket.setEncoding("utf8");
6382
- socket.on("connect", () => socket.write(`${JSON.stringify({ id, cmd, ...args })}
6383
- `));
6384
- socket.on("data", (chunk) => {
6385
- buffer += chunk;
6386
- const newline = buffer.indexOf("\n");
6387
- if (newline < 0) return;
6388
- cleanup();
6389
- socket.end();
6390
- try {
6391
- const parsed = JSON.parse(buffer.slice(0, newline));
6392
- if (parsed.ok === true) resolve2(parsed.result);
6393
- else reject(new HelperCommandError(parsed?.error?.message ?? `Daemon command '${cmd}' failed.`, parsed?.error?.code));
6394
- } catch (error) {
6395
- reject(error);
6396
- }
6397
- });
6398
- socket.on("error", (error) => {
6399
- cleanup();
6400
- reject(new HelperTransportError(error.message));
6401
- });
6402
- });
6698
+ const message = error instanceof Error ? error.message : String(error);
6699
+ const bytes = new TextEncoder().encode(message).byteLength;
6700
+ const lines = message.split("\n").length;
6701
+ if (bytes <= MODEL_TEXT_MAX_BYTES && lines <= MODEL_TEXT_MAX_LINES) return error instanceof Error ? error : new Error(message);
6702
+ const entry = storeOutput(message, owner);
6703
+ const preview = boundedPrefix(message, MODEL_PREVIEW_BYTES, MODEL_TEXT_MAX_LINES - 4);
6704
+ const returnedBytes = new TextEncoder().encode(preview).byteLength;
6705
+ const storageNote = entry.complete ? "" : `; only the first ${entry.storedBytes} bytes were stored`;
6706
+ return new Error(`${preview}
6707
+
6708
+ error truncated: returned ${returnedBytes} of ${entry.totalBytes} utf-8 bytes
6709
+ refine: ${refinementFor(tool)}
6710
+ continue: computer-use-axi read --ref "${entry.ref}" --offset ${returnedBytes}${storageNote}`);
6711
+ }
6712
+ function readStoredOutput(ref, offsetValue, owner = COMPUTER_USE_STANDALONE_OWNER) {
6713
+ const entry = outputs.get(ref);
6714
+ if (!entry || entry.owner !== normalizeComputerUseOwner(owner)) return void 0;
6715
+ let offset = Math.min(entry.storedBytes, Math.max(0, Math.trunc(typeof offsetValue === "number" && Number.isFinite(offsetValue) ? offsetValue : 0)));
6716
+ const requestedBytes = Math.min(entry.storedBytes - offset, OUTPUT_PAGE_BYTES + 4);
6717
+ const buffer = new Uint8Array(Math.max(0, requestedBytes));
6718
+ const fd = openSync2(entry.filePath, "r");
6719
+ try {
6720
+ if (buffer.byteLength > 0) readSync(fd, buffer, 0, buffer.byteLength, offset);
6721
+ } finally {
6722
+ closeSync2(fd);
6403
6723
  }
6404
- async ensureDaemon(signal) {
6405
- if (this.daemonAvailable) return true;
6406
- try {
6407
- await this.daemonCommand("diagnostics", {}, 1e3, signal);
6408
- this.daemonAvailable = true;
6409
- return true;
6410
- } catch {
6411
- }
6412
- await this.launchDaemon(signal).catch(() => void 0);
6413
- for (let index = 0; index < 30; index += 1) {
6724
+ let start = 0;
6725
+ while (start < buffer.byteLength && (buffer[start] & 192) === 128) start += 1;
6726
+ offset += start;
6727
+ const slice = utf8Prefix(buffer.subarray(start), OUTPUT_PAGE_BYTES);
6728
+ const actualEnd = offset + slice.byteLength;
6729
+ return {
6730
+ text: new TextDecoder().decode(slice),
6731
+ offset,
6732
+ limit: slice.byteLength,
6733
+ totalBytes: entry.totalBytes,
6734
+ hasMore: actualEnd < entry.storedBytes,
6735
+ complete: entry.complete
6736
+ };
6737
+ }
6738
+ function clearStoredOutputs(owner) {
6739
+ if (owner === void 0) {
6740
+ for (const entry of outputs.values()) {
6414
6741
  try {
6415
- await this.daemonCommand("diagnostics", {}, 1e3, signal);
6416
- this.daemonAvailable = true;
6417
- return true;
6742
+ unlinkSync3(entry.filePath);
6418
6743
  } catch {
6419
- await sleep(100, signal);
6420
6744
  }
6421
6745
  }
6422
- return false;
6746
+ outputs.clear();
6747
+ outputBytes = 0;
6748
+ return;
6423
6749
  }
6424
- async command(cmd, args = {}, options) {
6425
- const timeoutMs = options?.timeoutMs ?? COMMAND_TIMEOUT_MS2;
6426
- if (!await this.ensureDaemon(options?.signal)) {
6427
- throw new HelperTransportError(`pie-computer-use helper app daemon is unavailable at ${HELPER_APP_PATH}.`);
6428
- }
6750
+ const normalized = normalizeComputerUseOwner(owner);
6751
+ for (const [ref, entry] of [...outputs.entries()]) {
6752
+ if (entry.owner !== normalized) continue;
6753
+ outputs.delete(ref);
6754
+ outputBytes = Math.max(0, outputBytes - entry.storedBytes);
6429
6755
  try {
6430
- return await this.daemonCommand(cmd, args, timeoutMs, options?.signal);
6431
- } catch (error) {
6432
- this.daemonAvailable = false;
6433
- throw error instanceof Error ? error : new Error(String(error));
6434
- }
6435
- }
6436
- async restart(signal) {
6437
- await this.command("shutdown", {}, { signal, timeoutMs: 2e3 }).catch(() => void 0);
6438
- this.daemonAvailable = false;
6439
- await sleep(400, signal);
6440
- if (!await this.ensureDaemon(signal)) {
6441
- throw new Error(`pie-computer-use helper did not come back after restart. Helper app: ${HELPER_APP_PATH}`);
6442
- }
6443
- }
6444
- async diagnosticsCommand(signal) {
6445
- const result = await this.command("diagnostics", {}, { signal });
6446
- const diagnostics = {
6447
- protocolVersion: Math.trunc(toFiniteNumber(result?.protocolVersion, 0)),
6448
- architectureVersion: Math.trunc(toFiniteNumber(result?.architectureVersion, 0)),
6449
- invariants: Array.isArray(result?.invariants) ? result.invariants.filter((value) => typeof value === "string") : [],
6450
- pid: Math.trunc(toFiniteNumber(result?.pid, 0)),
6451
- parentPid: Math.trunc(toFiniteNumber(result?.parentPid, 0)) || void 0,
6452
- parentAppName: toOptionalString(result?.parentAppName),
6453
- parentBundleId: toOptionalString(result?.parentBundleId),
6454
- parentPath: toOptionalString(result?.parentPath),
6455
- executablePath: toOptionalString(result?.executablePath),
6456
- os: toOptionalString(result?.macOS),
6457
- arch: toOptionalString(result?.arch),
6458
- accessibility: toBoolean(result?.accessibility),
6459
- screenRecording: toBoolean(result?.screenRecording)
6460
- };
6461
- this.diagnosticsCache = diagnostics;
6462
- return diagnostics;
6463
- }
6464
- async ensureProtocol(signal) {
6465
- let diagnostics = await this.diagnosticsCommand(signal);
6466
- const executableMatches = await isResolvedHelperExecutable(diagnostics.executablePath);
6467
- if (diagnostics.protocolVersion === HELPER_PROTOCOL_VERSION && executableMatches) return diagnostics;
6468
- await this.restart(signal);
6469
- diagnostics = await this.diagnosticsCommand(signal);
6470
- const relaunchedExecutableMatches = await isResolvedHelperExecutable(diagnostics.executablePath);
6471
- if (diagnostics.protocolVersion !== HELPER_PROTOCOL_VERSION || !relaunchedExecutableMatches) {
6472
- this.daemonAvailable = false;
6473
- throw new Error(
6474
- `pie-computer-use helper mismatch after relaunch: expected protocol ${HELPER_PROTOCOL_VERSION} and executable ${HELPER_APP_EXECUTABLE_PATH}; got protocol ${diagnostics.protocolVersion} and executable ${diagnostics.executablePath ?? "unknown"}. Reinstall or rebuild the helper app at ${HELPER_APP_PATH}.`
6475
- );
6756
+ unlinkSync3(entry.filePath);
6757
+ } catch {
6476
6758
  }
6477
- return diagnostics;
6478
6759
  }
6479
- };
6480
- var macosHelper = new MacosHelperClient();
6760
+ }
6761
+
6762
+ // vendor/computer-use-axi/src/bridge.ts
6763
+ init_coerce();
6481
6764
 
6482
6765
  // vendor/computer-use-axi/src/platform/macos/backend.ts
6766
+ init_coerce();
6767
+ init_helper();
6483
6768
  function parseApps(result) {
6484
6769
  const array = Array.isArray(result) ? result : result?.apps;
6485
6770
  if (!Array.isArray(array)) return [];
@@ -6591,6 +6876,7 @@ var macosBackend = {
6591
6876
  };
6592
6877
 
6593
6878
  // vendor/computer-use-axi/src/platform/macos/browser.ts
6879
+ init_helper();
6594
6880
  var BROWSER_WINDOW_OPEN_TIMEOUT_MS = 1e4;
6595
6881
  var BROWSER_BUNDLE_IDS = /* @__PURE__ */ new Set([
6596
6882
  "com.apple.Safari",
@@ -6688,191 +6974,15 @@ async function openBrowserLocationWithAppleScript(target, url, signal) {
6688
6974
  }
6689
6975
  }
6690
6976
 
6691
- // vendor/computer-use-axi/src/permissions.ts
6692
- function throwIfAborted2(signal) {
6693
- if (signal?.aborted) throw new Error("Operation aborted.");
6694
- }
6695
- function granted(status, kind) {
6696
- return status[kind] === true;
6697
- }
6698
- function allGranted(status, kinds) {
6699
- return kinds.every(({ kind }) => granted(status, kind));
6700
- }
6701
- function missingKinds(status, kinds) {
6702
- return kinds.flatMap(({ kind }) => granted(status, kind) ? [] : [kind]);
6703
- }
6704
- function permissionStatusSuggestsHelperRestart(status) {
6705
- return status.screenRecordingPreflight === true && status.screenRecording === false;
6706
- }
6707
- async function ensurePermissions(ctx, bridge, helperPath, signal) {
6708
- let status = await bridge.checkPermissions(signal);
6709
- if (allGranted(status, bridge.kinds)) return status;
6710
- if (!ctx.hasUI) throw new Error(bridge.copy.nonInteractiveError(helperPath));
6711
- await bridge.registerPermissions(signal).catch(() => void 0);
6712
- while (!allGranted(status, bridge.kinds)) {
6713
- throwIfAborted2(signal);
6714
- const missing = missingKinds(status, bridge.kinds);
6715
- const options = bridge.kinds.filter(({ kind }) => missing.includes(kind)).map(({ openOption }) => openOption);
6716
- options.push("Recheck (restarts helper)", "Cancel");
6717
- const choice = await ctx.ui.select(bridge.copy.prompt(status, helperPath, bridge.permissionHint), options, { signal });
6718
- if (!choice || choice === "Cancel") throw new Error(bridge.copy.incompleteError(helperPath));
6719
- const selected = bridge.kinds.find(({ openOption }) => choice === openOption);
6720
- if (selected) await bridge.openPermissionPane(selected.kind, signal);
6721
- if (choice.startsWith("Recheck")) {
6722
- await bridge.restartHelper(signal);
6723
- status = await bridge.checkPermissions(signal);
6724
- if (allGranted(status, bridge.kinds)) {
6725
- ctx.ui.notify(bridge.copy.readyMessage, "info");
6726
- } else {
6727
- ctx.ui.notify(bridge.copy.stillMissing(missingKinds(status, bridge.kinds)), "warning");
6728
- }
6729
- }
6730
- }
6731
- return status;
6732
- }
6733
-
6734
- // vendor/computer-use-axi/src/platform/architecture.ts
6735
- var PLATFORM_ARCHITECTURE_VERSION = 1;
6736
- var REQUIRED_PLATFORM_INVARIANTS = [
6737
- "state-scoped-observations",
6738
- "bounded-observation-history",
6739
- "multi-root-forest",
6740
- "progressive-disclosure",
6741
- "atomic-physical-input",
6742
- "concurrent-requests",
6743
- "transactional-batching"
6744
- ];
6745
- function assertPlatformArchitecture(platform, diagnostics) {
6746
- if (diagnostics.architectureVersion !== PLATFORM_ARCHITECTURE_VERSION) {
6747
- throw new Error(`${platform} helper architecture mismatch: expected ${PLATFORM_ARCHITECTURE_VERSION}, got ${diagnostics.architectureVersion ?? "unknown"}. Rebuild and restart the helper.`);
6748
- }
6749
- const reported = new Set(diagnostics.invariants ?? []);
6750
- const missing = REQUIRED_PLATFORM_INVARIANTS.filter((invariant) => !reported.has(invariant));
6751
- if (missing.length > 0) {
6752
- throw new Error(`${platform} helper does not satisfy the shared computer-use contract: ${missing.join(", ")}.`);
6753
- }
6754
- }
6977
+ // vendor/computer-use-axi/src/platform/index.ts
6978
+ init_permissions2();
6755
6979
 
6756
- // vendor/computer-use-axi/src/platform/macos/permissions.ts
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.";
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.";
6759
- var macosPermissionKinds = [
6760
- { kind: "accessibility", openOption: "Open Accessibility Settings (missing)" },
6761
- { kind: "screenRecording", openOption: "Open Screen Recording Settings (missing)" }
6762
- ];
6763
- function permissionStatusSummary(status) {
6764
- const lines = [
6765
- `Accessibility: ${status.accessibility ? "granted" : "missing"}`,
6766
- `Screen Recording: ${status.screenRecording ? "granted" : "missing"}`
6767
- ];
6768
- if (status.screenRecordingPreflight && !status.screenRecording) {
6769
- lines.push(
6770
- "(Screen Recording reads granted in the TCC database but a live capture probe failed \u2014 the grant likely belongs to a different app identity, or the helper needs a restart.)"
6771
- );
6772
- }
6773
- return lines.join("; ");
6774
- }
6775
- function permissionPrompt(status, helperPath, hint) {
6776
- return [
6777
- "pie-computer-use needs macOS permissions for its helper app.",
6778
- permissionStatusSummary(status),
6779
- "",
6780
- `Helper: pie-computer-use.app (${helperPath})`,
6781
- hint,
6782
- "",
6783
- `Important: ${SIGNING_MIGRATION_WARNING}`,
6784
- "",
6785
- "pie-computer-use.app is already listed in the pane(s) \u2014 enable its toggle, then choose Recheck."
6786
- ].filter(Boolean).join("\n");
6787
- }
6788
- function missingPermissionMessage(kinds) {
6789
- return `Still missing after restart: ${kinds.join(" and ")}. ${SIGNING_MIGRATION_WARNING} Then choose Recheck again.`;
6790
- }
6791
- async function checkPermissions(signal) {
6792
- const result = await macosHelper.command("checkPermissions", {}, { signal });
6793
- const rawSource = result?.source;
6794
- return {
6795
- accessibility: toBoolean(result?.accessibility),
6796
- // Authoritative: the helper's live ScreenCaptureKit probe.
6797
- screenRecording: toBoolean(result?.screenRecordingCapturable),
6798
- // Keep the preflight value separate: disagreement means stale per-process
6799
- // TCC cache or a grant row belonging to another app identity.
6800
- screenRecordingPreflight: toBoolean(result?.screenRecordingPreflight),
6801
- source: rawSource && typeof rawSource === "object" ? {
6802
- // macOS attributes Accessibility / Screen Recording grants to the
6803
- // responsible process at the top of the launch chain. "helper-app"
6804
- // is the canonical installed app via LaunchServices; "caller" means
6805
- // grants would attach to the launching app instead.
6806
- attribution: rawSource.attribution === "helper-app" ? "helper-app" : "caller",
6807
- pid: Math.trunc(toFiniteNumber(rawSource.pid, 0)) || void 0,
6808
- parentPid: Math.trunc(toFiniteNumber(rawSource.parentPid, 0)) || void 0,
6809
- executablePath: toOptionalString(rawSource.executablePath),
6810
- parentPath: toOptionalString(rawSource.parentPath),
6811
- parentBundleId: toOptionalString(rawSource.parentBundleId),
6812
- os: toOptionalString(rawSource.macOS)
6813
- } : void 0
6814
- };
6815
- }
6816
- var registeredForHelperPid;
6817
- async function registerPermissions(signal) {
6818
- const helperPid = macosHelper.diagnostics?.pid;
6819
- if (helperPid !== void 0 && helperPid === registeredForHelperPid) return;
6820
- await macosHelper.command("registerPermissions", {}, { signal, timeoutMs: 15e3 });
6821
- registeredForHelperPid = helperPid;
6822
- }
6823
- var autoRestartAttempted = false;
6824
- async function ensureMacosReady(ctx, state, signal) {
6825
- await macosHelper.ensureInstalled(signal);
6826
- if (!await macosHelper.ensureDaemon(signal)) {
6827
- throw new Error(`pie-computer-use helper app daemon did not start. Helper app: ${HELPER_APP_PATH}`);
6828
- }
6829
- const helperDiagnostics = await macosHelper.ensureProtocol(signal);
6830
- assertPlatformArchitecture("macOS", helperDiagnostics);
6831
- const now = Date.now();
6832
- const cachedStatus = state.permissionStatus;
6833
- const canUseCachedPermissions = cachedStatus?.accessibility && cachedStatus.screenRecording && now - state.lastPermissionCheckAt < 2e3;
6834
- if (canUseCachedPermissions) {
6835
- return { ...state, helperDiagnostics };
6836
- }
6837
- let permissionStatus = await checkPermissions(signal);
6838
- let lastPermissionCheckAt = now;
6839
- if (!autoRestartAttempted && permissionStatusSuggestsHelperRestart(permissionStatus)) {
6840
- autoRestartAttempted = true;
6841
- await macosHelper.restart(signal).catch(() => void 0);
6842
- permissionStatus = await checkPermissions(signal);
6843
- lastPermissionCheckAt = Date.now();
6844
- }
6845
- if (!permissionStatus.accessibility || !permissionStatus.screenRecording) {
6846
- const attributionHint = permissionStatus.source?.attribution === "caller" ? `Warning: the helper is not running as the installed pie-computer-use.app (executable: ${permissionStatus.source?.executablePath ?? "unknown"}). Grants made now would attach to the launching app instead. Restart Pie so the canonical helper is used.` : void 0;
6847
- permissionStatus = await ensurePermissions(
6848
- ctx,
6849
- {
6850
- kinds: macosPermissionKinds,
6851
- copy: {
6852
- nonInteractiveError: (helperPath) => `computer-use setup requires an interactive session. Run Pie in interactive mode. ${GRANT_INSTRUCTIONS}
6853
- Helper path: ${helperPath}`,
6854
- prompt: permissionPrompt,
6855
- incompleteError: (helperPath) => `pie-computer-use setup is incomplete. ${GRANT_INSTRUCTIONS} Helper path: ${helperPath}`,
6856
- readyMessage: "pie-computer-use is ready.",
6857
- stillMissing: missingPermissionMessage
6858
- },
6859
- checkPermissions: (permissionSignal) => checkPermissions(permissionSignal ?? signal),
6860
- registerPermissions: (permissionSignal) => registerPermissions(permissionSignal ?? signal),
6861
- openPermissionPane: async (kind, permissionSignal) => {
6862
- await macosHelper.command("openPermissionPane", { kind }, { signal: permissionSignal ?? signal });
6863
- },
6864
- restartHelper: (permissionSignal) => macosHelper.restart(permissionSignal ?? signal),
6865
- permissionHint: attributionHint
6866
- },
6867
- HELPER_APP_PATH,
6868
- signal
6869
- );
6870
- lastPermissionCheckAt = Date.now();
6871
- }
6872
- return { permissionStatus, lastPermissionCheckAt, helperDiagnostics };
6873
- }
6980
+ // vendor/computer-use-axi/src/platform/linux/backend.ts
6981
+ init_architecture();
6982
+ init_coerce();
6874
6983
 
6875
6984
  // vendor/computer-use-axi/src/platform/linux/helper.ts
6985
+ init_package_root();
6876
6986
  import { spawn as spawn2 } from "node:child_process";
6877
6987
  import { randomUUID as randomUUID4 } from "node:crypto";
6878
6988
  import { constants as fsConstants3 } from "node:fs";
@@ -7272,7 +7382,11 @@ var linuxBackend = {
7272
7382
  }
7273
7383
  };
7274
7384
 
7385
+ // vendor/computer-use-axi/src/platform/windows/backend.ts
7386
+ init_coerce();
7387
+
7275
7388
  // vendor/computer-use-axi/src/platform/windows/helper.ts
7389
+ init_package_root();
7276
7390
  import { spawn as spawn3 } from "node:child_process";
7277
7391
  import { randomUUID as randomUUID5 } from "node:crypto";
7278
7392
  import { constants as fsConstants4 } from "node:fs";
@@ -7430,6 +7544,7 @@ var WindowsHelperClient = class {
7430
7544
  var windowsHelper = new WindowsHelperClient();
7431
7545
 
7432
7546
  // vendor/computer-use-axi/src/platform/windows/backend.ts
7547
+ init_architecture();
7433
7548
  function normalizedProcessName2(appName) {
7434
7549
  return appName.toLowerCase().replace(/\.exe$/i, "");
7435
7550
  }
@@ -7970,10 +8085,10 @@ function shouldPreferForegroundModalWindow(current, candidate) {
7970
8085
  }
7971
8086
 
7972
8087
  // vendor/computer-use-axi/src/state.ts
7973
- import { AsyncLocalStorage } from "node:async_hooks";
8088
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
7974
8089
  var SavedStates = class {
7975
8090
  store;
7976
- operations = new AsyncLocalStorage();
8091
+ operations = new AsyncLocalStorage2();
7977
8092
  constructor(store = new StateStore(128)) {
7978
8093
  this.store = store;
7979
8094
  }
@@ -8241,6 +8356,8 @@ function bumpHelperGeneration() {
8241
8356
  return helperGeneration;
8242
8357
  }
8243
8358
  function expireStatesAfterHelperRestart(reason = "the native helper restarted") {
8359
+ runtimeState.permissionStatus = void 0;
8360
+ runtimeState.lastPermissionCheckAt = 0;
8244
8361
  const ids = savedStates.store.ids?.() ?? [];
8245
8362
  for (const id of ids) expiredStateReasons.set(id, reason);
8246
8363
  savedStates.clear();
@@ -8460,7 +8577,6 @@ function emptyActivation() {
8460
8577
  return { activated: false, unminimized: false, raised: false };
8461
8578
  }
8462
8579
  async function ensureReady3(ctx, signal) {
8463
- loadComputerUseConfig(ctx.cwd);
8464
8580
  throwIfAborted3(signal);
8465
8581
  const ready = await currentPlatformBackend.ensureReady(
8466
8582
  ctx,
@@ -10079,12 +10195,11 @@ async function executeTool(tool, ctx, params, signal, run, runtime) {
10079
10195
  operation.signal = signal ?? runtime?.signal;
10080
10196
  operation.onDispatch = runtime?.onDispatch;
10081
10197
  if (requestedStateId && stateRecord) assertStateAccess(requestedStateId, stateRecord, operation);
10082
- return await savedStates.operations.run(operation, async () => {
10198
+ return await withComputerUseConfig(ctx.cwd, () => savedStates.operations.run(operation, async () => {
10083
10199
  try {
10084
10200
  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
10201
  await resourceScheduler.read("session-lifecycle", async () => {
10086
10202
  if (browserOnly || outputRef) {
10087
- loadComputerUseConfig(ctx.cwd);
10088
10203
  if (browserOnly && !outputRef && tool !== "find_roots" && !isBrowserUseEnabled()) {
10089
10204
  throw new Error("Browser use is disabled by computer-use config. Enable browser_use to control browser pages.");
10090
10205
  }
@@ -10097,7 +10212,7 @@ async function executeTool(tool, ctx, params, signal, run, runtime) {
10097
10212
  } finally {
10098
10213
  for (const artifactId of operation.artifactIds ?? []) engineArtifacts?.unpin(artifactId);
10099
10214
  }
10100
- });
10215
+ }));
10101
10216
  }
10102
10217
  var BROKER_PERFORMERS = {
10103
10218
  find_roots: performListWindows,
@@ -10272,6 +10387,9 @@ async function startBroker(options = {}) {
10272
10387
  });
10273
10388
  saveBrokerManifest({ generation, helperGeneration: helperGeneration2, stateIds: [], updatedAt: Date.now() });
10274
10389
  const entries = /* @__PURE__ */ new Map();
10390
+ const acceptedIds = /* @__PURE__ */ new Set();
10391
+ const resultCacheLimit = options.resultCacheLimit ?? BROKER_RESULT_CACHE_MAX_ENTRIES;
10392
+ const replayLedgerLimit = options.replayLedgerLimit ?? BROKER_REPLAY_LEDGER_MAX_IDS;
10275
10393
  const owners = /* @__PURE__ */ new Set();
10276
10394
  const knownStateIds = /* @__PURE__ */ new Set();
10277
10395
  let active = 0;
@@ -10279,6 +10397,7 @@ async function startBroker(options = {}) {
10279
10397
  let lastActivity = Date.now();
10280
10398
  let drainRequested = false;
10281
10399
  let stopping = false;
10400
+ let permissionSetupInFlight = false;
10282
10401
  let idleTimer;
10283
10402
  let statusHandle;
10284
10403
  const persistManifest = () => {
@@ -10401,8 +10520,12 @@ async function startBroker(options = {}) {
10401
10520
  }
10402
10521
  };
10403
10522
  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 } });
10523
+ if (stopping || drainRequested || permissionSetupInFlight) {
10524
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "broker_draining", message: "The broker is draining or performing permission setup; this request was not accepted. Retry after it finishes.", dispatched: false } });
10525
+ return;
10526
+ }
10527
+ if (request.generation && request.generation !== generation) {
10528
+ send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "generation_mismatch", message: "Request belongs to another broker generation. Observe again; do not replay old actions." } });
10406
10529
  return;
10407
10530
  }
10408
10531
  const key = request.requestId;
@@ -10419,18 +10542,23 @@ async function startBroker(options = {}) {
10419
10542
  else respond({ ...existing, socket }, "error", void 0, existing.error);
10420
10543
  return;
10421
10544
  }
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.` } });
10545
+ if (acceptedIds.has(key) || acceptedIds.size >= replayLedgerLimit) {
10546
+ send(socket, { type: "response", requestId: key, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: acceptedIds.has(key) ? "request_id_expired" : "request_ledger_full", message: acceptedIds.has(key) ? "Result expired; this requestId cannot be replayed. Observe again." : "Replay ledger is full. Stop the broker safely, then observe in a new generation. Do not replay prior actions.", dispatched: false } });
10424
10547
  return;
10425
10548
  }
10426
- if (entries.size >= 256) {
10549
+ if (entries.size >= resultCacheLimit) {
10427
10550
  for (const [id, candidate] of entries) {
10428
- if (candidate.state === "done" || candidate.state === "error" || candidate.state === "unknown") {
10551
+ if (candidate.state === "done" || candidate.state === "error") {
10429
10552
  entries.delete(id);
10430
10553
  break;
10431
10554
  }
10432
10555
  }
10433
10556
  }
10557
+ if (entries.size >= resultCacheLimit) {
10558
+ send(socket, { type: "response", requestId: key, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "broker_busy", message: "Request retention is full of unconfirmed work; no action dispatched.", dispatched: false } });
10559
+ return;
10560
+ }
10561
+ acceptedIds.add(key);
10434
10562
  const entry = {
10435
10563
  requestId: request.requestId,
10436
10564
  ownerId: request.ownerId,
@@ -10485,6 +10613,31 @@ async function startBroker(options = {}) {
10485
10613
  send(socket, { type: "response", requestId: request.requestId, ok: true, state: "done", generation, helperGeneration: currentHelperGenerationSafe(), result: statusHandle?.status() });
10486
10614
  return;
10487
10615
  }
10616
+ if (request.command === "permissions") {
10617
+ const reply = (result, error) => send(socket, { type: "response", requestId: request.requestId, ok: !error, state: error ? "error" : "done", generation, helperGeneration: currentHelperGenerationSafe(), result, error });
10618
+ if (permissionSetupInFlight || [...entries.values()].some((entry) => ["running", "queued", "unknown"].includes(entry.state))) {
10619
+ reply(void 0, { code: "broker_busy", message: "Permission setup requires an idle broker with no unconfirmed actions. Wait for work to settle first.", dispatched: false });
10620
+ return;
10621
+ }
10622
+ permissionSetupInFlight = true;
10623
+ try {
10624
+ if (process.platform !== "darwin" || options.testCommands) throw new Error("macOS permission setup requires a real macOS desktop backend.");
10625
+ const mode = request.params.mode;
10626
+ if (mode === "recheck") {
10627
+ liveHelperGeneration = bumpHelperGeneration();
10628
+ expireStatesAfterHelperRestart();
10629
+ }
10630
+ const { setupMacosPermissions: setupMacosPermissions2 } = await Promise.resolve().then(() => (init_permissions2(), permissions_exports));
10631
+ const status = await setupMacosPermissions2(mode);
10632
+ const ready = status.accessibility && status.screenRecording;
10633
+ reply({ details: status, isError: !ready, content: [{ type: "text", text: ready ? "Permissions granted. Observe a fresh root before acting." : "Grant Accessibility and Screen Recording to pie-computer-use.app in the opened Settings panes, then run 'computer-use-axi permissions recheck'." }] });
10634
+ } catch (error) {
10635
+ reply(void 0, { code: "permission_setup_failed", message: error instanceof Error ? error.message : String(error) });
10636
+ } finally {
10637
+ permissionSetupInFlight = false;
10638
+ }
10639
+ return;
10640
+ }
10488
10641
  if (request.command === "debug_restart_helper") {
10489
10642
  if (!options.testCommands) {
10490
10643
  send(socket, { type: "response", requestId: request.requestId, ok: false, state: "error", generation, helperGeneration: currentHelperGenerationSafe(), error: { code: "unknown_command", message: "Test commands are disabled." } });
@@ -10620,7 +10773,7 @@ async function startBroker(options = {}) {
10620
10773
  });
10621
10774
  continue;
10622
10775
  }
10623
- void (request.command === "status" || request.command === "stop" || request.command === "debug_restart_helper" ? handleControl(request, socket) : handleEngineRequest(request, socket));
10776
+ void (request.command === "status" || request.command === "stop" || request.command === "permissions" || request.command === "debug_restart_helper" ? handleControl(request, socket) : handleEngineRequest(request, socket));
10624
10777
  }
10625
10778
  });
10626
10779
  socket.on("close", () => {
@@ -10696,7 +10849,7 @@ async function startBroker(options = {}) {
10696
10849
  }
10697
10850
  }
10698
10851
  const deadline = Date.now() + BROKER_DRAIN_MAX_MS;
10699
- while ([...entries.values()].some((entry) => entry.state === "running" || entry.state === "unknown") && Date.now() < deadline) {
10852
+ while ((permissionSetupInFlight || [...entries.values()].some((entry) => entry.state === "running" || entry.state === "unknown")) && Date.now() < deadline) {
10700
10853
  await sleep3(50);
10701
10854
  }
10702
10855
  persistManifest();
@@ -10773,7 +10926,7 @@ async function startBroker(options = {}) {
10773
10926
  idleTimer = setInterval(() => {
10774
10927
  if (stopping) return;
10775
10928
  const uncertain = [...entries.values()].some((entry) => entry.state === "running" || entry.state === "unknown" || entry.state === "queued");
10776
- if (uncertain) return;
10929
+ if (uncertain || permissionSetupInFlight) return;
10777
10930
  if (Date.now() - lastActivity < idleExitMs) return;
10778
10931
  void shutdown("idle");
10779
10932
  }, Math.min(6e4, Math.max(1e3, Math.floor(idleExitMs / 4))));
@@ -10815,8 +10968,13 @@ async function loadTestOnlyBackend() {
10815
10968
  }
10816
10969
  async function main() {
10817
10970
  const fake = await loadTestOnlyBackend();
10971
+ const testCommands = process.env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS === "1";
10818
10972
  const handle = await startBroker({
10819
- testCommands: process.env.PIE_COMPUTER_USE_ENABLE_TEST_COMMANDS === "1",
10973
+ testCommands,
10974
+ // Fail-closed capacity contract hooks (tests only; both require the
10975
+ // explicit test-command switch and are ignored in every other build).
10976
+ 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,
10977
+ replayLedgerLimit: testCommands && Number.isFinite(Number(process.env.PIE_COMPUTER_USE_TEST_REPLAY_LEDGER_LIMIT)) ? Math.trunc(Number(process.env.PIE_COMPUTER_USE_TEST_REPLAY_LEDGER_LIMIT)) : void 0,
10820
10978
  restartTestHelper: fake ? () => fake.fakeControl.restart() : void 0,
10821
10979
  onShutdown: () => {
10822
10980
  setTimeout(() => process.exit(0), 50).unref();