local-commander-agent 0.3.6 → 0.3.7

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
@@ -2278,7 +2278,7 @@ var require_websocket = __commonJS({
2278
2278
  var http = __require("http");
2279
2279
  var net = __require("net");
2280
2280
  var tls = __require("tls");
2281
- var { randomBytes: randomBytes4, createHash: createHash10 } = __require("crypto");
2281
+ var { randomBytes: randomBytes4, createHash: createHash11 } = __require("crypto");
2282
2282
  var { Duplex, Readable } = __require("stream");
2283
2283
  var { URL: URL2 } = __require("url");
2284
2284
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -2959,7 +2959,7 @@ var require_websocket = __commonJS({
2959
2959
  abortHandshake(websocket, socket, "Invalid Upgrade header");
2960
2960
  return;
2961
2961
  }
2962
- const digest4 = createHash10("sha1").update(key + GUID).digest("base64");
2962
+ const digest4 = createHash11("sha1").update(key + GUID).digest("base64");
2963
2963
  if (res.headers["sec-websocket-accept"] !== digest4) {
2964
2964
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2965
2965
  return;
@@ -3240,7 +3240,7 @@ var require_stream = __commonJS({
3240
3240
  };
3241
3241
  duplex._final = function(callback) {
3242
3242
  if (ws.readyState === ws.CONNECTING) {
3243
- ws.once("open", function open7() {
3243
+ ws.once("open", function open8() {
3244
3244
  duplex._final(callback);
3245
3245
  });
3246
3246
  return;
@@ -3261,7 +3261,7 @@ var require_stream = __commonJS({
3261
3261
  };
3262
3262
  duplex._write = function(chunk, encoding, callback) {
3263
3263
  if (ws.readyState === ws.CONNECTING) {
3264
- ws.once("open", function open7() {
3264
+ ws.once("open", function open8() {
3265
3265
  duplex._write(chunk, encoding, callback);
3266
3266
  });
3267
3267
  return;
@@ -3328,7 +3328,7 @@ var require_websocket_server = __commonJS({
3328
3328
  var EventEmitter = __require("events");
3329
3329
  var http = __require("http");
3330
3330
  var { Duplex } = __require("stream");
3331
- var { createHash: createHash10 } = __require("crypto");
3331
+ var { createHash: createHash11 } = __require("crypto");
3332
3332
  var extension2 = require_extension();
3333
3333
  var PerMessageDeflate2 = require_permessage_deflate();
3334
3334
  var subprotocol2 = require_subprotocol();
@@ -3635,7 +3635,7 @@ var require_websocket_server = __commonJS({
3635
3635
  );
3636
3636
  }
3637
3637
  if (this._state > RUNNING) return abortHandshake(socket, 503);
3638
- const digest4 = createHash10("sha1").update(key + GUID).digest("base64");
3638
+ const digest4 = createHash11("sha1").update(key + GUID).digest("base64");
3639
3639
  const headers = [
3640
3640
  "HTTP/1.1 101 Switching Protocols",
3641
3641
  "Upgrade: websocket",
@@ -3723,9 +3723,9 @@ var require_websocket_server = __commonJS({
3723
3723
  });
3724
3724
 
3725
3725
  // agent/src/main.ts
3726
- import path12 from "node:path";
3726
+ import path14 from "node:path";
3727
3727
  import os3 from "node:os";
3728
- import { mkdir as mkdir5, open as open6, readFile as readFile5, rm as rm4 } from "node:fs/promises";
3728
+ import { mkdir as mkdir6, open as open7, readFile as readFile5, rm as rm5 } from "node:fs/promises";
3729
3729
  import { fileURLToPath } from "node:url";
3730
3730
 
3731
3731
  // packages/operations/src/crypto.ts
@@ -4674,10 +4674,10 @@ function mergeDefs(...defs) {
4674
4674
  function cloneDef(schema) {
4675
4675
  return mergeDefs(schema._zod.def);
4676
4676
  }
4677
- function getElementAtPath(obj, path13) {
4678
- if (!path13)
4677
+ function getElementAtPath(obj, path15) {
4678
+ if (!path15)
4679
4679
  return obj;
4680
- return path13.reduce((acc, key) => acc?.[key], obj);
4680
+ return path15.reduce((acc, key) => acc?.[key], obj);
4681
4681
  }
4682
4682
  function promiseAllObject(promisesObj) {
4683
4683
  const keys = Object.keys(promisesObj);
@@ -5017,11 +5017,11 @@ function explicitlyAborted(x, startIndex = 0) {
5017
5017
  }
5018
5018
  return false;
5019
5019
  }
5020
- function prefixIssues(path13, issues) {
5020
+ function prefixIssues(path15, issues) {
5021
5021
  return issues.map((iss) => {
5022
5022
  var _a3;
5023
5023
  (_a3 = iss).path ?? (_a3.path = []);
5024
- iss.path.unshift(path13);
5024
+ iss.path.unshift(path15);
5025
5025
  return iss;
5026
5026
  });
5027
5027
  }
@@ -5471,16 +5471,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
5471
5471
  }
5472
5472
  function formatError(error62, mapper = (issue2) => issue2.message) {
5473
5473
  const fieldErrors = { _errors: [] };
5474
- const processError = (error63, path13 = []) => {
5474
+ const processError = (error63, path15 = []) => {
5475
5475
  for (const issue2 of error63.issues) {
5476
5476
  if (issue2.code === "invalid_union" && issue2.errors.length) {
5477
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
5477
+ issue2.errors.map((issues) => processError({ issues }, [...path15, ...issue2.path]));
5478
5478
  } else if (issue2.code === "invalid_key") {
5479
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
5479
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
5480
5480
  } else if (issue2.code === "invalid_element") {
5481
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
5481
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
5482
5482
  } else {
5483
- const fullpath = [...path13, ...issue2.path];
5483
+ const fullpath = [...path15, ...issue2.path];
5484
5484
  if (fullpath.length === 0) {
5485
5485
  fieldErrors._errors.push(mapper(issue2));
5486
5486
  } else {
@@ -5519,17 +5519,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
5519
5519
  }
5520
5520
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
5521
5521
  const result2 = { errors: [] };
5522
- const processError = (error63, path13 = []) => {
5522
+ const processError = (error63, path15 = []) => {
5523
5523
  var _a3;
5524
5524
  for (const issue2 of error63.issues) {
5525
5525
  if (issue2.code === "invalid_union" && issue2.errors.length) {
5526
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
5526
+ issue2.errors.map((issues) => processError({ issues }, [...path15, ...issue2.path]));
5527
5527
  } else if (issue2.code === "invalid_key") {
5528
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
5528
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
5529
5529
  } else if (issue2.code === "invalid_element") {
5530
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
5530
+ processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
5531
5531
  } else {
5532
- const fullpath = [...path13, ...issue2.path];
5532
+ const fullpath = [...path15, ...issue2.path];
5533
5533
  if (fullpath.length === 0) {
5534
5534
  result2.errors.push(mapper(issue2));
5535
5535
  continue;
@@ -5568,8 +5568,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
5568
5568
  }
5569
5569
  function toDotPath(_path) {
5570
5570
  const segs = [];
5571
- const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
5572
- for (const seg of path13) {
5571
+ const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
5572
+ for (const seg of path15) {
5573
5573
  if (typeof seg === "number")
5574
5574
  segs.push(`[${seg}]`);
5575
5575
  else if (typeof seg === "symbol")
@@ -22671,13 +22671,13 @@ function resolveRef(ref, ctx) {
22671
22671
  if (!ref.startsWith("#")) {
22672
22672
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
22673
22673
  }
22674
- const path13 = ref.slice(1).split("/").filter(Boolean);
22675
- if (path13.length === 0) {
22674
+ const path15 = ref.slice(1).split("/").filter(Boolean);
22675
+ if (path15.length === 0) {
22676
22676
  return ctx.rootSchema;
22677
22677
  }
22678
22678
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
22679
- if (path13[0] === defsKey) {
22680
- const key = path13[1] === void 0 ? void 0 : decodeJSONPointerSegment(path13[1]);
22679
+ if (path15[0] === defsKey) {
22680
+ const key = path15[1] === void 0 ? void 0 : decodeJSONPointerSegment(path15[1]);
22681
22681
  if (!key || !ctx.defs[key]) {
22682
22682
  throw new Error(`Reference not found: ${ref}`);
22683
22683
  }
@@ -25288,12 +25288,21 @@ async function planPermissionChange(current2, programs, input2) {
25288
25288
  workspace.permissions.writeFiles = change.enabled;
25289
25289
  detail = "File writes: " + (change.enabled ? "ALLOW" : "DENY");
25290
25290
  } else if (change.kind === "localhost") {
25291
+ if (workspace.fullAccess) {
25292
+ workspace.deniedLocalhostPorts = change.enabled ? (workspace.deniedLocalhostPorts ?? []).filter((port) => port !== change.port) : [.../* @__PURE__ */ new Set([...workspace.deniedLocalhostPorts ?? [], change.port])];
25293
+ if (workspace.deniedLocalhostPorts.length > 32) invalid2("PERMISSION_LIMIT");
25294
+ }
25291
25295
  workspace.localhostPorts = change.enabled ? [.../* @__PURE__ */ new Set([...workspace.localhostPorts, change.port])].sort((a, b) => a - b) : workspace.localhostPorts.filter((port) => port !== change.port);
25292
25296
  if (workspace.localhostPorts.length > 32) invalid2("PERMISSION_LIMIT");
25293
- workspace.permissions.localhost = workspace.localhostPorts.length > 0;
25297
+ workspace.permissions.localhost = workspace.fullAccess === true || workspace.localhostPorts.length > 0;
25294
25298
  resource = { rootHash: workspace.rootHash, kind: change.kind, port: change.port };
25295
25299
  detail = "Localhost port " + change.port + ": " + (change.enabled ? "ALLOW" : "DENY");
25296
25300
  } else {
25301
+ if (workspace.fullAccess) {
25302
+ const key = change.name.replace(/\.(exe|com|cmd|bat)$/i, "");
25303
+ workspace.deniedCommands = change.enabled ? (workspace.deniedCommands ?? []).filter((name2) => name2.replace(/\.(exe|com|cmd|bat)$/i, "") !== key) : [.../* @__PURE__ */ new Set([...workspace.deniedCommands ?? [], change.name])];
25304
+ if (workspace.deniedCommands.length > 32) invalid2("PERMISSION_LIMIT");
25305
+ }
25297
25306
  let executableIdentity = null;
25298
25307
  if (change.enabled) {
25299
25308
  const executable = change.executable;
@@ -25307,7 +25316,7 @@ async function planPermissionChange(current2, programs, input2) {
25307
25316
  if (workspace.allowedCommands.length > 32 || Object.keys(nextPrograms).length > 32) invalid2("PERMISSION_LIMIT");
25308
25317
  executableIdentity = { executable: canonical2, dev: stat.dev, ino: stat.ino, size: stat.size, mtimeMs: stat.mtimeMs, ctimeMs: stat.ctimeMs };
25309
25318
  } else workspace.allowedCommands = workspace.allowedCommands.filter((value) => value !== change.name);
25310
- workspace.permissions.executeCommands = workspace.allowedCommands.length > 0;
25319
+ workspace.permissions.executeCommands = workspace.fullAccess === true || workspace.allowedCommands.length > 0;
25311
25320
  resource = { rootHash: workspace.rootHash, kind: change.kind, name: change.name, executable: nextPrograms[change.name] ?? null, executableIdentity };
25312
25321
  detail = "Command " + permissionLabel(change.name) + ": " + (change.enabled ? "ALLOW" : "DENY") + "\nExact executable: " + permissionLabel(nextPrograms[change.name] ?? "not registered") + nonAsciiNotice(nextPrograms[change.name]) + "\nA permitted program can access resources available to your Windows account, including outside this folder. This is not an OS sandbox.";
25313
25322
  }
@@ -25679,9 +25688,12 @@ function validateState(value) {
25679
25688
  const pendingWorkspaceRevokes = value.pendingWorkspaceRevokes ?? [];
25680
25689
  if (!Array.isArray(pendingWorkspaceRevokes) || pendingWorkspaceRevokes.length > 32 || pendingWorkspaceRevokes.some((id) => typeof id !== "string" || !UUID.test(id) || id !== id.toLowerCase()) || new Set(pendingWorkspaceRevokes).size !== pendingWorkspaceRevokes.length) throw fail("STATE_CORRUPT");
25681
25690
  if (!programs || typeof programs !== "object" || Array.isArray(programs) || Object.keys(programs).length > 32 || Object.entries(programs).some(([name2, executable]) => !/^[a-z0-9_.-]{1,64}$/.test(name2) || typeof executable !== "string" || !path5.isAbsolute(executable) || executable.length > 4096 || /[\u0000-\u001f]/.test(executable))) throw fail("STATE_CORRUPT");
25682
- if (!Array.isArray(workspaces) || workspaces.length > 32 || workspaces.some((w) => !w || !UUID.test(w.workspaceGrantId) || typeof w.root !== "string" || !path5.isAbsolute(w.root) || w.root.length > 4096 || /[\u0000-\u001f]/.test(w.root) || !/^[a-f0-9]{64}$/.test(w.rootHash) || typeof w.displayName !== "string" || !w.displayName || w.displayName.length > 120 || w.policyVersion !== 1 || !w.permissions || w.permissions.readFiles !== true || typeof w.permissions.writeFiles !== "boolean" || typeof w.permissions.executeCommands !== "boolean" || typeof w.permissions.localhost !== "boolean" || !Array.isArray(w.allowedCommands) || w.allowedCommands.length > 32 || w.allowedCommands.some((name2) => typeof name2 !== "string" || !Object.hasOwn(programs, name2)) || new Set(w.allowedCommands).size !== w.allowedCommands.length || w.permissions.executeCommands !== w.allowedCommands.length > 0 || !Array.isArray(w.localhostPorts) || w.localhostPorts.length > 32 || w.localhostPorts.some((port) => !Number.isInteger(port) || port < 1 || port > 65535) || new Set(w.localhostPorts).size !== w.localhostPorts.length || w.permissions.localhost !== w.localhostPorts.length > 0)) throw fail("STATE_CORRUPT");
25691
+ if (!Array.isArray(workspaces) || workspaces.length > 32 || workspaces.some((w) => !w || !UUID.test(w.workspaceGrantId) || typeof w.root !== "string" || !path5.isAbsolute(w.root) || w.root.length > 4096 || /[\u0000-\u001f]/.test(w.root) || !/^[a-f0-9]{64}$/.test(w.rootHash) || typeof w.displayName !== "string" || !w.displayName || w.displayName.length > 120 || w.policyVersion !== 1 || !w.permissions || w.permissions.readFiles !== true || typeof w.permissions.writeFiles !== "boolean" || typeof w.permissions.executeCommands !== "boolean" || typeof w.permissions.localhost !== "boolean" || !Array.isArray(w.allowedCommands) || w.allowedCommands.length > 32 || w.allowedCommands.some((name2) => typeof name2 !== "string" || !Object.hasOwn(programs, name2)) || new Set(w.allowedCommands).size !== w.allowedCommands.length || w.permissions.executeCommands !== (w.fullAccess === true || w.allowedCommands.length > 0) || !Array.isArray(w.localhostPorts) || w.localhostPorts.length > 32 || w.localhostPorts.some((port) => !Number.isInteger(port) || port < 1 || port > 65535) || new Set(w.localhostPorts).size !== w.localhostPorts.length || w.permissions.localhost !== (w.fullAccess === true || w.localhostPorts.length > 0))) throw fail("STATE_CORRUPT");
25683
25692
  if (new Set(workspaces.map((w) => w.workspaceGrantId)).size !== workspaces.length || new Set(workspaces.map((w) => w.rootHash)).size !== workspaces.length) throw fail("STATE_CORRUPT");
25684
25693
  if (workspaces.some((w) => pendingWorkspaceRevokes.includes(w.workspaceGrantId))) throw fail("STATE_CORRUPT");
25694
+ for (const w of workspaces) {
25695
+ if (w.fullAccess !== void 0 && w.fullAccess !== true || w.deniedCommands !== void 0 && (!w.fullAccess || !Array.isArray(w.deniedCommands) || w.deniedCommands.length > 32 || w.deniedCommands.some((name2) => typeof name2 !== "string" || !/^[a-z0-9_.-]{1,64}$/.test(name2))) || w.deniedLocalhostPorts !== void 0 && (!w.fullAccess || !Array.isArray(w.deniedLocalhostPorts) || w.deniedLocalhostPorts.length > 32 || w.deniedLocalhostPorts.some((port) => !Number.isInteger(port) || port < 1 || port > 65535))) throw fail("STATE_CORRUPT");
25696
+ }
25685
25697
  return { version: 1, publicKeyPem: value.publicKeyPem, privateKeyPem: value.privateKeyPem, fingerprint: value.fingerprint, dataKey: value.dataKey, ...enrollment ? { enrollment } : {}, workspaces, programs, pendingWorkspaceRevokes, ...value.permissionHistory ? { permissionHistory: permissionHistory.data } : {}, ...policyBundle ? { policyBundle } : {}, ...approvals?.success ? { approvals: approvals.data } : {}, ...value.guardRequired ? { guardRequired: true } : {}, ...guard ? { guard } : {} };
25686
25698
  }
25687
25699
  async function noSymlinkChain(target) {
@@ -26154,7 +26166,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
26154
26166
  return this.run(async () => {
26155
26167
  const state = await this.readState();
26156
26168
  if (guardActive === false && state?.guardRequired) throw fail("GUARD_RESTART_REQUIRED");
26157
- return [...state?.workspaces ?? []].map((w) => ({ ...w, permissions: { ...w.permissions }, allowedCommands: [...w.allowedCommands], localhostPorts: [...w.localhostPorts] }));
26169
+ return structuredClone(state?.workspaces ?? []);
26158
26170
  });
26159
26171
  }
26160
26172
  loadPrograms() {
@@ -26178,7 +26190,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
26178
26190
  const before = await this.rawHash();
26179
26191
  state.workspaces = state.workspaces.filter((w) => w.workspaceGrantId !== id);
26180
26192
  state.pendingWorkspaceRevokes = [...state.pendingWorkspaceRevokes ?? [], id];
26181
- for (const name2 of Object.keys(state.programs ?? {})) if (!state.workspaces.some((w) => w.allowedCommands.includes(name2))) delete state.programs[name2];
26193
+ for (const name2 of Object.keys(state.programs ?? {})) if (!state.workspaces.some((w) => w.allowedCommands.includes(name2) || w.deniedCommands?.includes(name2))) delete state.programs[name2];
26182
26194
  await this.writeState(state, before);
26183
26195
  }));
26184
26196
  }
@@ -26220,7 +26232,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
26220
26232
  const before = await this.rawHash();
26221
26233
  state.workspaces = state.workspaces.map((w) => w.workspaceGrantId === verified.workspace.workspaceGrantId ? verified.workspace : w);
26222
26234
  state.programs = verified.programs;
26223
- for (const name2 of Object.keys(state.programs)) if (!state.workspaces.some((w) => w.allowedCommands.includes(name2))) delete state.programs[name2];
26235
+ for (const name2 of Object.keys(state.programs)) if (!state.workspaces.some((w) => w.allowedCommands.includes(name2) || w.deniedCommands?.includes(name2))) delete state.programs[name2];
26224
26236
  const record2 = {
26225
26237
  id: randomUUID3(),
26226
26238
  changedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -26267,7 +26279,8 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
26267
26279
  rootHash,
26268
26280
  displayName: (path5.basename(root) || root).slice(0, 120),
26269
26281
  policyVersion: 1,
26270
- permissions: { readFiles: true, writeFiles: true, executeCommands: false, localhost: false },
26282
+ ...selected.mode === "all-drives" ? { fullAccess: true } : {},
26283
+ permissions: { readFiles: true, writeFiles: true, executeCommands: selected.mode === "all-drives", localhost: selected.mode === "all-drives" },
26271
26284
  allowedCommands: [],
26272
26285
  localhostPorts: []
26273
26286
  };
@@ -26323,7 +26336,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
26323
26336
  // agent/src/tools.ts
26324
26337
  import { constants as constants3 } from "node:fs";
26325
26338
  import { lstat as lstat5, open as open4, readdir as readdir3, realpath as realpath5, rename as rename3, rm as rm3 } from "node:fs/promises";
26326
- import path9 from "node:path";
26339
+ import path10 from "node:path";
26327
26340
  import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
26328
26341
 
26329
26342
  // src/guard.ts
@@ -26567,11 +26580,31 @@ function invokeRead(bridge, file2, maxBytes, prefix, signal) {
26567
26580
  });
26568
26581
  }
26569
26582
 
26583
+ // src/process.ts
26584
+ import { statSync } from "node:fs";
26585
+ import path8 from "node:path";
26586
+ var WINDOWS_LAUNCH_EXTENSIONS = [".com", ".exe", ".bat", ".cmd"];
26587
+ function resolveWindowsLauncher(commandName, env = process.env) {
26588
+ const extensions = (env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.trim().toLowerCase()).filter((ext) => WINDOWS_LAUNCH_EXTENSIONS.includes(ext));
26589
+ for (const entry of (env.PATH ?? "").split(";")) {
26590
+ const dir = entry.trim().replace(/^"(.*)"$/, "$1");
26591
+ if (!path8.win32.isAbsolute(dir)) continue;
26592
+ for (const ext of extensions) {
26593
+ const file2 = path8.win32.join(dir, commandName + ext);
26594
+ try {
26595
+ if (statSync(file2).isFile()) return { file: file2, shell: ext === ".bat" || ext === ".cmd" };
26596
+ } catch {
26597
+ }
26598
+ }
26599
+ }
26600
+ return void 0;
26601
+ }
26602
+
26570
26603
  // agent/src/job-supervisor.ts
26571
26604
  import { spawn as spawn2 } from "node:child_process";
26572
- import path8 from "node:path";
26605
+ import path9 from "node:path";
26573
26606
  function absolute(value) {
26574
- return typeof value === "string" && value.length > 0 && value.length < 32767 && !value.includes("\0") && path8.isAbsolute(value) && path8.resolve(value) === value;
26607
+ return typeof value === "string" && value.length > 0 && value.length < 32767 && !value.includes("\0") && path9.isAbsolute(value) && path9.resolve(value) === value;
26575
26608
  }
26576
26609
  async function runSupervised(helper, request, options = {}) {
26577
26610
  if (process.platform !== "win32") throw Error("WINDOWS_SUPERVISOR_REQUIRED");
@@ -26587,7 +26620,7 @@ async function runSupervised(helper, request, options = {}) {
26587
26620
  let pid = null, outcome = null;
26588
26621
  let buffer = "", failure5 = null, closed = false, cancelSent = false;
26589
26622
  let killTimer, hardTimer;
26590
- const child = spawn2(helper, [], { cwd: path8.dirname(helper), stdio: ["pipe", "pipe", "pipe"], windowsHide: true, shell: false, env: buildChildEnvironment(process.env) });
26623
+ const child = spawn2(helper, [], { cwd: path9.dirname(helper), stdio: ["pipe", "pipe", "pipe"], windowsHide: true, shell: false, env: buildChildEnvironment(process.env) });
26591
26624
  const cancel = () => {
26592
26625
  if (closed || cancelSent) return;
26593
26626
  cancelSent = true;
@@ -26741,7 +26774,7 @@ var NativeTools = class {
26741
26774
  options;
26742
26775
  async readFile(file2, maxBytes, signal) {
26743
26776
  try {
26744
- return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path9.join(path9.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
26777
+ return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path10.join(path10.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
26745
26778
  } catch (error62) {
26746
26779
  if (error62.code === "ENOENT") throw error62;
26747
26780
  if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail2(error62.message);
@@ -26766,15 +26799,15 @@ var NativeTools = class {
26766
26799
  try {
26767
26800
  const canonical2 = await realpath5(workspace.root);
26768
26801
  if (!equalPath3(canonical2, workspace.root) || hash5(process.platform === "win32" ? canonical2.toLowerCase() : canonical2) !== workspace.rootHash) fail2("WORKSPACE_CHANGED");
26769
- const runtimeDirectory = path9.dirname(this.options.helperPath);
26802
+ const runtimeDirectory = path10.dirname(this.options.helperPath);
26770
26803
  const protectedPaths = [
26771
26804
  this.options.stateDirectory,
26772
26805
  this.options.helperPath,
26773
- ...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe"].map((name2) => path9.join(runtimeDirectory, name2))
26806
+ ...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe"].map((name2) => path10.join(runtimeDirectory, name2))
26774
26807
  ];
26775
26808
  if (this.options.ownerBridgePath) protectedPaths.push(this.options.ownerBridgePath);
26776
- if (process.platform === "win32" && process.env.LOCALAPPDATA && path9.isAbsolute(process.env.LOCALAPPDATA)) {
26777
- protectedPaths.push(path9.join(process.env.LOCALAPPDATA, "LocalCommander"));
26809
+ if (process.platform === "win32" && process.env.LOCALAPPDATA && path10.isAbsolute(process.env.LOCALAPPDATA)) {
26810
+ protectedPaths.push(path10.join(process.env.LOCALAPPDATA, "LocalCommander"));
26778
26811
  }
26779
26812
  guard = await PathGuard.create([canonical2], false, { protectedPaths });
26780
26813
  } catch (e) {
@@ -26806,7 +26839,7 @@ var NativeTools = class {
26806
26839
  const bytes3 = await this.readFile(filename, 1048576, signal), contents = utf8(bytes3), lines = contents.split(/\r?\n/);
26807
26840
  const selected = lines.slice(first - 1, Math.min(last, lines.length)).join("\n");
26808
26841
  if (Buffer.byteLength(selected) > 12e4) fail2("OUTPUT_LIMIT_EXCEEDED");
26809
- return result({ path: path9.relative(workspace.root, filename), sha256: hash5(bytes3), startLine: first, endLine: Math.min(last, lines.length), totalLines: lines.length, content: selected, truncated: last < lines.length });
26842
+ return result({ path: path10.relative(workspace.root, filename), sha256: hash5(bytes3), startLine: first, endLine: Math.min(last, lines.length), totalLines: lines.length, content: selected, truncated: last < lines.length });
26810
26843
  } };
26811
26844
  }
26812
26845
  if (call.name === "fs_write" || call.name === "fs_replace") {
@@ -26842,7 +26875,7 @@ var NativeTools = class {
26842
26875
  }
26843
26876
  const bytes3 = Buffer.from(contents, "utf8");
26844
26877
  if (bytes3.length > MAX_FILE_WRITE_BYTES) fail2("FILE_WRITE_LIMIT");
26845
- const temp = path9.join(path9.dirname(target), ".lc-write-" + randomUUID4() + ".tmp");
26878
+ const temp = path10.join(path10.dirname(target), ".lc-write-" + randomUUID4() + ".tmp");
26846
26879
  const handle = await open4(temp, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
26847
26880
  try {
26848
26881
  await handle.writeFile(bytes3);
@@ -26859,7 +26892,7 @@ var NativeTools = class {
26859
26892
  await link(temp, target);
26860
26893
  await rm3(temp);
26861
26894
  }
26862
- return result({ path: path9.relative(workspace.root, target), bytes: bytes3.length, sha256: hash5(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
26895
+ return result({ path: path10.relative(workspace.root, target), bytes: bytes3.length, sha256: hash5(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
26863
26896
  } catch (e) {
26864
26897
  await handle.close().catch(() => {
26865
26898
  });
@@ -26880,12 +26913,12 @@ var NativeTools = class {
26880
26913
  stopped(signal);
26881
26914
  if (matches2.length >= call.args.maxResults || scanned >= 300) break;
26882
26915
  try {
26883
- const filename = await guard.resolveExisting(path9.join(base, entry.path));
26916
+ const filename = await guard.resolveExisting(path10.join(base, entry.path));
26884
26917
  guard.assertSafeFile(filename);
26885
26918
  const data = utf8(await this.readFile(filename, 256e3, signal));
26886
26919
  scanned++;
26887
26920
  const lines = data.split(/\r?\n/);
26888
- for (let i = 0; i < lines.length && matches2.length < call.args.maxResults; i++) if ((call.args.caseSensitive ? lines[i] : lines[i].toLowerCase()).includes(query)) matches2.push({ path: path9.relative(workspace.root, filename), line: i + 1, text: lines[i].slice(0, 500) });
26921
+ for (let i = 0; i < lines.length && matches2.length < call.args.maxResults; i++) if ((call.args.caseSensitive ? lines[i] : lines[i].toLowerCase()).includes(query)) matches2.push({ path: path10.relative(workspace.root, filename), line: i + 1, text: lines[i].slice(0, 500) });
26889
26922
  } catch (error62) {
26890
26923
  if (error62 instanceof NativeToolError && ["FILE_READ_FAILED", "CANCELLED"].includes(error62.code)) throw error62;
26891
26924
  }
@@ -26895,7 +26928,7 @@ var NativeTools = class {
26895
26928
  }
26896
26929
  if (call.name === "localhost_request") {
26897
26930
  const url2 = new URL(call.args.url), port = Number(url2.port || (url2.protocol === "https:" ? 443 : 80));
26898
- if (!["http:", "https:"].includes(url2.protocol) || !["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname) || url2.username || url2.password || url2.hash || !workspace.localhostPorts.includes(port) || this.options.protectedPorts?.includes(port)) fail2("LOCALHOST_NOT_ALLOWED");
26931
+ if (!["http:", "https:"].includes(url2.protocol) || !["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname) || url2.username || url2.password || url2.hash || (workspace.fullAccess ? workspace.deniedLocalhostPorts?.includes(port) : !workspace.localhostPorts.includes(port)) || this.options.protectedPorts?.includes(port)) fail2("LOCALHOST_NOT_ALLOWED");
26899
26932
  const headers = {};
26900
26933
  for (const [name2, value] of Object.entries(call.args.headers ?? {})) {
26901
26934
  if (!/^[A-Za-z0-9-]+$/.test(name2) || /[\r\n]/.test(value) || ["host", "connection", "content-length", "transfer-encoding", "upgrade", "proxy-authorization", "proxy-connection"].includes(name2.toLowerCase()) || Object.keys(headers).some((k) => k.toLowerCase() === name2.toLowerCase())) fail2("INVALID_HTTP_HEADER");
@@ -26935,10 +26968,10 @@ var NativeTools = class {
26935
26968
  } };
26936
26969
  }
26937
26970
  if (call.name === "command_run") {
26938
- const cwd2 = await resolve(call.args.cwd, true), program = this.resolveProgram(call.args.command, workspace);
26971
+ const cwd2 = await resolve(call.args.cwd, true), program = await this.resolveProgram(call.args.command, workspace, call.args.args);
26939
26972
  const claims2 = writeClaim(cwd2);
26940
- return { call, claims: claims2, execution: { executable: program.executable, args: [...program.prefixArgs ?? [], ...call.args.args], cwd: cwd2 }, run: async (signal, onStarted, onOutput) => {
26941
- const r = await runSupervised(this.options.helperPath, { executable: program.executable, args: [...program.prefixArgs ?? [], ...call.args.args], cwd: cwd2, timeoutMs: call.args.timeoutMs, maxProcesses: 32 }, { signal, maxOutputBytes: 9e4, onStarted, onOutput });
26973
+ return { call, claims: claims2, execution: { ...program, cwd: cwd2 }, run: async (signal, onStarted, onOutput) => {
26974
+ const r = await runSupervised(this.options.helperPath, { ...program, cwd: cwd2, timeoutMs: call.args.timeoutMs, maxProcesses: 32 }, { signal, maxOutputBytes: 9e4, onStarted, onOutput });
26942
26975
  const { pid: _pid, ...output2 } = r;
26943
26976
  return { ...output2, resultCode: r.cancelled ? "CANCELLED" : r.timedOut ? "TIMEOUT" : r.exitCode === 0 ? "SUCCESS" : "USER_PROGRAM_FAILED" };
26944
26977
  } };
@@ -26952,9 +26985,9 @@ var NativeTools = class {
26952
26985
  else if (call.name === "git_diff") {
26953
26986
  argv = ["diff", "--no-ext-diff", "--no-textconv", ...call.args.staged ? ["--cached"] : []];
26954
26987
  if (call.args.file) {
26955
- const file2 = await resolve(path9.resolve(cwd, call.args.file));
26956
- const relative = path9.relative(cwd, file2);
26957
- if (relative.startsWith(".." + path9.sep) || relative === ".." || path9.isAbsolute(relative)) fail2("PATH_NOT_ALLOWED");
26988
+ const file2 = await resolve(path10.resolve(cwd, call.args.file));
26989
+ const relative = path10.relative(cwd, file2);
26990
+ if (relative.startsWith(".." + path10.sep) || relative === ".." || path10.isAbsolute(relative)) fail2("PATH_NOT_ALLOWED");
26958
26991
  argv.push("--", relative);
26959
26992
  } else argv.push("--stat");
26960
26993
  } else fail2("TOOL_MISSING");
@@ -26965,7 +26998,7 @@ var NativeTools = class {
26965
26998
  const listing = await this.list(guard, cwd, 1, 150, signal);
26966
26999
  let packageInfo = null;
26967
27000
  try {
26968
- const name2 = await guard.resolveExisting(path9.join(cwd, "package.json"));
27001
+ const name2 = await guard.resolveExisting(path10.join(cwd, "package.json"));
26969
27002
  guard.assertSafeFile(name2);
26970
27003
  const value = JSON.parse(utf8(await this.readFile(name2, 64e3, signal)));
26971
27004
  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) : [] };
@@ -26981,16 +27014,44 @@ var NativeTools = class {
26981
27014
  return { ...output2, resultCode: r.exitCode === 0 ? "SUCCESS" : "GIT_FAILED" };
26982
27015
  } };
26983
27016
  }
26984
- resolveProgram(name2, workspace) {
26985
- const entry = Object.entries(this.options.programs).find(([key, value]) => key.toLowerCase() === name2.toLowerCase() || path9.isAbsolute(name2) && equalPath3(value.executable, path9.resolve(name2)));
26986
- if (!entry || !workspace.allowedCommands.some((v) => v.toLowerCase() === entry[0].toLowerCase()) || !path9.isAbsolute(entry[1].executable)) fail2("COMMAND_NOT_ALLOWED");
26987
- return { executable: entry[1].executable, prefixArgs: [...entry[1].prefixArgs ?? []] };
27017
+ async resolveProgram(name2, workspace, args) {
27018
+ const entry = Object.entries(this.options.programs).find(([key, value]) => key.toLowerCase() === name2.toLowerCase() || path10.isAbsolute(name2) && equalPath3(value.executable, path10.resolve(name2)));
27019
+ if (workspace.fullAccess) {
27020
+ const commandKey = (value) => path10.basename(value).toLowerCase().replace(/\.(exe|com|cmd|bat)$/i, "");
27021
+ const denied = new Set((workspace.deniedCommands ?? []).map(commandKey));
27022
+ if (denied.has(commandKey(name2)) || entry && denied.has(commandKey(entry[0]))) fail2("COMMAND_NOT_ALLOWED");
27023
+ const extension2 = path10.extname(name2).toLowerCase();
27024
+ const candidate = entry?.[1].executable ?? (path10.isAbsolute(name2) ? name2 : /^[\w.-]+$/.test(name2) ? resolveWindowsLauncher(
27025
+ commandKey(name2),
27026
+ [".exe", ".com", ".cmd", ".bat"].includes(extension2) ? { ...process.env, PATHEXT: extension2 } : process.env
27027
+ )?.file : void 0);
27028
+ if (!candidate || !path10.isAbsolute(candidate)) fail2("COMMAND_NOT_FOUND");
27029
+ const executable = await realpath5(candidate).catch(() => fail2("COMMAND_NOT_FOUND"));
27030
+ if (!(await lstat5(executable)).isFile()) fail2("COMMAND_NOT_FOUND");
27031
+ if (denied.has(commandKey(executable))) fail2("COMMAND_NOT_ALLOWED");
27032
+ for (const key of workspace.deniedCommands ?? []) {
27033
+ const configured = this.options.programs[key]?.executable;
27034
+ if (configured && equalPath3(executable, await realpath5(configured).catch(() => configured))) fail2("COMMAND_NOT_ALLOWED");
27035
+ }
27036
+ if (/\.(cmd|bat)$/i.test(executable)) {
27037
+ if ([executable, ...args].some((value) => /[&|<>^%!"\r\n]/.test(value))) fail2("INVALID_SCRIPT_ARGUMENTS");
27038
+ const literal2 = (value) => "'" + value.replaceAll("'", "''") + "'";
27039
+ const shell = path10.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
27040
+ if (denied.has("powershell") || denied.has("cmd")) fail2("COMMAND_NOT_ALLOWED");
27041
+ const script = "& " + literal2(executable) + " @(" + args.map(literal2).join(",") + "); exit $LASTEXITCODE";
27042
+ return { executable: shell, args: ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")] };
27043
+ }
27044
+ if (!/\.(exe|com)$/i.test(executable)) fail2("COMMAND_NOT_ALLOWED");
27045
+ return { executable, args: [...entry?.[1].prefixArgs ?? [], ...args] };
27046
+ }
27047
+ if (!entry || !workspace.allowedCommands.some((v) => v.toLowerCase() === entry[0].toLowerCase()) || !path10.isAbsolute(entry[1].executable)) fail2("COMMAND_NOT_ALLOWED");
27048
+ return { executable: entry[1].executable, args: [...entry[1].prefixArgs ?? [], ...args] };
26988
27049
  }
26989
27050
  async gitExecution(cwd, args) {
26990
27051
  const configured = this.options.programs.git;
26991
- 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 && path9.isAbsolute(root)).map(([root, suffix]) => path9.join(root, suffix, "cmd", "git.exe")) : [];
27052
+ 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 && path10.isAbsolute(root)).map(([root, suffix]) => path10.join(root, suffix, "cmd", "git.exe")) : [];
26992
27053
  for (const candidate of candidates) {
26993
- if (!path9.isAbsolute(candidate)) continue;
27054
+ if (!path10.isAbsolute(candidate)) continue;
26994
27055
  try {
26995
27056
  const stat = await lstat5(candidate);
26996
27057
  if (!stat.isFile() || stat.isSymbolicLink() || !equalPath3(candidate, await realpath5(candidate))) continue;
@@ -27016,7 +27077,7 @@ var NativeTools = class {
27016
27077
  break;
27017
27078
  }
27018
27079
  if (item.isSymbolicLink() || excluded.has(item.name.toLowerCase())) continue;
27019
- const candidate = path9.join(current2.path, item.name);
27080
+ const candidate = path10.join(current2.path, item.name);
27020
27081
  let resolved;
27021
27082
  try {
27022
27083
  resolved = await guard.resolveExisting(candidate);
@@ -27026,11 +27087,11 @@ var NativeTools = class {
27026
27087
  }
27027
27088
  if (!equalPath3(candidate, resolved)) continue;
27028
27089
  if (item.isDirectory()) {
27029
- entries.push({ path: path9.relative(root, resolved), type: "directory" });
27090
+ entries.push({ path: path10.relative(root, resolved), type: "directory" });
27030
27091
  if (current2.level < depth) queue.push({ path: resolved, level: current2.level + 1 });
27031
27092
  } else if (item.isFile()) {
27032
27093
  const stat = await lstat5(resolved);
27033
- entries.push({ path: path9.relative(root, resolved), type: "file", size: stat.size });
27094
+ entries.push({ path: path10.relative(root, resolved), type: "file", size: stat.size });
27034
27095
  }
27035
27096
  }
27036
27097
  if (truncated) break;
@@ -27040,7 +27101,7 @@ var NativeTools = class {
27040
27101
  async gitCommonDir(cwd, workspace, guard) {
27041
27102
  let directory = cwd;
27042
27103
  while (guard.isWithin(directory, workspace.root)) {
27043
- const dotGit = path9.join(directory, ".git");
27104
+ const dotGit = path10.join(directory, ".git");
27044
27105
  try {
27045
27106
  const stat = await lstat5(dotGit);
27046
27107
  if (stat.isSymbolicLink()) fail2("GIT_METADATA_CHANGED");
@@ -27049,14 +27110,14 @@ var NativeTools = class {
27049
27110
  else {
27050
27111
  const content = utf8(await this.readFile(dotGit, 4096)).trim();
27051
27112
  if (!content.startsWith("gitdir: ")) fail2("GIT_METADATA_CHANGED");
27052
- gitDir = await realpath5(path9.resolve(directory, content.slice(8)));
27113
+ gitDir = await realpath5(path10.resolve(directory, content.slice(8)));
27053
27114
  }
27054
27115
  if (guard.isWithin(gitDir, this.options.stateDirectory) || !guard.isWithin(gitDir, workspace.root) && (!workspace.gitCommonDir || !guard.isWithin(gitDir, workspace.gitCommonDir))) fail2("GIT_COMMON_DIRECTORY_NOT_APPROVED");
27055
27116
  let common = gitDir;
27056
27117
  try {
27057
- const content = utf8(await this.readFile(path9.join(gitDir, "commondir"), 4096)).trim();
27118
+ const content = utf8(await this.readFile(path10.join(gitDir, "commondir"), 4096)).trim();
27058
27119
  if (!content) fail2("GIT_METADATA_CHANGED");
27059
- common = await realpath5(path9.resolve(gitDir, content));
27120
+ common = await realpath5(path10.resolve(gitDir, content));
27060
27121
  } catch (e) {
27061
27122
  if (e.code !== "ENOENT") throw e;
27062
27123
  }
@@ -27067,22 +27128,22 @@ var NativeTools = class {
27067
27128
  if (e.code !== "ENOENT") throw e;
27068
27129
  }
27069
27130
  if (equalPath3(directory, workspace.root)) break;
27070
- directory = path9.dirname(directory);
27131
+ directory = path10.dirname(directory);
27071
27132
  }
27072
27133
  return null;
27073
27134
  }
27074
27135
  };
27075
27136
 
27076
27137
  // agent/src/scheduler.ts
27077
- import path10 from "node:path";
27138
+ import path11 from "node:path";
27078
27139
  import os2 from "node:os";
27079
27140
  function canonical(value) {
27080
- const p = path10.resolve(value);
27141
+ const p = path11.resolve(value);
27081
27142
  return process.platform === "win32" ? p.toLowerCase() : p;
27082
27143
  }
27083
27144
  function ancestor(a, b) {
27084
- const relative = path10.relative(a, b);
27085
- return relative === "" || !path10.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path10.sep);
27145
+ const relative = path11.relative(a, b);
27146
+ return relative === "" || !path11.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path11.sep);
27086
27147
  }
27087
27148
  function claimsConflict(a, b) {
27088
27149
  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))));
@@ -27102,7 +27163,7 @@ var NativeScheduler = class {
27102
27163
  schedule(id, claims, deadlineAt, run, signal) {
27103
27164
  if (!this.accepting) return Promise.reject(Error("AGENT_PAUSED"));
27104
27165
  if (!id || id.length > 100 || this.active.has(id) || this.waiting.some((j) => j.id === id)) return Promise.reject(Error("DUPLICATE_SCHEDULED_EXECUTION"));
27105
- if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !path10.isAbsolute(c.path) || !["read", "write"].includes(c.mode))) return Promise.reject(Error("INVALID_RESOURCE_CLAIM"));
27166
+ if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !path11.isAbsolute(c.path) || !["read", "write"].includes(c.mode))) return Promise.reject(Error("INVALID_RESOURCE_CLAIM"));
27106
27167
  const deadline = deadlineAt.getTime();
27107
27168
  if (!Number.isFinite(deadline) || deadline <= Date.now()) return Promise.reject(Error("ADMISSION_DEADLINE_EXPIRED"));
27108
27169
  if (signal?.aborted) return Promise.reject(Error("CANCELLED_BEFORE_ACCEPTANCE"));
@@ -28553,8 +28614,8 @@ function canonicalOrigin2(value) {
28553
28614
  fail4("ORIGIN_INVALID");
28554
28615
  }
28555
28616
  }
28556
- function endpoint(origin, path13) {
28557
- return origin + path13;
28617
+ function endpoint(origin, path15) {
28618
+ return origin + path15;
28558
28619
  }
28559
28620
  function uuid17(value, code) {
28560
28621
  if (typeof value !== "string" || !UUID3.test(value)) fail4(code);
@@ -29057,14 +29118,14 @@ async function deliverGuardEvidence(target, packet, options = {}) {
29057
29118
  // agent/src/optimization-ledger.ts
29058
29119
  import { constants as constants4 } from "node:fs";
29059
29120
  import { lstat as lstat6, mkdir as mkdir4, open as open5, readFile as readFile4, realpath as realpath6 } from "node:fs/promises";
29060
- import path11 from "node:path";
29121
+ import path12 from "node:path";
29061
29122
  var MAX_LEDGER_BYTES = 64 * 1024 * 1024;
29062
29123
  var MAX_NOTICE_LEDGER_BYTES = 8 * 1024 * 1024;
29063
29124
  function failure4(code) {
29064
29125
  return Object.assign(new Error(code), { code });
29065
29126
  }
29066
29127
  async function safeDirectory2(directory) {
29067
- const absolute2 = path11.resolve(directory);
29128
+ const absolute2 = path12.resolve(directory);
29068
29129
  let current2 = absolute2;
29069
29130
  for (; ; ) {
29070
29131
  try {
@@ -29072,7 +29133,7 @@ async function safeDirectory2(directory) {
29072
29133
  } catch (error62) {
29073
29134
  if (error62.code !== "ENOENT") throw error62;
29074
29135
  }
29075
- const parent = path11.dirname(current2);
29136
+ const parent = path12.dirname(current2);
29076
29137
  if (parent === current2) break;
29077
29138
  current2 = parent;
29078
29139
  }
@@ -29097,8 +29158,8 @@ var OptimizationLedger = class _OptimizationLedger {
29097
29158
  closed = false;
29098
29159
  static async open(directory) {
29099
29160
  const dir = await safeDirectory2(directory);
29100
- const filename = path11.join(dir, "live-efficiency.v1.jsonl");
29101
- const noticesFilename = path11.join(dir, "live-efficiency-notices.v1.jsonl");
29161
+ const filename = path12.join(dir, "live-efficiency.v1.jsonl");
29162
+ const noticesFilename = path12.join(dir, "live-efficiency-notices.v1.jsonl");
29102
29163
  let existing = "";
29103
29164
  try {
29104
29165
  const stat = await lstat6(filename);
@@ -29230,8 +29291,144 @@ var OptimizationLedger = class _OptimizationLedger {
29230
29291
  }
29231
29292
  };
29232
29293
 
29294
+ // agent/src/monitor.ts
29295
+ import { createHash as createHash10, randomUUID as randomUUID7 } from "node:crypto";
29296
+ import { lstat as lstat7, mkdir as mkdir5, open as open6, rename as rename4, rm as rm4 } from "node:fs/promises";
29297
+ import path13 from "node:path";
29298
+ var ProductionMonitor = class {
29299
+ constructor(directory, stateDirectory, agentVersion3) {
29300
+ this.agentVersion = agentVersion3;
29301
+ const key = createHash10("sha256").update(path13.resolve(stateDirectory).toLowerCase()).digest("hex");
29302
+ this.file = path13.join(directory, key + ".json");
29303
+ }
29304
+ agentVersion;
29305
+ instanceId = randomUUID7();
29306
+ events = [];
29307
+ sessions = /* @__PURE__ */ new Map();
29308
+ sequence = 0;
29309
+ connection = {
29310
+ state: "starting",
29311
+ origin: null,
29312
+ epoch: null
29313
+ };
29314
+ writing = null;
29315
+ file;
29316
+ record(event, details = {}) {
29317
+ this.events.push({ seq: ++this.sequence, at: (/* @__PURE__ */ new Date()).toISOString(), event, ...details });
29318
+ if (this.events.length > 100) this.events.shift();
29319
+ }
29320
+ configureOrigin(origin) {
29321
+ try {
29322
+ const url2 = new URL(origin);
29323
+ if (url2.origin === origin && !url2.username && !url2.password && (url2.protocol === "https:" || url2.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname))) {
29324
+ this.connection.origin = url2.origin;
29325
+ }
29326
+ } catch {
29327
+ }
29328
+ }
29329
+ setConnection(state, connection) {
29330
+ if (connection) {
29331
+ try {
29332
+ this.configureOrigin(new URL(connection.url).origin.replace(/^ws/, "http"));
29333
+ } catch {
29334
+ }
29335
+ this.connection.epoch = connection.connectionEpoch;
29336
+ }
29337
+ this.connection.state = state;
29338
+ this.record(state);
29339
+ }
29340
+ request(request) {
29341
+ const payload = request.payload;
29342
+ const parsed = ExecutionBindingSchema.safeParse(payload?.binding);
29343
+ if (!parsed.success || parsed.data.tenantId !== request.tenantId || parsed.data.deviceId !== request.deviceId || parsed.data.executionId !== request.executionId || parsed.data.operationId !== request.operationId) return;
29344
+ const binding2 = parsed.data;
29345
+ this.sessions.delete(binding2.sessionId);
29346
+ this.sessions.set(binding2.sessionId, {
29347
+ sessionId: binding2.sessionId,
29348
+ workspaceGrantId: binding2.workspaceGrantId,
29349
+ lastSeenAt: (/* @__PURE__ */ new Date()).toISOString(),
29350
+ model: null
29351
+ });
29352
+ if (this.sessions.size > 32) this.sessions.delete(this.sessions.keys().next().value);
29353
+ const tool = ToolCallSchema.safeParse(payload?.tool);
29354
+ this.record(request.kind, {
29355
+ sessionId: binding2.sessionId,
29356
+ executionId: binding2.executionId,
29357
+ ...tool.success ? { tool: tool.data.name } : {}
29358
+ });
29359
+ }
29360
+ result(binding2, state, code) {
29361
+ this.record(["finished", "failed", "cancelled", "unknown"].includes(state) ? state : "result", {
29362
+ sessionId: binding2.sessionId,
29363
+ executionId: binding2.executionId,
29364
+ code: code === "SUCCESS" || ErrorCodeSchema.safeParse(code).success ? code : "RESULT"
29365
+ });
29366
+ }
29367
+ requestFailed() {
29368
+ this.record("request_failed");
29369
+ }
29370
+ connectionFailed(error62) {
29371
+ const code = error62 instanceof Error ? error62.message : "";
29372
+ this.record("connection_error", { code: [
29373
+ "RELAY_CONNECT_FAILED",
29374
+ "RELAY_CONNECT_CLOSED",
29375
+ "RELAY_CONNECT_TIMEOUT",
29376
+ "RELAY_HANDSHAKE_TIMEOUT",
29377
+ "RELAY_RESULT_TIMEOUT",
29378
+ "WORKSPACE_ACK_TIMEOUT"
29379
+ ].includes(code) ? code : "CONNECTION_FAILED" });
29380
+ }
29381
+ response(value) {
29382
+ const result2 = value;
29383
+ if (result2?.accepted === false) this.record("rejected", {
29384
+ code: ErrorCodeSchema.safeParse(result2.code).success ? String(result2.code) : "REJECTED"
29385
+ });
29386
+ }
29387
+ snapshot() {
29388
+ return {
29389
+ schemaVersion: 1,
29390
+ instanceId: this.instanceId,
29391
+ pid: process.pid,
29392
+ agentVersion: this.agentVersion,
29393
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
29394
+ connection: { ...this.connection },
29395
+ sessions: [...this.sessions.values()].map((session) => ({ ...session })),
29396
+ events: this.events.map((event) => ({ ...event }))
29397
+ };
29398
+ }
29399
+ flush() {
29400
+ if (this.writing) return this.writing;
29401
+ this.writing = (async () => {
29402
+ const directory = path13.dirname(this.file);
29403
+ await mkdir5(directory, { recursive: true, mode: 448 });
29404
+ const stat = await lstat7(directory);
29405
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw Error("MONITOR_DIRECTORY_INVALID");
29406
+ const temporary = this.file + "." + this.instanceId + ".tmp";
29407
+ const handle = await open6(temporary, "wx", 384);
29408
+ try {
29409
+ try {
29410
+ await handle.writeFile(JSON.stringify(this.snapshot()) + "\n");
29411
+ } finally {
29412
+ await handle.close();
29413
+ }
29414
+ await rename4(temporary, this.file);
29415
+ } finally {
29416
+ await rm4(temporary, { force: true });
29417
+ }
29418
+ })().finally(() => {
29419
+ this.writing = null;
29420
+ });
29421
+ return this.writing;
29422
+ }
29423
+ async close() {
29424
+ await this.writing?.catch(() => {
29425
+ });
29426
+ await this.flush();
29427
+ }
29428
+ };
29429
+
29233
29430
  // agent/src/main.ts
29234
- var AGENT_VERSION2 = true ? "0.3.6" : "0.3.2";
29431
+ var AGENT_VERSION2 = true ? "0.3.7" : "0.3.2";
29235
29432
  function processAlive(pid) {
29236
29433
  if (!Number.isInteger(pid) || pid <= 0) return false;
29237
29434
  try {
@@ -29242,11 +29439,11 @@ function processAlive(pid) {
29242
29439
  }
29243
29440
  }
29244
29441
  async function claimAgentProcess(stateDir, runtimeDir, version2) {
29245
- await mkdir5(stateDir, { recursive: true });
29246
- const file2 = path12.join(stateDir, "agent-process.json");
29442
+ await mkdir6(stateDir, { recursive: true });
29443
+ const file2 = path14.join(stateDir, "agent-process.json");
29247
29444
  for (let attempt = 0; attempt < 2; attempt += 1) {
29248
29445
  try {
29249
- const handle = await open6(file2, "wx", 384);
29446
+ const handle = await open7(file2, "wx", 384);
29250
29447
  try {
29251
29448
  await handle.writeFile(JSON.stringify({ pid: process.pid, runtimeDir, version: version2, startedAt: (/* @__PURE__ */ new Date()).toISOString() }) + "\n", "utf8");
29252
29449
  } finally {
@@ -29255,7 +29452,7 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
29255
29452
  return async () => {
29256
29453
  try {
29257
29454
  const current2 = JSON.parse(await readFile5(file2, "utf8"));
29258
- if (current2.pid === process.pid) await rm4(file2, { force: true });
29455
+ if (current2.pid === process.pid) await rm5(file2, { force: true });
29259
29456
  } catch {
29260
29457
  }
29261
29458
  };
@@ -29268,7 +29465,7 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
29268
29465
  } catch {
29269
29466
  }
29270
29467
  if (!stale) throw Error("AGENT_ALREADY_RUNNING");
29271
- await rm4(file2, { force: true });
29468
+ await rm5(file2, { force: true });
29272
29469
  }
29273
29470
  }
29274
29471
  throw Error("AGENT_ALREADY_RUNNING");
@@ -29291,6 +29488,7 @@ async function runAgent(options) {
29291
29488
  if (!Number.isInteger(delay) || delay < 0 || delay > 3e4) throw Error("RECONNECT_DELAY_INVALID");
29292
29489
  const identity = await options.store.load();
29293
29490
  if (!identity?.enrollment) throw Error("ENROLLMENT_MISSING");
29491
+ options.monitor?.configureOrigin(identity.enrollment.serverOrigin);
29294
29492
  await options.journal.recoverAfterRestart();
29295
29493
  await options.store.loadWorkspaces();
29296
29494
  } catch (error62) {
@@ -29300,6 +29498,7 @@ async function runAgent(options) {
29300
29498
  const runtime = new NativeRuntime({ journal: options.journal, tools: options.tools, scheduler: new NativeScheduler(), workspaces: () => options.store.loadWorkspaces(Boolean(options.guard)), guard: options.guard, efficiencyLedger: options.efficiencyLedger });
29301
29499
  let connection = null;
29302
29500
  const bridge = new NativeRelayBridge(runtime, (binding2, state, code, metrics) => {
29501
+ options.monitor?.result(binding2, state, code);
29303
29502
  if (!connection) throw Error("RELAY_SOCKET_CLOSED");
29304
29503
  return connection.sendTerminal(binding2, state, code, metrics);
29305
29504
  }, options.journal);
@@ -29311,11 +29510,21 @@ async function runAgent(options) {
29311
29510
  ready = resolve;
29312
29511
  });
29313
29512
  try {
29513
+ options.monitor?.setConnection("connecting");
29314
29514
  connection = await connect({ store: options.store, agentVersion: options.agentVersion, handleRequest: async (request) => {
29315
29515
  await readyPromise;
29316
- return bridge.handle(request);
29516
+ options.monitor?.request(request);
29517
+ try {
29518
+ const result2 = await bridge.handle(request);
29519
+ options.monitor?.response(result2);
29520
+ return result2;
29521
+ } catch (error62) {
29522
+ options.monitor?.requestFailed();
29523
+ throw error62;
29524
+ }
29317
29525
  } });
29318
29526
  await bridge.connected(connection);
29527
+ options.monitor?.setConnection("connected", connection);
29319
29528
  ready();
29320
29529
  if (options.signal.aborted) connection.close("agent_shutdown");
29321
29530
  else {
@@ -29337,9 +29546,11 @@ async function runAgent(options) {
29337
29546
  }
29338
29547
  } catch (error62) {
29339
29548
  ready();
29549
+ options.monitor?.connectionFailed(error62);
29340
29550
  if (error62 instanceof RelayClientError && ["RELAY_CONNECT_FAILED", "RELAY_CONNECT_CLOSED", "RELAY_CONNECT_TIMEOUT", "RELAY_HANDSHAKE_TIMEOUT"].includes(error62.code)) {
29341
29551
  } else throw error62;
29342
29552
  } finally {
29553
+ options.monitor?.setConnection("disconnected");
29343
29554
  connection?.close("agent_disconnect");
29344
29555
  await bridge.disconnected();
29345
29556
  connection = null;
@@ -29354,10 +29565,10 @@ async function runAgent(options) {
29354
29565
  async function main() {
29355
29566
  if (process.platform !== "win32") throw Error("WINDOWS_REQUIRED");
29356
29567
  const appData = process.env.LOCALAPPDATA;
29357
- if (!appData || !path12.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
29358
- const stateDir = process.env.LC_AGENT_STATE_DIR ?? path12.join(appData, "LocalCommander", "Agent");
29359
- const binaryDir = path12.dirname(process.execPath);
29360
- const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path12.join(binaryDir, "OwnerBridge.exe");
29568
+ if (!appData || !path14.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
29569
+ const stateDir = process.env.LC_AGENT_STATE_DIR ?? path14.join(appData, "LocalCommander", "Agent");
29570
+ const binaryDir = path14.dirname(process.execPath);
29571
+ const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path14.join(binaryDir, "OwnerBridge.exe");
29361
29572
  const store = await WindowsPrivateStore.open(stateDir, ownerBridgePath);
29362
29573
  const command = process.argv[2] ?? "run";
29363
29574
  if (command === "pair") {
@@ -29395,6 +29606,9 @@ async function main() {
29395
29606
  displayName: w.displayName,
29396
29607
  path: w.root,
29397
29608
  permissions: w.permissions,
29609
+ accessMode: w.fullAccess ? "full" : "scoped",
29610
+ deniedCommands: w.deniedCommands ?? [],
29611
+ deniedLocalhostPorts: w.deniedLocalhostPorts ?? [],
29398
29612
  allowedCommands: w.allowedCommands,
29399
29613
  executables: Object.fromEntries(w.allowedCommands.map((name2) => [name2, programs[name2]?.executable ?? null])),
29400
29614
  localhostPorts: w.localhostPorts,
@@ -29405,7 +29619,7 @@ async function main() {
29405
29619
  const args = process.argv.slice(3);
29406
29620
  if (command === "efficiency-report") {
29407
29621
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
29408
- const ledger = await OptimizationLedger.open(path12.join(stateDir, "optimization"));
29622
+ const ledger = await OptimizationLedger.open(path14.join(stateDir, "optimization"));
29409
29623
  try {
29410
29624
  process.stdout.write(JSON.stringify(await ledger.report(), null, 2) + "\n");
29411
29625
  } finally {
@@ -29415,7 +29629,7 @@ async function main() {
29415
29629
  }
29416
29630
  if (command === "guard-configure") {
29417
29631
  if (args.length !== 1) throw Error("AGENT_COMMAND_INVALID");
29418
- const filename = await (await import("node:fs/promises")).realpath(path12.resolve(args[0]));
29632
+ const filename = await (await import("node:fs/promises")).realpath(path14.resolve(args[0]));
29419
29633
  const input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readWindowsFile(ownerBridgePath, filename, 2e5)));
29420
29634
  if (!input2 || typeof input2 !== "object" || Object.keys(input2).sort().join(",") !== "compact,settings") throw Error("GUARD_CONFIGURATION_INVALID");
29421
29635
  await store.configureGuard(input2.settings, input2.compact);
@@ -29434,7 +29648,7 @@ async function main() {
29434
29648
  }
29435
29649
  if (command === "guard-evidence") {
29436
29650
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
29437
- const journal = await NativeJournal.open(path12.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
29651
+ const journal = await NativeJournal.open(path14.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
29438
29652
  try {
29439
29653
  process.stdout.write(JSON.stringify(await journal.guardEvidence()) + "\n");
29440
29654
  } finally {
@@ -29446,7 +29660,7 @@ async function main() {
29446
29660
  if (args.length !== (command === "guard-export" ? 0 : 1)) throw Error("AGENT_COMMAND_INVALID");
29447
29661
  const identity = await store.load();
29448
29662
  if (!identity?.enrollment) throw Error("ENROLLMENT_MISSING");
29449
- const journal = await NativeJournal.open(path12.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
29663
+ const journal = await NativeJournal.open(path14.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
29450
29664
  try {
29451
29665
  const { tenantId, deviceId } = identity.enrollment;
29452
29666
  const records = (await journal.guardEvidence()).filter((record2) => record2.tenantId === tenantId && record2.deviceId === deviceId);
@@ -29484,25 +29698,41 @@ async function main() {
29484
29698
  if (args.length) throw Error("AGENT_COMMAND_INVALID");
29485
29699
  if (!(await store.load())?.enrollment) throw Error("ENROLLMENT_MISSING");
29486
29700
  const releaseProcess = await claimAgentProcess(stateDir, binaryDir, AGENT_VERSION2);
29701
+ const monitor = new ProductionMonitor(path14.join(appData, "LocalCommander", "Monitor"), stateDir, AGENT_VERSION2);
29702
+ const publishMonitor = () => monitor.flush().catch(() => {
29703
+ process.stderr.write("MONITOR_WRITE_FAILED\n");
29704
+ });
29705
+ await publishMonitor();
29706
+ const monitorTimer = setInterval(() => {
29707
+ void publishMonitor();
29708
+ }, 2e3);
29487
29709
  try {
29488
- const journal = await NativeJournal.open(path12.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
29489
- const efficiencyLedger = await OptimizationLedger.open(path12.join(stateDir, "optimization"));
29710
+ const journal = await NativeJournal.open(path14.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
29711
+ const efficiencyLedger = await OptimizationLedger.open(path14.join(stateDir, "optimization"));
29490
29712
  try {
29491
- const tools = new NativeTools({ stateDirectory: stateDir, helperPath: process.env.LC_JOB_HOST ?? path12.join(binaryDir, "JobHost.exe"), ownerBridgePath, programs: await store.loadPrograms() });
29713
+ const tools = new NativeTools({ stateDirectory: stateDir, helperPath: process.env.LC_JOB_HOST ?? path14.join(binaryDir, "JobHost.exe"), ownerBridgePath, programs: await store.loadPrograms() });
29492
29714
  const stop = new AbortController();
29493
29715
  process.once("SIGINT", () => stop.abort());
29494
29716
  process.once("SIGTERM", () => stop.abort());
29495
29717
  const guard = await NativeGuard.open(store, journal);
29496
- await runAgent({ store, journal, tools, signal: stop.signal, agentVersion: AGENT_VERSION2, guard, efficiencyLedger });
29718
+ await runAgent({ store, journal, tools, signal: stop.signal, agentVersion: AGENT_VERSION2, guard, efficiencyLedger, monitor });
29719
+ monitor.setConnection("stopped");
29497
29720
  } finally {
29498
29721
  await efficiencyLedger.close();
29499
29722
  await journal.close();
29500
29723
  }
29724
+ } catch (error62) {
29725
+ monitor.setConnection("failed");
29726
+ throw error62;
29501
29727
  } finally {
29728
+ clearInterval(monitorTimer);
29729
+ await monitor.close().catch(() => {
29730
+ process.stderr.write("MONITOR_WRITE_FAILED\n");
29731
+ });
29502
29732
  await releaseProcess();
29503
29733
  }
29504
29734
  }
29505
- if (process.argv[1] && path12.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
29735
+ if (process.argv[1] && path14.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
29506
29736
  void main().catch((error62) => {
29507
29737
  const code = error62 instanceof Error && /^[A-Z0-9_]{1,64}$/.test(error62.message) ? error62.message : "AGENT_START_FAILED";
29508
29738
  process.stderr.write(code + "\n");