local-commander-agent 0.3.13-launcher.1 → 0.3.14-cli.1
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/README.md +40 -8
- package/bin/localcommander.mjs +28 -0
- package/bin/monitor-context.d.mts +2 -0
- package/bin/monitor-context.mjs +19 -0
- package/bin/monitor-mcp.mjs +61 -5
- package/bin/monitor.mjs +96 -27
- package/package.json +1 -1
- package/runtime/JobHost.exe +0 -0
- package/runtime/LocalCommanderAgent.exe +0 -0
- package/runtime/OwnerBridge.exe +0 -0
- package/runtime/agent.mjs +603 -341
package/runtime/agent.mjs
CHANGED
|
@@ -2278,7 +2278,7 @@ var require_websocket = __commonJS({
|
|
|
2278
2278
|
var http = __require("http");
|
|
2279
2279
|
var net = __require("net");
|
|
2280
2280
|
var tls = __require("tls");
|
|
2281
|
-
var { randomBytes: randomBytes5, createHash:
|
|
2281
|
+
var { randomBytes: randomBytes5, createHash: createHash14 } = __require("crypto");
|
|
2282
2282
|
var { Duplex, Readable } = __require("stream");
|
|
2283
2283
|
var { URL: URL2 } = __require("url");
|
|
2284
2284
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -2959,7 +2959,7 @@ var require_websocket = __commonJS({
|
|
|
2959
2959
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2960
2960
|
return;
|
|
2961
2961
|
}
|
|
2962
|
-
const digest5 =
|
|
2962
|
+
const digest5 = createHash14("sha1").update(key + GUID).digest("base64");
|
|
2963
2963
|
if (res.headers["sec-websocket-accept"] !== digest5) {
|
|
2964
2964
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2965
2965
|
return;
|
|
@@ -3240,7 +3240,7 @@ var require_stream = __commonJS({
|
|
|
3240
3240
|
};
|
|
3241
3241
|
duplex._final = function(callback) {
|
|
3242
3242
|
if (ws.readyState === ws.CONNECTING) {
|
|
3243
|
-
ws.once("open", function
|
|
3243
|
+
ws.once("open", function open11() {
|
|
3244
3244
|
duplex._final(callback);
|
|
3245
3245
|
});
|
|
3246
3246
|
return;
|
|
@@ -3261,7 +3261,7 @@ var require_stream = __commonJS({
|
|
|
3261
3261
|
};
|
|
3262
3262
|
duplex._write = function(chunk, encoding, callback) {
|
|
3263
3263
|
if (ws.readyState === ws.CONNECTING) {
|
|
3264
|
-
ws.once("open", function
|
|
3264
|
+
ws.once("open", function open11() {
|
|
3265
3265
|
duplex._write(chunk, encoding, callback);
|
|
3266
3266
|
});
|
|
3267
3267
|
return;
|
|
@@ -3328,7 +3328,7 @@ var require_websocket_server = __commonJS({
|
|
|
3328
3328
|
var EventEmitter = __require("events");
|
|
3329
3329
|
var http = __require("http");
|
|
3330
3330
|
var { Duplex } = __require("stream");
|
|
3331
|
-
var { createHash:
|
|
3331
|
+
var { createHash: createHash14 } = __require("crypto");
|
|
3332
3332
|
var extension2 = require_extension();
|
|
3333
3333
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3334
3334
|
var subprotocol2 = require_subprotocol();
|
|
@@ -3635,7 +3635,7 @@ var require_websocket_server = __commonJS({
|
|
|
3635
3635
|
);
|
|
3636
3636
|
}
|
|
3637
3637
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3638
|
-
const digest5 =
|
|
3638
|
+
const digest5 = createHash14("sha1").update(key + GUID).digest("base64");
|
|
3639
3639
|
const headers = [
|
|
3640
3640
|
"HTTP/1.1 101 Switching Protocols",
|
|
3641
3641
|
"Upgrade: websocket",
|
|
@@ -3723,9 +3723,9 @@ var require_websocket_server = __commonJS({
|
|
|
3723
3723
|
});
|
|
3724
3724
|
|
|
3725
3725
|
// agent/src/main.ts
|
|
3726
|
-
import
|
|
3727
|
-
import
|
|
3728
|
-
import { mkdir as
|
|
3726
|
+
import path18 from "node:path";
|
|
3727
|
+
import os5 from "node:os";
|
|
3728
|
+
import { mkdir as mkdir10, open as open10, readFile as readFile7, rm as rm6 } from "node:fs/promises";
|
|
3729
3729
|
import { fileURLToPath } from "node:url";
|
|
3730
3730
|
|
|
3731
3731
|
// packages/operations/src/crypto.ts
|
|
@@ -4674,10 +4674,10 @@ function mergeDefs(...defs) {
|
|
|
4674
4674
|
function cloneDef(schema) {
|
|
4675
4675
|
return mergeDefs(schema._zod.def);
|
|
4676
4676
|
}
|
|
4677
|
-
function getElementAtPath(obj,
|
|
4678
|
-
if (!
|
|
4677
|
+
function getElementAtPath(obj, path19) {
|
|
4678
|
+
if (!path19)
|
|
4679
4679
|
return obj;
|
|
4680
|
-
return
|
|
4680
|
+
return path19.reduce((acc, key) => acc?.[key], obj);
|
|
4681
4681
|
}
|
|
4682
4682
|
function promiseAllObject(promisesObj) {
|
|
4683
4683
|
const keys = Object.keys(promisesObj);
|
|
@@ -5017,11 +5017,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
5017
5017
|
}
|
|
5018
5018
|
return false;
|
|
5019
5019
|
}
|
|
5020
|
-
function prefixIssues(
|
|
5020
|
+
function prefixIssues(path19, issues) {
|
|
5021
5021
|
return issues.map((iss) => {
|
|
5022
5022
|
var _a3;
|
|
5023
5023
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
5024
|
-
iss.path.unshift(
|
|
5024
|
+
iss.path.unshift(path19);
|
|
5025
5025
|
return iss;
|
|
5026
5026
|
});
|
|
5027
5027
|
}
|
|
@@ -5471,16 +5471,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
|
|
|
5471
5471
|
}
|
|
5472
5472
|
function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
5473
5473
|
const fieldErrors = { _errors: [] };
|
|
5474
|
-
const processError = (error63,
|
|
5474
|
+
const processError = (error63, path19 = []) => {
|
|
5475
5475
|
for (const issue2 of error63.issues) {
|
|
5476
5476
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5477
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5477
|
+
issue2.errors.map((issues) => processError({ issues }, [...path19, ...issue2.path]));
|
|
5478
5478
|
} else if (issue2.code === "invalid_key") {
|
|
5479
|
-
processError({ issues: issue2.issues }, [...
|
|
5479
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
5480
5480
|
} else if (issue2.code === "invalid_element") {
|
|
5481
|
-
processError({ issues: issue2.issues }, [...
|
|
5481
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
5482
5482
|
} else {
|
|
5483
|
-
const fullpath = [...
|
|
5483
|
+
const fullpath = [...path19, ...issue2.path];
|
|
5484
5484
|
if (fullpath.length === 0) {
|
|
5485
5485
|
fieldErrors._errors.push(mapper(issue2));
|
|
5486
5486
|
} else {
|
|
@@ -5519,17 +5519,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
|
5519
5519
|
}
|
|
5520
5520
|
function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
5521
5521
|
const result2 = { errors: [] };
|
|
5522
|
-
const processError = (error63,
|
|
5522
|
+
const processError = (error63, path19 = []) => {
|
|
5523
5523
|
var _a3;
|
|
5524
5524
|
for (const issue2 of error63.issues) {
|
|
5525
5525
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5526
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5526
|
+
issue2.errors.map((issues) => processError({ issues }, [...path19, ...issue2.path]));
|
|
5527
5527
|
} else if (issue2.code === "invalid_key") {
|
|
5528
|
-
processError({ issues: issue2.issues }, [...
|
|
5528
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
5529
5529
|
} else if (issue2.code === "invalid_element") {
|
|
5530
|
-
processError({ issues: issue2.issues }, [...
|
|
5530
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
5531
5531
|
} else {
|
|
5532
|
-
const fullpath = [...
|
|
5532
|
+
const fullpath = [...path19, ...issue2.path];
|
|
5533
5533
|
if (fullpath.length === 0) {
|
|
5534
5534
|
result2.errors.push(mapper(issue2));
|
|
5535
5535
|
continue;
|
|
@@ -5568,8 +5568,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
5568
5568
|
}
|
|
5569
5569
|
function toDotPath(_path) {
|
|
5570
5570
|
const segs = [];
|
|
5571
|
-
const
|
|
5572
|
-
for (const seg of
|
|
5571
|
+
const path19 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5572
|
+
for (const seg of path19) {
|
|
5573
5573
|
if (typeof seg === "number")
|
|
5574
5574
|
segs.push(`[${seg}]`);
|
|
5575
5575
|
else if (typeof seg === "symbol")
|
|
@@ -22671,13 +22671,13 @@ function resolveRef(ref, ctx) {
|
|
|
22671
22671
|
if (!ref.startsWith("#")) {
|
|
22672
22672
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
22673
22673
|
}
|
|
22674
|
-
const
|
|
22675
|
-
if (
|
|
22674
|
+
const path19 = ref.slice(1).split("/").filter(Boolean);
|
|
22675
|
+
if (path19.length === 0) {
|
|
22676
22676
|
return ctx.rootSchema;
|
|
22677
22677
|
}
|
|
22678
22678
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
22679
|
-
if (
|
|
22680
|
-
const key =
|
|
22679
|
+
if (path19[0] === defsKey) {
|
|
22680
|
+
const key = path19[1] === void 0 ? void 0 : decodeJSONPointerSegment(path19[1]);
|
|
22681
22681
|
if (!key || !ctx.defs[key]) {
|
|
22682
22682
|
throw new Error(`Reference not found: ${ref}`);
|
|
22683
22683
|
}
|
|
@@ -25773,7 +25773,12 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25773
25773
|
}
|
|
25774
25774
|
const approved = /* @__PURE__ */ new Set([MARKER, "owner-state.dat", "owner-state.lock", "journal", "agent-process.json", "optimization", ".local-commander"]);
|
|
25775
25775
|
if (names.length && !names.includes(MARKER)) throw fail("STORE_DIRECTORY_UNKNOWN");
|
|
25776
|
-
|
|
25776
|
+
const memoryFile = (name2) => name2 === "host-memory.json" || /^host-memory\.json\.[1-9][0-9]{0,9}\.tmp$/.test(name2);
|
|
25777
|
+
if (names.some((name2) => !approved.has(name2) && !memoryFile(name2))) throw fail("STORE_DIRECTORY_UNKNOWN");
|
|
25778
|
+
for (const name2 of names.filter(memoryFile)) {
|
|
25779
|
+
const stat = await lstat3(path5.join(absolute2, name2));
|
|
25780
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32768) throw fail("STORE_DIRECTORY_INVALID");
|
|
25781
|
+
}
|
|
25777
25782
|
for (const name2 of ["agent-process.json", "optimization", ".local-commander"]) {
|
|
25778
25783
|
if (!names.includes(name2)) continue;
|
|
25779
25784
|
const filename = path5.join(absolute2, name2), stat = await lstat3(filename);
|
|
@@ -26340,15 +26345,311 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
26340
26345
|
}
|
|
26341
26346
|
};
|
|
26342
26347
|
|
|
26348
|
+
// src/host-memory.ts
|
|
26349
|
+
import os2 from "node:os";
|
|
26350
|
+
import path7 from "node:path";
|
|
26351
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
26352
|
+
import { accessSync, constants as constants3, statSync as statSync2 } from "node:fs";
|
|
26353
|
+
import { lstat as lstat4, readFile as readFile3, mkdir as mkdir3, open as open4, rename as rename3, rm as rm3 } from "node:fs/promises";
|
|
26354
|
+
|
|
26355
|
+
// packages/agent-cli/bin/monitor-context.mjs
|
|
26356
|
+
var AGENT_NAMES = Object.freeze([
|
|
26357
|
+
"Avi",
|
|
26358
|
+
"Noam",
|
|
26359
|
+
"Yael",
|
|
26360
|
+
"Leah",
|
|
26361
|
+
"Ezra",
|
|
26362
|
+
"Eli",
|
|
26363
|
+
"Tamar",
|
|
26364
|
+
"Dalia",
|
|
26365
|
+
"Ruth",
|
|
26366
|
+
"Maya",
|
|
26367
|
+
"Oren",
|
|
26368
|
+
"Shira",
|
|
26369
|
+
"Eitan",
|
|
26370
|
+
"Lior",
|
|
26371
|
+
"Hila",
|
|
26372
|
+
"Amir",
|
|
26373
|
+
"Ivan",
|
|
26374
|
+
"Yuri",
|
|
26375
|
+
"Olga",
|
|
26376
|
+
"Anna",
|
|
26377
|
+
"Boris",
|
|
26378
|
+
"Nina",
|
|
26379
|
+
"Pavel",
|
|
26380
|
+
"Irina",
|
|
26381
|
+
"Vera",
|
|
26382
|
+
"Daria",
|
|
26383
|
+
"Misha",
|
|
26384
|
+
"Sasha",
|
|
26385
|
+
"Vadim",
|
|
26386
|
+
"Roman",
|
|
26387
|
+
"Anya",
|
|
26388
|
+
"Lev",
|
|
26389
|
+
"Omar",
|
|
26390
|
+
"Layla",
|
|
26391
|
+
"Ali",
|
|
26392
|
+
"Nadia",
|
|
26393
|
+
"Salim",
|
|
26394
|
+
"Hana",
|
|
26395
|
+
"Rami",
|
|
26396
|
+
"Zain",
|
|
26397
|
+
"Noor",
|
|
26398
|
+
"Amal",
|
|
26399
|
+
"Samir",
|
|
26400
|
+
"Farah",
|
|
26401
|
+
"Malik",
|
|
26402
|
+
"Yasmin",
|
|
26403
|
+
"Adil",
|
|
26404
|
+
"Hadi",
|
|
26405
|
+
"Arjun",
|
|
26406
|
+
"Priya",
|
|
26407
|
+
"Ravi",
|
|
26408
|
+
"Anika",
|
|
26409
|
+
"Asha",
|
|
26410
|
+
"Dev",
|
|
26411
|
+
"Kiran",
|
|
26412
|
+
"Meera",
|
|
26413
|
+
"Nisha",
|
|
26414
|
+
"Rohan",
|
|
26415
|
+
"Diya",
|
|
26416
|
+
"Neha",
|
|
26417
|
+
"Anil",
|
|
26418
|
+
"Sana",
|
|
26419
|
+
"Vijay",
|
|
26420
|
+
"Isha",
|
|
26421
|
+
"Wei",
|
|
26422
|
+
"Lin",
|
|
26423
|
+
"Mei",
|
|
26424
|
+
"Chen",
|
|
26425
|
+
"Li",
|
|
26426
|
+
"Jian",
|
|
26427
|
+
"Ming",
|
|
26428
|
+
"Hua",
|
|
26429
|
+
"Yan",
|
|
26430
|
+
"Tao",
|
|
26431
|
+
"Jun",
|
|
26432
|
+
"Lan",
|
|
26433
|
+
"Yue",
|
|
26434
|
+
"Lei",
|
|
26435
|
+
"Hong",
|
|
26436
|
+
"Qian"
|
|
26437
|
+
]);
|
|
26438
|
+
var identifier = (value) => typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,95}$/.test(value);
|
|
26439
|
+
function contextSummary(meta3 = {}) {
|
|
26440
|
+
const source = typeof (meta3.cwd ?? meta3.path ?? meta3.project) === "string" ? meta3.cwd ?? meta3.path ?? meta3.project : "";
|
|
26441
|
+
const normalized = source.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
26442
|
+
const safe = normalized.length <= 1024 && /^[A-Za-z0-9 _./:@()+-]*$/.test(normalized) && !/(?:^|\/)(?:\.env(?:\.[^/]*)?|credentials[^/]*|\.npmrc|agent-identities\.json)(?:\/|$)/i.test(normalized);
|
|
26443
|
+
const directory = safe && normalized ? normalized.slice(-96) : null;
|
|
26444
|
+
const project = directory ? directory.split("/").at(-1) : null;
|
|
26445
|
+
const taskMatch = safe && normalized.match(/\/planning\/tasks\/([A-Za-z0-9][A-Za-z0-9_.:-]{0,95})\.md$/);
|
|
26446
|
+
const taskId = identifier(meta3.taskId) ? meta3.taskId : taskMatch ? taskMatch[1] : null;
|
|
26447
|
+
const branchPr = safe && normalized.match(/(?:^|[/_-])pr[-_]?(\d{1,7})(?:[/_.-]|$)/i);
|
|
26448
|
+
const explicitPr = Number.isSafeInteger(meta3.pr) && meta3.pr > 0 && meta3.pr <= 9999999 ? meta3.pr : null;
|
|
26449
|
+
const args = Array.isArray(meta3.args) ? meta3.args : [];
|
|
26450
|
+
const ghPr = meta3.command === "gh" && args[0] === "pr" && ["view", "checkout", "diff", "checks", "merge"].includes(args[1]) && /^\d{1,7}$/.test(args[2] ?? "") ? Number(args[2]) : null;
|
|
26451
|
+
return { project, directory, taskId, pr: explicitPr ?? ghPr ?? (branchPr ? Number(branchPr[1]) : null), inferred: !explicitPr && !identifier(meta3.taskId) };
|
|
26452
|
+
}
|
|
26453
|
+
function commandSummary(tool, meta3 = {}) {
|
|
26454
|
+
if (tool === "agent_message" && ["send", "inbox", "ack"].includes(meta3.action)) {
|
|
26455
|
+
const kind = ["status", "question", "answer", "handoff", "result_summary", "blocker"].includes(meta3.kind) ? " " + meta3.kind : "";
|
|
26456
|
+
const target = identifier(meta3.to) ? " -> " + meta3.to.slice(0, 8) : "";
|
|
26457
|
+
return "agent_message " + meta3.action + kind + target;
|
|
26458
|
+
}
|
|
26459
|
+
if (!["command_run", "process_start"].includes(tool)) return tool;
|
|
26460
|
+
const candidate = typeof meta3.command === "string" ? meta3.command.replaceAll("\\", "/").split("/").at(-1).replace(/\.(exe|cmd|bat|com)$/i, "").toLowerCase() : "";
|
|
26461
|
+
const name2 = ["node", "npm", "npx", "git", "rg", "powershell", "pwsh", "cmd", "tsc", "python", "dotnet", "gh"].includes(candidate) ? candidate : "command";
|
|
26462
|
+
const args = Array.isArray(meta3.args) ? meta3.args : [];
|
|
26463
|
+
if (name2 === "git" && ["status", "diff", "log", "show", "fetch", "pull", "push", "commit"].includes(args[0])) return name2 + " " + args[0];
|
|
26464
|
+
if (name2 === "npm" && ["test", "install", "ci", "pack", "publish"].includes(args[0])) return name2 + " " + args[0];
|
|
26465
|
+
if (name2 === "npm" && args[0] === "run" && ["test", "build", "typecheck", "lint", "dev", "start"].includes(args[1])) return "npm run " + args[1];
|
|
26466
|
+
return name2 + (args.length ? " [args]" : "");
|
|
26467
|
+
}
|
|
26468
|
+
function commandPreview(tool, meta3 = {}) {
|
|
26469
|
+
if (!["command_run", "process_start"].includes(tool)) return commandSummary(tool, meta3);
|
|
26470
|
+
const name2 = typeof meta3.command === "string" && /^[A-Za-z0-9_.-]{1,40}$/.test(meta3.command) ? meta3.command : "command";
|
|
26471
|
+
const args = Array.isArray(meta3.args) ? meta3.args.slice(0, 24) : [];
|
|
26472
|
+
let hideNext = false, inline = false;
|
|
26473
|
+
const safe = args.map((arg) => {
|
|
26474
|
+
if (inline || hideNext) {
|
|
26475
|
+
hideNext = false;
|
|
26476
|
+
return "[redacted]";
|
|
26477
|
+
}
|
|
26478
|
+
if (typeof arg !== "string") return "[value]";
|
|
26479
|
+
if (/^(?:-e|--eval|-p|--print|-c|-command|--command|-encodedcommand|\/c|\/k)$/i.test(arg) && /^(?:node|python|bash|sh|powershell|pwsh|cmd)(?:\.[a-z]+)?$/i.test(name2)) inline = true;
|
|
26480
|
+
if (/^(?:[-/]+(?:.*(?:token|password|passwd|secret|credential|authorization|api[-_]?key)|auth|key|header|env|config|data|data-raw|data-binary|message|prompt)|-[uHpmd])$/i.test(arg)) hideNext = true;
|
|
26481
|
+
if (/(?:token|password|passwd|secret|credential|authorization|api[-_]?key)\s*[=:]|(?:^|[/\\])(?:\.env(?:\.|$)|credentials|\.npmrc)|:\/\/|[\x00-\x1f\x7f]|[A-Za-z0-9+/_=-]{40,}/i.test(arg)) return "[redacted]";
|
|
26482
|
+
return arg.length <= 96 && /^[A-Za-z0-9 _./\\:@()+=-]+$/.test(arg) ? arg.includes(" ") ? JSON.stringify(arg) : arg : "[value]";
|
|
26483
|
+
});
|
|
26484
|
+
return [name2, ...safe, ...Array.isArray(meta3.args) && meta3.args.length > 24 ? ["\u2026"] : []].join(" ").slice(0, 240);
|
|
26485
|
+
}
|
|
26486
|
+
|
|
26487
|
+
// src/process.ts
|
|
26488
|
+
import { statSync } from "node:fs";
|
|
26489
|
+
import path6 from "node:path";
|
|
26490
|
+
var WINDOWS_LAUNCH_EXTENSIONS = [".com", ".exe", ".bat", ".cmd"];
|
|
26491
|
+
function envValue(env, name2) {
|
|
26492
|
+
const key = Object.keys(env).find((k) => k.toUpperCase() === name2.toUpperCase());
|
|
26493
|
+
return key === void 0 ? void 0 : env[key];
|
|
26494
|
+
}
|
|
26495
|
+
function resolveWindowsLauncher(commandName, env = process.env) {
|
|
26496
|
+
const extensions = (envValue(env, "PATHEXT") || ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.trim().toLowerCase()).filter((ext) => WINDOWS_LAUNCH_EXTENSIONS.includes(ext));
|
|
26497
|
+
for (const entry of (envValue(env, "PATH") ?? "").split(";")) {
|
|
26498
|
+
const dir = entry.trim().replace(/^"(.*)"$/, "$1");
|
|
26499
|
+
if (!path6.win32.isAbsolute(dir)) continue;
|
|
26500
|
+
for (const ext of extensions) {
|
|
26501
|
+
const file2 = path6.win32.join(dir, commandName + ext);
|
|
26502
|
+
try {
|
|
26503
|
+
if (statSync(file2).isFile()) return { file: file2, shell: ext === ".bat" || ext === ".cmd" };
|
|
26504
|
+
} catch {
|
|
26505
|
+
}
|
|
26506
|
+
}
|
|
26507
|
+
}
|
|
26508
|
+
return void 0;
|
|
26509
|
+
}
|
|
26510
|
+
|
|
26511
|
+
// src/host-memory.ts
|
|
26512
|
+
var Entry = external_exports.strictObject({
|
|
26513
|
+
id: external_exports.string().regex(/^[a-f0-9]{16}$/),
|
|
26514
|
+
command: external_exports.string().max(240).refine((v) => !/[\x00-\x1f\x7f]/.test(v)),
|
|
26515
|
+
directory: external_exports.string().max(96).nullable(),
|
|
26516
|
+
outcome: external_exports.enum(["succeeded", "failed"]),
|
|
26517
|
+
code: external_exports.enum(["EXIT_NONZERO", "TIMED_OUT", "INCOMPLETE", "NOT_FOUND", "NOT_ALLOWED", "COMMAND_ERROR"]).nullable(),
|
|
26518
|
+
exitCode: external_exports.number().int().nullable(),
|
|
26519
|
+
at: external_exports.number().int().positive(),
|
|
26520
|
+
count: external_exports.number().int().min(1).max(1e6)
|
|
26521
|
+
});
|
|
26522
|
+
var State = external_exports.strictObject({ version: external_exports.literal(1), platform: external_exports.string().max(16), entries: external_exports.array(Entry).max(32) });
|
|
26523
|
+
var HostMemory = class {
|
|
26524
|
+
constructor(file2, allowed, programs) {
|
|
26525
|
+
this.file = file2;
|
|
26526
|
+
this.allowed = allowed;
|
|
26527
|
+
this.programs = programs;
|
|
26528
|
+
}
|
|
26529
|
+
file;
|
|
26530
|
+
allowed;
|
|
26531
|
+
programs;
|
|
26532
|
+
entries = [];
|
|
26533
|
+
loaded;
|
|
26534
|
+
writing = Promise.resolve();
|
|
26535
|
+
errors = 0;
|
|
26536
|
+
facts;
|
|
26537
|
+
async load() {
|
|
26538
|
+
this.loaded ??= (async () => {
|
|
26539
|
+
try {
|
|
26540
|
+
const stat = await lstat4(this.file);
|
|
26541
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32768) throw Error("HOST_MEMORY_INVALID");
|
|
26542
|
+
const data = State.parse(JSON.parse(await readFile3(this.file, "utf8")));
|
|
26543
|
+
if (data.platform === process.platform) this.entries = data.entries.filter((e) => e.at <= Date.now() && Date.now() - e.at < 30 * 864e5);
|
|
26544
|
+
} catch (error62) {
|
|
26545
|
+
if (error62.code !== "ENOENT") this.errors++;
|
|
26546
|
+
}
|
|
26547
|
+
})();
|
|
26548
|
+
await this.loaded;
|
|
26549
|
+
}
|
|
26550
|
+
discover() {
|
|
26551
|
+
const commands = this.allowed.slice(0, 32).filter((name2) => /^[A-Za-z0-9_.-]{1,40}$/.test(name2)).map((command) => {
|
|
26552
|
+
let available = command === "node" && !this.programs;
|
|
26553
|
+
if (this.programs) {
|
|
26554
|
+
try {
|
|
26555
|
+
const executable = this.programs[command];
|
|
26556
|
+
available = !!executable && path7.isAbsolute(executable) && statSync2(executable).isFile();
|
|
26557
|
+
} catch {
|
|
26558
|
+
available = false;
|
|
26559
|
+
}
|
|
26560
|
+
}
|
|
26561
|
+
if (!this.programs && !available && process.platform === "win32") available = !!resolveWindowsLauncher(command);
|
|
26562
|
+
else if (!this.programs && !available) available = (process.env.PATH ?? "").split(path7.delimiter).some((dir) => {
|
|
26563
|
+
if (!path7.isAbsolute(dir)) return false;
|
|
26564
|
+
try {
|
|
26565
|
+
const file2 = path7.join(dir, command);
|
|
26566
|
+
accessSync(file2, constants3.X_OK);
|
|
26567
|
+
return statSync2(file2).isFile();
|
|
26568
|
+
} catch {
|
|
26569
|
+
return false;
|
|
26570
|
+
}
|
|
26571
|
+
});
|
|
26572
|
+
return { command, available, registeredOrAllowed: true };
|
|
26573
|
+
});
|
|
26574
|
+
return {
|
|
26575
|
+
platform: process.platform,
|
|
26576
|
+
os: os2.type(),
|
|
26577
|
+
release: os2.release(),
|
|
26578
|
+
architecture: process.arch,
|
|
26579
|
+
node: process.version,
|
|
26580
|
+
shell: process.platform === "win32" ? "Windows; prefer available powershell/pwsh or structured argv" : "POSIX; structured argv",
|
|
26581
|
+
commands,
|
|
26582
|
+
commandsTruncated: this.allowed.length > 32,
|
|
26583
|
+
packages: "Executable availability only; package versions are not inferred",
|
|
26584
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26585
|
+
};
|
|
26586
|
+
}
|
|
26587
|
+
async context() {
|
|
26588
|
+
await this.load();
|
|
26589
|
+
if (!this.facts || Date.now() - this.facts.at > 6e4) this.facts = { at: Date.now(), value: this.discover() };
|
|
26590
|
+
return {
|
|
26591
|
+
system: this.facts.value,
|
|
26592
|
+
workedCommands: this.entries.filter((e) => e.outcome === "succeeded").slice(-8).reverse(),
|
|
26593
|
+
recentFailures: this.entries.filter((e) => e.outcome === "failed").slice(-8).reverse(),
|
|
26594
|
+
persistenceErrors: this.errors,
|
|
26595
|
+
guidance: (process.platform === "win32" ? "This is Windows: do not assume Bash exists. Use an available approved shell or structured argv. " : "") + "Use current system facts before discovery. Success is observed exit 0, not approval for reuse. Failures are hints; permissions remain unchanged."
|
|
26596
|
+
};
|
|
26597
|
+
}
|
|
26598
|
+
async record(request, result2, error62) {
|
|
26599
|
+
await this.load();
|
|
26600
|
+
const command = commandPreview("command_run", request);
|
|
26601
|
+
const directory = contextSummary({ cwd: request.cwd }).directory;
|
|
26602
|
+
const complete = !!result2 && result2.exitCode !== null && !result2.timedOut && !result2.signal && !result2.descendantsHeldOutput && !result2.stdinFailed && !result2.cancelled && result2.treeTerminated !== false;
|
|
26603
|
+
const succeeded = complete && result2.exitCode === 0;
|
|
26604
|
+
const errorCode = error62?.code;
|
|
26605
|
+
const message2 = error62 instanceof Error ? error62.message : "";
|
|
26606
|
+
const code = succeeded ? null : result2?.timedOut ? "TIMED_OUT" : result2 && !complete ? "INCOMPLETE" : errorCode === "ENOENT" || errorCode === "COMMAND_NOT_FOUND" ? "NOT_FOUND" : message2.includes("is not allowed") || errorCode === "COMMAND_NOT_ALLOWED" || errorCode === "LOCAL_PERMISSION_REQUIRED" ? "NOT_ALLOWED" : result2 ? "EXIT_NONZERO" : "COMMAND_ERROR";
|
|
26607
|
+
const id2 = createHash9("sha256").update(command + "\n" + (directory ?? "") + "\n" + (succeeded ? "succeeded" : "failed")).digest("hex").slice(0, 16);
|
|
26608
|
+
const old = this.entries.find((e) => e.id === id2);
|
|
26609
|
+
this.entries = this.entries.filter((e) => e.id !== id2);
|
|
26610
|
+
this.entries.push({
|
|
26611
|
+
id: id2,
|
|
26612
|
+
command,
|
|
26613
|
+
directory,
|
|
26614
|
+
outcome: succeeded ? "succeeded" : "failed",
|
|
26615
|
+
code,
|
|
26616
|
+
exitCode: result2?.exitCode ?? null,
|
|
26617
|
+
at: Date.now(),
|
|
26618
|
+
count: Math.min(1e6, (old?.count ?? 0) + 1)
|
|
26619
|
+
});
|
|
26620
|
+
this.entries = this.entries.slice(-32);
|
|
26621
|
+
const encoded = JSON.stringify({ version: 1, platform: process.platform, entries: this.entries }) + "\n";
|
|
26622
|
+
this.writing = this.writing.then(async () => {
|
|
26623
|
+
const directory2 = path7.dirname(this.file), temp = this.file + "." + process.pid + ".tmp";
|
|
26624
|
+
await mkdir3(directory2, { recursive: true, mode: 448 });
|
|
26625
|
+
const stat = await lstat4(directory2);
|
|
26626
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) throw Error("HOST_MEMORY_DIRECTORY_INVALID");
|
|
26627
|
+
const file2 = await open4(temp, "wx", 384);
|
|
26628
|
+
try {
|
|
26629
|
+
await file2.writeFile(encoded);
|
|
26630
|
+
await file2.close();
|
|
26631
|
+
await rename3(temp, this.file);
|
|
26632
|
+
} finally {
|
|
26633
|
+
await file2.close().catch(() => {
|
|
26634
|
+
});
|
|
26635
|
+
await rm3(temp, { force: true }).catch(() => {
|
|
26636
|
+
});
|
|
26637
|
+
}
|
|
26638
|
+
}).catch(() => {
|
|
26639
|
+
this.errors++;
|
|
26640
|
+
});
|
|
26641
|
+
}
|
|
26642
|
+
};
|
|
26643
|
+
|
|
26343
26644
|
// agent/src/tools.ts
|
|
26344
|
-
import { constants as
|
|
26345
|
-
import { lstat as
|
|
26346
|
-
import
|
|
26347
|
-
import { createHash as
|
|
26645
|
+
import { constants as constants4 } from "node:fs";
|
|
26646
|
+
import { lstat as lstat6, open as open5, readdir as readdir3, realpath as realpath5, rename as rename4, rm as rm4 } from "node:fs/promises";
|
|
26647
|
+
import path11 from "node:path";
|
|
26648
|
+
import { createHash as createHash10, randomUUID as randomUUID4 } from "node:crypto";
|
|
26348
26649
|
|
|
26349
26650
|
// src/guard.ts
|
|
26350
|
-
import { lstat as
|
|
26351
|
-
import
|
|
26651
|
+
import { lstat as lstat5, realpath as realpath4 } from "node:fs/promises";
|
|
26652
|
+
import path8 from "node:path";
|
|
26352
26653
|
var SENSITIVE_NAMES = /* @__PURE__ */ new Set([
|
|
26353
26654
|
".npmrc",
|
|
26354
26655
|
".pypirc",
|
|
@@ -26385,12 +26686,12 @@ function comparePath(value) {
|
|
|
26385
26686
|
return process.platform === "win32" ? value.toLowerCase() : value;
|
|
26386
26687
|
}
|
|
26387
26688
|
function isInside(root, candidate) {
|
|
26388
|
-
const relative =
|
|
26389
|
-
return relative === "" || !
|
|
26689
|
+
const relative = path8.relative(root, candidate);
|
|
26690
|
+
return relative === "" || !path8.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path8.sep}`);
|
|
26390
26691
|
}
|
|
26391
26692
|
function splitPathSegments(filePath) {
|
|
26392
|
-
const parsed =
|
|
26393
|
-
return
|
|
26693
|
+
const parsed = path8.parse(path8.resolve(filePath));
|
|
26694
|
+
return path8.relative(parsed.root, path8.resolve(filePath)).split(path8.sep).filter((segment) => segment.length > 0);
|
|
26394
26695
|
}
|
|
26395
26696
|
function isProtectedAuditFile(base) {
|
|
26396
26697
|
return base === ".local-commander-audit.jsonl" || base.startsWith(".local-commander-audit.jsonl.");
|
|
@@ -26405,40 +26706,40 @@ function looksProtected(filePath) {
|
|
|
26405
26706
|
return false;
|
|
26406
26707
|
}
|
|
26407
26708
|
function looksSensitive(filePath) {
|
|
26408
|
-
const base =
|
|
26709
|
+
const base = path8.basename(filePath).toLowerCase();
|
|
26409
26710
|
if (base === ".env" || base.startsWith(".env.") && base !== ".env.example") return true;
|
|
26410
26711
|
if (SENSITIVE_NAMES.has(base)) return true;
|
|
26411
|
-
if (SENSITIVE_EXTENSIONS.has(
|
|
26712
|
+
if (SENSITIVE_EXTENSIONS.has(path8.extname(base))) return true;
|
|
26412
26713
|
const segments = splitPathSegments(filePath).map((segment) => segment.toLowerCase());
|
|
26413
26714
|
if (segments.slice(0, -1).some((segment) => SENSITIVE_DIRECTORIES.has(segment))) return true;
|
|
26414
26715
|
const parent = segments.at(-2);
|
|
26415
26716
|
return SENSITIVE_IN_DIRECTORY.some(([directory, name2]) => directory === parent && name2 === base);
|
|
26416
26717
|
}
|
|
26417
26718
|
async function canonicalizePossiblyMissing(inputPath, base) {
|
|
26418
|
-
const absolute2 =
|
|
26419
|
-
const parsed =
|
|
26719
|
+
const absolute2 = path8.isAbsolute(inputPath) ? path8.resolve(inputPath) : path8.resolve(base, inputPath);
|
|
26720
|
+
const parsed = path8.parse(absolute2);
|
|
26420
26721
|
let current2 = absolute2;
|
|
26421
26722
|
const missing = [];
|
|
26422
26723
|
while (current2 !== parsed.root) {
|
|
26423
26724
|
try {
|
|
26424
26725
|
const resolved = await realpath4(current2);
|
|
26425
|
-
return
|
|
26726
|
+
return path8.join(resolved, ...missing.reverse());
|
|
26426
26727
|
} catch (error62) {
|
|
26427
26728
|
if (error62.code !== "ENOENT") throw error62;
|
|
26428
26729
|
let exists = false;
|
|
26429
26730
|
try {
|
|
26430
|
-
await
|
|
26731
|
+
await lstat5(current2);
|
|
26431
26732
|
exists = true;
|
|
26432
26733
|
} catch (statError) {
|
|
26433
26734
|
if (statError.code !== "ENOENT") throw statError;
|
|
26434
26735
|
}
|
|
26435
26736
|
if (exists) throw error62;
|
|
26436
|
-
missing.push(
|
|
26437
|
-
current2 =
|
|
26737
|
+
missing.push(path8.basename(current2));
|
|
26738
|
+
current2 = path8.dirname(current2);
|
|
26438
26739
|
}
|
|
26439
26740
|
}
|
|
26440
26741
|
const root = await realpath4(parsed.root);
|
|
26441
|
-
return
|
|
26742
|
+
return path8.join(root, ...missing.reverse());
|
|
26442
26743
|
}
|
|
26443
26744
|
var PathGuard = class _PathGuard {
|
|
26444
26745
|
constructor(roots, allowSensitiveFiles, protectedPaths) {
|
|
@@ -26454,11 +26755,11 @@ var PathGuard = class _PathGuard {
|
|
|
26454
26755
|
for (const root of roots) {
|
|
26455
26756
|
let resolved;
|
|
26456
26757
|
try {
|
|
26457
|
-
resolved = await realpath4(
|
|
26758
|
+
resolved = await realpath4(path8.resolve(root));
|
|
26458
26759
|
} catch {
|
|
26459
26760
|
throw new Error(`Configured root does not exist: ${root}`);
|
|
26460
26761
|
}
|
|
26461
|
-
const stat = await
|
|
26762
|
+
const stat = await lstat5(resolved);
|
|
26462
26763
|
if (!stat.isDirectory()) throw new Error(`Configured root is not a directory: ${root}`);
|
|
26463
26764
|
if (!canonical2.some((existing) => comparePath(existing) === comparePath(resolved))) {
|
|
26464
26765
|
canonical2.push(resolved);
|
|
@@ -26467,8 +26768,8 @@ var PathGuard = class _PathGuard {
|
|
|
26467
26768
|
if (canonical2.length === 0) throw new Error("At least one allowed root is required");
|
|
26468
26769
|
const protectedPaths = [];
|
|
26469
26770
|
for (const protectedPath of options.protectedPaths ?? []) {
|
|
26470
|
-
const base =
|
|
26471
|
-
const absolute2 =
|
|
26771
|
+
const base = path8.isAbsolute(protectedPath) ? path8.parse(path8.resolve(protectedPath)).root : canonical2[0];
|
|
26772
|
+
const absolute2 = path8.resolve(base, protectedPath);
|
|
26472
26773
|
if (!protectedPaths.some((existing) => comparePath(existing) === comparePath(absolute2))) protectedPaths.push(absolute2);
|
|
26473
26774
|
const resolved = await canonicalizePossiblyMissing(protectedPath, base);
|
|
26474
26775
|
if (!protectedPaths.some((existing) => comparePath(existing) === comparePath(resolved))) {
|
|
@@ -26484,7 +26785,7 @@ var PathGuard = class _PathGuard {
|
|
|
26484
26785
|
}
|
|
26485
26786
|
assertNotProtected(candidate) {
|
|
26486
26787
|
if (looksProtected(candidate)) {
|
|
26487
|
-
throw new Error(`Local Commander protected state is blocked: ${
|
|
26788
|
+
throw new Error(`Local Commander protected state is blocked: ${path8.basename(candidate)}`);
|
|
26488
26789
|
}
|
|
26489
26790
|
const normalizedCandidate = comparePath(candidate);
|
|
26490
26791
|
for (const protectedPath of this.protectedPaths) {
|
|
@@ -26497,13 +26798,13 @@ var PathGuard = class _PathGuard {
|
|
|
26497
26798
|
this.assertNotProtected(filePath);
|
|
26498
26799
|
if (!this.allowSensitiveFiles && looksSensitive(filePath)) {
|
|
26499
26800
|
throw new Error(
|
|
26500
|
-
`Sensitive file access is blocked by default: ${
|
|
26801
|
+
`Sensitive file access is blocked by default: ${path8.basename(filePath)}. Enable files.allowSensitiveFiles only if you really need it.`
|
|
26501
26802
|
);
|
|
26502
26803
|
}
|
|
26503
26804
|
}
|
|
26504
26805
|
async resolveExisting(inputPath, cwd) {
|
|
26505
26806
|
const base = cwd ? await this.resolveExisting(cwd) : this.roots[0];
|
|
26506
|
-
const candidate =
|
|
26807
|
+
const candidate = path8.isAbsolute(inputPath) ? path8.resolve(inputPath) : path8.resolve(base, inputPath);
|
|
26507
26808
|
this.assertNotProtected(candidate);
|
|
26508
26809
|
const resolved = await realpath4(candidate);
|
|
26509
26810
|
this.assertWithinRoots(resolved);
|
|
@@ -26512,13 +26813,13 @@ var PathGuard = class _PathGuard {
|
|
|
26512
26813
|
}
|
|
26513
26814
|
async resolveDirectory(inputPath, cwd) {
|
|
26514
26815
|
const resolved = await this.resolveExisting(inputPath, cwd);
|
|
26515
|
-
const stat = await
|
|
26816
|
+
const stat = await lstat5(resolved);
|
|
26516
26817
|
if (!stat.isDirectory()) throw new Error(`Not a directory: ${resolved}`);
|
|
26517
26818
|
return resolved;
|
|
26518
26819
|
}
|
|
26519
26820
|
async resolveForWrite(inputPath, cwd) {
|
|
26520
26821
|
const base = cwd ? await this.resolveDirectory(cwd) : this.roots[0];
|
|
26521
|
-
const candidate =
|
|
26822
|
+
const candidate = path8.isAbsolute(inputPath) ? path8.resolve(inputPath) : path8.resolve(base, inputPath);
|
|
26522
26823
|
this.assertNotProtected(candidate);
|
|
26523
26824
|
let existing;
|
|
26524
26825
|
try {
|
|
@@ -26527,7 +26828,7 @@ var PathGuard = class _PathGuard {
|
|
|
26527
26828
|
if (error62.code !== "ENOENT") throw error62;
|
|
26528
26829
|
let exists = false;
|
|
26529
26830
|
try {
|
|
26530
|
-
await
|
|
26831
|
+
await lstat5(candidate);
|
|
26531
26832
|
exists = true;
|
|
26532
26833
|
} catch (statError) {
|
|
26533
26834
|
if (statError.code !== "ENOENT") throw statError;
|
|
@@ -26540,11 +26841,11 @@ var PathGuard = class _PathGuard {
|
|
|
26540
26841
|
this.assertSafeFile(existing);
|
|
26541
26842
|
return existing;
|
|
26542
26843
|
}
|
|
26543
|
-
const parent = await realpath4(
|
|
26844
|
+
const parent = await realpath4(path8.dirname(candidate));
|
|
26544
26845
|
this.assertWithinRoots(parent);
|
|
26545
26846
|
this.assertNotProtected(parent);
|
|
26546
26847
|
this.assertSafeFile(candidate);
|
|
26547
|
-
const target =
|
|
26848
|
+
const target = path8.join(parent, path8.basename(candidate));
|
|
26548
26849
|
this.assertSafeFile(target);
|
|
26549
26850
|
return target;
|
|
26550
26851
|
}
|
|
@@ -26555,12 +26856,12 @@ var PathGuard = class _PathGuard {
|
|
|
26555
26856
|
|
|
26556
26857
|
// src/windows-file-read.ts
|
|
26557
26858
|
import { execFile } from "node:child_process";
|
|
26558
|
-
import
|
|
26859
|
+
import path9 from "node:path";
|
|
26559
26860
|
function readWindowsFile(bridge, file2, maxBytes, signal) {
|
|
26560
26861
|
return invokeRead(bridge, file2, maxBytes, false, signal);
|
|
26561
26862
|
}
|
|
26562
26863
|
function invokeRead(bridge, file2, maxBytes, prefix, signal) {
|
|
26563
|
-
if (process.platform !== "win32" || !
|
|
26864
|
+
if (process.platform !== "win32" || !path9.isAbsolute(bridge) || !path9.isAbsolute(file2) || !Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > (prefix ? 16777216 : 1048576)) {
|
|
26564
26865
|
return Promise.reject(new Error("FILE_READ_ARGUMENT_INVALID"));
|
|
26565
26866
|
}
|
|
26566
26867
|
if (signal?.aborted) return Promise.reject(new Error("CANCELLED"));
|
|
@@ -26587,31 +26888,11 @@ function invokeRead(bridge, file2, maxBytes, prefix, signal) {
|
|
|
26587
26888
|
});
|
|
26588
26889
|
}
|
|
26589
26890
|
|
|
26590
|
-
// src/process.ts
|
|
26591
|
-
import { statSync } from "node:fs";
|
|
26592
|
-
import path8 from "node:path";
|
|
26593
|
-
var WINDOWS_LAUNCH_EXTENSIONS = [".com", ".exe", ".bat", ".cmd"];
|
|
26594
|
-
function resolveWindowsLauncher(commandName, env = process.env) {
|
|
26595
|
-
const extensions = (env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.trim().toLowerCase()).filter((ext) => WINDOWS_LAUNCH_EXTENSIONS.includes(ext));
|
|
26596
|
-
for (const entry of (env.PATH ?? "").split(";")) {
|
|
26597
|
-
const dir = entry.trim().replace(/^"(.*)"$/, "$1");
|
|
26598
|
-
if (!path8.win32.isAbsolute(dir)) continue;
|
|
26599
|
-
for (const ext of extensions) {
|
|
26600
|
-
const file2 = path8.win32.join(dir, commandName + ext);
|
|
26601
|
-
try {
|
|
26602
|
-
if (statSync(file2).isFile()) return { file: file2, shell: ext === ".bat" || ext === ".cmd" };
|
|
26603
|
-
} catch {
|
|
26604
|
-
}
|
|
26605
|
-
}
|
|
26606
|
-
}
|
|
26607
|
-
return void 0;
|
|
26608
|
-
}
|
|
26609
|
-
|
|
26610
26891
|
// agent/src/job-supervisor.ts
|
|
26611
26892
|
import { spawn as spawn2 } from "node:child_process";
|
|
26612
|
-
import
|
|
26893
|
+
import path10 from "node:path";
|
|
26613
26894
|
function absolute(value) {
|
|
26614
|
-
return typeof value === "string" && value.length > 0 && value.length < 32767 && !value.includes("\0") &&
|
|
26895
|
+
return typeof value === "string" && value.length > 0 && value.length < 32767 && !value.includes("\0") && path10.isAbsolute(value) && path10.resolve(value) === value;
|
|
26615
26896
|
}
|
|
26616
26897
|
async function runSupervised(helper, request, options = {}) {
|
|
26617
26898
|
if (process.platform !== "win32") throw Error("WINDOWS_SUPERVISOR_REQUIRED");
|
|
@@ -26627,7 +26908,7 @@ async function runSupervised(helper, request, options = {}) {
|
|
|
26627
26908
|
let pid = null, outcome = null;
|
|
26628
26909
|
let buffer = "", failure5 = null, closed = false, cancelSent = false;
|
|
26629
26910
|
let killTimer, hardTimer;
|
|
26630
|
-
const child = spawn2(helper, [], { cwd:
|
|
26911
|
+
const child = spawn2(helper, [], { cwd: path10.dirname(helper), stdio: ["pipe", "pipe", "pipe"], windowsHide: true, shell: false, env: buildChildEnvironment(process.env) });
|
|
26631
26912
|
const cancel = () => {
|
|
26632
26913
|
if (closed || cancelSent) return;
|
|
26633
26914
|
cancelSent = true;
|
|
@@ -26782,7 +27063,7 @@ function fail2(code) {
|
|
|
26782
27063
|
throw new NativeToolError(code);
|
|
26783
27064
|
}
|
|
26784
27065
|
function hash5(value) {
|
|
26785
|
-
return
|
|
27066
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
26786
27067
|
}
|
|
26787
27068
|
function equalPath3(a, b) {
|
|
26788
27069
|
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
@@ -26796,10 +27077,10 @@ function stopped(signal) {
|
|
|
26796
27077
|
if (signal.aborted) fail2("CANCELLED");
|
|
26797
27078
|
}
|
|
26798
27079
|
async function readBoundedFile(file2, maxBytes, bridge, signal) {
|
|
26799
|
-
const stat = await
|
|
27080
|
+
const stat = await lstat6(file2);
|
|
26800
27081
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > maxBytes) fail2("FILE_UNSUPPORTED_OR_TOO_LARGE");
|
|
26801
27082
|
if (process.platform === "win32") return readWindowsFile(bridge, file2, maxBytes, signal);
|
|
26802
|
-
const handle = await
|
|
27083
|
+
const handle = await open5(file2, constants4.O_RDONLY | (constants4.O_NOFOLLOW ?? 0));
|
|
26803
27084
|
try {
|
|
26804
27085
|
const current2 = await handle.stat();
|
|
26805
27086
|
if (!current2.isFile() || current2.size > maxBytes) fail2("FILE_UNSUPPORTED_OR_TOO_LARGE");
|
|
@@ -26830,11 +27111,13 @@ var NativeTools = class {
|
|
|
26830
27111
|
constructor(options) {
|
|
26831
27112
|
this.options = options;
|
|
26832
27113
|
this.options = structuredClone(options);
|
|
27114
|
+
this.memory = new HostMemory(path11.join(options.stateDirectory, "host-memory.json"), Object.keys(options.programs), Object.fromEntries(Object.entries(options.programs).map(([name2, program]) => [name2, program.executable])));
|
|
26833
27115
|
}
|
|
26834
27116
|
options;
|
|
27117
|
+
memory;
|
|
26835
27118
|
async readFile(file2, maxBytes, signal) {
|
|
26836
27119
|
try {
|
|
26837
|
-
return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ??
|
|
27120
|
+
return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path11.join(path11.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
|
|
26838
27121
|
} catch (error62) {
|
|
26839
27122
|
if (error62.code === "ENOENT") throw error62;
|
|
26840
27123
|
if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail2(error62.message);
|
|
@@ -26842,7 +27125,15 @@ var NativeTools = class {
|
|
|
26842
27125
|
}
|
|
26843
27126
|
}
|
|
26844
27127
|
async prepare(workspace, candidate) {
|
|
26845
|
-
|
|
27128
|
+
let prepared;
|
|
27129
|
+
try {
|
|
27130
|
+
prepared = await this.prepareTool(workspace, candidate);
|
|
27131
|
+
} catch (error62) {
|
|
27132
|
+
const parsed = ToolCallSchema.safeParse(candidate);
|
|
27133
|
+
if (parsed.success && parsed.data.name === "command_run") await this.memory.record({ ...parsed.data.args, cwd: path11.resolve(workspace.root, parsed.data.args.cwd ?? ".") }, void 0, error62).catch(() => {
|
|
27134
|
+
});
|
|
27135
|
+
throw error62;
|
|
27136
|
+
}
|
|
26846
27137
|
prepared.effective = structuredClone({
|
|
26847
27138
|
call: prepared.call,
|
|
26848
27139
|
claims: prepared.claims,
|
|
@@ -26859,15 +27150,15 @@ var NativeTools = class {
|
|
|
26859
27150
|
try {
|
|
26860
27151
|
const canonical2 = await realpath5(workspace.root);
|
|
26861
27152
|
if (!equalPath3(canonical2, workspace.root) || hash5(process.platform === "win32" ? canonical2.toLowerCase() : canonical2) !== workspace.rootHash) fail2("WORKSPACE_CHANGED");
|
|
26862
|
-
const runtimeDirectory =
|
|
27153
|
+
const runtimeDirectory = path11.dirname(this.options.helperPath);
|
|
26863
27154
|
const protectedPaths = [
|
|
26864
27155
|
this.options.stateDirectory,
|
|
26865
27156
|
this.options.helperPath,
|
|
26866
|
-
...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe"].map((name2) =>
|
|
27157
|
+
...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe"].map((name2) => path11.join(runtimeDirectory, name2))
|
|
26867
27158
|
];
|
|
26868
27159
|
if (this.options.ownerBridgePath) protectedPaths.push(this.options.ownerBridgePath);
|
|
26869
|
-
if (process.platform === "win32" && process.env.LOCALAPPDATA &&
|
|
26870
|
-
protectedPaths.push(
|
|
27160
|
+
if (process.platform === "win32" && process.env.LOCALAPPDATA && path11.isAbsolute(process.env.LOCALAPPDATA)) {
|
|
27161
|
+
protectedPaths.push(path11.join(process.env.LOCALAPPDATA, "LocalCommander"));
|
|
26871
27162
|
}
|
|
26872
27163
|
guard = await PathGuard.create([canonical2], false, { protectedPaths });
|
|
26873
27164
|
} catch (e) {
|
|
@@ -26899,7 +27190,7 @@ var NativeTools = class {
|
|
|
26899
27190
|
const bytes3 = await this.readFile(filename, 1048576, signal), contents = utf8(bytes3), lines = contents.split(/\r?\n/);
|
|
26900
27191
|
const selected = lines.slice(first - 1, Math.min(last, lines.length)).join("\n");
|
|
26901
27192
|
if (Buffer.byteLength(selected) > 12e4) fail2("OUTPUT_LIMIT_EXCEEDED");
|
|
26902
|
-
return result({ path:
|
|
27193
|
+
return result({ path: path11.relative(workspace.root, filename), sha256: hash5(bytes3), startLine: first, endLine: Math.min(last, lines.length), totalLines: lines.length, content: selected, truncated: last < lines.length });
|
|
26903
27194
|
} };
|
|
26904
27195
|
}
|
|
26905
27196
|
if (call.name === "fs_write" || call.name === "fs_replace") {
|
|
@@ -26935,8 +27226,8 @@ var NativeTools = class {
|
|
|
26935
27226
|
}
|
|
26936
27227
|
const bytes3 = Buffer.from(contents, "utf8");
|
|
26937
27228
|
if (bytes3.length > MAX_FILE_WRITE_BYTES) fail2("FILE_WRITE_LIMIT");
|
|
26938
|
-
const temp =
|
|
26939
|
-
const handle = await
|
|
27229
|
+
const temp = path11.join(path11.dirname(target), ".lc-write-" + randomUUID4() + ".tmp");
|
|
27230
|
+
const handle = await open5(temp, constants4.O_CREAT | constants4.O_EXCL | constants4.O_WRONLY, 384);
|
|
26940
27231
|
try {
|
|
26941
27232
|
await handle.writeFile(bytes3);
|
|
26942
27233
|
await handle.sync();
|
|
@@ -26946,17 +27237,17 @@ var NativeTools = class {
|
|
|
26946
27237
|
if (!equalPath3(target, again)) fail2("FILE_CHANGED");
|
|
26947
27238
|
if (old) {
|
|
26948
27239
|
if (hash5(await this.readFile(target, 1048576, signal)) !== hash5(old)) fail2("FILE_CHANGED");
|
|
26949
|
-
await
|
|
27240
|
+
await rename4(temp, target);
|
|
26950
27241
|
} else {
|
|
26951
27242
|
const { link } = await import("node:fs/promises");
|
|
26952
27243
|
await link(temp, target);
|
|
26953
|
-
await
|
|
27244
|
+
await rm4(temp);
|
|
26954
27245
|
}
|
|
26955
|
-
return result({ path:
|
|
27246
|
+
return result({ path: path11.relative(workspace.root, target), bytes: bytes3.length, sha256: hash5(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
|
|
26956
27247
|
} catch (e) {
|
|
26957
27248
|
await handle.close().catch(() => {
|
|
26958
27249
|
});
|
|
26959
|
-
await
|
|
27250
|
+
await rm4(temp, { force: true }).catch(() => {
|
|
26960
27251
|
});
|
|
26961
27252
|
throw e;
|
|
26962
27253
|
}
|
|
@@ -26973,12 +27264,12 @@ var NativeTools = class {
|
|
|
26973
27264
|
stopped(signal);
|
|
26974
27265
|
if (matches2.length >= call.args.maxResults || scanned >= 300) break;
|
|
26975
27266
|
try {
|
|
26976
|
-
const filename = await guard.resolveExisting(
|
|
27267
|
+
const filename = await guard.resolveExisting(path11.join(base, entry.path));
|
|
26977
27268
|
guard.assertSafeFile(filename);
|
|
26978
27269
|
const data = utf8(await this.readFile(filename, 256e3, signal));
|
|
26979
27270
|
scanned++;
|
|
26980
27271
|
const lines = data.split(/\r?\n/);
|
|
26981
|
-
for (let i = 0; i < lines.length && matches2.length < call.args.maxResults; i++) if ((call.args.caseSensitive ? lines[i] : lines[i].toLowerCase()).includes(query)) matches2.push({ path:
|
|
27272
|
+
for (let i = 0; i < lines.length && matches2.length < call.args.maxResults; i++) if ((call.args.caseSensitive ? lines[i] : lines[i].toLowerCase()).includes(query)) matches2.push({ path: path11.relative(workspace.root, filename), line: i + 1, text: lines[i].slice(0, 500) });
|
|
26982
27273
|
} catch (error62) {
|
|
26983
27274
|
if (error62 instanceof NativeToolError && ["FILE_READ_FAILED", "CANCELLED"].includes(error62.code)) throw error62;
|
|
26984
27275
|
}
|
|
@@ -27031,7 +27322,16 @@ var NativeTools = class {
|
|
|
27031
27322
|
const cwd2 = await resolve(call.args.cwd, true), program = await this.resolveProgram(call.args.command, workspace, call.args.args);
|
|
27032
27323
|
const claims2 = writeClaim(cwd2);
|
|
27033
27324
|
return { call, claims: claims2, execution: { ...program, cwd: cwd2 }, run: async (signal, onStarted, onOutput) => {
|
|
27034
|
-
|
|
27325
|
+
let r;
|
|
27326
|
+
try {
|
|
27327
|
+
r = await runSupervised(this.options.helperPath, { ...program, cwd: cwd2, timeoutMs: call.args.timeoutMs, maxProcesses: 32 }, { signal, maxOutputBytes: 9e4, onStarted, onOutput });
|
|
27328
|
+
} catch (error62) {
|
|
27329
|
+
await this.memory.record({ ...call.args, cwd: cwd2 }, void 0, error62).catch(() => {
|
|
27330
|
+
});
|
|
27331
|
+
throw error62;
|
|
27332
|
+
}
|
|
27333
|
+
await this.memory.record({ ...call.args, cwd: cwd2 }, r).catch(() => {
|
|
27334
|
+
});
|
|
27035
27335
|
const { pid: _pid, ...output2 } = r;
|
|
27036
27336
|
return { ...output2, resultCode: r.cancelled ? "CANCELLED" : r.timedOut ? "TIMEOUT" : r.exitCode === 0 ? "SUCCESS" : "USER_PROGRAM_FAILED" };
|
|
27037
27337
|
} };
|
|
@@ -27046,9 +27346,9 @@ var NativeTools = class {
|
|
|
27046
27346
|
else if (call.name === "git_diff") {
|
|
27047
27347
|
argv = ["diff", "--no-ext-diff", "--no-textconv", ...call.args.staged ? ["--cached"] : []];
|
|
27048
27348
|
if (call.args.file) {
|
|
27049
|
-
const file2 = await resolve(
|
|
27050
|
-
const relative =
|
|
27051
|
-
if (relative.startsWith(".." +
|
|
27349
|
+
const file2 = await resolve(path11.resolve(cwd, call.args.file));
|
|
27350
|
+
const relative = path11.relative(cwd, file2);
|
|
27351
|
+
if (relative.startsWith(".." + path11.sep) || relative === ".." || path11.isAbsolute(relative)) fail2("PATH_NOT_ALLOWED");
|
|
27052
27352
|
argv.push("--", relative);
|
|
27053
27353
|
} else argv.push("--stat");
|
|
27054
27354
|
} else fail2("TOOL_MISSING");
|
|
@@ -27059,7 +27359,7 @@ var NativeTools = class {
|
|
|
27059
27359
|
const listing = await this.list(guard, cwd, 1, call.args.startup ? 20 : 150, signal);
|
|
27060
27360
|
let packageInfo = null;
|
|
27061
27361
|
try {
|
|
27062
|
-
const name2 = await guard.resolveExisting(
|
|
27362
|
+
const name2 = await guard.resolveExisting(path11.join(cwd, "package.json"));
|
|
27063
27363
|
guard.assertSafeFile(name2);
|
|
27064
27364
|
const value = JSON.parse(utf8(await this.readFile(name2, 64e3, signal)));
|
|
27065
27365
|
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) : [] };
|
|
@@ -27079,7 +27379,7 @@ var NativeTools = class {
|
|
|
27079
27379
|
}
|
|
27080
27380
|
const contextFile = async (relative, limit, optional2 = false) => {
|
|
27081
27381
|
try {
|
|
27082
|
-
const file2 = await guard.resolveExisting(
|
|
27382
|
+
const file2 = await guard.resolveExisting(path11.join(primary, relative));
|
|
27083
27383
|
guard.assertSafeFile(file2);
|
|
27084
27384
|
return utf8(await this.readFile(file2, limit, signal));
|
|
27085
27385
|
} catch (error62) {
|
|
@@ -27095,6 +27395,7 @@ var NativeTools = class {
|
|
|
27095
27395
|
return result({
|
|
27096
27396
|
root: cwd,
|
|
27097
27397
|
primary,
|
|
27398
|
+
hostMemory: await this.memoryContext(workspace),
|
|
27098
27399
|
package: packageInfo,
|
|
27099
27400
|
git: status?.stdout ?? null,
|
|
27100
27401
|
files: listing,
|
|
@@ -27102,7 +27403,7 @@ var NativeTools = class {
|
|
|
27102
27403
|
task: call.args.taskId ? { taskId: call.args.taskId, entry: entry?.slice(0, 4096) ?? null, continuation: log?.slice(-4096) ?? null, truncated: !!entry && entry.length > 4096 || !!log && log.length > 4096 } : null
|
|
27103
27404
|
});
|
|
27104
27405
|
}
|
|
27105
|
-
return result({ root: workspace.displayName, files: listing, package: packageInfo, git: status?.stdout ?? null });
|
|
27406
|
+
return result({ root: workspace.displayName, hostMemory: await this.memoryContext(workspace), files: listing, package: packageInfo, git: status?.stdout ?? null });
|
|
27106
27407
|
}
|
|
27107
27408
|
if (!common) fail2("NOT_A_GIT_REPOSITORY");
|
|
27108
27409
|
const r = await runGit(signal, onStarted, onOutput);
|
|
@@ -27111,19 +27412,19 @@ var NativeTools = class {
|
|
|
27111
27412
|
} };
|
|
27112
27413
|
}
|
|
27113
27414
|
async resolveProgram(name2, workspace, args) {
|
|
27114
|
-
const entry = Object.entries(this.options.programs).find(([key, value]) => key.toLowerCase() === name2.toLowerCase() ||
|
|
27415
|
+
const entry = Object.entries(this.options.programs).find(([key, value]) => key.toLowerCase() === name2.toLowerCase() || path11.isAbsolute(name2) && equalPath3(value.executable, path11.resolve(name2)));
|
|
27115
27416
|
if (workspace.fullAccess) {
|
|
27116
|
-
const commandKey = (value) =>
|
|
27417
|
+
const commandKey = (value) => path11.basename(value).toLowerCase().replace(/\.(exe|com|cmd|bat)$/i, "");
|
|
27117
27418
|
const denied = new Set((workspace.deniedCommands ?? []).map(commandKey));
|
|
27118
27419
|
if (denied.has(commandKey(name2)) || entry && denied.has(commandKey(entry[0]))) fail2("COMMAND_NOT_ALLOWED");
|
|
27119
|
-
const extension2 =
|
|
27120
|
-
const candidate = entry?.[1].executable ?? (
|
|
27420
|
+
const extension2 = path11.extname(name2).toLowerCase();
|
|
27421
|
+
const candidate = entry?.[1].executable ?? (path11.isAbsolute(name2) ? name2 : /^[\w.-]+$/.test(name2) ? resolveWindowsLauncher(
|
|
27121
27422
|
commandKey(name2),
|
|
27122
27423
|
[".exe", ".com", ".cmd", ".bat"].includes(extension2) ? { ...process.env, PATHEXT: extension2 } : process.env
|
|
27123
27424
|
)?.file : void 0);
|
|
27124
|
-
if (!candidate || !
|
|
27425
|
+
if (!candidate || !path11.isAbsolute(candidate)) fail2("COMMAND_NOT_FOUND");
|
|
27125
27426
|
const executable = await realpath5(candidate).catch(() => fail2("COMMAND_NOT_FOUND"));
|
|
27126
|
-
if (!(await
|
|
27427
|
+
if (!(await lstat6(executable)).isFile()) fail2("COMMAND_NOT_FOUND");
|
|
27127
27428
|
if (denied.has(commandKey(executable))) fail2("COMMAND_NOT_ALLOWED");
|
|
27128
27429
|
for (const key of workspace.deniedCommands ?? []) {
|
|
27129
27430
|
const configured = this.options.programs[key]?.executable;
|
|
@@ -27136,7 +27437,7 @@ var NativeTools = class {
|
|
|
27136
27437
|
if (/\.(cmd|bat)$/i.test(executable)) {
|
|
27137
27438
|
if ([executable, ...args].some((value) => /[&|<>^%!"\r\n]/.test(value))) fail2("INVALID_SCRIPT_ARGUMENTS");
|
|
27138
27439
|
const literal2 = (value) => "'" + value.replaceAll("'", "''") + "'";
|
|
27139
|
-
const shell =
|
|
27440
|
+
const shell = path11.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
27140
27441
|
if (denied.has("powershell") || denied.has("cmd")) fail2("COMMAND_NOT_ALLOWED");
|
|
27141
27442
|
const script = "& " + literal2(executable) + " @(" + args.map(literal2).join(",") + "); exit $LASTEXITCODE";
|
|
27142
27443
|
return { executable: shell, args: ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")] };
|
|
@@ -27144,16 +27445,25 @@ var NativeTools = class {
|
|
|
27144
27445
|
if (!/\.(exe|com)$/i.test(executable)) fail2("COMMAND_NOT_ALLOWED");
|
|
27145
27446
|
return { executable, args: [...entry?.[1].prefixArgs ?? [], ...args] };
|
|
27146
27447
|
}
|
|
27147
|
-
if (!entry || !workspace.allowedCommands.some((v) => v.toLowerCase() === entry[0].toLowerCase()) || !
|
|
27448
|
+
if (!entry || !workspace.allowedCommands.some((v) => v.toLowerCase() === entry[0].toLowerCase()) || !path11.isAbsolute(entry[1].executable)) fail2("COMMAND_NOT_ALLOWED");
|
|
27148
27449
|
return { executable: entry[1].executable, args: [...entry[1].prefixArgs ?? [], ...args] };
|
|
27149
27450
|
}
|
|
27451
|
+
async memoryContext(workspace) {
|
|
27452
|
+
const context = await this.memory.context();
|
|
27453
|
+
const root = workspace.root.replaceAll("\\", "/").replace(/\/+$/, "").toLowerCase();
|
|
27454
|
+
const inWorkspace = (entry) => entry.directory !== null && (entry.directory.toLowerCase() === root || entry.directory.toLowerCase().startsWith(root + "/"));
|
|
27455
|
+
return { ...context, workedCommands: context.workedCommands.filter(inWorkspace), recentFailures: context.recentFailures.filter(inWorkspace), system: { ...context.system, commands: context.system.commands.map((item) => ({
|
|
27456
|
+
...item,
|
|
27457
|
+
permitted: workspace.permissions.executeCommands && (workspace.fullAccess ? !(workspace.deniedCommands ?? []).includes(item.command) : workspace.allowedCommands.includes(item.command))
|
|
27458
|
+
})) } };
|
|
27459
|
+
}
|
|
27150
27460
|
async gitExecution(cwd, args) {
|
|
27151
27461
|
const configured = this.options.programs.git;
|
|
27152
|
-
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 &&
|
|
27462
|
+
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 && path11.isAbsolute(root)).map(([root, suffix]) => path11.join(root, suffix, "cmd", "git.exe")) : [];
|
|
27153
27463
|
for (const candidate of candidates) {
|
|
27154
|
-
if (!
|
|
27464
|
+
if (!path11.isAbsolute(candidate)) continue;
|
|
27155
27465
|
try {
|
|
27156
|
-
const stat = await
|
|
27466
|
+
const stat = await lstat6(candidate);
|
|
27157
27467
|
if (!stat.isFile() || stat.isSymbolicLink() || !equalPath3(candidate, await realpath5(candidate))) continue;
|
|
27158
27468
|
} catch {
|
|
27159
27469
|
continue;
|
|
@@ -27177,7 +27487,7 @@ var NativeTools = class {
|
|
|
27177
27487
|
break;
|
|
27178
27488
|
}
|
|
27179
27489
|
if (item.isSymbolicLink() || excluded.has(item.name.toLowerCase())) continue;
|
|
27180
|
-
const candidate =
|
|
27490
|
+
const candidate = path11.join(current2.path, item.name);
|
|
27181
27491
|
let resolved;
|
|
27182
27492
|
try {
|
|
27183
27493
|
resolved = await guard.resolveExisting(candidate);
|
|
@@ -27187,11 +27497,11 @@ var NativeTools = class {
|
|
|
27187
27497
|
}
|
|
27188
27498
|
if (!equalPath3(candidate, resolved)) continue;
|
|
27189
27499
|
if (item.isDirectory()) {
|
|
27190
|
-
entries.push({ path:
|
|
27500
|
+
entries.push({ path: path11.relative(root, resolved), type: "directory" });
|
|
27191
27501
|
if (current2.level < depth) queue.push({ path: resolved, level: current2.level + 1 });
|
|
27192
27502
|
} else if (item.isFile()) {
|
|
27193
|
-
const stat = await
|
|
27194
|
-
entries.push({ path:
|
|
27503
|
+
const stat = await lstat6(resolved);
|
|
27504
|
+
entries.push({ path: path11.relative(root, resolved), type: "file", size: stat.size });
|
|
27195
27505
|
}
|
|
27196
27506
|
}
|
|
27197
27507
|
if (truncated) break;
|
|
@@ -27201,49 +27511,49 @@ var NativeTools = class {
|
|
|
27201
27511
|
async gitCommonDir(cwd, workspace, guard) {
|
|
27202
27512
|
let directory = cwd;
|
|
27203
27513
|
while (guard.isWithin(directory, workspace.root)) {
|
|
27204
|
-
const dotGit =
|
|
27514
|
+
const dotGit = path11.join(directory, ".git");
|
|
27205
27515
|
try {
|
|
27206
|
-
const stat = await
|
|
27516
|
+
const stat = await lstat6(dotGit);
|
|
27207
27517
|
if (stat.isSymbolicLink()) fail2("GIT_METADATA_CHANGED");
|
|
27208
27518
|
let gitDir;
|
|
27209
27519
|
if (stat.isDirectory()) gitDir = await realpath5(dotGit);
|
|
27210
27520
|
else {
|
|
27211
27521
|
const content = utf8(await this.readFile(dotGit, 4096)).trim();
|
|
27212
27522
|
if (!content.startsWith("gitdir: ")) fail2("GIT_METADATA_CHANGED");
|
|
27213
|
-
gitDir = await realpath5(
|
|
27523
|
+
gitDir = await realpath5(path11.resolve(directory, content.slice(8)));
|
|
27214
27524
|
}
|
|
27215
27525
|
if (guard.isWithin(gitDir, this.options.stateDirectory) || !guard.isWithin(gitDir, workspace.root) && (!workspace.gitCommonDir || !guard.isWithin(gitDir, workspace.gitCommonDir))) fail2("GIT_COMMON_DIRECTORY_NOT_APPROVED");
|
|
27216
27526
|
let common = gitDir;
|
|
27217
27527
|
try {
|
|
27218
|
-
const content = utf8(await this.readFile(
|
|
27528
|
+
const content = utf8(await this.readFile(path11.join(gitDir, "commondir"), 4096)).trim();
|
|
27219
27529
|
if (!content) fail2("GIT_METADATA_CHANGED");
|
|
27220
|
-
common = await realpath5(
|
|
27530
|
+
common = await realpath5(path11.resolve(gitDir, content));
|
|
27221
27531
|
} catch (e) {
|
|
27222
27532
|
if (e.code !== "ENOENT") throw e;
|
|
27223
27533
|
}
|
|
27224
|
-
if (!(await
|
|
27534
|
+
if (!(await lstat6(common)).isDirectory() || guard.isWithin(common, this.options.stateDirectory)) fail2("GIT_METADATA_CHANGED");
|
|
27225
27535
|
if (!guard.isWithin(common, workspace.root) && (!workspace.gitCommonDir || !equalPath3(common, workspace.gitCommonDir))) fail2("GIT_COMMON_DIRECTORY_NOT_APPROVED");
|
|
27226
27536
|
return common;
|
|
27227
27537
|
} catch (e) {
|
|
27228
27538
|
if (e.code !== "ENOENT") throw e;
|
|
27229
27539
|
}
|
|
27230
27540
|
if (equalPath3(directory, workspace.root)) break;
|
|
27231
|
-
directory =
|
|
27541
|
+
directory = path11.dirname(directory);
|
|
27232
27542
|
}
|
|
27233
27543
|
return null;
|
|
27234
27544
|
}
|
|
27235
27545
|
};
|
|
27236
27546
|
|
|
27237
27547
|
// agent/src/scheduler.ts
|
|
27238
|
-
import
|
|
27239
|
-
import
|
|
27548
|
+
import path12 from "node:path";
|
|
27549
|
+
import os3 from "node:os";
|
|
27240
27550
|
function canonical(value) {
|
|
27241
|
-
const p =
|
|
27551
|
+
const p = path12.resolve(value);
|
|
27242
27552
|
return process.platform === "win32" ? p.toLowerCase() : p;
|
|
27243
27553
|
}
|
|
27244
27554
|
function ancestor(a, b) {
|
|
27245
|
-
const relative =
|
|
27246
|
-
return relative === "" || !
|
|
27555
|
+
const relative = path12.relative(a, b);
|
|
27556
|
+
return relative === "" || !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path12.sep);
|
|
27247
27557
|
}
|
|
27248
27558
|
function claimsConflict(a, b) {
|
|
27249
27559
|
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))));
|
|
@@ -27251,7 +27561,7 @@ function claimsConflict(a, b) {
|
|
|
27251
27561
|
var NativeScheduler = class {
|
|
27252
27562
|
constructor(options = {}) {
|
|
27253
27563
|
this.options = options;
|
|
27254
|
-
const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2,
|
|
27564
|
+
const capacity = Math.max(1, Math.min(16, Math.floor(Math.max(2, os3.availableParallelism?.() ?? os3.cpus().length) / 2)));
|
|
27255
27565
|
this.safeSlots = options.safeSlots ?? capacity;
|
|
27256
27566
|
this.maxQueued = options.maxQueued ?? 32;
|
|
27257
27567
|
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");
|
|
@@ -27272,7 +27582,7 @@ var NativeScheduler = class {
|
|
|
27272
27582
|
schedule(id2, claims, deadlineAt, run, signal) {
|
|
27273
27583
|
if (!this.accepting) return Promise.reject(Error("AGENT_PAUSED"));
|
|
27274
27584
|
if (!id2 || id2.length > 100 || this.active.has(id2) || this.waiting.some((j) => j.id === id2)) return Promise.reject(Error("DUPLICATE_SCHEDULED_EXECUTION"));
|
|
27275
|
-
if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !
|
|
27585
|
+
if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !path12.isAbsolute(c.path) || !["read", "write"].includes(c.mode))) return Promise.reject(Error("INVALID_RESOURCE_CLAIM"));
|
|
27276
27586
|
const deadline = deadlineAt.getTime();
|
|
27277
27587
|
if (!Number.isFinite(deadline) || deadline <= Date.now()) return Promise.reject(Error("ADMISSION_DEADLINE_EXPIRED"));
|
|
27278
27588
|
if (signal?.aborted) return Promise.reject(Error("CANCELLED_BEFORE_ACCEPTANCE"));
|
|
@@ -27339,6 +27649,30 @@ var NativeScheduler = class {
|
|
|
27339
27649
|
}
|
|
27340
27650
|
};
|
|
27341
27651
|
|
|
27652
|
+
// packages/optimization/src/operation-library.mjs
|
|
27653
|
+
function compactJsonOutput(source) {
|
|
27654
|
+
if (typeof source !== "string" || Buffer.byteLength(source) > 1048576 || !/^\s*[\[{]/.test(source)) return null;
|
|
27655
|
+
try {
|
|
27656
|
+
JSON.parse(source);
|
|
27657
|
+
} catch {
|
|
27658
|
+
return null;
|
|
27659
|
+
}
|
|
27660
|
+
let quoted = false, escaped = false, compact = "";
|
|
27661
|
+
for (const ch of source) {
|
|
27662
|
+
if (quoted) {
|
|
27663
|
+
compact += ch;
|
|
27664
|
+
if (escaped) escaped = false;
|
|
27665
|
+
else if (ch === "\\") escaped = true;
|
|
27666
|
+
else if (ch === '"') quoted = false;
|
|
27667
|
+
} else if (ch === '"') {
|
|
27668
|
+
quoted = true;
|
|
27669
|
+
compact += ch;
|
|
27670
|
+
} else if (!/[ \t\r\n]/.test(ch)) compact += ch;
|
|
27671
|
+
}
|
|
27672
|
+
if (source.endsWith("\n")) compact += "\n";
|
|
27673
|
+
return Buffer.byteLength(compact) < Buffer.byteLength(source) ? compact : null;
|
|
27674
|
+
}
|
|
27675
|
+
|
|
27342
27676
|
// packages/optimization/src/parsers/node-tap.ts
|
|
27343
27677
|
var NODE_TAP_PARSER_ID = "node-tap";
|
|
27344
27678
|
var NODE_TAP_PARSER_VERSION = "1";
|
|
@@ -27706,6 +28040,23 @@ function shapeCommandResultForAgentDetailed(input2, result2) {
|
|
|
27706
28040
|
}
|
|
27707
28041
|
const source = capture(input2, result2);
|
|
27708
28042
|
const parsed = result2.exitCode === 0 ? parseNodeTapShadow(source) : parseNodeTapFailureShadow(source);
|
|
28043
|
+
if (parsed.state !== "candidate" && result2.exitCode === 0 && !result2.stdoutTruncated && !result2.stderrTruncated && result2.stderr === "") {
|
|
28044
|
+
const compact = compactJsonOutput(result2.stdout);
|
|
28045
|
+
if (compact !== null) {
|
|
28046
|
+
const sent = bytes(compact), saved = originalBytes - sent;
|
|
28047
|
+
return Object.freeze({ result: Object.freeze({ ...result2, stdout: compact }), telemetry: Object.freeze({
|
|
28048
|
+
parserId: "json-whitespace",
|
|
28049
|
+
parserVersion: "1",
|
|
28050
|
+
eligible: true,
|
|
28051
|
+
applied: true,
|
|
28052
|
+
reason: "validated_compact",
|
|
28053
|
+
originalStdoutBytes: originalBytes,
|
|
28054
|
+
sentStdoutBytes: sent,
|
|
28055
|
+
savedStdoutBytes: saved,
|
|
28056
|
+
reductionPercent: originalBytes === 0 ? 0 : saved / originalBytes * 100
|
|
28057
|
+
}) });
|
|
28058
|
+
}
|
|
28059
|
+
}
|
|
27709
28060
|
if (parsed.state !== "candidate") {
|
|
27710
28061
|
return Object.freeze({
|
|
27711
28062
|
result: result2,
|
|
@@ -28942,8 +29293,8 @@ function canonicalOrigin2(value) {
|
|
|
28942
29293
|
fail4("ORIGIN_INVALID");
|
|
28943
29294
|
}
|
|
28944
29295
|
}
|
|
28945
|
-
function endpoint(origin,
|
|
28946
|
-
return origin +
|
|
29296
|
+
function endpoint(origin, path19) {
|
|
29297
|
+
return origin + path19;
|
|
28947
29298
|
}
|
|
28948
29299
|
function uuid18(value, code) {
|
|
28949
29300
|
if (typeof value !== "string" || !UUID3.test(value)) fail4(code);
|
|
@@ -29444,29 +29795,29 @@ async function deliverGuardEvidence(target, packet, options = {}) {
|
|
|
29444
29795
|
}
|
|
29445
29796
|
|
|
29446
29797
|
// agent/src/optimization-ledger.ts
|
|
29447
|
-
import { constants as
|
|
29448
|
-
import { lstat as
|
|
29449
|
-
import
|
|
29798
|
+
import { constants as constants5 } from "node:fs";
|
|
29799
|
+
import { lstat as lstat7, mkdir as mkdir5, open as open6, readFile as readFile5, realpath as realpath6 } from "node:fs/promises";
|
|
29800
|
+
import path13 from "node:path";
|
|
29450
29801
|
var MAX_LEDGER_BYTES = 64 * 1024 * 1024;
|
|
29451
29802
|
var MAX_NOTICE_LEDGER_BYTES = 8 * 1024 * 1024;
|
|
29452
29803
|
function failure4(code) {
|
|
29453
29804
|
return Object.assign(new Error(code), { code });
|
|
29454
29805
|
}
|
|
29455
29806
|
async function safeDirectory2(directory) {
|
|
29456
|
-
const absolute2 =
|
|
29807
|
+
const absolute2 = path13.resolve(directory);
|
|
29457
29808
|
let current2 = absolute2;
|
|
29458
29809
|
for (; ; ) {
|
|
29459
29810
|
try {
|
|
29460
|
-
if ((await
|
|
29811
|
+
if ((await lstat7(current2)).isSymbolicLink()) throw failure4("OPTIMIZATION_LEDGER_DIRECTORY_INVALID");
|
|
29461
29812
|
} catch (error62) {
|
|
29462
29813
|
if (error62.code !== "ENOENT") throw error62;
|
|
29463
29814
|
}
|
|
29464
|
-
const parent =
|
|
29815
|
+
const parent = path13.dirname(current2);
|
|
29465
29816
|
if (parent === current2) break;
|
|
29466
29817
|
current2 = parent;
|
|
29467
29818
|
}
|
|
29468
|
-
await
|
|
29469
|
-
const stat = await
|
|
29819
|
+
await mkdir5(absolute2, { recursive: true, mode: 448 });
|
|
29820
|
+
const stat = await lstat7(absolute2);
|
|
29470
29821
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw failure4("OPTIMIZATION_LEDGER_DIRECTORY_INVALID");
|
|
29471
29822
|
return realpath6(absolute2);
|
|
29472
29823
|
}
|
|
@@ -29486,29 +29837,29 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
29486
29837
|
closed = false;
|
|
29487
29838
|
static async open(directory) {
|
|
29488
29839
|
const dir = await safeDirectory2(directory);
|
|
29489
|
-
const filename =
|
|
29490
|
-
const noticesFilename =
|
|
29840
|
+
const filename = path13.join(dir, "live-efficiency.v1.jsonl");
|
|
29841
|
+
const noticesFilename = path13.join(dir, "live-efficiency-notices.v1.jsonl");
|
|
29491
29842
|
let existing = "";
|
|
29492
29843
|
try {
|
|
29493
|
-
const stat = await
|
|
29844
|
+
const stat = await lstat7(filename);
|
|
29494
29845
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_LEDGER_BYTES) {
|
|
29495
29846
|
throw failure4("OPTIMIZATION_LEDGER_INVALID");
|
|
29496
29847
|
}
|
|
29497
|
-
existing = await
|
|
29848
|
+
existing = await readFile5(filename, "utf8");
|
|
29498
29849
|
} catch (error62) {
|
|
29499
29850
|
if (error62.code !== "ENOENT") throw error62;
|
|
29500
29851
|
}
|
|
29501
|
-
const handle = await
|
|
29852
|
+
const handle = await open6(
|
|
29502
29853
|
filename,
|
|
29503
|
-
|
|
29854
|
+
constants5.O_CREAT | constants5.O_APPEND | constants5.O_WRONLY | (constants5.O_NOFOLLOW ?? 0),
|
|
29504
29855
|
384
|
|
29505
29856
|
);
|
|
29506
29857
|
const ledger = new _OptimizationLedger(filename, handle, noticesFilename);
|
|
29507
29858
|
try {
|
|
29508
29859
|
try {
|
|
29509
|
-
const noticeStat = await
|
|
29860
|
+
const noticeStat = await lstat7(noticesFilename);
|
|
29510
29861
|
if (!noticeStat.isFile() || noticeStat.isSymbolicLink() || noticeStat.size > MAX_NOTICE_LEDGER_BYTES) throw failure4("OPTIMIZATION_NOTICE_LEDGER_INVALID");
|
|
29511
|
-
const notices = await
|
|
29862
|
+
const notices = await readFile5(noticesFilename, "utf8");
|
|
29512
29863
|
for (const line of notices.split("\n")) {
|
|
29513
29864
|
if (!line) continue;
|
|
29514
29865
|
const parsed = JSON.parse(line);
|
|
@@ -29573,16 +29924,16 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
29573
29924
|
const marker = JSON.stringify({ sessionId: event.sessionId, checkpointCalls, deliveredAt: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
|
|
29574
29925
|
let currentBytes = 0;
|
|
29575
29926
|
try {
|
|
29576
|
-
const stat = await
|
|
29927
|
+
const stat = await lstat7(this.noticesFilename);
|
|
29577
29928
|
if (!stat.isFile() || stat.isSymbolicLink()) throw failure4("OPTIMIZATION_NOTICE_LEDGER_INVALID");
|
|
29578
29929
|
currentBytes = stat.size;
|
|
29579
29930
|
} catch (error62) {
|
|
29580
29931
|
if (error62.code !== "ENOENT") throw error62;
|
|
29581
29932
|
}
|
|
29582
29933
|
if (currentBytes + Buffer.byteLength(marker, "utf8") > MAX_NOTICE_LEDGER_BYTES) throw failure4("OPTIMIZATION_NOTICE_LEDGER_CAPACITY_EXCEEDED");
|
|
29583
|
-
const markerHandle = await
|
|
29934
|
+
const markerHandle = await open6(
|
|
29584
29935
|
this.noticesFilename,
|
|
29585
|
-
|
|
29936
|
+
constants5.O_CREAT | constants5.O_APPEND | constants5.O_WRONLY | (constants5.O_NOFOLLOW ?? 0),
|
|
29586
29937
|
384
|
|
29587
29938
|
);
|
|
29588
29939
|
try {
|
|
@@ -29620,114 +29971,13 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
29620
29971
|
};
|
|
29621
29972
|
|
|
29622
29973
|
// agent/src/monitor.ts
|
|
29623
|
-
import { createHash as
|
|
29624
|
-
import { lstat as
|
|
29625
|
-
import
|
|
29626
|
-
import
|
|
29627
|
-
|
|
29628
|
-
// packages/agent-cli/bin/monitor-context.mjs
|
|
29629
|
-
var AGENT_NAMES = Object.freeze([
|
|
29630
|
-
"Avi",
|
|
29631
|
-
"Noam",
|
|
29632
|
-
"Yael",
|
|
29633
|
-
"Leah",
|
|
29634
|
-
"Ezra",
|
|
29635
|
-
"Eli",
|
|
29636
|
-
"Tamar",
|
|
29637
|
-
"Dalia",
|
|
29638
|
-
"Ruth",
|
|
29639
|
-
"Maya",
|
|
29640
|
-
"Oren",
|
|
29641
|
-
"Shira",
|
|
29642
|
-
"Eitan",
|
|
29643
|
-
"Lior",
|
|
29644
|
-
"Hila",
|
|
29645
|
-
"Amir",
|
|
29646
|
-
"Ivan",
|
|
29647
|
-
"Yuri",
|
|
29648
|
-
"Olga",
|
|
29649
|
-
"Anna",
|
|
29650
|
-
"Boris",
|
|
29651
|
-
"Nina",
|
|
29652
|
-
"Pavel",
|
|
29653
|
-
"Irina",
|
|
29654
|
-
"Vera",
|
|
29655
|
-
"Daria",
|
|
29656
|
-
"Misha",
|
|
29657
|
-
"Sasha",
|
|
29658
|
-
"Vadim",
|
|
29659
|
-
"Roman",
|
|
29660
|
-
"Anya",
|
|
29661
|
-
"Lev",
|
|
29662
|
-
"Omar",
|
|
29663
|
-
"Layla",
|
|
29664
|
-
"Ali",
|
|
29665
|
-
"Nadia",
|
|
29666
|
-
"Salim",
|
|
29667
|
-
"Hana",
|
|
29668
|
-
"Rami",
|
|
29669
|
-
"Zain",
|
|
29670
|
-
"Noor",
|
|
29671
|
-
"Amal",
|
|
29672
|
-
"Samir",
|
|
29673
|
-
"Farah",
|
|
29674
|
-
"Malik",
|
|
29675
|
-
"Yasmin",
|
|
29676
|
-
"Adil",
|
|
29677
|
-
"Hadi",
|
|
29678
|
-
"Arjun",
|
|
29679
|
-
"Priya",
|
|
29680
|
-
"Ravi",
|
|
29681
|
-
"Anika",
|
|
29682
|
-
"Asha",
|
|
29683
|
-
"Dev",
|
|
29684
|
-
"Kiran",
|
|
29685
|
-
"Meera",
|
|
29686
|
-
"Nisha",
|
|
29687
|
-
"Rohan",
|
|
29688
|
-
"Diya",
|
|
29689
|
-
"Neha",
|
|
29690
|
-
"Anil",
|
|
29691
|
-
"Sana",
|
|
29692
|
-
"Vijay",
|
|
29693
|
-
"Isha",
|
|
29694
|
-
"Wei",
|
|
29695
|
-
"Lin",
|
|
29696
|
-
"Mei",
|
|
29697
|
-
"Chen",
|
|
29698
|
-
"Li",
|
|
29699
|
-
"Jian",
|
|
29700
|
-
"Ming",
|
|
29701
|
-
"Hua",
|
|
29702
|
-
"Yan",
|
|
29703
|
-
"Tao",
|
|
29704
|
-
"Jun",
|
|
29705
|
-
"Lan",
|
|
29706
|
-
"Yue",
|
|
29707
|
-
"Lei",
|
|
29708
|
-
"Hong",
|
|
29709
|
-
"Qian"
|
|
29710
|
-
]);
|
|
29711
|
-
var identifier = (value) => typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,95}$/.test(value);
|
|
29712
|
-
function contextSummary(meta3 = {}) {
|
|
29713
|
-
const source = typeof (meta3.cwd ?? meta3.path ?? meta3.project) === "string" ? meta3.cwd ?? meta3.path ?? meta3.project : "";
|
|
29714
|
-
const normalized = source.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
29715
|
-
const safe = normalized.length <= 1024 && /^[A-Za-z0-9 _./:@()+-]*$/.test(normalized) && !/(?:^|\/)(?:\.env(?:\.[^/]*)?|credentials[^/]*|\.npmrc|agent-identities\.json)(?:\/|$)/i.test(normalized);
|
|
29716
|
-
const directory = safe && normalized ? normalized.slice(-96) : null;
|
|
29717
|
-
const project = directory ? directory.split("/").at(-1) : null;
|
|
29718
|
-
const taskMatch = safe && normalized.match(/\/planning\/tasks\/([A-Za-z0-9][A-Za-z0-9_.:-]{0,95})\.md$/);
|
|
29719
|
-
const taskId = identifier(meta3.taskId) ? meta3.taskId : taskMatch ? taskMatch[1] : null;
|
|
29720
|
-
const branchPr = safe && normalized.match(/(?:^|[/_-])pr[-_]?(\d{1,7})(?:[/_.-]|$)/i);
|
|
29721
|
-
const explicitPr = Number.isSafeInteger(meta3.pr) && meta3.pr > 0 && meta3.pr <= 9999999 ? meta3.pr : null;
|
|
29722
|
-
const args = Array.isArray(meta3.args) ? meta3.args : [];
|
|
29723
|
-
const ghPr = meta3.command === "gh" && args[0] === "pr" && ["view", "checkout", "diff", "checks", "merge"].includes(args[1]) && /^\d{1,7}$/.test(args[2] ?? "") ? Number(args[2]) : null;
|
|
29724
|
-
return { project, directory, taskId, pr: explicitPr ?? ghPr ?? (branchPr ? Number(branchPr[1]) : null), inferred: !explicitPr && !identifier(meta3.taskId) };
|
|
29725
|
-
}
|
|
29726
|
-
|
|
29727
|
-
// agent/src/monitor.ts
|
|
29728
|
-
function commandSummary(tool) {
|
|
29974
|
+
import { createHash as createHash11, randomUUID as randomUUID8 } from "node:crypto";
|
|
29975
|
+
import { lstat as lstat8, mkdir as mkdir6, open as open7, rename as rename5, rm as rm5 } from "node:fs/promises";
|
|
29976
|
+
import path14 from "node:path";
|
|
29977
|
+
import os4 from "node:os";
|
|
29978
|
+
function commandSummary2(tool) {
|
|
29729
29979
|
if (tool.name !== "command_run") return { name: tool.name, command: tool.name };
|
|
29730
|
-
const candidate =
|
|
29980
|
+
const candidate = path14.win32.basename(tool.args.command).replace(/\.(exe|cmd|bat|com)$/i, "").toLowerCase();
|
|
29731
29981
|
const name2 = ["node", "npm", "npx", "git", "rg", "powershell", "pwsh", "cmd", "tsc", "python", "dotnet"].includes(candidate) ? candidate : "command";
|
|
29732
29982
|
let command = name2;
|
|
29733
29983
|
if (name2 === "node" && tool.args.args.includes("--test") && !tool.args.args.some((arg) => ["-e", "--eval", "-p", "--print"].includes(arg))) command += " --test";
|
|
@@ -29740,8 +29990,8 @@ function commandSummary(tool) {
|
|
|
29740
29990
|
var ProductionMonitor = class {
|
|
29741
29991
|
constructor(directory, stateDirectory, agentVersion3) {
|
|
29742
29992
|
this.agentVersion = agentVersion3;
|
|
29743
|
-
const key =
|
|
29744
|
-
this.file =
|
|
29993
|
+
const key = createHash11("sha256").update(path14.resolve(stateDirectory).toLowerCase()).digest("hex");
|
|
29994
|
+
this.file = path14.join(directory, key + ".json");
|
|
29745
29995
|
}
|
|
29746
29996
|
agentVersion;
|
|
29747
29997
|
instanceId = randomUUID8();
|
|
@@ -29752,7 +30002,7 @@ var ProductionMonitor = class {
|
|
|
29752
30002
|
measured = /* @__PURE__ */ new Set();
|
|
29753
30003
|
polls = { status: 0, output: 0 };
|
|
29754
30004
|
efficiencyCalls = 0;
|
|
29755
|
-
computer =
|
|
30005
|
+
computer = os4.hostname().replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 64) || "PC";
|
|
29756
30006
|
sequence = 0;
|
|
29757
30007
|
connection = {
|
|
29758
30008
|
state: "starting",
|
|
@@ -29813,7 +30063,12 @@ var ProductionMonitor = class {
|
|
|
29813
30063
|
this.executions.set(binding2.executionId, {
|
|
29814
30064
|
executionId: binding2.executionId,
|
|
29815
30065
|
sessionId: binding2.sessionId,
|
|
29816
|
-
...
|
|
30066
|
+
...commandSummary2(tool.data),
|
|
30067
|
+
preview: commandPreview(tool.data.name, tool.data.args),
|
|
30068
|
+
startedAt: Date.now(),
|
|
30069
|
+
endedAt: null,
|
|
30070
|
+
exitCode: null,
|
|
30071
|
+
timedOut: false,
|
|
29817
30072
|
context: contextSummary(tool.data.args),
|
|
29818
30073
|
state: "requested",
|
|
29819
30074
|
pid: null,
|
|
@@ -29825,6 +30080,7 @@ var ProductionMonitor = class {
|
|
|
29825
30080
|
});
|
|
29826
30081
|
if (this.executions.size > 64) this.executions.delete(this.executions.keys().next().value);
|
|
29827
30082
|
}
|
|
30083
|
+
if (request.kind === "status" || request.kind === "output") return;
|
|
29828
30084
|
this.record(request.kind, {
|
|
29829
30085
|
sessionId: binding2.sessionId,
|
|
29830
30086
|
executionId: binding2.executionId,
|
|
@@ -29833,7 +30089,10 @@ var ProductionMonitor = class {
|
|
|
29833
30089
|
}
|
|
29834
30090
|
result(binding2, state, code) {
|
|
29835
30091
|
const execution = this.executions.get(binding2.executionId);
|
|
29836
|
-
if (execution)
|
|
30092
|
+
if (execution) {
|
|
30093
|
+
execution.endedAt = Date.now();
|
|
30094
|
+
execution.state = ["finished", "failed", "cancelled", "unknown"].includes(state) ? state : "unknown";
|
|
30095
|
+
}
|
|
29837
30096
|
this.record(["finished", "failed", "cancelled", "unknown"].includes(state) ? state : "result", {
|
|
29838
30097
|
sessionId: binding2.sessionId,
|
|
29839
30098
|
executionId: binding2.executionId,
|
|
@@ -29849,6 +30108,9 @@ var ProductionMonitor = class {
|
|
|
29849
30108
|
if (frame.type === "not_accepted") execution.state = frame.provedNotStarted ? "rejected" : "unknown";
|
|
29850
30109
|
if (frame.type === "result") {
|
|
29851
30110
|
const result2 = frame.result;
|
|
30111
|
+
execution.endedAt = Date.now();
|
|
30112
|
+
execution.exitCode = result2.exitCode;
|
|
30113
|
+
execution.timedOut = result2.timedOut;
|
|
29852
30114
|
execution.state = !result2.treeTerminated ? "unknown" : result2.cancelled ? "cancelled" : result2.timedOut || result2.exitCode !== 0 ? "failed" : "finished";
|
|
29853
30115
|
}
|
|
29854
30116
|
if (frame.type === "control_result") execution.state = frame.state;
|
|
@@ -29928,21 +30190,21 @@ var ProductionMonitor = class {
|
|
|
29928
30190
|
this.writing = (async () => {
|
|
29929
30191
|
do {
|
|
29930
30192
|
this.dirty = false;
|
|
29931
|
-
const directory =
|
|
29932
|
-
await
|
|
29933
|
-
const stat = await
|
|
30193
|
+
const directory = path14.dirname(this.file);
|
|
30194
|
+
await mkdir6(directory, { recursive: true, mode: 448 });
|
|
30195
|
+
const stat = await lstat8(directory);
|
|
29934
30196
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw Error("MONITOR_DIRECTORY_INVALID");
|
|
29935
30197
|
const temporary = this.file + "." + this.instanceId + ".tmp";
|
|
29936
|
-
const handle = await
|
|
30198
|
+
const handle = await open7(temporary, "wx", 384);
|
|
29937
30199
|
try {
|
|
29938
30200
|
try {
|
|
29939
30201
|
await handle.writeFile(JSON.stringify(this.snapshot()) + "\n");
|
|
29940
30202
|
} finally {
|
|
29941
30203
|
await handle.close();
|
|
29942
30204
|
}
|
|
29943
|
-
await
|
|
30205
|
+
await rename5(temporary, this.file);
|
|
29944
30206
|
} finally {
|
|
29945
|
-
await
|
|
30207
|
+
await rm5(temporary, { force: true });
|
|
29946
30208
|
}
|
|
29947
30209
|
} while (this.dirty);
|
|
29948
30210
|
})().finally(() => {
|
|
@@ -29958,9 +30220,9 @@ var ProductionMonitor = class {
|
|
|
29958
30220
|
};
|
|
29959
30221
|
|
|
29960
30222
|
// agent/src/native-event-buffer.ts
|
|
29961
|
-
import { createHash as
|
|
30223
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
29962
30224
|
function nativeFingerprint(code, executionId = "") {
|
|
29963
|
-
return
|
|
30225
|
+
return createHash12("sha256").update(code + "\0" + executionId).digest("hex");
|
|
29964
30226
|
}
|
|
29965
30227
|
var NativeEventBuffer = class {
|
|
29966
30228
|
pending = /* @__PURE__ */ new Map();
|
|
@@ -30358,27 +30620,27 @@ var NativeFabricObserver = class {
|
|
|
30358
30620
|
};
|
|
30359
30621
|
|
|
30360
30622
|
// agent/src/native-fabric-startup.ts
|
|
30361
|
-
import { lstat as
|
|
30362
|
-
import
|
|
30623
|
+
import { lstat as lstat10, mkdir as mkdir9, open as open9, readFile as readFile6 } from "node:fs/promises";
|
|
30624
|
+
import path17 from "node:path";
|
|
30363
30625
|
|
|
30364
30626
|
// src/agent-fabric-service.ts
|
|
30365
|
-
import { lstat as
|
|
30627
|
+
import { lstat as lstat9, mkdir as mkdir8, realpath as realpath7 } from "node:fs/promises";
|
|
30366
30628
|
import { watch } from "node:fs";
|
|
30367
|
-
import
|
|
30629
|
+
import path16 from "node:path";
|
|
30368
30630
|
|
|
30369
30631
|
// src/agent-runtime-identity.ts
|
|
30370
|
-
import { createHash as
|
|
30632
|
+
import { createHash as createHash13, randomBytes as randomBytes4, randomUUID as randomUUID10, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
30371
30633
|
|
|
30372
30634
|
// src/agent-fabric-state.ts
|
|
30373
30635
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
30374
|
-
import { mkdir as
|
|
30375
|
-
import
|
|
30636
|
+
import { mkdir as mkdir7, open as open8, rename as rename6, unlink } from "node:fs/promises";
|
|
30637
|
+
import path15 from "node:path";
|
|
30376
30638
|
var queues = /* @__PURE__ */ new Map();
|
|
30377
30639
|
var FabricStateFile = class {
|
|
30378
30640
|
constructor(file2, maxBytes, parse3) {
|
|
30379
30641
|
this.maxBytes = maxBytes;
|
|
30380
30642
|
this.parse = parse3;
|
|
30381
|
-
this.file =
|
|
30643
|
+
this.file = path15.resolve(file2);
|
|
30382
30644
|
}
|
|
30383
30645
|
maxBytes;
|
|
30384
30646
|
parse;
|
|
@@ -30396,7 +30658,7 @@ var FabricStateFile = class {
|
|
|
30396
30658
|
return result2;
|
|
30397
30659
|
}
|
|
30398
30660
|
async load() {
|
|
30399
|
-
const handle = await
|
|
30661
|
+
const handle = await open8(this.file, "r");
|
|
30400
30662
|
try {
|
|
30401
30663
|
const info = await handle.stat();
|
|
30402
30664
|
if (!info.isFile() || info.size > this.maxBytes) throw Error("FABRIC_STATE_LIMIT");
|
|
@@ -30422,10 +30684,10 @@ var FabricStateFile = class {
|
|
|
30422
30684
|
}
|
|
30423
30685
|
update(fn, create) {
|
|
30424
30686
|
return this.serial(async () => {
|
|
30425
|
-
if (create) await
|
|
30687
|
+
if (create) await mkdir7(path15.dirname(this.file), { recursive: true });
|
|
30426
30688
|
const lockPath = this.file + ".lock";
|
|
30427
30689
|
const token = randomUUID9();
|
|
30428
|
-
const lock = await
|
|
30690
|
+
const lock = await open8(lockPath, "wx", 384).catch((error62) => {
|
|
30429
30691
|
if (error62.code === "EEXIST") throw Error("FABRIC_STATE_BUSY");
|
|
30430
30692
|
throw error62;
|
|
30431
30693
|
});
|
|
@@ -30443,7 +30705,7 @@ var FabricStateFile = class {
|
|
|
30443
30705
|
const encoded = JSON.stringify(this.parse(state));
|
|
30444
30706
|
if (Buffer.byteLength(encoded) > this.maxBytes) throw Error("FABRIC_STATE_LIMIT");
|
|
30445
30707
|
const temporary = this.file + "." + token + ".tmp";
|
|
30446
|
-
const handle = await
|
|
30708
|
+
const handle = await open8(temporary, "wx", 384);
|
|
30447
30709
|
try {
|
|
30448
30710
|
try {
|
|
30449
30711
|
await handle.writeFile(encoded, "utf8");
|
|
@@ -30451,7 +30713,7 @@ var FabricStateFile = class {
|
|
|
30451
30713
|
} finally {
|
|
30452
30714
|
await handle.close();
|
|
30453
30715
|
}
|
|
30454
|
-
await
|
|
30716
|
+
await rename6(temporary, this.file);
|
|
30455
30717
|
} finally {
|
|
30456
30718
|
await unlink(temporary).catch((error62) => {
|
|
30457
30719
|
if (error62.code !== "ENOENT") throw error62;
|
|
@@ -30460,7 +30722,7 @@ var FabricStateFile = class {
|
|
|
30460
30722
|
return result2;
|
|
30461
30723
|
} finally {
|
|
30462
30724
|
await lock.close();
|
|
30463
|
-
const current2 = await
|
|
30725
|
+
const current2 = await open8(lockPath, "r");
|
|
30464
30726
|
try {
|
|
30465
30727
|
if ((await current2.stat()).size > 1024 || JSON.parse(await current2.readFile("utf8")).token !== token)
|
|
30466
30728
|
throw Error("FABRIC_STATE_LOCK_CHANGED");
|
|
@@ -30490,7 +30752,7 @@ var StateSchema = external_exports.strictObject({
|
|
|
30490
30752
|
bindings: external_exports.array(BindingSchema).max(MAX_BINDINGS)
|
|
30491
30753
|
});
|
|
30492
30754
|
function digest4(value) {
|
|
30493
|
-
return
|
|
30755
|
+
return createHash13("sha256").update(value, "utf8").digest();
|
|
30494
30756
|
}
|
|
30495
30757
|
function encodedDigest(value) {
|
|
30496
30758
|
return digest4(value).toString("hex");
|
|
@@ -31066,9 +31328,9 @@ var WorkerRequest = external_exports.discriminatedUnion("operation", [
|
|
|
31066
31328
|
var AgentFabricService = class _AgentFabricService {
|
|
31067
31329
|
constructor(directory, controllerId) {
|
|
31068
31330
|
this.directory = directory;
|
|
31069
|
-
this.identities = new AgentRuntimeIdentityStore(
|
|
31331
|
+
this.identities = new AgentRuntimeIdentityStore(path16.join(directory, "identities.json"));
|
|
31070
31332
|
this.mailbox = new AgentWorkerMailbox(
|
|
31071
|
-
|
|
31333
|
+
path16.join(directory, "mailbox.json"),
|
|
31072
31334
|
controllerId,
|
|
31073
31335
|
this.identities,
|
|
31074
31336
|
void 0,
|
|
@@ -31083,21 +31345,21 @@ var AgentFabricService = class _AgentFabricService {
|
|
|
31083
31345
|
closed = false;
|
|
31084
31346
|
static async open(directory, controllerId, device = null, initialize = true) {
|
|
31085
31347
|
const expected = Binding.parse({ version: 1, controllerId, device, initialized: false });
|
|
31086
|
-
const absolute2 =
|
|
31087
|
-
for (let current2 = absolute2; ; current2 =
|
|
31348
|
+
const absolute2 = path16.resolve(directory);
|
|
31349
|
+
for (let current2 = absolute2; ; current2 = path16.dirname(current2)) {
|
|
31088
31350
|
try {
|
|
31089
|
-
if ((await
|
|
31351
|
+
if ((await lstat9(current2)).isSymbolicLink()) throw Error("FABRIC_DIRECTORY_INVALID");
|
|
31090
31352
|
} catch (error62) {
|
|
31091
31353
|
if (error62.code !== "ENOENT") throw error62;
|
|
31092
31354
|
}
|
|
31093
|
-
if (
|
|
31355
|
+
if (path16.dirname(current2) === current2) break;
|
|
31094
31356
|
}
|
|
31095
|
-
if (initialize) await
|
|
31096
|
-
if (!(await
|
|
31357
|
+
if (initialize) await mkdir8(absolute2, { recursive: true, mode: 448 });
|
|
31358
|
+
if (!(await lstat9(absolute2)).isDirectory() || (await realpath7(absolute2)).toLowerCase() !== absolute2.toLowerCase())
|
|
31097
31359
|
throw Error("FABRIC_DIRECTORY_INVALID");
|
|
31098
31360
|
const present = /* @__PURE__ */ new Set();
|
|
31099
31361
|
for (const name2 of ["binding.json", "mailbox.json", "identities.json"]) {
|
|
31100
|
-
const file2 = await
|
|
31362
|
+
const file2 = await lstat9(path16.join(absolute2, name2)).catch((error62) => {
|
|
31101
31363
|
if (error62.code === "ENOENT") return null;
|
|
31102
31364
|
throw error62;
|
|
31103
31365
|
});
|
|
@@ -31105,7 +31367,7 @@ var AgentFabricService = class _AgentFabricService {
|
|
|
31105
31367
|
if (file2) present.add(name2);
|
|
31106
31368
|
}
|
|
31107
31369
|
if (!present.has("binding.json") && present.size) throw Error("FABRIC_BINDING_MISSING");
|
|
31108
|
-
const binding2 = new FabricStateFile(
|
|
31370
|
+
const binding2 = new FabricStateFile(path16.join(absolute2, "binding.json"), 2048, (value) => Binding.parse(value));
|
|
31109
31371
|
const service = new _AgentFabricService(absolute2, controllerId);
|
|
31110
31372
|
await binding2.update(async (state) => {
|
|
31111
31373
|
if (state.controllerId !== expected.controllerId || JSON.stringify(state.device) !== JSON.stringify(expected.device))
|
|
@@ -31120,7 +31382,7 @@ var AgentFabricService = class _AgentFabricService {
|
|
|
31120
31382
|
state.initialized = true;
|
|
31121
31383
|
}
|
|
31122
31384
|
const snapshot2 = await service.mailbox.snapshot();
|
|
31123
|
-
if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await
|
|
31385
|
+
if (snapshot2.workers.some((worker) => worker.runtimeId !== null)) await lstat9(path16.join(absolute2, "identities.json"));
|
|
31124
31386
|
}, initialize ? () => expected : void 0);
|
|
31125
31387
|
return service;
|
|
31126
31388
|
}
|
|
@@ -31207,23 +31469,23 @@ var Delivery = external_exports.strictObject({ capability: external_exports.stri
|
|
|
31207
31469
|
async function openNativeFabric(stateDirectory, enrollment, box, initialize = true) {
|
|
31208
31470
|
const controllerId = "device-" + external_exports.string().uuid().parse(enrollment.deviceId).toLowerCase();
|
|
31209
31471
|
const tenantId = external_exports.string().uuid().parse(enrollment.tenantId).toLowerCase();
|
|
31210
|
-
const parent =
|
|
31472
|
+
const parent = path17.join(stateDirectory, ".local-commander"), marker = path17.join(parent, "fabric-established.json");
|
|
31211
31473
|
try {
|
|
31212
|
-
await
|
|
31474
|
+
await mkdir9(parent, { mode: 448 });
|
|
31213
31475
|
} catch (error62) {
|
|
31214
31476
|
if (error62.code !== "EEXIST") throw error62;
|
|
31215
31477
|
}
|
|
31216
|
-
const parentInfo = await
|
|
31478
|
+
const parentInfo = await lstat10(parent);
|
|
31217
31479
|
if (!parentInfo.isDirectory() || parentInfo.isSymbolicLink()) throw Error("FABRIC_DIRECTORY_INVALID");
|
|
31218
31480
|
const expected = JSON.stringify({ version: 1, controllerId, tenantId });
|
|
31219
31481
|
let fresh = false;
|
|
31220
31482
|
try {
|
|
31221
|
-
const info = await
|
|
31222
|
-
if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await
|
|
31483
|
+
const info = await lstat10(marker);
|
|
31484
|
+
if (!info.isFile() || info.isSymbolicLink() || info.size > 2048 || await readFile6(marker, "utf8") !== expected)
|
|
31223
31485
|
throw Error("FABRIC_BINDING_CHANGED");
|
|
31224
31486
|
} catch (error62) {
|
|
31225
31487
|
if (error62.code !== "ENOENT" || !initialize) throw error62;
|
|
31226
|
-
const file2 = await
|
|
31488
|
+
const file2 = await open9(marker, "wx", 384);
|
|
31227
31489
|
try {
|
|
31228
31490
|
await file2.writeFile(expected);
|
|
31229
31491
|
await file2.datasync();
|
|
@@ -31233,22 +31495,22 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
|
|
|
31233
31495
|
fresh = true;
|
|
31234
31496
|
}
|
|
31235
31497
|
const service = await AgentFabricService.open(
|
|
31236
|
-
|
|
31498
|
+
path17.join(stateDirectory, ".local-commander", "fabric"),
|
|
31237
31499
|
controllerId,
|
|
31238
31500
|
{ deviceId: enrollment.deviceId.toLowerCase(), enrollmentEvidenceRef: "enrollment-" + tenantId },
|
|
31239
31501
|
fresh
|
|
31240
31502
|
);
|
|
31241
31503
|
const purpose = "native-fabric:" + tenantId + ":" + controllerId;
|
|
31242
|
-
const credentialFile = (workerId) =>
|
|
31504
|
+
const credentialFile = (workerId) => path17.join(service.directory, external_exports.string().uuid().parse(workerId) + ".capability");
|
|
31243
31505
|
const decode4 = (value) => {
|
|
31244
31506
|
const credential = Credential.parse(JSON.parse(box.open(Buffer.from(value, "base64"), purpose).toString("utf8")));
|
|
31245
31507
|
if (credential.controllerId !== controllerId) throw Error("FABRIC_WORKER_DENIED");
|
|
31246
31508
|
return credential;
|
|
31247
31509
|
};
|
|
31248
31510
|
async function capability(workerId) {
|
|
31249
|
-
const file2 = credentialFile(workerId), info = await
|
|
31511
|
+
const file2 = credentialFile(workerId), info = await lstat10(file2);
|
|
31250
31512
|
if (!info.isFile() || info.isSymbolicLink() || info.size > 4096) throw Error("FABRIC_CREDENTIAL_UNKNOWN");
|
|
31251
|
-
const encoded = await
|
|
31513
|
+
const encoded = await readFile6(file2, "utf8");
|
|
31252
31514
|
if (decode4(encoded).workerId !== workerId) throw Error("FABRIC_WORKER_DENIED");
|
|
31253
31515
|
return encoded;
|
|
31254
31516
|
}
|
|
@@ -31281,7 +31543,7 @@ async function openNativeFabric(stateDirectory, enrollment, box, initialize = tr
|
|
|
31281
31543
|
} else {
|
|
31282
31544
|
const credential = await service.identities.issue();
|
|
31283
31545
|
const encoded = box.seal(Buffer.from(JSON.stringify({ ...credential, workerId: worker.workerId, controllerId })), purpose).toString("base64");
|
|
31284
|
-
const file2 = await
|
|
31546
|
+
const file2 = await open9(credentialFile(worker.workerId), "wx", 384);
|
|
31285
31547
|
try {
|
|
31286
31548
|
await file2.writeFile(encoded);
|
|
31287
31549
|
await file2.datasync();
|
|
@@ -31339,7 +31601,7 @@ async function readFabricRequest(input2 = process.stdin) {
|
|
|
31339
31601
|
}
|
|
31340
31602
|
|
|
31341
31603
|
// agent/src/main.ts
|
|
31342
|
-
var AGENT_VERSION2 = true ? "0.3.
|
|
31604
|
+
var AGENT_VERSION2 = true ? "0.3.14-cli.1" : "0.3.2";
|
|
31343
31605
|
function processAlive(pid) {
|
|
31344
31606
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
31345
31607
|
try {
|
|
@@ -31350,11 +31612,11 @@ function processAlive(pid) {
|
|
|
31350
31612
|
}
|
|
31351
31613
|
}
|
|
31352
31614
|
async function claimAgentProcess(stateDir, runtimeDir, version2) {
|
|
31353
|
-
await
|
|
31354
|
-
const file2 =
|
|
31615
|
+
await mkdir10(stateDir, { recursive: true });
|
|
31616
|
+
const file2 = path18.join(stateDir, "agent-process.json");
|
|
31355
31617
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
31356
31618
|
try {
|
|
31357
|
-
const handle = await
|
|
31619
|
+
const handle = await open10(file2, "wx", 384);
|
|
31358
31620
|
try {
|
|
31359
31621
|
await handle.writeFile(JSON.stringify({ pid: process.pid, runtimeDir, version: version2, startedAt: (/* @__PURE__ */ new Date()).toISOString() }) + "\n", "utf8");
|
|
31360
31622
|
} finally {
|
|
@@ -31362,8 +31624,8 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
|
|
|
31362
31624
|
}
|
|
31363
31625
|
return async () => {
|
|
31364
31626
|
try {
|
|
31365
|
-
const current2 = JSON.parse(await
|
|
31366
|
-
if (current2.pid === process.pid) await
|
|
31627
|
+
const current2 = JSON.parse(await readFile7(file2, "utf8"));
|
|
31628
|
+
if (current2.pid === process.pid) await rm6(file2, { force: true });
|
|
31367
31629
|
} catch {
|
|
31368
31630
|
}
|
|
31369
31631
|
};
|
|
@@ -31371,12 +31633,12 @@ async function claimAgentProcess(stateDir, runtimeDir, version2) {
|
|
|
31371
31633
|
if (!error62 || typeof error62 !== "object" || !("code" in error62) || error62.code !== "EEXIST") throw error62;
|
|
31372
31634
|
let stale = true;
|
|
31373
31635
|
try {
|
|
31374
|
-
const current2 = JSON.parse(await
|
|
31636
|
+
const current2 = JSON.parse(await readFile7(file2, "utf8"));
|
|
31375
31637
|
stale = typeof current2.pid !== "number" || !processAlive(current2.pid);
|
|
31376
31638
|
} catch {
|
|
31377
31639
|
}
|
|
31378
31640
|
if (!stale) throw Error("AGENT_ALREADY_RUNNING");
|
|
31379
|
-
await
|
|
31641
|
+
await rm6(file2, { force: true });
|
|
31380
31642
|
}
|
|
31381
31643
|
}
|
|
31382
31644
|
throw Error("AGENT_ALREADY_RUNNING");
|
|
@@ -31548,10 +31810,10 @@ async function runAgent(options) {
|
|
|
31548
31810
|
async function main() {
|
|
31549
31811
|
if (process.platform !== "win32") throw Error("WINDOWS_REQUIRED");
|
|
31550
31812
|
const appData = process.env.LOCALAPPDATA;
|
|
31551
|
-
if (!appData || !
|
|
31552
|
-
const stateDir = process.env.LC_AGENT_STATE_DIR ??
|
|
31553
|
-
const binaryDir =
|
|
31554
|
-
const ownerBridgePath = process.env.LC_OWNER_BRIDGE ??
|
|
31813
|
+
if (!appData || !path18.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
|
|
31814
|
+
const stateDir = process.env.LC_AGENT_STATE_DIR ?? path18.join(appData, "LocalCommander", "Agent");
|
|
31815
|
+
const binaryDir = path18.dirname(process.execPath);
|
|
31816
|
+
const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path18.join(binaryDir, "OwnerBridge.exe");
|
|
31555
31817
|
const store = await WindowsPrivateStore.open(stateDir, ownerBridgePath);
|
|
31556
31818
|
const command = process.argv[2] ?? "run";
|
|
31557
31819
|
if (command === "pair") {
|
|
@@ -31560,7 +31822,7 @@ async function main() {
|
|
|
31560
31822
|
const pairing = new PairingClient(store, { controlPlaneOrigin: origin, agentVersion: AGENT_VERSION2 });
|
|
31561
31823
|
const begun = await pairing.begin();
|
|
31562
31824
|
process.stdout.write(JSON.stringify({ approvalUrl: begun.approvalUrl, confirmationCode: begun.confirmationCode, expiresAt: begun.expiresAt.toISOString() }) + "\n");
|
|
31563
|
-
await pairing.waitAndComplete(begun,
|
|
31825
|
+
await pairing.waitAndComplete(begun, os5.hostname().slice(0, 120));
|
|
31564
31826
|
process.stdout.write("DEVICE_PAIRED\n");
|
|
31565
31827
|
return;
|
|
31566
31828
|
}
|
|
@@ -31621,7 +31883,7 @@ async function main() {
|
|
|
31621
31883
|
}
|
|
31622
31884
|
if (command === "efficiency-report") {
|
|
31623
31885
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
31624
|
-
const ledger = await OptimizationLedger.open(
|
|
31886
|
+
const ledger = await OptimizationLedger.open(path18.join(stateDir, "optimization"));
|
|
31625
31887
|
try {
|
|
31626
31888
|
process.stdout.write(JSON.stringify(await ledger.report(), null, 2) + "\n");
|
|
31627
31889
|
} finally {
|
|
@@ -31631,7 +31893,7 @@ async function main() {
|
|
|
31631
31893
|
}
|
|
31632
31894
|
if (command === "guard-configure") {
|
|
31633
31895
|
if (args.length !== 1) throw Error("AGENT_COMMAND_INVALID");
|
|
31634
|
-
const filename = await (await import("node:fs/promises")).realpath(
|
|
31896
|
+
const filename = await (await import("node:fs/promises")).realpath(path18.resolve(args[0]));
|
|
31635
31897
|
const input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readWindowsFile(ownerBridgePath, filename, 2e5)));
|
|
31636
31898
|
if (!input2 || typeof input2 !== "object" || Object.keys(input2).sort().join(",") !== "compact,settings") throw Error("GUARD_CONFIGURATION_INVALID");
|
|
31637
31899
|
await store.configureGuard(input2.settings, input2.compact);
|
|
@@ -31650,7 +31912,7 @@ async function main() {
|
|
|
31650
31912
|
}
|
|
31651
31913
|
if (command === "guard-evidence") {
|
|
31652
31914
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
31653
|
-
const journal = await NativeJournal.open(
|
|
31915
|
+
const journal = await NativeJournal.open(path18.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
31654
31916
|
try {
|
|
31655
31917
|
process.stdout.write(JSON.stringify(await journal.guardEvidence()) + "\n");
|
|
31656
31918
|
} finally {
|
|
@@ -31662,7 +31924,7 @@ async function main() {
|
|
|
31662
31924
|
if (args.length !== (command === "guard-export" ? 0 : 1)) throw Error("AGENT_COMMAND_INVALID");
|
|
31663
31925
|
const identity = await store.load();
|
|
31664
31926
|
if (!identity?.enrollment) throw Error("ENROLLMENT_MISSING");
|
|
31665
|
-
const journal = await NativeJournal.open(
|
|
31927
|
+
const journal = await NativeJournal.open(path18.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
31666
31928
|
try {
|
|
31667
31929
|
const { tenantId, deviceId } = identity.enrollment;
|
|
31668
31930
|
const records = (await journal.guardEvidence()).filter((record2) => record2.tenantId === tenantId && record2.deviceId === deviceId);
|
|
@@ -31700,16 +31962,16 @@ async function main() {
|
|
|
31700
31962
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
31701
31963
|
if (!(await store.load())?.enrollment) throw Error("ENROLLMENT_MISSING");
|
|
31702
31964
|
const releaseProcess = await claimAgentProcess(stateDir, binaryDir, AGENT_VERSION2);
|
|
31703
|
-
const monitor = new ProductionMonitor(
|
|
31965
|
+
const monitor = new ProductionMonitor(path18.join(appData, "LocalCommander", "Monitor"), stateDir, AGENT_VERSION2);
|
|
31704
31966
|
const publishMonitor = () => monitor.flush().catch(() => {
|
|
31705
31967
|
process.stderr.write("MONITOR_WRITE_FAILED\n");
|
|
31706
31968
|
});
|
|
31707
31969
|
await publishMonitor();
|
|
31708
31970
|
try {
|
|
31709
|
-
const journal = await NativeJournal.open(
|
|
31710
|
-
const efficiencyLedger = await OptimizationLedger.open(
|
|
31971
|
+
const journal = await NativeJournal.open(path18.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
31972
|
+
const efficiencyLedger = await OptimizationLedger.open(path18.join(stateDir, "optimization"));
|
|
31711
31973
|
try {
|
|
31712
|
-
const tools = new NativeTools({ stateDirectory: stateDir, helperPath: process.env.LC_JOB_HOST ??
|
|
31974
|
+
const tools = new NativeTools({ stateDirectory: stateDir, helperPath: process.env.LC_JOB_HOST ?? path18.join(binaryDir, "JobHost.exe"), ownerBridgePath, programs: await store.loadPrograms() });
|
|
31713
31975
|
const stop = new AbortController();
|
|
31714
31976
|
process.once("SIGINT", () => stop.abort());
|
|
31715
31977
|
process.once("SIGTERM", () => stop.abort());
|
|
@@ -31755,7 +32017,7 @@ async function main() {
|
|
|
31755
32017
|
await releaseProcess();
|
|
31756
32018
|
}
|
|
31757
32019
|
}
|
|
31758
|
-
if (process.argv[1] &&
|
|
32020
|
+
if (process.argv[1] && path18.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
31759
32021
|
void main().catch((error62) => {
|
|
31760
32022
|
const code = error62 instanceof Error && /^[A-Z0-9_]{1,64}$/.test(error62.message) ? error62.message : "AGENT_START_FAILED";
|
|
31761
32023
|
process.stderr.write(code + "\n");
|