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