local-commander-agent-linux-arm64 0.3.45 → 0.3.47

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.
package/runtime/agent.mjs CHANGED
@@ -2138,7 +2138,7 @@ var require_extension = __commonJS({
2138
2138
  if (dest[name2] === void 0) dest[name2] = [elem];
2139
2139
  else dest[name2].push(elem);
2140
2140
  }
2141
- function parse3(header) {
2141
+ function parse4(header) {
2142
2142
  const offers = /* @__PURE__ */ Object.create(null);
2143
2143
  let params = /* @__PURE__ */ Object.create(null);
2144
2144
  let mustUnescape = false;
@@ -2278,7 +2278,7 @@ var require_extension = __commonJS({
2278
2278
  }).join(", ");
2279
2279
  }).join(", ");
2280
2280
  }
2281
- module.exports = { format, parse: parse3 };
2281
+ module.exports = { format, parse: parse4 };
2282
2282
  }
2283
2283
  });
2284
2284
 
@@ -2289,9 +2289,9 @@ var require_websocket = __commonJS({
2289
2289
  var EventEmitter = __require("events");
2290
2290
  var https2 = __require("https");
2291
2291
  var http2 = __require("http");
2292
- var net2 = __require("net");
2292
+ var net3 = __require("net");
2293
2293
  var tls2 = __require("tls");
2294
- var { randomBytes: randomBytes10, createHash: createHash21 } = __require("crypto");
2294
+ var { randomBytes: randomBytes11, createHash: createHash21 } = __require("crypto");
2295
2295
  var { Duplex, Readable } = __require("stream");
2296
2296
  var { URL: URL2 } = __require("url");
2297
2297
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -2312,7 +2312,7 @@ var require_websocket = __commonJS({
2312
2312
  var {
2313
2313
  EventTarget: { addEventListener, removeEventListener }
2314
2314
  } = require_event_target();
2315
- var { format, parse: parse3 } = require_extension();
2315
+ var { format, parse: parse4 } = require_extension();
2316
2316
  var { toBuffer } = require_buffer_util();
2317
2317
  var kAborted = /* @__PURE__ */ Symbol("kAborted");
2318
2318
  var protocolVersions = [8, 13];
@@ -2842,7 +2842,7 @@ var require_websocket = __commonJS({
2842
2842
  }
2843
2843
  }
2844
2844
  const defaultPort = isSecure ? 443 : 80;
2845
- const key = randomBytes10(16).toString("base64");
2845
+ const key = randomBytes11(16).toString("base64");
2846
2846
  const request = isSecure ? https2.request : http2.request;
2847
2847
  const protocolSet = /* @__PURE__ */ new Set();
2848
2848
  let perMessageDeflate;
@@ -3002,7 +3002,7 @@ var require_websocket = __commonJS({
3002
3002
  }
3003
3003
  let extensions;
3004
3004
  try {
3005
- extensions = parse3(secWebSocketExtensions);
3005
+ extensions = parse4(secWebSocketExtensions);
3006
3006
  } catch (err) {
3007
3007
  const message2 = "Invalid Sec-WebSocket-Extensions header";
3008
3008
  abortHandshake(websocket, socket, message2);
@@ -3046,12 +3046,12 @@ var require_websocket = __commonJS({
3046
3046
  }
3047
3047
  function netConnect2(options) {
3048
3048
  options.path = options.socketPath;
3049
- return net2.connect(options);
3049
+ return net3.connect(options);
3050
3050
  }
3051
3051
  function tlsConnect(options) {
3052
3052
  options.path = void 0;
3053
3053
  if (!options.servername && options.servername !== "") {
3054
- options.servername = net2.isIP(options.host) ? "" : options.host;
3054
+ options.servername = net3.isIP(options.host) ? "" : options.host;
3055
3055
  }
3056
3056
  return tls2.connect(options);
3057
3057
  }
@@ -3294,7 +3294,7 @@ var require_subprotocol = __commonJS({
3294
3294
  "node_modules/ws/lib/subprotocol.js"(exports, module) {
3295
3295
  "use strict";
3296
3296
  var { tokenChars } = require_validation();
3297
- function parse3(header) {
3297
+ function parse4(header) {
3298
3298
  const protocols = /* @__PURE__ */ new Set();
3299
3299
  let start = -1;
3300
3300
  let end = -1;
@@ -3330,7 +3330,7 @@ var require_subprotocol = __commonJS({
3330
3330
  protocols.add(protocol2);
3331
3331
  return protocols;
3332
3332
  }
3333
- module.exports = { parse: parse3 };
3333
+ module.exports = { parse: parse4 };
3334
3334
  }
3335
3335
  });
3336
3336
 
@@ -4554,10 +4554,10 @@ function mergeDefs(...defs) {
4554
4554
  function cloneDef(schema) {
4555
4555
  return mergeDefs(schema._zod.def);
4556
4556
  }
4557
- function getElementAtPath(obj, path29) {
4558
- if (!path29)
4557
+ function getElementAtPath(obj, path30) {
4558
+ if (!path30)
4559
4559
  return obj;
4560
- return path29.reduce((acc, key) => acc?.[key], obj);
4560
+ return path30.reduce((acc, key) => acc?.[key], obj);
4561
4561
  }
4562
4562
  function promiseAllObject(promisesObj) {
4563
4563
  const keys = Object.keys(promisesObj);
@@ -4897,11 +4897,11 @@ function explicitlyAborted(x, startIndex = 0) {
4897
4897
  }
4898
4898
  return false;
4899
4899
  }
4900
- function prefixIssues(path29, issues) {
4900
+ function prefixIssues(path30, issues) {
4901
4901
  return issues.map((iss) => {
4902
4902
  var _a3;
4903
4903
  (_a3 = iss).path ?? (_a3.path = []);
4904
- iss.path.unshift(path29);
4904
+ iss.path.unshift(path30);
4905
4905
  return iss;
4906
4906
  });
4907
4907
  }
@@ -5351,16 +5351,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
5351
5351
  }
5352
5352
  function formatError(error62, mapper = (issue2) => issue2.message) {
5353
5353
  const fieldErrors = { _errors: [] };
5354
- const processError = (error63, path29 = []) => {
5354
+ const processError = (error63, path30 = []) => {
5355
5355
  for (const issue2 of error63.issues) {
5356
5356
  if (issue2.code === "invalid_union" && issue2.errors.length) {
5357
- issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
5357
+ issue2.errors.map((issues) => processError({ issues }, [...path30, ...issue2.path]));
5358
5358
  } else if (issue2.code === "invalid_key") {
5359
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5359
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5360
5360
  } else if (issue2.code === "invalid_element") {
5361
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5361
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5362
5362
  } else {
5363
- const fullpath = [...path29, ...issue2.path];
5363
+ const fullpath = [...path30, ...issue2.path];
5364
5364
  if (fullpath.length === 0) {
5365
5365
  fieldErrors._errors.push(mapper(issue2));
5366
5366
  } else {
@@ -5399,17 +5399,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
5399
5399
  }
5400
5400
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
5401
5401
  const result2 = { errors: [] };
5402
- const processError = (error63, path29 = []) => {
5402
+ const processError = (error63, path30 = []) => {
5403
5403
  var _a3;
5404
5404
  for (const issue2 of error63.issues) {
5405
5405
  if (issue2.code === "invalid_union" && issue2.errors.length) {
5406
- issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
5406
+ issue2.errors.map((issues) => processError({ issues }, [...path30, ...issue2.path]));
5407
5407
  } else if (issue2.code === "invalid_key") {
5408
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5408
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5409
5409
  } else if (issue2.code === "invalid_element") {
5410
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5410
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5411
5411
  } else {
5412
- const fullpath = [...path29, ...issue2.path];
5412
+ const fullpath = [...path30, ...issue2.path];
5413
5413
  if (fullpath.length === 0) {
5414
5414
  result2.errors.push(mapper(issue2));
5415
5415
  continue;
@@ -5448,8 +5448,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
5448
5448
  }
5449
5449
  function toDotPath(_path) {
5450
5450
  const segs = [];
5451
- const path29 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
5452
- for (const seg of path29) {
5451
+ const path30 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
5452
+ for (const seg of path30) {
5453
5453
  if (typeof seg === "number")
5454
5454
  segs.push(`[${seg}]`);
5455
5455
  else if (typeof seg === "symbol")
@@ -5583,18 +5583,18 @@ var validateAsync = async (schema, value, _ctx) => {
5583
5583
  return result2.issues.length === 0;
5584
5584
  };
5585
5585
  var _encode = (_Err) => {
5586
- const parse3 = _parse(_Err);
5586
+ const parse4 = _parse(_Err);
5587
5587
  const fn = (schema, value, _ctx, _params) => {
5588
5588
  const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
5589
- return parse3(schema, value, ctx, finalizeParams(fn, _params));
5589
+ return parse4(schema, value, ctx, finalizeParams(fn, _params));
5590
5590
  };
5591
5591
  return fn;
5592
5592
  };
5593
5593
  var encode = /* @__PURE__ */ _encode($ZodRealError);
5594
5594
  var _decode = (_Err) => {
5595
- const parse3 = _parse(_Err);
5595
+ const parse4 = _parse(_Err);
5596
5596
  const fn = (schema, value, _ctx, _params) => {
5597
- return parse3(schema, value, _ctx, finalizeParams(fn, _params));
5597
+ return parse4(schema, value, _ctx, finalizeParams(fn, _params));
5598
5598
  };
5599
5599
  return fn;
5600
5600
  };
@@ -22551,13 +22551,13 @@ function resolveRef(ref, ctx) {
22551
22551
  if (!ref.startsWith("#")) {
22552
22552
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
22553
22553
  }
22554
- const path29 = ref.slice(1).split("/").filter(Boolean);
22555
- if (path29.length === 0) {
22554
+ const path30 = ref.slice(1).split("/").filter(Boolean);
22555
+ if (path30.length === 0) {
22556
22556
  return ctx.rootSchema;
22557
22557
  }
22558
22558
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
22559
- if (path29[0] === defsKey) {
22560
- const key = path29[1] === void 0 ? void 0 : decodeJSONPointerSegment(path29[1]);
22559
+ if (path30[0] === defsKey) {
22560
+ const key = path30[1] === void 0 ? void 0 : decodeJSONPointerSegment(path30[1]);
22561
22561
  if (!key || !ctx.defs[key]) {
22562
22562
  throw new Error(`Reference not found: ${ref}`);
22563
22563
  }
@@ -23192,7 +23192,7 @@ function visit(schema, fnOrHandlers) {
23192
23192
  return h ? h(node2, rewritten) : node2;
23193
23193
  };
23194
23194
  const cache2 = /* @__PURE__ */ new Map();
23195
- function run(s) {
23195
+ function run2(s) {
23196
23196
  const cached2 = cache2.get(s);
23197
23197
  if (cached2 === RESOLVING) {
23198
23198
  return new $ZodLazy({
@@ -23218,21 +23218,21 @@ function visit(schema, fnOrHandlers) {
23218
23218
  let changed = false;
23219
23219
  const newShape = {};
23220
23220
  for (const k of keys) {
23221
- const mapped = run(oldShape[k]);
23221
+ const mapped = run2(oldShape[k]);
23222
23222
  if (mapped !== oldShape[k])
23223
23223
  changed = true;
23224
23224
  newShape[k] = mapped;
23225
23225
  }
23226
23226
  let newCatchall = def.catchall;
23227
23227
  if (def.catchall) {
23228
- newCatchall = run(def.catchall);
23228
+ newCatchall = run2(def.catchall);
23229
23229
  if (newCatchall !== def.catchall)
23230
23230
  changed = true;
23231
23231
  }
23232
23232
  return changed ? clone(s, { ...def, shape: newShape, catchall: newCatchall }) : s;
23233
23233
  }
23234
23234
  case "array": {
23235
- const mapped = run(def.element);
23235
+ const mapped = run2(def.element);
23236
23236
  return mapped === def.element ? s : clone(s, { ...def, element: mapped });
23237
23237
  }
23238
23238
  case "tuple": {
@@ -23240,14 +23240,14 @@ function visit(schema, fnOrHandlers) {
23240
23240
  let changed = false;
23241
23241
  const newItems = [];
23242
23242
  for (const item of oldItems) {
23243
- const mapped = run(item);
23243
+ const mapped = run2(item);
23244
23244
  if (mapped !== item)
23245
23245
  changed = true;
23246
23246
  newItems.push(mapped);
23247
23247
  }
23248
23248
  let newRest = def.rest;
23249
23249
  if (def.rest) {
23250
- newRest = run(def.rest);
23250
+ newRest = run2(def.rest);
23251
23251
  if (newRest !== def.rest)
23252
23252
  changed = true;
23253
23253
  }
@@ -23255,12 +23255,12 @@ function visit(schema, fnOrHandlers) {
23255
23255
  }
23256
23256
  case "record":
23257
23257
  case "map": {
23258
- const newKey = run(def.keyType);
23259
- const newVal = run(def.valueType);
23258
+ const newKey = run2(def.keyType);
23259
+ const newVal = run2(def.valueType);
23260
23260
  return newKey === def.keyType && newVal === def.valueType ? s : clone(s, { ...def, keyType: newKey, valueType: newVal });
23261
23261
  }
23262
23262
  case "set": {
23263
- const newVal = run(def.valueType);
23263
+ const newVal = run2(def.valueType);
23264
23264
  return newVal === def.valueType ? s : clone(s, { ...def, valueType: newVal });
23265
23265
  }
23266
23266
  case "union": {
@@ -23268,7 +23268,7 @@ function visit(schema, fnOrHandlers) {
23268
23268
  let changed = false;
23269
23269
  const newOptions = [];
23270
23270
  for (const opt of oldOptions) {
23271
- const mapped = run(opt);
23271
+ const mapped = run2(opt);
23272
23272
  if (mapped !== opt)
23273
23273
  changed = true;
23274
23274
  newOptions.push(mapped);
@@ -23276,8 +23276,8 @@ function visit(schema, fnOrHandlers) {
23276
23276
  return changed ? clone(s, { ...def, options: newOptions }) : s;
23277
23277
  }
23278
23278
  case "intersection": {
23279
- const newLeft = run(def.left);
23280
- const newRight = run(def.right);
23279
+ const newLeft = run2(def.left);
23280
+ const newRight = run2(def.right);
23281
23281
  return newLeft === def.left && newRight === def.right ? s : clone(s, { ...def, left: newLeft, right: newRight });
23282
23282
  }
23283
23283
  case "optional":
@@ -23289,23 +23289,23 @@ function visit(schema, fnOrHandlers) {
23289
23289
  case "nonoptional":
23290
23290
  case "promise":
23291
23291
  case "success": {
23292
- const newInner = run(def.innerType);
23292
+ const newInner = run2(def.innerType);
23293
23293
  return newInner === def.innerType ? s : clone(s, { ...def, innerType: newInner });
23294
23294
  }
23295
23295
  case "pipe": {
23296
- const newIn = run(def.in);
23297
- const newOut = run(def.out);
23296
+ const newIn = run2(def.in);
23297
+ const newOut = run2(def.out);
23298
23298
  return newIn === def.in && newOut === def.out ? s : clone(s, { ...def, in: newIn, out: newOut });
23299
23299
  }
23300
23300
  case "function": {
23301
- const newInput = run(def.input);
23302
- const newOutput = run(def.output);
23301
+ const newInput = run2(def.input);
23302
+ const newOutput = run2(def.output);
23303
23303
  return newInput === def.input && newOutput === def.output ? s : clone(s, { ...def, input: newInput, output: newOutput });
23304
23304
  }
23305
23305
  case "lazy": {
23306
23306
  const original = def.getter;
23307
23307
  const { _cachedInner, ...rest } = def;
23308
- return clone(s, { ...rest, getter: () => run(original()) });
23308
+ return clone(s, { ...rest, getter: () => run2(original()) });
23309
23309
  }
23310
23310
  // A leaf by choice: `parts` are regex fragments, not data positions.
23311
23311
  case "template_literal":
@@ -23336,7 +23336,7 @@ function visit(schema, fnOrHandlers) {
23336
23336
  }
23337
23337
  }
23338
23338
  }
23339
- return run(schema);
23339
+ return run2(schema);
23340
23340
  }
23341
23341
 
23342
23342
  // node_modules/zod/v4/classic/deep-partial.js
@@ -25177,8 +25177,8 @@ async function openNetworkPanel(binaryDirectory, identity) {
25177
25177
  }
25178
25178
 
25179
25179
  // agent/src/main.ts
25180
- import path28 from "node:path";
25181
- import os7 from "node:os";
25180
+ import path29 from "node:path";
25181
+ import os8 from "node:os";
25182
25182
 
25183
25183
  // agent/src/posix-store.ts
25184
25184
  import { constants } from "node:fs";
@@ -25597,7 +25597,7 @@ async function acquirePosixJournalGuard(directory, helper) {
25597
25597
  }
25598
25598
 
25599
25599
  // agent/src/main.ts
25600
- import { mkdir as mkdir14, open as open13, readFile as readFile11, realpath as realpath10, rm as rm9 } from "node:fs/promises";
25600
+ import { mkdir as mkdir14, open as open13, readFile as readFile12, realpath as realpath10, rm as rm10 } from "node:fs/promises";
25601
25601
  import { fileURLToPath } from "node:url";
25602
25602
 
25603
25603
  // packages/operations/src/crypto.ts
@@ -25734,13 +25734,13 @@ var exec2 = promisify2(execFile2);
25734
25734
  async function darwinSupervisorLiveness(helper, pids, records = []) {
25735
25735
  if (process.platform !== "darwin" || !process.getuid?.() || process.getuid() !== process.geteuid?.()) return null;
25736
25736
  const remaining = new Set(pids), uid = process.getuid(), deadline = Date.now() + 1e4, env = buildChildEnvironment(process.env);
25737
- const run = (file2, args) => exec2(
25737
+ const run2 = (file2, args) => exec2(
25738
25738
  file2,
25739
25739
  args,
25740
25740
  { env, timeout: Math.max(1, Math.min(7e3, deadline - Date.now())), maxBuffer: 8192, encoding: "utf8", windowsHide: true }
25741
25741
  );
25742
25742
  try {
25743
- const boot = (await run("/usr/sbin/sysctl", ["-n", "kern.bootsessionuuid"])).stdout.trim();
25743
+ const boot = (await run2("/usr/sbin/sysctl", ["-n", "kern.bootsessionuuid"])).stdout.trim();
25744
25744
  if (!bootSession.test(boot)) return null;
25745
25745
  for (const pid of remaining) {
25746
25746
  if (Date.now() >= deadline) break;
@@ -25749,9 +25749,9 @@ async function darwinSupervisorLiveness(helper, pids, records = []) {
25749
25749
  const proof2 = matches2[0].containment;
25750
25750
  if (!validDarwinContainment(proof2) || proof2.uid !== uid || proof2.bootSession !== boot) continue;
25751
25751
  try {
25752
- await run(helper, ["--reap", proof2.coalition]);
25753
- if ((await run(helper, ["--count", proof2.coalition])).stdout.trim() !== "0") continue;
25754
- await run("/bin/launchctl", ["bootout", "gui/" + uid + "/" + proof2.label]).catch(() => {
25752
+ await run2(helper, ["--reap", proof2.coalition]);
25753
+ if ((await run2(helper, ["--count", proof2.coalition])).stdout.trim() !== "0") continue;
25754
+ await run2("/bin/launchctl", ["bootout", "gui/" + uid + "/" + proof2.label]).catch(() => {
25755
25755
  });
25756
25756
  remaining.delete(pid);
25757
25757
  } catch {
@@ -26458,10 +26458,12 @@ var ToolCallSchema = external_exports.discriminatedUnion("name", [
26458
26458
  external_exports.object({ name: external_exports.literal("git_log"), args: external_exports.object({ path: path5.optional(), limit: external_exports.number().int().min(1).max(50).default(15) }).strict() }).strict(),
26459
26459
  external_exports.object({ name: external_exports.literal("project_snapshot"), args: external_exports.object({ path: path5.optional(), startup: external_exports.boolean().optional(), taskId: external_exports.string().regex(/^[A-Za-z0-9_-]{1,100}$/).optional() }).strict() }).strict(),
26460
26460
  external_exports.object({ name: external_exports.literal("command_run"), args: external_exports.object({ command: external_exports.string().min(1).max(260).refine((v) => !/[\r\n\0]/.test(v)), args: external_exports.array(external_exports.string().max(8192).refine((v) => !v.includes("\0"))).max(128).default([]), cwd: path5.optional(), timeoutMs: external_exports.number().int().min(100).max(864e5).default(6e4) }).strict() }).strict(),
26461
+ // Still image of the device's primary display; the agent requires an owner Full Access workspace.
26462
+ external_exports.object({ name: external_exports.literal("take_screenshot"), args: external_exports.object({}).strict() }).strict(),
26461
26463
  external_exports.object({ name: external_exports.literal("localhost_request"), args: external_exports.object({ url: external_exports.string().url().max(2048), method: external_exports.enum(["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"]).default("GET"), headers: external_exports.record(external_exports.string().max(128), external_exports.string().max(2048)).optional(), body: external_exports.string().max(6e4).optional() }).strict() }).strict()
26462
26464
  ]);
26463
26465
  function scopeForTool(call) {
26464
- if (call.name === "command_run") return "commands:execute";
26466
+ if (call.name === "command_run" || call.name === "take_screenshot") return "commands:execute";
26465
26467
  if (call.name === "localhost_request") return "localhost:access";
26466
26468
  return call.name === "fs_write" || call.name === "fs_replace" ? "files:write" : "files:read";
26467
26469
  }
@@ -26477,10 +26479,12 @@ var ServerFrameSchema = external_exports.discriminatedUnion("type", [
26477
26479
  external_exports.object({ type: external_exports.literal("workspace_ack"), version: external_exports.literal(1), requestId: uuid11, workspaceGrantId: uuid11, accepted: external_exports.boolean(), code: external_exports.string().max(64).optional() }).strict(),
26478
26480
  external_exports.object({ type: external_exports.literal("revoke"), version: external_exports.literal(1), reason: external_exports.enum(["device_revoked", "account_revoked", "server_shutdown", "connection_replaced"]) }).strict()
26479
26481
  ]);
26482
+ var WORKSPACE_ACCESS_MODE_CAPABILITY = "workspaceAccessModeV1";
26483
+ var WorkspaceAccessModeSchema = external_exports.enum(["full", "scoped"]);
26480
26484
  var ClientFrameSchema = external_exports.discriminatedUnion("type", [
26481
26485
  external_exports.object({ type: external_exports.literal("ready"), version: external_exports.literal(1), safeSlots: external_exports.number().int().min(1).max(128), platform: external_exports.literal("win32"), agentVersion: external_exports.string().regex(/^[A-Za-z0-9._+-]{1,64}$/), supervisor: external_exports.boolean() }).strict(),
26482
26486
  external_exports.object({ type: external_exports.literal("heartbeat"), version: external_exports.literal(1), connectionEpoch: epoch2 }).strict(),
26483
- external_exports.object({ type: external_exports.literal("workspace_grant"), version: external_exports.literal(1), requestId: uuid11, workspaceGrantId: uuid11, rootHash: hash3, displayName: external_exports.string().min(1).max(120), policyVersion: external_exports.number().int().min(1).max(2147483647) }).strict(),
26487
+ external_exports.object({ type: external_exports.literal("workspace_grant"), version: external_exports.literal(1), requestId: uuid11, workspaceGrantId: uuid11, rootHash: hash3, displayName: external_exports.string().min(1).max(120), policyVersion: external_exports.number().int().min(1).max(2147483647), accessMode: WorkspaceAccessModeSchema.optional() }).strict(),
26484
26488
  external_exports.object({ type: external_exports.literal("workspace_revoke"), version: external_exports.literal(1), requestId: uuid11, workspaceGrantId: uuid11 }).strict(),
26485
26489
  external_exports.object({ type: external_exports.literal("prepared"), version: external_exports.literal(1), binding: ExecutionBindingSchema }).strict(),
26486
26490
  external_exports.object({ type: external_exports.literal("accepted"), version: external_exports.literal(1), binding: ExecutionBindingSchema }).strict(),
@@ -26565,6 +26569,7 @@ function guardAction(binding2, tool, config2, observedAt) {
26565
26569
  throw Error("GUARD_IDENTITY_REQUIRED");
26566
26570
  }
26567
26571
  const name2 = tool.call.name;
26572
+ if (name2 === "take_screenshot") throw Error("GUARD_ACTION_UNSUPPORTED");
26568
26573
  const kind = name2 === "command_run" ? "execute" : name2 === "localhost_request" ? "localhost-access" : name2 === "fs_write" || name2 === "fs_replace" ? "write" : name2.startsWith("git_") ? "git-read" : "read";
26569
26574
  const resourceKind = kind === "execute" ? "workspace" : kind === "localhost-access" ? "localhost-service" : kind === "git-read" ? "git-repository" : name2 === "fs_read" || kind === "write" ? "file" : "workspace";
26570
26575
  return { payloadHash: guardHash(tool.effective), request: BoundActionRequestSchema.parse({
@@ -27040,9 +27045,9 @@ var NativeJournal = class _NativeJournal {
27040
27045
  if (!validPid(pid)) throw failure2("JOURNAL_INPUT_INVALID");
27041
27046
  if (e.state !== "running" || !e.supervisors) throw failure2("JOURNAL_STATE_INVALID");
27042
27047
  if (containment !== void 0) {
27043
- const linux = validLinuxContainment(containment), darwin = !linux && validDarwinContainment(containment);
27044
- if (!linux && !darwin || !e.supervisors.includes(pid) || e.linuxSupervisors?.some((s) => s.pid === pid) || e.darwinSupervisors?.some((s) => s.pid === pid)) throw failure2("JOURNAL_INPUT_INVALID");
27045
- if (linux) (e.linuxSupervisors ??= []).push({ pid, containment: clone2(containment) });
27048
+ const linux2 = validLinuxContainment(containment), darwin = !linux2 && validDarwinContainment(containment);
27049
+ if (!linux2 && !darwin || !e.supervisors.includes(pid) || e.linuxSupervisors?.some((s) => s.pid === pid) || e.darwinSupervisors?.some((s) => s.pid === pid)) throw failure2("JOURNAL_INPUT_INVALID");
27050
+ if (linux2) (e.linuxSupervisors ??= []).push({ pid, containment: clone2(containment) });
27046
27051
  else (e.darwinSupervisors ??= []).push({ pid, containment: clone2(containment) });
27047
27052
  } else {
27048
27053
  if (e.supervisors.length >= MAX_SUPERVISORS) throw failure2("JOURNAL_SUPERVISOR_LIMIT");
@@ -27246,6 +27251,7 @@ import { constants as constants4 } from "node:fs";
27246
27251
 
27247
27252
  // agent/src/posix-consent.ts
27248
27253
  import { openSync, closeSync } from "node:fs";
27254
+ import { spawnSync as spawnSync2 } from "node:child_process";
27249
27255
  import { isatty, ReadStream, WriteStream } from "node:tty";
27250
27256
  import { createInterface } from "node:readline/promises";
27251
27257
  import path8 from "node:path";
@@ -27348,7 +27354,7 @@ async function planPermissionChange(current2, programs, input2) {
27348
27354
  }
27349
27355
 
27350
27356
  // agent/src/posix-consent.ts
27351
- async function terminal2(run, timeoutMs2, signal) {
27357
+ async function terminal2(run2, timeoutMs2, signal) {
27352
27358
  if (!process.getuid || process.getuid() === 0 || process.geteuid?.() !== process.getuid() || signal?.aborted) throw Error("OWNER_REVIEW_UNAVAILABLE");
27353
27359
  let readFd;
27354
27360
  try {
@@ -27384,7 +27390,7 @@ async function terminal2(run, timeoutMs2, signal) {
27384
27390
  };
27385
27391
  input2.on("data", bound);
27386
27392
  try {
27387
- return await run(async (prompt) => {
27393
+ return await run2(async (prompt) => {
27388
27394
  if (stop.signal.aborted) throw Error("OWNER_REVIEW_CANCELLED");
27389
27395
  return review.question(prompt, { signal: stop.signal });
27390
27396
  });
@@ -27413,16 +27419,41 @@ async function choosePosixFolder() {
27413
27419
  return await ask("Read/write folder: " + permissionLabel(folder) + "\nType APPROVE to accept: ") === "APPROVE" ? folder : null;
27414
27420
  }, 12e4);
27415
27421
  }
27422
+ var ACCESS_TEXT = "Local Commander lets your AI work on this computer.\n\nFull Access: files, commands and localhost with your account's rights (not an OS sandbox).\nChoose Folder: read and write one folder only.\n\nThis replaces the previous selection and lasts until you change or revoke it.";
27423
+ function selection(folder, full) {
27424
+ if (!path8.isAbsolute(folder) || folder.length > 4096 || /[\u0000-\u001f]/.test(folder)) throw Error("WORKSPACE_INVALID");
27425
+ return { mode: full ? "all-drives" : "folders", paths: [full ? "/" : folder] };
27426
+ }
27427
+ function macDialog() {
27428
+ const script = [
27429
+ "on run argv",
27430
+ 'set answer to button returned of (display dialog (item 1 of argv) with title "Local Commander" buttons {"Cancel", "Choose Folder\uFFFD", "Full Access"} default button "Full Access" cancel button "Cancel" with icon note)',
27431
+ 'if answer is "Full Access" then return "full"',
27432
+ 'return "folder:" & POSIX path of (choose folder with prompt "Choose the folder Local Commander may read and write")',
27433
+ "end run"
27434
+ ];
27435
+ const result2 = spawnSync2(
27436
+ "/usr/bin/osascript",
27437
+ [...script.flatMap((line) => ["-e", line]), ACCESS_TEXT],
27438
+ { encoding: "utf8", timeout: 24e4, maxBuffer: 16384, shell: false }
27439
+ );
27440
+ if (result2.error) return void 0;
27441
+ if (result2.status !== 0) return /\(-128\)/.test(result2.stderr) ? null : void 0;
27442
+ const out = result2.stdout.replace(/\n$/, "");
27443
+ if (out === "full") return selection("/", true);
27444
+ if (out.startsWith("folder:")) return selection(out.slice(7).replace(/(.)\/$/, "$1"), false);
27445
+ return void 0;
27446
+ }
27416
27447
  async function choosePosixAccess() {
27448
+ if (process.platform === "darwin") {
27449
+ const chosen = macDialog();
27450
+ if (chosen !== void 0) return chosen;
27451
+ }
27417
27452
  return terminal2(async (ask) => {
27418
- if (process.platform === "darwin") await ask("Local Commander runs each command as its own launchd job and stops that job's processes when the command ends; work handed to other services is not stopped. Press Enter to review access: ");
27419
- const choice = await ask("Local Commander access\n1. One folder: read and write files\n2. Full Access: account capabilities across this computer, including commands and localhost\nEnter 1 or 2 (empty cancels): ");
27420
- if (choice !== "1" && choice !== "2") return null;
27421
- const folder = choice === "2" ? "/" : await ask("Absolute folder path: ");
27422
- if (!path8.isAbsolute(folder) || folder.length > 4096 || /[\u0000-\u001f]/.test(folder)) throw Error("WORKSPACE_INVALID");
27423
- const summary = choice === "2" ? "Full Access allows programs to use your account's capabilities across this computer. This is not an OS sandbox." : "Allow reading and writing files in " + permissionLabel(folder) + ".";
27424
- if (await ask(summary + "\nThis replaces the previous folder/command/localhost selection and persists until revoked.\nType APPROVE to accept: ") !== "APPROVE") return null;
27425
- return { mode: choice === "2" ? "all-drives" : "folders", paths: [folder] };
27453
+ const answer = await ask("\n" + ACCESS_TEXT + "\n\nPress Enter for Full Access, type a folder path for one folder, or n to cancel: ");
27454
+ if (answer === "") return selection("/", true);
27455
+ if (/^(n|no|cancel)$/i.test(answer)) return null;
27456
+ return selection(answer, false);
27426
27457
  }, 24e4);
27427
27458
  }
27428
27459
 
@@ -28889,9 +28920,9 @@ var HostMemory = class {
28889
28920
  };
28890
28921
 
28891
28922
  // agent/src/tools.ts
28892
- import { constants as constants7 } from "node:fs";
28893
- import { lstat as lstat7, open as open6, readdir as readdir4, realpath as realpath7, rename as rename4, rm as rm5 } from "node:fs/promises";
28894
- import path17 from "node:path";
28923
+ import { constants as constants8 } from "node:fs";
28924
+ import { lstat as lstat8, open as open6, readdir as readdir5, realpath as realpath7, rename as rename4, rm as rm6 } from "node:fs/promises";
28925
+ import path18 from "node:path";
28895
28926
  import { createHash as createHash14, randomUUID as randomUUID7 } from "node:crypto";
28896
28927
 
28897
28928
  // src/guard.ts
@@ -29335,6 +29366,1249 @@ async function runSupervised(helper, request, options = {}) {
29335
29366
  });
29336
29367
  }
29337
29368
 
29369
+ // agent/src/screen-capture.ts
29370
+ import { execFile as execFile4 } from "node:child_process";
29371
+ import { randomBytes as randomBytes6 } from "node:crypto";
29372
+ import { constants as constants7 } from "node:fs";
29373
+ import { access as access3, lstat as lstat7, mkdtemp, readFile as readFile6, readdir as readdir4, rm as rm5, unlink as unlink2 } from "node:fs/promises";
29374
+ import os4 from "node:os";
29375
+ import path17 from "node:path";
29376
+
29377
+ // agent/src/dbus-portal.ts
29378
+ import net from "node:net";
29379
+ function sessionBusSocket(address) {
29380
+ for (const entry of (address ?? "").split(";")) {
29381
+ if (!entry.startsWith("unix:")) continue;
29382
+ for (const part of entry.slice(5).split(",")) {
29383
+ const at = part.indexOf("="), key = part.slice(0, at), value = decodeURIComponent(part.slice(at + 1));
29384
+ if (at > 0 && value && key === "path") return value;
29385
+ if (at > 0 && value && key === "abstract") return "\0" + value;
29386
+ }
29387
+ }
29388
+ return null;
29389
+ }
29390
+ var Writer = class {
29391
+ bytes = [];
29392
+ align(n) {
29393
+ while (this.bytes.length % n) this.bytes.push(0);
29394
+ }
29395
+ byte(v) {
29396
+ this.bytes.push(v & 255);
29397
+ }
29398
+ u32(v) {
29399
+ this.align(4);
29400
+ this.bytes.push(v & 255, v >>> 8 & 255, v >>> 16 & 255, v >>> 24 & 255);
29401
+ }
29402
+ str(v) {
29403
+ const b = Buffer.from(v, "utf8");
29404
+ this.u32(b.length);
29405
+ this.bytes.push(...b, 0);
29406
+ }
29407
+ sig(v) {
29408
+ this.byte(v.length);
29409
+ this.bytes.push(...Buffer.from(v, "ascii"), 0);
29410
+ }
29411
+ /** Basic value or variant: `s`, `o`, `g`, `u`, `b`, `v` ([signature, value]). */
29412
+ put(type, value) {
29413
+ if (type === "s" || type === "o") this.str(String(value));
29414
+ else if (type === "g") this.sig(String(value));
29415
+ else if (type === "u") this.u32(Number(value));
29416
+ else if (type === "b") this.u32(value ? 1 : 0);
29417
+ else if (type === "v") {
29418
+ const [inner, v] = value;
29419
+ this.sig(inner);
29420
+ this.put(inner, v);
29421
+ } else throw Error("type " + type);
29422
+ }
29423
+ /** a{sv} */
29424
+ dict(entries) {
29425
+ this.u32(0);
29426
+ const lengthAt = this.bytes.length - 4;
29427
+ this.align(8);
29428
+ const start = this.bytes.length;
29429
+ for (const [key, value] of entries) {
29430
+ this.align(8);
29431
+ this.str(key);
29432
+ this.put("v", value);
29433
+ }
29434
+ const length = this.bytes.length - start;
29435
+ this.bytes.splice(lengthAt, 4, length & 255, length >>> 8 & 255, length >>> 16 & 255, length >>> 24 & 255);
29436
+ }
29437
+ };
29438
+ var Reader = class {
29439
+ constructor(data, at, le) {
29440
+ this.data = data;
29441
+ this.at = at;
29442
+ this.le = le;
29443
+ }
29444
+ data;
29445
+ at;
29446
+ le;
29447
+ align(n) {
29448
+ this.at = Math.ceil(this.at / n) * n;
29449
+ }
29450
+ u32() {
29451
+ this.align(4);
29452
+ const v = this.le ? this.data.readUInt32LE(this.at) : this.data.readUInt32BE(this.at);
29453
+ this.at += 4;
29454
+ return v;
29455
+ }
29456
+ /** Reads one complete type from `sig` starting at `i`; returns the value and the index after the type. */
29457
+ read(sig2, i) {
29458
+ const c = sig2[i];
29459
+ const fixed = { y: 1, n: 2, q: 2, b: 4, i: 4, u: 4, h: 4, x: 8, t: 8, d: 8 };
29460
+ if (c in fixed) {
29461
+ const size = fixed[c];
29462
+ this.align(size);
29463
+ const v = size === 1 ? this.data[this.at] : size === 2 ? this.le ? this.data.readUInt16LE(this.at) : this.data.readUInt16BE(this.at) : size === 4 ? this.le ? this.data.readUInt32LE(this.at) : this.data.readUInt32BE(this.at) : null;
29464
+ this.at += size;
29465
+ return [c === "b" ? v === 1 : v, i + 1];
29466
+ }
29467
+ if (c === "s" || c === "o") {
29468
+ const n = this.u32(), v = this.data.toString("utf8", this.at, this.at + n);
29469
+ this.at += n + 1;
29470
+ return [v, i + 1];
29471
+ }
29472
+ if (c === "g") {
29473
+ const n = this.data[this.at], v = this.data.toString("ascii", this.at + 1, this.at + 1 + n);
29474
+ this.at += n + 2;
29475
+ return [v, i + 1];
29476
+ }
29477
+ if (c === "v") {
29478
+ const [inner] = this.read("g", 0);
29479
+ return [this.read(inner, 0)[0], i + 1];
29480
+ }
29481
+ if (c === "(" || c === "{") {
29482
+ this.align(8);
29483
+ const close = c === "(" ? ")" : "}", values = [];
29484
+ let j = i + 1;
29485
+ while (sig2[j] !== close) {
29486
+ const [v, next] = this.read(sig2, j);
29487
+ values.push(v);
29488
+ j = next;
29489
+ }
29490
+ return [values, j + 1];
29491
+ }
29492
+ if (c === "a") {
29493
+ const n = this.u32(), element = sig2[i + 1];
29494
+ this.align("xtd({".includes(element) ? 8 : element === "n" || element === "q" ? 2 : element === "y" || element === "g" || element === "v" ? 1 : 4);
29495
+ const end = this.at + n, values = [];
29496
+ let next = skip(sig2, i + 1);
29497
+ while (this.at < end) {
29498
+ const [v, j] = this.read(sig2, i + 1);
29499
+ values.push(v);
29500
+ next = j;
29501
+ }
29502
+ return [values, next];
29503
+ }
29504
+ throw Error("signature " + sig2);
29505
+ }
29506
+ };
29507
+ function skip(sig2, i) {
29508
+ const c = sig2[i];
29509
+ if (c === "a") return skip(sig2, i + 1);
29510
+ if (c === "(" || c === "{") {
29511
+ let j = i + 1;
29512
+ while (sig2[j] !== (c === "(" ? ")" : "}")) j = skip(sig2, j);
29513
+ return j + 1;
29514
+ }
29515
+ return i + 1;
29516
+ }
29517
+ function parse3(data) {
29518
+ const le = data[0] === 108, r = new Reader(data, 4, le), bodyLength = r.u32(), serial = r.u32();
29519
+ const [fields] = r.read("a(yv)", 0);
29520
+ const message2 = { type: data[1], serial, signature: "", body: [] };
29521
+ for (const [code, value] of fields) {
29522
+ if (code === 1) message2.path = String(value);
29523
+ else if (code === 2) message2.interface = String(value);
29524
+ else if (code === 3) message2.member = String(value);
29525
+ else if (code === 4) message2.errorName = String(value);
29526
+ else if (code === 5) message2.replySerial = Number(value);
29527
+ else if (code === 8) message2.signature = String(value);
29528
+ }
29529
+ r.align(8);
29530
+ const end = r.at + bodyLength;
29531
+ for (let i = 0; i < message2.signature.length && r.at < end; ) {
29532
+ const [v, next] = r.read(message2.signature, i);
29533
+ message2.body.push(v);
29534
+ i = next;
29535
+ }
29536
+ return message2;
29537
+ }
29538
+ function frameLength(data) {
29539
+ if (data.length < 16) return 0;
29540
+ const le = data[0] === 108, u = (at) => le ? data.readUInt32LE(at) : data.readUInt32BE(at);
29541
+ const length = Math.ceil((16 + u(12)) / 8) * 8 + u(4);
29542
+ return data.length >= length ? length : 0;
29543
+ }
29544
+ async function portalScreenshot(socket, uid, token, signal) {
29545
+ const connection = net.createConnection({ path: socket });
29546
+ try {
29547
+ return await new Promise((resolve, reject) => {
29548
+ let serial = 0, buffer = Buffer.alloc(0), authenticated = false, requestPath = "";
29549
+ const pending = /* @__PURE__ */ new Map();
29550
+ const fail7 = (error62) => reject(error62 instanceof Error ? error62 : Error(String(error62)));
29551
+ const abort = () => fail7(Error("ABORTED"));
29552
+ if (signal.aborted) return abort();
29553
+ signal.addEventListener("abort", abort, { once: true });
29554
+ connection.on("error", fail7);
29555
+ connection.on("close", () => fail7(Error("CLOSED")));
29556
+ const call = (destination, path30, iface, member, signature = "", body = () => {
29557
+ }) => new Promise((done, failed) => {
29558
+ const payload2 = new Writer();
29559
+ body(payload2);
29560
+ const header = new Writer(), fields = [[1, "o", path30], [2, "s", iface], [3, "s", member], [6, "s", destination]];
29561
+ if (signature) fields.push([8, "g", signature]);
29562
+ header.byte(108);
29563
+ header.byte(1);
29564
+ header.byte(0);
29565
+ header.byte(1);
29566
+ header.u32(payload2.bytes.length);
29567
+ header.u32(++serial);
29568
+ header.u32(0);
29569
+ const lengthAt = header.bytes.length - 4;
29570
+ header.align(8);
29571
+ const start = header.bytes.length;
29572
+ for (const [code, type, value] of fields) {
29573
+ header.align(8);
29574
+ header.byte(code);
29575
+ header.sig(type);
29576
+ header.put(type, value);
29577
+ }
29578
+ const length = header.bytes.length - start;
29579
+ header.bytes.splice(lengthAt, 4, length & 255, length >>> 8 & 255, length >>> 16 & 255, length >>> 24 & 255);
29580
+ header.align(8);
29581
+ pending.set(serial, (reply) => reply.type === 3 ? failed(Error(reply.errorName ?? "DBUS_ERROR")) : done(reply));
29582
+ connection.write(Buffer.from([...header.bytes, ...payload2.bytes]));
29583
+ });
29584
+ const bus = (member, signature, body) => call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", member, signature, body);
29585
+ connection.on("data", (chunk) => {
29586
+ try {
29587
+ receive(chunk);
29588
+ } catch (error62) {
29589
+ fail7(error62);
29590
+ }
29591
+ });
29592
+ const receive = (chunk) => {
29593
+ buffer = Buffer.concat([buffer, chunk]);
29594
+ if (buffer.length > 1048576) return fail7(Error("OVERSIZED"));
29595
+ if (!authenticated) {
29596
+ const end = buffer.indexOf("\r\n");
29597
+ if (end < 0) return;
29598
+ const line = buffer.toString("ascii", 0, end);
29599
+ buffer = buffer.subarray(end + 2);
29600
+ if (!line.startsWith("OK ")) return fail7(Error("AUTH"));
29601
+ authenticated = true;
29602
+ connection.write("BEGIN\r\n");
29603
+ void (async () => {
29604
+ const unique = String((await bus("Hello")).body[0]);
29605
+ requestPath = "/org/freedesktop/portal/desktop/request/" + unique.slice(1).replace(/\./g, "_") + "/" + token;
29606
+ await bus("AddMatch", "s", (w) => w.put("s", "type='signal',interface='org.freedesktop.portal.Request',member='Response',path='" + requestPath + "'"));
29607
+ const handle = await call(
29608
+ "org.freedesktop.portal.Desktop",
29609
+ "/org/freedesktop/portal/desktop",
29610
+ "org.freedesktop.portal.Screenshot",
29611
+ "Screenshot",
29612
+ "sa{sv}",
29613
+ (w) => {
29614
+ w.put("s", "");
29615
+ w.dict([["handle_token", ["s", token]], ["interactive", ["b", false]]]);
29616
+ }
29617
+ );
29618
+ if (handle.body[0] !== requestPath) {
29619
+ requestPath = String(handle.body[0]);
29620
+ await bus("AddMatch", "s", (w) => w.put("s", "type='signal',interface='org.freedesktop.portal.Request',member='Response',path='" + requestPath + "'"));
29621
+ }
29622
+ })().catch(fail7);
29623
+ }
29624
+ for (let length = frameLength(buffer); authenticated && length; length = frameLength(buffer)) {
29625
+ const message2 = parse3(buffer.subarray(0, length));
29626
+ buffer = buffer.subarray(length);
29627
+ if ((message2.type === 2 || message2.type === 3) && message2.replySerial !== void 0) {
29628
+ pending.get(message2.replySerial)?.(message2);
29629
+ pending.delete(message2.replySerial);
29630
+ } else if (message2.type === 4 && message2.member === "Response" && message2.path === requestPath && message2.signature === "ua{sv}") {
29631
+ const results2 = message2.body[1], uri = results2.find(([key]) => key === "uri")?.[1];
29632
+ resolve({ code: Number(message2.body[0]), uri: typeof uri === "string" ? uri : void 0 });
29633
+ }
29634
+ }
29635
+ };
29636
+ connection.on("connect", () => connection.write("\0AUTH EXTERNAL " + Buffer.from(String(uid), "ascii").toString("hex") + "\r\n"));
29637
+ });
29638
+ } finally {
29639
+ connection.destroy();
29640
+ }
29641
+ }
29642
+
29643
+ // agent/src/screen-image.ts
29644
+ import { inflateSync } from "node:zlib";
29645
+ var MAX_EDGE = 16384;
29646
+ var MAX_PIXELS = 67108864;
29647
+ function sizeOk(width, height) {
29648
+ return Number.isSafeInteger(width) && Number.isSafeInteger(height) && width > 0 && height > 0 && width <= MAX_EDGE && height <= MAX_EDGE && width * height <= MAX_PIXELS;
29649
+ }
29650
+ function decodePng(data) {
29651
+ if (data.length < 33 || data.readUInt32BE(0) !== 2303741511 || data.readUInt32BE(4) !== 218765834) return null;
29652
+ let width = 0, height = 0, channels = 0;
29653
+ const idat = [];
29654
+ for (let at = 8; at + 12 <= data.length; ) {
29655
+ const length = data.readUInt32BE(at), type = data.toString("latin1", at + 4, at + 8), body = at + 8;
29656
+ if (body + length + 4 > data.length) return null;
29657
+ if (type === "IHDR") {
29658
+ if (length !== 13) return null;
29659
+ width = data.readUInt32BE(body);
29660
+ height = data.readUInt32BE(body + 4);
29661
+ const depth = data[body + 8], color = data[body + 9], interlace = data[body + 12];
29662
+ channels = color === 0 ? 1 : color === 2 ? 3 : color === 4 ? 2 : color === 6 ? 4 : 0;
29663
+ if (depth !== 8 || !channels || interlace !== 0 || data[body + 10] !== 0 || data[body + 11] !== 0 || !sizeOk(width, height)) return null;
29664
+ } else if (type === "IDAT") idat.push(data.subarray(body, body + length));
29665
+ else if (type === "IEND") break;
29666
+ at = body + length + 4;
29667
+ }
29668
+ if (!channels || !idat.length) return null;
29669
+ const stride = width * channels, expected = (stride + 1) * height;
29670
+ let raw;
29671
+ try {
29672
+ raw = inflateSync(Buffer.concat(idat), { maxOutputLength: expected });
29673
+ } catch {
29674
+ return null;
29675
+ }
29676
+ if (raw.length !== expected) return null;
29677
+ const rgb = Buffer.alloc(width * height * 3);
29678
+ let previous = Buffer.alloc(stride), current2 = Buffer.alloc(stride);
29679
+ for (let y = 0; y < height; y++) {
29680
+ const filter = raw[y * (stride + 1)], line = raw.subarray(y * (stride + 1) + 1, (y + 1) * (stride + 1));
29681
+ for (let x = 0; x < stride; x++) {
29682
+ const a = x >= channels ? current2[x - channels] : 0, b = previous[x], c = x >= channels ? previous[x - channels] : 0;
29683
+ let value = line[x];
29684
+ if (filter === 1) value += a;
29685
+ else if (filter === 2) value += b;
29686
+ else if (filter === 3) value += a + b >> 1;
29687
+ else if (filter === 4) {
29688
+ const p = a + b - c, pa = Math.abs(p - a), pb = Math.abs(p - b), pc = Math.abs(p - c);
29689
+ value += pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
29690
+ } else if (filter !== 0) return null;
29691
+ current2[x] = value & 255;
29692
+ }
29693
+ for (let x = 0, o = y * width * 3; x < width; x++, o += 3) {
29694
+ const i = x * channels;
29695
+ if (channels <= 2) rgb[o] = rgb[o + 1] = rgb[o + 2] = current2[i];
29696
+ else {
29697
+ rgb[o] = current2[i];
29698
+ rgb[o + 1] = current2[i + 1];
29699
+ rgb[o + 2] = current2[i + 2];
29700
+ }
29701
+ }
29702
+ [previous, current2] = [current2, previous];
29703
+ }
29704
+ return { width, height, rgb };
29705
+ }
29706
+ function decodeXwd(data) {
29707
+ if (data.length < 100) return null;
29708
+ const field = (index) => data.readUInt32BE(index * 4);
29709
+ const headerSize = field(0), version2 = field(1), format = field(2), width = field(4), height = field(5), byteOrder = field(7);
29710
+ const bitsPerPixel = field(11), bytesPerLine = field(12), visualClass = field(13), masks = [field(14), field(15), field(16)], colors = field(19);
29711
+ if (version2 !== 7 || format !== 2 || headerSize < 100 || ![4, 5].includes(visualClass) || ![24, 32].includes(bitsPerPixel) || !sizeOk(width, height) || colors > 65536) return null;
29712
+ const pixelBytes = bitsPerPixel / 8, start = headerSize + colors * 12;
29713
+ if (bytesPerLine < width * pixelBytes || start + bytesPerLine * height > data.length || masks.some((mask) => !mask)) return null;
29714
+ const shifts = masks.map((mask) => {
29715
+ let shift = 0;
29716
+ while (!(mask >>> shift & 1)) shift++;
29717
+ return shift;
29718
+ });
29719
+ const scales = masks.map((mask, i) => 255 / (mask >>> shifts[i]));
29720
+ const rgb = Buffer.alloc(width * height * 3);
29721
+ for (let y = 0; y < height; y++) for (let x = 0, at = start + y * bytesPerLine, o = y * width * 3; x < width; x++, at += pixelBytes, o += 3) {
29722
+ const pixel = pixelBytes === 4 ? byteOrder === 0 ? data.readUInt32LE(at) : data.readUInt32BE(at) : byteOrder === 0 ? data[at] | data[at + 1] << 8 | data[at + 2] << 16 : data[at] << 16 | data[at + 1] << 8 | data[at + 2];
29723
+ for (let c = 0; c < 3; c++) rgb[o + c] = Math.round(((pixel & masks[c]) >>> 0 >>> shifts[c]) * scales[c]);
29724
+ }
29725
+ return { width, height, rgb };
29726
+ }
29727
+ function downscale(image, edge) {
29728
+ const scale = Math.min(1, edge / Math.max(image.width, image.height));
29729
+ if (scale >= 1) return image;
29730
+ const width = Math.max(1, Math.round(image.width * scale)), height = Math.max(1, Math.round(image.height * scale));
29731
+ const xs = Array.from({ length: width + 1 }, (_, x) => Math.min(image.width, Math.floor(x * image.width / width)));
29732
+ const ys = Array.from({ length: height + 1 }, (_, y) => Math.min(image.height, Math.floor(y * image.height / height)));
29733
+ const rgb = Buffer.alloc(width * height * 3), sums = new Float64Array(width * 3);
29734
+ for (let y = 0; y < height; y++) {
29735
+ sums.fill(0);
29736
+ for (let sy = ys[y]; sy < ys[y + 1]; sy++) for (let x = 0; x < width; x++) for (let sx = xs[x]; sx < xs[x + 1]; sx++) {
29737
+ const i = (sy * image.width + sx) * 3;
29738
+ sums[x * 3] = sums[x * 3] + image.rgb[i];
29739
+ sums[x * 3 + 1] = sums[x * 3 + 1] + image.rgb[i + 1];
29740
+ sums[x * 3 + 2] = sums[x * 3 + 2] + image.rgb[i + 2];
29741
+ }
29742
+ for (let x = 0; x < width; x++) {
29743
+ const count3 = (ys[y + 1] - ys[y]) * (xs[x + 1] - xs[x]);
29744
+ for (let c = 0; c < 3; c++) rgb[(y * width + x) * 3 + c] = Math.round(sums[x * 3 + c] / count3);
29745
+ }
29746
+ }
29747
+ return { width, height, rgb };
29748
+ }
29749
+ var ZIGZAG = [
29750
+ 0,
29751
+ 1,
29752
+ 5,
29753
+ 6,
29754
+ 14,
29755
+ 15,
29756
+ 27,
29757
+ 28,
29758
+ 2,
29759
+ 4,
29760
+ 7,
29761
+ 13,
29762
+ 16,
29763
+ 26,
29764
+ 29,
29765
+ 42,
29766
+ 3,
29767
+ 8,
29768
+ 12,
29769
+ 17,
29770
+ 25,
29771
+ 30,
29772
+ 41,
29773
+ 43,
29774
+ 9,
29775
+ 11,
29776
+ 18,
29777
+ 24,
29778
+ 31,
29779
+ 40,
29780
+ 44,
29781
+ 53,
29782
+ 10,
29783
+ 19,
29784
+ 23,
29785
+ 32,
29786
+ 39,
29787
+ 45,
29788
+ 52,
29789
+ 54,
29790
+ 20,
29791
+ 22,
29792
+ 33,
29793
+ 38,
29794
+ 46,
29795
+ 51,
29796
+ 55,
29797
+ 60,
29798
+ 21,
29799
+ 34,
29800
+ 37,
29801
+ 47,
29802
+ 50,
29803
+ 56,
29804
+ 59,
29805
+ 61,
29806
+ 35,
29807
+ 36,
29808
+ 48,
29809
+ 49,
29810
+ 57,
29811
+ 58,
29812
+ 62,
29813
+ 63
29814
+ ];
29815
+ var LUMA_QUANT = [
29816
+ 16,
29817
+ 11,
29818
+ 10,
29819
+ 16,
29820
+ 24,
29821
+ 40,
29822
+ 51,
29823
+ 61,
29824
+ 12,
29825
+ 12,
29826
+ 14,
29827
+ 19,
29828
+ 26,
29829
+ 58,
29830
+ 60,
29831
+ 55,
29832
+ 14,
29833
+ 13,
29834
+ 16,
29835
+ 24,
29836
+ 40,
29837
+ 57,
29838
+ 69,
29839
+ 56,
29840
+ 14,
29841
+ 17,
29842
+ 22,
29843
+ 29,
29844
+ 51,
29845
+ 87,
29846
+ 80,
29847
+ 62,
29848
+ 18,
29849
+ 22,
29850
+ 37,
29851
+ 56,
29852
+ 68,
29853
+ 109,
29854
+ 103,
29855
+ 77,
29856
+ 24,
29857
+ 35,
29858
+ 55,
29859
+ 64,
29860
+ 81,
29861
+ 104,
29862
+ 113,
29863
+ 92,
29864
+ 49,
29865
+ 64,
29866
+ 78,
29867
+ 87,
29868
+ 103,
29869
+ 121,
29870
+ 120,
29871
+ 101,
29872
+ 72,
29873
+ 92,
29874
+ 95,
29875
+ 98,
29876
+ 112,
29877
+ 100,
29878
+ 103,
29879
+ 99
29880
+ ];
29881
+ var CHROMA_QUANT = [17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, ...Array(38).fill(99)];
29882
+ var AC_LUMA_VALUES = [
29883
+ 1,
29884
+ 2,
29885
+ 3,
29886
+ 0,
29887
+ 4,
29888
+ 17,
29889
+ 5,
29890
+ 18,
29891
+ 33,
29892
+ 49,
29893
+ 65,
29894
+ 6,
29895
+ 19,
29896
+ 81,
29897
+ 97,
29898
+ 7,
29899
+ 34,
29900
+ 113,
29901
+ 20,
29902
+ 50,
29903
+ 129,
29904
+ 145,
29905
+ 161,
29906
+ 8,
29907
+ 35,
29908
+ 66,
29909
+ 177,
29910
+ 193,
29911
+ 21,
29912
+ 82,
29913
+ 209,
29914
+ 240,
29915
+ 36,
29916
+ 51,
29917
+ 98,
29918
+ 114,
29919
+ 130,
29920
+ 9,
29921
+ 10,
29922
+ 22,
29923
+ 23,
29924
+ 24,
29925
+ 25,
29926
+ 26,
29927
+ 37,
29928
+ 38,
29929
+ 39,
29930
+ 40,
29931
+ 41,
29932
+ 42,
29933
+ 52,
29934
+ 53,
29935
+ 54,
29936
+ 55,
29937
+ 56,
29938
+ 57,
29939
+ 58,
29940
+ 67,
29941
+ 68,
29942
+ 69,
29943
+ 70,
29944
+ 71,
29945
+ 72,
29946
+ 73,
29947
+ 74,
29948
+ 83,
29949
+ 84,
29950
+ 85,
29951
+ 86,
29952
+ 87,
29953
+ 88,
29954
+ 89,
29955
+ 90,
29956
+ 99,
29957
+ 100,
29958
+ 101,
29959
+ 102,
29960
+ 103,
29961
+ 104,
29962
+ 105,
29963
+ 106,
29964
+ 115,
29965
+ 116,
29966
+ 117,
29967
+ 118,
29968
+ 119,
29969
+ 120,
29970
+ 121,
29971
+ 122,
29972
+ 131,
29973
+ 132,
29974
+ 133,
29975
+ 134,
29976
+ 135,
29977
+ 136,
29978
+ 137,
29979
+ 138,
29980
+ 146,
29981
+ 147,
29982
+ 148,
29983
+ 149,
29984
+ 150,
29985
+ 151,
29986
+ 152,
29987
+ 153,
29988
+ 154,
29989
+ 162,
29990
+ 163,
29991
+ 164,
29992
+ 165,
29993
+ 166,
29994
+ 167,
29995
+ 168,
29996
+ 169,
29997
+ 170,
29998
+ 178,
29999
+ 179,
30000
+ 180,
30001
+ 181,
30002
+ 182,
30003
+ 183,
30004
+ 184,
30005
+ 185,
30006
+ 186,
30007
+ 194,
30008
+ 195,
30009
+ 196,
30010
+ 197,
30011
+ 198,
30012
+ 199,
30013
+ 200,
30014
+ 201,
30015
+ 202,
30016
+ 210,
30017
+ 211,
30018
+ 212,
30019
+ 213,
30020
+ 214,
30021
+ 215,
30022
+ 216,
30023
+ 217,
30024
+ 218,
30025
+ 225,
30026
+ 226,
30027
+ 227,
30028
+ 228,
30029
+ 229,
30030
+ 230,
30031
+ 231,
30032
+ 232,
30033
+ 233,
30034
+ 234,
30035
+ 241,
30036
+ 242,
30037
+ 243,
30038
+ 244,
30039
+ 245,
30040
+ 246,
30041
+ 247,
30042
+ 248,
30043
+ 249,
30044
+ 250
30045
+ ];
30046
+ var AC_CHROMA_VALUES = [
30047
+ 0,
30048
+ 1,
30049
+ 2,
30050
+ 3,
30051
+ 17,
30052
+ 4,
30053
+ 5,
30054
+ 33,
30055
+ 49,
30056
+ 6,
30057
+ 18,
30058
+ 65,
30059
+ 81,
30060
+ 7,
30061
+ 97,
30062
+ 113,
30063
+ 19,
30064
+ 34,
30065
+ 50,
30066
+ 129,
30067
+ 8,
30068
+ 20,
30069
+ 66,
30070
+ 145,
30071
+ 161,
30072
+ 177,
30073
+ 193,
30074
+ 9,
30075
+ 35,
30076
+ 51,
30077
+ 82,
30078
+ 240,
30079
+ 21,
30080
+ 98,
30081
+ 114,
30082
+ 209,
30083
+ 10,
30084
+ 22,
30085
+ 36,
30086
+ 52,
30087
+ 225,
30088
+ 37,
30089
+ 241,
30090
+ 23,
30091
+ 24,
30092
+ 25,
30093
+ 26,
30094
+ 38,
30095
+ 39,
30096
+ 40,
30097
+ 41,
30098
+ 42,
30099
+ 53,
30100
+ 54,
30101
+ 55,
30102
+ 56,
30103
+ 57,
30104
+ 58,
30105
+ 67,
30106
+ 68,
30107
+ 69,
30108
+ 70,
30109
+ 71,
30110
+ 72,
30111
+ 73,
30112
+ 74,
30113
+ 83,
30114
+ 84,
30115
+ 85,
30116
+ 86,
30117
+ 87,
30118
+ 88,
30119
+ 89,
30120
+ 90,
30121
+ 99,
30122
+ 100,
30123
+ 101,
30124
+ 102,
30125
+ 103,
30126
+ 104,
30127
+ 105,
30128
+ 106,
30129
+ 115,
30130
+ 116,
30131
+ 117,
30132
+ 118,
30133
+ 119,
30134
+ 120,
30135
+ 121,
30136
+ 122,
30137
+ 130,
30138
+ 131,
30139
+ 132,
30140
+ 133,
30141
+ 134,
30142
+ 135,
30143
+ 136,
30144
+ 137,
30145
+ 138,
30146
+ 146,
30147
+ 147,
30148
+ 148,
30149
+ 149,
30150
+ 150,
30151
+ 151,
30152
+ 152,
30153
+ 153,
30154
+ 154,
30155
+ 162,
30156
+ 163,
30157
+ 164,
30158
+ 165,
30159
+ 166,
30160
+ 167,
30161
+ 168,
30162
+ 169,
30163
+ 170,
30164
+ 178,
30165
+ 179,
30166
+ 180,
30167
+ 181,
30168
+ 182,
30169
+ 183,
30170
+ 184,
30171
+ 185,
30172
+ 186,
30173
+ 194,
30174
+ 195,
30175
+ 196,
30176
+ 197,
30177
+ 198,
30178
+ 199,
30179
+ 200,
30180
+ 201,
30181
+ 202,
30182
+ 210,
30183
+ 211,
30184
+ 212,
30185
+ 213,
30186
+ 214,
30187
+ 215,
30188
+ 216,
30189
+ 217,
30190
+ 218,
30191
+ 226,
30192
+ 227,
30193
+ 228,
30194
+ 229,
30195
+ 230,
30196
+ 231,
30197
+ 232,
30198
+ 233,
30199
+ 234,
30200
+ 242,
30201
+ 243,
30202
+ 244,
30203
+ 245,
30204
+ 246,
30205
+ 247,
30206
+ 248,
30207
+ 249,
30208
+ 250
30209
+ ];
30210
+ var DC_VALUES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
30211
+ var HUFFMAN = [
30212
+ [0, [0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], DC_VALUES],
30213
+ [16, [0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125], AC_LUMA_VALUES],
30214
+ [1, [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], DC_VALUES],
30215
+ [17, [0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119], AC_CHROMA_VALUES]
30216
+ ];
30217
+ var CODES = HUFFMAN.map(([, counts, values]) => {
30218
+ const table2 = [];
30219
+ let code = 0, at = 0;
30220
+ counts.forEach((count3, index) => {
30221
+ for (let i = 0; i < count3; i++) table2[values[at++]] = [code++, index + 1];
30222
+ code <<= 1;
30223
+ });
30224
+ return table2;
30225
+ });
30226
+ var AAN = [1, 1.387039845, 1.306562965, 1.175875602, 1, 0.785694958, 0.5411961, 0.275899379];
30227
+ function quantTables(quality) {
30228
+ const factor = quality < 50 ? 5e3 / quality : 200 - quality * 2;
30229
+ const scaled = (base) => base.map((value) => Math.min(255, Math.max(1, Math.floor((value * factor + 50) / 100))));
30230
+ const divisors = (table2) => Float64Array.from(table2, (value, k) => 1 / (value * AAN[k >> 3] * AAN[k & 7] * 8));
30231
+ const luma = scaled(LUMA_QUANT), chroma = scaled(CHROMA_QUANT);
30232
+ return { luma, chroma, lumaDivisors: divisors(luma), chromaDivisors: divisors(chroma) };
30233
+ }
30234
+ var BitWriter = class {
30235
+ buffer = Buffer.alloc(65536);
30236
+ length = 0;
30237
+ bits = 0;
30238
+ count = 0;
30239
+ byte(value) {
30240
+ if (this.length === this.buffer.length) {
30241
+ const next = Buffer.alloc(this.buffer.length * 2);
30242
+ this.buffer.copy(next);
30243
+ this.buffer = next;
30244
+ }
30245
+ this.buffer[this.length++] = value;
30246
+ }
30247
+ bytes(values) {
30248
+ for (const value of values) this.byte(value);
30249
+ }
30250
+ write(code, length) {
30251
+ this.bits = (this.bits << length | code) >>> 0;
30252
+ this.count += length;
30253
+ while (this.count >= 8) {
30254
+ const value = this.bits >>> this.count - 8 & 255;
30255
+ this.byte(value);
30256
+ if (value === 255) this.byte(0);
30257
+ this.count -= 8;
30258
+ this.bits &= (1 << this.count) - 1;
30259
+ }
30260
+ }
30261
+ flush() {
30262
+ if (this.count > 0) this.write((1 << 8 - this.count) - 1, 8 - this.count);
30263
+ }
30264
+ result() {
30265
+ return Buffer.from(this.buffer.subarray(0, this.length));
30266
+ }
30267
+ };
30268
+ function transform2(block, divisors, out) {
30269
+ for (let pass = 0; pass < 2; pass++) for (let i = 0; i < 8; i++) {
30270
+ const step = pass ? 8 : 1, base = pass ? i : i * 8, at = (k) => base + k * step;
30271
+ const d0 = block[at(0)], d1 = block[at(1)], d2 = block[at(2)], d3 = block[at(3)], d4 = block[at(4)], d5 = block[at(5)], d6 = block[at(6)], d7 = block[at(7)];
30272
+ const t0 = d0 + d7, t7 = d0 - d7, t1 = d1 + d6, t6 = d1 - d6, t2 = d2 + d5, t5 = d2 - d5, t3 = d3 + d4, t4 = d3 - d4;
30273
+ const t10 = t0 + t3, t13 = t0 - t3, t11 = t1 + t2, t12 = t1 - t2;
30274
+ block[at(0)] = t10 + t11;
30275
+ block[at(4)] = t10 - t11;
30276
+ const z1 = (t12 + t13) * 0.707106781;
30277
+ block[at(2)] = t13 + z1;
30278
+ block[at(6)] = t13 - z1;
30279
+ const o10 = t4 + t5, o11 = t5 + t6, o12 = t6 + t7;
30280
+ const z5 = (o10 - o12) * 0.382683433, z2 = 0.5411961 * o10 + z5, z4 = 1.306562965 * o12 + z5, z3 = o11 * 0.707106781;
30281
+ const z11 = t7 + z3, z13 = t7 - z3;
30282
+ block[at(5)] = z13 + z2;
30283
+ block[at(3)] = z13 - z2;
30284
+ block[at(1)] = z11 + z4;
30285
+ block[at(7)] = z11 - z4;
30286
+ }
30287
+ for (let k = 0; k < 64; k++) out[ZIGZAG[k]] = Math.round(block[k] * divisors[k]);
30288
+ }
30289
+ function magnitude(value) {
30290
+ const absolute2 = Math.abs(value);
30291
+ let length = 0;
30292
+ while (absolute2 >> length) length++;
30293
+ return [value < 0 ? value + (1 << length) - 1 : value, length];
30294
+ }
30295
+ function encodeJpeg(image, quality) {
30296
+ const { width, height, rgb } = image, tables = quantTables(Math.min(100, Math.max(1, Math.round(quality))));
30297
+ const out = new BitWriter(), word = (value) => [value >> 8, value & 255];
30298
+ out.bytes([255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0]);
30299
+ out.bytes([255, 219, 0, 132]);
30300
+ for (const [id2, table2] of [[0, tables.luma], [1, tables.chroma]]) {
30301
+ const zig = new Array(64);
30302
+ table2.forEach((value, k) => {
30303
+ zig[ZIGZAG[k]] = value;
30304
+ });
30305
+ out.bytes([id2, ...zig]);
30306
+ }
30307
+ out.bytes([255, 192, 0, 17, 8, ...word(height), ...word(width), 3, 1, 34, 0, 2, 17, 1, 3, 17, 1]);
30308
+ out.bytes([255, 196, ...word(2 + HUFFMAN.reduce((sum, [, , values]) => sum + 17 + values.length, 0))]);
30309
+ for (const [id2, counts, values] of HUFFMAN) out.bytes([id2, ...counts, ...values]);
30310
+ out.bytes([255, 218, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0]);
30311
+ const block = new Float64Array(64), coefficients = new Int32Array(64), dc = [0, 0, 0];
30312
+ const Y = new Float64Array(256), Cb = new Float64Array(256), Cr = new Float64Array(256);
30313
+ const encode5 = (component, divisors) => {
30314
+ transform2(block, divisors, coefficients);
30315
+ const dcCodes = CODES[component ? 2 : 0], acCodes = CODES[component ? 3 : 1];
30316
+ const diff = coefficients[0] - dc[component];
30317
+ dc[component] = coefficients[0];
30318
+ const [bits, size] = magnitude(diff);
30319
+ out.write(...dcCodes[size]);
30320
+ if (size) out.write(bits, size);
30321
+ let last = 63;
30322
+ while (last > 0 && coefficients[last] === 0) last--;
30323
+ for (let k = 1, zeros = 0; k <= last; k++) {
30324
+ if (coefficients[k] === 0) {
30325
+ zeros++;
30326
+ continue;
30327
+ }
30328
+ while (zeros >= 16) {
30329
+ out.write(...acCodes[240]);
30330
+ zeros -= 16;
30331
+ }
30332
+ const [value, length] = magnitude(coefficients[k]);
30333
+ out.write(...acCodes[(zeros << 4) + length]);
30334
+ out.write(value, length);
30335
+ zeros = 0;
30336
+ }
30337
+ if (last < 63) out.write(...acCodes[0]);
30338
+ };
30339
+ for (let my = 0; my < height; my += 16) for (let mx = 0; mx < width; mx += 16) {
30340
+ for (let y = 0; y < 16; y++) for (let x = 0; x < 16; x++) {
30341
+ const i = (Math.min(height - 1, my + y) * width + Math.min(width - 1, mx + x)) * 3, r = rgb[i], g = rgb[i + 1], b = rgb[i + 2];
30342
+ Y[y * 16 + x] = 0.299 * r + 0.587 * g + 0.114 * b - 128;
30343
+ Cb[y * 16 + x] = -0.168736 * r - 0.331264 * g + 0.5 * b;
30344
+ Cr[y * 16 + x] = 0.5 * r - 0.418688 * g - 0.081312 * b;
30345
+ }
30346
+ for (const [ox, oy] of [[0, 0], [8, 0], [0, 8], [8, 8]]) {
30347
+ for (let y = 0; y < 8; y++) for (let x = 0; x < 8; x++) block[y * 8 + x] = Y[(oy + y) * 16 + ox + x];
30348
+ encode5(0, tables.lumaDivisors);
30349
+ }
30350
+ for (const [component, plane] of [[1, Cb], [2, Cr]]) {
30351
+ for (let y = 0; y < 8; y++) for (let x = 0; x < 8; x++) {
30352
+ const at = y * 32 + x * 2;
30353
+ block[y * 8 + x] = (plane[at] + plane[at + 1] + plane[at + 16] + plane[at + 17]) / 4;
30354
+ }
30355
+ encode5(component, tables.chromaDivisors);
30356
+ }
30357
+ }
30358
+ out.flush();
30359
+ out.bytes([255, 217]);
30360
+ return out.result();
30361
+ }
30362
+ function fitJpeg(image, maxEdge, maxBytes) {
30363
+ for (const edge of [maxEdge, 1280, 1024, 800, 640]) {
30364
+ const scaled = downscale(image, edge);
30365
+ for (const quality of [75, 60, 45, 35]) {
30366
+ const data = encodeJpeg(scaled, quality);
30367
+ if (data.length <= maxBytes) return { data, width: scaled.width, height: scaled.height };
30368
+ }
30369
+ }
30370
+ return null;
30371
+ }
30372
+
30373
+ // agent/src/screen-capture.ts
30374
+ var SCREENSHOT_MAX_JPEG_BYTES = 131072;
30375
+ var SCREENSHOT_MAX_EDGE = 1568;
30376
+ function screenshotEnabled(env = process.env) {
30377
+ return env.LC_SCREENSHOT_ENABLED === "true";
30378
+ }
30379
+ var SCREENSHOT_ACCEPTANCE_FILE = "screenshot-acceptance-enabled";
30380
+ var SCREENSHOT_OWNER_OFF_FILE = "screenshot-disabled-by-owner";
30381
+ var ScreenCaptureError = class extends Error {
30382
+ constructor(code, detail) {
30383
+ super(code);
30384
+ this.code = code;
30385
+ this.detail = detail;
30386
+ this.name = "ScreenCaptureError";
30387
+ }
30388
+ code;
30389
+ detail;
30390
+ };
30391
+ var KNOWN = /^(SCREEN_UNAVAILABLE|SCREEN_LOCKED|SCREEN_ENCODER_UNAVAILABLE|SCREENSHOT_TOO_LARGE|ARGUMENT_INVALID)$/;
30392
+ function jpegSize(data) {
30393
+ if (data.length < 4 || data[0] !== 255 || data[1] !== 216 || data[data.length - 2] !== 255 || data[data.length - 1] !== 217) return null;
30394
+ for (let at = 2; at + 9 < data.length; ) {
30395
+ if (data[at] !== 255) return null;
30396
+ const marker = data[at + 1], length = data.readUInt16BE(at + 2);
30397
+ if (marker >= 192 && marker <= 207 && ![196, 200, 204].includes(marker)) {
30398
+ const height = data.readUInt16BE(at + 5), width = data.readUInt16BE(at + 7);
30399
+ return width > 0 && height > 0 ? { width, height } : null;
30400
+ }
30401
+ at += 2 + length;
30402
+ }
30403
+ return null;
30404
+ }
30405
+ function run(file2, args, signal, maxBuffer = 65536, env = buildChildEnvironment(process.env, process.platform)) {
30406
+ return new Promise((resolve, reject) => {
30407
+ execFile4(
30408
+ file2,
30409
+ args,
30410
+ { encoding: "buffer", timeout: 15e3, maxBuffer, windowsHide: true, shell: false, env, signal },
30411
+ (error62, stdout, stderr) => error62 ? reject(Object.assign(error62, { stdout, stderr })) : resolve({ stdout, stderr })
30412
+ );
30413
+ });
30414
+ }
30415
+ async function windows(bridge, signal) {
30416
+ if (!path17.isAbsolute(bridge)) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
30417
+ let stdout;
30418
+ try {
30419
+ ({ stdout } = await run(bridge, ["screenshot", String(SCREENSHOT_MAX_EDGE), String(SCREENSHOT_MAX_JPEG_BYTES)], signal, 262144));
30420
+ } catch (error62) {
30421
+ if (signal.aborted) throw new ScreenCaptureError("CANCELLED");
30422
+ const code = /^\{"error":"([A-Z_]+)"\}$/.exec(String(error62.stderr ?? ""))?.[1];
30423
+ throw new ScreenCaptureError(code && KNOWN.test(code) ? code : "SCREEN_UNAVAILABLE");
30424
+ }
30425
+ try {
30426
+ const value = JSON.parse(stdout.toString("utf8"));
30427
+ const data = Buffer.from(value.data, "base64"), size = jpegSize(data);
30428
+ if (!size || size.width !== value.width || size.height !== value.height || !Number.isSafeInteger(value.sourceWidth) || !Number.isSafeInteger(value.sourceHeight)) throw Error();
30429
+ return { data, width: size.width, height: size.height, sourceWidth: value.sourceWidth, sourceHeight: value.sourceHeight };
30430
+ } catch {
30431
+ throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
30432
+ }
30433
+ }
30434
+ async function mac3(signal) {
30435
+ try {
30436
+ const preflight = await run("/usr/bin/osascript", ["-l", "JavaScript", "-e", "ObjC.import('CoreGraphics'); $.CGPreflightScreenCaptureAccess()"], signal);
30437
+ if (preflight.stdout.toString("utf8").trim() !== "true") {
30438
+ await run("/usr/bin/osascript", ["-l", "JavaScript", "-e", "ObjC.import('CoreGraphics'); $.CGRequestScreenCaptureAccess()"], signal).catch(() => {
30439
+ });
30440
+ throw new ScreenCaptureError("SCREEN_RECORDING_PERMISSION_REQUIRED");
30441
+ }
30442
+ } catch (error62) {
30443
+ if (error62 instanceof ScreenCaptureError) throw error62;
30444
+ throw new ScreenCaptureError(signal.aborted ? "CANCELLED" : "SCREEN_UNAVAILABLE");
30445
+ }
30446
+ const folder = await mkdtemp(path17.join(os4.tmpdir(), "lc-screen-"));
30447
+ try {
30448
+ const full = path17.join(folder, "full.png"), small = path17.join(folder, "small.jpg");
30449
+ try {
30450
+ await run("/usr/sbin/screencapture", ["-x", "-m", "-t", "png", full], signal);
30451
+ } catch {
30452
+ throw new ScreenCaptureError(signal.aborted ? "CANCELLED" : "SCREEN_UNAVAILABLE");
30453
+ }
30454
+ const source = (await run("/usr/bin/sips", ["-g", "pixelWidth", "-g", "pixelHeight", full], signal)).stdout.toString("utf8");
30455
+ const sourceWidth = Number(/pixelWidth: (\d+)/.exec(source)?.[1]), sourceHeight = Number(/pixelHeight: (\d+)/.exec(source)?.[1]);
30456
+ if (!sourceWidth || !sourceHeight) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
30457
+ for (const edge of [SCREENSHOT_MAX_EDGE, 1280, 1024, 800, 640]) {
30458
+ const target = Math.min(edge, Math.max(sourceWidth, sourceHeight));
30459
+ for (const quality of [75, 60, 45, 35]) {
30460
+ await run("/usr/bin/sips", ["-Z", String(target), "-s", "format", "jpeg", "-s", "formatOptions", String(quality), full, "--out", small], signal);
30461
+ const data = await readFile6(small), size = jpegSize(data);
30462
+ if (!size) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
30463
+ if (data.length <= SCREENSHOT_MAX_JPEG_BYTES) return { data, ...size, sourceWidth, sourceHeight };
30464
+ }
30465
+ }
30466
+ throw new ScreenCaptureError("SCREENSHOT_TOO_LARGE");
30467
+ } catch (error62) {
30468
+ if (error62 instanceof ScreenCaptureError) throw error62;
30469
+ throw new ScreenCaptureError(signal.aborted ? "CANCELLED" : "SCREEN_UNAVAILABLE");
30470
+ } finally {
30471
+ await rm5(folder, { recursive: true, force: true }).catch(() => {
30472
+ });
30473
+ }
30474
+ }
30475
+ var SESSION_KEYS = ["DISPLAY", "WAYLAND_DISPLAY", "XAUTHORITY", "XDG_RUNTIME_DIR", "DBUS_SESSION_BUS_ADDRESS", "XDG_SESSION_TYPE", "XDG_CURRENT_DESKTOP"];
30476
+ var SESSION_VALUE = /^[A-Za-z0-9_.:,;=@+/-]{1,256}$/;
30477
+ var LINUX_SOURCE_BYTES = 150994944;
30478
+ async function linuxTool(name2) {
30479
+ for (const directory of ["/usr/bin", "/bin", "/usr/local/bin"]) {
30480
+ const file2 = path17.posix.join(directory, name2);
30481
+ try {
30482
+ await access3(file2, constants7.X_OK);
30483
+ return file2;
30484
+ } catch {
30485
+ }
30486
+ }
30487
+ return null;
30488
+ }
30489
+ async function linuxSession(signal) {
30490
+ const session = {}, uid = process.getuid?.();
30491
+ const take = (key, value) => {
30492
+ if (value && !session[key] && SESSION_VALUE.test(value)) session[key] = value;
30493
+ };
30494
+ const base = buildChildEnvironment(process.env, "linux");
30495
+ for (const key of SESSION_KEYS) take(key, process.env[key]);
30496
+ if (!session.DISPLAY && !session.WAYLAND_DISPLAY) {
30497
+ const systemctl = await linuxTool("systemctl");
30498
+ if (systemctl) try {
30499
+ const { stdout } = await run(systemctl, ["--user", "show-environment"], signal, 262144, base);
30500
+ for (const line of stdout.toString("utf8").split("\n")) {
30501
+ const at = line.indexOf("=");
30502
+ if (at > 0 && SESSION_KEYS.includes(line.slice(0, at))) take(line.slice(0, at), line.slice(at + 1));
30503
+ }
30504
+ } catch {
30505
+ if (signal.aborted) throw new ScreenCaptureError("CANCELLED");
30506
+ }
30507
+ }
30508
+ if (uid !== void 0) take("XDG_RUNTIME_DIR", "/run/user/" + uid);
30509
+ if (!session.DISPLAY && !session.WAYLAND_DISPLAY) {
30510
+ if (session.XDG_RUNTIME_DIR) for (const name2 of ["wayland-0", "wayland-1"]) {
30511
+ const socket = await lstat7(path17.posix.join(session.XDG_RUNTIME_DIR, name2)).catch(() => null);
30512
+ if (socket?.isSocket() && socket.uid === uid) {
30513
+ session.WAYLAND_DISPLAY = name2;
30514
+ break;
30515
+ }
30516
+ }
30517
+ if (!session.WAYLAND_DISPLAY) {
30518
+ const servers = [];
30519
+ for (const name2 of await readdir4("/tmp/.X11-unix").catch(() => [])) {
30520
+ const n = /^X(\d{1,4})$/.exec(name2)?.[1], socket = n ? await lstat7("/tmp/.X11-unix/" + name2).catch(() => null) : null;
30521
+ if (n && socket?.isSocket()) servers.push({ n: Number(n), own: socket.uid === uid });
30522
+ }
30523
+ const server = servers.sort((a, b) => Number(b.own) - Number(a.own) || a.n - b.n)[0];
30524
+ if (server) session.DISPLAY = ":" + server.n;
30525
+ }
30526
+ }
30527
+ if (session.DISPLAY && !session.XAUTHORITY) {
30528
+ const file2 = path17.posix.join(os4.homedir(), ".Xauthority");
30529
+ if ((await lstat7(file2).catch(() => null))?.isFile()) take("XAUTHORITY", file2);
30530
+ }
30531
+ if (session.XDG_RUNTIME_DIR) take("DBUS_SESSION_BUS_ADDRESS", "unix:path=" + session.XDG_RUNTIME_DIR + "/bus");
30532
+ const wayland = !!session.WAYLAND_DISPLAY || session.XDG_SESSION_TYPE === "wayland";
30533
+ return { env: { ...base, ...session }, wayland, x11: !wayland && !!session.DISPLAY };
30534
+ }
30535
+ async function busSocket(env) {
30536
+ const socket = sessionBusSocket(env.DBUS_SESSION_BUS_ADDRESS);
30537
+ if (!socket || socket.startsWith("\0")) return socket;
30538
+ return (await lstat7(socket).catch(() => null))?.isSocket() ? socket : null;
30539
+ }
30540
+ async function portalCapture(socket, signal) {
30541
+ const token = "lc" + randomBytes6(8).toString("hex"), started = Date.now(), uid = process.getuid?.();
30542
+ if (uid === void 0) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
30543
+ let answer;
30544
+ try {
30545
+ answer = await portalScreenshot(socket, uid, token, AbortSignal.any([signal, AbortSignal.timeout(3e4)]));
30546
+ } catch {
30547
+ throw new ScreenCaptureError(signal.aborted ? "CANCELLED" : "SCREEN_UNAVAILABLE");
30548
+ }
30549
+ const { code, uri } = answer;
30550
+ if (code === 1) throw new ScreenCaptureError("SCREEN_RECORDING_PERMISSION_REQUIRED");
30551
+ if (code !== 0 || !uri?.startsWith("file://")) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
30552
+ const file2 = decodeURIComponent(new URL(uri).pathname), info = await lstat7(file2);
30553
+ const fresh = info.isFile() && info.uid === uid && info.mtimeMs >= started - 5e3;
30554
+ try {
30555
+ if (!fresh || info.size > LINUX_SOURCE_BYTES) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
30556
+ return await readFile6(file2);
30557
+ } finally {
30558
+ if (fresh) await unlink2(file2).catch(() => {
30559
+ });
30560
+ }
30561
+ }
30562
+ async function linux(signal) {
30563
+ const session = await linuxSession(signal);
30564
+ if (!session.wayland && !session.x11) throw new ScreenCaptureError("SCREENSHOT_UNSUPPORTED", { reason: "NO_DISPLAY" });
30565
+ const output2 = (args) => async (tool) => (await run(tool, args, signal, LINUX_SOURCE_BYTES, session.env)).stdout;
30566
+ const portal = (socket) => portalCapture(socket, signal);
30567
+ const methods = session.wayland ? [["grim", "grim", output2(["-t", "png", "-"])], ["portal", "", portal]] : [
30568
+ ["xwd", "xwd", output2(["-root", "-silent"])],
30569
+ ["import", "import", output2(["-silent", "-window", "root", "png:-"])],
30570
+ ["maim", "maim", output2(["-f", "png"])],
30571
+ ["portal", "", portal]
30572
+ ];
30573
+ const tried = [];
30574
+ for (const [name2, program, capture2] of methods) {
30575
+ const tool = program ? await linuxTool(program) : await busSocket(session.env);
30576
+ if (!tool) {
30577
+ tried.push(name2 + ":missing");
30578
+ continue;
30579
+ }
30580
+ let image;
30581
+ try {
30582
+ const source = await capture2(tool);
30583
+ image = decodePng(source) ?? decodeXwd(source);
30584
+ } catch (error62) {
30585
+ if (signal.aborted) throw new ScreenCaptureError("CANCELLED");
30586
+ if (error62 instanceof ScreenCaptureError && error62.code === "SCREEN_RECORDING_PERMISSION_REQUIRED") throw error62;
30587
+ tried.push(name2 + ":failed");
30588
+ continue;
30589
+ }
30590
+ if (!image) {
30591
+ tried.push(name2 + ":unreadable");
30592
+ continue;
30593
+ }
30594
+ const fitted = fitJpeg(image, SCREENSHOT_MAX_EDGE, SCREENSHOT_MAX_JPEG_BYTES);
30595
+ if (!fitted) throw new ScreenCaptureError("SCREENSHOT_TOO_LARGE");
30596
+ return { ...fitted, sourceWidth: image.width, sourceHeight: image.height };
30597
+ }
30598
+ throw new ScreenCaptureError("SCREENSHOT_UNSUPPORTED", {
30599
+ reason: tried.every((entry) => entry.endsWith(":missing")) ? "NO_CAPTURE_TOOL" : "CAPTURE_FAILED",
30600
+ session: session.wayland ? "wayland" : "x11",
30601
+ tried
30602
+ });
30603
+ }
30604
+ async function captureScreen(options) {
30605
+ if (options.signal.aborted) throw new ScreenCaptureError("CANCELLED");
30606
+ if (process.platform === "win32") return windows(options.ownerBridgePath, options.signal);
30607
+ if (process.platform === "darwin") return mac3(options.signal);
30608
+ if (process.platform === "linux") return linux(options.signal);
30609
+ throw new ScreenCaptureError("SCREENSHOT_UNSUPPORTED", { reason: "PLATFORM_UNSUPPORTED" });
30610
+ }
30611
+
29338
30612
  // agent/src/tools.ts
29339
30613
  var NativeToolError = class extends Error {
29340
30614
  constructor(code) {
@@ -29365,7 +30639,7 @@ function stopped(signal) {
29365
30639
  if (signal.aborted) fail3("CANCELLED");
29366
30640
  }
29367
30641
  async function readBoundedFile(file2, maxBytes, bridge, signal) {
29368
- const stat2 = await lstat7(file2);
30642
+ const stat2 = await lstat8(file2);
29369
30643
  if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > maxBytes) fail3("FILE_UNSUPPORTED_OR_TOO_LARGE");
29370
30644
  if (process.platform === "win32") {
29371
30645
  if (maxBytes <= 1048576 || stat2.size <= 1048576) return readWindowsFile(bridge, file2, Math.min(maxBytes, 1048576), signal);
@@ -29373,7 +30647,7 @@ async function readBoundedFile(file2, maxBytes, bridge, signal) {
29373
30647
  if (read.truncated) fail3("FILE_UNSUPPORTED_OR_TOO_LARGE");
29374
30648
  return read.data;
29375
30649
  }
29376
- const handle = await open6(file2, constants7.O_RDONLY | (constants7.O_NOFOLLOW ?? 0));
30650
+ const handle = await open6(file2, constants8.O_RDONLY | (constants8.O_NOFOLLOW ?? 0));
29377
30651
  try {
29378
30652
  const current2 = await handle.stat();
29379
30653
  if (!current2.isFile() || current2.size > maxBytes) fail3("FILE_UNSUPPORTED_OR_TOO_LARGE");
@@ -29425,13 +30699,13 @@ var NativeTools = class {
29425
30699
  constructor(options) {
29426
30700
  this.options = options;
29427
30701
  this.options = structuredClone(options);
29428
- this.memory = new HostMemory(path17.join(options.stateDirectory, "host-memory.json"), Object.keys(options.programs), Object.fromEntries(Object.entries(options.programs).map(([name2, program]) => [name2, program.executable])));
30702
+ this.memory = new HostMemory(path18.join(options.stateDirectory, "host-memory.json"), Object.keys(options.programs), Object.fromEntries(Object.entries(options.programs).map(([name2, program]) => [name2, program.executable])));
29429
30703
  }
29430
30704
  options;
29431
30705
  memory;
29432
30706
  async readFile(file2, maxBytes, signal) {
29433
30707
  try {
29434
- return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path17.join(path17.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
30708
+ return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
29435
30709
  } catch (error62) {
29436
30710
  if (error62.code === "ENOENT") throw error62;
29437
30711
  if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail3(error62.message);
@@ -29441,31 +30715,31 @@ var NativeTools = class {
29441
30715
  /** Windows only: up to 64 files of at most 1 MiB in one bridge process, each with its own result. */
29442
30716
  async readFiles(files, maxTotalBytes, signal) {
29443
30717
  try {
29444
- return await readWindowsFiles(this.options.ownerBridgePath ?? path17.join(path17.dirname(this.options.helperPath), "OwnerBridge.exe"), files, 1048576, maxTotalBytes, signal);
30718
+ return await readWindowsFiles(this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe"), files, 1048576, maxTotalBytes, signal);
29445
30719
  } catch (error62) {
29446
30720
  if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail3(error62.message);
29447
30721
  throw error62;
29448
30722
  }
29449
30723
  }
29450
- async prepare(workspace2, candidate, selection) {
30724
+ async prepare(workspace2, candidate, selection2) {
29451
30725
  let prepared;
29452
30726
  try {
29453
30727
  let projectRoot;
29454
- if (selection) {
29455
- const target = ProjectTargetBindingSchema.parse(selection);
30728
+ if (selection2) {
30729
+ const target = ProjectTargetBindingSchema.parse(selection2);
29456
30730
  if (workspace2.rootHash !== target.workspaceRootHash) fail3("PROJECT_IDENTITY_MISMATCH");
29457
30731
  const identity = await this.prepareTool(workspace2, { name: "project_identity", args: { path: target.relativePath } });
29458
30732
  const proof2 = JSON.parse((await identity.run(AbortSignal.timeout(15e3))).stdout);
29459
30733
  if (!proof2.repositoryFingerprint) fail3("PROJECT_IDENTITY_UNKNOWN");
29460
30734
  if (proof2.repositoryFingerprint !== target.repositoryFingerprint) fail3("PROJECT_IDENTITY_MISMATCH");
29461
- projectRoot = path17.resolve(workspace2.root, target.relativePath);
30735
+ projectRoot = path18.resolve(workspace2.root, target.relativePath);
29462
30736
  const common = identity.claims.find((claim2) => claim2.namespace === "git")?.path;
29463
30737
  if (common) workspace2 = { ...workspace2, gitCommonDir: common };
29464
30738
  }
29465
30739
  prepared = await this.prepareTool(workspace2, candidate, projectRoot);
29466
30740
  } catch (error62) {
29467
30741
  const parsed = ToolCallSchema.safeParse(candidate);
29468
- if (parsed.success && parsed.data.name === "command_run") await this.memory.record({ ...parsed.data.args, cwd: path17.resolve(workspace2.root, parsed.data.args.cwd ?? ".") }, void 0, error62).catch(() => {
30742
+ if (parsed.success && parsed.data.name === "command_run") await this.memory.record({ ...parsed.data.args, cwd: path18.resolve(workspace2.root, parsed.data.args.cwd ?? ".") }, void 0, error62).catch(() => {
29469
30743
  });
29470
30744
  throw error62;
29471
30745
  }
@@ -29485,17 +30759,17 @@ var NativeTools = class {
29485
30759
  try {
29486
30760
  const canonical2 = await realpath7(workspace2.root);
29487
30761
  if (!equalPath3(canonical2, workspace2.root) || hash6(process.platform === "win32" ? canonical2.toLowerCase() : canonical2) !== workspace2.rootHash) fail3("WORKSPACE_CHANGED");
29488
- const runtimeDirectory = path17.dirname(this.options.helperPath);
30762
+ const runtimeDirectory = path18.dirname(this.options.helperPath);
29489
30763
  const protectedPaths = [
29490
30764
  this.options.stateDirectory,
29491
30765
  this.options.helperPath,
29492
- ...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe", "node", "owner-store", "posix-host", "job-host.mjs", "lifecycle.mjs", "manifest.json"].map((name2) => path17.join(runtimeDirectory, name2))
30766
+ ...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe", "node", "owner-store", "posix-host", "job-host.mjs", "lifecycle.mjs", "manifest.json"].map((name2) => path18.join(runtimeDirectory, name2))
29493
30767
  ];
29494
30768
  if (this.options.ownerBridgePath) protectedPaths.push(this.options.ownerBridgePath);
29495
- if (process.platform === "win32" && process.env.LOCALAPPDATA && path17.isAbsolute(process.env.LOCALAPPDATA)) {
29496
- protectedPaths.push(path17.join(process.env.LOCALAPPDATA, "LocalCommander"));
30769
+ if (process.platform === "win32" && process.env.LOCALAPPDATA && path18.isAbsolute(process.env.LOCALAPPDATA)) {
30770
+ protectedPaths.push(path18.join(process.env.LOCALAPPDATA, "LocalCommander"));
29497
30771
  }
29498
- if (process.platform !== "win32") protectedPaths.push(path17.join(process.env.LC_AGENT_DATA_DIR || posixDataHome(), "LocalCommander"));
30772
+ if (process.platform !== "win32") protectedPaths.push(path18.join(process.env.LC_AGENT_DATA_DIR || posixDataHome(), "LocalCommander"));
29499
30773
  guard = await PathGuard.create([canonical2], false, { protectedPaths });
29500
30774
  if (projectRoot) {
29501
30775
  const selected = await guard.resolveDirectory(projectRoot);
@@ -29584,7 +30858,7 @@ var NativeTools = class {
29584
30858
  }
29585
30859
  if (taken === first - 1 && first <= end) fail3("OUTPUT_LIMIT_EXCEEDED");
29586
30860
  const remaining = lines.length - (lines.length > 1 && lines.at(-1) === "" ? 1 : 0);
29587
- return result({ path: path17.relative(workspace2.root, filename), sha256: hash6(bytes3), startLine: first, endLine: Math.min(taken === first - 1 ? last : taken, lines.length), totalLines: lines.length, content: lines.slice(first - 1, taken).join("\n"), truncated: taken < remaining });
30861
+ return result({ path: path18.relative(workspace2.root, filename), sha256: hash6(bytes3), startLine: first, endLine: Math.min(taken === first - 1 ? last : taken, lines.length), totalLines: lines.length, content: lines.slice(first - 1, taken).join("\n"), truncated: taken < remaining });
29588
30862
  } };
29589
30863
  }
29590
30864
  if (call.name === "fs_write" || call.name === "fs_replace") {
@@ -29627,8 +30901,8 @@ var NativeTools = class {
29627
30901
  bytes3 = encodeText(pieces.join(newText), original.encoding);
29628
30902
  }
29629
30903
  if (bytes3.length > MAX_FILE_WRITE_BYTES) fail3("FILE_WRITE_LIMIT");
29630
- const temp = path17.join(path17.dirname(target), ".lc-write-" + randomUUID7() + ".tmp");
29631
- const handle = await open6(temp, constants7.O_CREAT | constants7.O_EXCL | constants7.O_WRONLY, 384);
30904
+ const temp = path18.join(path18.dirname(target), ".lc-write-" + randomUUID7() + ".tmp");
30905
+ const handle = await open6(temp, constants8.O_CREAT | constants8.O_EXCL | constants8.O_WRONLY, 384);
29632
30906
  try {
29633
30907
  await handle.writeFile(bytes3);
29634
30908
  await handle.sync();
@@ -29644,7 +30918,7 @@ var NativeTools = class {
29644
30918
  break;
29645
30919
  } catch (error62) {
29646
30920
  if (process.platform !== "win32" || !["EPERM", "EBUSY", "EACCES"].includes(error62.code ?? "")) throw error62;
29647
- if (attempt === 4) fail3((await lstat7(target)).mode & 128 ? "FILE_IN_USE" : "FILE_READ_ONLY");
30921
+ if (attempt === 4) fail3((await lstat8(target)).mode & 128 ? "FILE_IN_USE" : "FILE_READ_ONLY");
29648
30922
  await delay2(50 << attempt);
29649
30923
  stopped(signal);
29650
30924
  }
@@ -29659,18 +30933,18 @@ var NativeTools = class {
29659
30933
  }
29660
30934
  for (let attempt = 0; attempt < 3; attempt++) {
29661
30935
  try {
29662
- await rm5(temp);
30936
+ await rm6(temp);
29663
30937
  break;
29664
30938
  } catch {
29665
30939
  await delay2(100);
29666
30940
  }
29667
30941
  }
29668
30942
  }
29669
- return result({ path: path17.relative(workspace2.root, target), bytes: bytes3.length, sha256: hash6(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
30943
+ return result({ path: path18.relative(workspace2.root, target), bytes: bytes3.length, sha256: hash6(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
29670
30944
  } catch (e) {
29671
30945
  await handle.close().catch(() => {
29672
30946
  });
29673
- await rm5(temp, { force: true }).catch(() => {
30947
+ await rm6(temp, { force: true }).catch(() => {
29674
30948
  });
29675
30949
  throw e;
29676
30950
  }
@@ -29692,7 +30966,7 @@ var NativeTools = class {
29692
30966
  const lines = decodeText(bytes3).text.split(/\r?\n/);
29693
30967
  scanned++;
29694
30968
  for (let i = 0; i < lines.length && matches2.length < call.args.maxResults; i++) if ((call.args.caseSensitive ? lines[i] : lines[i].toLowerCase()).includes(query)) {
29695
- const match = { path: path17.relative(workspace2.root, filename), line: i + 1, text: lines[i].slice(0, 500) };
30969
+ const match = { path: path18.relative(workspace2.root, filename), line: i + 1, text: lines[i].slice(0, 500) };
29696
30970
  if ((room -= Buffer.byteLength(JSON.stringify(match)) + 1) < 0) {
29697
30971
  incomplete = true;
29698
30972
  break;
@@ -29735,7 +31009,7 @@ var NativeTools = class {
29735
31009
  continue;
29736
31010
  }
29737
31011
  try {
29738
- const filename = await guard.resolveExisting(path17.join(base, entry.path));
31012
+ const filename = await guard.resolveExisting(path18.join(base, entry.path));
29739
31013
  guard.assertSafeFile(filename);
29740
31014
  if (!batched) {
29741
31015
  searchFile(filename, await this.readFile(filename, 1048576, signal));
@@ -29759,6 +31033,42 @@ var NativeTools = class {
29759
31033
  return result({ matches: matches2, scannedFiles: scanned, truncated: listing.truncated || incomplete || matches2.length >= call.args.maxResults || scanned >= 300 });
29760
31034
  } };
29761
31035
  }
31036
+ if (call.name === "take_screenshot") {
31037
+ if (!screenshotEnabled() && !await lstat8(path18.join(this.options.stateDirectory, SCREENSHOT_ACCEPTANCE_FILE)).then((s) => s.isFile(), () => false)) fail3("SCREENSHOT_DISABLED");
31038
+ if (!workspace2.fullAccess) fail3("FULL_ACCESS_REQUIRED");
31039
+ if (await lstat8(path18.join(this.options.stateDirectory, SCREENSHOT_OWNER_OFF_FILE)).then(() => true, (error62) => error62.code !== "ENOENT")) fail3("SCREENSHOT_DISABLED_BY_OWNER");
31040
+ const bridge = this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe");
31041
+ return { call, claims: [{ path: path18.join(this.options.stateDirectory, "screen-capture"), mode: "read" }], run: async (signal) => {
31042
+ let shot;
31043
+ try {
31044
+ shot = await captureScreen({ ownerBridgePath: bridge, signal });
31045
+ } catch (error62) {
31046
+ if (error62 instanceof ScreenCaptureError && error62.detail) return {
31047
+ exitCode: 1,
31048
+ timedOut: false,
31049
+ cancelled: false,
31050
+ treeTerminated: true,
31051
+ stdout: JSON.stringify({ type: "screenshot_error", resultCode: error62.code, ...error62.detail }),
31052
+ stderr: "",
31053
+ stdoutTruncated: false,
31054
+ stderrTruncated: false,
31055
+ resultCode: error62.code
31056
+ };
31057
+ fail3(error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message) ? error62.message : "SCREEN_UNAVAILABLE");
31058
+ }
31059
+ return result({
31060
+ type: "screenshot",
31061
+ mimeType: "image/jpeg",
31062
+ width: shot.width,
31063
+ height: shot.height,
31064
+ sourceWidth: shot.sourceWidth,
31065
+ sourceHeight: shot.sourceHeight,
31066
+ bytes: shot.data.length,
31067
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
31068
+ data: shot.data.toString("base64")
31069
+ });
31070
+ } };
31071
+ }
29762
31072
  if (call.name === "localhost_request") {
29763
31073
  const url2 = new URL(call.args.url), port = Number(url2.port || (url2.protocol === "https:" ? 443 : 80));
29764
31074
  if (!["http:", "https:"].includes(url2.protocol) || !["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname) || url2.username || url2.password || url2.hash || (workspace2.fullAccess ? workspace2.deniedLocalhostPorts?.includes(port) : !workspace2.localhostPorts.includes(port)) || this.options.protectedPorts?.includes(port)) fail3("LOCALHOST_NOT_ALLOWED");
@@ -29829,9 +31139,9 @@ var NativeTools = class {
29829
31139
  else if (call.name === "git_diff") {
29830
31140
  argv = ["diff", "--no-ext-diff", "--no-textconv", ...call.args.staged ? ["--cached"] : []];
29831
31141
  if (call.args.file) {
29832
- const file2 = await resolve(path17.resolve(cwd, call.args.file));
29833
- const relative = path17.relative(cwd, file2);
29834
- if (relative.startsWith(".." + path17.sep) || relative === ".." || path17.isAbsolute(relative)) fail3("PATH_NOT_ALLOWED");
31142
+ const file2 = await resolve(path18.resolve(cwd, call.args.file));
31143
+ const relative = path18.relative(cwd, file2);
31144
+ if (relative.startsWith(".." + path18.sep) || relative === ".." || path18.isAbsolute(relative)) fail3("PATH_NOT_ALLOWED");
29835
31145
  argv.push("--", relative);
29836
31146
  } else argv.push("--stat");
29837
31147
  } else fail3("TOOL_MISSING");
@@ -29842,7 +31152,7 @@ var NativeTools = class {
29842
31152
  const listing = await this.list(guard, cwd, 1, call.args.startup ? 20 : 150, signal);
29843
31153
  let packageInfo = null;
29844
31154
  try {
29845
- const name2 = await guard.resolveExisting(path17.join(cwd, "package.json"));
31155
+ const name2 = await guard.resolveExisting(path18.join(cwd, "package.json"));
29846
31156
  guard.assertSafeFile(name2);
29847
31157
  const value = JSON.parse(utf8(await this.readFile(name2, 64e3, signal)));
29848
31158
  packageInfo = { name: typeof value.name === "string" ? value.name : null, version: typeof value.version === "string" ? value.version : null, scripts: value.scripts && typeof value.scripts === "object" ? Object.keys(value.scripts).slice(0, 100) : [] };
@@ -29862,7 +31172,7 @@ var NativeTools = class {
29862
31172
  }
29863
31173
  const contextFile = async (relative, limit, optional2 = false) => {
29864
31174
  try {
29865
- const file2 = await guard.resolveExisting(path17.join(primary, relative));
31175
+ const file2 = await guard.resolveExisting(path18.join(primary, relative));
29866
31176
  guard.assertSafeFile(file2);
29867
31177
  return utf8(await this.readFile(file2, limit, signal));
29868
31178
  } catch (error62) {
@@ -29895,19 +31205,19 @@ var NativeTools = class {
29895
31205
  } };
29896
31206
  }
29897
31207
  async resolveProgram(name2, workspace2, args) {
29898
- const entry = Object.entries(this.options.programs).find(([key, value]) => equalPath3(key, name2) || path17.isAbsolute(name2) && equalPath3(value.executable, path17.resolve(name2)));
31208
+ const entry = Object.entries(this.options.programs).find(([key, value]) => equalPath3(key, name2) || path18.isAbsolute(name2) && equalPath3(value.executable, path18.resolve(name2)));
29899
31209
  if (workspace2.fullAccess) {
29900
- const commandKey = (value) => process.platform === "win32" ? path17.basename(value).toLowerCase().replace(/\.(exe|com|cmd|bat)$/i, "") : path17.basename(value);
31210
+ const commandKey = (value) => process.platform === "win32" ? path18.basename(value).toLowerCase().replace(/\.(exe|com|cmd|bat)$/i, "") : path18.basename(value);
29901
31211
  const denied = new Set((workspace2.deniedCommands ?? []).map(commandKey));
29902
31212
  if (denied.has(commandKey(name2)) || entry && denied.has(commandKey(entry[0]))) fail3("COMMAND_NOT_ALLOWED");
29903
- const extension2 = path17.extname(name2).toLowerCase();
29904
- const candidate = entry?.[1].executable ?? (process.platform !== "win32" ? await resolvePosixExecutable(name2) : path17.isAbsolute(name2) ? name2 : /^[\w.-]+$/.test(name2) ? resolveWindowsLauncher(
31213
+ const extension2 = path18.extname(name2).toLowerCase();
31214
+ const candidate = entry?.[1].executable ?? (process.platform !== "win32" ? await resolvePosixExecutable(name2) : path18.isAbsolute(name2) ? name2 : /^[\w.-]+$/.test(name2) ? resolveWindowsLauncher(
29905
31215
  commandKey(name2),
29906
31216
  [".exe", ".com", ".cmd", ".bat"].includes(extension2) ? { ...process.env, PATHEXT: extension2 } : process.env
29907
31217
  )?.file : void 0);
29908
- if (!candidate || !path17.isAbsolute(candidate)) fail3("COMMAND_NOT_FOUND");
31218
+ if (!candidate || !path18.isAbsolute(candidate)) fail3("COMMAND_NOT_FOUND");
29909
31219
  const executable = await realpath7(candidate).catch(() => fail3("COMMAND_NOT_FOUND"));
29910
- if (!(await lstat7(executable)).isFile()) fail3("COMMAND_NOT_FOUND");
31220
+ if (!(await lstat8(executable)).isFile()) fail3("COMMAND_NOT_FOUND");
29911
31221
  if (denied.has(commandKey(executable))) fail3("COMMAND_NOT_ALLOWED");
29912
31222
  for (const key of workspace2.deniedCommands ?? []) {
29913
31223
  const configured = this.options.programs[key]?.executable;
@@ -29920,7 +31230,7 @@ var NativeTools = class {
29920
31230
  if (/\.(cmd|bat)$/i.test(executable)) {
29921
31231
  if ([executable, ...args].some((value) => /[&|<>^%!"\r\n]/.test(value))) fail3("INVALID_SCRIPT_ARGUMENTS");
29922
31232
  const literal2 = (value) => "'" + value.replaceAll("'", "''") + "'";
29923
- const shell = path17.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
31233
+ const shell = path18.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
29924
31234
  if (denied.has("powershell") || denied.has("cmd")) fail3("COMMAND_NOT_ALLOWED");
29925
31235
  const script = "& " + literal2(executable) + " @(" + args.map(literal2).join(",") + "); exit $LASTEXITCODE";
29926
31236
  return { executable: shell, args: ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")] };
@@ -29928,7 +31238,7 @@ var NativeTools = class {
29928
31238
  if (!/\.(exe|com)$/i.test(executable)) fail3("COMMAND_NOT_ALLOWED");
29929
31239
  return { executable, args: [...entry?.[1].prefixArgs ?? [], ...args] };
29930
31240
  }
29931
- if (!entry || !workspace2.allowedCommands.some((v) => equalPath3(v, entry[0])) || !path17.isAbsolute(entry[1].executable)) fail3("COMMAND_NOT_ALLOWED");
31241
+ if (!entry || !workspace2.allowedCommands.some((v) => equalPath3(v, entry[0])) || !path18.isAbsolute(entry[1].executable)) fail3("COMMAND_NOT_ALLOWED");
29932
31242
  return { executable: entry[1].executable, args: [...entry[1].prefixArgs ?? [], ...args] };
29933
31243
  }
29934
31244
  async memoryContext(workspace2) {
@@ -29943,13 +31253,13 @@ var NativeTools = class {
29943
31253
  async gitExecution(cwd, args) {
29944
31254
  if (!["win32", "linux", "darwin"].includes(process.platform)) fail3("COMMAND_NOT_ALLOWED");
29945
31255
  const configured = this.options.programs.git;
29946
- const candidates = configured ? [configured.executable] : process.platform === "win32" ? [[process.env.ProgramFiles, "Git"], [process.env["ProgramFiles(x86)"], "Git"], [process.env.LOCALAPPDATA, "Programs/Git"]].filter(([root]) => root && path17.isAbsolute(root)).map(([root, suffix]) => path17.join(root, suffix, "cmd", "git.exe")) : ["/usr/bin/git", "/usr/local/bin/git", "/opt/homebrew/bin/git"];
31256
+ const candidates = configured ? [configured.executable] : process.platform === "win32" ? [[process.env.ProgramFiles, "Git"], [process.env["ProgramFiles(x86)"], "Git"], [process.env.LOCALAPPDATA, "Programs/Git"]].filter(([root]) => root && path18.isAbsolute(root)).map(([root, suffix]) => path18.join(root, suffix, "cmd", "git.exe")) : ["/usr/bin/git", "/usr/local/bin/git", "/opt/homebrew/bin/git"];
29947
31257
  for (const source of candidates) {
29948
- if (!path17.isAbsolute(source)) continue;
31258
+ if (!path18.isAbsolute(source)) continue;
29949
31259
  const candidate = process.platform === "win32" ? source : await resolvePosixExecutable(source);
29950
31260
  if (!candidate) continue;
29951
31261
  try {
29952
- const stat2 = await lstat7(candidate);
31262
+ const stat2 = await lstat8(candidate);
29953
31263
  if (!stat2.isFile() || stat2.isSymbolicLink() || !equalPath3(candidate, await realpath7(candidate))) continue;
29954
31264
  } catch {
29955
31265
  continue;
@@ -29967,7 +31277,7 @@ var NativeTools = class {
29967
31277
  const current2 = queue.shift();
29968
31278
  let names;
29969
31279
  try {
29970
- names = await readdir4(current2.path, { withFileTypes: true });
31280
+ names = await readdir5(current2.path, { withFileTypes: true });
29971
31281
  } catch (error62) {
29972
31282
  if (current2.level === 0) throw error62;
29973
31283
  continue;
@@ -29979,7 +31289,7 @@ var NativeTools = class {
29979
31289
  break;
29980
31290
  }
29981
31291
  if (item.isSymbolicLink() || excluded.has(item.name.toLowerCase())) continue;
29982
- const candidate = path17.join(current2.path, item.name);
31292
+ const candidate = path18.join(current2.path, item.name);
29983
31293
  let resolved;
29984
31294
  try {
29985
31295
  resolved = await guard.resolveExisting(candidate);
@@ -29989,11 +31299,11 @@ var NativeTools = class {
29989
31299
  }
29990
31300
  if (!equalPath3(candidate, resolved)) continue;
29991
31301
  if (item.isDirectory()) {
29992
- entries.push({ path: path17.relative(root, resolved), type: "directory" });
31302
+ entries.push({ path: path18.relative(root, resolved), type: "directory" });
29993
31303
  if (current2.level < depth) queue.push({ path: resolved, level: current2.level + 1 });
29994
31304
  } else if (item.isFile()) {
29995
- const stat2 = await lstat7(resolved).catch(() => null);
29996
- if (stat2) entries.push({ path: path17.relative(root, resolved), type: "file", size: stat2.size });
31305
+ const stat2 = await lstat8(resolved).catch(() => null);
31306
+ if (stat2) entries.push({ path: path18.relative(root, resolved), type: "file", size: stat2.size });
29997
31307
  }
29998
31308
  }
29999
31309
  if (truncated) break;
@@ -30003,49 +31313,49 @@ var NativeTools = class {
30003
31313
  async gitCommonDir(cwd, workspace2, guard) {
30004
31314
  let directory = cwd;
30005
31315
  while (guard.isWithin(directory, workspace2.root)) {
30006
- const dotGit = path17.join(directory, ".git");
31316
+ const dotGit = path18.join(directory, ".git");
30007
31317
  try {
30008
- const stat2 = await lstat7(dotGit);
31318
+ const stat2 = await lstat8(dotGit);
30009
31319
  if (stat2.isSymbolicLink()) fail3("GIT_METADATA_CHANGED");
30010
31320
  let gitDir;
30011
31321
  if (stat2.isDirectory()) gitDir = await realpath7(dotGit);
30012
31322
  else {
30013
31323
  const content = utf8(await this.readFile(dotGit, 4096)).trim();
30014
31324
  if (!content.startsWith("gitdir: ")) fail3("GIT_METADATA_CHANGED");
30015
- gitDir = await realpath7(path17.resolve(directory, content.slice(8)));
31325
+ gitDir = await realpath7(path18.resolve(directory, content.slice(8)));
30016
31326
  }
30017
31327
  if (guard.isWithin(gitDir, this.options.stateDirectory) || !guard.isWithin(gitDir, workspace2.root) && (!workspace2.gitCommonDir || !guard.isWithin(gitDir, workspace2.gitCommonDir))) fail3("GIT_COMMON_DIRECTORY_NOT_APPROVED");
30018
31328
  let common = gitDir;
30019
31329
  try {
30020
- const content = utf8(await this.readFile(path17.join(gitDir, "commondir"), 4096)).trim();
31330
+ const content = utf8(await this.readFile(path18.join(gitDir, "commondir"), 4096)).trim();
30021
31331
  if (!content) fail3("GIT_METADATA_CHANGED");
30022
- common = await realpath7(path17.resolve(gitDir, content));
31332
+ common = await realpath7(path18.resolve(gitDir, content));
30023
31333
  } catch (e) {
30024
31334
  if (e.code !== "ENOENT") throw e;
30025
31335
  }
30026
- if (!(await lstat7(common)).isDirectory() || guard.isWithin(common, this.options.stateDirectory)) fail3("GIT_METADATA_CHANGED");
31336
+ if (!(await lstat8(common)).isDirectory() || guard.isWithin(common, this.options.stateDirectory)) fail3("GIT_METADATA_CHANGED");
30027
31337
  if (!guard.isWithin(common, workspace2.root) && (!workspace2.gitCommonDir || !equalPath3(common, workspace2.gitCommonDir))) fail3("GIT_COMMON_DIRECTORY_NOT_APPROVED");
30028
31338
  return common;
30029
31339
  } catch (e) {
30030
31340
  if (e.code !== "ENOENT") throw e;
30031
31341
  }
30032
31342
  if (equalPath3(directory, workspace2.root)) break;
30033
- directory = path17.dirname(directory);
31343
+ directory = path18.dirname(directory);
30034
31344
  }
30035
31345
  return null;
30036
31346
  }
30037
31347
  };
30038
31348
 
30039
31349
  // agent/src/scheduler.ts
30040
- import path18 from "node:path";
30041
- import os4 from "node:os";
31350
+ import path19 from "node:path";
31351
+ import os5 from "node:os";
30042
31352
  function canonical(value) {
30043
- const p = path18.resolve(value);
31353
+ const p = path19.resolve(value);
30044
31354
  return process.platform === "win32" ? p.toLowerCase() : p;
30045
31355
  }
30046
31356
  function ancestor(a, b) {
30047
- const relative = path18.relative(a, b);
30048
- return relative === "" || !path18.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path18.sep);
31357
+ const relative = path19.relative(a, b);
31358
+ return relative === "" || !path19.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path19.sep);
30049
31359
  }
30050
31360
  function claimsConflict(a, b) {
30051
31361
  return a.some((x) => b.some((y) => (x.namespace ?? "filesystem") === (y.namespace ?? "filesystem") && (x.mode === "write" || y.mode === "write") && (ancestor(x.path, y.path) || ancestor(y.path, x.path))));
@@ -30053,7 +31363,7 @@ function claimsConflict(a, b) {
30053
31363
  var NativeScheduler = class {
30054
31364
  constructor(options = {}) {
30055
31365
  this.options = options;
30056
- const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2, os4.availableParallelism?.() ?? os4.cpus().length) / 2)));
31366
+ const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2, os5.availableParallelism?.() ?? os5.cpus().length) / 2)));
30057
31367
  this.safeSlots = options.safeSlots ?? capacity;
30058
31368
  this.maxQueued = options.maxQueued ?? 32;
30059
31369
  if (!Number.isInteger(this.safeSlots) || this.safeSlots < 1 || this.safeSlots > 32 || !Number.isInteger(this.maxQueued) || this.maxQueued < 1 || this.maxQueued > 256) throw Error("INVALID_SCHEDULER_LIMIT");
@@ -30071,16 +31381,16 @@ var NativeScheduler = class {
30071
31381
  } catch {
30072
31382
  }
30073
31383
  }
30074
- schedule(id2, claims, deadlineAt, run, signal) {
31384
+ schedule(id2, claims, deadlineAt, run2, signal) {
30075
31385
  if (!this.accepting) return Promise.reject(Error("AGENT_PAUSED"));
30076
31386
  if (!id2 || id2.length > 100 || this.active.has(id2) || this.waiting.some((j) => j.id === id2)) return Promise.reject(Error("DUPLICATE_SCHEDULED_EXECUTION"));
30077
- if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !path18.isAbsolute(c.path) || !["read", "write"].includes(c.mode))) return Promise.reject(Error("INVALID_RESOURCE_CLAIM"));
31387
+ if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !path19.isAbsolute(c.path) || !["read", "write"].includes(c.mode))) return Promise.reject(Error("INVALID_RESOURCE_CLAIM"));
30078
31388
  const deadline = deadlineAt.getTime();
30079
31389
  if (!Number.isFinite(deadline) || deadline <= Date.now()) return Promise.reject(Error("ADMISSION_DEADLINE_EXPIRED"));
30080
31390
  if (signal?.aborted) return Promise.reject(Error("CANCELLED_BEFORE_ACCEPTANCE"));
30081
31391
  if (this.waiting.length >= this.maxQueued) return Promise.reject(Error("RESOURCE_BUSY"));
30082
31392
  return new Promise((resolve, reject) => {
30083
- const job = { id: id2, claims: claims.map((c) => ({ ...c, path: canonical(c.path) })), deadline, run, signal, resolve, reject };
31393
+ const job = { id: id2, claims: claims.map((c) => ({ ...c, path: canonical(c.path) })), deadline, run: run2, signal, resolve, reject };
30084
31394
  const remove = (reason) => {
30085
31395
  const index = this.waiting.indexOf(job);
30086
31396
  if (index < 0) return;
@@ -30779,7 +32089,45 @@ function journalBinding(entry, binding2) {
30779
32089
  function journalResult(value, code) {
30780
32090
  return { ...value, resultCode: code ?? (value.treeTerminated ? value.cancelled ? "CANCELLED" : value.timedOut ? "TIMEOUT" : value.exitCode === 0 ? "SUCCESS" : "USER_PROGRAM_FAILED" : "EXECUTION_UNKNOWN") };
30781
32091
  }
30782
- var knownCodes = /* @__PURE__ */ new Set(["PROJECT_IDENTITY_UNKNOWN", "PROJECT_IDENTITY_MISMATCH", "INVALID_TOOL_ARGUMENTS", "LOCAL_PERMISSION_REQUIRED", "PATH_NOT_ALLOWED", "FILE_CHANGED", "FILE_NOT_FOUND", "FILE_ALREADY_EXISTS", "REPLACEMENT_NOT_UNIQUE", "OUTPUT_LIMIT_EXCEEDED", "BINARY_FILE_NOT_SUPPORTED", "FILE_UNSUPPORTED_OR_TOO_LARGE", "INVALID_LINE_RANGE", "FILE_IN_USE", "FILE_READ_ONLY", "FILE_WRITE_LIMIT", "GIT_METADATA_CHANGED", "GIT_COMMON_DIRECTORY_NOT_APPROVED", "GIT_NOT_INSTALLED", "LOCALHOST_NOT_ALLOWED", "COMMAND_NOT_ALLOWED", "WORKSPACE_CHANGED", "WORKSPACE_UNAVAILABLE", "RESOURCE_BUSY", "AGENT_PAUSED", "CANCELLED_BEFORE_ACCEPTANCE", "ADMISSION_DEADLINE_EXPIRED"]);
32092
+ var knownCodes = /* @__PURE__ */ new Set([
32093
+ "PROJECT_IDENTITY_UNKNOWN",
32094
+ "PROJECT_IDENTITY_MISMATCH",
32095
+ "INVALID_TOOL_ARGUMENTS",
32096
+ "LOCAL_PERMISSION_REQUIRED",
32097
+ "PATH_NOT_ALLOWED",
32098
+ "FILE_CHANGED",
32099
+ "FILE_NOT_FOUND",
32100
+ "FILE_ALREADY_EXISTS",
32101
+ "REPLACEMENT_NOT_UNIQUE",
32102
+ "OUTPUT_LIMIT_EXCEEDED",
32103
+ "BINARY_FILE_NOT_SUPPORTED",
32104
+ "FILE_UNSUPPORTED_OR_TOO_LARGE",
32105
+ "INVALID_LINE_RANGE",
32106
+ "FILE_IN_USE",
32107
+ "FILE_READ_ONLY",
32108
+ "FILE_WRITE_LIMIT",
32109
+ "GIT_METADATA_CHANGED",
32110
+ "GIT_COMMON_DIRECTORY_NOT_APPROVED",
32111
+ "GIT_NOT_INSTALLED",
32112
+ "LOCALHOST_NOT_ALLOWED",
32113
+ "COMMAND_NOT_ALLOWED",
32114
+ "WORKSPACE_CHANGED",
32115
+ "WORKSPACE_UNAVAILABLE",
32116
+ "RESOURCE_BUSY",
32117
+ "AGENT_PAUSED",
32118
+ "CANCELLED_BEFORE_ACCEPTANCE",
32119
+ "ADMISSION_DEADLINE_EXPIRED",
32120
+ // take_screenshot refusals (#434, #486): without these the client sees TOOL_FAILED.
32121
+ "FULL_ACCESS_REQUIRED",
32122
+ "SCREENSHOT_DISABLED",
32123
+ "SCREENSHOT_DISABLED_BY_OWNER",
32124
+ "SCREENSHOT_UNSUPPORTED",
32125
+ "SCREENSHOT_TOO_LARGE",
32126
+ "SCREEN_UNAVAILABLE",
32127
+ "SCREEN_LOCKED",
32128
+ "SCREEN_ENCODER_UNAVAILABLE",
32129
+ "SCREEN_RECORDING_PERMISSION_REQUIRED"
32130
+ ]);
30783
32131
  function safeCode(error62) {
30784
32132
  const code = error62 instanceof NativeToolError ? error62.code : error62 instanceof Error ? error62.message : "";
30785
32133
  return knownCodes.has(code) || /^GUARD_[A-Z_]{1,30}$/.test(code) ? code : "TOOL_FAILED";
@@ -30790,6 +32138,14 @@ function resultOutcome(result2) {
30790
32138
  if (!result2.treeTerminated || result2.exitCode === null) return "unknown";
30791
32139
  return result2.exitCode === 0 ? "success" : "failed";
30792
32140
  }
32141
+ function screenshotMetadata(stdout) {
32142
+ try {
32143
+ const { data: _data, ...metadata } = JSON.parse(stdout);
32144
+ return JSON.stringify(metadata);
32145
+ } catch {
32146
+ return "";
32147
+ }
32148
+ }
30793
32149
  async function outboundResult(call, result2, binding2, optional2, ledger) {
30794
32150
  const shaped = call.name === "command_run" ? shapeCommandResultForAgentDetailed({ command: call.args.command, args: call.args.args, cwd: call.args.cwd ?? "." }, result2) : { result: result2, telemetry: unshapedResultTelemetry(result2) };
30795
32151
  if (ledger) {
@@ -30842,7 +32198,7 @@ var NativeRuntime = class {
30842
32198
  }
30843
32199
  if (frame.type === "result" && this.options.contentAudit) {
30844
32200
  const call = this.contexts.get(frame.binding.executionId)?.tool.call;
30845
- if (call) try {
32201
+ if (call && call.name !== "take_screenshot") try {
30846
32202
  this.options.contentAudit.record(frame.binding, call, frame.result);
30847
32203
  } catch {
30848
32204
  }
@@ -30979,8 +32335,10 @@ var NativeRuntime = class {
30979
32335
  const checked = ResultSchema.parse(output2);
30980
32336
  const { resultCode, ...journalOutput } = checked;
30981
32337
  if (context.guardPermit) await this.options.guard.result(context.guardPermit, checked);
30982
- const final = await this.options.journal.finish(binding2.executionId, journalOutput, resultCode);
30983
- this.send({ type: "result", version: 1, binding: binding2, result: await outboundResult(runnable.call, journalResult(final.result, resultCode), binding2, this.optionalTelemetry, this.options.efficiencyLedger) });
32338
+ const image = runnable.call.name === "take_screenshot" ? journalOutput.stdout : void 0;
32339
+ const final = await this.options.journal.finish(binding2.executionId, image === void 0 ? journalOutput : { ...journalOutput, stdout: screenshotMetadata(image) }, resultCode);
32340
+ const outbound = await outboundResult(runnable.call, journalResult(final.result, resultCode), binding2, this.optionalTelemetry, this.options.efficiencyLedger);
32341
+ this.send({ type: "result", version: 1, binding: binding2, result: image === void 0 ? outbound : { ...outbound, stdout: image } });
30984
32342
  }, abort.signal);
30985
32343
  context.task = work.catch(async (error62) => {
30986
32344
  if (!context.accepted) {
@@ -31202,10 +32560,10 @@ var NativeRelayBridge = class {
31202
32560
  };
31203
32561
 
31204
32562
  // agent/src/local-direct.ts
31205
- import net from "node:net";
31206
- import path19 from "node:path";
31207
- import { createHmac as createHmac2, hkdfSync, randomBytes as randomBytes6, randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
31208
- import { mkdir as mkdir7, readFile as readFile7, rename as rename5, rm as rm6, writeFile as writeFile3 } from "node:fs/promises";
32563
+ import net2 from "node:net";
32564
+ import path20 from "node:path";
32565
+ import { createHmac as createHmac2, hkdfSync, randomBytes as randomBytes7, randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
32566
+ import { mkdir as mkdir7, readFile as readFile8, rename as rename5, rm as rm7, writeFile as writeFile3 } from "node:fs/promises";
31209
32567
  var LocalDirectError = class extends Error {
31210
32568
  constructor(code) {
31211
32569
  super(code);
@@ -31223,11 +32581,11 @@ var ADMISSION_MS = 6e4;
31223
32581
  var MAX_IN_FLIGHT = 16;
31224
32582
  var MAX_CONNECTIONS = 32;
31225
32583
  function localDirectDirectory(appData) {
31226
- return path19.join(appData, "LocalCommander", "LocalMcp");
32584
+ return path20.join(appData, "LocalCommander", "LocalMcp");
31227
32585
  }
31228
32586
  async function localDirectEnabled(directory) {
31229
32587
  try {
31230
- return JSON.parse(await readFile7(path19.join(directory, "settings.json"), "utf8"))?.enabled === true;
32588
+ return JSON.parse(await readFile8(path20.join(directory, "settings.json"), "utf8"))?.enabled === true;
31231
32589
  } catch {
31232
32590
  return false;
31233
32591
  }
@@ -31241,7 +32599,7 @@ function sameProof(candidate, expected) {
31241
32599
  const a = Buffer.from(candidate), b = Buffer.from(expected);
31242
32600
  return a.length === b.length && timingSafeEqual3(a, b);
31243
32601
  }
31244
- var nonce = () => randomBytes6(32).toString("base64url");
32602
+ var nonce = () => randomBytes7(32).toString("base64url");
31245
32603
  var NONCE = /^[A-Za-z0-9_-]{43}$/;
31246
32604
  function codeOf(error62) {
31247
32605
  const code = error62 instanceof NativeToolError || error62 instanceof LocalDirectError ? error62.code : error62 instanceof Error ? error62.message : "";
@@ -31300,7 +32658,7 @@ var Lines = class {
31300
32658
  async function readEndpoint(directory) {
31301
32659
  let value;
31302
32660
  try {
31303
- value = JSON.parse(await readFile7(path19.join(directory, "endpoint.json"), "utf8"));
32661
+ value = JSON.parse(await readFile8(path20.join(directory, "endpoint.json"), "utf8"));
31304
32662
  } catch {
31305
32663
  fail4("LOCAL_AGENT_NOT_RUNNING");
31306
32664
  }
@@ -31317,13 +32675,13 @@ var LocalDirectServer = class _LocalDirectServer {
31317
32675
  sockets = /* @__PURE__ */ new Set();
31318
32676
  /** Listens only while the owner has enabled direct local access; null otherwise. */
31319
32677
  static async start(options) {
31320
- const endpointFile = path19.join(options.directory, "endpoint.json");
32678
+ const endpointFile = path20.join(options.directory, "endpoint.json");
31321
32679
  if (!await localDirectEnabled(options.directory)) {
31322
- await rm6(endpointFile, { force: true }).catch(() => {
32680
+ await rm7(endpointFile, { force: true }).catch(() => {
31323
32681
  });
31324
32682
  return null;
31325
32683
  }
31326
- const server = net.createServer(), self = new _LocalDirectServer(server, options);
32684
+ const server = net2.createServer(), self = new _LocalDirectServer(server, options);
31327
32685
  server.on("connection", (socket) => self.accept(socket));
31328
32686
  await new Promise((resolve, reject) => {
31329
32687
  server.once("error", reject);
@@ -31345,7 +32703,7 @@ var LocalDirectServer = class _LocalDirectServer {
31345
32703
  for (const socket of this.sockets) socket.destroy();
31346
32704
  await new Promise((resolve) => this.server.close(() => resolve()));
31347
32705
  try {
31348
- if ((await readEndpoint(this.options.directory)).pid === process.pid) await rm6(path19.join(this.options.directory, "endpoint.json"), { force: true });
32706
+ if ((await readEndpoint(this.options.directory)).pid === process.pid) await rm7(path20.join(this.options.directory, "endpoint.json"), { force: true });
31349
32707
  } catch {
31350
32708
  }
31351
32709
  }
@@ -31480,7 +32838,7 @@ var LocalDirectClient = class _LocalDirectClient {
31480
32838
  static async connect(options) {
31481
32839
  if (!await localDirectEnabled(options.directory)) fail4("LOCAL_ACCESS_DISABLED");
31482
32840
  const endpoint2 = await readEndpoint(options.directory);
31483
- const socket = net.createConnection({ host: "127.0.0.1", port: endpoint2.port });
32841
+ const socket = net2.createConnection({ host: "127.0.0.1", port: endpoint2.port });
31484
32842
  let handler = () => {
31485
32843
  };
31486
32844
  const lines = new Lines(socket, (frame) => handler(frame));
@@ -35200,9 +36558,9 @@ var rev2026Codec = {
35200
36558
  });
35201
36559
  const parsed = buildSchemas2026().RequestMetaEnvelopeSchema.safeParse(meta3);
35202
36560
  if (!parsed.success) for (const issue2 of parsed.error.issues) {
35203
- const path29 = issue2.path.map(String);
35204
- const key = path29.length > 0 ? path29.join(".") : "_meta";
35205
- if (path29.length === 1 && issues.some((existing) => existing.key === key && existing.problem === "missing")) continue;
36561
+ const path30 = issue2.path.map(String);
36562
+ const key = path30.length > 0 ? path30.join(".") : "_meta";
36563
+ if (path30.length === 1 && issues.some((existing) => existing.key === key && existing.problem === "missing")) continue;
35206
36564
  issues.push({
35207
36565
  key,
35208
36566
  problem: issue2.message
@@ -35504,29 +36862,29 @@ var PERMITTED_X_MCP_HEADER_TYPES = /* @__PURE__ */ new Set([
35504
36862
  function scanXMcpHeaderDeclarations(inputSchema) {
35505
36863
  const declarations = [];
35506
36864
  const seenLower = /* @__PURE__ */ new Map();
35507
- const visit2 = (node2, path29, reachable) => {
36865
+ const visit2 = (node2, path30, reachable) => {
35508
36866
  if (node2 === null || typeof node2 !== "object") return void 0;
35509
36867
  const schema = node2;
35510
36868
  if (X_MCP_HEADER_KEY in schema) {
35511
- if (!reachable || path29.length === 0) return `${pathName(path29)}: x-mcp-header is only permitted on properties statically reachable via a chain of 'properties' keys (not under items, additionalProperties, oneOf/anyOf/allOf/not, if/then/else, or $ref)`;
36869
+ if (!reachable || path30.length === 0) return `${pathName(path30)}: x-mcp-header is only permitted on properties statically reachable via a chain of 'properties' keys (not under items, additionalProperties, oneOf/anyOf/allOf/not, if/then/else, or $ref)`;
35512
36870
  const raw = schema[X_MCP_HEADER_KEY];
35513
- if (typeof raw !== "string" || raw.length === 0) return `${pathName(path29)}: x-mcp-header MUST be a non-empty string`;
35514
- if (!RFC9110_TOKEN.test(raw)) return `${pathName(path29)}: x-mcp-header '${raw}' is not a valid RFC 9110 token (no spaces, control characters or HTTP delimiters)`;
36871
+ if (typeof raw !== "string" || raw.length === 0) return `${pathName(path30)}: x-mcp-header MUST be a non-empty string`;
36872
+ if (!RFC9110_TOKEN.test(raw)) return `${pathName(path30)}: x-mcp-header '${raw}' is not a valid RFC 9110 token (no spaces, control characters or HTTP delimiters)`;
35515
36873
  const type = typeof schema.type === "string" ? schema.type : void 0;
35516
- if (type === void 0 || !PERMITTED_X_MCP_HEADER_TYPES.has(type)) return `${pathName(path29)}: x-mcp-header is only permitted on primitive-typed properties (string, integer, boolean); got ${type ?? "<none>"}`;
36874
+ if (type === void 0 || !PERMITTED_X_MCP_HEADER_TYPES.has(type)) return `${pathName(path30)}: x-mcp-header is only permitted on primitive-typed properties (string, integer, boolean); got ${type ?? "<none>"}`;
35517
36875
  const lower = raw.toLowerCase();
35518
36876
  const prior = seenLower.get(lower);
35519
36877
  if (prior !== void 0) return `x-mcp-header '${raw}' is not case-insensitively unique (also declared as '${prior}')`;
35520
36878
  seenLower.set(lower, raw);
35521
36879
  declarations.push({
35522
- path: path29,
36880
+ path: path30,
35523
36881
  headerName: raw,
35524
36882
  type
35525
36883
  });
35526
36884
  }
35527
36885
  const properties = schema.properties;
35528
36886
  if (properties !== null && typeof properties === "object") for (const [key, child] of Object.entries(properties)) {
35529
- const fault$1 = visit2(child, [...path29, key], reachable);
36887
+ const fault$1 = visit2(child, [...path30, key], reachable);
35530
36888
  if (fault$1 !== void 0) return fault$1;
35531
36889
  }
35532
36890
  for (const k of NON_REACHABLE_SUBSCHEMA_KEYWORDS) {
@@ -35534,7 +36892,7 @@ function scanXMcpHeaderDeclarations(inputSchema) {
35534
36892
  if (sub === void 0) continue;
35535
36893
  const branches = Array.isArray(sub) ? sub : sub !== null && typeof sub === "object" && OBJECT_VALUED_SUBSCHEMA_KEYWORDS.has(k) ? Object.values(sub) : [sub];
35536
36894
  for (const branch of branches) {
35537
- const fault$1 = visit2(branch, [...path29, `<${k}>`], false);
36895
+ const fault$1 = visit2(branch, [...path30, `<${k}>`], false);
35538
36896
  if (fault$1 !== void 0) return fault$1;
35539
36897
  }
35540
36898
  }
@@ -35574,8 +36932,8 @@ var OBJECT_VALUED_SUBSCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
35574
36932
  "$defs",
35575
36933
  "definitions"
35576
36934
  ]);
35577
- function pathName(path29) {
35578
- return path29.length === 0 ? "<root>" : path29.join(".");
36935
+ function pathName(path30) {
36936
+ return path30.length === 0 ? "<root>" : path30.join(".");
35579
36937
  }
35580
36938
  var HEADER_MISMATCH_ERROR_CODE = -32020;
35581
36939
  var INBOUND_VALIDATION_LADDER = [
@@ -35825,7 +37183,7 @@ var PROPERTY_KEYS_BY_TYPE = {
35825
37183
  array: shapeKeys([UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema])
35826
37184
  };
35827
37185
  var SUPPORTED_STRING_FORMATS = new Set(StringSchemaSchema.shape.format.unwrap().options);
35828
- function walkProperty(node2, path29, vendor, unsupported) {
37186
+ function walkProperty(node2, path30, vendor, unsupported) {
35829
37187
  if (!isJsonObject(node2)) return node2;
35830
37188
  const allowedKeys = typeof node2.type === "string" && Object.hasOwn(PROPERTY_KEYS_BY_TYPE, node2.type) ? PROPERTY_KEYS_BY_TYPE[node2.type] : void 0;
35831
37189
  if (allowedKeys === void 0) return node2;
@@ -35833,8 +37191,8 @@ function walkProperty(node2, path29, vendor, unsupported) {
35833
37191
  for (const [key, value] of Object.entries(node2)) if (allowedKeys.has(key) || isAnnotationOnlyJsonSchemaKeyword(key)) pruned[key] = value;
35834
37192
  else if (key === "pattern" && node2.type === "string" && typeof node2.format === "string") {
35835
37193
  if (!SUPPORTED_STRING_FORMATS.has(node2.format)) pruned[key] = value;
35836
- else if (typeof value !== "string" || !isLibraryFormatPattern(node2.format, value, vendor)) unsupported.push(`${path29}.${key}`);
35837
- } else unsupported.push(`${path29}.${key}`);
37194
+ else if (typeof value !== "string" || !isLibraryFormatPattern(node2.format, value, vendor)) unsupported.push(`${path30}.${key}`);
37195
+ } else unsupported.push(`${path30}.${key}`);
35838
37196
  return pruned;
35839
37197
  }
35840
37198
  function walkRequestedSchema(converted, vendor) {
@@ -35851,11 +37209,11 @@ function describeUnsupportedProperties(pruned, fallback) {
35851
37209
  const offenders = Object.entries(pruned.properties).filter(([, node2]) => !parseSchema(PrimitiveSchemaDefinitionSchema, node2).success).map(([name2]) => `properties.${name2}`);
35852
37210
  return offenders.length > 0 ? offenders.join(", ") : fallback;
35853
37211
  }
35854
- function findDroppedConstraintPaths(original, parsed, path29 = "") {
35855
- if (Array.isArray(original) && Array.isArray(parsed)) return original.flatMap((item, index) => findDroppedConstraintPaths(item, parsed[index], `${path29}[${index}]`));
37212
+ function findDroppedConstraintPaths(original, parsed, path30 = "") {
37213
+ if (Array.isArray(original) && Array.isArray(parsed)) return original.flatMap((item, index) => findDroppedConstraintPaths(item, parsed[index], `${path30}[${index}]`));
35856
37214
  if (!isJsonObject(original) || !isJsonObject(parsed)) return [];
35857
37215
  return Object.entries(original).flatMap(([key, value]) => {
35858
- const childPath = path29 ? `${path29}.${key}` : key;
37216
+ const childPath = path30 ? `${path30}.${key}` : key;
35859
37217
  if (!Object.prototype.hasOwnProperty.call(parsed, key)) return isAnnotationOnlyJsonSchemaKeyword(key) ? [] : [childPath];
35860
37218
  return findDroppedConstraintPaths(value, parsed[key], childPath);
35861
37219
  });
@@ -37003,8 +38361,8 @@ var require_content_type = /* @__PURE__ */ __commonJSMin(((exports) => {
37003
38361
  var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g;
37004
38362
  var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g;
37005
38363
  var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
37006
- exports.parse = parse3;
37007
- function parse3(string4) {
38364
+ exports.parse = parse4;
38365
+ function parse4(string4) {
37008
38366
  if (!string4) throw new TypeError("argument string is required");
37009
38367
  var header = typeof string4 === "object" ? getcontenttype(string4) : string4;
37010
38368
  if (typeof header !== "string") throw new TypeError("argument string is required to be a string");
@@ -37528,9 +38886,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37528
38886
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
37529
38887
  return `${varKind} ${this.name}${rhs};` + _n;
37530
38888
  }
37531
- optimizeNames(names, constants10) {
38889
+ optimizeNames(names, constants11) {
37532
38890
  if (!names[this.name.str]) return;
37533
- if (this.rhs) this.rhs = optimizeExpr(this.rhs, names, constants10);
38891
+ if (this.rhs) this.rhs = optimizeExpr(this.rhs, names, constants11);
37534
38892
  return this;
37535
38893
  }
37536
38894
  get names() {
@@ -37547,9 +38905,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37547
38905
  render({ _n }) {
37548
38906
  return `${this.lhs} = ${this.rhs};` + _n;
37549
38907
  }
37550
- optimizeNames(names, constants10) {
38908
+ optimizeNames(names, constants11) {
37551
38909
  if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects) return;
37552
- this.rhs = optimizeExpr(this.rhs, names, constants10);
38910
+ this.rhs = optimizeExpr(this.rhs, names, constants11);
37553
38911
  return this;
37554
38912
  }
37555
38913
  get names() {
@@ -37608,8 +38966,8 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37608
38966
  optimizeNodes() {
37609
38967
  return `${this.code}` ? this : void 0;
37610
38968
  }
37611
- optimizeNames(names, constants10) {
37612
- this.code = optimizeExpr(this.code, names, constants10);
38969
+ optimizeNames(names, constants11) {
38970
+ this.code = optimizeExpr(this.code, names, constants11);
37613
38971
  return this;
37614
38972
  }
37615
38973
  get names() {
@@ -37635,12 +38993,12 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37635
38993
  }
37636
38994
  return nodes.length > 0 ? this : void 0;
37637
38995
  }
37638
- optimizeNames(names, constants10) {
38996
+ optimizeNames(names, constants11) {
37639
38997
  const { nodes } = this;
37640
38998
  let i = nodes.length;
37641
38999
  while (i--) {
37642
39000
  const n = nodes[i];
37643
- if (n.optimizeNames(names, constants10)) continue;
39001
+ if (n.optimizeNames(names, constants11)) continue;
37644
39002
  subtractNames(names, n.names);
37645
39003
  nodes.splice(i, 1);
37646
39004
  }
@@ -37687,11 +39045,11 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37687
39045
  if (cond === false || !this.nodes.length) return void 0;
37688
39046
  return this;
37689
39047
  }
37690
- optimizeNames(names, constants10) {
39048
+ optimizeNames(names, constants11) {
37691
39049
  var _a3;
37692
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants10);
37693
- if (!(super.optimizeNames(names, constants10) || this.else)) return;
37694
- this.condition = optimizeExpr(this.condition, names, constants10);
39050
+ this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants11);
39051
+ if (!(super.optimizeNames(names, constants11) || this.else)) return;
39052
+ this.condition = optimizeExpr(this.condition, names, constants11);
37695
39053
  return this;
37696
39054
  }
37697
39055
  get names() {
@@ -37713,9 +39071,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37713
39071
  render(opts) {
37714
39072
  return `for(${this.iteration})` + super.render(opts);
37715
39073
  }
37716
- optimizeNames(names, constants10) {
37717
- if (!super.optimizeNames(names, constants10)) return;
37718
- this.iteration = optimizeExpr(this.iteration, names, constants10);
39074
+ optimizeNames(names, constants11) {
39075
+ if (!super.optimizeNames(names, constants11)) return;
39076
+ this.iteration = optimizeExpr(this.iteration, names, constants11);
37719
39077
  return this;
37720
39078
  }
37721
39079
  get names() {
@@ -37750,9 +39108,9 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37750
39108
  render(opts) {
37751
39109
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
37752
39110
  }
37753
- optimizeNames(names, constants10) {
37754
- if (!super.optimizeNames(names, constants10)) return;
37755
- this.iterable = optimizeExpr(this.iterable, names, constants10);
39111
+ optimizeNames(names, constants11) {
39112
+ if (!super.optimizeNames(names, constants11)) return;
39113
+ this.iterable = optimizeExpr(this.iterable, names, constants11);
37756
39114
  return this;
37757
39115
  }
37758
39116
  get names() {
@@ -37791,11 +39149,11 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
37791
39149
  (_b = this.finally) === null || _b === void 0 || _b.optimizeNodes();
37792
39150
  return this;
37793
39151
  }
37794
- optimizeNames(names, constants10) {
39152
+ optimizeNames(names, constants11) {
37795
39153
  var _a3, _b;
37796
- super.optimizeNames(names, constants10);
37797
- (_a3 = this.catch) === null || _a3 === void 0 || _a3.optimizeNames(names, constants10);
37798
- (_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names, constants10);
39154
+ super.optimizeNames(names, constants11);
39155
+ (_a3 = this.catch) === null || _a3 === void 0 || _a3.optimizeNames(names, constants11);
39156
+ (_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names, constants11);
37799
39157
  return this;
37800
39158
  }
37801
39159
  get names() {
@@ -38044,7 +39402,7 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
38044
39402
  function addExprNames(names, from) {
38045
39403
  return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
38046
39404
  }
38047
- function optimizeExpr(expr, names, constants10) {
39405
+ function optimizeExpr(expr, names, constants11) {
38048
39406
  if (expr instanceof code_1.Name) return replaceName(expr);
38049
39407
  if (!canOptimize(expr)) return expr;
38050
39408
  return new code_1._Code(expr._items.reduce((items, c) => {
@@ -38054,13 +39412,13 @@ var require_codegen = /* @__PURE__ */ __commonJSMin(((exports) => {
38054
39412
  return items;
38055
39413
  }, []));
38056
39414
  function replaceName(n) {
38057
- const c = constants10[n.str];
39415
+ const c = constants11[n.str];
38058
39416
  if (c === void 0 || names[n.str] !== 1) return n;
38059
39417
  delete names[n.str];
38060
39418
  return c;
38061
39419
  }
38062
39420
  function canOptimize(e) {
38063
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants10[c.str] !== void 0);
39421
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants11[c.str] !== void 0);
38064
39422
  }
38065
39423
  }
38066
39424
  function subtractNames(names, from) {
@@ -39931,8 +41289,8 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
39931
41289
  for (let i = 0; i < str.length; i++) if (str[i] === token) ind++;
39932
41290
  return ind;
39933
41291
  }
39934
- function removeDotSegments(path29) {
39935
- let input2 = path29;
41292
+ function removeDotSegments(path30) {
41293
+ let input2 = path30;
39936
41294
  const output2 = [];
39937
41295
  let nextSlash = -1;
39938
41296
  let len = 0;
@@ -40085,8 +41443,8 @@ var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40085
41443
  wsComponent.secure = void 0;
40086
41444
  }
40087
41445
  if (wsComponent.resourceName) {
40088
- const [path29, query] = wsComponent.resourceName.split("?");
40089
- wsComponent.path = path29 && path29 !== "/" ? path29 : void 0;
41446
+ const [path30, query] = wsComponent.resourceName.split("?");
41447
+ wsComponent.path = path30 && path30 !== "/" ? path30 : void 0;
40090
41448
  wsComponent.query = query;
40091
41449
  wsComponent.resourceName = void 0;
40092
41450
  }
@@ -40192,21 +41550,21 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40192
41550
  const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
40193
41551
  const { SCHEMES, getSchemeHandler } = require_schemes();
40194
41552
  function normalize(uri, options) {
40195
- if (typeof uri === "string") uri = serialize(parse3(uri, options), options);
40196
- else if (typeof uri === "object") uri = parse3(serialize(uri, options), options);
41553
+ if (typeof uri === "string") uri = serialize(parse4(uri, options), options);
41554
+ else if (typeof uri === "object") uri = parse4(serialize(uri, options), options);
40197
41555
  return uri;
40198
41556
  }
40199
41557
  function resolve(baseURI, relativeURI, options) {
40200
41558
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
40201
- const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
41559
+ const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
40202
41560
  schemelessOptions.skipEscape = true;
40203
41561
  return serialize(resolved, schemelessOptions);
40204
41562
  }
40205
41563
  function resolveComponent(base, relative, options, skipNormalization) {
40206
41564
  const target = {};
40207
41565
  if (!skipNormalization) {
40208
- base = parse3(serialize(base, options), options);
40209
- relative = parse3(serialize(relative, options), options);
41566
+ base = parse4(serialize(base, options), options);
41567
+ relative = parse4(serialize(relative, options), options);
40210
41568
  }
40211
41569
  options = options || {};
40212
41570
  if (!options.tolerant && relative.scheme) {
@@ -40250,7 +41608,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40250
41608
  function equal(uriA, uriB, options) {
40251
41609
  if (typeof uriA === "string") {
40252
41610
  uriA = unescape(uriA);
40253
- uriA = serialize(normalizeComponentEncoding(parse3(uriA, options), true), {
41611
+ uriA = serialize(normalizeComponentEncoding(parse4(uriA, options), true), {
40254
41612
  ...options,
40255
41613
  skipEscape: true
40256
41614
  });
@@ -40260,7 +41618,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40260
41618
  });
40261
41619
  if (typeof uriB === "string") {
40262
41620
  uriB = unescape(uriB);
40263
- uriB = serialize(normalizeComponentEncoding(parse3(uriB, options), true), {
41621
+ uriB = serialize(normalizeComponentEncoding(parse4(uriB, options), true), {
40264
41622
  ...options,
40265
41623
  skipEscape: true
40266
41624
  });
@@ -40313,7 +41671,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40313
41671
  return uriTokens.join("");
40314
41672
  }
40315
41673
  const URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
40316
- function parse3(uri, opts) {
41674
+ function parse4(uri, opts) {
40317
41675
  const options = Object.assign({}, opts);
40318
41676
  const parsed = {
40319
41677
  scheme: void 0,
@@ -40374,7 +41732,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
40374
41732
  resolveComponent,
40375
41733
  equal,
40376
41734
  serialize,
40377
- parse: parse3
41735
+ parse: parse4
40378
41736
  };
40379
41737
  module.exports = fastUri;
40380
41738
  module.exports.default = fastUri;
@@ -45653,7 +47011,8 @@ var DESCRIPTIONS = {
45653
47011
  git_diff: ["Git diff of the repository at a workspace-relative path.", { readOnlyHint: true, openWorldHint: false }],
45654
47012
  git_log: ["Recent Git commits of the repository at a workspace-relative path.", { readOnlyHint: true, openWorldHint: false }],
45655
47013
  project_snapshot: ["Compact project overview: Git state and, with startup, AGENTS.md policy and task continuation.", { readOnlyHint: true, openWorldHint: false }],
45656
- command_run: ["Run one executable with an argument array (no shell parsing), hidden, with captured output. Uses this Windows account's rights within the owner's grant.", { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true }],
47014
+ command_run: ["Run one executable with an argument array (no shell parsing), hidden, with captured output. Uses this user account's rights within the owner's grant.", { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true }],
47015
+ take_screenshot: ["Take a still image of this computer's primary screen, returned as a JPEG image. It contains everything visible on the screen, including any open passwords, keys or private messages. Needs a Full Access workspace; the lock screen is never captured.", { readOnlyHint: true, openWorldHint: false }],
45657
47016
  localhost_request: ["HTTP request to a service on this computer (localhost only).", { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }]
45658
47017
  };
45659
47018
  var workspace = external_exports.string().min(1).max(4096).optional().describe("Workspace grant id, root path (for example D:\\) or display name from workspace_list. Optional when only one workspace is approved.");
@@ -45666,6 +47025,14 @@ function failure4(error62) {
45666
47025
  return text2(code + hint, true);
45667
47026
  }
45668
47027
  function render(name2, result2) {
47028
+ if (name2 === "take_screenshot" && result2.resultCode === "SUCCESS") {
47029
+ try {
47030
+ const { data, mimeType, ...metadata } = JSON.parse(result2.stdout);
47031
+ if (typeof data === "string" && data && mimeType === "image/jpeg") return { content: [{ type: "image", data, mimeType }, { type: "text", text: JSON.stringify(metadata) }] };
47032
+ } catch {
47033
+ }
47034
+ return text2(JSON.stringify({ resultCode: "SCREEN_UNAVAILABLE" }), true);
47035
+ }
45669
47036
  if (name2 !== "command_run" && result2.resultCode === "SUCCESS") return text2(result2.stdout);
45670
47037
  const { exitCode, resultCode, timedOut, cancelled, stdout, stderr, stdoutTruncated, stderrTruncated } = result2;
45671
47038
  return text2(
@@ -45686,7 +47053,7 @@ async function serveLocalMcp(options) {
45686
47053
  return connecting;
45687
47054
  };
45688
47055
  const server = new McpServer({ name: "local-commander-local", version: options.agentVersion }, {
45689
- instructions: "Local Commander direct access to this computer, through the owner's approved workspaces. Paths are relative to the selected workspace root; call workspace_list to see roots. Commands run hidden with this Windows account's rights; owner denials still apply."
47056
+ instructions: "Local Commander direct access to this computer, through the owner's approved workspaces. Paths are relative to the selected workspace root; call workspace_list to see roots. Commands run hidden with this user account's rights; owner denials still apply."
45690
47057
  });
45691
47058
  server.registerTool(
45692
47059
  "workspace_list",
@@ -45701,7 +47068,7 @@ async function serveLocalMcp(options) {
45701
47068
  );
45702
47069
  for (const option of ToolCallSchema.options) {
45703
47070
  const name2 = option.shape.name.value, entry = DESCRIPTIONS[name2];
45704
- if (!entry) continue;
47071
+ if (!entry || name2 === "take_screenshot" && !screenshotEnabled()) continue;
45705
47072
  const inputSchema = option.shape.args.extend({ workspace });
45706
47073
  const callback = async (input2, ctx) => {
45707
47074
  const { workspace: selected, ...args } = input2;
@@ -46167,6 +47534,7 @@ async function connectOnce(options) {
46167
47534
  const incidents = Array.isArray(readyFrame.capabilities) && readyFrame.capabilities.includes("incidentBatchV1");
46168
47535
  const monitorHeartbeat = Array.isArray(readyFrame.capabilities) && readyFrame.capabilities.includes("monitorHeartbeatV1") && typeof readyFrame.heartbeatMs === "number" && Number.isInteger(readyFrame.heartbeatMs) && readyFrame.heartbeatMs >= 1e3 && readyFrame.heartbeatMs <= 6e4 ? readyFrame.heartbeatMs : void 0;
46169
47536
  const nativeStatus = Array.isArray(readyFrame.capabilities) && readyFrame.capabilities.includes(NATIVE_STATUS_CAPABILITY) && options.status;
47537
+ const accessModes = Array.isArray(readyFrame.capabilities) && readyFrame.capabilities.includes(WORKSPACE_ACCESS_MODE_CAPABILITY);
46170
47538
  const reportStatus = () => {
46171
47539
  if (!nativeStatus) return;
46172
47540
  const { safeSlots, active, queued, paused } = nativeStatus();
@@ -46393,7 +47761,16 @@ async function connectOnce(options) {
46393
47761
  registerWorkspace: (workspace2) => {
46394
47762
  if (pendingWorkspace.size >= 32) return Promise.reject(new RelayClientError("RELAY_PENDING_LIMIT"));
46395
47763
  const requestId = randomUUID10();
46396
- const event = { type: "workspace_grant", version: 1, requestId, workspaceGrantId: workspace2.workspaceGrantId, rootHash: workspace2.rootHash, displayName: workspace2.displayName, policyVersion: workspace2.policyVersion };
47764
+ const event = {
47765
+ type: "workspace_grant",
47766
+ version: 1,
47767
+ requestId,
47768
+ workspaceGrantId: workspace2.workspaceGrantId,
47769
+ rootHash: workspace2.rootHash,
47770
+ displayName: workspace2.displayName,
47771
+ policyVersion: workspace2.policyVersion,
47772
+ ...accessModes ? { accessMode: workspace2.fullAccess === true ? "full" : "scoped" } : {}
47773
+ };
46397
47774
  return new Promise((resolve, reject) => {
46398
47775
  const timer = setTimeout(() => {
46399
47776
  pendingWorkspace.delete(requestId);
@@ -46440,16 +47817,16 @@ async function connectOnce(options) {
46440
47817
  // agent/src/machine-identity.ts
46441
47818
  import { spawn as spawn5 } from "node:child_process";
46442
47819
  import { createHash as createHash16 } from "node:crypto";
46443
- import os5 from "node:os";
47820
+ import os6 from "node:os";
46444
47821
  import { open as open7 } from "node:fs/promises";
46445
- import { constants as constants8 } from "node:fs";
46446
- import path20 from "node:path";
47822
+ import { constants as constants9 } from "node:fs";
47823
+ import path21 from "node:path";
46447
47824
  var MACHINE_GUID = /^\s*MachineGuid\s+REG_SZ\s+([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\s*$/m;
46448
47825
  async function readMachineGuid(timeoutMs2 = 5e3) {
46449
47826
  if (process.platform === "linux") {
46450
47827
  let handle;
46451
47828
  try {
46452
- handle = await open7("/etc/machine-id", constants8.O_RDONLY | constants8.O_NOFOLLOW);
47829
+ handle = await open7("/etc/machine-id", constants9.O_RDONLY | constants9.O_NOFOLLOW);
46453
47830
  const stat2 = await handle.stat();
46454
47831
  if (!stat2.isFile() || stat2.size > 128) return null;
46455
47832
  const data = Buffer.alloc(129);
@@ -46464,7 +47841,7 @@ async function readMachineGuid(timeoutMs2 = 5e3) {
46464
47841
  }
46465
47842
  }
46466
47843
  if (!["win32", "darwin"].includes(process.platform)) return null;
46467
- const reg = process.platform === "darwin" ? "/usr/sbin/ioreg" : path20.join(process.env.SystemRoot || "C:\\Windows", "System32", "reg.exe");
47844
+ const reg = process.platform === "darwin" ? "/usr/sbin/ioreg" : path21.join(process.env.SystemRoot || "C:\\Windows", "System32", "reg.exe");
46468
47845
  const args = process.platform === "darwin" ? ["-rd1", "-c", "IOPlatformExpertDevice"] : ["query", "HKLM\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid", "/reg:64"];
46469
47846
  const pattern = process.platform === "darwin" ? /"IOPlatformUUID"\s*=\s*"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})"/ : MACHINE_GUID;
46470
47847
  return new Promise((resolve) => {
@@ -46498,7 +47875,7 @@ async function readComputerName(timeoutMs2 = 5e3) {
46498
47875
  if (process.platform === "linux") {
46499
47876
  let handle;
46500
47877
  try {
46501
- handle = await open7("/etc/hostname", constants8.O_RDONLY | constants8.O_NOFOLLOW);
47878
+ handle = await open7("/etc/hostname", constants9.O_RDONLY | constants9.O_NOFOLLOW);
46502
47879
  const data = Buffer.alloc(257), { bytesRead } = await handle.read(data, 0, data.length, 0);
46503
47880
  const name2 = data.subarray(0, bytesRead).toString("utf8").trim();
46504
47881
  if (bytesRead <= 256 && valid(name2)) return name2;
@@ -46536,9 +47913,9 @@ async function readComputerName(timeoutMs2 = 5e3) {
46536
47913
  });
46537
47914
  if (valid(name2)) return name2;
46538
47915
  }
46539
- return os5.hostname();
47916
+ return os6.hostname();
46540
47917
  }
46541
- function machineProof(deviceId, machineGuid, computerName = os5.hostname()) {
47918
+ function machineProof(deviceId, machineGuid, computerName = os6.hostname()) {
46542
47919
  const name2 = computerName.slice(0, 120);
46543
47920
  if (!name2 || name2.trim() !== name2 || /[\u0000-\u001f\u007f]/.test(name2)) return null;
46544
47921
  const fingerprint3 = createHash16("sha256").update("lcmcp-machine-v1\0" + deviceId.toLowerCase() + "\0" + machineGuid.toLowerCase() + "\0" + name2.toUpperCase(), "utf8").digest("hex");
@@ -46579,8 +47956,8 @@ function canonicalOrigin2(value) {
46579
47956
  fail6("ORIGIN_INVALID");
46580
47957
  }
46581
47958
  }
46582
- function endpoint(origin, path29) {
46583
- return origin + path29;
47959
+ function endpoint(origin, path30) {
47960
+ return origin + path30;
46584
47961
  }
46585
47962
  function uuid21(value, code) {
46586
47963
  if (typeof value !== "string" || !UUID3.test(value)) fail6(code);
@@ -47081,29 +48458,29 @@ async function deliverGuardEvidence(target, packet, options = {}) {
47081
48458
  }
47082
48459
 
47083
48460
  // agent/src/optimization-ledger.ts
47084
- import { constants as constants9 } from "node:fs";
47085
- import { lstat as lstat8, mkdir as mkdir8, open as open8, readFile as readFile8, realpath as realpath8 } from "node:fs/promises";
47086
- import path21 from "node:path";
48461
+ import { constants as constants10 } from "node:fs";
48462
+ import { lstat as lstat9, mkdir as mkdir8, open as open8, readFile as readFile9, realpath as realpath8 } from "node:fs/promises";
48463
+ import path22 from "node:path";
47087
48464
  var MAX_LEDGER_BYTES = 64 * 1024 * 1024;
47088
48465
  var MAX_NOTICE_LEDGER_BYTES = 8 * 1024 * 1024;
47089
48466
  function failure5(code) {
47090
48467
  return Object.assign(new Error(code), { code });
47091
48468
  }
47092
48469
  async function safeDirectory2(directory) {
47093
- const absolute2 = path21.resolve(directory);
48470
+ const absolute2 = path22.resolve(directory);
47094
48471
  let current2 = absolute2;
47095
48472
  for (; ; ) {
47096
48473
  try {
47097
- if ((await lstat8(current2)).isSymbolicLink()) throw failure5("OPTIMIZATION_LEDGER_DIRECTORY_INVALID");
48474
+ if ((await lstat9(current2)).isSymbolicLink()) throw failure5("OPTIMIZATION_LEDGER_DIRECTORY_INVALID");
47098
48475
  } catch (error62) {
47099
48476
  if (error62.code !== "ENOENT") throw error62;
47100
48477
  }
47101
- const parent = path21.dirname(current2);
48478
+ const parent = path22.dirname(current2);
47102
48479
  if (parent === current2) break;
47103
48480
  current2 = parent;
47104
48481
  }
47105
48482
  await mkdir8(absolute2, { recursive: true, mode: 448 });
47106
- const stat2 = await lstat8(absolute2);
48483
+ const stat2 = await lstat9(absolute2);
47107
48484
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw failure5("OPTIMIZATION_LEDGER_DIRECTORY_INVALID");
47108
48485
  return realpath8(absolute2);
47109
48486
  }
@@ -47133,29 +48510,29 @@ var OptimizationLedger = class _OptimizationLedger {
47133
48510
  closed = false;
47134
48511
  static async open(directory) {
47135
48512
  const dir = await safeDirectory2(directory);
47136
- const filename = path21.join(dir, "live-efficiency.v1.jsonl");
47137
- const noticesFilename = path21.join(dir, "live-efficiency-notices.v1.jsonl");
48513
+ const filename = path22.join(dir, "live-efficiency.v1.jsonl");
48514
+ const noticesFilename = path22.join(dir, "live-efficiency-notices.v1.jsonl");
47138
48515
  let existing = "";
47139
48516
  try {
47140
- const stat2 = await lstat8(filename);
48517
+ const stat2 = await lstat9(filename);
47141
48518
  if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > MAX_LEDGER_BYTES) {
47142
48519
  throw failure5("OPTIMIZATION_LEDGER_INVALID");
47143
48520
  }
47144
- existing = await readFile8(filename, "utf8");
48521
+ existing = await readFile9(filename, "utf8");
47145
48522
  } catch (error62) {
47146
48523
  if (error62.code !== "ENOENT") throw error62;
47147
48524
  }
47148
48525
  const handle = await open8(
47149
48526
  filename,
47150
- constants9.O_CREAT | constants9.O_APPEND | constants9.O_WRONLY | (constants9.O_NOFOLLOW ?? 0),
48527
+ constants10.O_CREAT | constants10.O_APPEND | constants10.O_WRONLY | (constants10.O_NOFOLLOW ?? 0),
47151
48528
  384
47152
48529
  );
47153
48530
  const ledger = new _OptimizationLedger(filename, handle, noticesFilename);
47154
48531
  try {
47155
48532
  try {
47156
- const noticeStat = await lstat8(noticesFilename);
48533
+ const noticeStat = await lstat9(noticesFilename);
47157
48534
  if (!noticeStat.isFile() || noticeStat.isSymbolicLink() || noticeStat.size > MAX_NOTICE_LEDGER_BYTES) throw failure5("OPTIMIZATION_NOTICE_LEDGER_INVALID");
47158
- const notices = await readFile8(noticesFilename, "utf8");
48535
+ const notices = await readFile9(noticesFilename, "utf8");
47159
48536
  for (const line of notices.split("\n")) {
47160
48537
  if (!line) continue;
47161
48538
  const parsed = JSON.parse(line);
@@ -47235,7 +48612,7 @@ var OptimizationLedger = class _OptimizationLedger {
47235
48612
  const marker = JSON.stringify({ sessionId: event.sessionId, checkpointCalls, deliveredAt: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
47236
48613
  let currentBytes = 0;
47237
48614
  try {
47238
- const stat2 = await lstat8(this.noticesFilename);
48615
+ const stat2 = await lstat9(this.noticesFilename);
47239
48616
  if (!stat2.isFile() || stat2.isSymbolicLink()) throw failure5("OPTIMIZATION_NOTICE_LEDGER_INVALID");
47240
48617
  currentBytes = stat2.size;
47241
48618
  } catch (error62) {
@@ -47244,7 +48621,7 @@ var OptimizationLedger = class _OptimizationLedger {
47244
48621
  if (currentBytes + Buffer.byteLength(marker, "utf8") > MAX_NOTICE_LEDGER_BYTES) throw failure5("OPTIMIZATION_NOTICE_LEDGER_CAPACITY_EXCEEDED");
47245
48622
  const markerHandle = await open8(
47246
48623
  this.noticesFilename,
47247
- constants9.O_CREAT | constants9.O_APPEND | constants9.O_WRONLY | (constants9.O_NOFOLLOW ?? 0),
48624
+ constants10.O_CREAT | constants10.O_APPEND | constants10.O_WRONLY | (constants10.O_NOFOLLOW ?? 0),
47248
48625
  384
47249
48626
  );
47250
48627
  try {
@@ -47283,9 +48660,9 @@ var OptimizationLedger = class _OptimizationLedger {
47283
48660
 
47284
48661
  // agent/src/monitor.ts
47285
48662
  import { createHash as createHash17, randomUUID as randomUUID12 } from "node:crypto";
47286
- import { lstat as lstat9, mkdir as mkdir9, open as open9, rename as rename6, rm as rm7 } from "node:fs/promises";
47287
- import path22 from "node:path";
47288
- import os6 from "node:os";
48663
+ import { lstat as lstat10, mkdir as mkdir9, open as open9, rename as rename6, rm as rm8 } from "node:fs/promises";
48664
+ import path23 from "node:path";
48665
+ import os7 from "node:os";
47289
48666
 
47290
48667
  // packages/agent-cli/bin/monitor-savings.mjs
47291
48668
  var count = (value) => Number.isSafeInteger(value) && value >= 0 && value <= 1e15;
@@ -47307,7 +48684,7 @@ function lifetimeSavingsView(raw) {
47307
48684
  // agent/src/monitor.ts
47308
48685
  function commandSummary2(tool) {
47309
48686
  if (tool.name !== "command_run") return { name: tool.name, command: tool.name };
47310
- const candidate = path22.win32.basename(tool.args.command).replace(/\.(exe|cmd|bat|com)$/i, "").toLowerCase();
48687
+ const candidate = path23.win32.basename(tool.args.command).replace(/\.(exe|cmd|bat|com)$/i, "").toLowerCase();
47311
48688
  const name2 = ["node", "npm", "npx", "git", "rg", "powershell", "pwsh", "cmd", "tsc", "python", "dotnet"].includes(candidate) ? candidate : "command";
47312
48689
  let command = name2;
47313
48690
  if (name2 === "node" && tool.args.args.includes("--test") && !tool.args.args.some((arg) => ["-e", "--eval", "-p", "--print"].includes(arg))) command += " --test";
@@ -47320,9 +48697,9 @@ function commandSummary2(tool) {
47320
48697
  var ProductionMonitor = class {
47321
48698
  constructor(directory, stateDirectory, agentVersion3) {
47322
48699
  this.agentVersion = agentVersion3;
47323
- const key = createHash17("sha256").update(path22.resolve(stateDirectory).toLowerCase()).digest("hex");
47324
- this.file = path22.join(directory, key + ".json");
47325
- this.transportFile = path22.join(directory, key + ".transport");
48700
+ const key = createHash17("sha256").update(path23.resolve(stateDirectory).toLowerCase()).digest("hex");
48701
+ this.file = path23.join(directory, key + ".json");
48702
+ this.transportFile = path23.join(directory, key + ".transport");
47326
48703
  }
47327
48704
  agentVersion;
47328
48705
  instanceId = randomUUID12();
@@ -47333,7 +48710,7 @@ var ProductionMonitor = class {
47333
48710
  measured = /* @__PURE__ */ new Set();
47334
48711
  polls = { status: 0, output: 0 };
47335
48712
  efficiencyCalls = 0;
47336
- computer = os6.hostname().replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 64) || "PC";
48713
+ computer = os7.hostname().replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 64) || "PC";
47337
48714
  sequence = 0;
47338
48715
  connection = {
47339
48716
  state: "starting",
@@ -47514,7 +48891,7 @@ var ProductionMonitor = class {
47514
48891
  schemaVersion: 1,
47515
48892
  instanceId: this.instanceId,
47516
48893
  pid: process.pid,
47517
- savingsSourceId: path22.basename(this.file, ".json"),
48894
+ savingsSourceId: path23.basename(this.file, ".json"),
47518
48895
  lifetimeSavings: this.lifetimeSavings && { ...this.lifetimeSavings },
47519
48896
  computer: this.computer,
47520
48897
  processName: "lc-agent",
@@ -47548,9 +48925,9 @@ var ProductionMonitor = class {
47548
48925
  return this.writing;
47549
48926
  }
47550
48927
  async write(file2, contents) {
47551
- const directory = path22.dirname(file2);
48928
+ const directory = path23.dirname(file2);
47552
48929
  await mkdir9(directory, { recursive: true, mode: 448 });
47553
- const stat2 = await lstat9(directory);
48930
+ const stat2 = await lstat10(directory);
47554
48931
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw Error("MONITOR_DIRECTORY_INVALID");
47555
48932
  const temporary = file2 + "." + this.instanceId + ".tmp";
47556
48933
  const handle = await open9(temporary, "wx", 384);
@@ -47562,7 +48939,7 @@ var ProductionMonitor = class {
47562
48939
  }
47563
48940
  await rename6(temporary, file2);
47564
48941
  } finally {
47565
- await rm7(temporary, { force: true });
48942
+ await rm8(temporary, { force: true });
47566
48943
  }
47567
48944
  }
47568
48945
  async close() {
@@ -47973,27 +49350,27 @@ var NativeFabricObserver = class {
47973
49350
  };
47974
49351
 
47975
49352
  // agent/src/native-fabric-startup.ts
47976
- import { lstat as lstat11, mkdir as mkdir12, open as open11, readFile as readFile9 } from "node:fs/promises";
47977
- import path25 from "node:path";
49353
+ import { lstat as lstat12, mkdir as mkdir12, open as open11, readFile as readFile10 } from "node:fs/promises";
49354
+ import path26 from "node:path";
47978
49355
 
47979
49356
  // src/agent-fabric-service.ts
47980
- import { lstat as lstat10, mkdir as mkdir11, realpath as realpath9 } from "node:fs/promises";
49357
+ import { lstat as lstat11, mkdir as mkdir11, realpath as realpath9 } from "node:fs/promises";
47981
49358
  import { watch } from "node:fs";
47982
- import path24 from "node:path";
49359
+ import path25 from "node:path";
47983
49360
 
47984
49361
  // src/agent-runtime-identity.ts
47985
- import { createHash as createHash19, randomBytes as randomBytes7, randomUUID as randomUUID14, timingSafeEqual as timingSafeEqual4 } from "node:crypto";
49362
+ import { createHash as createHash19, randomBytes as randomBytes8, randomUUID as randomUUID14, timingSafeEqual as timingSafeEqual4 } from "node:crypto";
47986
49363
 
47987
49364
  // src/agent-fabric-state.ts
47988
49365
  import { randomUUID as randomUUID13 } from "node:crypto";
47989
- import { mkdir as mkdir10, open as open10, rename as rename7, unlink as unlink2 } from "node:fs/promises";
47990
- import path23 from "node:path";
49366
+ import { mkdir as mkdir10, open as open10, rename as rename7, unlink as unlink3 } from "node:fs/promises";
49367
+ import path24 from "node:path";
47991
49368
  var queues = /* @__PURE__ */ new Map();
47992
49369
  var FabricStateFile = class {
47993
- constructor(file2, maxBytes, parse3) {
49370
+ constructor(file2, maxBytes, parse4) {
47994
49371
  this.maxBytes = maxBytes;
47995
- this.parse = parse3;
47996
- this.file = path23.resolve(file2);
49372
+ this.parse = parse4;
49373
+ this.file = path24.resolve(file2);
47997
49374
  }
47998
49375
  maxBytes;
47999
49376
  parse;
@@ -48037,7 +49414,7 @@ var FabricStateFile = class {
48037
49414
  }
48038
49415
  update(fn, create) {
48039
49416
  return this.serial(async () => {
48040
- if (create) await mkdir10(path23.dirname(this.file), { recursive: true });
49417
+ if (create) await mkdir10(path24.dirname(this.file), { recursive: true });
48041
49418
  const lockPath = this.file + ".lock";
48042
49419
  const token = randomUUID13();
48043
49420
  const lock = await open10(lockPath, "wx", 384).catch((error62) => {
@@ -48068,7 +49445,7 @@ var FabricStateFile = class {
48068
49445
  }
48069
49446
  await rename7(temporary, this.file);
48070
49447
  } finally {
48071
- await unlink2(temporary).catch((error62) => {
49448
+ await unlink3(temporary).catch((error62) => {
48072
49449
  if (error62.code !== "ENOENT") throw error62;
48073
49450
  });
48074
49451
  }
@@ -48082,7 +49459,7 @@ var FabricStateFile = class {
48082
49459
  } finally {
48083
49460
  await current2.close();
48084
49461
  }
48085
- await unlink2(lockPath);
49462
+ await unlink3(lockPath);
48086
49463
  }
48087
49464
  });
48088
49465
  }
@@ -48136,7 +49513,7 @@ var AgentRuntimeIdentityStore = class {
48136
49513
  return this.serial((state) => {
48137
49514
  if (state.bindings.length >= MAX_BINDINGS) throw Error("RUNTIME_IDENTITY_LIMIT");
48138
49515
  const runtimeId = "rt-" + randomUUID14();
48139
- const runtimeKey = randomBytes7(32).toString("base64url");
49516
+ const runtimeKey = randomBytes8(32).toString("base64url");
48140
49517
  const now = this.now();
48141
49518
  state.bindings.push({ runtimeId, keyHash: encodedDigest(runtimeKey), createdAt: now, lastUsedAt: now, revoked: false });
48142
49519
  return { runtimeId, runtimeKey };
@@ -48681,9 +50058,9 @@ var WorkerRequest = external_exports.discriminatedUnion("operation", [
48681
50058
  var AgentFabricService = class _AgentFabricService {
48682
50059
  constructor(directory, controllerId) {
48683
50060
  this.directory = directory;
48684
- this.identities = new AgentRuntimeIdentityStore(path24.join(directory, "identities.json"));
50061
+ this.identities = new AgentRuntimeIdentityStore(path25.join(directory, "identities.json"));
48685
50062
  this.mailbox = new AgentWorkerMailbox(
48686
- path24.join(directory, "mailbox.json"),
50063
+ path25.join(directory, "mailbox.json"),
48687
50064
  controllerId,
48688
50065
  this.identities,
48689
50066
  void 0,
@@ -48698,21 +50075,21 @@ var AgentFabricService = class _AgentFabricService {
48698
50075
  closed = false;
48699
50076
  static async open(directory, controllerId, device = null, initialize = true) {
48700
50077
  const expected = Binding.parse({ version: 1, controllerId, device, initialized: false });
48701
- const absolute2 = path24.resolve(directory);
48702
- for (let current2 = absolute2; ; current2 = path24.dirname(current2)) {
50078
+ const absolute2 = path25.resolve(directory);
50079
+ for (let current2 = absolute2; ; current2 = path25.dirname(current2)) {
48703
50080
  try {
48704
- if ((await lstat10(current2)).isSymbolicLink()) throw Error("FABRIC_DIRECTORY_INVALID");
50081
+ if ((await lstat11(current2)).isSymbolicLink()) throw Error("FABRIC_DIRECTORY_INVALID");
48705
50082
  } catch (error62) {
48706
50083
  if (error62.code !== "ENOENT") throw error62;
48707
50084
  }
48708
- if (path24.dirname(current2) === current2) break;
50085
+ if (path25.dirname(current2) === current2) break;
48709
50086
  }
48710
50087
  if (initialize) await mkdir11(absolute2, { recursive: true, mode: 448 });
48711
- if (!(await lstat10(absolute2)).isDirectory() || (await realpath9(absolute2)).toLowerCase() !== absolute2.toLowerCase())
50088
+ if (!(await lstat11(absolute2)).isDirectory() || (await realpath9(absolute2)).toLowerCase() !== absolute2.toLowerCase())
48712
50089
  throw Error("FABRIC_DIRECTORY_INVALID");
48713
50090
  const present = /* @__PURE__ */ new Set();
48714
50091
  for (const name2 of ["binding.json", "mailbox.json", "identities.json"]) {
48715
- const file2 = await lstat10(path24.join(absolute2, name2)).catch((error62) => {
50092
+ const file2 = await lstat11(path25.join(absolute2, name2)).catch((error62) => {
48716
50093
  if (error62.code === "ENOENT") return null;
48717
50094
  throw error62;
48718
50095
  });
@@ -48720,7 +50097,7 @@ var AgentFabricService = class _AgentFabricService {
48720
50097
  if (file2) present.add(name2);
48721
50098
  }
48722
50099
  if (!present.has("binding.json") && present.size) throw Error("FABRIC_BINDING_MISSING");
48723
- const binding2 = new FabricStateFile(path24.join(absolute2, "binding.json"), 2048, (value) => Binding.parse(value));
50100
+ const binding2 = new FabricStateFile(path25.join(absolute2, "binding.json"), 2048, (value) => Binding.parse(value));
48724
50101
  const service2 = new _AgentFabricService(absolute2, controllerId);
48725
50102
  await binding2.update(async (state) => {
48726
50103
  if (state.controllerId !== expected.controllerId || JSON.stringify(state.device) !== JSON.stringify(expected.device))
@@ -48735,7 +50112,7 @@ var AgentFabricService = class _AgentFabricService {
48735
50112
  state.initialized = true;
48736
50113
  }
48737
50114
  const snapshot2 = await service2.mailbox.snapshot();
48738
- if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await lstat10(path24.join(absolute2, "identities.json"));
50115
+ if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await lstat11(path25.join(absolute2, "identities.json"));
48739
50116
  }, initialize ? () => expected : void 0);
48740
50117
  return service2;
48741
50118
  }
@@ -48822,19 +50199,19 @@ var Delivery = external_exports.strictObject({ capability: external_exports.stri
48822
50199
  async function openNativeFabric(stateDirectory, enrollment, box, initialize = true) {
48823
50200
  const controllerId = "device-" + external_exports.string().uuid().parse(enrollment.deviceId).toLowerCase();
48824
50201
  const tenantId = external_exports.string().uuid().parse(enrollment.tenantId).toLowerCase();
48825
- const parent = path25.join(stateDirectory, ".local-commander"), marker = path25.join(parent, "fabric-established.json");
50202
+ const parent = path26.join(stateDirectory, ".local-commander"), marker = path26.join(parent, "fabric-established.json");
48826
50203
  try {
48827
50204
  await mkdir12(parent, { mode: 448 });
48828
50205
  } catch (error62) {
48829
50206
  if (error62.code !== "EEXIST") throw error62;
48830
50207
  }
48831
- const parentInfo = await lstat11(parent);
50208
+ const parentInfo = await lstat12(parent);
48832
50209
  if (!parentInfo.isDirectory() || parentInfo.isSymbolicLink()) throw Error("FABRIC_DIRECTORY_INVALID");
48833
50210
  const expected = JSON.stringify({ version: 1, controllerId, tenantId });
48834
50211
  let fresh = false;
48835
50212
  try {
48836
- const info = await lstat11(marker);
48837
- if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await readFile9(marker, "utf8") !== expected)
50213
+ const info = await lstat12(marker);
50214
+ if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await readFile10(marker, "utf8") !== expected)
48838
50215
  throw Error("FABRIC_BINDING_CHANGED");
48839
50216
  } catch (error62) {
48840
50217
  if (error62.code !== "ENOENT" || !initialize) throw error62;
@@ -48848,22 +50225,22 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
48848
50225
  fresh = true;
48849
50226
  }
48850
50227
  const service2 = await AgentFabricService.open(
48851
- path25.join(stateDirectory, ".local-commander", "fabric"),
50228
+ path26.join(stateDirectory, ".local-commander", "fabric"),
48852
50229
  controllerId,
48853
50230
  { deviceId: enrollment.deviceId.toLowerCase(), enrollmentEvidenceRef: "enrollment-" + tenantId },
48854
50231
  fresh
48855
50232
  );
48856
50233
  const purpose = "native-fabric:" + tenantId + ":" + controllerId;
48857
- const credentialFile = (workerId) => path25.join(service2.directory, external_exports.string().uuid().parse(workerId) + ".capability");
50234
+ const credentialFile = (workerId) => path26.join(service2.directory, external_exports.string().uuid().parse(workerId) + ".capability");
48858
50235
  const decode4 = (value) => {
48859
50236
  const credential = Credential.parse(JSON.parse(box.open(Buffer.from(value, "base64"), purpose).toString("utf8")));
48860
50237
  if (credential.controllerId !== controllerId) throw Error("FABRIC_WORKER_DENIED");
48861
50238
  return credential;
48862
50239
  };
48863
50240
  async function capability(workerId) {
48864
- const file2 = credentialFile(workerId), info = await lstat11(file2);
50241
+ const file2 = credentialFile(workerId), info = await lstat12(file2);
48865
50242
  if (!info.isFile() || info.isSymbolicLink() || info.size > 4096) throw Error("FABRIC_CREDENTIAL_UNKNOWN");
48866
- const encoded = await readFile9(file2, "utf8");
50243
+ const encoded = await readFile10(file2, "utf8");
48867
50244
  if (decode4(encoded).workerId !== workerId) throw Error("FABRIC_WORKER_DENIED");
48868
50245
  return encoded;
48869
50246
  }
@@ -48955,7 +50332,7 @@ async function readFabricRequest(input2 = process.stdin) {
48955
50332
 
48956
50333
  // agent/src/supervisor-liveness.ts
48957
50334
  import { spawn as spawn6 } from "node:child_process";
48958
- import path26 from "node:path";
50335
+ import path27 from "node:path";
48959
50336
  import { setTimeout as delay3 } from "node:timers/promises";
48960
50337
  var ROW = /^"([^"]+)","(\d{1,10})"/;
48961
50338
  function parseTasklist(output2, image) {
@@ -48970,7 +50347,7 @@ function parseTasklist(output2, image) {
48970
50347
  }
48971
50348
  function listProcesses(image, timeoutMs2 = 5e3) {
48972
50349
  if (process.platform !== "win32" || !/^[A-Za-z0-9._-]{1,64}\.exe$/i.test(image)) return Promise.resolve(null);
48973
- const tasklist = path26.join(process.env.SystemRoot || "C:\\Windows", "System32", "tasklist.exe");
50350
+ const tasklist = path27.join(process.env.SystemRoot || "C:\\Windows", "System32", "tasklist.exe");
48974
50351
  return new Promise((resolve) => {
48975
50352
  let output2 = "", settled = false;
48976
50353
  const finish = (value) => {
@@ -48999,8 +50376,8 @@ function listProcesses(image, timeoutMs2 = 5e3) {
48999
50376
  }
49000
50377
  function supervisorLiveness(helperPath, options = {}) {
49001
50378
  if (process.platform === "linux" && !options.list) return linuxSupervisorLiveness;
49002
- if (process.platform === "darwin" && !options.list) return (pids, _linux, darwin) => darwinSupervisorLiveness(path26.join(path26.dirname(helperPath), "posix-host"), pids, darwin);
49003
- const image = path26.basename(helperPath), waitMs = options.waitMs ?? 1e4, pollMs = options.pollMs ?? 500, list = options.list ?? listProcesses;
50379
+ if (process.platform === "darwin" && !options.list) return (pids, _linux, darwin) => darwinSupervisorLiveness(path27.join(path27.dirname(helperPath), "posix-host"), pids, darwin);
50380
+ const image = path27.basename(helperPath), waitMs = options.waitMs ?? 1e4, pollMs = options.pollMs ?? 500, list = options.list ?? listProcesses;
49004
50381
  return async (pids) => {
49005
50382
  const deadline = Date.now() + waitMs;
49006
50383
  for (; ; ) {
@@ -49015,14 +50392,14 @@ function supervisorLiveness(helperPath, options = {}) {
49015
50392
 
49016
50393
  // agent/src/content-audit.ts
49017
50394
  import { createReadStream } from "node:fs";
49018
- import { appendFile, lstat as lstat12, mkdir as mkdir13, open as open12, readdir as readdir5, readFile as readFile10, rename as rename8, rm as rm8, writeFile as writeFile4 } from "node:fs/promises";
49019
- import path27 from "node:path";
50395
+ import { appendFile, lstat as lstat13, mkdir as mkdir13, open as open12, readdir as readdir6, readFile as readFile11, rename as rename8, rm as rm9, writeFile as writeFile4 } from "node:fs/promises";
50396
+ import path28 from "node:path";
49020
50397
  import { performance as performance3 } from "node:perf_hooks";
49021
50398
  import { createInterface as createInterface2 } from "node:readline";
49022
- import { randomBytes as randomBytes9 } from "node:crypto";
50399
+ import { randomBytes as randomBytes10 } from "node:crypto";
49023
50400
 
49024
50401
  // src/audit-crypto.ts
49025
- import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, createHash as createHash20, randomBytes as randomBytes8 } from "node:crypto";
50402
+ import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, createHash as createHash20, randomBytes as randomBytes9 } from "node:crypto";
49026
50403
  import { promisify as promisify3 } from "node:util";
49027
50404
  import { gunzipSync, gzip, gzipSync } from "node:zlib";
49028
50405
  var gzipAsync = promisify3(gzip);
@@ -49074,7 +50451,7 @@ async function encryptAuditRecordAsync(record2, keyInput, keyId2) {
49074
50451
  function sealCompressed(compressed, keyInput, keyId2) {
49075
50452
  const key = parseAuditRecoveryKey(keyInput);
49076
50453
  const kid = keyId2?.trim() || auditRecoveryKeyId(key);
49077
- const iv = randomBytes8(IV_BYTES);
50454
+ const iv = randomBytes9(IV_BYTES);
49078
50455
  try {
49079
50456
  const cipher = createCipheriv3("aes-256-gcm", key, iv, { authTagLength: TAG_BYTES });
49080
50457
  cipher.setAAD(additionalData(kid));
@@ -49185,17 +50562,17 @@ var FILE = /^(full|metrics)-(\d{4}-\d{2}-\d{2})\.jsonl$/;
49185
50562
  var PAUSED_FILE = "paused.json";
49186
50563
  var DAY_MS = 864e5;
49187
50564
  function contentAuditDirectory(stateDir) {
49188
- return path27.join(path27.dirname(path27.resolve(stateDir)), "Audit");
50565
+ return path28.join(path28.dirname(path28.resolve(stateDir)), "Audit");
49189
50566
  }
49190
50567
  async function plainDirectory(dir) {
49191
50568
  await mkdir13(dir, { recursive: true, mode: 448 });
49192
- const info = await lstat12(dir);
50569
+ const info = await lstat13(dir);
49193
50570
  if (info.isSymbolicLink() || !info.isDirectory()) throw Error("AUDIT_DIRECTORY_INVALID");
49194
50571
  }
49195
50572
  async function auditFiles(dir) {
49196
50573
  let names;
49197
50574
  try {
49198
- names = await readdir5(dir);
50575
+ names = await readdir6(dir);
49199
50576
  } catch (error62) {
49200
50577
  if (error62.code === "ENOENT") return [];
49201
50578
  throw error62;
@@ -49204,18 +50581,18 @@ async function auditFiles(dir) {
49204
50581
  for (const name2 of names) {
49205
50582
  const match = FILE.exec(name2);
49206
50583
  if (!match) continue;
49207
- const info = await lstat12(path27.join(dir, name2));
50584
+ const info = await lstat13(path28.join(dir, name2));
49208
50585
  if (info.isFile()) files.push({ name: name2, kind: match[1], day: match[2], bytes: info.size });
49209
50586
  }
49210
50587
  return files.sort((a, b) => a.name.localeCompare(b.name));
49211
50588
  }
49212
50589
  async function writeJsonAtomic(file2, value) {
49213
- const temp = `${file2}.${randomBytes9(6).toString("hex")}.tmp`;
50590
+ const temp = `${file2}.${randomBytes10(6).toString("hex")}.tmp`;
49214
50591
  try {
49215
50592
  await writeFile4(temp, JSON.stringify(value) + "\n", { flag: "wx", mode: 384 });
49216
50593
  await rename8(temp, file2);
49217
50594
  } finally {
49218
- await rm8(temp, { force: true }).catch(() => {
50595
+ await rm9(temp, { force: true }).catch(() => {
49219
50596
  });
49220
50597
  }
49221
50598
  }
@@ -49242,7 +50619,7 @@ var ContentAudit = class _ContentAudit {
49242
50619
  skipped = 0;
49243
50620
  closed = false;
49244
50621
  static async open(options) {
49245
- const dir = path27.resolve(options.directory);
50622
+ const dir = path28.resolve(options.directory);
49246
50623
  await plainDirectory(dir);
49247
50624
  const audit = new _ContentAudit(
49248
50625
  dir,
@@ -49251,7 +50628,7 @@ var ContentAudit = class _ContentAudit {
49251
50628
  { retentionDays: options.retentionDays ?? AUDIT_RETENTION_DAYS, maxBytes: options.maxBytes ?? AUDIT_MAX_BYTES },
49252
50629
  options.now ?? (() => /* @__PURE__ */ new Date())
49253
50630
  );
49254
- await rm8(path27.join(dir, PAUSED_FILE), { force: true });
50631
+ await rm9(path28.join(dir, PAUSED_FILE), { force: true });
49255
50632
  await audit.rollover(audit.now());
49256
50633
  if (audit.usedBytes >= audit.limits.maxBytes) await audit.pause("QUOTA_EXCEEDED");
49257
50634
  return audit;
@@ -49321,8 +50698,8 @@ var ContentAudit = class _ContentAudit {
49321
50698
  await this.pause("QUOTA_EXCEEDED");
49322
50699
  return;
49323
50700
  }
49324
- await appendFile(path27.join(this.dir, `full-${day}.jsonl`), line, { mode: 384 });
49325
- await appendFile(path27.join(this.dir, `metrics-${day}.jsonl`), metrics, { mode: 384 });
50701
+ await appendFile(path28.join(this.dir, `full-${day}.jsonl`), line, { mode: 384 });
50702
+ await appendFile(path28.join(this.dir, `metrics-${day}.jsonl`), metrics, { mode: 384 });
49326
50703
  this.usedBytes += bytes3;
49327
50704
  }
49328
50705
  /** Daily retention runs on the first write of a new day; no timer or background scan. */
@@ -49331,7 +50708,7 @@ var ContentAudit = class _ContentAudit {
49331
50708
  const cutoff = new Date(at.getTime() - this.limits.retentionDays * DAY_MS).toISOString().slice(0, 10);
49332
50709
  let used = 0;
49333
50710
  for (const file2 of await auditFiles(this.dir)) {
49334
- if (file2.day <= cutoff) await rm8(path27.join(this.dir, file2.name), { force: true });
50711
+ if (file2.day <= cutoff) await rm9(path28.join(this.dir, file2.name), { force: true });
49335
50712
  else used += file2.bytes;
49336
50713
  }
49337
50714
  this.usedBytes = used;
@@ -49339,7 +50716,7 @@ var ContentAudit = class _ContentAudit {
49339
50716
  async pause(reason) {
49340
50717
  if (this.paused) return;
49341
50718
  this.paused = reason;
49342
- await writeJsonAtomic(path27.join(this.dir, PAUSED_FILE), { reason, at: this.now().toISOString() });
50719
+ await writeJsonAtomic(path28.join(this.dir, PAUSED_FILE), { reason, at: this.now().toISOString() });
49343
50720
  }
49344
50721
  };
49345
50722
  function percentiles(values) {
@@ -49361,13 +50738,13 @@ async function* jsonLines(file2) {
49361
50738
  }
49362
50739
  var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
49363
50740
  async function summarizeContentAudit(directory, key) {
49364
- const dir = path27.resolve(directory);
50741
+ const dir = path28.resolve(directory);
49365
50742
  const files = await auditFiles(dir);
49366
50743
  const days = /* @__PURE__ */ new Map();
49367
50744
  const sizes = [];
49368
50745
  const timings = [];
49369
50746
  for (const file2 of files.filter((f) => f.kind === "metrics")) {
49370
- for await (const line of jsonLines(path27.join(dir, file2.name))) {
50747
+ for await (const line of jsonLines(path28.join(dir, file2.name))) {
49371
50748
  let day = days.get(file2.day);
49372
50749
  if (!day) {
49373
50750
  day = { day: file2.day, records: 0, failed: 0, rawBytes: 0, sanitizedBytes: 0, compressedBytes: 0, envelopeBytes: 0 };
@@ -49387,7 +50764,7 @@ async function summarizeContentAudit(directory, key) {
49387
50764
  }
49388
50765
  let paused = null;
49389
50766
  try {
49390
- const value = JSON.parse(await readFile10(path27.join(dir, PAUSED_FILE), "utf8"));
50767
+ const value = JSON.parse(await readFile11(path28.join(dir, PAUSED_FILE), "utf8"));
49391
50768
  if (typeof value.reason === "string" && typeof value.at === "string") paused = { reason: value.reason.slice(0, 40), at: value.at.slice(0, 40) };
49392
50769
  } catch {
49393
50770
  }
@@ -49395,7 +50772,7 @@ async function summarizeContentAudit(directory, key) {
49395
50772
  const newest = files.filter((f) => f.kind === "full").at(-1);
49396
50773
  if (key && newest) {
49397
50774
  const tail = [];
49398
- for await (const line of jsonLines(path27.join(dir, newest.name))) {
50775
+ for await (const line of jsonLines(path28.join(dir, newest.name))) {
49399
50776
  tail.push(line);
49400
50777
  if (tail.length > 5) tail.shift();
49401
50778
  }
@@ -49429,10 +50806,10 @@ async function summarizeContentAudit(directory, key) {
49429
50806
  };
49430
50807
  }
49431
50808
  async function restoreContentAudit(input2, output2, key) {
49432
- const handle = await open12(path27.resolve(output2), "wx", 384);
50809
+ const handle = await open12(path28.resolve(output2), "wx", 384);
49433
50810
  let records = 0, failed = 0;
49434
50811
  try {
49435
- for await (const line of jsonLines(path27.resolve(input2))) {
50812
+ for await (const line of jsonLines(path28.resolve(input2))) {
49436
50813
  try {
49437
50814
  await handle.appendFile(JSON.stringify(decryptAuditRecord(line, key)) + "\n");
49438
50815
  records += 1;
@@ -49447,7 +50824,7 @@ async function restoreContentAudit(input2, output2, key) {
49447
50824
  }
49448
50825
 
49449
50826
  // agent/src/main.ts
49450
- var AGENT_VERSION2 = true ? "0.3.45" : "0.3.2";
50827
+ var AGENT_VERSION2 = true ? "0.3.47" : "0.3.2";
49451
50828
  var NETWORK_PUBLIC_KEY = true ? "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvmu+81vWtJBQDZNHcAIW\nzCSxpG+R9RBsum2df5mP2cOW+wyUDTpnYquFge1qgI5YYTF96j0xCyXL8B9FeNWs\n939opWNmv53j+CQlS4cEIQhBbZSCu0eC4icsVEzBhvf68MB+E668SOtZBcVTEnyh\n96PTcupxS10rQJBWDinbKBXRC2gvGYeu01rWa/nsrndy4vAYP5t3yQtdOC8e8mr0\n+2Mg2Qhiq+KiTCtDd+L9oXvoLqqJYbzUIveNGha25AWxF1Weblp0gOM87hell5gV\nK7q4ZLUq/wBRGYNmQRdLyV7/WRE1FFPSW21/SBZQ/5aU4UqJU/MjMcrJUrnRKngz\nYKmo0czkxS3N7Q2KVxomgR1AQSuQFKMrboZYKjShADp9RIYUxzs7cYg51Of5PnHh\n6Ax+VevDGfzjMD+yHuyxYZqCtX4OwgolJxz63UQbzKlris+8xb5lLYTbIuz90Pss\nn6HK/F5May25c6oMmS3nh/NsiZopL1OvdtWKTt1L4WlRAgMBAAE=\n-----END PUBLIC KEY-----\n" : "";
49452
50829
  var AI_CONNECTION_SHIPPED = false;
49453
50830
  function processAlive(pid) {
@@ -49461,7 +50838,7 @@ function processAlive(pid) {
49461
50838
  }
49462
50839
  async function claimAgentProcess(stateDir, runtimeDir, version2) {
49463
50840
  await mkdir14(stateDir, { recursive: true });
49464
- const file2 = path28.join(stateDir, "agent-process.json");
50841
+ const file2 = path29.join(stateDir, "agent-process.json");
49465
50842
  for (let attempt = 0; attempt < 2; attempt += 1) {
49466
50843
  try {
49467
50844
  const handle = await open13(file2, "wx", 384);
@@ -49472,8 +50849,8 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
49472
50849
  }
49473
50850
  return async () => {
49474
50851
  try {
49475
- const current2 = JSON.parse(await readFile11(file2, "utf8"));
49476
- if (current2.pid === process.pid) await rm9(file2, { force: true });
50852
+ const current2 = JSON.parse(await readFile12(file2, "utf8"));
50853
+ if (current2.pid === process.pid) await rm10(file2, { force: true });
49477
50854
  } catch {
49478
50855
  }
49479
50856
  };
@@ -49481,12 +50858,12 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
49481
50858
  if (!error62 || typeof error62 !== "object" || !("code" in error62) || error62.code !== "EEXIST") throw error62;
49482
50859
  let stale = true;
49483
50860
  try {
49484
- const current2 = JSON.parse(await readFile11(file2, "utf8"));
50861
+ const current2 = JSON.parse(await readFile12(file2, "utf8"));
49485
50862
  stale = typeof current2.pid !== "number" || !processAlive(current2.pid);
49486
50863
  } catch {
49487
50864
  }
49488
50865
  if (!stale) throw Error("AGENT_ALREADY_RUNNING");
49489
- await rm9(file2, { force: true });
50866
+ await rm10(file2, { force: true });
49490
50867
  }
49491
50868
  }
49492
50869
  throw Error("AGENT_ALREADY_RUNNING");
@@ -49737,10 +51114,10 @@ async function openContentAudit(store, stateDir) {
49737
51114
  async function main() {
49738
51115
  if (!["win32", "linux", "darwin"].includes(process.platform)) throw Error("PLATFORM_UNSUPPORTED");
49739
51116
  const appData = process.env.LC_AGENT_DATA_DIR ?? (process.platform === "win32" ? process.env.LOCALAPPDATA : posixDataHome());
49740
- if (!appData || !path28.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
49741
- const stateDir = process.env.LC_AGENT_STATE_DIR ?? path28.join(appData, "LocalCommander", "Agent");
49742
- const binaryDir = path28.dirname(process.platform === "win32" ? process.execPath : await realpath10(process.execPath));
49743
- const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path28.join(binaryDir, process.platform === "win32" ? "OwnerBridge.exe" : "owner-store");
51117
+ if (!appData || !path29.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
51118
+ const stateDir = process.env.LC_AGENT_STATE_DIR ?? path29.join(appData, "LocalCommander", "Agent");
51119
+ const binaryDir = path29.dirname(process.platform === "win32" ? process.execPath : await realpath10(process.execPath));
51120
+ const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path29.join(binaryDir, process.platform === "win32" ? "OwnerBridge.exe" : "owner-store");
49744
51121
  const store = await WindowsPrivateStore.open(stateDir, ownerBridgePath);
49745
51122
  const command = process.argv[2] ?? "run";
49746
51123
  if (process.platform !== "win32" && (command.startsWith("guard-") || command.startsWith("network-"))) throw Error("FEATURE_PLATFORM_UNSUPPORTED");
@@ -49750,7 +51127,7 @@ async function main() {
49750
51127
  const pairing = new PairingClient(store, { controlPlaneOrigin: origin, agentVersion: AGENT_VERSION2 });
49751
51128
  const begun = await pairing.begin();
49752
51129
  process.stdout.write(JSON.stringify({ approvalUrl: begun.approvalUrl, confirmationCode: begun.confirmationCode, expiresAt: begun.expiresAt.toISOString() }) + "\n");
49753
- await pairing.waitAndComplete(begun, os7.hostname().slice(0, 120));
51130
+ await pairing.waitAndComplete(begun, os8.hostname().slice(0, 120));
49754
51131
  process.stdout.write("DEVICE_PAIRED\n");
49755
51132
  return;
49756
51133
  }
@@ -49835,7 +51212,7 @@ async function main() {
49835
51212
  }
49836
51213
  if (command === "efficiency-report") {
49837
51214
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
49838
- const ledger = await OptimizationLedger.open(path28.join(stateDir, "optimization"));
51215
+ const ledger = await OptimizationLedger.open(path29.join(stateDir, "optimization"));
49839
51216
  try {
49840
51217
  process.stdout.write(JSON.stringify(await ledger.report(), null, 2) + "\n");
49841
51218
  } finally {
@@ -49845,7 +51222,7 @@ async function main() {
49845
51222
  }
49846
51223
  if (command === "guard-configure") {
49847
51224
  if (args.length !== 1) throw Error("AGENT_COMMAND_INVALID");
49848
- const filename = await (await import("node:fs/promises")).realpath(path28.resolve(args[0]));
51225
+ const filename = await (await import("node:fs/promises")).realpath(path29.resolve(args[0]));
49849
51226
  const input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readWindowsFile(ownerBridgePath, filename, 2e5)));
49850
51227
  if (!input2 || typeof input2 !== "object" || Object.keys(input2).sort().join(",") !== "compact,settings") throw Error("GUARD_CONFIGURATION_INVALID");
49851
51228
  await store.configureGuard(input2.settings, input2.compact);
@@ -49864,7 +51241,7 @@ async function main() {
49864
51241
  }
49865
51242
  if (command === "guard-evidence") {
49866
51243
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
49867
- const journal = await NativeJournal.open(path28.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
51244
+ const journal = await NativeJournal.open(path29.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
49868
51245
  try {
49869
51246
  process.stdout.write(JSON.stringify(await journal.guardEvidence()) + "\n");
49870
51247
  } finally {
@@ -49876,7 +51253,7 @@ async function main() {
49876
51253
  if (args.length !== (command === "guard-export" ? 0 : 1)) throw Error("AGENT_COMMAND_INVALID");
49877
51254
  const identity = await store.load();
49878
51255
  if (!identity?.enrollment) throw Error("ENROLLMENT_MISSING");
49879
- const journal = await NativeJournal.open(path28.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
51256
+ const journal = await NativeJournal.open(path29.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
49880
51257
  try {
49881
51258
  const { tenantId, deviceId } = identity.enrollment;
49882
51259
  const records = (await journal.guardEvidence()).filter((record2) => record2.tenantId === tenantId && record2.deviceId === deviceId);
@@ -49954,27 +51331,27 @@ async function main() {
49954
51331
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
49955
51332
  if (!(await store.load())?.enrollment) throw Error("ENROLLMENT_MISSING");
49956
51333
  const releaseProcess = await claimAgentProcess(stateDir, binaryDir, AGENT_VERSION2);
49957
- const monitor = new ProductionMonitor(path28.join(appData, "LocalCommander", "Monitor"), stateDir, AGENT_VERSION2);
51334
+ const monitor = new ProductionMonitor(path29.join(appData, "LocalCommander", "Monitor"), stateDir, AGENT_VERSION2);
49958
51335
  const publishMonitor = () => monitor.flush().catch(() => {
49959
51336
  process.stderr.write("MONITOR_WRITE_FAILED\n");
49960
51337
  });
49961
51338
  await publishMonitor();
49962
51339
  try {
49963
51340
  const journal = await NativeJournal.open(
49964
- path28.join(stateDir, "journal"),
51341
+ path29.join(stateDir, "journal"),
49965
51342
  new SecretBox({ "1": await store.loadDataKey() }),
49966
- process.platform === "win32" ? {} : { lockHelper: path28.join(binaryDir, "posix-host") }
51343
+ process.platform === "win32" ? {} : { lockHelper: path29.join(binaryDir, "posix-host") }
49967
51344
  );
49968
51345
  const ledgerLoss = () => {
49969
51346
  process.stderr.write("OPTIMIZATION_TELEMETRY_INCOMPLETE\n");
49970
51347
  };
49971
51348
  const efficiencyLedger = await new OptionalWork(ledgerLoss, 1e3, 1).run(
49972
- () => OptimizationLedger.open(path28.join(stateDir, "optimization")),
51349
+ () => OptimizationLedger.open(path29.join(stateDir, "optimization")),
49973
51350
  void 0,
49974
51351
  (ledger) => ledger.close()
49975
51352
  );
49976
51353
  try {
49977
- const helperPath = process.env.LC_JOB_HOST ?? path28.join(binaryDir, process.platform === "win32" ? "JobHost.exe" : "job-host.mjs");
51354
+ const helperPath = process.env.LC_JOB_HOST ?? path29.join(binaryDir, process.platform === "win32" ? "JobHost.exe" : "job-host.mjs");
49978
51355
  const tools = new NativeTools({ stateDirectory: stateDir, helperPath, ownerBridgePath, programs: await store.loadPrograms() });
49979
51356
  const stop = new AbortController();
49980
51357
  process.once("SIGINT", () => stop.abort());
@@ -50045,7 +51422,7 @@ async function main() {
50045
51422
  await releaseProcess();
50046
51423
  }
50047
51424
  }
50048
- var entrypoint = process.argv[1] && (process.platform === "win32" ? path28.resolve(process.argv[1]) : await realpath10(process.argv[1]).catch(() => null));
51425
+ var entrypoint = process.argv[1] && (process.platform === "win32" ? path29.resolve(process.argv[1]) : await realpath10(process.argv[1]).catch(() => null));
50049
51426
  if (entrypoint === fileURLToPath(import.meta.url)) {
50050
51427
  void main().catch((error62) => {
50051
51428
  const code = error62 instanceof Error && /^[A-Z0-9_]{1,64}$/.test(error62.message) ? error62.message : "AGENT_START_FAILED";