local-commander-agent 0.3.45 → 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/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/bin/posix.mjs +66 -66
- package/package.json +4 -4
- package/runtime/JobHost.exe +0 -0
- package/runtime/LocalCommanderAgent.exe +0 -0
- package/runtime/OwnerBridge.exe +0 -0
- package/runtime/agent.mjs +418 -236
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,
|
|
4545
|
-
if (!
|
|
4544
|
+
function getElementAtPath(obj, path30) {
|
|
4545
|
+
if (!path30)
|
|
4546
4546
|
return obj;
|
|
4547
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 }, [...
|
|
5344
|
+
issue2.errors.map((issues) => processError({ issues }, [...path30, ...issue2.path]));
|
|
5345
5345
|
} else if (issue2.code === "invalid_key") {
|
|
5346
|
-
processError({ issues: issue2.issues }, [...
|
|
5346
|
+
processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
|
|
5347
5347
|
} else if (issue2.code === "invalid_element") {
|
|
5348
|
-
processError({ issues: issue2.issues }, [...
|
|
5348
|
+
processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
|
|
5349
5349
|
} else {
|
|
5350
|
-
const fullpath = [...
|
|
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,
|
|
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 }, [...
|
|
5393
|
+
issue2.errors.map((issues) => processError({ issues }, [...path30, ...issue2.path]));
|
|
5394
5394
|
} else if (issue2.code === "invalid_key") {
|
|
5395
|
-
processError({ issues: issue2.issues }, [...
|
|
5395
|
+
processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
|
|
5396
5396
|
} else if (issue2.code === "invalid_element") {
|
|
5397
|
-
processError({ issues: issue2.issues }, [...
|
|
5397
|
+
processError({ issues: issue2.issues }, [...path30, ...issue2.path]);
|
|
5398
5398
|
} else {
|
|
5399
|
-
const fullpath = [...
|
|
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
|
|
5439
|
-
for (const seg of
|
|
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
|
|
22542
|
-
if (
|
|
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 (
|
|
22547
|
-
const key =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
23246
|
-
const newVal =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
23267
|
-
const newRight =
|
|
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 =
|
|
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 =
|
|
23284
|
-
const newOut =
|
|
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 =
|
|
23289
|
-
const newOutput =
|
|
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: () =>
|
|
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
|
|
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
|
|
25168
|
-
import
|
|
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";
|
|
@@ -25584,7 +25584,7 @@ async function acquirePosixJournalGuard(directory, helper) {
|
|
|
25584
25584
|
}
|
|
25585
25585
|
|
|
25586
25586
|
// agent/src/main.ts
|
|
25587
|
-
import { mkdir as mkdir14, open as open13, readFile as
|
|
25587
|
+
import { mkdir as mkdir14, open as open13, readFile as readFile12, realpath as realpath10, rm as rm10 } from "node:fs/promises";
|
|
25588
25588
|
import { fileURLToPath } from "node:url";
|
|
25589
25589
|
|
|
25590
25590
|
// packages/operations/src/crypto.ts
|
|
@@ -25721,13 +25721,13 @@ var exec2 = promisify2(execFile2);
|
|
|
25721
25721
|
async function darwinSupervisorLiveness(helper, pids, records = []) {
|
|
25722
25722
|
if (process.platform !== "darwin" || !process.getuid?.() || process.getuid() !== process.geteuid?.()) return null;
|
|
25723
25723
|
const remaining = new Set(pids), uid = process.getuid(), deadline = Date.now() + 1e4, env = buildChildEnvironment(process.env);
|
|
25724
|
-
const
|
|
25724
|
+
const run2 = (file2, args) => exec2(
|
|
25725
25725
|
file2,
|
|
25726
25726
|
args,
|
|
25727
25727
|
{ env, timeout: Math.max(1, Math.min(7e3, deadline - Date.now())), maxBuffer: 8192, encoding: "utf8", windowsHide: true }
|
|
25728
25728
|
);
|
|
25729
25729
|
try {
|
|
25730
|
-
const boot = (await
|
|
25730
|
+
const boot = (await run2("/usr/sbin/sysctl", ["-n", "kern.bootsessionuuid"])).stdout.trim();
|
|
25731
25731
|
if (!bootSession.test(boot)) return null;
|
|
25732
25732
|
for (const pid of remaining) {
|
|
25733
25733
|
if (Date.now() >= deadline) break;
|
|
@@ -25736,9 +25736,9 @@ async function darwinSupervisorLiveness(helper, pids, records = []) {
|
|
|
25736
25736
|
const proof2 = matches2[0].containment;
|
|
25737
25737
|
if (!validDarwinContainment(proof2) || proof2.uid !== uid || proof2.bootSession !== boot) continue;
|
|
25738
25738
|
try {
|
|
25739
|
-
await
|
|
25740
|
-
if ((await
|
|
25741
|
-
await
|
|
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(() => {
|
|
25742
25742
|
});
|
|
25743
25743
|
remaining.delete(pid);
|
|
25744
25744
|
} catch {
|
|
@@ -26445,10 +26445,12 @@ var ToolCallSchema = external_exports.discriminatedUnion("name", [
|
|
|
26445
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(),
|
|
26446
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(),
|
|
26447
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(),
|
|
26448
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()
|
|
26449
26451
|
]);
|
|
26450
26452
|
function scopeForTool(call) {
|
|
26451
|
-
if (call.name === "command_run") return "commands:execute";
|
|
26453
|
+
if (call.name === "command_run" || call.name === "take_screenshot") return "commands:execute";
|
|
26452
26454
|
if (call.name === "localhost_request") return "localhost:access";
|
|
26453
26455
|
return call.name === "fs_write" || call.name === "fs_replace" ? "files:write" : "files:read";
|
|
26454
26456
|
}
|
|
@@ -26552,6 +26554,7 @@ function guardAction(binding2, tool, config2, observedAt) {
|
|
|
26552
26554
|
throw Error("GUARD_IDENTITY_REQUIRED");
|
|
26553
26555
|
}
|
|
26554
26556
|
const name2 = tool.call.name;
|
|
26557
|
+
if (name2 === "take_screenshot") throw Error("GUARD_ACTION_UNSUPPORTED");
|
|
26555
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";
|
|
26556
26559
|
const resourceKind = kind === "execute" ? "workspace" : kind === "localhost-access" ? "localhost-service" : kind === "git-read" ? "git-repository" : name2 === "fs_read" || kind === "write" ? "file" : "workspace";
|
|
26557
26560
|
return { payloadHash: guardHash(tool.effective), request: BoundActionRequestSchema.parse({
|
|
@@ -27233,6 +27236,7 @@ import { constants as constants4 } from "node:fs";
|
|
|
27233
27236
|
|
|
27234
27237
|
// agent/src/posix-consent.ts
|
|
27235
27238
|
import { openSync, closeSync } from "node:fs";
|
|
27239
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
27236
27240
|
import { isatty, ReadStream, WriteStream } from "node:tty";
|
|
27237
27241
|
import { createInterface } from "node:readline/promises";
|
|
27238
27242
|
import path8 from "node:path";
|
|
@@ -27335,7 +27339,7 @@ async function planPermissionChange(current2, programs, input2) {
|
|
|
27335
27339
|
}
|
|
27336
27340
|
|
|
27337
27341
|
// agent/src/posix-consent.ts
|
|
27338
|
-
async function terminal2(
|
|
27342
|
+
async function terminal2(run2, timeoutMs2, signal) {
|
|
27339
27343
|
if (!process.getuid || process.getuid() === 0 || process.geteuid?.() !== process.getuid() || signal?.aborted) throw Error("OWNER_REVIEW_UNAVAILABLE");
|
|
27340
27344
|
let readFd;
|
|
27341
27345
|
try {
|
|
@@ -27371,7 +27375,7 @@ async function terminal2(run, timeoutMs2, signal) {
|
|
|
27371
27375
|
};
|
|
27372
27376
|
input2.on("data", bound);
|
|
27373
27377
|
try {
|
|
27374
|
-
return await
|
|
27378
|
+
return await run2(async (prompt) => {
|
|
27375
27379
|
if (stop.signal.aborted) throw Error("OWNER_REVIEW_CANCELLED");
|
|
27376
27380
|
return review.question(prompt, { signal: stop.signal });
|
|
27377
27381
|
});
|
|
@@ -27400,16 +27404,41 @@ async function choosePosixFolder() {
|
|
|
27400
27404
|
return await ask("Read/write folder: " + permissionLabel(folder) + "\nType APPROVE to accept: ") === "APPROVE" ? folder : null;
|
|
27401
27405
|
}, 12e4);
|
|
27402
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
|
+
}
|
|
27403
27432
|
async function choosePosixAccess() {
|
|
27433
|
+
if (process.platform === "darwin") {
|
|
27434
|
+
const chosen = macDialog();
|
|
27435
|
+
if (chosen !== void 0) return chosen;
|
|
27436
|
+
}
|
|
27404
27437
|
return terminal2(async (ask) => {
|
|
27405
|
-
|
|
27406
|
-
|
|
27407
|
-
if (
|
|
27408
|
-
|
|
27409
|
-
if (!path8.isAbsolute(folder) || folder.length > 4096 || /[\u0000-\u001f]/.test(folder)) throw Error("WORKSPACE_INVALID");
|
|
27410
|
-
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) + ".";
|
|
27411
|
-
if (await ask(summary + "\nThis replaces the previous folder/command/localhost selection and persists until revoked.\nType APPROVE to accept: ") !== "APPROVE") return null;
|
|
27412
|
-
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);
|
|
27413
27442
|
}, 24e4);
|
|
27414
27443
|
}
|
|
27415
27444
|
|
|
@@ -28877,8 +28906,8 @@ var HostMemory = class {
|
|
|
28877
28906
|
|
|
28878
28907
|
// agent/src/tools.ts
|
|
28879
28908
|
import { constants as constants7 } from "node:fs";
|
|
28880
|
-
import { lstat as lstat7, open as open6, readdir as readdir4, realpath as realpath7, rename as rename4, rm as
|
|
28881
|
-
import
|
|
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";
|
|
28882
28911
|
import { createHash as createHash14, randomUUID as randomUUID7 } from "node:crypto";
|
|
28883
28912
|
|
|
28884
28913
|
// src/guard.ts
|
|
@@ -29322,6 +29351,116 @@ async function runSupervised(helper, request, options = {}) {
|
|
|
29322
29351
|
});
|
|
29323
29352
|
}
|
|
29324
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
|
+
|
|
29325
29464
|
// agent/src/tools.ts
|
|
29326
29465
|
var NativeToolError = class extends Error {
|
|
29327
29466
|
constructor(code) {
|
|
@@ -29412,13 +29551,13 @@ var NativeTools = class {
|
|
|
29412
29551
|
constructor(options) {
|
|
29413
29552
|
this.options = options;
|
|
29414
29553
|
this.options = structuredClone(options);
|
|
29415
|
-
this.memory = new HostMemory(
|
|
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])));
|
|
29416
29555
|
}
|
|
29417
29556
|
options;
|
|
29418
29557
|
memory;
|
|
29419
29558
|
async readFile(file2, maxBytes, signal) {
|
|
29420
29559
|
try {
|
|
29421
|
-
return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ??
|
|
29560
|
+
return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
|
|
29422
29561
|
} catch (error62) {
|
|
29423
29562
|
if (error62.code === "ENOENT") throw error62;
|
|
29424
29563
|
if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail3(error62.message);
|
|
@@ -29428,31 +29567,31 @@ var NativeTools = class {
|
|
|
29428
29567
|
/** Windows only: up to 64 files of at most 1 MiB in one bridge process, each with its own result. */
|
|
29429
29568
|
async readFiles(files, maxTotalBytes, signal) {
|
|
29430
29569
|
try {
|
|
29431
|
-
return await readWindowsFiles(this.options.ownerBridgePath ??
|
|
29570
|
+
return await readWindowsFiles(this.options.ownerBridgePath ?? path18.join(path18.dirname(this.options.helperPath), "OwnerBridge.exe"), files, 1048576, maxTotalBytes, signal);
|
|
29432
29571
|
} catch (error62) {
|
|
29433
29572
|
if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail3(error62.message);
|
|
29434
29573
|
throw error62;
|
|
29435
29574
|
}
|
|
29436
29575
|
}
|
|
29437
|
-
async prepare(workspace2, candidate,
|
|
29576
|
+
async prepare(workspace2, candidate, selection2) {
|
|
29438
29577
|
let prepared;
|
|
29439
29578
|
try {
|
|
29440
29579
|
let projectRoot;
|
|
29441
|
-
if (
|
|
29442
|
-
const target = ProjectTargetBindingSchema.parse(
|
|
29580
|
+
if (selection2) {
|
|
29581
|
+
const target = ProjectTargetBindingSchema.parse(selection2);
|
|
29443
29582
|
if (workspace2.rootHash !== target.workspaceRootHash) fail3("PROJECT_IDENTITY_MISMATCH");
|
|
29444
29583
|
const identity = await this.prepareTool(workspace2, { name: "project_identity", args: { path: target.relativePath } });
|
|
29445
29584
|
const proof2 = JSON.parse((await identity.run(AbortSignal.timeout(15e3))).stdout);
|
|
29446
29585
|
if (!proof2.repositoryFingerprint) fail3("PROJECT_IDENTITY_UNKNOWN");
|
|
29447
29586
|
if (proof2.repositoryFingerprint !== target.repositoryFingerprint) fail3("PROJECT_IDENTITY_MISMATCH");
|
|
29448
|
-
projectRoot =
|
|
29587
|
+
projectRoot = path18.resolve(workspace2.root, target.relativePath);
|
|
29449
29588
|
const common = identity.claims.find((claim2) => claim2.namespace === "git")?.path;
|
|
29450
29589
|
if (common) workspace2 = { ...workspace2, gitCommonDir: common };
|
|
29451
29590
|
}
|
|
29452
29591
|
prepared = await this.prepareTool(workspace2, candidate, projectRoot);
|
|
29453
29592
|
} catch (error62) {
|
|
29454
29593
|
const parsed = ToolCallSchema.safeParse(candidate);
|
|
29455
|
-
if (parsed.success && parsed.data.name === "command_run") await this.memory.record({ ...parsed.data.args, cwd:
|
|
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(() => {
|
|
29456
29595
|
});
|
|
29457
29596
|
throw error62;
|
|
29458
29597
|
}
|
|
@@ -29472,17 +29611,17 @@ var NativeTools = class {
|
|
|
29472
29611
|
try {
|
|
29473
29612
|
const canonical2 = await realpath7(workspace2.root);
|
|
29474
29613
|
if (!equalPath3(canonical2, workspace2.root) || hash6(process.platform === "win32" ? canonical2.toLowerCase() : canonical2) !== workspace2.rootHash) fail3("WORKSPACE_CHANGED");
|
|
29475
|
-
const runtimeDirectory =
|
|
29614
|
+
const runtimeDirectory = path18.dirname(this.options.helperPath);
|
|
29476
29615
|
const protectedPaths = [
|
|
29477
29616
|
this.options.stateDirectory,
|
|
29478
29617
|
this.options.helperPath,
|
|
29479
|
-
...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe", "node", "owner-store", "posix-host", "job-host.mjs", "lifecycle.mjs", "manifest.json"].map((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))
|
|
29480
29619
|
];
|
|
29481
29620
|
if (this.options.ownerBridgePath) protectedPaths.push(this.options.ownerBridgePath);
|
|
29482
|
-
if (process.platform === "win32" && process.env.LOCALAPPDATA &&
|
|
29483
|
-
protectedPaths.push(
|
|
29621
|
+
if (process.platform === "win32" && process.env.LOCALAPPDATA && path18.isAbsolute(process.env.LOCALAPPDATA)) {
|
|
29622
|
+
protectedPaths.push(path18.join(process.env.LOCALAPPDATA, "LocalCommander"));
|
|
29484
29623
|
}
|
|
29485
|
-
if (process.platform !== "win32") protectedPaths.push(
|
|
29624
|
+
if (process.platform !== "win32") protectedPaths.push(path18.join(process.env.LC_AGENT_DATA_DIR || posixDataHome(), "LocalCommander"));
|
|
29486
29625
|
guard = await PathGuard.create([canonical2], false, { protectedPaths });
|
|
29487
29626
|
if (projectRoot) {
|
|
29488
29627
|
const selected = await guard.resolveDirectory(projectRoot);
|
|
@@ -29571,7 +29710,7 @@ var NativeTools = class {
|
|
|
29571
29710
|
}
|
|
29572
29711
|
if (taken === first - 1 && first <= end) fail3("OUTPUT_LIMIT_EXCEEDED");
|
|
29573
29712
|
const remaining = lines.length - (lines.length > 1 && lines.at(-1) === "" ? 1 : 0);
|
|
29574
|
-
return result({ path:
|
|
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 });
|
|
29575
29714
|
} };
|
|
29576
29715
|
}
|
|
29577
29716
|
if (call.name === "fs_write" || call.name === "fs_replace") {
|
|
@@ -29614,7 +29753,7 @@ var NativeTools = class {
|
|
|
29614
29753
|
bytes3 = encodeText(pieces.join(newText), original.encoding);
|
|
29615
29754
|
}
|
|
29616
29755
|
if (bytes3.length > MAX_FILE_WRITE_BYTES) fail3("FILE_WRITE_LIMIT");
|
|
29617
|
-
const temp =
|
|
29756
|
+
const temp = path18.join(path18.dirname(target), ".lc-write-" + randomUUID7() + ".tmp");
|
|
29618
29757
|
const handle = await open6(temp, constants7.O_CREAT | constants7.O_EXCL | constants7.O_WRONLY, 384);
|
|
29619
29758
|
try {
|
|
29620
29759
|
await handle.writeFile(bytes3);
|
|
@@ -29646,18 +29785,18 @@ var NativeTools = class {
|
|
|
29646
29785
|
}
|
|
29647
29786
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
29648
29787
|
try {
|
|
29649
|
-
await
|
|
29788
|
+
await rm6(temp);
|
|
29650
29789
|
break;
|
|
29651
29790
|
} catch {
|
|
29652
29791
|
await delay2(100);
|
|
29653
29792
|
}
|
|
29654
29793
|
}
|
|
29655
29794
|
}
|
|
29656
|
-
return result({ path:
|
|
29795
|
+
return result({ path: path18.relative(workspace2.root, target), bytes: bytes3.length, sha256: hash6(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
|
|
29657
29796
|
} catch (e) {
|
|
29658
29797
|
await handle.close().catch(() => {
|
|
29659
29798
|
});
|
|
29660
|
-
await
|
|
29799
|
+
await rm6(temp, { force: true }).catch(() => {
|
|
29661
29800
|
});
|
|
29662
29801
|
throw e;
|
|
29663
29802
|
}
|
|
@@ -29679,7 +29818,7 @@ var NativeTools = class {
|
|
|
29679
29818
|
const lines = decodeText(bytes3).text.split(/\r?\n/);
|
|
29680
29819
|
scanned++;
|
|
29681
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)) {
|
|
29682
|
-
const match = { path:
|
|
29821
|
+
const match = { path: path18.relative(workspace2.root, filename), line: i + 1, text: lines[i].slice(0, 500) };
|
|
29683
29822
|
if ((room -= Buffer.byteLength(JSON.stringify(match)) + 1) < 0) {
|
|
29684
29823
|
incomplete = true;
|
|
29685
29824
|
break;
|
|
@@ -29722,7 +29861,7 @@ var NativeTools = class {
|
|
|
29722
29861
|
continue;
|
|
29723
29862
|
}
|
|
29724
29863
|
try {
|
|
29725
|
-
const filename = await guard.resolveExisting(
|
|
29864
|
+
const filename = await guard.resolveExisting(path18.join(base, entry.path));
|
|
29726
29865
|
guard.assertSafeFile(filename);
|
|
29727
29866
|
if (!batched) {
|
|
29728
29867
|
searchFile(filename, await this.readFile(filename, 1048576, signal));
|
|
@@ -29746,6 +29885,30 @@ var NativeTools = class {
|
|
|
29746
29885
|
return result({ matches: matches2, scannedFiles: scanned, truncated: listing.truncated || incomplete || matches2.length >= call.args.maxResults || scanned >= 300 });
|
|
29747
29886
|
} };
|
|
29748
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
|
+
}
|
|
29749
29912
|
if (call.name === "localhost_request") {
|
|
29750
29913
|
const url2 = new URL(call.args.url), port = Number(url2.port || (url2.protocol === "https:" ? 443 : 80));
|
|
29751
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");
|
|
@@ -29816,9 +29979,9 @@ var NativeTools = class {
|
|
|
29816
29979
|
else if (call.name === "git_diff") {
|
|
29817
29980
|
argv = ["diff", "--no-ext-diff", "--no-textconv", ...call.args.staged ? ["--cached"] : []];
|
|
29818
29981
|
if (call.args.file) {
|
|
29819
|
-
const file2 = await resolve(
|
|
29820
|
-
const relative =
|
|
29821
|
-
if (relative.startsWith(".." +
|
|
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");
|
|
29822
29985
|
argv.push("--", relative);
|
|
29823
29986
|
} else argv.push("--stat");
|
|
29824
29987
|
} else fail3("TOOL_MISSING");
|
|
@@ -29829,7 +29992,7 @@ var NativeTools = class {
|
|
|
29829
29992
|
const listing = await this.list(guard, cwd, 1, call.args.startup ? 20 : 150, signal);
|
|
29830
29993
|
let packageInfo = null;
|
|
29831
29994
|
try {
|
|
29832
|
-
const name2 = await guard.resolveExisting(
|
|
29995
|
+
const name2 = await guard.resolveExisting(path18.join(cwd, "package.json"));
|
|
29833
29996
|
guard.assertSafeFile(name2);
|
|
29834
29997
|
const value = JSON.parse(utf8(await this.readFile(name2, 64e3, signal)));
|
|
29835
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) : [] };
|
|
@@ -29849,7 +30012,7 @@ var NativeTools = class {
|
|
|
29849
30012
|
}
|
|
29850
30013
|
const contextFile = async (relative, limit, optional2 = false) => {
|
|
29851
30014
|
try {
|
|
29852
|
-
const file2 = await guard.resolveExisting(
|
|
30015
|
+
const file2 = await guard.resolveExisting(path18.join(primary, relative));
|
|
29853
30016
|
guard.assertSafeFile(file2);
|
|
29854
30017
|
return utf8(await this.readFile(file2, limit, signal));
|
|
29855
30018
|
} catch (error62) {
|
|
@@ -29882,17 +30045,17 @@ var NativeTools = class {
|
|
|
29882
30045
|
} };
|
|
29883
30046
|
}
|
|
29884
30047
|
async resolveProgram(name2, workspace2, args) {
|
|
29885
|
-
const entry = Object.entries(this.options.programs).find(([key, value]) => equalPath3(key, name2) ||
|
|
30048
|
+
const entry = Object.entries(this.options.programs).find(([key, value]) => equalPath3(key, name2) || path18.isAbsolute(name2) && equalPath3(value.executable, path18.resolve(name2)));
|
|
29886
30049
|
if (workspace2.fullAccess) {
|
|
29887
|
-
const commandKey = (value) => process.platform === "win32" ?
|
|
30050
|
+
const commandKey = (value) => process.platform === "win32" ? path18.basename(value).toLowerCase().replace(/\.(exe|com|cmd|bat)$/i, "") : path18.basename(value);
|
|
29888
30051
|
const denied = new Set((workspace2.deniedCommands ?? []).map(commandKey));
|
|
29889
30052
|
if (denied.has(commandKey(name2)) || entry && denied.has(commandKey(entry[0]))) fail3("COMMAND_NOT_ALLOWED");
|
|
29890
|
-
const extension2 =
|
|
29891
|
-
const candidate = entry?.[1].executable ?? (process.platform !== "win32" ? await resolvePosixExecutable(name2) :
|
|
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(
|
|
29892
30055
|
commandKey(name2),
|
|
29893
30056
|
[".exe", ".com", ".cmd", ".bat"].includes(extension2) ? { ...process.env, PATHEXT: extension2 } : process.env
|
|
29894
30057
|
)?.file : void 0);
|
|
29895
|
-
if (!candidate || !
|
|
30058
|
+
if (!candidate || !path18.isAbsolute(candidate)) fail3("COMMAND_NOT_FOUND");
|
|
29896
30059
|
const executable = await realpath7(candidate).catch(() => fail3("COMMAND_NOT_FOUND"));
|
|
29897
30060
|
if (!(await lstat7(executable)).isFile()) fail3("COMMAND_NOT_FOUND");
|
|
29898
30061
|
if (denied.has(commandKey(executable))) fail3("COMMAND_NOT_ALLOWED");
|
|
@@ -29907,7 +30070,7 @@ var NativeTools = class {
|
|
|
29907
30070
|
if (/\.(cmd|bat)$/i.test(executable)) {
|
|
29908
30071
|
if ([executable, ...args].some((value) => /[&|<>^%!"\r\n]/.test(value))) fail3("INVALID_SCRIPT_ARGUMENTS");
|
|
29909
30072
|
const literal2 = (value) => "'" + value.replaceAll("'", "''") + "'";
|
|
29910
|
-
const shell =
|
|
30073
|
+
const shell = path18.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
29911
30074
|
if (denied.has("powershell") || denied.has("cmd")) fail3("COMMAND_NOT_ALLOWED");
|
|
29912
30075
|
const script = "& " + literal2(executable) + " @(" + args.map(literal2).join(",") + "); exit $LASTEXITCODE";
|
|
29913
30076
|
return { executable: shell, args: ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")] };
|
|
@@ -29915,7 +30078,7 @@ var NativeTools = class {
|
|
|
29915
30078
|
if (!/\.(exe|com)$/i.test(executable)) fail3("COMMAND_NOT_ALLOWED");
|
|
29916
30079
|
return { executable, args: [...entry?.[1].prefixArgs ?? [], ...args] };
|
|
29917
30080
|
}
|
|
29918
|
-
if (!entry || !workspace2.allowedCommands.some((v) => equalPath3(v, entry[0])) || !
|
|
30081
|
+
if (!entry || !workspace2.allowedCommands.some((v) => equalPath3(v, entry[0])) || !path18.isAbsolute(entry[1].executable)) fail3("COMMAND_NOT_ALLOWED");
|
|
29919
30082
|
return { executable: entry[1].executable, args: [...entry[1].prefixArgs ?? [], ...args] };
|
|
29920
30083
|
}
|
|
29921
30084
|
async memoryContext(workspace2) {
|
|
@@ -29930,9 +30093,9 @@ var NativeTools = class {
|
|
|
29930
30093
|
async gitExecution(cwd, args) {
|
|
29931
30094
|
if (!["win32", "linux", "darwin"].includes(process.platform)) fail3("COMMAND_NOT_ALLOWED");
|
|
29932
30095
|
const configured = this.options.programs.git;
|
|
29933
|
-
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 &&
|
|
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"];
|
|
29934
30097
|
for (const source of candidates) {
|
|
29935
|
-
if (!
|
|
30098
|
+
if (!path18.isAbsolute(source)) continue;
|
|
29936
30099
|
const candidate = process.platform === "win32" ? source : await resolvePosixExecutable(source);
|
|
29937
30100
|
if (!candidate) continue;
|
|
29938
30101
|
try {
|
|
@@ -29966,7 +30129,7 @@ var NativeTools = class {
|
|
|
29966
30129
|
break;
|
|
29967
30130
|
}
|
|
29968
30131
|
if (item.isSymbolicLink() || excluded.has(item.name.toLowerCase())) continue;
|
|
29969
|
-
const candidate =
|
|
30132
|
+
const candidate = path18.join(current2.path, item.name);
|
|
29970
30133
|
let resolved;
|
|
29971
30134
|
try {
|
|
29972
30135
|
resolved = await guard.resolveExisting(candidate);
|
|
@@ -29976,11 +30139,11 @@ var NativeTools = class {
|
|
|
29976
30139
|
}
|
|
29977
30140
|
if (!equalPath3(candidate, resolved)) continue;
|
|
29978
30141
|
if (item.isDirectory()) {
|
|
29979
|
-
entries.push({ path:
|
|
30142
|
+
entries.push({ path: path18.relative(root, resolved), type: "directory" });
|
|
29980
30143
|
if (current2.level < depth) queue.push({ path: resolved, level: current2.level + 1 });
|
|
29981
30144
|
} else if (item.isFile()) {
|
|
29982
30145
|
const stat2 = await lstat7(resolved).catch(() => null);
|
|
29983
|
-
if (stat2) entries.push({ path:
|
|
30146
|
+
if (stat2) entries.push({ path: path18.relative(root, resolved), type: "file", size: stat2.size });
|
|
29984
30147
|
}
|
|
29985
30148
|
}
|
|
29986
30149
|
if (truncated) break;
|
|
@@ -29990,7 +30153,7 @@ var NativeTools = class {
|
|
|
29990
30153
|
async gitCommonDir(cwd, workspace2, guard) {
|
|
29991
30154
|
let directory = cwd;
|
|
29992
30155
|
while (guard.isWithin(directory, workspace2.root)) {
|
|
29993
|
-
const dotGit =
|
|
30156
|
+
const dotGit = path18.join(directory, ".git");
|
|
29994
30157
|
try {
|
|
29995
30158
|
const stat2 = await lstat7(dotGit);
|
|
29996
30159
|
if (stat2.isSymbolicLink()) fail3("GIT_METADATA_CHANGED");
|
|
@@ -29999,14 +30162,14 @@ var NativeTools = class {
|
|
|
29999
30162
|
else {
|
|
30000
30163
|
const content = utf8(await this.readFile(dotGit, 4096)).trim();
|
|
30001
30164
|
if (!content.startsWith("gitdir: ")) fail3("GIT_METADATA_CHANGED");
|
|
30002
|
-
gitDir = await realpath7(
|
|
30165
|
+
gitDir = await realpath7(path18.resolve(directory, content.slice(8)));
|
|
30003
30166
|
}
|
|
30004
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");
|
|
30005
30168
|
let common = gitDir;
|
|
30006
30169
|
try {
|
|
30007
|
-
const content = utf8(await this.readFile(
|
|
30170
|
+
const content = utf8(await this.readFile(path18.join(gitDir, "commondir"), 4096)).trim();
|
|
30008
30171
|
if (!content) fail3("GIT_METADATA_CHANGED");
|
|
30009
|
-
common = await realpath7(
|
|
30172
|
+
common = await realpath7(path18.resolve(gitDir, content));
|
|
30010
30173
|
} catch (e) {
|
|
30011
30174
|
if (e.code !== "ENOENT") throw e;
|
|
30012
30175
|
}
|
|
@@ -30017,22 +30180,22 @@ var NativeTools = class {
|
|
|
30017
30180
|
if (e.code !== "ENOENT") throw e;
|
|
30018
30181
|
}
|
|
30019
30182
|
if (equalPath3(directory, workspace2.root)) break;
|
|
30020
|
-
directory =
|
|
30183
|
+
directory = path18.dirname(directory);
|
|
30021
30184
|
}
|
|
30022
30185
|
return null;
|
|
30023
30186
|
}
|
|
30024
30187
|
};
|
|
30025
30188
|
|
|
30026
30189
|
// agent/src/scheduler.ts
|
|
30027
|
-
import
|
|
30028
|
-
import
|
|
30190
|
+
import path19 from "node:path";
|
|
30191
|
+
import os5 from "node:os";
|
|
30029
30192
|
function canonical(value) {
|
|
30030
|
-
const p =
|
|
30193
|
+
const p = path19.resolve(value);
|
|
30031
30194
|
return process.platform === "win32" ? p.toLowerCase() : p;
|
|
30032
30195
|
}
|
|
30033
30196
|
function ancestor(a, b) {
|
|
30034
|
-
const relative =
|
|
30035
|
-
return relative === "" || !
|
|
30197
|
+
const relative = path19.relative(a, b);
|
|
30198
|
+
return relative === "" || !path19.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path19.sep);
|
|
30036
30199
|
}
|
|
30037
30200
|
function claimsConflict(a, b) {
|
|
30038
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))));
|
|
@@ -30040,7 +30203,7 @@ function claimsConflict(a, b) {
|
|
|
30040
30203
|
var NativeScheduler = class {
|
|
30041
30204
|
constructor(options = {}) {
|
|
30042
30205
|
this.options = options;
|
|
30043
|
-
const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2,
|
|
30206
|
+
const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2, os5.availableParallelism?.() ?? os5.cpus().length) / 2)));
|
|
30044
30207
|
this.safeSlots = options.safeSlots ?? capacity;
|
|
30045
30208
|
this.maxQueued = options.maxQueued ?? 32;
|
|
30046
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");
|
|
@@ -30058,16 +30221,16 @@ var NativeScheduler = class {
|
|
|
30058
30221
|
} catch {
|
|
30059
30222
|
}
|
|
30060
30223
|
}
|
|
30061
|
-
schedule(id2, claims, deadlineAt,
|
|
30224
|
+
schedule(id2, claims, deadlineAt, run2, signal) {
|
|
30062
30225
|
if (!this.accepting) return Promise.reject(Error("AGENT_PAUSED"));
|
|
30063
30226
|
if (!id2 || id2.length > 100 || this.active.has(id2) || this.waiting.some((j) => j.id === id2)) return Promise.reject(Error("DUPLICATE_SCHEDULED_EXECUTION"));
|
|
30064
|
-
if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !
|
|
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"));
|
|
30065
30228
|
const deadline = deadlineAt.getTime();
|
|
30066
30229
|
if (!Number.isFinite(deadline) || deadline <= Date.now()) return Promise.reject(Error("ADMISSION_DEADLINE_EXPIRED"));
|
|
30067
30230
|
if (signal?.aborted) return Promise.reject(Error("CANCELLED_BEFORE_ACCEPTANCE"));
|
|
30068
30231
|
if (this.waiting.length >= this.maxQueued) return Promise.reject(Error("RESOURCE_BUSY"));
|
|
30069
30232
|
return new Promise((resolve, reject) => {
|
|
30070
|
-
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 };
|
|
30071
30234
|
const remove = (reason) => {
|
|
30072
30235
|
const index = this.waiting.indexOf(job);
|
|
30073
30236
|
if (index < 0) return;
|
|
@@ -30777,6 +30940,14 @@ function resultOutcome(result2) {
|
|
|
30777
30940
|
if (!result2.treeTerminated || result2.exitCode === null) return "unknown";
|
|
30778
30941
|
return result2.exitCode === 0 ? "success" : "failed";
|
|
30779
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
|
+
}
|
|
30780
30951
|
async function outboundResult(call, result2, binding2, optional2, ledger) {
|
|
30781
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) };
|
|
30782
30953
|
if (ledger) {
|
|
@@ -30829,7 +31000,7 @@ var NativeRuntime = class {
|
|
|
30829
31000
|
}
|
|
30830
31001
|
if (frame.type === "result" && this.options.contentAudit) {
|
|
30831
31002
|
const call = this.contexts.get(frame.binding.executionId)?.tool.call;
|
|
30832
|
-
if (call) try {
|
|
31003
|
+
if (call && call.name !== "take_screenshot") try {
|
|
30833
31004
|
this.options.contentAudit.record(frame.binding, call, frame.result);
|
|
30834
31005
|
} catch {
|
|
30835
31006
|
}
|
|
@@ -30966,8 +31137,10 @@ var NativeRuntime = class {
|
|
|
30966
31137
|
const checked = ResultSchema.parse(output2);
|
|
30967
31138
|
const { resultCode, ...journalOutput } = checked;
|
|
30968
31139
|
if (context.guardPermit) await this.options.guard.result(context.guardPermit, checked);
|
|
30969
|
-
const
|
|
30970
|
-
this.
|
|
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 } });
|
|
30971
31144
|
}, abort.signal);
|
|
30972
31145
|
context.task = work.catch(async (error62) => {
|
|
30973
31146
|
if (!context.accepted) {
|
|
@@ -31190,9 +31363,9 @@ var NativeRelayBridge = class {
|
|
|
31190
31363
|
|
|
31191
31364
|
// agent/src/local-direct.ts
|
|
31192
31365
|
import net from "node:net";
|
|
31193
|
-
import
|
|
31366
|
+
import path20 from "node:path";
|
|
31194
31367
|
import { createHmac as createHmac2, hkdfSync, randomBytes as randomBytes6, randomUUID as randomUUID8, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
|
|
31195
|
-
import { mkdir as mkdir7, readFile as
|
|
31368
|
+
import { mkdir as mkdir7, readFile as readFile8, rename as rename5, rm as rm7, writeFile as writeFile3 } from "node:fs/promises";
|
|
31196
31369
|
var LocalDirectError = class extends Error {
|
|
31197
31370
|
constructor(code) {
|
|
31198
31371
|
super(code);
|
|
@@ -31210,11 +31383,11 @@ var ADMISSION_MS = 6e4;
|
|
|
31210
31383
|
var MAX_IN_FLIGHT = 16;
|
|
31211
31384
|
var MAX_CONNECTIONS = 32;
|
|
31212
31385
|
function localDirectDirectory(appData) {
|
|
31213
|
-
return
|
|
31386
|
+
return path20.join(appData, "LocalCommander", "LocalMcp");
|
|
31214
31387
|
}
|
|
31215
31388
|
async function localDirectEnabled(directory) {
|
|
31216
31389
|
try {
|
|
31217
|
-
return JSON.parse(await
|
|
31390
|
+
return JSON.parse(await readFile8(path20.join(directory, "settings.json"), "utf8"))?.enabled === true;
|
|
31218
31391
|
} catch {
|
|
31219
31392
|
return false;
|
|
31220
31393
|
}
|
|
@@ -31287,7 +31460,7 @@ var Lines = class {
|
|
|
31287
31460
|
async function readEndpoint(directory) {
|
|
31288
31461
|
let value;
|
|
31289
31462
|
try {
|
|
31290
|
-
value = JSON.parse(await
|
|
31463
|
+
value = JSON.parse(await readFile8(path20.join(directory, "endpoint.json"), "utf8"));
|
|
31291
31464
|
} catch {
|
|
31292
31465
|
fail4("LOCAL_AGENT_NOT_RUNNING");
|
|
31293
31466
|
}
|
|
@@ -31304,9 +31477,9 @@ var LocalDirectServer = class _LocalDirectServer {
|
|
|
31304
31477
|
sockets = /* @__PURE__ */ new Set();
|
|
31305
31478
|
/** Listens only while the owner has enabled direct local access; null otherwise. */
|
|
31306
31479
|
static async start(options) {
|
|
31307
|
-
const endpointFile =
|
|
31480
|
+
const endpointFile = path20.join(options.directory, "endpoint.json");
|
|
31308
31481
|
if (!await localDirectEnabled(options.directory)) {
|
|
31309
|
-
await
|
|
31482
|
+
await rm7(endpointFile, { force: true }).catch(() => {
|
|
31310
31483
|
});
|
|
31311
31484
|
return null;
|
|
31312
31485
|
}
|
|
@@ -31332,7 +31505,7 @@ var LocalDirectServer = class _LocalDirectServer {
|
|
|
31332
31505
|
for (const socket of this.sockets) socket.destroy();
|
|
31333
31506
|
await new Promise((resolve) => this.server.close(() => resolve()));
|
|
31334
31507
|
try {
|
|
31335
|
-
if ((await readEndpoint(this.options.directory)).pid === process.pid) await
|
|
31508
|
+
if ((await readEndpoint(this.options.directory)).pid === process.pid) await rm7(path20.join(this.options.directory, "endpoint.json"), { force: true });
|
|
31336
31509
|
} catch {
|
|
31337
31510
|
}
|
|
31338
31511
|
}
|
|
@@ -35187,9 +35360,9 @@ var rev2026Codec = {
|
|
|
35187
35360
|
});
|
|
35188
35361
|
const parsed = buildSchemas2026().RequestMetaEnvelopeSchema.safeParse(meta3);
|
|
35189
35362
|
if (!parsed.success) for (const issue2 of parsed.error.issues) {
|
|
35190
|
-
const
|
|
35191
|
-
const key =
|
|
35192
|
-
if (
|
|
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;
|
|
35193
35366
|
issues.push({
|
|
35194
35367
|
key,
|
|
35195
35368
|
problem: issue2.message
|
|
@@ -35491,29 +35664,29 @@ var PERMITTED_X_MCP_HEADER_TYPES = /* @__PURE__ */ new Set([
|
|
|
35491
35664
|
function scanXMcpHeaderDeclarations(inputSchema) {
|
|
35492
35665
|
const declarations = [];
|
|
35493
35666
|
const seenLower = /* @__PURE__ */ new Map();
|
|
35494
|
-
const visit2 = (node2,
|
|
35667
|
+
const visit2 = (node2, path30, reachable) => {
|
|
35495
35668
|
if (node2 === null || typeof node2 !== "object") return void 0;
|
|
35496
35669
|
const schema = node2;
|
|
35497
35670
|
if (X_MCP_HEADER_KEY in schema) {
|
|
35498
|
-
if (!reachable ||
|
|
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)`;
|
|
35499
35672
|
const raw = schema[X_MCP_HEADER_KEY];
|
|
35500
|
-
if (typeof raw !== "string" || raw.length === 0) return `${pathName(
|
|
35501
|
-
if (!RFC9110_TOKEN.test(raw)) return `${pathName(
|
|
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)`;
|
|
35502
35675
|
const type = typeof schema.type === "string" ? schema.type : void 0;
|
|
35503
|
-
if (type === void 0 || !PERMITTED_X_MCP_HEADER_TYPES.has(type)) return `${pathName(
|
|
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>"}`;
|
|
35504
35677
|
const lower = raw.toLowerCase();
|
|
35505
35678
|
const prior = seenLower.get(lower);
|
|
35506
35679
|
if (prior !== void 0) return `x-mcp-header '${raw}' is not case-insensitively unique (also declared as '${prior}')`;
|
|
35507
35680
|
seenLower.set(lower, raw);
|
|
35508
35681
|
declarations.push({
|
|
35509
|
-
path:
|
|
35682
|
+
path: path30,
|
|
35510
35683
|
headerName: raw,
|
|
35511
35684
|
type
|
|
35512
35685
|
});
|
|
35513
35686
|
}
|
|
35514
35687
|
const properties = schema.properties;
|
|
35515
35688
|
if (properties !== null && typeof properties === "object") for (const [key, child] of Object.entries(properties)) {
|
|
35516
|
-
const fault$1 = visit2(child, [...
|
|
35689
|
+
const fault$1 = visit2(child, [...path30, key], reachable);
|
|
35517
35690
|
if (fault$1 !== void 0) return fault$1;
|
|
35518
35691
|
}
|
|
35519
35692
|
for (const k of NON_REACHABLE_SUBSCHEMA_KEYWORDS) {
|
|
@@ -35521,7 +35694,7 @@ function scanXMcpHeaderDeclarations(inputSchema) {
|
|
|
35521
35694
|
if (sub === void 0) continue;
|
|
35522
35695
|
const branches = Array.isArray(sub) ? sub : sub !== null && typeof sub === "object" && OBJECT_VALUED_SUBSCHEMA_KEYWORDS.has(k) ? Object.values(sub) : [sub];
|
|
35523
35696
|
for (const branch of branches) {
|
|
35524
|
-
const fault$1 = visit2(branch, [...
|
|
35697
|
+
const fault$1 = visit2(branch, [...path30, `<${k}>`], false);
|
|
35525
35698
|
if (fault$1 !== void 0) return fault$1;
|
|
35526
35699
|
}
|
|
35527
35700
|
}
|
|
@@ -35561,8 +35734,8 @@ var OBJECT_VALUED_SUBSCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
35561
35734
|
"$defs",
|
|
35562
35735
|
"definitions"
|
|
35563
35736
|
]);
|
|
35564
|
-
function pathName(
|
|
35565
|
-
return
|
|
35737
|
+
function pathName(path30) {
|
|
35738
|
+
return path30.length === 0 ? "<root>" : path30.join(".");
|
|
35566
35739
|
}
|
|
35567
35740
|
var HEADER_MISMATCH_ERROR_CODE = -32020;
|
|
35568
35741
|
var INBOUND_VALIDATION_LADDER = [
|
|
@@ -35812,7 +35985,7 @@ var PROPERTY_KEYS_BY_TYPE = {
|
|
|
35812
35985
|
array: shapeKeys([UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema])
|
|
35813
35986
|
};
|
|
35814
35987
|
var SUPPORTED_STRING_FORMATS = new Set(StringSchemaSchema.shape.format.unwrap().options);
|
|
35815
|
-
function walkProperty(node2,
|
|
35988
|
+
function walkProperty(node2, path30, vendor, unsupported) {
|
|
35816
35989
|
if (!isJsonObject(node2)) return node2;
|
|
35817
35990
|
const allowedKeys = typeof node2.type === "string" && Object.hasOwn(PROPERTY_KEYS_BY_TYPE, node2.type) ? PROPERTY_KEYS_BY_TYPE[node2.type] : void 0;
|
|
35818
35991
|
if (allowedKeys === void 0) return node2;
|
|
@@ -35820,8 +35993,8 @@ function walkProperty(node2, path29, vendor, unsupported) {
|
|
|
35820
35993
|
for (const [key, value] of Object.entries(node2)) if (allowedKeys.has(key) || isAnnotationOnlyJsonSchemaKeyword(key)) pruned[key] = value;
|
|
35821
35994
|
else if (key === "pattern" && node2.type === "string" && typeof node2.format === "string") {
|
|
35822
35995
|
if (!SUPPORTED_STRING_FORMATS.has(node2.format)) pruned[key] = value;
|
|
35823
|
-
else if (typeof value !== "string" || !isLibraryFormatPattern(node2.format, value, vendor)) unsupported.push(`${
|
|
35824
|
-
} else unsupported.push(`${
|
|
35996
|
+
else if (typeof value !== "string" || !isLibraryFormatPattern(node2.format, value, vendor)) unsupported.push(`${path30}.${key}`);
|
|
35997
|
+
} else unsupported.push(`${path30}.${key}`);
|
|
35825
35998
|
return pruned;
|
|
35826
35999
|
}
|
|
35827
36000
|
function walkRequestedSchema(converted, vendor) {
|
|
@@ -35838,11 +36011,11 @@ function describeUnsupportedProperties(pruned, fallback) {
|
|
|
35838
36011
|
const offenders = Object.entries(pruned.properties).filter(([, node2]) => !parseSchema(PrimitiveSchemaDefinitionSchema, node2).success).map(([name2]) => `properties.${name2}`);
|
|
35839
36012
|
return offenders.length > 0 ? offenders.join(", ") : fallback;
|
|
35840
36013
|
}
|
|
35841
|
-
function findDroppedConstraintPaths(original, parsed,
|
|
35842
|
-
if (Array.isArray(original) && Array.isArray(parsed)) return original.flatMap((item, index) => findDroppedConstraintPaths(item, parsed[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}]`));
|
|
35843
36016
|
if (!isJsonObject(original) || !isJsonObject(parsed)) return [];
|
|
35844
36017
|
return Object.entries(original).flatMap(([key, value]) => {
|
|
35845
|
-
const childPath =
|
|
36018
|
+
const childPath = path30 ? `${path30}.${key}` : key;
|
|
35846
36019
|
if (!Object.prototype.hasOwnProperty.call(parsed, key)) return isAnnotationOnlyJsonSchemaKeyword(key) ? [] : [childPath];
|
|
35847
36020
|
return findDroppedConstraintPaths(value, parsed[key], childPath);
|
|
35848
36021
|
});
|
|
@@ -39918,8 +40091,8 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
39918
40091
|
for (let i = 0; i < str.length; i++) if (str[i] === token) ind++;
|
|
39919
40092
|
return ind;
|
|
39920
40093
|
}
|
|
39921
|
-
function removeDotSegments(
|
|
39922
|
-
let input2 =
|
|
40094
|
+
function removeDotSegments(path30) {
|
|
40095
|
+
let input2 = path30;
|
|
39923
40096
|
const output2 = [];
|
|
39924
40097
|
let nextSlash = -1;
|
|
39925
40098
|
let len = 0;
|
|
@@ -40072,8 +40245,8 @@ var require_schemes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
40072
40245
|
wsComponent.secure = void 0;
|
|
40073
40246
|
}
|
|
40074
40247
|
if (wsComponent.resourceName) {
|
|
40075
|
-
const [
|
|
40076
|
-
wsComponent.path =
|
|
40248
|
+
const [path30, query] = wsComponent.resourceName.split("?");
|
|
40249
|
+
wsComponent.path = path30 && path30 !== "/" ? path30 : void 0;
|
|
40077
40250
|
wsComponent.query = query;
|
|
40078
40251
|
wsComponent.resourceName = void 0;
|
|
40079
40252
|
}
|
|
@@ -45640,7 +45813,8 @@ var DESCRIPTIONS = {
|
|
|
45640
45813
|
git_diff: ["Git diff of the repository at a workspace-relative path.", { readOnlyHint: true, openWorldHint: false }],
|
|
45641
45814
|
git_log: ["Recent Git commits of the repository at a workspace-relative path.", { readOnlyHint: true, openWorldHint: false }],
|
|
45642
45815
|
project_snapshot: ["Compact project overview: Git state and, with startup, AGENTS.md policy and task continuation.", { readOnlyHint: true, openWorldHint: false }],
|
|
45643
|
-
command_run: ["Run one executable with an argument array (no shell parsing), hidden, with captured output. Uses this
|
|
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 }],
|
|
45644
45818
|
localhost_request: ["HTTP request to a service on this computer (localhost only).", { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }]
|
|
45645
45819
|
};
|
|
45646
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.");
|
|
@@ -45653,6 +45827,14 @@ function failure4(error62) {
|
|
|
45653
45827
|
return text2(code + hint, true);
|
|
45654
45828
|
}
|
|
45655
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
|
+
}
|
|
45656
45838
|
if (name2 !== "command_run" && result2.resultCode === "SUCCESS") return text2(result2.stdout);
|
|
45657
45839
|
const { exitCode, resultCode, timedOut, cancelled, stdout, stderr, stdoutTruncated, stderrTruncated } = result2;
|
|
45658
45840
|
return text2(
|
|
@@ -45673,7 +45855,7 @@ async function serveLocalMcp(options) {
|
|
|
45673
45855
|
return connecting;
|
|
45674
45856
|
};
|
|
45675
45857
|
const server = new McpServer({ name: "local-commander-local", version: options.agentVersion }, {
|
|
45676
|
-
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
|
|
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."
|
|
45677
45859
|
});
|
|
45678
45860
|
server.registerTool(
|
|
45679
45861
|
"workspace_list",
|
|
@@ -45688,7 +45870,7 @@ async function serveLocalMcp(options) {
|
|
|
45688
45870
|
);
|
|
45689
45871
|
for (const option of ToolCallSchema.options) {
|
|
45690
45872
|
const name2 = option.shape.name.value, entry = DESCRIPTIONS[name2];
|
|
45691
|
-
if (!entry) continue;
|
|
45873
|
+
if (!entry || name2 === "take_screenshot" && !screenshotEnabled()) continue;
|
|
45692
45874
|
const inputSchema = option.shape.args.extend({ workspace });
|
|
45693
45875
|
const callback = async (input2, ctx) => {
|
|
45694
45876
|
const { workspace: selected, ...args } = input2;
|
|
@@ -46427,10 +46609,10 @@ async function connectOnce(options) {
|
|
|
46427
46609
|
// agent/src/machine-identity.ts
|
|
46428
46610
|
import { spawn as spawn5 } from "node:child_process";
|
|
46429
46611
|
import { createHash as createHash16 } from "node:crypto";
|
|
46430
|
-
import
|
|
46612
|
+
import os6 from "node:os";
|
|
46431
46613
|
import { open as open7 } from "node:fs/promises";
|
|
46432
46614
|
import { constants as constants8 } from "node:fs";
|
|
46433
|
-
import
|
|
46615
|
+
import path21 from "node:path";
|
|
46434
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;
|
|
46435
46617
|
async function readMachineGuid(timeoutMs2 = 5e3) {
|
|
46436
46618
|
if (process.platform === "linux") {
|
|
@@ -46451,7 +46633,7 @@ async function readMachineGuid(timeoutMs2 = 5e3) {
|
|
|
46451
46633
|
}
|
|
46452
46634
|
}
|
|
46453
46635
|
if (!["win32", "darwin"].includes(process.platform)) return null;
|
|
46454
|
-
const reg = process.platform === "darwin" ? "/usr/sbin/ioreg" :
|
|
46636
|
+
const reg = process.platform === "darwin" ? "/usr/sbin/ioreg" : path21.join(process.env.SystemRoot || "C:\\Windows", "System32", "reg.exe");
|
|
46455
46637
|
const args = process.platform === "darwin" ? ["-rd1", "-c", "IOPlatformExpertDevice"] : ["query", "HKLM\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid", "/reg:64"];
|
|
46456
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;
|
|
46457
46639
|
return new Promise((resolve) => {
|
|
@@ -46523,9 +46705,9 @@ async function readComputerName(timeoutMs2 = 5e3) {
|
|
|
46523
46705
|
});
|
|
46524
46706
|
if (valid(name2)) return name2;
|
|
46525
46707
|
}
|
|
46526
|
-
return
|
|
46708
|
+
return os6.hostname();
|
|
46527
46709
|
}
|
|
46528
|
-
function machineProof(deviceId, machineGuid, computerName =
|
|
46710
|
+
function machineProof(deviceId, machineGuid, computerName = os6.hostname()) {
|
|
46529
46711
|
const name2 = computerName.slice(0, 120);
|
|
46530
46712
|
if (!name2 || name2.trim() !== name2 || /[\u0000-\u001f\u007f]/.test(name2)) return null;
|
|
46531
46713
|
const fingerprint3 = createHash16("sha256").update("lcmcp-machine-v1\0" + deviceId.toLowerCase() + "\0" + machineGuid.toLowerCase() + "\0" + name2.toUpperCase(), "utf8").digest("hex");
|
|
@@ -46566,8 +46748,8 @@ function canonicalOrigin2(value) {
|
|
|
46566
46748
|
fail6("ORIGIN_INVALID");
|
|
46567
46749
|
}
|
|
46568
46750
|
}
|
|
46569
|
-
function endpoint(origin,
|
|
46570
|
-
return origin +
|
|
46751
|
+
function endpoint(origin, path30) {
|
|
46752
|
+
return origin + path30;
|
|
46571
46753
|
}
|
|
46572
46754
|
function uuid21(value, code) {
|
|
46573
46755
|
if (typeof value !== "string" || !UUID3.test(value)) fail6(code);
|
|
@@ -47069,15 +47251,15 @@ async function deliverGuardEvidence(target, packet, options = {}) {
|
|
|
47069
47251
|
|
|
47070
47252
|
// agent/src/optimization-ledger.ts
|
|
47071
47253
|
import { constants as constants9 } from "node:fs";
|
|
47072
|
-
import { lstat as lstat8, mkdir as mkdir8, open as open8, readFile as
|
|
47073
|
-
import
|
|
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";
|
|
47074
47256
|
var MAX_LEDGER_BYTES = 64 * 1024 * 1024;
|
|
47075
47257
|
var MAX_NOTICE_LEDGER_BYTES = 8 * 1024 * 1024;
|
|
47076
47258
|
function failure5(code) {
|
|
47077
47259
|
return Object.assign(new Error(code), { code });
|
|
47078
47260
|
}
|
|
47079
47261
|
async function safeDirectory2(directory) {
|
|
47080
|
-
const absolute2 =
|
|
47262
|
+
const absolute2 = path22.resolve(directory);
|
|
47081
47263
|
let current2 = absolute2;
|
|
47082
47264
|
for (; ; ) {
|
|
47083
47265
|
try {
|
|
@@ -47085,7 +47267,7 @@ async function safeDirectory2(directory) {
|
|
|
47085
47267
|
} catch (error62) {
|
|
47086
47268
|
if (error62.code !== "ENOENT") throw error62;
|
|
47087
47269
|
}
|
|
47088
|
-
const parent =
|
|
47270
|
+
const parent = path22.dirname(current2);
|
|
47089
47271
|
if (parent === current2) break;
|
|
47090
47272
|
current2 = parent;
|
|
47091
47273
|
}
|
|
@@ -47120,15 +47302,15 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
47120
47302
|
closed = false;
|
|
47121
47303
|
static async open(directory) {
|
|
47122
47304
|
const dir = await safeDirectory2(directory);
|
|
47123
|
-
const filename =
|
|
47124
|
-
const noticesFilename =
|
|
47305
|
+
const filename = path22.join(dir, "live-efficiency.v1.jsonl");
|
|
47306
|
+
const noticesFilename = path22.join(dir, "live-efficiency-notices.v1.jsonl");
|
|
47125
47307
|
let existing = "";
|
|
47126
47308
|
try {
|
|
47127
47309
|
const stat2 = await lstat8(filename);
|
|
47128
47310
|
if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > MAX_LEDGER_BYTES) {
|
|
47129
47311
|
throw failure5("OPTIMIZATION_LEDGER_INVALID");
|
|
47130
47312
|
}
|
|
47131
|
-
existing = await
|
|
47313
|
+
existing = await readFile9(filename, "utf8");
|
|
47132
47314
|
} catch (error62) {
|
|
47133
47315
|
if (error62.code !== "ENOENT") throw error62;
|
|
47134
47316
|
}
|
|
@@ -47142,7 +47324,7 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
47142
47324
|
try {
|
|
47143
47325
|
const noticeStat = await lstat8(noticesFilename);
|
|
47144
47326
|
if (!noticeStat.isFile() || noticeStat.isSymbolicLink() || noticeStat.size > MAX_NOTICE_LEDGER_BYTES) throw failure5("OPTIMIZATION_NOTICE_LEDGER_INVALID");
|
|
47145
|
-
const notices = await
|
|
47327
|
+
const notices = await readFile9(noticesFilename, "utf8");
|
|
47146
47328
|
for (const line of notices.split("\n")) {
|
|
47147
47329
|
if (!line) continue;
|
|
47148
47330
|
const parsed = JSON.parse(line);
|
|
@@ -47270,9 +47452,9 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
47270
47452
|
|
|
47271
47453
|
// agent/src/monitor.ts
|
|
47272
47454
|
import { createHash as createHash17, randomUUID as randomUUID12 } from "node:crypto";
|
|
47273
|
-
import { lstat as lstat9, mkdir as mkdir9, open as open9, rename as rename6, rm as
|
|
47274
|
-
import
|
|
47275
|
-
import
|
|
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";
|
|
47276
47458
|
|
|
47277
47459
|
// packages/agent-cli/bin/monitor-savings.mjs
|
|
47278
47460
|
var count = (value) => Number.isSafeInteger(value) && value >= 0 && value <= 1e15;
|
|
@@ -47294,7 +47476,7 @@ function lifetimeSavingsView(raw) {
|
|
|
47294
47476
|
// agent/src/monitor.ts
|
|
47295
47477
|
function commandSummary2(tool) {
|
|
47296
47478
|
if (tool.name !== "command_run") return { name: tool.name, command: tool.name };
|
|
47297
|
-
const candidate =
|
|
47479
|
+
const candidate = path23.win32.basename(tool.args.command).replace(/\.(exe|cmd|bat|com)$/i, "").toLowerCase();
|
|
47298
47480
|
const name2 = ["node", "npm", "npx", "git", "rg", "powershell", "pwsh", "cmd", "tsc", "python", "dotnet"].includes(candidate) ? candidate : "command";
|
|
47299
47481
|
let command = name2;
|
|
47300
47482
|
if (name2 === "node" && tool.args.args.includes("--test") && !tool.args.args.some((arg) => ["-e", "--eval", "-p", "--print"].includes(arg))) command += " --test";
|
|
@@ -47307,9 +47489,9 @@ function commandSummary2(tool) {
|
|
|
47307
47489
|
var ProductionMonitor = class {
|
|
47308
47490
|
constructor(directory, stateDirectory, agentVersion3) {
|
|
47309
47491
|
this.agentVersion = agentVersion3;
|
|
47310
|
-
const key = createHash17("sha256").update(
|
|
47311
|
-
this.file =
|
|
47312
|
-
this.transportFile =
|
|
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");
|
|
47313
47495
|
}
|
|
47314
47496
|
agentVersion;
|
|
47315
47497
|
instanceId = randomUUID12();
|
|
@@ -47320,7 +47502,7 @@ var ProductionMonitor = class {
|
|
|
47320
47502
|
measured = /* @__PURE__ */ new Set();
|
|
47321
47503
|
polls = { status: 0, output: 0 };
|
|
47322
47504
|
efficiencyCalls = 0;
|
|
47323
|
-
computer =
|
|
47505
|
+
computer = os7.hostname().replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 64) || "PC";
|
|
47324
47506
|
sequence = 0;
|
|
47325
47507
|
connection = {
|
|
47326
47508
|
state: "starting",
|
|
@@ -47501,7 +47683,7 @@ var ProductionMonitor = class {
|
|
|
47501
47683
|
schemaVersion: 1,
|
|
47502
47684
|
instanceId: this.instanceId,
|
|
47503
47685
|
pid: process.pid,
|
|
47504
|
-
savingsSourceId:
|
|
47686
|
+
savingsSourceId: path23.basename(this.file, ".json"),
|
|
47505
47687
|
lifetimeSavings: this.lifetimeSavings && { ...this.lifetimeSavings },
|
|
47506
47688
|
computer: this.computer,
|
|
47507
47689
|
processName: "lc-agent",
|
|
@@ -47535,7 +47717,7 @@ var ProductionMonitor = class {
|
|
|
47535
47717
|
return this.writing;
|
|
47536
47718
|
}
|
|
47537
47719
|
async write(file2, contents) {
|
|
47538
|
-
const directory =
|
|
47720
|
+
const directory = path23.dirname(file2);
|
|
47539
47721
|
await mkdir9(directory, { recursive: true, mode: 448 });
|
|
47540
47722
|
const stat2 = await lstat9(directory);
|
|
47541
47723
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw Error("MONITOR_DIRECTORY_INVALID");
|
|
@@ -47549,7 +47731,7 @@ var ProductionMonitor = class {
|
|
|
47549
47731
|
}
|
|
47550
47732
|
await rename6(temporary, file2);
|
|
47551
47733
|
} finally {
|
|
47552
|
-
await
|
|
47734
|
+
await rm8(temporary, { force: true });
|
|
47553
47735
|
}
|
|
47554
47736
|
}
|
|
47555
47737
|
async close() {
|
|
@@ -47960,13 +48142,13 @@ var NativeFabricObserver = class {
|
|
|
47960
48142
|
};
|
|
47961
48143
|
|
|
47962
48144
|
// agent/src/native-fabric-startup.ts
|
|
47963
|
-
import { lstat as lstat11, mkdir as mkdir12, open as open11, readFile as
|
|
47964
|
-
import
|
|
48145
|
+
import { lstat as lstat11, mkdir as mkdir12, open as open11, readFile as readFile10 } from "node:fs/promises";
|
|
48146
|
+
import path26 from "node:path";
|
|
47965
48147
|
|
|
47966
48148
|
// src/agent-fabric-service.ts
|
|
47967
48149
|
import { lstat as lstat10, mkdir as mkdir11, realpath as realpath9 } from "node:fs/promises";
|
|
47968
48150
|
import { watch } from "node:fs";
|
|
47969
|
-
import
|
|
48151
|
+
import path25 from "node:path";
|
|
47970
48152
|
|
|
47971
48153
|
// src/agent-runtime-identity.ts
|
|
47972
48154
|
import { createHash as createHash19, randomBytes as randomBytes7, randomUUID as randomUUID14, timingSafeEqual as timingSafeEqual4 } from "node:crypto";
|
|
@@ -47974,13 +48156,13 @@ import { createHash as createHash19, randomBytes as randomBytes7, randomUUID as
|
|
|
47974
48156
|
// src/agent-fabric-state.ts
|
|
47975
48157
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
47976
48158
|
import { mkdir as mkdir10, open as open10, rename as rename7, unlink as unlink2 } from "node:fs/promises";
|
|
47977
|
-
import
|
|
48159
|
+
import path24 from "node:path";
|
|
47978
48160
|
var queues = /* @__PURE__ */ new Map();
|
|
47979
48161
|
var FabricStateFile = class {
|
|
47980
48162
|
constructor(file2, maxBytes, parse3) {
|
|
47981
48163
|
this.maxBytes = maxBytes;
|
|
47982
48164
|
this.parse = parse3;
|
|
47983
|
-
this.file =
|
|
48165
|
+
this.file = path24.resolve(file2);
|
|
47984
48166
|
}
|
|
47985
48167
|
maxBytes;
|
|
47986
48168
|
parse;
|
|
@@ -48024,7 +48206,7 @@ var FabricStateFile = class {
|
|
|
48024
48206
|
}
|
|
48025
48207
|
update(fn, create) {
|
|
48026
48208
|
return this.serial(async () => {
|
|
48027
|
-
if (create) await mkdir10(
|
|
48209
|
+
if (create) await mkdir10(path24.dirname(this.file), { recursive: true });
|
|
48028
48210
|
const lockPath = this.file + ".lock";
|
|
48029
48211
|
const token = randomUUID13();
|
|
48030
48212
|
const lock = await open10(lockPath, "wx", 384).catch((error62) => {
|
|
@@ -48668,9 +48850,9 @@ var WorkerRequest = external_exports.discriminatedUnion("operation", [
|
|
|
48668
48850
|
var AgentFabricService = class _AgentFabricService {
|
|
48669
48851
|
constructor(directory, controllerId) {
|
|
48670
48852
|
this.directory = directory;
|
|
48671
|
-
this.identities = new AgentRuntimeIdentityStore(
|
|
48853
|
+
this.identities = new AgentRuntimeIdentityStore(path25.join(directory, "identities.json"));
|
|
48672
48854
|
this.mailbox = new AgentWorkerMailbox(
|
|
48673
|
-
|
|
48855
|
+
path25.join(directory, "mailbox.json"),
|
|
48674
48856
|
controllerId,
|
|
48675
48857
|
this.identities,
|
|
48676
48858
|
void 0,
|
|
@@ -48685,21 +48867,21 @@ var AgentFabricService = class _AgentFabricService {
|
|
|
48685
48867
|
closed = false;
|
|
48686
48868
|
static async open(directory, controllerId, device = null, initialize = true) {
|
|
48687
48869
|
const expected = Binding.parse({ version: 1, controllerId, device, initialized: false });
|
|
48688
|
-
const absolute2 =
|
|
48689
|
-
for (let current2 = absolute2; ; current2 =
|
|
48870
|
+
const absolute2 = path25.resolve(directory);
|
|
48871
|
+
for (let current2 = absolute2; ; current2 = path25.dirname(current2)) {
|
|
48690
48872
|
try {
|
|
48691
48873
|
if ((await lstat10(current2)).isSymbolicLink()) throw Error("FABRIC_DIRECTORY_INVALID");
|
|
48692
48874
|
} catch (error62) {
|
|
48693
48875
|
if (error62.code !== "ENOENT") throw error62;
|
|
48694
48876
|
}
|
|
48695
|
-
if (
|
|
48877
|
+
if (path25.dirname(current2) === current2) break;
|
|
48696
48878
|
}
|
|
48697
48879
|
if (initialize) await mkdir11(absolute2, { recursive: true, mode: 448 });
|
|
48698
48880
|
if (!(await lstat10(absolute2)).isDirectory() || (await realpath9(absolute2)).toLowerCase() !== absolute2.toLowerCase())
|
|
48699
48881
|
throw Error("FABRIC_DIRECTORY_INVALID");
|
|
48700
48882
|
const present = /* @__PURE__ */ new Set();
|
|
48701
48883
|
for (const name2 of ["binding.json", "mailbox.json", "identities.json"]) {
|
|
48702
|
-
const file2 = await lstat10(
|
|
48884
|
+
const file2 = await lstat10(path25.join(absolute2, name2)).catch((error62) => {
|
|
48703
48885
|
if (error62.code === "ENOENT") return null;
|
|
48704
48886
|
throw error62;
|
|
48705
48887
|
});
|
|
@@ -48707,7 +48889,7 @@ var AgentFabricService = class _AgentFabricService {
|
|
|
48707
48889
|
if (file2) present.add(name2);
|
|
48708
48890
|
}
|
|
48709
48891
|
if (!present.has("binding.json") && present.size) throw Error("FABRIC_BINDING_MISSING");
|
|
48710
|
-
const binding2 = new FabricStateFile(
|
|
48892
|
+
const binding2 = new FabricStateFile(path25.join(absolute2, "binding.json"), 2048, (value) => Binding.parse(value));
|
|
48711
48893
|
const service2 = new _AgentFabricService(absolute2, controllerId);
|
|
48712
48894
|
await binding2.update(async (state) => {
|
|
48713
48895
|
if (state.controllerId !== expected.controllerId || JSON.stringify(state.device) !== JSON.stringify(expected.device))
|
|
@@ -48722,7 +48904,7 @@ var AgentFabricService = class _AgentFabricService {
|
|
|
48722
48904
|
state.initialized = true;
|
|
48723
48905
|
}
|
|
48724
48906
|
const snapshot2 = await service2.mailbox.snapshot();
|
|
48725
|
-
if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await lstat10(
|
|
48907
|
+
if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await lstat10(path25.join(absolute2, "identities.json"));
|
|
48726
48908
|
}, initialize ? () => expected : void 0);
|
|
48727
48909
|
return service2;
|
|
48728
48910
|
}
|
|
@@ -48809,7 +48991,7 @@ var Delivery = external_exports.strictObject({ capability: external_exports.stri
|
|
|
48809
48991
|
async function openNativeFabric(stateDirectory, enrollment, box, initialize = true) {
|
|
48810
48992
|
const controllerId = "device-" + external_exports.string().uuid().parse(enrollment.deviceId).toLowerCase();
|
|
48811
48993
|
const tenantId = external_exports.string().uuid().parse(enrollment.tenantId).toLowerCase();
|
|
48812
|
-
const parent =
|
|
48994
|
+
const parent = path26.join(stateDirectory, ".local-commander"), marker = path26.join(parent, "fabric-established.json");
|
|
48813
48995
|
try {
|
|
48814
48996
|
await mkdir12(parent, { mode: 448 });
|
|
48815
48997
|
} catch (error62) {
|
|
@@ -48821,7 +49003,7 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
|
|
|
48821
49003
|
let fresh = false;
|
|
48822
49004
|
try {
|
|
48823
49005
|
const info = await lstat11(marker);
|
|
48824
|
-
if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await
|
|
49006
|
+
if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await readFile10(marker, "utf8") !== expected)
|
|
48825
49007
|
throw Error("FABRIC_BINDING_CHANGED");
|
|
48826
49008
|
} catch (error62) {
|
|
48827
49009
|
if (error62.code !== "ENOENT" || !initialize) throw error62;
|
|
@@ -48835,13 +49017,13 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
|
|
|
48835
49017
|
fresh = true;
|
|
48836
49018
|
}
|
|
48837
49019
|
const service2 = await AgentFabricService.open(
|
|
48838
|
-
|
|
49020
|
+
path26.join(stateDirectory, ".local-commander", "fabric"),
|
|
48839
49021
|
controllerId,
|
|
48840
49022
|
{ deviceId: enrollment.deviceId.toLowerCase(), enrollmentEvidenceRef: "enrollment-" + tenantId },
|
|
48841
49023
|
fresh
|
|
48842
49024
|
);
|
|
48843
49025
|
const purpose = "native-fabric:" + tenantId + ":" + controllerId;
|
|
48844
|
-
const credentialFile = (workerId) =>
|
|
49026
|
+
const credentialFile = (workerId) => path26.join(service2.directory, external_exports.string().uuid().parse(workerId) + ".capability");
|
|
48845
49027
|
const decode4 = (value) => {
|
|
48846
49028
|
const credential = Credential.parse(JSON.parse(box.open(Buffer.from(value, "base64"), purpose).toString("utf8")));
|
|
48847
49029
|
if (credential.controllerId !== controllerId) throw Error("FABRIC_WORKER_DENIED");
|
|
@@ -48850,7 +49032,7 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
|
|
|
48850
49032
|
async function capability(workerId) {
|
|
48851
49033
|
const file2 = credentialFile(workerId), info = await lstat11(file2);
|
|
48852
49034
|
if (!info.isFile() || info.isSymbolicLink() || info.size > 4096) throw Error("FABRIC_CREDENTIAL_UNKNOWN");
|
|
48853
|
-
const encoded = await
|
|
49035
|
+
const encoded = await readFile10(file2, "utf8");
|
|
48854
49036
|
if (decode4(encoded).workerId !== workerId) throw Error("FABRIC_WORKER_DENIED");
|
|
48855
49037
|
return encoded;
|
|
48856
49038
|
}
|
|
@@ -48942,7 +49124,7 @@ async function readFabricRequest(input2 = process.stdin) {
|
|
|
48942
49124
|
|
|
48943
49125
|
// agent/src/supervisor-liveness.ts
|
|
48944
49126
|
import { spawn as spawn6 } from "node:child_process";
|
|
48945
|
-
import
|
|
49127
|
+
import path27 from "node:path";
|
|
48946
49128
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
48947
49129
|
var ROW = /^"([^"]+)","(\d{1,10})"/;
|
|
48948
49130
|
function parseTasklist(output2, image) {
|
|
@@ -48957,7 +49139,7 @@ function parseTasklist(output2, image) {
|
|
|
48957
49139
|
}
|
|
48958
49140
|
function listProcesses(image, timeoutMs2 = 5e3) {
|
|
48959
49141
|
if (process.platform !== "win32" || !/^[A-Za-z0-9._-]{1,64}\.exe$/i.test(image)) return Promise.resolve(null);
|
|
48960
|
-
const tasklist =
|
|
49142
|
+
const tasklist = path27.join(process.env.SystemRoot || "C:\\Windows", "System32", "tasklist.exe");
|
|
48961
49143
|
return new Promise((resolve) => {
|
|
48962
49144
|
let output2 = "", settled = false;
|
|
48963
49145
|
const finish = (value) => {
|
|
@@ -48986,8 +49168,8 @@ function listProcesses(image, timeoutMs2 = 5e3) {
|
|
|
48986
49168
|
}
|
|
48987
49169
|
function supervisorLiveness(helperPath, options = {}) {
|
|
48988
49170
|
if (process.platform === "linux" && !options.list) return linuxSupervisorLiveness;
|
|
48989
|
-
if (process.platform === "darwin" && !options.list) return (pids, _linux, darwin) => darwinSupervisorLiveness(
|
|
48990
|
-
const image =
|
|
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;
|
|
48991
49173
|
return async (pids) => {
|
|
48992
49174
|
const deadline = Date.now() + waitMs;
|
|
48993
49175
|
for (; ; ) {
|
|
@@ -49002,8 +49184,8 @@ function supervisorLiveness(helperPath, options = {}) {
|
|
|
49002
49184
|
|
|
49003
49185
|
// agent/src/content-audit.ts
|
|
49004
49186
|
import { createReadStream } from "node:fs";
|
|
49005
|
-
import { appendFile, lstat as lstat12, mkdir as mkdir13, open as open12, readdir as readdir5, readFile as
|
|
49006
|
-
import
|
|
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";
|
|
49007
49189
|
import { performance as performance3 } from "node:perf_hooks";
|
|
49008
49190
|
import { createInterface as createInterface2 } from "node:readline";
|
|
49009
49191
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
@@ -49172,7 +49354,7 @@ var FILE = /^(full|metrics)-(\d{4}-\d{2}-\d{2})\.jsonl$/;
|
|
|
49172
49354
|
var PAUSED_FILE = "paused.json";
|
|
49173
49355
|
var DAY_MS = 864e5;
|
|
49174
49356
|
function contentAuditDirectory(stateDir) {
|
|
49175
|
-
return
|
|
49357
|
+
return path28.join(path28.dirname(path28.resolve(stateDir)), "Audit");
|
|
49176
49358
|
}
|
|
49177
49359
|
async function plainDirectory(dir) {
|
|
49178
49360
|
await mkdir13(dir, { recursive: true, mode: 448 });
|
|
@@ -49191,7 +49373,7 @@ async function auditFiles(dir) {
|
|
|
49191
49373
|
for (const name2 of names) {
|
|
49192
49374
|
const match = FILE.exec(name2);
|
|
49193
49375
|
if (!match) continue;
|
|
49194
|
-
const info = await lstat12(
|
|
49376
|
+
const info = await lstat12(path28.join(dir, name2));
|
|
49195
49377
|
if (info.isFile()) files.push({ name: name2, kind: match[1], day: match[2], bytes: info.size });
|
|
49196
49378
|
}
|
|
49197
49379
|
return files.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -49202,7 +49384,7 @@ async function writeJsonAtomic(file2, value) {
|
|
|
49202
49384
|
await writeFile4(temp, JSON.stringify(value) + "\n", { flag: "wx", mode: 384 });
|
|
49203
49385
|
await rename8(temp, file2);
|
|
49204
49386
|
} finally {
|
|
49205
|
-
await
|
|
49387
|
+
await rm9(temp, { force: true }).catch(() => {
|
|
49206
49388
|
});
|
|
49207
49389
|
}
|
|
49208
49390
|
}
|
|
@@ -49229,7 +49411,7 @@ var ContentAudit = class _ContentAudit {
|
|
|
49229
49411
|
skipped = 0;
|
|
49230
49412
|
closed = false;
|
|
49231
49413
|
static async open(options) {
|
|
49232
|
-
const dir =
|
|
49414
|
+
const dir = path28.resolve(options.directory);
|
|
49233
49415
|
await plainDirectory(dir);
|
|
49234
49416
|
const audit = new _ContentAudit(
|
|
49235
49417
|
dir,
|
|
@@ -49238,7 +49420,7 @@ var ContentAudit = class _ContentAudit {
|
|
|
49238
49420
|
{ retentionDays: options.retentionDays ?? AUDIT_RETENTION_DAYS, maxBytes: options.maxBytes ?? AUDIT_MAX_BYTES },
|
|
49239
49421
|
options.now ?? (() => /* @__PURE__ */ new Date())
|
|
49240
49422
|
);
|
|
49241
|
-
await
|
|
49423
|
+
await rm9(path28.join(dir, PAUSED_FILE), { force: true });
|
|
49242
49424
|
await audit.rollover(audit.now());
|
|
49243
49425
|
if (audit.usedBytes >= audit.limits.maxBytes) await audit.pause("QUOTA_EXCEEDED");
|
|
49244
49426
|
return audit;
|
|
@@ -49308,8 +49490,8 @@ var ContentAudit = class _ContentAudit {
|
|
|
49308
49490
|
await this.pause("QUOTA_EXCEEDED");
|
|
49309
49491
|
return;
|
|
49310
49492
|
}
|
|
49311
|
-
await appendFile(
|
|
49312
|
-
await appendFile(
|
|
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 });
|
|
49313
49495
|
this.usedBytes += bytes3;
|
|
49314
49496
|
}
|
|
49315
49497
|
/** Daily retention runs on the first write of a new day; no timer or background scan. */
|
|
@@ -49318,7 +49500,7 @@ var ContentAudit = class _ContentAudit {
|
|
|
49318
49500
|
const cutoff = new Date(at.getTime() - this.limits.retentionDays * DAY_MS).toISOString().slice(0, 10);
|
|
49319
49501
|
let used = 0;
|
|
49320
49502
|
for (const file2 of await auditFiles(this.dir)) {
|
|
49321
|
-
if (file2.day <= cutoff) await
|
|
49503
|
+
if (file2.day <= cutoff) await rm9(path28.join(this.dir, file2.name), { force: true });
|
|
49322
49504
|
else used += file2.bytes;
|
|
49323
49505
|
}
|
|
49324
49506
|
this.usedBytes = used;
|
|
@@ -49326,7 +49508,7 @@ var ContentAudit = class _ContentAudit {
|
|
|
49326
49508
|
async pause(reason) {
|
|
49327
49509
|
if (this.paused) return;
|
|
49328
49510
|
this.paused = reason;
|
|
49329
|
-
await writeJsonAtomic(
|
|
49511
|
+
await writeJsonAtomic(path28.join(this.dir, PAUSED_FILE), { reason, at: this.now().toISOString() });
|
|
49330
49512
|
}
|
|
49331
49513
|
};
|
|
49332
49514
|
function percentiles(values) {
|
|
@@ -49348,13 +49530,13 @@ async function* jsonLines(file2) {
|
|
|
49348
49530
|
}
|
|
49349
49531
|
var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
49350
49532
|
async function summarizeContentAudit(directory, key) {
|
|
49351
|
-
const dir =
|
|
49533
|
+
const dir = path28.resolve(directory);
|
|
49352
49534
|
const files = await auditFiles(dir);
|
|
49353
49535
|
const days = /* @__PURE__ */ new Map();
|
|
49354
49536
|
const sizes = [];
|
|
49355
49537
|
const timings = [];
|
|
49356
49538
|
for (const file2 of files.filter((f) => f.kind === "metrics")) {
|
|
49357
|
-
for await (const line of jsonLines(
|
|
49539
|
+
for await (const line of jsonLines(path28.join(dir, file2.name))) {
|
|
49358
49540
|
let day = days.get(file2.day);
|
|
49359
49541
|
if (!day) {
|
|
49360
49542
|
day = { day: file2.day, records: 0, failed: 0, rawBytes: 0, sanitizedBytes: 0, compressedBytes: 0, envelopeBytes: 0 };
|
|
@@ -49374,7 +49556,7 @@ async function summarizeContentAudit(directory, key) {
|
|
|
49374
49556
|
}
|
|
49375
49557
|
let paused = null;
|
|
49376
49558
|
try {
|
|
49377
|
-
const value = JSON.parse(await
|
|
49559
|
+
const value = JSON.parse(await readFile11(path28.join(dir, PAUSED_FILE), "utf8"));
|
|
49378
49560
|
if (typeof value.reason === "string" && typeof value.at === "string") paused = { reason: value.reason.slice(0, 40), at: value.at.slice(0, 40) };
|
|
49379
49561
|
} catch {
|
|
49380
49562
|
}
|
|
@@ -49382,7 +49564,7 @@ async function summarizeContentAudit(directory, key) {
|
|
|
49382
49564
|
const newest = files.filter((f) => f.kind === "full").at(-1);
|
|
49383
49565
|
if (key && newest) {
|
|
49384
49566
|
const tail = [];
|
|
49385
|
-
for await (const line of jsonLines(
|
|
49567
|
+
for await (const line of jsonLines(path28.join(dir, newest.name))) {
|
|
49386
49568
|
tail.push(line);
|
|
49387
49569
|
if (tail.length > 5) tail.shift();
|
|
49388
49570
|
}
|
|
@@ -49416,10 +49598,10 @@ async function summarizeContentAudit(directory, key) {
|
|
|
49416
49598
|
};
|
|
49417
49599
|
}
|
|
49418
49600
|
async function restoreContentAudit(input2, output2, key) {
|
|
49419
|
-
const handle = await open12(
|
|
49601
|
+
const handle = await open12(path28.resolve(output2), "wx", 384);
|
|
49420
49602
|
let records = 0, failed = 0;
|
|
49421
49603
|
try {
|
|
49422
|
-
for await (const line of jsonLines(
|
|
49604
|
+
for await (const line of jsonLines(path28.resolve(input2))) {
|
|
49423
49605
|
try {
|
|
49424
49606
|
await handle.appendFile(JSON.stringify(decryptAuditRecord(line, key)) + "\n");
|
|
49425
49607
|
records += 1;
|
|
@@ -49434,7 +49616,7 @@ async function restoreContentAudit(input2, output2, key) {
|
|
|
49434
49616
|
}
|
|
49435
49617
|
|
|
49436
49618
|
// agent/src/main.ts
|
|
49437
|
-
var AGENT_VERSION2 = true ? "0.3.
|
|
49619
|
+
var AGENT_VERSION2 = true ? "0.3.46" : "0.3.2";
|
|
49438
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" : "";
|
|
49439
49621
|
var AI_CONNECTION_SHIPPED = false;
|
|
49440
49622
|
function processAlive(pid) {
|
|
@@ -49448,7 +49630,7 @@ function processAlive(pid) {
|
|
|
49448
49630
|
}
|
|
49449
49631
|
async function claimAgentProcess(stateDir, runtimeDir, version2) {
|
|
49450
49632
|
await mkdir14(stateDir, { recursive: true });
|
|
49451
|
-
const file2 =
|
|
49633
|
+
const file2 = path29.join(stateDir, "agent-process.json");
|
|
49452
49634
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
49453
49635
|
try {
|
|
49454
49636
|
const handle = await open13(file2, "wx", 384);
|
|
@@ -49459,8 +49641,8 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
|
|
|
49459
49641
|
}
|
|
49460
49642
|
return async () => {
|
|
49461
49643
|
try {
|
|
49462
|
-
const current2 = JSON.parse(await
|
|
49463
|
-
if (current2.pid === process.pid) await
|
|
49644
|
+
const current2 = JSON.parse(await readFile12(file2, "utf8"));
|
|
49645
|
+
if (current2.pid === process.pid) await rm10(file2, { force: true });
|
|
49464
49646
|
} catch {
|
|
49465
49647
|
}
|
|
49466
49648
|
};
|
|
@@ -49468,12 +49650,12 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
|
|
|
49468
49650
|
if (!error62 || typeof error62 !== "object" || !("code" in error62) || error62.code !== "EEXIST") throw error62;
|
|
49469
49651
|
let stale = true;
|
|
49470
49652
|
try {
|
|
49471
|
-
const current2 = JSON.parse(await
|
|
49653
|
+
const current2 = JSON.parse(await readFile12(file2, "utf8"));
|
|
49472
49654
|
stale = typeof current2.pid !== "number" || !processAlive(current2.pid);
|
|
49473
49655
|
} catch {
|
|
49474
49656
|
}
|
|
49475
49657
|
if (!stale) throw Error("AGENT_ALREADY_RUNNING");
|
|
49476
|
-
await
|
|
49658
|
+
await rm10(file2, { force: true });
|
|
49477
49659
|
}
|
|
49478
49660
|
}
|
|
49479
49661
|
throw Error("AGENT_ALREADY_RUNNING");
|
|
@@ -49724,10 +49906,10 @@ async function openContentAudit(store, stateDir) {
|
|
|
49724
49906
|
async function main() {
|
|
49725
49907
|
if (!["win32", "linux", "darwin"].includes(process.platform)) throw Error("PLATFORM_UNSUPPORTED");
|
|
49726
49908
|
const appData = process.env.LC_AGENT_DATA_DIR ?? (process.platform === "win32" ? process.env.LOCALAPPDATA : posixDataHome());
|
|
49727
|
-
if (!appData || !
|
|
49728
|
-
const stateDir = process.env.LC_AGENT_STATE_DIR ??
|
|
49729
|
-
const binaryDir =
|
|
49730
|
-
const ownerBridgePath = process.env.LC_OWNER_BRIDGE ??
|
|
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");
|
|
49731
49913
|
const store = await WindowsPrivateStore.open(stateDir, ownerBridgePath);
|
|
49732
49914
|
const command = process.argv[2] ?? "run";
|
|
49733
49915
|
if (process.platform !== "win32" && (command.startsWith("guard-") || command.startsWith("network-"))) throw Error("FEATURE_PLATFORM_UNSUPPORTED");
|
|
@@ -49737,7 +49919,7 @@ async function main() {
|
|
|
49737
49919
|
const pairing = new PairingClient(store, { controlPlaneOrigin: origin, agentVersion: AGENT_VERSION2 });
|
|
49738
49920
|
const begun = await pairing.begin();
|
|
49739
49921
|
process.stdout.write(JSON.stringify({ approvalUrl: begun.approvalUrl, confirmationCode: begun.confirmationCode, expiresAt: begun.expiresAt.toISOString() }) + "\n");
|
|
49740
|
-
await pairing.waitAndComplete(begun,
|
|
49922
|
+
await pairing.waitAndComplete(begun, os8.hostname().slice(0, 120));
|
|
49741
49923
|
process.stdout.write("DEVICE_PAIRED\n");
|
|
49742
49924
|
return;
|
|
49743
49925
|
}
|
|
@@ -49822,7 +50004,7 @@ async function main() {
|
|
|
49822
50004
|
}
|
|
49823
50005
|
if (command === "efficiency-report") {
|
|
49824
50006
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
49825
|
-
const ledger = await OptimizationLedger.open(
|
|
50007
|
+
const ledger = await OptimizationLedger.open(path29.join(stateDir, "optimization"));
|
|
49826
50008
|
try {
|
|
49827
50009
|
process.stdout.write(JSON.stringify(await ledger.report(), null, 2) + "\n");
|
|
49828
50010
|
} finally {
|
|
@@ -49832,7 +50014,7 @@ async function main() {
|
|
|
49832
50014
|
}
|
|
49833
50015
|
if (command === "guard-configure") {
|
|
49834
50016
|
if (args.length !== 1) throw Error("AGENT_COMMAND_INVALID");
|
|
49835
|
-
const filename = await (await import("node:fs/promises")).realpath(
|
|
50017
|
+
const filename = await (await import("node:fs/promises")).realpath(path29.resolve(args[0]));
|
|
49836
50018
|
const input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readWindowsFile(ownerBridgePath, filename, 2e5)));
|
|
49837
50019
|
if (!input2 || typeof input2 !== "object" || Object.keys(input2).sort().join(",") !== "compact,settings") throw Error("GUARD_CONFIGURATION_INVALID");
|
|
49838
50020
|
await store.configureGuard(input2.settings, input2.compact);
|
|
@@ -49851,7 +50033,7 @@ async function main() {
|
|
|
49851
50033
|
}
|
|
49852
50034
|
if (command === "guard-evidence") {
|
|
49853
50035
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
49854
|
-
const journal = await NativeJournal.open(
|
|
50036
|
+
const journal = await NativeJournal.open(path29.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
49855
50037
|
try {
|
|
49856
50038
|
process.stdout.write(JSON.stringify(await journal.guardEvidence()) + "\n");
|
|
49857
50039
|
} finally {
|
|
@@ -49863,7 +50045,7 @@ async function main() {
|
|
|
49863
50045
|
if (args.length !== (command === "guard-export" ? 0 : 1)) throw Error("AGENT_COMMAND_INVALID");
|
|
49864
50046
|
const identity = await store.load();
|
|
49865
50047
|
if (!identity?.enrollment) throw Error("ENROLLMENT_MISSING");
|
|
49866
|
-
const journal = await NativeJournal.open(
|
|
50048
|
+
const journal = await NativeJournal.open(path29.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
49867
50049
|
try {
|
|
49868
50050
|
const { tenantId, deviceId } = identity.enrollment;
|
|
49869
50051
|
const records = (await journal.guardEvidence()).filter((record2) => record2.tenantId === tenantId && record2.deviceId === deviceId);
|
|
@@ -49941,27 +50123,27 @@ async function main() {
|
|
|
49941
50123
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
49942
50124
|
if (!(await store.load())?.enrollment) throw Error("ENROLLMENT_MISSING");
|
|
49943
50125
|
const releaseProcess = await claimAgentProcess(stateDir, binaryDir, AGENT_VERSION2);
|
|
49944
|
-
const monitor = new ProductionMonitor(
|
|
50126
|
+
const monitor = new ProductionMonitor(path29.join(appData, "LocalCommander", "Monitor"), stateDir, AGENT_VERSION2);
|
|
49945
50127
|
const publishMonitor = () => monitor.flush().catch(() => {
|
|
49946
50128
|
process.stderr.write("MONITOR_WRITE_FAILED\n");
|
|
49947
50129
|
});
|
|
49948
50130
|
await publishMonitor();
|
|
49949
50131
|
try {
|
|
49950
50132
|
const journal = await NativeJournal.open(
|
|
49951
|
-
|
|
50133
|
+
path29.join(stateDir, "journal"),
|
|
49952
50134
|
new SecretBox({ "1": await store.loadDataKey() }),
|
|
49953
|
-
process.platform === "win32" ? {} : { lockHelper:
|
|
50135
|
+
process.platform === "win32" ? {} : { lockHelper: path29.join(binaryDir, "posix-host") }
|
|
49954
50136
|
);
|
|
49955
50137
|
const ledgerLoss = () => {
|
|
49956
50138
|
process.stderr.write("OPTIMIZATION_TELEMETRY_INCOMPLETE\n");
|
|
49957
50139
|
};
|
|
49958
50140
|
const efficiencyLedger = await new OptionalWork(ledgerLoss, 1e3, 1).run(
|
|
49959
|
-
() => OptimizationLedger.open(
|
|
50141
|
+
() => OptimizationLedger.open(path29.join(stateDir, "optimization")),
|
|
49960
50142
|
void 0,
|
|
49961
50143
|
(ledger) => ledger.close()
|
|
49962
50144
|
);
|
|
49963
50145
|
try {
|
|
49964
|
-
const helperPath = process.env.LC_JOB_HOST ??
|
|
50146
|
+
const helperPath = process.env.LC_JOB_HOST ?? path29.join(binaryDir, process.platform === "win32" ? "JobHost.exe" : "job-host.mjs");
|
|
49965
50147
|
const tools = new NativeTools({ stateDirectory: stateDir, helperPath, ownerBridgePath, programs: await store.loadPrograms() });
|
|
49966
50148
|
const stop = new AbortController();
|
|
49967
50149
|
process.once("SIGINT", () => stop.abort());
|
|
@@ -50032,7 +50214,7 @@ async function main() {
|
|
|
50032
50214
|
await releaseProcess();
|
|
50033
50215
|
}
|
|
50034
50216
|
}
|
|
50035
|
-
var entrypoint = process.argv[1] && (process.platform === "win32" ?
|
|
50217
|
+
var entrypoint = process.argv[1] && (process.platform === "win32" ? path29.resolve(process.argv[1]) : await realpath10(process.argv[1]).catch(() => null));
|
|
50036
50218
|
if (entrypoint === fileURLToPath(import.meta.url)) {
|
|
50037
50219
|
void main().catch((error62) => {
|
|
50038
50220
|
const code = error62 instanceof Error && /^[A-Z0-9_]{1,64}$/.test(error62.message) ? error62.message : "AGENT_START_FAILED";
|