local-commander-agent 0.3.44 → 0.3.46

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
@@ -4541,10 +4541,10 @@ function mergeDefs(...defs) {
4541
4541
  function cloneDef(schema) {
4542
4542
  return mergeDefs(schema._zod.def);
4543
4543
  }
4544
- function getElementAtPath(obj, path29) {
4545
- if (!path29)
4544
+ function getElementAtPath(obj, path30) {
4545
+ if (!path30)
4546
4546
  return obj;
4547
- return path29.reduce((acc, key) => acc?.[key], obj);
4547
+ return path30.reduce((acc, key) => acc?.[key], obj);
4548
4548
  }
4549
4549
  function promiseAllObject(promisesObj) {
4550
4550
  const keys = Object.keys(promisesObj);
@@ -4884,11 +4884,11 @@ function explicitlyAborted(x, startIndex = 0) {
4884
4884
  }
4885
4885
  return false;
4886
4886
  }
4887
- function prefixIssues(path29, issues) {
4887
+ function prefixIssues(path30, issues) {
4888
4888
  return issues.map((iss) => {
4889
4889
  var _a3;
4890
4890
  (_a3 = iss).path ?? (_a3.path = []);
4891
- iss.path.unshift(path29);
4891
+ iss.path.unshift(path30);
4892
4892
  return iss;
4893
4893
  });
4894
4894
  }
@@ -5338,16 +5338,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
5338
5338
  }
5339
5339
  function formatError(error62, mapper = (issue2) => issue2.message) {
5340
5340
  const fieldErrors = { _errors: [] };
5341
- const processError = (error63, path29 = []) => {
5341
+ const processError = (error63, path30 = []) => {
5342
5342
  for (const issue2 of error63.issues) {
5343
5343
  if (issue2.code === "invalid_union" && issue2.errors.length) {
5344
- issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
5344
+ issue2.errors.map((issues) => processError({ issues }, [...path30, ...issue2.path]));
5345
5345
  } else if (issue2.code === "invalid_key") {
5346
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5346
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5347
5347
  } else if (issue2.code === "invalid_element") {
5348
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5348
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5349
5349
  } else {
5350
- const fullpath = [...path29, ...issue2.path];
5350
+ const fullpath = [...path30, ...issue2.path];
5351
5351
  if (fullpath.length === 0) {
5352
5352
  fieldErrors._errors.push(mapper(issue2));
5353
5353
  } else {
@@ -5386,17 +5386,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
5386
5386
  }
5387
5387
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
5388
5388
  const result2 = { errors: [] };
5389
- const processError = (error63, path29 = []) => {
5389
+ const processError = (error63, path30 = []) => {
5390
5390
  var _a3;
5391
5391
  for (const issue2 of error63.issues) {
5392
5392
  if (issue2.code === "invalid_union" && issue2.errors.length) {
5393
- issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
5393
+ issue2.errors.map((issues) => processError({ issues }, [...path30, ...issue2.path]));
5394
5394
  } else if (issue2.code === "invalid_key") {
5395
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5395
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5396
5396
  } else if (issue2.code === "invalid_element") {
5397
- processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
5397
+ processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
5398
5398
  } else {
5399
- const fullpath = [...path29, ...issue2.path];
5399
+ const fullpath = [...path30, ...issue2.path];
5400
5400
  if (fullpath.length === 0) {
5401
5401
  result2.errors.push(mapper(issue2));
5402
5402
  continue;
@@ -5435,8 +5435,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
5435
5435
  }
5436
5436
  function toDotPath(_path) {
5437
5437
  const segs = [];
5438
- const path29 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
5439
- for (const seg of path29) {
5438
+ const path30 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
5439
+ for (const seg of path30) {
5440
5440
  if (typeof seg === "number")
5441
5441
  segs.push(`[${seg}]`);
5442
5442
  else if (typeof seg === "symbol")
@@ -22538,13 +22538,13 @@ function resolveRef(ref, ctx) {
22538
22538
  if (!ref.startsWith("#")) {
22539
22539
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
22540
22540
  }
22541
- const path29 = ref.slice(1).split("/").filter(Boolean);
22542
- if (path29.length === 0) {
22541
+ const path30 = ref.slice(1).split("/").filter(Boolean);
22542
+ if (path30.length === 0) {
22543
22543
  return ctx.rootSchema;
22544
22544
  }
22545
22545
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
22546
- if (path29[0] === defsKey) {
22547
- const key = path29[1] === void 0 ? void 0 : decodeJSONPointerSegment(path29[1]);
22546
+ if (path30[0] === defsKey) {
22547
+ const key = path30[1] === void 0 ? void 0 : decodeJSONPointerSegment(path30[1]);
22548
22548
  if (!key || !ctx.defs[key]) {
22549
22549
  throw new Error(`Reference not found: ${ref}`);
22550
22550
  }
@@ -23179,7 +23179,7 @@ function visit(schema, fnOrHandlers) {
23179
23179
  return h ? h(node2, rewritten) : node2;
23180
23180
  };
23181
23181
  const cache2 = /* @__PURE__ */ new Map();
23182
- function run(s) {
23182
+ function run2(s) {
23183
23183
  const cached2 = cache2.get(s);
23184
23184
  if (cached2 === RESOLVING) {
23185
23185
  return new $ZodLazy({
@@ -23205,21 +23205,21 @@ function visit(schema, fnOrHandlers) {
23205
23205
  let changed = false;
23206
23206
  const newShape = {};
23207
23207
  for (const k of keys) {
23208
- const mapped = run(oldShape[k]);
23208
+ const mapped = run2(oldShape[k]);
23209
23209
  if (mapped !== oldShape[k])
23210
23210
  changed = true;
23211
23211
  newShape[k] = mapped;
23212
23212
  }
23213
23213
  let newCatchall = def.catchall;
23214
23214
  if (def.catchall) {
23215
- newCatchall = run(def.catchall);
23215
+ newCatchall = run2(def.catchall);
23216
23216
  if (newCatchall !== def.catchall)
23217
23217
  changed = true;
23218
23218
  }
23219
23219
  return changed ? clone(s, { ...def, shape: newShape, catchall: newCatchall }) : s;
23220
23220
  }
23221
23221
  case "array": {
23222
- const mapped = run(def.element);
23222
+ const mapped = run2(def.element);
23223
23223
  return mapped === def.element ? s : clone(s, { ...def, element: mapped });
23224
23224
  }
23225
23225
  case "tuple": {
@@ -23227,14 +23227,14 @@ function visit(schema, fnOrHandlers) {
23227
23227
  let changed = false;
23228
23228
  const newItems = [];
23229
23229
  for (const item of oldItems) {
23230
- const mapped = run(item);
23230
+ const mapped = run2(item);
23231
23231
  if (mapped !== item)
23232
23232
  changed = true;
23233
23233
  newItems.push(mapped);
23234
23234
  }
23235
23235
  let newRest = def.rest;
23236
23236
  if (def.rest) {
23237
- newRest = run(def.rest);
23237
+ newRest = run2(def.rest);
23238
23238
  if (newRest !== def.rest)
23239
23239
  changed = true;
23240
23240
  }
@@ -23242,12 +23242,12 @@ function visit(schema, fnOrHandlers) {
23242
23242
  }
23243
23243
  case "record":
23244
23244
  case "map": {
23245
- const newKey = run(def.keyType);
23246
- const newVal = run(def.valueType);
23245
+ const newKey = run2(def.keyType);
23246
+ const newVal = run2(def.valueType);
23247
23247
  return newKey === def.keyType && newVal === def.valueType ? s : clone(s, { ...def, keyType: newKey, valueType: newVal });
23248
23248
  }
23249
23249
  case "set": {
23250
- const newVal = run(def.valueType);
23250
+ const newVal = run2(def.valueType);
23251
23251
  return newVal === def.valueType ? s : clone(s, { ...def, valueType: newVal });
23252
23252
  }
23253
23253
  case "union": {
@@ -23255,7 +23255,7 @@ function visit(schema, fnOrHandlers) {
23255
23255
  let changed = false;
23256
23256
  const newOptions = [];
23257
23257
  for (const opt of oldOptions) {
23258
- const mapped = run(opt);
23258
+ const mapped = run2(opt);
23259
23259
  if (mapped !== opt)
23260
23260
  changed = true;
23261
23261
  newOptions.push(mapped);
@@ -23263,8 +23263,8 @@ function visit(schema, fnOrHandlers) {
23263
23263
  return changed ? clone(s, { ...def, options: newOptions }) : s;
23264
23264
  }
23265
23265
  case "intersection": {
23266
- const newLeft = run(def.left);
23267
- const newRight = run(def.right);
23266
+ const newLeft = run2(def.left);
23267
+ const newRight = run2(def.right);
23268
23268
  return newLeft === def.left && newRight === def.right ? s : clone(s, { ...def, left: newLeft, right: newRight });
23269
23269
  }
23270
23270
  case "optional":
@@ -23276,23 +23276,23 @@ function visit(schema, fnOrHandlers) {
23276
23276
  case "nonoptional":
23277
23277
  case "promise":
23278
23278
  case "success": {
23279
- const newInner = run(def.innerType);
23279
+ const newInner = run2(def.innerType);
23280
23280
  return newInner === def.innerType ? s : clone(s, { ...def, innerType: newInner });
23281
23281
  }
23282
23282
  case "pipe": {
23283
- const newIn = run(def.in);
23284
- const newOut = run(def.out);
23283
+ const newIn = run2(def.in);
23284
+ const newOut = run2(def.out);
23285
23285
  return newIn === def.in && newOut === def.out ? s : clone(s, { ...def, in: newIn, out: newOut });
23286
23286
  }
23287
23287
  case "function": {
23288
- const newInput = run(def.input);
23289
- const newOutput = run(def.output);
23288
+ const newInput = run2(def.input);
23289
+ const newOutput = run2(def.output);
23290
23290
  return newInput === def.input && newOutput === def.output ? s : clone(s, { ...def, input: newInput, output: newOutput });
23291
23291
  }
23292
23292
  case "lazy": {
23293
23293
  const original = def.getter;
23294
23294
  const { _cachedInner, ...rest } = def;
23295
- return clone(s, { ...rest, getter: () => run(original()) });
23295
+ return clone(s, { ...rest, getter: () => run2(original()) });
23296
23296
  }
23297
23297
  // A leaf by choice: `parts` are regex fragments, not data positions.
23298
23298
  case "template_literal":
@@ -23323,7 +23323,7 @@ function visit(schema, fnOrHandlers) {
23323
23323
  }
23324
23324
  }
23325
23325
  }
23326
- return run(schema);
23326
+ return run2(schema);
23327
23327
  }
23328
23328
 
23329
23329
  // ../../node_modules/zod/v4/classic/deep-partial.js
@@ -25164,8 +25164,8 @@ async function openNetworkPanel(binaryDirectory, identity) {
25164
25164
  }
25165
25165
 
25166
25166
  // agent/src/main.ts
25167
- import path28 from "node:path";
25168
- import os7 from "node:os";
25167
+ import path29 from "node:path";
25168
+ import os8 from "node:os";
25169
25169
 
25170
25170
  // agent/src/posix-store.ts
25171
25171
  import { constants } from "node:fs";
@@ -25388,6 +25388,7 @@ async function secretCommand(executable, args, input2) {
25388
25388
  async function secretServicePresent() {
25389
25389
  const bus = path3.join("/run/user", String(process.getuid()), "bus");
25390
25390
  if (!process.env.DBUS_SESSION_BUS_ADDRESS && await absent(bus)) return false;
25391
+ if (await absent("/usr/bin/gdbus")) return false;
25391
25392
  const args = ["call", "--session", "--dest", "org.freedesktop.DBus", "--object-path", "/org/freedesktop/DBus", "--method"];
25392
25393
  for (const method of ["org.freedesktop.DBus.ListNames", "org.freedesktop.DBus.ListActivatableNames"]) {
25393
25394
  const output2 = (await secretCommand("/usr/bin/gdbus", [...args, method])).toString("utf8");
@@ -25583,7 +25584,7 @@ async function acquirePosixJournalGuard(directory, helper) {
25583
25584
  }
25584
25585
 
25585
25586
  // agent/src/main.ts
25586
- import { mkdir as mkdir14, open as open13, readFile as readFile11, realpath as realpath10, rm as rm9 } from "node:fs/promises";
25587
+ import { mkdir as mkdir14, open as open13, readFile as readFile12, realpath as realpath10, rm as rm10 } from "node:fs/promises";
25587
25588
  import { fileURLToPath } from "node:url";
25588
25589
 
25589
25590
  // packages/operations/src/crypto.ts
@@ -25720,13 +25721,13 @@ var exec2 = promisify2(execFile2);
25720
25721
  async function darwinSupervisorLiveness(helper, pids, records = []) {
25721
25722
  if (process.platform !== "darwin" || !process.getuid?.() || process.getuid() !== process.geteuid?.()) return null;
25722
25723
  const remaining = new Set(pids), uid = process.getuid(), deadline = Date.now() + 1e4, env = buildChildEnvironment(process.env);
25723
- const run = (file2, args) => exec2(
25724
+ const run2 = (file2, args) => exec2(
25724
25725
  file2,
25725
25726
  args,
25726
25727
  { env, timeout: Math.max(1, Math.min(7e3, deadline - Date.now())), maxBuffer: 8192, encoding: "utf8", windowsHide: true }
25727
25728
  );
25728
25729
  try {
25729
- const boot = (await run("/usr/sbin/sysctl", ["-n", "kern.bootsessionuuid"])).stdout.trim();
25730
+ const boot = (await run2("/usr/sbin/sysctl", ["-n", "kern.bootsessionuuid"])).stdout.trim();
25730
25731
  if (!bootSession.test(boot)) return null;
25731
25732
  for (const pid of remaining) {
25732
25733
  if (Date.now() >= deadline) break;
@@ -25735,9 +25736,9 @@ async function darwinSupervisorLiveness(helper, pids, records = []) {
25735
25736
  const proof2 = matches2[0].containment;
25736
25737
  if (!validDarwinContainment(proof2) || proof2.uid !== uid || proof2.bootSession !== boot) continue;
25737
25738
  try {
25738
- await run(helper, ["--reap", proof2.coalition]);
25739
- if ((await run(helper, ["--count", proof2.coalition])).stdout.trim() !== "0") continue;
25740
- await run("/bin/launchctl", ["bootout", "gui/" + uid + "/" + proof2.label]).catch(() => {
25739
+ await run2(helper, ["--reap", proof2.coalition]);
25740
+ if ((await run2(helper, ["--count", proof2.coalition])).stdout.trim() !== "0") continue;
25741
+ await run2("/bin/launchctl", ["bootout", "gui/" + uid + "/" + proof2.label]).catch(() => {
25741
25742
  });
25742
25743
  remaining.delete(pid);
25743
25744
  } catch {
@@ -26444,10 +26445,12 @@ var ToolCallSchema = external_exports.discriminatedUnion("name", [
26444
26445
  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(),
26445
26446
  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(),
26446
26447
  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(),
26448
+ // Still image of the device's primary display; the agent requires an owner Full Access workspace.
26449
+ external_exports.object({ name: external_exports.literal("take_screenshot"), args: external_exports.object({}).strict() }).strict(),
26447
26450
  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()
26448
26451
  ]);
26449
26452
  function scopeForTool(call) {
26450
- if (call.name === "command_run") return "commands:execute";
26453
+ if (call.name === "command_run" || call.name === "take_screenshot") return "commands:execute";
26451
26454
  if (call.name === "localhost_request") return "localhost:access";
26452
26455
  return call.name === "fs_write" || call.name === "fs_replace" ? "files:write" : "files:read";
26453
26456
  }
@@ -26484,6 +26487,7 @@ var NativeCapacitySchema = external_exports.object({ type: external_exports.lite
26484
26487
  var NATIVE_STATUS_CAPABILITY = "nativeStatusV1";
26485
26488
  var NativeStatusSchema = NativeCapacitySchema.extend({ type: external_exports.literal("nativeStatus"), active: external_exports.number().int().min(0).max(32), queued: external_exports.number().int().min(0).max(256), paused: external_exports.boolean() }).strict().refine((v) => v.active <= v.safeSlots);
26486
26489
  var TerminalEventSchema = external_exports.object({ type: external_exports.literal("executionResult"), protocolVersion: external_exports.literal(1), requestId: uuid11, tenantId: uuid11, deviceId: uuid11, connectionEpoch: epoch2, binding: ExecutionBindingSchema, state: external_exports.enum(["finished", "failed", "cancelled", "unknown", "rejected"]), resultCode: external_exports.string().regex(/^[A-Z0-9_]{1,40}$/), metrics: TerminalMetricsSchema.optional() }).strict();
26490
+ var HeldLeasesFrameSchema = external_exports.object({ type: external_exports.literal("heldLeases"), protocolVersion: external_exports.literal(1), connectionEpoch: epoch2, bindings: external_exports.array(ExecutionBindingSchema).min(1).max(64) }).strict();
26487
26491
  var TerminalEventAckSchema = external_exports.object({ type: external_exports.literal("executionResultAck"), protocolVersion: external_exports.literal(1), requestId: uuid11, ok: external_exports.boolean() }).strict();
26488
26492
  function canonicalJson(value) {
26489
26493
  function canonical2(v) {
@@ -26550,6 +26554,7 @@ function guardAction(binding2, tool, config2, observedAt) {
26550
26554
  throw Error("GUARD_IDENTITY_REQUIRED");
26551
26555
  }
26552
26556
  const name2 = tool.call.name;
26557
+ if (name2 === "take_screenshot") throw Error("GUARD_ACTION_UNSUPPORTED");
26553
26558
  const kind = name2 === "command_run" ? "execute" : name2 === "localhost_request" ? "localhost-access" : name2 === "fs_write" || name2 === "fs_replace" ? "write" : name2.startsWith("git_") ? "git-read" : "read";
26554
26559
  const resourceKind = kind === "execute" ? "workspace" : kind === "localhost-access" ? "localhost-service" : kind === "git-read" ? "git-repository" : name2 === "fs_read" || kind === "write" ? "file" : "workspace";
26555
26560
  return { payloadHash: guardHash(tool.effective), request: BoundActionRequestSchema.parse({
@@ -26763,9 +26768,19 @@ var NativeJournal = class _NativeJournal {
26763
26768
  sizes = /* @__PURE__ */ new Map();
26764
26769
  digests = /* @__PURE__ */ new Map();
26765
26770
  totalBytes = 0;
26771
+ /** First connection epoch this journal saw (#448): from then on every received request has an entry. "0" for a journal
26772
+ * an older agent created (continuous since pairing); null until a new journal's first connection. */
26773
+ firstEpoch = null;
26766
26774
  static async open(directory, box, options = {}) {
26767
26775
  const maxEntries = options.maxEntries ?? 2e3, maxBytes = options.maxBytes ?? 64 * 1048576, retentionMs = options.retentionMs ?? 864e5;
26768
26776
  if (!Number.isInteger(maxEntries) || maxEntries < 1 || maxEntries > 1e4 || !Number.isInteger(maxBytes) || maxBytes < 1024 || maxBytes > 64 * 1048576 || !Number.isInteger(retentionMs) || retentionMs < 0 || retentionMs > 30 * 864e5) throw failure2("JOURNAL_LIMIT_INVALID");
26777
+ let existed = true;
26778
+ try {
26779
+ await lstat2(path6.resolve(directory));
26780
+ } catch (e) {
26781
+ if (e.code !== "ENOENT") throw e;
26782
+ existed = false;
26783
+ }
26769
26784
  const dir = await safeDirectory(directory), lockPath = path6.join(dir, "journal.lock"), nonce2 = randomBytes4(16).toString("hex");
26770
26785
  const guard = options.lockHelper ? await acquirePosixJournalGuard(dir, options.lockHelper) : void 0;
26771
26786
  let file2;
@@ -26781,6 +26796,7 @@ var NativeJournal = class _NativeJournal {
26781
26796
  await file2.writeFile(JSON.stringify({ pid: process.pid, nonce: nonce2, createdAt: journal.now().toISOString() }));
26782
26797
  await file2.sync();
26783
26798
  await journal.load();
26799
+ await journal.loadStart(existed);
26784
26800
  return journal;
26785
26801
  } catch (e) {
26786
26802
  await file2.close().catch(() => {
@@ -26862,6 +26878,65 @@ var NativeJournal = class _NativeJournal {
26862
26878
  this.digests.set(id2, digest2(envelope));
26863
26879
  }
26864
26880
  }
26881
+ async loadStart(existed) {
26882
+ const filename = path6.join(this.dir, "journal.start");
26883
+ let envelope;
26884
+ try {
26885
+ const stat2 = await lstat2(filename);
26886
+ if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > 4096) throw failure2("JOURNAL_CORRUPT");
26887
+ envelope = await readFile3(filename);
26888
+ } catch (e) {
26889
+ if (e.code !== "ENOENT") throw e;
26890
+ return this.writeStart(existed ? "0" : null);
26891
+ }
26892
+ try {
26893
+ const value = JSON.parse(this.box.open(envelope, "journal-start").toString("utf8"));
26894
+ if (value?.version !== 1 || Object.keys(value).length !== 2 || value.firstEpoch !== null && (typeof value.firstEpoch !== "string" || !/^(0|[1-9]\d{0,18})$/.test(value.firstEpoch))) throw Error();
26895
+ this.firstEpoch = value.firstEpoch;
26896
+ } catch {
26897
+ throw failure2("JOURNAL_CORRUPT");
26898
+ }
26899
+ }
26900
+ async writeStart(firstEpoch) {
26901
+ const temporary = path6.join(this.dir, "journal-start." + this.lock.nonce + "." + randomBytes4(8).toString("hex") + ".tmp");
26902
+ const handle = await open3(temporary, constants2.O_CREAT | constants2.O_EXCL | constants2.O_WRONLY, 384);
26903
+ try {
26904
+ await handle.writeFile(this.box.seal(Buffer.from(JSON.stringify({ version: 1, firstEpoch })), "journal-start"));
26905
+ await handle.sync();
26906
+ await handle.close();
26907
+ await rename(temporary, path6.join(this.dir, "journal.start"));
26908
+ if (process.platform !== "win32") {
26909
+ const d = await open3(this.dir, constants2.O_RDONLY);
26910
+ try {
26911
+ await d.sync();
26912
+ } finally {
26913
+ await d.close();
26914
+ }
26915
+ }
26916
+ } catch (e) {
26917
+ await handle.close().catch(() => {
26918
+ });
26919
+ await rm2(temporary, { force: true }).catch(() => {
26920
+ });
26921
+ throw e;
26922
+ }
26923
+ this.firstEpoch = firstEpoch;
26924
+ }
26925
+ /** Called on every connection before any request of it is served; only the first one is recorded. */
26926
+ recordConnection(connectionEpoch) {
26927
+ return this.enqueue(async () => {
26928
+ if (!/^[1-9]\d{0,18}$/.test(connectionEpoch)) throw failure2("JOURNAL_INPUT_INVALID");
26929
+ if (this.firstEpoch === null) await this.writeStart(connectionEpoch);
26930
+ });
26931
+ }
26932
+ /** True only when this journal existed for the whole connection that leased the request and has no entry for it:
26933
+ * every received request is journaled synchronously on arrival, before it can start (#448). */
26934
+ neverReceived(executionId, connectionEpoch) {
26935
+ return this.enqueue(async () => {
26936
+ if (!uuid14.test(executionId) || !/^[1-9]\d{0,18}$/.test(connectionEpoch)) throw failure2("JOURNAL_INPUT_INVALID");
26937
+ return this.firstEpoch !== null && BigInt(connectionEpoch) >= BigInt(this.firstEpoch) && !this.entries.has(executionId);
26938
+ });
26939
+ }
26865
26940
  async persist(entry) {
26866
26941
  const st = await lstat2(this.dir);
26867
26942
  if (!st.isDirectory() || st.isSymbolicLink()) throw failure2("JOURNAL_DIRECTORY_INVALID");
@@ -27161,6 +27236,7 @@ import { constants as constants4 } from "node:fs";
27161
27236
 
27162
27237
  // agent/src/posix-consent.ts
27163
27238
  import { openSync, closeSync } from "node:fs";
27239
+ import { spawnSync as spawnSync2 } from "node:child_process";
27164
27240
  import { isatty, ReadStream, WriteStream } from "node:tty";
27165
27241
  import { createInterface } from "node:readline/promises";
27166
27242
  import path8 from "node:path";
@@ -27263,7 +27339,7 @@ async function planPermissionChange(current2, programs, input2) {
27263
27339
  }
27264
27340
 
27265
27341
  // agent/src/posix-consent.ts
27266
- async function terminal2(run, timeoutMs2, signal) {
27342
+ async function terminal2(run2, timeoutMs2, signal) {
27267
27343
  if (!process.getuid || process.getuid() === 0 || process.geteuid?.() !== process.getuid() || signal?.aborted) throw Error("OWNER_REVIEW_UNAVAILABLE");
27268
27344
  let readFd;
27269
27345
  try {
@@ -27299,7 +27375,7 @@ async function terminal2(run, timeoutMs2, signal) {
27299
27375
  };
27300
27376
  input2.on("data", bound);
27301
27377
  try {
27302
- return await run(async (prompt) => {
27378
+ return await run2(async (prompt) => {
27303
27379
  if (stop.signal.aborted) throw Error("OWNER_REVIEW_CANCELLED");
27304
27380
  return review.question(prompt, { signal: stop.signal });
27305
27381
  });
@@ -27328,16 +27404,41 @@ async function choosePosixFolder() {
27328
27404
  return await ask("Read/write folder: " + permissionLabel(folder) + "\nType APPROVE to accept: ") === "APPROVE" ? folder : null;
27329
27405
  }, 12e4);
27330
27406
  }
27407
+ 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.";
27408
+ function selection(folder, full) {
27409
+ if (!path8.isAbsolute(folder) || folder.length > 4096 || /[\u0000-\u001f]/.test(folder)) throw Error("WORKSPACE_INVALID");
27410
+ return { mode: full ? "all-drives" : "folders", paths: [full ? "/" : folder] };
27411
+ }
27412
+ function macDialog() {
27413
+ const script = [
27414
+ "on run argv",
27415
+ '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)',
27416
+ 'if answer is "Full Access" then return "full"',
27417
+ 'return "folder:" & POSIX path of (choose folder with prompt "Choose the folder Local Commander may read and write")',
27418
+ "end run"
27419
+ ];
27420
+ const result2 = spawnSync2(
27421
+ "/usr/bin/osascript",
27422
+ [...script.flatMap((line) => ["-e", line]), ACCESS_TEXT],
27423
+ { encoding: "utf8", timeout: 24e4, maxBuffer: 16384, shell: false }
27424
+ );
27425
+ if (result2.error) return void 0;
27426
+ if (result2.status !== 0) return /\(-128\)/.test(result2.stderr) ? null : void 0;
27427
+ const out = result2.stdout.replace(/\n$/, "");
27428
+ if (out === "full") return selection("/", true);
27429
+ if (out.startsWith("folder:")) return selection(out.slice(7).replace(/(.)\/$/, "$1"), false);
27430
+ return void 0;
27431
+ }
27331
27432
  async function choosePosixAccess() {
27433
+ if (process.platform === "darwin") {
27434
+ const chosen = macDialog();
27435
+ if (chosen !== void 0) return chosen;
27436
+ }
27332
27437
  return terminal2(async (ask) => {
27333
- 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: ");
27334
- 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): ");
27335
- if (choice !== "1" && choice !== "2") return null;
27336
- const folder = choice === "2" ? "/" : await ask("Absolute folder path: ");
27337
- if (!path8.isAbsolute(folder) || folder.length > 4096 || /[\u0000-\u001f]/.test(folder)) throw Error("WORKSPACE_INVALID");
27338
- 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) + ".";
27339
- if (await ask(summary + "\nThis replaces the previous folder/command/localhost selection and persists until revoked.\nType APPROVE to accept: ") !== "APPROVE") return null;
27340
- return { mode: choice === "2" ? "all-drives" : "folders", paths: [folder] };
27438
+ const answer = await ask("\n" + ACCESS_TEXT + "\n\nPress Enter for Full Access, type a folder path for one folder, or n to cancel: ");
27439
+ if (answer === "") return selection("/", true);
27440
+ if (/^(n|no|cancel)$/i.test(answer)) return null;
27441
+ return selection(answer, false);
27341
27442
  }, 24e4);
27342
27443
  }
27343
27444
 
@@ -28805,8 +28906,8 @@ var HostMemory = class {
28805
28906
 
28806
28907
  // agent/src/tools.ts
28807
28908
  import { constants as constants7 } from "node:fs";
28808
- import { lstat as lstat7, open as open6, readdir as readdir4, realpath as realpath7, rename as rename4, rm as rm5 } from "node:fs/promises";
28809
- import path17 from "node:path";
28909
+ import { lstat as lstat7, open as open6, readdir as readdir4, realpath as realpath7, rename as rename4, rm as rm6 } from "node:fs/promises";
28910
+ import path18 from "node:path";
28810
28911
  import { createHash as createHash14, randomUUID as randomUUID7 } from "node:crypto";
28811
28912
 
28812
28913
  // src/guard.ts
@@ -29250,6 +29351,116 @@ async function runSupervised(helper, request, options = {}) {
29250
29351
  });
29251
29352
  }
29252
29353
 
29354
+ // agent/src/screen-capture.ts
29355
+ import { execFile as execFile4 } from "node:child_process";
29356
+ import { mkdtemp, readFile as readFile6, rm as rm5 } from "node:fs/promises";
29357
+ import os4 from "node:os";
29358
+ import path17 from "node:path";
29359
+ var SCREENSHOT_MAX_JPEG_BYTES = 131072;
29360
+ var SCREENSHOT_MAX_EDGE = 1568;
29361
+ function screenshotEnabled(env = process.env) {
29362
+ return env.LC_SCREENSHOT_ENABLED === "true";
29363
+ }
29364
+ var SCREENSHOT_ACCEPTANCE_FILE = "screenshot-acceptance-enabled";
29365
+ var ScreenCaptureError = class extends Error {
29366
+ constructor(code) {
29367
+ super(code);
29368
+ this.code = code;
29369
+ this.name = "ScreenCaptureError";
29370
+ }
29371
+ code;
29372
+ };
29373
+ var KNOWN = /^(SCREEN_UNAVAILABLE|SCREEN_LOCKED|SCREEN_ENCODER_UNAVAILABLE|SCREENSHOT_TOO_LARGE|ARGUMENT_INVALID)$/;
29374
+ function jpegSize(data) {
29375
+ if (data.length < 4 || data[0] !== 255 || data[1] !== 216 || data[data.length - 2] !== 255 || data[data.length - 1] !== 217) return null;
29376
+ for (let at = 2; at + 9 < data.length; ) {
29377
+ if (data[at] !== 255) return null;
29378
+ const marker = data[at + 1], length = data.readUInt16BE(at + 2);
29379
+ if (marker >= 192 && marker <= 207 && ![196, 200, 204].includes(marker)) {
29380
+ const height = data.readUInt16BE(at + 5), width = data.readUInt16BE(at + 7);
29381
+ return width > 0 && height > 0 ? { width, height } : null;
29382
+ }
29383
+ at += 2 + length;
29384
+ }
29385
+ return null;
29386
+ }
29387
+ function run(file2, args, signal, maxBuffer = 65536) {
29388
+ return new Promise((resolve, reject) => {
29389
+ execFile4(
29390
+ file2,
29391
+ args,
29392
+ { encoding: "buffer", timeout: 15e3, maxBuffer, windowsHide: true, shell: false, env: buildChildEnvironment(process.env, process.platform), signal },
29393
+ (error62, stdout, stderr) => error62 ? reject(Object.assign(error62, { stdout, stderr })) : resolve({ stdout, stderr })
29394
+ );
29395
+ });
29396
+ }
29397
+ async function windows(bridge, signal) {
29398
+ if (!path17.isAbsolute(bridge)) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
29399
+ let stdout;
29400
+ try {
29401
+ ({ stdout } = await run(bridge, ["screenshot", String(SCREENSHOT_MAX_EDGE), String(SCREENSHOT_MAX_JPEG_BYTES)], signal, 262144));
29402
+ } catch (error62) {
29403
+ if (signal.aborted) throw new ScreenCaptureError("CANCELLED");
29404
+ const code = /^\{"error":"([A-Z_]+)"\}$/.exec(String(error62.stderr ?? ""))?.[1];
29405
+ throw new ScreenCaptureError(code && KNOWN.test(code) ? code : "SCREEN_UNAVAILABLE");
29406
+ }
29407
+ try {
29408
+ const value = JSON.parse(stdout.toString("utf8"));
29409
+ const data = Buffer.from(value.data, "base64"), size = jpegSize(data);
29410
+ if (!size || size.width !== value.width || size.height !== value.height || !Number.isSafeInteger(value.sourceWidth) || !Number.isSafeInteger(value.sourceHeight)) throw Error();
29411
+ return { data, width: size.width, height: size.height, sourceWidth: value.sourceWidth, sourceHeight: value.sourceHeight };
29412
+ } catch {
29413
+ throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
29414
+ }
29415
+ }
29416
+ async function mac3(signal) {
29417
+ try {
29418
+ const preflight = await run("/usr/bin/osascript", ["-l", "JavaScript", "-e", "ObjC.import('CoreGraphics'); $.CGPreflightScreenCaptureAccess()"], signal);
29419
+ if (preflight.stdout.toString("utf8").trim() !== "true") {
29420
+ await run("/usr/bin/osascript", ["-l", "JavaScript", "-e", "ObjC.import('CoreGraphics'); $.CGRequestScreenCaptureAccess()"], signal).catch(() => {
29421
+ });
29422
+ throw new ScreenCaptureError("SCREEN_RECORDING_PERMISSION_REQUIRED");
29423
+ }
29424
+ } catch (error62) {
29425
+ if (error62 instanceof ScreenCaptureError) throw error62;
29426
+ throw new ScreenCaptureError(signal.aborted ? "CANCELLED" : "SCREEN_UNAVAILABLE");
29427
+ }
29428
+ const folder = await mkdtemp(path17.join(os4.tmpdir(), "lc-screen-"));
29429
+ try {
29430
+ const full = path17.join(folder, "full.png"), small = path17.join(folder, "small.jpg");
29431
+ try {
29432
+ await run("/usr/sbin/screencapture", ["-x", "-m", "-t", "png", full], signal);
29433
+ } catch {
29434
+ throw new ScreenCaptureError(signal.aborted ? "CANCELLED" : "SCREEN_UNAVAILABLE");
29435
+ }
29436
+ const source = (await run("/usr/bin/sips", ["-g", "pixelWidth", "-g", "pixelHeight", full], signal)).stdout.toString("utf8");
29437
+ const sourceWidth = Number(/pixelWidth: (\d+)/.exec(source)?.[1]), sourceHeight = Number(/pixelHeight: (\d+)/.exec(source)?.[1]);
29438
+ if (!sourceWidth || !sourceHeight) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
29439
+ for (const edge of [SCREENSHOT_MAX_EDGE, 1280, 1024, 800, 640]) {
29440
+ const target = Math.min(edge, Math.max(sourceWidth, sourceHeight));
29441
+ for (const quality of [75, 60, 45, 35]) {
29442
+ await run("/usr/bin/sips", ["-Z", String(target), "-s", "format", "jpeg", "-s", "formatOptions", String(quality), full, "--out", small], signal);
29443
+ const data = await readFile6(small), size = jpegSize(data);
29444
+ if (!size) throw new ScreenCaptureError("SCREEN_UNAVAILABLE");
29445
+ if (data.length <= SCREENSHOT_MAX_JPEG_BYTES) return { data, ...size, sourceWidth, sourceHeight };
29446
+ }
29447
+ }
29448
+ throw new ScreenCaptureError("SCREENSHOT_TOO_LARGE");
29449
+ } catch (error62) {
29450
+ if (error62 instanceof ScreenCaptureError) throw error62;
29451
+ throw new ScreenCaptureError(signal.aborted ? "CANCELLED" : "SCREEN_UNAVAILABLE");
29452
+ } finally {
29453
+ await rm5(folder, { recursive: true, force: true }).catch(() => {
29454
+ });
29455
+ }
29456
+ }
29457
+ async function captureScreen(options) {
29458
+ if (options.signal.aborted) throw new ScreenCaptureError("CANCELLED");
29459
+ if (process.platform === "win32") return windows(options.ownerBridgePath, options.signal);
29460
+ if (process.platform === "darwin") return mac3(options.signal);
29461
+ throw new ScreenCaptureError("SCREENSHOT_UNSUPPORTED");
29462
+ }
29463
+
29253
29464
  // agent/src/tools.ts
29254
29465
  var NativeToolError = class extends Error {
29255
29466
  constructor(code) {
@@ -29340,13 +29551,13 @@ var NativeTools = class {
29340
29551
  constructor(options) {
29341
29552
  this.options = options;
29342
29553
  this.options = structuredClone(options);
29343
- 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])));
29554
+ 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])));
29344
29555
  }
29345
29556
  options;
29346
29557
  memory;
29347
29558
  async readFile(file2, maxBytes, signal) {
29348
29559
  try {
29349
- return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path17.join(path17.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
29560
+ return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
29350
29561
  } catch (error62) {
29351
29562
  if (error62.code === "ENOENT") throw error62;
29352
29563
  if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail3(error62.message);
@@ -29356,31 +29567,31 @@ var NativeTools = class {
29356
29567
  /** Windows only: up to 64 files of at most 1 MiB in one bridge process, each with its own result. */
29357
29568
  async readFiles(files, maxTotalBytes, signal) {
29358
29569
  try {
29359
- return await readWindowsFiles(this.options.ownerBridgePath ?? path17.join(path17.dirname(this.options.helperPath), "OwnerBridge.exe"), files, 1048576, maxTotalBytes, signal);
29570
+ return await readWindowsFiles(this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe"), files, 1048576, maxTotalBytes, signal);
29360
29571
  } catch (error62) {
29361
29572
  if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail3(error62.message);
29362
29573
  throw error62;
29363
29574
  }
29364
29575
  }
29365
- async prepare(workspace2, candidate, selection) {
29576
+ async prepare(workspace2, candidate, selection2) {
29366
29577
  let prepared;
29367
29578
  try {
29368
29579
  let projectRoot;
29369
- if (selection) {
29370
- const target = ProjectTargetBindingSchema.parse(selection);
29580
+ if (selection2) {
29581
+ const target = ProjectTargetBindingSchema.parse(selection2);
29371
29582
  if (workspace2.rootHash !== target.workspaceRootHash) fail3("PROJECT_IDENTITY_MISMATCH");
29372
29583
  const identity = await this.prepareTool(workspace2, { name: "project_identity", args: { path: target.relativePath } });
29373
29584
  const proof2 = JSON.parse((await identity.run(AbortSignal.timeout(15e3))).stdout);
29374
29585
  if (!proof2.repositoryFingerprint) fail3("PROJECT_IDENTITY_UNKNOWN");
29375
29586
  if (proof2.repositoryFingerprint !== target.repositoryFingerprint) fail3("PROJECT_IDENTITY_MISMATCH");
29376
- projectRoot = path17.resolve(workspace2.root, target.relativePath);
29587
+ projectRoot = path18.resolve(workspace2.root, target.relativePath);
29377
29588
  const common = identity.claims.find((claim2) => claim2.namespace === "git")?.path;
29378
29589
  if (common) workspace2 = { ...workspace2, gitCommonDir: common };
29379
29590
  }
29380
29591
  prepared = await this.prepareTool(workspace2, candidate, projectRoot);
29381
29592
  } catch (error62) {
29382
29593
  const parsed = ToolCallSchema.safeParse(candidate);
29383
- 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(() => {
29594
+ 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(() => {
29384
29595
  });
29385
29596
  throw error62;
29386
29597
  }
@@ -29400,17 +29611,17 @@ var NativeTools = class {
29400
29611
  try {
29401
29612
  const canonical2 = await realpath7(workspace2.root);
29402
29613
  if (!equalPath3(canonical2, workspace2.root) || hash6(process.platform === "win32" ? canonical2.toLowerCase() : canonical2) !== workspace2.rootHash) fail3("WORKSPACE_CHANGED");
29403
- const runtimeDirectory = path17.dirname(this.options.helperPath);
29614
+ const runtimeDirectory = path18.dirname(this.options.helperPath);
29404
29615
  const protectedPaths = [
29405
29616
  this.options.stateDirectory,
29406
29617
  this.options.helperPath,
29407
- ...["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))
29618
+ ...["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))
29408
29619
  ];
29409
29620
  if (this.options.ownerBridgePath) protectedPaths.push(this.options.ownerBridgePath);
29410
- if (process.platform === "win32" && process.env.LOCALAPPDATA && path17.isAbsolute(process.env.LOCALAPPDATA)) {
29411
- protectedPaths.push(path17.join(process.env.LOCALAPPDATA, "LocalCommander"));
29621
+ if (process.platform === "win32" && process.env.LOCALAPPDATA && path18.isAbsolute(process.env.LOCALAPPDATA)) {
29622
+ protectedPaths.push(path18.join(process.env.LOCALAPPDATA, "LocalCommander"));
29412
29623
  }
29413
- if (process.platform !== "win32") protectedPaths.push(path17.join(process.env.LC_AGENT_DATA_DIR || posixDataHome(), "LocalCommander"));
29624
+ if (process.platform !== "win32") protectedPaths.push(path18.join(process.env.LC_AGENT_DATA_DIR || posixDataHome(), "LocalCommander"));
29414
29625
  guard = await PathGuard.create([canonical2], false, { protectedPaths });
29415
29626
  if (projectRoot) {
29416
29627
  const selected = await guard.resolveDirectory(projectRoot);
@@ -29499,7 +29710,7 @@ var NativeTools = class {
29499
29710
  }
29500
29711
  if (taken === first - 1 && first <= end) fail3("OUTPUT_LIMIT_EXCEEDED");
29501
29712
  const remaining = lines.length - (lines.length > 1 && lines.at(-1) === "" ? 1 : 0);
29502
- 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 });
29713
+ 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 });
29503
29714
  } };
29504
29715
  }
29505
29716
  if (call.name === "fs_write" || call.name === "fs_replace") {
@@ -29542,7 +29753,7 @@ var NativeTools = class {
29542
29753
  bytes3 = encodeText(pieces.join(newText), original.encoding);
29543
29754
  }
29544
29755
  if (bytes3.length > MAX_FILE_WRITE_BYTES) fail3("FILE_WRITE_LIMIT");
29545
- const temp = path17.join(path17.dirname(target), ".lc-write-" + randomUUID7() + ".tmp");
29756
+ const temp = path18.join(path18.dirname(target), ".lc-write-" + randomUUID7() + ".tmp");
29546
29757
  const handle = await open6(temp, constants7.O_CREAT | constants7.O_EXCL | constants7.O_WRONLY, 384);
29547
29758
  try {
29548
29759
  await handle.writeFile(bytes3);
@@ -29574,18 +29785,18 @@ var NativeTools = class {
29574
29785
  }
29575
29786
  for (let attempt = 0; attempt < 3; attempt++) {
29576
29787
  try {
29577
- await rm5(temp);
29788
+ await rm6(temp);
29578
29789
  break;
29579
29790
  } catch {
29580
29791
  await delay2(100);
29581
29792
  }
29582
29793
  }
29583
29794
  }
29584
- return result({ path: path17.relative(workspace2.root, target), bytes: bytes3.length, sha256: hash6(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
29795
+ return result({ path: path18.relative(workspace2.root, target), bytes: bytes3.length, sha256: hash6(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
29585
29796
  } catch (e) {
29586
29797
  await handle.close().catch(() => {
29587
29798
  });
29588
- await rm5(temp, { force: true }).catch(() => {
29799
+ await rm6(temp, { force: true }).catch(() => {
29589
29800
  });
29590
29801
  throw e;
29591
29802
  }
@@ -29607,7 +29818,7 @@ var NativeTools = class {
29607
29818
  const lines = decodeText(bytes3).text.split(/\r?\n/);
29608
29819
  scanned++;
29609
29820
  for (let i = 0; i < lines.length && matches2.length < call.args.maxResults; i++) if ((call.args.caseSensitive ? lines[i] : lines[i].toLowerCase()).includes(query)) {
29610
- const match = { path: path17.relative(workspace2.root, filename), line: i + 1, text: lines[i].slice(0, 500) };
29821
+ const match = { path: path18.relative(workspace2.root, filename), line: i + 1, text: lines[i].slice(0, 500) };
29611
29822
  if ((room -= Buffer.byteLength(JSON.stringify(match)) + 1) < 0) {
29612
29823
  incomplete = true;
29613
29824
  break;
@@ -29650,7 +29861,7 @@ var NativeTools = class {
29650
29861
  continue;
29651
29862
  }
29652
29863
  try {
29653
- const filename = await guard.resolveExisting(path17.join(base, entry.path));
29864
+ const filename = await guard.resolveExisting(path18.join(base, entry.path));
29654
29865
  guard.assertSafeFile(filename);
29655
29866
  if (!batched) {
29656
29867
  searchFile(filename, await this.readFile(filename, 1048576, signal));
@@ -29674,6 +29885,30 @@ var NativeTools = class {
29674
29885
  return result({ matches: matches2, scannedFiles: scanned, truncated: listing.truncated || incomplete || matches2.length >= call.args.maxResults || scanned >= 300 });
29675
29886
  } };
29676
29887
  }
29888
+ if (call.name === "take_screenshot") {
29889
+ if (!screenshotEnabled() && !await lstat7(path18.join(this.options.stateDirectory, SCREENSHOT_ACCEPTANCE_FILE)).then((s) => s.isFile(), () => false)) fail3("SCREENSHOT_DISABLED");
29890
+ if (!workspace2.fullAccess) fail3("FULL_ACCESS_REQUIRED");
29891
+ const bridge = this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe");
29892
+ return { call, claims: [{ path: path18.join(this.options.stateDirectory, "screen-capture"), mode: "read" }], run: async (signal) => {
29893
+ let shot;
29894
+ try {
29895
+ shot = await captureScreen({ ownerBridgePath: bridge, signal });
29896
+ } catch (error62) {
29897
+ fail3(error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message) ? error62.message : "SCREEN_UNAVAILABLE");
29898
+ }
29899
+ return result({
29900
+ type: "screenshot",
29901
+ mimeType: "image/jpeg",
29902
+ width: shot.width,
29903
+ height: shot.height,
29904
+ sourceWidth: shot.sourceWidth,
29905
+ sourceHeight: shot.sourceHeight,
29906
+ bytes: shot.data.length,
29907
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
29908
+ data: shot.data.toString("base64")
29909
+ });
29910
+ } };
29911
+ }
29677
29912
  if (call.name === "localhost_request") {
29678
29913
  const url2 = new URL(call.args.url), port = Number(url2.port || (url2.protocol === "https:" ? 443 : 80));
29679
29914
  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");
@@ -29744,9 +29979,9 @@ var NativeTools = class {
29744
29979
  else if (call.name === "git_diff") {
29745
29980
  argv = ["diff", "--no-ext-diff", "--no-textconv", ...call.args.staged ? ["--cached"] : []];
29746
29981
  if (call.args.file) {
29747
- const file2 = await resolve(path17.resolve(cwd, call.args.file));
29748
- const relative = path17.relative(cwd, file2);
29749
- if (relative.startsWith(".." + path17.sep) || relative === ".." || path17.isAbsolute(relative)) fail3("PATH_NOT_ALLOWED");
29982
+ const file2 = await resolve(path18.resolve(cwd, call.args.file));
29983
+ const relative = path18.relative(cwd, file2);
29984
+ if (relative.startsWith(".." + path18.sep) || relative === ".." || path18.isAbsolute(relative)) fail3("PATH_NOT_ALLOWED");
29750
29985
  argv.push("--", relative);
29751
29986
  } else argv.push("--stat");
29752
29987
  } else fail3("TOOL_MISSING");
@@ -29757,7 +29992,7 @@ var NativeTools = class {
29757
29992
  const listing = await this.list(guard, cwd, 1, call.args.startup ? 20 : 150, signal);
29758
29993
  let packageInfo = null;
29759
29994
  try {
29760
- const name2 = await guard.resolveExisting(path17.join(cwd, "package.json"));
29995
+ const name2 = await guard.resolveExisting(path18.join(cwd, "package.json"));
29761
29996
  guard.assertSafeFile(name2);
29762
29997
  const value = JSON.parse(utf8(await this.readFile(name2, 64e3, signal)));
29763
29998
  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) : [] };
@@ -29777,7 +30012,7 @@ var NativeTools = class {
29777
30012
  }
29778
30013
  const contextFile = async (relative, limit, optional2 = false) => {
29779
30014
  try {
29780
- const file2 = await guard.resolveExisting(path17.join(primary, relative));
30015
+ const file2 = await guard.resolveExisting(path18.join(primary, relative));
29781
30016
  guard.assertSafeFile(file2);
29782
30017
  return utf8(await this.readFile(file2, limit, signal));
29783
30018
  } catch (error62) {
@@ -29810,17 +30045,17 @@ var NativeTools = class {
29810
30045
  } };
29811
30046
  }
29812
30047
  async resolveProgram(name2, workspace2, args) {
29813
- const entry = Object.entries(this.options.programs).find(([key, value]) => equalPath3(key, name2) || path17.isAbsolute(name2) && equalPath3(value.executable, path17.resolve(name2)));
30048
+ const entry = Object.entries(this.options.programs).find(([key, value]) => equalPath3(key, name2) || path18.isAbsolute(name2) && equalPath3(value.executable, path18.resolve(name2)));
29814
30049
  if (workspace2.fullAccess) {
29815
- const commandKey = (value) => process.platform === "win32" ? path17.basename(value).toLowerCase().replace(/\.(exe|com|cmd|bat)$/i, "") : path17.basename(value);
30050
+ const commandKey = (value) => process.platform === "win32" ? path18.basename(value).toLowerCase().replace(/\.(exe|com|cmd|bat)$/i, "") : path18.basename(value);
29816
30051
  const denied = new Set((workspace2.deniedCommands ?? []).map(commandKey));
29817
30052
  if (denied.has(commandKey(name2)) || entry && denied.has(commandKey(entry[0]))) fail3("COMMAND_NOT_ALLOWED");
29818
- const extension2 = path17.extname(name2).toLowerCase();
29819
- const candidate = entry?.[1].executable ?? (process.platform !== "win32" ? await resolvePosixExecutable(name2) : path17.isAbsolute(name2) ? name2 : /^[\w.-]+$/.test(name2) ? resolveWindowsLauncher(
30053
+ const extension2 = path18.extname(name2).toLowerCase();
30054
+ const candidate = entry?.[1].executable ?? (process.platform !== "win32" ? await resolvePosixExecutable(name2) : path18.isAbsolute(name2) ? name2 : /^[\w.-]+$/.test(name2) ? resolveWindowsLauncher(
29820
30055
  commandKey(name2),
29821
30056
  [".exe", ".com", ".cmd", ".bat"].includes(extension2) ? { ...process.env, PATHEXT: extension2 } : process.env
29822
30057
  )?.file : void 0);
29823
- if (!candidate || !path17.isAbsolute(candidate)) fail3("COMMAND_NOT_FOUND");
30058
+ if (!candidate || !path18.isAbsolute(candidate)) fail3("COMMAND_NOT_FOUND");
29824
30059
  const executable = await realpath7(candidate).catch(() => fail3("COMMAND_NOT_FOUND"));
29825
30060
  if (!(await lstat7(executable)).isFile()) fail3("COMMAND_NOT_FOUND");
29826
30061
  if (denied.has(commandKey(executable))) fail3("COMMAND_NOT_ALLOWED");
@@ -29835,7 +30070,7 @@ var NativeTools = class {
29835
30070
  if (/\.(cmd|bat)$/i.test(executable)) {
29836
30071
  if ([executable, ...args].some((value) => /[&|<>^%!"\r\n]/.test(value))) fail3("INVALID_SCRIPT_ARGUMENTS");
29837
30072
  const literal2 = (value) => "'" + value.replaceAll("'", "''") + "'";
29838
- const shell = path17.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
30073
+ const shell = path18.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
29839
30074
  if (denied.has("powershell") || denied.has("cmd")) fail3("COMMAND_NOT_ALLOWED");
29840
30075
  const script = "& " + literal2(executable) + " @(" + args.map(literal2).join(",") + "); exit $LASTEXITCODE";
29841
30076
  return { executable: shell, args: ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")] };
@@ -29843,7 +30078,7 @@ var NativeTools = class {
29843
30078
  if (!/\.(exe|com)$/i.test(executable)) fail3("COMMAND_NOT_ALLOWED");
29844
30079
  return { executable, args: [...entry?.[1].prefixArgs ?? [], ...args] };
29845
30080
  }
29846
- if (!entry || !workspace2.allowedCommands.some((v) => equalPath3(v, entry[0])) || !path17.isAbsolute(entry[1].executable)) fail3("COMMAND_NOT_ALLOWED");
30081
+ if (!entry || !workspace2.allowedCommands.some((v) => equalPath3(v, entry[0])) || !path18.isAbsolute(entry[1].executable)) fail3("COMMAND_NOT_ALLOWED");
29847
30082
  return { executable: entry[1].executable, args: [...entry[1].prefixArgs ?? [], ...args] };
29848
30083
  }
29849
30084
  async memoryContext(workspace2) {
@@ -29858,9 +30093,9 @@ var NativeTools = class {
29858
30093
  async gitExecution(cwd, args) {
29859
30094
  if (!["win32", "linux", "darwin"].includes(process.platform)) fail3("COMMAND_NOT_ALLOWED");
29860
30095
  const configured = this.options.programs.git;
29861
- 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"];
30096
+ 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"];
29862
30097
  for (const source of candidates) {
29863
- if (!path17.isAbsolute(source)) continue;
30098
+ if (!path18.isAbsolute(source)) continue;
29864
30099
  const candidate = process.platform === "win32" ? source : await resolvePosixExecutable(source);
29865
30100
  if (!candidate) continue;
29866
30101
  try {
@@ -29894,7 +30129,7 @@ var NativeTools = class {
29894
30129
  break;
29895
30130
  }
29896
30131
  if (item.isSymbolicLink() || excluded.has(item.name.toLowerCase())) continue;
29897
- const candidate = path17.join(current2.path, item.name);
30132
+ const candidate = path18.join(current2.path, item.name);
29898
30133
  let resolved;
29899
30134
  try {
29900
30135
  resolved = await guard.resolveExisting(candidate);
@@ -29904,11 +30139,11 @@ var NativeTools = class {
29904
30139
  }
29905
30140
  if (!equalPath3(candidate, resolved)) continue;
29906
30141
  if (item.isDirectory()) {
29907
- entries.push({ path: path17.relative(root, resolved), type: "directory" });
30142
+ entries.push({ path: path18.relative(root, resolved), type: "directory" });
29908
30143
  if (current2.level < depth) queue.push({ path: resolved, level: current2.level + 1 });
29909
30144
  } else if (item.isFile()) {
29910
30145
  const stat2 = await lstat7(resolved).catch(() => null);
29911
- if (stat2) entries.push({ path: path17.relative(root, resolved), type: "file", size: stat2.size });
30146
+ if (stat2) entries.push({ path: path18.relative(root, resolved), type: "file", size: stat2.size });
29912
30147
  }
29913
30148
  }
29914
30149
  if (truncated) break;
@@ -29918,7 +30153,7 @@ var NativeTools = class {
29918
30153
  async gitCommonDir(cwd, workspace2, guard) {
29919
30154
  let directory = cwd;
29920
30155
  while (guard.isWithin(directory, workspace2.root)) {
29921
- const dotGit = path17.join(directory, ".git");
30156
+ const dotGit = path18.join(directory, ".git");
29922
30157
  try {
29923
30158
  const stat2 = await lstat7(dotGit);
29924
30159
  if (stat2.isSymbolicLink()) fail3("GIT_METADATA_CHANGED");
@@ -29927,14 +30162,14 @@ var NativeTools = class {
29927
30162
  else {
29928
30163
  const content = utf8(await this.readFile(dotGit, 4096)).trim();
29929
30164
  if (!content.startsWith("gitdir: ")) fail3("GIT_METADATA_CHANGED");
29930
- gitDir = await realpath7(path17.resolve(directory, content.slice(8)));
30165
+ gitDir = await realpath7(path18.resolve(directory, content.slice(8)));
29931
30166
  }
29932
30167
  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");
29933
30168
  let common = gitDir;
29934
30169
  try {
29935
- const content = utf8(await this.readFile(path17.join(gitDir, "commondir"), 4096)).trim();
30170
+ const content = utf8(await this.readFile(path18.join(gitDir, "commondir"), 4096)).trim();
29936
30171
  if (!content) fail3("GIT_METADATA_CHANGED");
29937
- common = await realpath7(path17.resolve(gitDir, content));
30172
+ common = await realpath7(path18.resolve(gitDir, content));
29938
30173
  } catch (e) {
29939
30174
  if (e.code !== "ENOENT") throw e;
29940
30175
  }
@@ -29945,22 +30180,22 @@ var NativeTools = class {
29945
30180
  if (e.code !== "ENOENT") throw e;
29946
30181
  }
29947
30182
  if (equalPath3(directory, workspace2.root)) break;
29948
- directory = path17.dirname(directory);
30183
+ directory = path18.dirname(directory);
29949
30184
  }
29950
30185
  return null;
29951
30186
  }
29952
30187
  };
29953
30188
 
29954
30189
  // agent/src/scheduler.ts
29955
- import path18 from "node:path";
29956
- import os4 from "node:os";
30190
+ import path19 from "node:path";
30191
+ import os5 from "node:os";
29957
30192
  function canonical(value) {
29958
- const p = path18.resolve(value);
30193
+ const p = path19.resolve(value);
29959
30194
  return process.platform === "win32" ? p.toLowerCase() : p;
29960
30195
  }
29961
30196
  function ancestor(a, b) {
29962
- const relative = path18.relative(a, b);
29963
- return relative === "" || !path18.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path18.sep);
30197
+ const relative = path19.relative(a, b);
30198
+ return relative === "" || !path19.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path19.sep);
29964
30199
  }
29965
30200
  function claimsConflict(a, b) {
29966
30201
  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))));
@@ -29968,7 +30203,7 @@ function claimsConflict(a, b) {
29968
30203
  var NativeScheduler = class {
29969
30204
  constructor(options = {}) {
29970
30205
  this.options = options;
29971
- const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2, os4.availableParallelism?.() ?? os4.cpus().length) / 2)));
30206
+ const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2, os5.availableParallelism?.() ?? os5.cpus().length) / 2)));
29972
30207
  this.safeSlots = options.safeSlots ?? capacity;
29973
30208
  this.maxQueued = options.maxQueued ?? 32;
29974
30209
  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");
@@ -29986,16 +30221,16 @@ var NativeScheduler = class {
29986
30221
  } catch {
29987
30222
  }
29988
30223
  }
29989
- schedule(id2, claims, deadlineAt, run, signal) {
30224
+ schedule(id2, claims, deadlineAt, run2, signal) {
29990
30225
  if (!this.accepting) return Promise.reject(Error("AGENT_PAUSED"));
29991
30226
  if (!id2 || id2.length > 100 || this.active.has(id2) || this.waiting.some((j) => j.id === id2)) return Promise.reject(Error("DUPLICATE_SCHEDULED_EXECUTION"));
29992
- 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"));
30227
+ 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"));
29993
30228
  const deadline = deadlineAt.getTime();
29994
30229
  if (!Number.isFinite(deadline) || deadline <= Date.now()) return Promise.reject(Error("ADMISSION_DEADLINE_EXPIRED"));
29995
30230
  if (signal?.aborted) return Promise.reject(Error("CANCELLED_BEFORE_ACCEPTANCE"));
29996
30231
  if (this.waiting.length >= this.maxQueued) return Promise.reject(Error("RESOURCE_BUSY"));
29997
30232
  return new Promise((resolve, reject) => {
29998
- const job = { id: id2, claims: claims.map((c) => ({ ...c, path: canonical(c.path) })), deadline, run, signal, resolve, reject };
30233
+ const job = { id: id2, claims: claims.map((c) => ({ ...c, path: canonical(c.path) })), deadline, run: run2, signal, resolve, reject };
29999
30234
  const remove = (reason) => {
30000
30235
  const index = this.waiting.indexOf(job);
30001
30236
  if (index < 0) return;
@@ -30705,6 +30940,14 @@ function resultOutcome(result2) {
30705
30940
  if (!result2.treeTerminated || result2.exitCode === null) return "unknown";
30706
30941
  return result2.exitCode === 0 ? "success" : "failed";
30707
30942
  }
30943
+ function screenshotMetadata(stdout) {
30944
+ try {
30945
+ const { data: _data, ...metadata } = JSON.parse(stdout);
30946
+ return JSON.stringify(metadata);
30947
+ } catch {
30948
+ return "";
30949
+ }
30950
+ }
30708
30951
  async function outboundResult(call, result2, binding2, optional2, ledger) {
30709
30952
  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) };
30710
30953
  if (ledger) {
@@ -30757,7 +31000,7 @@ var NativeRuntime = class {
30757
31000
  }
30758
31001
  if (frame.type === "result" && this.options.contentAudit) {
30759
31002
  const call = this.contexts.get(frame.binding.executionId)?.tool.call;
30760
- if (call) try {
31003
+ if (call && call.name !== "take_screenshot") try {
30761
31004
  this.options.contentAudit.record(frame.binding, call, frame.result);
30762
31005
  } catch {
30763
31006
  }
@@ -30894,8 +31137,10 @@ var NativeRuntime = class {
30894
31137
  const checked = ResultSchema.parse(output2);
30895
31138
  const { resultCode, ...journalOutput } = checked;
30896
31139
  if (context.guardPermit) await this.options.guard.result(context.guardPermit, checked);
30897
- const final = await this.options.journal.finish(binding2.executionId, journalOutput, resultCode);
30898
- this.send({ type: "result", version: 1, binding: binding2, result: await outboundResult(runnable.call, journalResult(final.result, resultCode), binding2, this.optionalTelemetry, this.options.efficiencyLedger) });
31140
+ const image = runnable.call.name === "take_screenshot" ? journalOutput.stdout : void 0;
31141
+ const final = await this.options.journal.finish(binding2.executionId, image === void 0 ? journalOutput : { ...journalOutput, stdout: screenshotMetadata(image) }, resultCode);
31142
+ const outbound = await outboundResult(runnable.call, journalResult(final.result, resultCode), binding2, this.optionalTelemetry, this.options.efficiencyLedger);
31143
+ this.send({ type: "result", version: 1, binding: binding2, result: image === void 0 ? outbound : { ...outbound, stdout: image } });
30899
31144
  }, abort.signal);
30900
31145
  context.task = work.catch(async (error62) => {
30901
31146
  if (!context.accepted) {
@@ -31009,6 +31254,7 @@ var NativeRelayBridge = class {
31009
31254
  async connected(connection) {
31010
31255
  if (this.connection) await this.disconnected();
31011
31256
  this.connection = { ...connection };
31257
+ await this.journal.recordConnection?.(connection.connectionEpoch);
31012
31258
  this.runtime.connected(connection, (frame) => {
31013
31259
  if (frame.type === "control_result") this.control.get(frame.requestId)?.resolve(frame);
31014
31260
  else if ("binding" in frame) this.execution.get(frame.binding.executionId)?.resolve(frame);
@@ -31036,6 +31282,22 @@ var NativeRelayBridge = class {
31036
31282
  }
31037
31283
  }
31038
31284
  }
31285
+ /** Leases the cloud holds from earlier connections that this device never accepted (#448). Each one the journal
31286
+ * never received gets the same never-started receipt as #143; the cloud checks it against its own rows. */
31287
+ async heldLeases(bindings) {
31288
+ for (const binding2 of bindings) {
31289
+ const connection = this.connection, id2 = binding2.executionId;
31290
+ if (!connection || binding2.tenantId !== connection.tenantId || binding2.deviceId !== connection.deviceId || BigInt(binding2.connectionEpoch) >= BigInt(connection.connectionEpoch)) continue;
31291
+ if (this.terminalSending.has(id2)) continue;
31292
+ this.terminalSending.add(id2);
31293
+ try {
31294
+ if (await this.journal.neverReceived?.(id2, binding2.connectionEpoch)) await this.sendTerminal(binding2, "rejected", "PRE_ACCEPTANCE_REJECTED");
31295
+ } catch {
31296
+ } finally {
31297
+ this.terminalSending.delete(id2);
31298
+ }
31299
+ }
31300
+ }
31039
31301
  async disconnected() {
31040
31302
  this.connection = null;
31041
31303
  for (const pending of [...this.execution.values(), ...this.control.values()]) pending.resolve(null);
@@ -31101,9 +31363,9 @@ var NativeRelayBridge = class {
31101
31363
 
31102
31364
  // agent/src/local-direct.ts
31103
31365
  import net from "node:net";
31104
- import path19 from "node:path";
31366
+ import path20 from "node:path";
31105
31367
  import { createHmac as createHmac2, hkdfSync, randomBytes as randomBytes6, randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
31106
- import { mkdir as mkdir7, readFile as readFile7, rename as rename5, rm as rm6, writeFile as writeFile3 } from "node:fs/promises";
31368
+ import { mkdir as mkdir7, readFile as readFile8, rename as rename5, rm as rm7, writeFile as writeFile3 } from "node:fs/promises";
31107
31369
  var LocalDirectError = class extends Error {
31108
31370
  constructor(code) {
31109
31371
  super(code);
@@ -31121,11 +31383,11 @@ var ADMISSION_MS = 6e4;
31121
31383
  var MAX_IN_FLIGHT = 16;
31122
31384
  var MAX_CONNECTIONS = 32;
31123
31385
  function localDirectDirectory(appData) {
31124
- return path19.join(appData, "LocalCommander", "LocalMcp");
31386
+ return path20.join(appData, "LocalCommander", "LocalMcp");
31125
31387
  }
31126
31388
  async function localDirectEnabled(directory) {
31127
31389
  try {
31128
- return JSON.parse(await readFile7(path19.join(directory, "settings.json"), "utf8"))?.enabled === true;
31390
+ return JSON.parse(await readFile8(path20.join(directory, "settings.json"), "utf8"))?.enabled === true;
31129
31391
  } catch {
31130
31392
  return false;
31131
31393
  }
@@ -31198,7 +31460,7 @@ var Lines = class {
31198
31460
  async function readEndpoint(directory) {
31199
31461
  let value;
31200
31462
  try {
31201
- value = JSON.parse(await readFile7(path19.join(directory, "endpoint.json"), "utf8"));
31463
+ value = JSON.parse(await readFile8(path20.join(directory, "endpoint.json"), "utf8"));
31202
31464
  } catch {
31203
31465
  fail4("LOCAL_AGENT_NOT_RUNNING");
31204
31466
  }
@@ -31215,9 +31477,9 @@ var LocalDirectServer = class _LocalDirectServer {
31215
31477
  sockets = /* @__PURE__ */ new Set();
31216
31478
  /** Listens only while the owner has enabled direct local access; null otherwise. */
31217
31479
  static async start(options) {
31218
- const endpointFile = path19.join(options.directory, "endpoint.json");
31480
+ const endpointFile = path20.join(options.directory, "endpoint.json");
31219
31481
  if (!await localDirectEnabled(options.directory)) {
31220
- await rm6(endpointFile, { force: true }).catch(() => {
31482
+ await rm7(endpointFile, { force: true }).catch(() => {
31221
31483
  });
31222
31484
  return null;
31223
31485
  }
@@ -31243,7 +31505,7 @@ var LocalDirectServer = class _LocalDirectServer {
31243
31505
  for (const socket of this.sockets) socket.destroy();
31244
31506
  await new Promise((resolve) => this.server.close(() => resolve()));
31245
31507
  try {
31246
- if ((await readEndpoint(this.options.directory)).pid === process.pid) await rm6(path19.join(this.options.directory, "endpoint.json"), { force: true });
31508
+ if ((await readEndpoint(this.options.directory)).pid === process.pid) await rm7(path20.join(this.options.directory, "endpoint.json"), { force: true });
31247
31509
  } catch {
31248
31510
  }
31249
31511
  }
@@ -35098,9 +35360,9 @@ var rev2026Codec = {
35098
35360
  });
35099
35361
  const parsed = buildSchemas2026().RequestMetaEnvelopeSchema.safeParse(meta3);
35100
35362
  if (!parsed.success) for (const issue2 of parsed.error.issues) {
35101
- const path29 = issue2.path.map(String);
35102
- const key = path29.length > 0 ? path29.join(".") : "_meta";
35103
- if (path29.length === 1 && issues.some((existing) => existing.key === key && existing.problem === "missing")) continue;
35363
+ const path30 = issue2.path.map(String);
35364
+ const key = path30.length > 0 ? path30.join(".") : "_meta";
35365
+ if (path30.length === 1 && issues.some((existing) => existing.key === key && existing.problem === "missing")) continue;
35104
35366
  issues.push({
35105
35367
  key,
35106
35368
  problem: issue2.message
@@ -35402,29 +35664,29 @@ var PERMITTED_X_MCP_HEADER_TYPES = /* @__PURE__ */ new Set([
35402
35664
  function scanXMcpHeaderDeclarations(inputSchema) {
35403
35665
  const declarations = [];
35404
35666
  const seenLower = /* @__PURE__ */ new Map();
35405
- const visit2 = (node2, path29, reachable) => {
35667
+ const visit2 = (node2, path30, reachable) => {
35406
35668
  if (node2 === null || typeof node2 !== "object") return void 0;
35407
35669
  const schema = node2;
35408
35670
  if (X_MCP_HEADER_KEY in schema) {
35409
- 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)`;
35671
+ 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)`;
35410
35672
  const raw = schema[X_MCP_HEADER_KEY];
35411
- if (typeof raw !== "string" || raw.length === 0) return `${pathName(path29)}: x-mcp-header MUST be a non-empty string`;
35412
- 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)`;
35673
+ if (typeof raw !== "string" || raw.length === 0) return `${pathName(path30)}: x-mcp-header MUST be a non-empty string`;
35674
+ 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)`;
35413
35675
  const type = typeof schema.type === "string" ? schema.type : void 0;
35414
- 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>"}`;
35676
+ 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>"}`;
35415
35677
  const lower = raw.toLowerCase();
35416
35678
  const prior = seenLower.get(lower);
35417
35679
  if (prior !== void 0) return `x-mcp-header '${raw}' is not case-insensitively unique (also declared as '${prior}')`;
35418
35680
  seenLower.set(lower, raw);
35419
35681
  declarations.push({
35420
- path: path29,
35682
+ path: path30,
35421
35683
  headerName: raw,
35422
35684
  type
35423
35685
  });
35424
35686
  }
35425
35687
  const properties = schema.properties;
35426
35688
  if (properties !== null && typeof properties === "object") for (const [key, child] of Object.entries(properties)) {
35427
- const fault$1 = visit2(child, [...path29, key], reachable);
35689
+ const fault$1 = visit2(child, [...path30, key], reachable);
35428
35690
  if (fault$1 !== void 0) return fault$1;
35429
35691
  }
35430
35692
  for (const k of NON_REACHABLE_SUBSCHEMA_KEYWORDS) {
@@ -35432,7 +35694,7 @@ function scanXMcpHeaderDeclarations(inputSchema) {
35432
35694
  if (sub === void 0) continue;
35433
35695
  const branches = Array.isArray(sub) ? sub : sub !== null && typeof sub === "object" && OBJECT_VALUED_SUBSCHEMA_KEYWORDS.has(k) ? Object.values(sub) : [sub];
35434
35696
  for (const branch of branches) {
35435
- const fault$1 = visit2(branch, [...path29, `<${k}>`], false);
35697
+ const fault$1 = visit2(branch, [...path30, `<${k}>`], false);
35436
35698
  if (fault$1 !== void 0) return fault$1;
35437
35699
  }
35438
35700
  }
@@ -35472,8 +35734,8 @@ var OBJECT_VALUED_SUBSCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
35472
35734
  "$defs",
35473
35735
  "definitions"
35474
35736
  ]);
35475
- function pathName(path29) {
35476
- return path29.length === 0 ? "<root>" : path29.join(".");
35737
+ function pathName(path30) {
35738
+ return path30.length === 0 ? "<root>" : path30.join(".");
35477
35739
  }
35478
35740
  var HEADER_MISMATCH_ERROR_CODE = -32020;
35479
35741
  var INBOUND_VALIDATION_LADDER = [
@@ -35723,7 +35985,7 @@ var PROPERTY_KEYS_BY_TYPE = {
35723
35985
  array: shapeKeys([UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema])
35724
35986
  };
35725
35987
  var SUPPORTED_STRING_FORMATS = new Set(StringSchemaSchema.shape.format.unwrap().options);
35726
- function walkProperty(node2, path29, vendor, unsupported) {
35988
+ function walkProperty(node2, path30, vendor, unsupported) {
35727
35989
  if (!isJsonObject(node2)) return node2;
35728
35990
  const allowedKeys = typeof node2.type === "string" && Object.hasOwn(PROPERTY_KEYS_BY_TYPE, node2.type) ? PROPERTY_KEYS_BY_TYPE[node2.type] : void 0;
35729
35991
  if (allowedKeys === void 0) return node2;
@@ -35731,8 +35993,8 @@ function walkProperty(node2, path29, vendor, unsupported) {
35731
35993
  for (const [key, value] of Object.entries(node2)) if (allowedKeys.has(key) || isAnnotationOnlyJsonSchemaKeyword(key)) pruned[key] = value;
35732
35994
  else if (key === "pattern" && node2.type === "string" && typeof node2.format === "string") {
35733
35995
  if (!SUPPORTED_STRING_FORMATS.has(node2.format)) pruned[key] = value;
35734
- else if (typeof value !== "string" || !isLibraryFormatPattern(node2.format, value, vendor)) unsupported.push(`${path29}.${key}`);
35735
- } else unsupported.push(`${path29}.${key}`);
35996
+ else if (typeof value !== "string" || !isLibraryFormatPattern(node2.format, value, vendor)) unsupported.push(`${path30}.${key}`);
35997
+ } else unsupported.push(`${path30}.${key}`);
35736
35998
  return pruned;
35737
35999
  }
35738
36000
  function walkRequestedSchema(converted, vendor) {
@@ -35749,11 +36011,11 @@ function describeUnsupportedProperties(pruned, fallback) {
35749
36011
  const offenders = Object.entries(pruned.properties).filter(([, node2]) => !parseSchema(PrimitiveSchemaDefinitionSchema, node2).success).map(([name2]) => `properties.${name2}`);
35750
36012
  return offenders.length > 0 ? offenders.join(", ") : fallback;
35751
36013
  }
35752
- function findDroppedConstraintPaths(original, parsed, path29 = "") {
35753
- if (Array.isArray(original) && Array.isArray(parsed)) return original.flatMap((item, index) => findDroppedConstraintPaths(item, parsed[index], `${path29}[${index}]`));
36014
+ function findDroppedConstraintPaths(original, parsed, path30 = "") {
36015
+ if (Array.isArray(original) && Array.isArray(parsed)) return original.flatMap((item, index) => findDroppedConstraintPaths(item, parsed[index], `${path30}[${index}]`));
35754
36016
  if (!isJsonObject(original) || !isJsonObject(parsed)) return [];
35755
36017
  return Object.entries(original).flatMap(([key, value]) => {
35756
- const childPath = path29 ? `${path29}.${key}` : key;
36018
+ const childPath = path30 ? `${path30}.${key}` : key;
35757
36019
  if (!Object.prototype.hasOwnProperty.call(parsed, key)) return isAnnotationOnlyJsonSchemaKeyword(key) ? [] : [childPath];
35758
36020
  return findDroppedConstraintPaths(value, parsed[key], childPath);
35759
36021
  });
@@ -39829,8 +40091,8 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
39829
40091
  for (let i = 0; i < str.length; i++) if (str[i] === token) ind++;
39830
40092
  return ind;
39831
40093
  }
39832
- function removeDotSegments(path29) {
39833
- let input2 = path29;
40094
+ function removeDotSegments(path30) {
40095
+ let input2 = path30;
39834
40096
  const output2 = [];
39835
40097
  let nextSlash = -1;
39836
40098
  let len = 0;
@@ -39983,8 +40245,8 @@ var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
39983
40245
  wsComponent.secure = void 0;
39984
40246
  }
39985
40247
  if (wsComponent.resourceName) {
39986
- const [path29, query] = wsComponent.resourceName.split("?");
39987
- wsComponent.path = path29 && path29 !== "/" ? path29 : void 0;
40248
+ const [path30, query] = wsComponent.resourceName.split("?");
40249
+ wsComponent.path = path30 && path30 !== "/" ? path30 : void 0;
39988
40250
  wsComponent.query = query;
39989
40251
  wsComponent.resourceName = void 0;
39990
40252
  }
@@ -45551,7 +45813,8 @@ var DESCRIPTIONS = {
45551
45813
  git_diff: ["Git diff of the repository at a workspace-relative path.", { readOnlyHint: true, openWorldHint: false }],
45552
45814
  git_log: ["Recent Git commits of the repository at a workspace-relative path.", { readOnlyHint: true, openWorldHint: false }],
45553
45815
  project_snapshot: ["Compact project overview: Git state and, with startup, AGENTS.md policy and task continuation.", { readOnlyHint: true, openWorldHint: false }],
45554
- 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 }],
45816
+ 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 }],
45817
+ take_screenshot: ["Take a still image of this computer's primary screen, returned as a JPEG image. Needs a Full Access workspace; the lock screen is never captured.", { readOnlyHint: true, openWorldHint: false }],
45555
45818
  localhost_request: ["HTTP request to a service on this computer (localhost only).", { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }]
45556
45819
  };
45557
45820
  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.");
@@ -45564,6 +45827,14 @@ function failure4(error62) {
45564
45827
  return text2(code + hint, true);
45565
45828
  }
45566
45829
  function render(name2, result2) {
45830
+ if (name2 === "take_screenshot" && result2.resultCode === "SUCCESS") {
45831
+ try {
45832
+ const { data, mimeType, ...metadata } = JSON.parse(result2.stdout);
45833
+ if (typeof data === "string" && data && mimeType === "image/jpeg") return { content: [{ type: "image", data, mimeType }, { type: "text", text: JSON.stringify(metadata) }] };
45834
+ } catch {
45835
+ }
45836
+ return text2(JSON.stringify({ resultCode: "SCREEN_UNAVAILABLE" }), true);
45837
+ }
45567
45838
  if (name2 !== "command_run" && result2.resultCode === "SUCCESS") return text2(result2.stdout);
45568
45839
  const { exitCode, resultCode, timedOut, cancelled, stdout, stderr, stdoutTruncated, stderrTruncated } = result2;
45569
45840
  return text2(
@@ -45584,7 +45855,7 @@ async function serveLocalMcp(options) {
45584
45855
  return connecting;
45585
45856
  };
45586
45857
  const server = new McpServer({ name: "local-commander-local", version: options.agentVersion }, {
45587
- 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."
45858
+ 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."
45588
45859
  });
45589
45860
  server.registerTool(
45590
45861
  "workspace_list",
@@ -45599,7 +45870,7 @@ async function serveLocalMcp(options) {
45599
45870
  );
45600
45871
  for (const option of ToolCallSchema.options) {
45601
45872
  const name2 = option.shape.name.value, entry = DESCRIPTIONS[name2];
45602
- if (!entry) continue;
45873
+ if (!entry || name2 === "take_screenshot" && !screenshotEnabled()) continue;
45603
45874
  const inputSchema = option.shape.args.extend({ workspace });
45604
45875
  const callback = async (input2, ctx) => {
45605
45876
  const { workspace: selected, ...args } = input2;
@@ -46035,7 +46306,8 @@ async function connectOnce(options) {
46035
46306
  tenantId,
46036
46307
  deviceId,
46037
46308
  guardIdentity: true,
46038
- ...options.aiConnectivity ? { aiConnectivity: true } : {}
46309
+ ...options.aiConnectivity ? { aiConnectivity: true } : {},
46310
+ ...options.onHeldLeases ? { heldLeases: true } : {}
46039
46311
  }, maxFrameBytes);
46040
46312
  const challenge = validateChallenge(await waitForMessage(socket, maxFrameBytes, connectTimeoutMs, "RELAY_HANDSHAKE_TIMEOUT"), protocolVersion2);
46041
46313
  const machine = challenge.machineIdentity ? options.machineIdentity?.(deviceId) ?? null : null;
@@ -46069,8 +46341,22 @@ async function connectOnce(options) {
46069
46341
  const { safeSlots, active, queued, paused } = nativeStatus();
46070
46342
  sendJson(socket, NativeStatusSchema.parse({ type: "nativeStatus", protocolVersion: 1, connectionEpoch, agentVersion: options.agentVersion, safeSlots, active, queued, paused }), maxFrameBytes);
46071
46343
  };
46344
+ let watchdog;
46345
+ const armWatchdog = () => {
46346
+ clearTimeout(watchdog);
46347
+ watchdog = setTimeout(() => {
46348
+ process.stderr.write("RELAY_HEARTBEAT_LOST\n");
46349
+ socket.terminate();
46350
+ }, monitorHeartbeat * 3);
46351
+ watchdog.unref();
46352
+ };
46353
+ if (monitorHeartbeat) {
46354
+ armWatchdog();
46355
+ socket.once("close", () => clearTimeout(watchdog));
46356
+ }
46072
46357
  if (monitorHeartbeat) socket.on("ping", (data) => {
46073
46358
  if (data.toString() !== "lcmcp-monitor:" + connectionEpoch) return;
46359
+ armWatchdog();
46074
46360
  try {
46075
46361
  void Promise.resolve(options.onMonitorHeartbeat?.()).catch(() => {
46076
46362
  });
@@ -46158,6 +46444,15 @@ async function connectOnce(options) {
46158
46444
  ack.data.ok ? pending.resolve() : pending.reject(new RelayClientError("RELAY_RESULT_REJECTED"));
46159
46445
  return;
46160
46446
  }
46447
+ if (frame.type === "heldLeases") {
46448
+ const held = HeldLeasesFrameSchema.safeParse(frame);
46449
+ if (!held.success || !options.onHeldLeases || held.data.connectionEpoch !== connectionEpoch) fail5("RELAY_FRAME_INVALID");
46450
+ try {
46451
+ options.onHeldLeases(held.data.bindings);
46452
+ } catch {
46453
+ }
46454
+ return;
46455
+ }
46161
46456
  if (frame.type === "workspace_ack") {
46162
46457
  const ack = ServerFrameSchema.safeParse(frame);
46163
46458
  if (!ack.success || ack.data.type !== "workspace_ack" || !pendingWorkspace.has(ack.data.requestId)) fail5("RELAY_FRAME_INVALID");
@@ -46314,10 +46609,10 @@ async function connectOnce(options) {
46314
46609
  // agent/src/machine-identity.ts
46315
46610
  import { spawn as spawn5 } from "node:child_process";
46316
46611
  import { createHash as createHash16 } from "node:crypto";
46317
- import os5 from "node:os";
46612
+ import os6 from "node:os";
46318
46613
  import { open as open7 } from "node:fs/promises";
46319
46614
  import { constants as constants8 } from "node:fs";
46320
- import path20 from "node:path";
46615
+ import path21 from "node:path";
46321
46616
  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;
46322
46617
  async function readMachineGuid(timeoutMs2 = 5e3) {
46323
46618
  if (process.platform === "linux") {
@@ -46338,7 +46633,7 @@ async function readMachineGuid(timeoutMs2 = 5e3) {
46338
46633
  }
46339
46634
  }
46340
46635
  if (!["win32", "darwin"].includes(process.platform)) return null;
46341
- const reg = process.platform === "darwin" ? "/usr/sbin/ioreg" : path20.join(process.env.SystemRoot || "C:\\Windows", "System32", "reg.exe");
46636
+ const reg = process.platform === "darwin" ? "/usr/sbin/ioreg" : path21.join(process.env.SystemRoot || "C:\\Windows", "System32", "reg.exe");
46342
46637
  const args = process.platform === "darwin" ? ["-rd1", "-c", "IOPlatformExpertDevice"] : ["query", "HKLM\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid", "/reg:64"];
46343
46638
  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;
46344
46639
  return new Promise((resolve) => {
@@ -46367,7 +46662,52 @@ async function readMachineGuid(timeoutMs2 = 5e3) {
46367
46662
  child.on("close", (code) => finish(code === 0 ? pattern.exec(output2)?.[1]?.toLowerCase() ?? null : null));
46368
46663
  });
46369
46664
  }
46370
- function machineProof(deviceId, machineGuid, computerName = os5.hostname()) {
46665
+ async function readComputerName(timeoutMs2 = 5e3) {
46666
+ const valid = (name2) => !!name2 && name2.length <= 120 && name2.trim() === name2 && !/[\u0000-\u001f\u007f]/.test(name2);
46667
+ if (process.platform === "linux") {
46668
+ let handle;
46669
+ try {
46670
+ handle = await open7("/etc/hostname", constants8.O_RDONLY | constants8.O_NOFOLLOW);
46671
+ const data = Buffer.alloc(257), { bytesRead } = await handle.read(data, 0, data.length, 0);
46672
+ const name2 = data.subarray(0, bytesRead).toString("utf8").trim();
46673
+ if (bytesRead <= 256 && valid(name2)) return name2;
46674
+ } catch {
46675
+ } finally {
46676
+ await handle?.close().catch(() => {
46677
+ });
46678
+ }
46679
+ }
46680
+ if (process.platform === "darwin") {
46681
+ const name2 = await new Promise((resolve) => {
46682
+ let output2 = "", settled = false;
46683
+ const finish = (value) => {
46684
+ if (!settled) {
46685
+ settled = true;
46686
+ clearTimeout(timer);
46687
+ resolve(value);
46688
+ }
46689
+ };
46690
+ const child = spawn5("/usr/sbin/scutil", ["--get", "ComputerName"], { shell: false, stdio: ["ignore", "pipe", "ignore"], env: buildChildEnvironment(process.env) });
46691
+ const timer = setTimeout(() => {
46692
+ child.kill();
46693
+ finish("");
46694
+ }, timeoutMs2);
46695
+ child.stdout.setEncoding("utf8");
46696
+ child.stdout.on("data", (chunk) => {
46697
+ if (output2.length + chunk.length <= 1024) output2 += chunk;
46698
+ else {
46699
+ child.kill();
46700
+ finish("");
46701
+ }
46702
+ });
46703
+ child.on("error", () => finish(""));
46704
+ child.on("close", (code) => finish(code === 0 ? output2.replace(/\n$/, "") : ""));
46705
+ });
46706
+ if (valid(name2)) return name2;
46707
+ }
46708
+ return os6.hostname();
46709
+ }
46710
+ function machineProof(deviceId, machineGuid, computerName = os6.hostname()) {
46371
46711
  const name2 = computerName.slice(0, 120);
46372
46712
  if (!name2 || name2.trim() !== name2 || /[\u0000-\u001f\u007f]/.test(name2)) return null;
46373
46713
  const fingerprint3 = createHash16("sha256").update("lcmcp-machine-v1\0" + deviceId.toLowerCase() + "\0" + machineGuid.toLowerCase() + "\0" + name2.toUpperCase(), "utf8").digest("hex");
@@ -46408,8 +46748,8 @@ function canonicalOrigin2(value) {
46408
46748
  fail6("ORIGIN_INVALID");
46409
46749
  }
46410
46750
  }
46411
- function endpoint(origin, path29) {
46412
- return origin + path29;
46751
+ function endpoint(origin, path30) {
46752
+ return origin + path30;
46413
46753
  }
46414
46754
  function uuid21(value, code) {
46415
46755
  if (typeof value !== "string" || !UUID3.test(value)) fail6(code);
@@ -46911,15 +47251,15 @@ async function deliverGuardEvidence(target, packet, options = {}) {
46911
47251
 
46912
47252
  // agent/src/optimization-ledger.ts
46913
47253
  import { constants as constants9 } from "node:fs";
46914
- import { lstat as lstat8, mkdir as mkdir8, open as open8, readFile as readFile8, realpath as realpath8 } from "node:fs/promises";
46915
- import path21 from "node:path";
47254
+ import { lstat as lstat8, mkdir as mkdir8, open as open8, readFile as readFile9, realpath as realpath8 } from "node:fs/promises";
47255
+ import path22 from "node:path";
46916
47256
  var MAX_LEDGER_BYTES = 64 * 1024 * 1024;
46917
47257
  var MAX_NOTICE_LEDGER_BYTES = 8 * 1024 * 1024;
46918
47258
  function failure5(code) {
46919
47259
  return Object.assign(new Error(code), { code });
46920
47260
  }
46921
47261
  async function safeDirectory2(directory) {
46922
- const absolute2 = path21.resolve(directory);
47262
+ const absolute2 = path22.resolve(directory);
46923
47263
  let current2 = absolute2;
46924
47264
  for (; ; ) {
46925
47265
  try {
@@ -46927,7 +47267,7 @@ async function safeDirectory2(directory) {
46927
47267
  } catch (error62) {
46928
47268
  if (error62.code !== "ENOENT") throw error62;
46929
47269
  }
46930
- const parent = path21.dirname(current2);
47270
+ const parent = path22.dirname(current2);
46931
47271
  if (parent === current2) break;
46932
47272
  current2 = parent;
46933
47273
  }
@@ -46962,15 +47302,15 @@ var OptimizationLedger = class _OptimizationLedger {
46962
47302
  closed = false;
46963
47303
  static async open(directory) {
46964
47304
  const dir = await safeDirectory2(directory);
46965
- const filename = path21.join(dir, "live-efficiency.v1.jsonl");
46966
- const noticesFilename = path21.join(dir, "live-efficiency-notices.v1.jsonl");
47305
+ const filename = path22.join(dir, "live-efficiency.v1.jsonl");
47306
+ const noticesFilename = path22.join(dir, "live-efficiency-notices.v1.jsonl");
46967
47307
  let existing = "";
46968
47308
  try {
46969
47309
  const stat2 = await lstat8(filename);
46970
47310
  if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > MAX_LEDGER_BYTES) {
46971
47311
  throw failure5("OPTIMIZATION_LEDGER_INVALID");
46972
47312
  }
46973
- existing = await readFile8(filename, "utf8");
47313
+ existing = await readFile9(filename, "utf8");
46974
47314
  } catch (error62) {
46975
47315
  if (error62.code !== "ENOENT") throw error62;
46976
47316
  }
@@ -46984,7 +47324,7 @@ var OptimizationLedger = class _OptimizationLedger {
46984
47324
  try {
46985
47325
  const noticeStat = await lstat8(noticesFilename);
46986
47326
  if (!noticeStat.isFile() || noticeStat.isSymbolicLink() || noticeStat.size > MAX_NOTICE_LEDGER_BYTES) throw failure5("OPTIMIZATION_NOTICE_LEDGER_INVALID");
46987
- const notices = await readFile8(noticesFilename, "utf8");
47327
+ const notices = await readFile9(noticesFilename, "utf8");
46988
47328
  for (const line of notices.split("\n")) {
46989
47329
  if (!line) continue;
46990
47330
  const parsed = JSON.parse(line);
@@ -47112,9 +47452,9 @@ var OptimizationLedger = class _OptimizationLedger {
47112
47452
 
47113
47453
  // agent/src/monitor.ts
47114
47454
  import { createHash as createHash17, randomUUID as randomUUID12 } from "node:crypto";
47115
- import { lstat as lstat9, mkdir as mkdir9, open as open9, rename as rename6, rm as rm7 } from "node:fs/promises";
47116
- import path22 from "node:path";
47117
- import os6 from "node:os";
47455
+ import { lstat as lstat9, mkdir as mkdir9, open as open9, rename as rename6, rm as rm8 } from "node:fs/promises";
47456
+ import path23 from "node:path";
47457
+ import os7 from "node:os";
47118
47458
 
47119
47459
  // packages/agent-cli/bin/monitor-savings.mjs
47120
47460
  var count = (value) => Number.isSafeInteger(value) && value >= 0 && value <= 1e15;
@@ -47136,7 +47476,7 @@ function lifetimeSavingsView(raw) {
47136
47476
  // agent/src/monitor.ts
47137
47477
  function commandSummary2(tool) {
47138
47478
  if (tool.name !== "command_run") return { name: tool.name, command: tool.name };
47139
- const candidate = path22.win32.basename(tool.args.command).replace(/\.(exe|cmd|bat|com)$/i, "").toLowerCase();
47479
+ const candidate = path23.win32.basename(tool.args.command).replace(/\.(exe|cmd|bat|com)$/i, "").toLowerCase();
47140
47480
  const name2 = ["node", "npm", "npx", "git", "rg", "powershell", "pwsh", "cmd", "tsc", "python", "dotnet"].includes(candidate) ? candidate : "command";
47141
47481
  let command = name2;
47142
47482
  if (name2 === "node" && tool.args.args.includes("--test") && !tool.args.args.some((arg) => ["-e", "--eval", "-p", "--print"].includes(arg))) command += " --test";
@@ -47149,9 +47489,9 @@ function commandSummary2(tool) {
47149
47489
  var ProductionMonitor = class {
47150
47490
  constructor(directory, stateDirectory, agentVersion3) {
47151
47491
  this.agentVersion = agentVersion3;
47152
- const key = createHash17("sha256").update(path22.resolve(stateDirectory).toLowerCase()).digest("hex");
47153
- this.file = path22.join(directory, key + ".json");
47154
- this.transportFile = path22.join(directory, key + ".transport");
47492
+ const key = createHash17("sha256").update(path23.resolve(stateDirectory).toLowerCase()).digest("hex");
47493
+ this.file = path23.join(directory, key + ".json");
47494
+ this.transportFile = path23.join(directory, key + ".transport");
47155
47495
  }
47156
47496
  agentVersion;
47157
47497
  instanceId = randomUUID12();
@@ -47162,7 +47502,7 @@ var ProductionMonitor = class {
47162
47502
  measured = /* @__PURE__ */ new Set();
47163
47503
  polls = { status: 0, output: 0 };
47164
47504
  efficiencyCalls = 0;
47165
- computer = os6.hostname().replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 64) || "PC";
47505
+ computer = os7.hostname().replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 64) || "PC";
47166
47506
  sequence = 0;
47167
47507
  connection = {
47168
47508
  state: "starting",
@@ -47343,7 +47683,7 @@ var ProductionMonitor = class {
47343
47683
  schemaVersion: 1,
47344
47684
  instanceId: this.instanceId,
47345
47685
  pid: process.pid,
47346
- savingsSourceId: path22.basename(this.file, ".json"),
47686
+ savingsSourceId: path23.basename(this.file, ".json"),
47347
47687
  lifetimeSavings: this.lifetimeSavings && { ...this.lifetimeSavings },
47348
47688
  computer: this.computer,
47349
47689
  processName: "lc-agent",
@@ -47377,7 +47717,7 @@ var ProductionMonitor = class {
47377
47717
  return this.writing;
47378
47718
  }
47379
47719
  async write(file2, contents) {
47380
- const directory = path22.dirname(file2);
47720
+ const directory = path23.dirname(file2);
47381
47721
  await mkdir9(directory, { recursive: true, mode: 448 });
47382
47722
  const stat2 = await lstat9(directory);
47383
47723
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw Error("MONITOR_DIRECTORY_INVALID");
@@ -47391,7 +47731,7 @@ var ProductionMonitor = class {
47391
47731
  }
47392
47732
  await rename6(temporary, file2);
47393
47733
  } finally {
47394
- await rm7(temporary, { force: true });
47734
+ await rm8(temporary, { force: true });
47395
47735
  }
47396
47736
  }
47397
47737
  async close() {
@@ -47802,13 +48142,13 @@ var NativeFabricObserver = class {
47802
48142
  };
47803
48143
 
47804
48144
  // agent/src/native-fabric-startup.ts
47805
- import { lstat as lstat11, mkdir as mkdir12, open as open11, readFile as readFile9 } from "node:fs/promises";
47806
- import path25 from "node:path";
48145
+ import { lstat as lstat11, mkdir as mkdir12, open as open11, readFile as readFile10 } from "node:fs/promises";
48146
+ import path26 from "node:path";
47807
48147
 
47808
48148
  // src/agent-fabric-service.ts
47809
48149
  import { lstat as lstat10, mkdir as mkdir11, realpath as realpath9 } from "node:fs/promises";
47810
48150
  import { watch } from "node:fs";
47811
- import path24 from "node:path";
48151
+ import path25 from "node:path";
47812
48152
 
47813
48153
  // src/agent-runtime-identity.ts
47814
48154
  import { createHash as createHash19, randomBytes as randomBytes7, randomUUID as randomUUID14, timingSafeEqual as timingSafeEqual4 } from "node:crypto";
@@ -47816,13 +48156,13 @@ import { createHash as createHash19, randomBytes as randomBytes7, randomUUID as
47816
48156
  // src/agent-fabric-state.ts
47817
48157
  import { randomUUID as randomUUID13 } from "node:crypto";
47818
48158
  import { mkdir as mkdir10, open as open10, rename as rename7, unlink as unlink2 } from "node:fs/promises";
47819
- import path23 from "node:path";
48159
+ import path24 from "node:path";
47820
48160
  var queues = /* @__PURE__ */ new Map();
47821
48161
  var FabricStateFile = class {
47822
48162
  constructor(file2, maxBytes, parse3) {
47823
48163
  this.maxBytes = maxBytes;
47824
48164
  this.parse = parse3;
47825
- this.file = path23.resolve(file2);
48165
+ this.file = path24.resolve(file2);
47826
48166
  }
47827
48167
  maxBytes;
47828
48168
  parse;
@@ -47866,7 +48206,7 @@ var FabricStateFile = class {
47866
48206
  }
47867
48207
  update(fn, create) {
47868
48208
  return this.serial(async () => {
47869
- if (create) await mkdir10(path23.dirname(this.file), { recursive: true });
48209
+ if (create) await mkdir10(path24.dirname(this.file), { recursive: true });
47870
48210
  const lockPath = this.file + ".lock";
47871
48211
  const token = randomUUID13();
47872
48212
  const lock = await open10(lockPath, "wx", 384).catch((error62) => {
@@ -48510,9 +48850,9 @@ var WorkerRequest = external_exports.discriminatedUnion("operation", [
48510
48850
  var AgentFabricService = class _AgentFabricService {
48511
48851
  constructor(directory, controllerId) {
48512
48852
  this.directory = directory;
48513
- this.identities = new AgentRuntimeIdentityStore(path24.join(directory, "identities.json"));
48853
+ this.identities = new AgentRuntimeIdentityStore(path25.join(directory, "identities.json"));
48514
48854
  this.mailbox = new AgentWorkerMailbox(
48515
- path24.join(directory, "mailbox.json"),
48855
+ path25.join(directory, "mailbox.json"),
48516
48856
  controllerId,
48517
48857
  this.identities,
48518
48858
  void 0,
@@ -48527,21 +48867,21 @@ var AgentFabricService = class _AgentFabricService {
48527
48867
  closed = false;
48528
48868
  static async open(directory, controllerId, device = null, initialize = true) {
48529
48869
  const expected = Binding.parse({ version: 1, controllerId, device, initialized: false });
48530
- const absolute2 = path24.resolve(directory);
48531
- for (let current2 = absolute2; ; current2 = path24.dirname(current2)) {
48870
+ const absolute2 = path25.resolve(directory);
48871
+ for (let current2 = absolute2; ; current2 = path25.dirname(current2)) {
48532
48872
  try {
48533
48873
  if ((await lstat10(current2)).isSymbolicLink()) throw Error("FABRIC_DIRECTORY_INVALID");
48534
48874
  } catch (error62) {
48535
48875
  if (error62.code !== "ENOENT") throw error62;
48536
48876
  }
48537
- if (path24.dirname(current2) === current2) break;
48877
+ if (path25.dirname(current2) === current2) break;
48538
48878
  }
48539
48879
  if (initialize) await mkdir11(absolute2, { recursive: true, mode: 448 });
48540
48880
  if (!(await lstat10(absolute2)).isDirectory() || (await realpath9(absolute2)).toLowerCase() !== absolute2.toLowerCase())
48541
48881
  throw Error("FABRIC_DIRECTORY_INVALID");
48542
48882
  const present = /* @__PURE__ */ new Set();
48543
48883
  for (const name2 of ["binding.json", "mailbox.json", "identities.json"]) {
48544
- const file2 = await lstat10(path24.join(absolute2, name2)).catch((error62) => {
48884
+ const file2 = await lstat10(path25.join(absolute2, name2)).catch((error62) => {
48545
48885
  if (error62.code === "ENOENT") return null;
48546
48886
  throw error62;
48547
48887
  });
@@ -48549,7 +48889,7 @@ var AgentFabricService = class _AgentFabricService {
48549
48889
  if (file2) present.add(name2);
48550
48890
  }
48551
48891
  if (!present.has("binding.json") && present.size) throw Error("FABRIC_BINDING_MISSING");
48552
- const binding2 = new FabricStateFile(path24.join(absolute2, "binding.json"), 2048, (value) => Binding.parse(value));
48892
+ const binding2 = new FabricStateFile(path25.join(absolute2, "binding.json"), 2048, (value) => Binding.parse(value));
48553
48893
  const service2 = new _AgentFabricService(absolute2, controllerId);
48554
48894
  await binding2.update(async (state) => {
48555
48895
  if (state.controllerId !== expected.controllerId || JSON.stringify(state.device) !== JSON.stringify(expected.device))
@@ -48564,7 +48904,7 @@ var AgentFabricService = class _AgentFabricService {
48564
48904
  state.initialized = true;
48565
48905
  }
48566
48906
  const snapshot2 = await service2.mailbox.snapshot();
48567
- if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await lstat10(path24.join(absolute2, "identities.json"));
48907
+ if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await lstat10(path25.join(absolute2, "identities.json"));
48568
48908
  }, initialize ? () => expected : void 0);
48569
48909
  return service2;
48570
48910
  }
@@ -48651,7 +48991,7 @@ var Delivery = external_exports.strictObject({ capability: external_exports.stri
48651
48991
  async function openNativeFabric(stateDirectory, enrollment, box, initialize = true) {
48652
48992
  const controllerId = "device-" + external_exports.string().uuid().parse(enrollment.deviceId).toLowerCase();
48653
48993
  const tenantId = external_exports.string().uuid().parse(enrollment.tenantId).toLowerCase();
48654
- const parent = path25.join(stateDirectory, ".local-commander"), marker = path25.join(parent, "fabric-established.json");
48994
+ const parent = path26.join(stateDirectory, ".local-commander"), marker = path26.join(parent, "fabric-established.json");
48655
48995
  try {
48656
48996
  await mkdir12(parent, { mode: 448 });
48657
48997
  } catch (error62) {
@@ -48663,7 +49003,7 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
48663
49003
  let fresh = false;
48664
49004
  try {
48665
49005
  const info = await lstat11(marker);
48666
- if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await readFile9(marker, "utf8") !== expected)
49006
+ if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await readFile10(marker, "utf8") !== expected)
48667
49007
  throw Error("FABRIC_BINDING_CHANGED");
48668
49008
  } catch (error62) {
48669
49009
  if (error62.code !== "ENOENT" || !initialize) throw error62;
@@ -48677,13 +49017,13 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
48677
49017
  fresh = true;
48678
49018
  }
48679
49019
  const service2 = await AgentFabricService.open(
48680
- path25.join(stateDirectory, ".local-commander", "fabric"),
49020
+ path26.join(stateDirectory, ".local-commander", "fabric"),
48681
49021
  controllerId,
48682
49022
  { deviceId: enrollment.deviceId.toLowerCase(), enrollmentEvidenceRef: "enrollment-" + tenantId },
48683
49023
  fresh
48684
49024
  );
48685
49025
  const purpose = "native-fabric:" + tenantId + ":" + controllerId;
48686
- const credentialFile = (workerId) => path25.join(service2.directory, external_exports.string().uuid().parse(workerId) + ".capability");
49026
+ const credentialFile = (workerId) => path26.join(service2.directory, external_exports.string().uuid().parse(workerId) + ".capability");
48687
49027
  const decode4 = (value) => {
48688
49028
  const credential = Credential.parse(JSON.parse(box.open(Buffer.from(value, "base64"), purpose).toString("utf8")));
48689
49029
  if (credential.controllerId !== controllerId) throw Error("FABRIC_WORKER_DENIED");
@@ -48692,7 +49032,7 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
48692
49032
  async function capability(workerId) {
48693
49033
  const file2 = credentialFile(workerId), info = await lstat11(file2);
48694
49034
  if (!info.isFile() || info.isSymbolicLink() || info.size > 4096) throw Error("FABRIC_CREDENTIAL_UNKNOWN");
48695
- const encoded = await readFile9(file2, "utf8");
49035
+ const encoded = await readFile10(file2, "utf8");
48696
49036
  if (decode4(encoded).workerId !== workerId) throw Error("FABRIC_WORKER_DENIED");
48697
49037
  return encoded;
48698
49038
  }
@@ -48784,7 +49124,7 @@ async function readFabricRequest(input2 = process.stdin) {
48784
49124
 
48785
49125
  // agent/src/supervisor-liveness.ts
48786
49126
  import { spawn as spawn6 } from "node:child_process";
48787
- import path26 from "node:path";
49127
+ import path27 from "node:path";
48788
49128
  import { setTimeout as delay3 } from "node:timers/promises";
48789
49129
  var ROW = /^"([^"]+)","(\d{1,10})"/;
48790
49130
  function parseTasklist(output2, image) {
@@ -48799,7 +49139,7 @@ function parseTasklist(output2, image) {
48799
49139
  }
48800
49140
  function listProcesses(image, timeoutMs2 = 5e3) {
48801
49141
  if (process.platform !== "win32" || !/^[A-Za-z0-9._-]{1,64}\.exe$/i.test(image)) return Promise.resolve(null);
48802
- const tasklist = path26.join(process.env.SystemRoot || "C:\\Windows", "System32", "tasklist.exe");
49142
+ const tasklist = path27.join(process.env.SystemRoot || "C:\\Windows", "System32", "tasklist.exe");
48803
49143
  return new Promise((resolve) => {
48804
49144
  let output2 = "", settled = false;
48805
49145
  const finish = (value) => {
@@ -48828,8 +49168,8 @@ function listProcesses(image, timeoutMs2 = 5e3) {
48828
49168
  }
48829
49169
  function supervisorLiveness(helperPath, options = {}) {
48830
49170
  if (process.platform === "linux" && !options.list) return linuxSupervisorLiveness;
48831
- if (process.platform === "darwin" && !options.list) return (pids, _linux, darwin) => darwinSupervisorLiveness(path26.join(path26.dirname(helperPath), "posix-host"), pids, darwin);
48832
- const image = path26.basename(helperPath), waitMs = options.waitMs ?? 1e4, pollMs = options.pollMs ?? 500, list = options.list ?? listProcesses;
49171
+ if (process.platform === "darwin" && !options.list) return (pids, _linux, darwin) => darwinSupervisorLiveness(path27.join(path27.dirname(helperPath), "posix-host"), pids, darwin);
49172
+ const image = path27.basename(helperPath), waitMs = options.waitMs ?? 1e4, pollMs = options.pollMs ?? 500, list = options.list ?? listProcesses;
48833
49173
  return async (pids) => {
48834
49174
  const deadline = Date.now() + waitMs;
48835
49175
  for (; ; ) {
@@ -48844,8 +49184,8 @@ function supervisorLiveness(helperPath, options = {}) {
48844
49184
 
48845
49185
  // agent/src/content-audit.ts
48846
49186
  import { createReadStream } from "node:fs";
48847
- 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";
48848
- import path27 from "node:path";
49187
+ import { appendFile, lstat as lstat12, mkdir as mkdir13, open as open12, readdir as readdir5, readFile as readFile11, rename as rename8, rm as rm9, writeFile as writeFile4 } from "node:fs/promises";
49188
+ import path28 from "node:path";
48849
49189
  import { performance as performance3 } from "node:perf_hooks";
48850
49190
  import { createInterface as createInterface2 } from "node:readline";
48851
49191
  import { randomBytes as randomBytes9 } from "node:crypto";
@@ -49014,7 +49354,7 @@ var FILE = /^(full|metrics)-(\d{4}-\d{2}-\d{2})\.jsonl$/;
49014
49354
  var PAUSED_FILE = "paused.json";
49015
49355
  var DAY_MS = 864e5;
49016
49356
  function contentAuditDirectory(stateDir) {
49017
- return path27.join(path27.dirname(path27.resolve(stateDir)), "Audit");
49357
+ return path28.join(path28.dirname(path28.resolve(stateDir)), "Audit");
49018
49358
  }
49019
49359
  async function plainDirectory(dir) {
49020
49360
  await mkdir13(dir, { recursive: true, mode: 448 });
@@ -49033,7 +49373,7 @@ async function auditFiles(dir) {
49033
49373
  for (const name2 of names) {
49034
49374
  const match = FILE.exec(name2);
49035
49375
  if (!match) continue;
49036
- const info = await lstat12(path27.join(dir, name2));
49376
+ const info = await lstat12(path28.join(dir, name2));
49037
49377
  if (info.isFile()) files.push({ name: name2, kind: match[1], day: match[2], bytes: info.size });
49038
49378
  }
49039
49379
  return files.sort((a, b) => a.name.localeCompare(b.name));
@@ -49044,7 +49384,7 @@ async function writeJsonAtomic(file2, value) {
49044
49384
  await writeFile4(temp, JSON.stringify(value) + "\n", { flag: "wx", mode: 384 });
49045
49385
  await rename8(temp, file2);
49046
49386
  } finally {
49047
- await rm8(temp, { force: true }).catch(() => {
49387
+ await rm9(temp, { force: true }).catch(() => {
49048
49388
  });
49049
49389
  }
49050
49390
  }
@@ -49071,7 +49411,7 @@ var ContentAudit = class _ContentAudit {
49071
49411
  skipped = 0;
49072
49412
  closed = false;
49073
49413
  static async open(options) {
49074
- const dir = path27.resolve(options.directory);
49414
+ const dir = path28.resolve(options.directory);
49075
49415
  await plainDirectory(dir);
49076
49416
  const audit = new _ContentAudit(
49077
49417
  dir,
@@ -49080,7 +49420,7 @@ var ContentAudit = class _ContentAudit {
49080
49420
  { retentionDays: options.retentionDays ?? AUDIT_RETENTION_DAYS, maxBytes: options.maxBytes ?? AUDIT_MAX_BYTES },
49081
49421
  options.now ?? (() => /* @__PURE__ */ new Date())
49082
49422
  );
49083
- await rm8(path27.join(dir, PAUSED_FILE), { force: true });
49423
+ await rm9(path28.join(dir, PAUSED_FILE), { force: true });
49084
49424
  await audit.rollover(audit.now());
49085
49425
  if (audit.usedBytes >= audit.limits.maxBytes) await audit.pause("QUOTA_EXCEEDED");
49086
49426
  return audit;
@@ -49150,8 +49490,8 @@ var ContentAudit = class _ContentAudit {
49150
49490
  await this.pause("QUOTA_EXCEEDED");
49151
49491
  return;
49152
49492
  }
49153
- await appendFile(path27.join(this.dir, `full-${day}.jsonl`), line, { mode: 384 });
49154
- await appendFile(path27.join(this.dir, `metrics-${day}.jsonl`), metrics, { mode: 384 });
49493
+ await appendFile(path28.join(this.dir, `full-${day}.jsonl`), line, { mode: 384 });
49494
+ await appendFile(path28.join(this.dir, `metrics-${day}.jsonl`), metrics, { mode: 384 });
49155
49495
  this.usedBytes += bytes3;
49156
49496
  }
49157
49497
  /** Daily retention runs on the first write of a new day; no timer or background scan. */
@@ -49160,7 +49500,7 @@ var ContentAudit = class _ContentAudit {
49160
49500
  const cutoff = new Date(at.getTime() - this.limits.retentionDays * DAY_MS).toISOString().slice(0, 10);
49161
49501
  let used = 0;
49162
49502
  for (const file2 of await auditFiles(this.dir)) {
49163
- if (file2.day <= cutoff) await rm8(path27.join(this.dir, file2.name), { force: true });
49503
+ if (file2.day <= cutoff) await rm9(path28.join(this.dir, file2.name), { force: true });
49164
49504
  else used += file2.bytes;
49165
49505
  }
49166
49506
  this.usedBytes = used;
@@ -49168,7 +49508,7 @@ var ContentAudit = class _ContentAudit {
49168
49508
  async pause(reason) {
49169
49509
  if (this.paused) return;
49170
49510
  this.paused = reason;
49171
- await writeJsonAtomic(path27.join(this.dir, PAUSED_FILE), { reason, at: this.now().toISOString() });
49511
+ await writeJsonAtomic(path28.join(this.dir, PAUSED_FILE), { reason, at: this.now().toISOString() });
49172
49512
  }
49173
49513
  };
49174
49514
  function percentiles(values) {
@@ -49190,13 +49530,13 @@ async function* jsonLines(file2) {
49190
49530
  }
49191
49531
  var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
49192
49532
  async function summarizeContentAudit(directory, key) {
49193
- const dir = path27.resolve(directory);
49533
+ const dir = path28.resolve(directory);
49194
49534
  const files = await auditFiles(dir);
49195
49535
  const days = /* @__PURE__ */ new Map();
49196
49536
  const sizes = [];
49197
49537
  const timings = [];
49198
49538
  for (const file2 of files.filter((f) => f.kind === "metrics")) {
49199
- for await (const line of jsonLines(path27.join(dir, file2.name))) {
49539
+ for await (const line of jsonLines(path28.join(dir, file2.name))) {
49200
49540
  let day = days.get(file2.day);
49201
49541
  if (!day) {
49202
49542
  day = { day: file2.day, records: 0, failed: 0, rawBytes: 0, sanitizedBytes: 0, compressedBytes: 0, envelopeBytes: 0 };
@@ -49216,7 +49556,7 @@ async function summarizeContentAudit(directory, key) {
49216
49556
  }
49217
49557
  let paused = null;
49218
49558
  try {
49219
- const value = JSON.parse(await readFile10(path27.join(dir, PAUSED_FILE), "utf8"));
49559
+ const value = JSON.parse(await readFile11(path28.join(dir, PAUSED_FILE), "utf8"));
49220
49560
  if (typeof value.reason === "string" && typeof value.at === "string") paused = { reason: value.reason.slice(0, 40), at: value.at.slice(0, 40) };
49221
49561
  } catch {
49222
49562
  }
@@ -49224,7 +49564,7 @@ async function summarizeContentAudit(directory, key) {
49224
49564
  const newest = files.filter((f) => f.kind === "full").at(-1);
49225
49565
  if (key && newest) {
49226
49566
  const tail = [];
49227
- for await (const line of jsonLines(path27.join(dir, newest.name))) {
49567
+ for await (const line of jsonLines(path28.join(dir, newest.name))) {
49228
49568
  tail.push(line);
49229
49569
  if (tail.length > 5) tail.shift();
49230
49570
  }
@@ -49258,10 +49598,10 @@ async function summarizeContentAudit(directory, key) {
49258
49598
  };
49259
49599
  }
49260
49600
  async function restoreContentAudit(input2, output2, key) {
49261
- const handle = await open12(path27.resolve(output2), "wx", 384);
49601
+ const handle = await open12(path28.resolve(output2), "wx", 384);
49262
49602
  let records = 0, failed = 0;
49263
49603
  try {
49264
- for await (const line of jsonLines(path27.resolve(input2))) {
49604
+ for await (const line of jsonLines(path28.resolve(input2))) {
49265
49605
  try {
49266
49606
  await handle.appendFile(JSON.stringify(decryptAuditRecord(line, key)) + "\n");
49267
49607
  records += 1;
@@ -49276,7 +49616,7 @@ async function restoreContentAudit(input2, output2, key) {
49276
49616
  }
49277
49617
 
49278
49618
  // agent/src/main.ts
49279
- var AGENT_VERSION2 = true ? "0.3.44" : "0.3.2";
49619
+ var AGENT_VERSION2 = true ? "0.3.46" : "0.3.2";
49280
49620
  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" : "";
49281
49621
  var AI_CONNECTION_SHIPPED = false;
49282
49622
  function processAlive(pid) {
@@ -49290,7 +49630,7 @@ function processAlive(pid) {
49290
49630
  }
49291
49631
  async function claimAgentProcess(stateDir, runtimeDir, version2) {
49292
49632
  await mkdir14(stateDir, { recursive: true });
49293
- const file2 = path28.join(stateDir, "agent-process.json");
49633
+ const file2 = path29.join(stateDir, "agent-process.json");
49294
49634
  for (let attempt = 0; attempt < 2; attempt += 1) {
49295
49635
  try {
49296
49636
  const handle = await open13(file2, "wx", 384);
@@ -49301,8 +49641,8 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
49301
49641
  }
49302
49642
  return async () => {
49303
49643
  try {
49304
- const current2 = JSON.parse(await readFile11(file2, "utf8"));
49305
- if (current2.pid === process.pid) await rm9(file2, { force: true });
49644
+ const current2 = JSON.parse(await readFile12(file2, "utf8"));
49645
+ if (current2.pid === process.pid) await rm10(file2, { force: true });
49306
49646
  } catch {
49307
49647
  }
49308
49648
  };
@@ -49310,12 +49650,12 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
49310
49650
  if (!error62 || typeof error62 !== "object" || !("code" in error62) || error62.code !== "EEXIST") throw error62;
49311
49651
  let stale = true;
49312
49652
  try {
49313
- const current2 = JSON.parse(await readFile11(file2, "utf8"));
49653
+ const current2 = JSON.parse(await readFile12(file2, "utf8"));
49314
49654
  stale = typeof current2.pid !== "number" || !processAlive(current2.pid);
49315
49655
  } catch {
49316
49656
  }
49317
49657
  if (!stale) throw Error("AGENT_ALREADY_RUNNING");
49318
- await rm9(file2, { force: true });
49658
+ await rm10(file2, { force: true });
49319
49659
  }
49320
49660
  }
49321
49661
  throw Error("AGENT_ALREADY_RUNNING");
@@ -49355,7 +49695,8 @@ async function runAgent(options) {
49355
49695
  throw error62;
49356
49696
  }
49357
49697
  const machineGuid = await readMachineGuid();
49358
- const machineIdentity = machineGuid ? (deviceId) => machineProof(deviceId, machineGuid) : void 0;
49698
+ let computerName = "";
49699
+ const machineIdentity = machineGuid ? (deviceId) => machineProof(deviceId, machineGuid, computerName) : void 0;
49359
49700
  const ledger = options.efficiencyLedger;
49360
49701
  monitor(() => options.monitor?.setLifetimeSavings(ledger?.savingsSnapshot?.()));
49361
49702
  const efficiencyLedger = ledger && {
@@ -49422,6 +49763,7 @@ async function runAgent(options) {
49422
49763
  });
49423
49764
  try {
49424
49765
  while (!options.signal.aborted) {
49766
+ computerName = await readComputerName();
49425
49767
  let ready;
49426
49768
  const readyPromise = new Promise((resolve) => {
49427
49769
  ready = resolve;
@@ -49436,6 +49778,11 @@ async function runAgent(options) {
49436
49778
  safeSlots: runtime.status().safeSlots,
49437
49779
  status: () => runtime.status(),
49438
49780
  onIncidentAck: (ack) => incidentProducer.ack(ack),
49781
+ // After bridge.connected, like requests: the journal has recorded this connection first.
49782
+ onHeldLeases: (bindings) => {
49783
+ void readyPromise.then(() => bridge.heldLeases(bindings)).catch(() => {
49784
+ });
49785
+ },
49439
49786
  handleRequest: async (request) => {
49440
49787
  await readyPromise;
49441
49788
  monitor(() => {
@@ -49559,10 +49906,10 @@ async function openContentAudit(store, stateDir) {
49559
49906
  async function main() {
49560
49907
  if (!["win32", "linux", "darwin"].includes(process.platform)) throw Error("PLATFORM_UNSUPPORTED");
49561
49908
  const appData = process.env.LC_AGENT_DATA_DIR ?? (process.platform === "win32" ? process.env.LOCALAPPDATA : posixDataHome());
49562
- if (!appData || !path28.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
49563
- const stateDir = process.env.LC_AGENT_STATE_DIR ?? path28.join(appData, "LocalCommander", "Agent");
49564
- const binaryDir = path28.dirname(process.platform === "win32" ? process.execPath : await realpath10(process.execPath));
49565
- const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path28.join(binaryDir, process.platform === "win32" ? "OwnerBridge.exe" : "owner-store");
49909
+ if (!appData || !path29.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
49910
+ const stateDir = process.env.LC_AGENT_STATE_DIR ?? path29.join(appData, "LocalCommander", "Agent");
49911
+ const binaryDir = path29.dirname(process.platform === "win32" ? process.execPath : await realpath10(process.execPath));
49912
+ const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path29.join(binaryDir, process.platform === "win32" ? "OwnerBridge.exe" : "owner-store");
49566
49913
  const store = await WindowsPrivateStore.open(stateDir, ownerBridgePath);
49567
49914
  const command = process.argv[2] ?? "run";
49568
49915
  if (process.platform !== "win32" && (command.startsWith("guard-") || command.startsWith("network-"))) throw Error("FEATURE_PLATFORM_UNSUPPORTED");
@@ -49572,7 +49919,7 @@ async function main() {
49572
49919
  const pairing = new PairingClient(store, { controlPlaneOrigin: origin, agentVersion: AGENT_VERSION2 });
49573
49920
  const begun = await pairing.begin();
49574
49921
  process.stdout.write(JSON.stringify({ approvalUrl: begun.approvalUrl, confirmationCode: begun.confirmationCode, expiresAt: begun.expiresAt.toISOString() }) + "\n");
49575
- await pairing.waitAndComplete(begun, os7.hostname().slice(0, 120));
49922
+ await pairing.waitAndComplete(begun, os8.hostname().slice(0, 120));
49576
49923
  process.stdout.write("DEVICE_PAIRED\n");
49577
49924
  return;
49578
49925
  }
@@ -49657,7 +50004,7 @@ async function main() {
49657
50004
  }
49658
50005
  if (command === "efficiency-report") {
49659
50006
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
49660
- const ledger = await OptimizationLedger.open(path28.join(stateDir, "optimization"));
50007
+ const ledger = await OptimizationLedger.open(path29.join(stateDir, "optimization"));
49661
50008
  try {
49662
50009
  process.stdout.write(JSON.stringify(await ledger.report(), null, 2) + "\n");
49663
50010
  } finally {
@@ -49667,7 +50014,7 @@ async function main() {
49667
50014
  }
49668
50015
  if (command === "guard-configure") {
49669
50016
  if (args.length !== 1) throw Error("AGENT_COMMAND_INVALID");
49670
- const filename = await (await import("node:fs/promises")).realpath(path28.resolve(args[0]));
50017
+ const filename = await (await import("node:fs/promises")).realpath(path29.resolve(args[0]));
49671
50018
  const input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readWindowsFile(ownerBridgePath, filename, 2e5)));
49672
50019
  if (!input2 || typeof input2 !== "object" || Object.keys(input2).sort().join(",") !== "compact,settings") throw Error("GUARD_CONFIGURATION_INVALID");
49673
50020
  await store.configureGuard(input2.settings, input2.compact);
@@ -49686,7 +50033,7 @@ async function main() {
49686
50033
  }
49687
50034
  if (command === "guard-evidence") {
49688
50035
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
49689
- const journal = await NativeJournal.open(path28.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
50036
+ const journal = await NativeJournal.open(path29.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
49690
50037
  try {
49691
50038
  process.stdout.write(JSON.stringify(await journal.guardEvidence()) + "\n");
49692
50039
  } finally {
@@ -49698,7 +50045,7 @@ async function main() {
49698
50045
  if (args.length !== (command === "guard-export" ? 0 : 1)) throw Error("AGENT_COMMAND_INVALID");
49699
50046
  const identity = await store.load();
49700
50047
  if (!identity?.enrollment) throw Error("ENROLLMENT_MISSING");
49701
- const journal = await NativeJournal.open(path28.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
50048
+ const journal = await NativeJournal.open(path29.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
49702
50049
  try {
49703
50050
  const { tenantId, deviceId } = identity.enrollment;
49704
50051
  const records = (await journal.guardEvidence()).filter((record2) => record2.tenantId === tenantId && record2.deviceId === deviceId);
@@ -49776,27 +50123,27 @@ async function main() {
49776
50123
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
49777
50124
  if (!(await store.load())?.enrollment) throw Error("ENROLLMENT_MISSING");
49778
50125
  const releaseProcess = await claimAgentProcess(stateDir, binaryDir, AGENT_VERSION2);
49779
- const monitor = new ProductionMonitor(path28.join(appData, "LocalCommander", "Monitor"), stateDir, AGENT_VERSION2);
50126
+ const monitor = new ProductionMonitor(path29.join(appData, "LocalCommander", "Monitor"), stateDir, AGENT_VERSION2);
49780
50127
  const publishMonitor = () => monitor.flush().catch(() => {
49781
50128
  process.stderr.write("MONITOR_WRITE_FAILED\n");
49782
50129
  });
49783
50130
  await publishMonitor();
49784
50131
  try {
49785
50132
  const journal = await NativeJournal.open(
49786
- path28.join(stateDir, "journal"),
50133
+ path29.join(stateDir, "journal"),
49787
50134
  new SecretBox({ "1": await store.loadDataKey() }),
49788
- process.platform === "win32" ? {} : { lockHelper: path28.join(binaryDir, "posix-host") }
50135
+ process.platform === "win32" ? {} : { lockHelper: path29.join(binaryDir, "posix-host") }
49789
50136
  );
49790
50137
  const ledgerLoss = () => {
49791
50138
  process.stderr.write("OPTIMIZATION_TELEMETRY_INCOMPLETE\n");
49792
50139
  };
49793
50140
  const efficiencyLedger = await new OptionalWork(ledgerLoss, 1e3, 1).run(
49794
- () => OptimizationLedger.open(path28.join(stateDir, "optimization")),
50141
+ () => OptimizationLedger.open(path29.join(stateDir, "optimization")),
49795
50142
  void 0,
49796
50143
  (ledger) => ledger.close()
49797
50144
  );
49798
50145
  try {
49799
- const helperPath = process.env.LC_JOB_HOST ?? path28.join(binaryDir, process.platform === "win32" ? "JobHost.exe" : "job-host.mjs");
50146
+ const helperPath = process.env.LC_JOB_HOST ?? path29.join(binaryDir, process.platform === "win32" ? "JobHost.exe" : "job-host.mjs");
49800
50147
  const tools = new NativeTools({ stateDirectory: stateDir, helperPath, ownerBridgePath, programs: await store.loadPrograms() });
49801
50148
  const stop = new AbortController();
49802
50149
  process.once("SIGINT", () => stop.abort());
@@ -49867,7 +50214,7 @@ async function main() {
49867
50214
  await releaseProcess();
49868
50215
  }
49869
50216
  }
49870
- var entrypoint = process.argv[1] && (process.platform === "win32" ? path28.resolve(process.argv[1]) : await realpath10(process.argv[1]).catch(() => null));
50217
+ var entrypoint = process.argv[1] && (process.platform === "win32" ? path29.resolve(process.argv[1]) : await realpath10(process.argv[1]).catch(() => null));
49871
50218
  if (entrypoint === fileURLToPath(import.meta.url)) {
49872
50219
  void main().catch((error62) => {
49873
50220
  const code = error62 instanceof Error && /^[A-Z0-9_]{1,64}$/.test(error62.message) ? error62.message : "AGENT_START_FAILED";