local-commander-agent 0.3.2 → 0.3.4
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 +87 -15
- package/bin/localcommander.mjs +72 -9
- package/package.json +8 -3
- package/runtime/JobHost.exe +0 -0
- package/runtime/LocalCommanderAgent.exe +0 -0
- package/runtime/OwnerBridge.exe +0 -0
- package/runtime/agent.mjs +715 -480
package/runtime/agent.mjs
CHANGED
|
@@ -19,8 +19,8 @@ var __commonJS = (cb, mod) => function __require2() {
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
var __export = (target, all) => {
|
|
22
|
-
for (var
|
|
23
|
-
__defProp(target,
|
|
22
|
+
for (var name2 in all)
|
|
23
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
24
24
|
};
|
|
25
25
|
var __copyProps = (to, from, except, desc) => {
|
|
26
26
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -2121,9 +2121,9 @@ var require_extension = __commonJS({
|
|
|
2121
2121
|
"node_modules/ws/lib/extension.js"(exports, module) {
|
|
2122
2122
|
"use strict";
|
|
2123
2123
|
var { tokenChars } = require_validation();
|
|
2124
|
-
function push(dest,
|
|
2125
|
-
if (dest[
|
|
2126
|
-
else dest[
|
|
2124
|
+
function push(dest, name2, elem) {
|
|
2125
|
+
if (dest[name2] === void 0) dest[name2] = [elem];
|
|
2126
|
+
else dest[name2].push(elem);
|
|
2127
2127
|
}
|
|
2128
2128
|
function parse3(header) {
|
|
2129
2129
|
const offers = /* @__PURE__ */ Object.create(null);
|
|
@@ -2149,12 +2149,12 @@ var require_extension = __commonJS({
|
|
|
2149
2149
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
2150
2150
|
}
|
|
2151
2151
|
if (end === -1) end = i;
|
|
2152
|
-
const
|
|
2152
|
+
const name2 = header.slice(start, end);
|
|
2153
2153
|
if (code === 44) {
|
|
2154
|
-
push(offers,
|
|
2154
|
+
push(offers, name2, params);
|
|
2155
2155
|
params = /* @__PURE__ */ Object.create(null);
|
|
2156
2156
|
} else {
|
|
2157
|
-
extensionName =
|
|
2157
|
+
extensionName = name2;
|
|
2158
2158
|
}
|
|
2159
2159
|
start = end = -1;
|
|
2160
2160
|
} else {
|
|
@@ -2278,7 +2278,7 @@ var require_websocket = __commonJS({
|
|
|
2278
2278
|
var http = __require("http");
|
|
2279
2279
|
var net = __require("net");
|
|
2280
2280
|
var tls = __require("tls");
|
|
2281
|
-
var { randomBytes: randomBytes4, createHash:
|
|
2281
|
+
var { randomBytes: randomBytes4, createHash: createHash10 } = __require("crypto");
|
|
2282
2282
|
var { Duplex, Readable } = __require("stream");
|
|
2283
2283
|
var { URL: URL2 } = __require("url");
|
|
2284
2284
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -2959,7 +2959,7 @@ var require_websocket = __commonJS({
|
|
|
2959
2959
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2960
2960
|
return;
|
|
2961
2961
|
}
|
|
2962
|
-
const digest4 =
|
|
2962
|
+
const digest4 = createHash10("sha1").update(key + GUID).digest("base64");
|
|
2963
2963
|
if (res.headers["sec-websocket-accept"] !== digest4) {
|
|
2964
2964
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2965
2965
|
return;
|
|
@@ -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: createHash10 } = __require("crypto");
|
|
3332
3332
|
var extension2 = require_extension();
|
|
3333
3333
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3334
3334
|
var subprotocol2 = require_subprotocol();
|
|
@@ -3635,7 +3635,7 @@ var require_websocket_server = __commonJS({
|
|
|
3635
3635
|
);
|
|
3636
3636
|
}
|
|
3637
3637
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3638
|
-
const digest4 =
|
|
3638
|
+
const digest4 = createHash10("sha1").update(key + GUID).digest("base64");
|
|
3639
3639
|
const headers = [
|
|
3640
3640
|
"HTTP/1.1 101 Switching Protocols",
|
|
3641
3641
|
"Upgrade: websocket",
|
|
@@ -3723,7 +3723,7 @@ var require_websocket_server = __commonJS({
|
|
|
3723
3723
|
});
|
|
3724
3724
|
|
|
3725
3725
|
// agent/src/main.ts
|
|
3726
|
-
import
|
|
3726
|
+
import path12 from "node:path";
|
|
3727
3727
|
import os3 from "node:os";
|
|
3728
3728
|
import { mkdir as mkdir5, open as open6, readFile as readFile5, rm as rm4 } from "node:fs/promises";
|
|
3729
3729
|
import { fileURLToPath } from "node:url";
|
|
@@ -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, path13) {
|
|
4678
|
+
if (!path13)
|
|
4679
4679
|
return obj;
|
|
4680
|
-
return
|
|
4680
|
+
return path13.reduce((acc, key) => acc?.[key], obj);
|
|
4681
4681
|
}
|
|
4682
4682
|
function promiseAllObject(promisesObj) {
|
|
4683
4683
|
const keys = Object.keys(promisesObj);
|
|
@@ -4976,12 +4976,12 @@ function merge(a, b) {
|
|
|
4976
4976
|
});
|
|
4977
4977
|
return clone(a, def);
|
|
4978
4978
|
}
|
|
4979
|
-
function partial(Class2, schema, mask,
|
|
4979
|
+
function partial(Class2, schema, mask, name2 = "partial") {
|
|
4980
4980
|
const currDef = schema._zod.def;
|
|
4981
4981
|
const checks = currDef.checks;
|
|
4982
4982
|
const hasChecks = checks && checks.length > 0;
|
|
4983
4983
|
if (hasChecks) {
|
|
4984
|
-
throw new Error(`.${
|
|
4984
|
+
throw new Error(`.${name2}() cannot be used on object schemas containing refinements`);
|
|
4985
4985
|
}
|
|
4986
4986
|
const selected = mask ? new Set(maskedKeys(schema, mask)) : void 0;
|
|
4987
4987
|
const newShape = {};
|
|
@@ -5017,11 +5017,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
5017
5017
|
}
|
|
5018
5018
|
return false;
|
|
5019
5019
|
}
|
|
5020
|
-
function prefixIssues(
|
|
5020
|
+
function prefixIssues(path13, 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(path13);
|
|
5025
5025
|
return iss;
|
|
5026
5026
|
});
|
|
5027
5027
|
}
|
|
@@ -5309,7 +5309,7 @@ function newError(Definition) {
|
|
|
5309
5309
|
return new Definition();
|
|
5310
5310
|
}
|
|
5311
5311
|
// @__NO_SIDE_EFFECTS__
|
|
5312
|
-
function $constructor(
|
|
5312
|
+
function $constructor(name2, initializer3, proto, params) {
|
|
5313
5313
|
const zodProto = {};
|
|
5314
5314
|
function Internals(def) {
|
|
5315
5315
|
this.def = def;
|
|
@@ -5327,10 +5327,10 @@ function $constructor(name, initializer3, proto, params) {
|
|
|
5327
5327
|
} finally {
|
|
5328
5328
|
_zodDesc.value = void 0;
|
|
5329
5329
|
}
|
|
5330
|
-
} else if (inst._zod.traits.has(
|
|
5330
|
+
} else if (inst._zod.traits.has(name2)) {
|
|
5331
5331
|
return;
|
|
5332
5332
|
}
|
|
5333
|
-
inst._zod.traits.add(
|
|
5333
|
+
inst._zod.traits.add(name2);
|
|
5334
5334
|
initializer3(inst, def);
|
|
5335
5335
|
if (initialized) {
|
|
5336
5336
|
const own2 = Object.getPrototypeOf(inst);
|
|
@@ -5356,7 +5356,7 @@ function $constructor(name, initializer3, proto, params) {
|
|
|
5356
5356
|
const Parent = params?.Parent ?? Object;
|
|
5357
5357
|
class Definition extends Parent {
|
|
5358
5358
|
}
|
|
5359
|
-
Object.defineProperty(Definition, "name", { value:
|
|
5359
|
+
Object.defineProperty(Definition, "name", { value: name2 });
|
|
5360
5360
|
function _(def) {
|
|
5361
5361
|
const inst = params?.Parent ? newError(Definition) : this;
|
|
5362
5362
|
init(inst, def);
|
|
@@ -5377,10 +5377,10 @@ function $constructor(name, initializer3, proto, params) {
|
|
|
5377
5377
|
value: (inst) => {
|
|
5378
5378
|
if (params?.Parent && inst instanceof params.Parent)
|
|
5379
5379
|
return true;
|
|
5380
|
-
return inst?._zod?.traits?.has(
|
|
5380
|
+
return inst?._zod?.traits?.has(name2);
|
|
5381
5381
|
}
|
|
5382
5382
|
});
|
|
5383
|
-
Object.defineProperty(_, "name", { value:
|
|
5383
|
+
Object.defineProperty(_, "name", { value: name2 });
|
|
5384
5384
|
return _;
|
|
5385
5385
|
}
|
|
5386
5386
|
var $brand = /* @__PURE__ */ Symbol("zod_brand");
|
|
@@ -5390,8 +5390,8 @@ var $ZodAsyncError = class extends Error {
|
|
|
5390
5390
|
}
|
|
5391
5391
|
};
|
|
5392
5392
|
var $ZodEncodeError = class extends Error {
|
|
5393
|
-
constructor(
|
|
5394
|
-
super(`Encountered unidirectional transform during encode: ${
|
|
5393
|
+
constructor(name2) {
|
|
5394
|
+
super(`Encountered unidirectional transform during encode: ${name2}`);
|
|
5395
5395
|
this.name = "ZodEncodeError";
|
|
5396
5396
|
}
|
|
5397
5397
|
};
|
|
@@ -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, path13 = []) => {
|
|
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 }, [...path13, ...issue2.path]));
|
|
5478
5478
|
} else if (issue2.code === "invalid_key") {
|
|
5479
|
-
processError({ issues: issue2.issues }, [...
|
|
5479
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
5480
5480
|
} else if (issue2.code === "invalid_element") {
|
|
5481
|
-
processError({ issues: issue2.issues }, [...
|
|
5481
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
5482
5482
|
} else {
|
|
5483
|
-
const fullpath = [...
|
|
5483
|
+
const fullpath = [...path13, ...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, path13 = []) => {
|
|
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 }, [...path13, ...issue2.path]));
|
|
5527
5527
|
} else if (issue2.code === "invalid_key") {
|
|
5528
|
-
processError({ issues: issue2.issues }, [...
|
|
5528
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
5529
5529
|
} else if (issue2.code === "invalid_element") {
|
|
5530
|
-
processError({ issues: issue2.issues }, [...
|
|
5530
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
5531
5531
|
} else {
|
|
5532
|
-
const fullpath = [...
|
|
5532
|
+
const fullpath = [...path13, ...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 path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5572
|
+
for (const seg of path13) {
|
|
5573
5573
|
if (typeof seg === "number")
|
|
5574
5574
|
segs.push(`[${seg}]`);
|
|
5575
5575
|
else if (typeof seg === "symbol")
|
|
@@ -16890,13 +16890,13 @@ ${code}
|
|
|
16890
16890
|
return fn;
|
|
16891
16891
|
}
|
|
16892
16892
|
function addConstant(ctx, value) {
|
|
16893
|
-
for (const [
|
|
16893
|
+
for (const [name3, v] of ctx.constants) {
|
|
16894
16894
|
if (v === value)
|
|
16895
|
-
return
|
|
16895
|
+
return name3;
|
|
16896
16896
|
}
|
|
16897
|
-
const
|
|
16898
|
-
ctx.constants.set(
|
|
16899
|
-
return
|
|
16897
|
+
const name2 = `c${ctx.constantCounter++}`;
|
|
16898
|
+
ctx.constants.set(name2, value);
|
|
16899
|
+
return name2;
|
|
16900
16900
|
}
|
|
16901
16901
|
function addUserConstant(ctx, fn) {
|
|
16902
16902
|
ctx.definite = false;
|
|
@@ -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 path13 = ref.slice(1).split("/").filter(Boolean);
|
|
22675
|
+
if (path13.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 (path13[0] === defsKey) {
|
|
22680
|
+
const key = path13[1] === void 0 ? void 0 : decodeJSONPointerSegment(path13[1]);
|
|
22681
22681
|
if (!key || !ctx.defs[key]) {
|
|
22682
22682
|
throw new Error(`Reference not found: ${ref}`);
|
|
22683
22683
|
}
|
|
@@ -23643,9 +23643,9 @@ function isDisjoint(...headers) {
|
|
|
23643
23643
|
}
|
|
23644
23644
|
return true;
|
|
23645
23645
|
}
|
|
23646
|
-
function assertNotSet(value,
|
|
23646
|
+
function assertNotSet(value, name2) {
|
|
23647
23647
|
if (value !== void 0)
|
|
23648
|
-
throw new TypeError(`${
|
|
23648
|
+
throw new TypeError(`${name2} can only be called once`);
|
|
23649
23649
|
}
|
|
23650
23650
|
function decodeBase64url(value, label, ErrorClass) {
|
|
23651
23651
|
try {
|
|
@@ -23806,7 +23806,7 @@ function invalidKeyType(alg, actual, secret) {
|
|
|
23806
23806
|
const types = ["CryptoKey", "KeyObject", "JSON Web Key"];
|
|
23807
23807
|
return secret && types.push("Uint8Array"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));
|
|
23808
23808
|
}
|
|
23809
|
-
var unusable = (
|
|
23809
|
+
var unusable = (name2, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name2}`);
|
|
23810
23810
|
function checkUsage(key, usage) {
|
|
23811
23811
|
if (usage && !key.usages.includes(usage))
|
|
23812
23812
|
throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
@@ -24295,8 +24295,145 @@ var ActionEvidenceSchema = external_exports.object({
|
|
|
24295
24295
|
errorCode: external_exports.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/).optional()
|
|
24296
24296
|
}).strict();
|
|
24297
24297
|
|
|
24298
|
-
// packages/contracts/src/
|
|
24298
|
+
// packages/contracts/src/index.ts
|
|
24299
|
+
var protocolVersion = 1;
|
|
24300
|
+
var MAX_FILE_WRITE_BYTES = 1024 * 1024;
|
|
24301
|
+
var MAX_RELAY_FRAME_BYTES = 8 * 1024 * 1024;
|
|
24299
24302
|
var uuid5 = external_exports.string().uuid().toLowerCase();
|
|
24303
|
+
var nonEmpty = external_exports.string().trim().min(1);
|
|
24304
|
+
var utcDateTime2 = external_exports.iso.datetime({ offset: false }).refine((value) => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/.test(value), "Expected UTC timestamp with seconds");
|
|
24305
|
+
var units = external_exports.number().int().min(0).max(1e9);
|
|
24306
|
+
function validUsagePeriod(value) {
|
|
24307
|
+
const start = new Date(value.periodStartUtc);
|
|
24308
|
+
if (!Number.isFinite(start.getTime()) || start.getUTCDate() !== 1 || start.getUTCHours() !== 0 || start.getUTCMinutes() !== 0 || start.getUTCSeconds() !== 0 || start.getUTCMilliseconds() !== 0) return false;
|
|
24309
|
+
const end = new Date(start);
|
|
24310
|
+
end.setUTCMonth(end.getUTCMonth() + 1);
|
|
24311
|
+
return Date.parse(value.periodEndUtc) === end.getTime();
|
|
24312
|
+
}
|
|
24313
|
+
var PermissionScopeSchema = external_exports.enum([
|
|
24314
|
+
"devices:read",
|
|
24315
|
+
"sessions:manage",
|
|
24316
|
+
"files:read",
|
|
24317
|
+
"files:write",
|
|
24318
|
+
"commands:execute",
|
|
24319
|
+
"processes:control",
|
|
24320
|
+
"localhost:access"
|
|
24321
|
+
]);
|
|
24322
|
+
var OperationStateSchema = external_exports.enum([
|
|
24323
|
+
"queued",
|
|
24324
|
+
"prepared",
|
|
24325
|
+
"accepted",
|
|
24326
|
+
"running",
|
|
24327
|
+
"finished",
|
|
24328
|
+
"failed",
|
|
24329
|
+
"cancel_requested",
|
|
24330
|
+
"cancelled",
|
|
24331
|
+
"rejected",
|
|
24332
|
+
"unknown"
|
|
24333
|
+
]);
|
|
24334
|
+
var ErrorCodeSchema = external_exports.enum([
|
|
24335
|
+
"AUTH_REQUIRED",
|
|
24336
|
+
"GRANT_REVOKED",
|
|
24337
|
+
"DEVICE_OFFLINE",
|
|
24338
|
+
"SETUP_REQUIRED",
|
|
24339
|
+
"DEVICE_NOT_OWNED",
|
|
24340
|
+
"SESSION_EXPIRED",
|
|
24341
|
+
"LOCAL_PERMISSION_REQUIRED",
|
|
24342
|
+
"QUOTA_EXHAUSTED",
|
|
24343
|
+
"CAPACITY_BUSY",
|
|
24344
|
+
"RESOURCE_BUSY",
|
|
24345
|
+
"POLICY_DENIED",
|
|
24346
|
+
"TOOL_MISSING",
|
|
24347
|
+
"TIMEOUT",
|
|
24348
|
+
"CANCEL_REQUESTED",
|
|
24349
|
+
"EXECUTION_UNKNOWN",
|
|
24350
|
+
"OUTPUT_EXPIRED",
|
|
24351
|
+
"INFRA_UNAVAILABLE",
|
|
24352
|
+
"IDEMPOTENCY_CONFLICT"
|
|
24353
|
+
]);
|
|
24354
|
+
var LedgerEventKindSchema = external_exports.enum(["reserve", "charge", "release", "credit"]);
|
|
24355
|
+
var TrustedPrincipalSchema = external_exports.object({
|
|
24356
|
+
protocolVersion: external_exports.literal(protocolVersion),
|
|
24357
|
+
accountId: uuid5,
|
|
24358
|
+
tenantId: uuid5,
|
|
24359
|
+
grantId: uuid5,
|
|
24360
|
+
scopes: external_exports.array(PermissionScopeSchema).min(1).max(32),
|
|
24361
|
+
authenticatedAt: utcDateTime2,
|
|
24362
|
+
expiresAt: utcDateTime2
|
|
24363
|
+
}).strict().refine((value) => Date.parse(value.authenticatedAt) < Date.parse(value.expiresAt), { path: ["expiresAt"], message: "Expiry must follow authentication" });
|
|
24364
|
+
var ExecutionSessionSchema = external_exports.object({
|
|
24365
|
+
protocolVersion: external_exports.literal(protocolVersion),
|
|
24366
|
+
executionSessionId: uuid5,
|
|
24367
|
+
tenantId: uuid5,
|
|
24368
|
+
grantId: uuid5,
|
|
24369
|
+
deviceId: uuid5,
|
|
24370
|
+
workspaceGrantId: uuid5.optional(),
|
|
24371
|
+
policyVersion: external_exports.string().trim().min(1).max(64),
|
|
24372
|
+
openedAt: utcDateTime2,
|
|
24373
|
+
expiresAt: utcDateTime2,
|
|
24374
|
+
state: external_exports.enum(["open", "closing", "closed", "expired"])
|
|
24375
|
+
}).strict().refine((value) => Date.parse(value.openedAt) < Date.parse(value.expiresAt), { path: ["expiresAt"], message: "Expiry must follow session creation" });
|
|
24376
|
+
var ChildCommandSchema = external_exports.object({
|
|
24377
|
+
childExecutionId: uuid5,
|
|
24378
|
+
executable: nonEmpty.max(260),
|
|
24379
|
+
argv: external_exports.array(external_exports.string().max(8192)).max(128).default([]),
|
|
24380
|
+
cwd: external_exports.string().trim().min(1).max(2048).optional(),
|
|
24381
|
+
deadlineAt: utcDateTime2.optional()
|
|
24382
|
+
}).strict();
|
|
24383
|
+
var ClientCommandRequestSchema = external_exports.object({
|
|
24384
|
+
protocolVersion: external_exports.literal(protocolVersion),
|
|
24385
|
+
executionSessionId: uuid5,
|
|
24386
|
+
operationId: uuid5,
|
|
24387
|
+
idempotencyKey: external_exports.string().trim().min(8).max(128),
|
|
24388
|
+
children: external_exports.array(ChildCommandSchema).min(2).max(32)
|
|
24389
|
+
}).strict().superRefine((value, ctx) => {
|
|
24390
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24391
|
+
value.children.forEach((child, index) => {
|
|
24392
|
+
if (seen.has(child.childExecutionId)) {
|
|
24393
|
+
ctx.addIssue({ code: "custom", path: ["children", index, "childExecutionId"], message: "childExecutionId must be unique within a batch" });
|
|
24394
|
+
}
|
|
24395
|
+
seen.add(child.childExecutionId);
|
|
24396
|
+
});
|
|
24397
|
+
});
|
|
24398
|
+
var ControlOperationSchema = external_exports.object({
|
|
24399
|
+
protocolVersion: external_exports.literal(protocolVersion),
|
|
24400
|
+
executionSessionId: uuid5,
|
|
24401
|
+
operationId: uuid5,
|
|
24402
|
+
kind: external_exports.enum(["status", "output", "cancel"]),
|
|
24403
|
+
cursor: external_exports.string().trim().min(1).max(512).optional()
|
|
24404
|
+
}).strict();
|
|
24405
|
+
var LedgerEventSchema = external_exports.object({
|
|
24406
|
+
protocolVersion: external_exports.literal(protocolVersion),
|
|
24407
|
+
tenantId: uuid5,
|
|
24408
|
+
executionId: uuid5,
|
|
24409
|
+
eventKind: LedgerEventKindSchema,
|
|
24410
|
+
units: external_exports.literal(1),
|
|
24411
|
+
periodStartUtc: utcDateTime2,
|
|
24412
|
+
periodEndUtc: utcDateTime2,
|
|
24413
|
+
occurredAt: utcDateTime2,
|
|
24414
|
+
adjustmentId: uuid5.optional()
|
|
24415
|
+
}).strict().refine(validUsagePeriod, { path: ["periodEndUtc"], message: "Expected one UTC calendar month" }).refine((value) => value.eventKind !== "credit" || value.adjustmentId !== void 0, { path: ["adjustmentId"], message: "Credit requires a unique adjustment ID" });
|
|
24416
|
+
var UsageCountersSchema = external_exports.object({
|
|
24417
|
+
protocolVersion: external_exports.literal(protocolVersion),
|
|
24418
|
+
tenantId: uuid5,
|
|
24419
|
+
periodStartUtc: utcDateTime2,
|
|
24420
|
+
periodEndUtc: utcDateTime2,
|
|
24421
|
+
limitUnits: units,
|
|
24422
|
+
reservedUnits: units,
|
|
24423
|
+
consumedUnits: units,
|
|
24424
|
+
creditedUnits: units
|
|
24425
|
+
}).strict().refine(validUsagePeriod, { path: ["periodEndUtc"], message: "Expected one UTC calendar month" });
|
|
24426
|
+
var OperationErrorSchema = external_exports.object({
|
|
24427
|
+
protocolVersion: external_exports.literal(protocolVersion),
|
|
24428
|
+
code: ErrorCodeSchema,
|
|
24429
|
+
message: external_exports.string().trim().min(1).max(512),
|
|
24430
|
+
retryable: external_exports.boolean(),
|
|
24431
|
+
dispatched: external_exports.boolean(),
|
|
24432
|
+
quotaEffect: external_exports.enum(["none", "reserved", "charged", "released", "credited", "unknown"])
|
|
24433
|
+
}).strict();
|
|
24434
|
+
|
|
24435
|
+
// packages/contracts/src/device-protocol.ts
|
|
24436
|
+
var uuid8 = external_exports.string().uuid().toLowerCase();
|
|
24300
24437
|
var hash2 = external_exports.string().regex(/^[a-f0-9]{64}$/);
|
|
24301
24438
|
var epoch = external_exports.string().regex(/^[1-9]\d{0,18}$/).refine((v) => BigInt(v) <= 9223372036854775807n);
|
|
24302
24439
|
var text = external_exports.string().max(32767).refine((v) => !v.includes("\0"));
|
|
@@ -24306,7 +24443,7 @@ var ToolCallSchema = external_exports.discriminatedUnion("name", [
|
|
|
24306
24443
|
external_exports.object({ name: external_exports.literal("fs_list"), args: external_exports.object({ path: path.optional(), recursive: external_exports.boolean().default(false), maxDepth: external_exports.number().int().min(0).max(8).default(3), maxEntries: external_exports.number().int().min(1).max(1e3).default(200) }).strict() }).strict(),
|
|
24307
24444
|
external_exports.object({ name: external_exports.literal("fs_read"), args: external_exports.object({ path, startLine: external_exports.number().int().min(1).max(1e6).optional(), endLine: external_exports.number().int().min(1).max(1e6).optional() }).strict() }).strict(),
|
|
24308
24445
|
external_exports.object({ name: external_exports.literal("fs_search"), args: external_exports.object({ path: path.optional(), query: external_exports.string().min(1).max(1e3), caseSensitive: external_exports.boolean().default(false), maxResults: external_exports.number().int().min(1).max(300).default(100) }).strict() }).strict(),
|
|
24309
|
-
external_exports.object({ name: external_exports.literal("fs_write"), args: external_exports.object({ path, content: external_exports.string().max(
|
|
24446
|
+
external_exports.object({ name: external_exports.literal("fs_write"), args: external_exports.object({ path, content: external_exports.string().max(MAX_FILE_WRITE_BYTES).refine((value) => Buffer.byteLength(value, "utf8") <= MAX_FILE_WRITE_BYTES, "fs_write content exceeds 1 MiB UTF-8"), overwrite: external_exports.boolean().default(false), expectedSha256: hash2.optional() }).strict() }).strict(),
|
|
24310
24447
|
external_exports.object({ name: external_exports.literal("fs_replace"), args: external_exports.object({ path, oldText: external_exports.string().min(1).max(6e4), newText: external_exports.string().max(6e4), replaceAll: external_exports.boolean().default(false), expectedSha256: hash2.optional() }).strict() }).strict(),
|
|
24311
24448
|
external_exports.object({ name: external_exports.literal("git_status"), args: external_exports.object({ path: path.optional() }).strict() }).strict(),
|
|
24312
24449
|
external_exports.object({ name: external_exports.literal("git_diff"), args: external_exports.object({ path: path.optional(), file: path.optional(), staged: external_exports.boolean().default(false) }).strict() }).strict(),
|
|
@@ -24320,32 +24457,32 @@ function scopeForTool(call) {
|
|
|
24320
24457
|
if (call.name === "localhost_request") return "localhost:access";
|
|
24321
24458
|
return call.name === "fs_write" || call.name === "fs_replace" ? "files:write" : "files:read";
|
|
24322
24459
|
}
|
|
24323
|
-
var ExecutionBindingSchema = external_exports.object({ tenantId:
|
|
24460
|
+
var ExecutionBindingSchema = external_exports.object({ tenantId: uuid8, accountId: uuid8.optional(), deviceId: uuid8, grantId: uuid8, sessionId: uuid8, operationId: uuid8, executionId: uuid8, connectionEpoch: epoch, workspaceGrantId: uuid8, policyVersion: external_exports.number().int().min(1).max(2147483647), payloadHash: hash2, deadlineAt: timestamp }).strict();
|
|
24324
24461
|
var EfficiencyNoticeSchema = external_exports.object({ message: external_exports.string().min(1).max(160), estimatedSavedTokens: external_exports.number().int().min(1).max(1e12), savedBytes: external_exports.number().int().min(1).max(1e12), sessionCalls: external_exports.number().int().min(20).max(1e9) }).strict();
|
|
24325
24462
|
var ResultSchema = external_exports.object({ exitCode: external_exports.number().int().min(-2147483648).max(4294967295).nullable(), timedOut: external_exports.boolean(), cancelled: external_exports.boolean(), treeTerminated: external_exports.boolean(), stdout: external_exports.string().max(196608), stderr: external_exports.string().max(196608), stdoutTruncated: external_exports.boolean(), stderrTruncated: external_exports.boolean(), resultCode: external_exports.string().regex(/^[A-Z0-9_]{1,40}$/), efficiencyNotice: EfficiencyNoticeSchema.optional() }).strict();
|
|
24326
24463
|
var ServerFrameSchema = external_exports.discriminatedUnion("type", [
|
|
24327
|
-
external_exports.object({ type: external_exports.literal("hello"), version: external_exports.literal(1), tenantId:
|
|
24464
|
+
external_exports.object({ type: external_exports.literal("hello"), version: external_exports.literal(1), tenantId: uuid8, deviceId: uuid8, connectionEpoch: epoch, serverTime: timestamp }).strict(),
|
|
24328
24465
|
external_exports.object({ type: external_exports.literal("prepare"), version: external_exports.literal(1), binding: ExecutionBindingSchema, tool: ToolCallSchema }).strict(),
|
|
24329
24466
|
external_exports.object({ type: external_exports.literal("execute"), version: external_exports.literal(1), binding: ExecutionBindingSchema }).strict(),
|
|
24330
|
-
external_exports.object({ type: external_exports.literal("control"), version: external_exports.literal(1), requestId:
|
|
24467
|
+
external_exports.object({ type: external_exports.literal("control"), version: external_exports.literal(1), requestId: uuid8, binding: ExecutionBindingSchema, action: external_exports.enum(["status", "output", "cancel"]) }).strict(),
|
|
24331
24468
|
external_exports.object({ type: external_exports.literal("heartbeat_ack"), version: external_exports.literal(1), connectionEpoch: epoch, leaseExpiresAt: timestamp }).strict(),
|
|
24332
|
-
external_exports.object({ type: external_exports.literal("workspace_ack"), version: external_exports.literal(1), requestId:
|
|
24469
|
+
external_exports.object({ type: external_exports.literal("workspace_ack"), version: external_exports.literal(1), requestId: uuid8, workspaceGrantId: uuid8, accepted: external_exports.boolean(), code: external_exports.string().max(64).optional() }).strict(),
|
|
24333
24470
|
external_exports.object({ type: external_exports.literal("revoke"), version: external_exports.literal(1), reason: external_exports.enum(["device_revoked", "account_revoked", "server_shutdown", "connection_replaced"]) }).strict()
|
|
24334
24471
|
]);
|
|
24335
24472
|
var ClientFrameSchema = external_exports.discriminatedUnion("type", [
|
|
24336
24473
|
external_exports.object({ type: external_exports.literal("ready"), version: external_exports.literal(1), safeSlots: external_exports.number().int().min(1).max(128), platform: external_exports.literal("win32"), agentVersion: external_exports.string().regex(/^[A-Za-z0-9._+-]{1,64}$/), supervisor: external_exports.boolean() }).strict(),
|
|
24337
24474
|
external_exports.object({ type: external_exports.literal("heartbeat"), version: external_exports.literal(1), connectionEpoch: epoch }).strict(),
|
|
24338
|
-
external_exports.object({ type: external_exports.literal("workspace_grant"), version: external_exports.literal(1), requestId:
|
|
24339
|
-
external_exports.object({ type: external_exports.literal("workspace_revoke"), version: external_exports.literal(1), requestId:
|
|
24475
|
+
external_exports.object({ type: external_exports.literal("workspace_grant"), version: external_exports.literal(1), requestId: uuid8, workspaceGrantId: uuid8, rootHash: hash2, displayName: external_exports.string().min(1).max(120), policyVersion: external_exports.number().int().min(1).max(2147483647) }).strict(),
|
|
24476
|
+
external_exports.object({ type: external_exports.literal("workspace_revoke"), version: external_exports.literal(1), requestId: uuid8, workspaceGrantId: uuid8 }).strict(),
|
|
24340
24477
|
external_exports.object({ type: external_exports.literal("prepared"), version: external_exports.literal(1), binding: ExecutionBindingSchema }).strict(),
|
|
24341
24478
|
external_exports.object({ type: external_exports.literal("accepted"), version: external_exports.literal(1), binding: ExecutionBindingSchema }).strict(),
|
|
24342
24479
|
external_exports.object({ type: external_exports.literal("running"), version: external_exports.literal(1), binding: ExecutionBindingSchema, pid: external_exports.number().int().positive().optional() }).strict(),
|
|
24343
24480
|
external_exports.object({ type: external_exports.literal("result"), version: external_exports.literal(1), binding: ExecutionBindingSchema, result: ResultSchema }).strict(),
|
|
24344
24481
|
external_exports.object({ type: external_exports.literal("not_accepted"), version: external_exports.literal(1), binding: ExecutionBindingSchema, code: external_exports.string().regex(/^[A-Z0-9_]{1,40}$/), provedNotStarted: external_exports.boolean() }).strict(),
|
|
24345
|
-
external_exports.object({ type: external_exports.literal("control_result"), version: external_exports.literal(1), requestId:
|
|
24482
|
+
external_exports.object({ type: external_exports.literal("control_result"), version: external_exports.literal(1), requestId: uuid8, binding: ExecutionBindingSchema, state: external_exports.enum(["prepared", "accepted", "running", "finished", "failed", "cancelled", "rejected", "unknown", "missing"]), result: ResultSchema.optional() }).strict()
|
|
24346
24483
|
]);
|
|
24347
|
-
var TerminalEventSchema = external_exports.object({ type: external_exports.literal("executionResult"), protocolVersion: external_exports.literal(1), requestId:
|
|
24348
|
-
var TerminalEventAckSchema = external_exports.object({ type: external_exports.literal("executionResultAck"), protocolVersion: external_exports.literal(1), requestId:
|
|
24484
|
+
var TerminalEventSchema = external_exports.object({ type: external_exports.literal("executionResult"), protocolVersion: external_exports.literal(1), requestId: uuid8, tenantId: uuid8, deviceId: uuid8, connectionEpoch: epoch, binding: ExecutionBindingSchema, state: external_exports.enum(["finished", "failed", "cancelled", "unknown"]), resultCode: external_exports.string().regex(/^[A-Z0-9_]{1,40}$/) }).strict();
|
|
24485
|
+
var TerminalEventAckSchema = external_exports.object({ type: external_exports.literal("executionResultAck"), protocolVersion: external_exports.literal(1), requestId: uuid8, ok: external_exports.boolean() }).strict();
|
|
24349
24486
|
function canonicalJson(value) {
|
|
24350
24487
|
function canonical2(v) {
|
|
24351
24488
|
if (Array.isArray(v)) return v.map(canonical2);
|
|
@@ -24378,16 +24515,16 @@ var guardAdapter = AdapterDescriptorSchema.parse({
|
|
|
24378
24515
|
detectsNativeBypass: false
|
|
24379
24516
|
}
|
|
24380
24517
|
});
|
|
24381
|
-
var
|
|
24518
|
+
var uuid9 = external_exports.string().uuid().toLowerCase();
|
|
24382
24519
|
var GuardSettingsSchema = external_exports.object({
|
|
24383
24520
|
policyId: external_exports.string().regex(/^[a-z][a-z0-9._-]{0,63}$/),
|
|
24384
24521
|
keys: external_exports.array(external_exports.object({ keyId: external_exports.string().regex(/^[a-z][a-z0-9._-]{0,63}$/), publicKeyPem: external_exports.string().max(1024) }).strict()).min(1).max(8),
|
|
24385
24522
|
environment: EnvironmentContextSchema
|
|
24386
24523
|
}).strict();
|
|
24387
24524
|
var GuardConfigurationSchema = GuardSettingsSchema.extend({
|
|
24388
|
-
tenantId:
|
|
24389
|
-
deviceId:
|
|
24390
|
-
ownerAccountId:
|
|
24525
|
+
tenantId: uuid9,
|
|
24526
|
+
deviceId: uuid9,
|
|
24527
|
+
ownerAccountId: uuid9,
|
|
24391
24528
|
ownerSid: external_exports.string().regex(/^S-1-(?:[0-9]+-)+[0-9]+$/).max(184)
|
|
24392
24529
|
}).strict();
|
|
24393
24530
|
function guardHash(value) {
|
|
@@ -24410,9 +24547,9 @@ function guardAction(binding2, tool, config2, observedAt) {
|
|
|
24410
24547
|
if (!binding2.accountId || binding2.tenantId !== config2.tenantId || binding2.deviceId !== config2.deviceId || !tool.effective) {
|
|
24411
24548
|
throw Error("GUARD_IDENTITY_REQUIRED");
|
|
24412
24549
|
}
|
|
24413
|
-
const
|
|
24414
|
-
const kind =
|
|
24415
|
-
const resourceKind = kind === "execute" ? "workspace" : kind === "localhost-access" ? "localhost-service" : kind === "git-read" ? "git-repository" :
|
|
24550
|
+
const name2 = tool.call.name;
|
|
24551
|
+
const kind = name2 === "command_run" ? "execute" : name2 === "localhost_request" ? "localhost-access" : name2 === "fs_write" || name2 === "fs_replace" ? "write" : name2.startsWith("git_") ? "git-read" : "read";
|
|
24552
|
+
const resourceKind = kind === "execute" ? "workspace" : kind === "localhost-access" ? "localhost-service" : kind === "git-read" ? "git-repository" : name2 === "fs_read" || kind === "write" ? "file" : "workspace";
|
|
24416
24553
|
return { payloadHash: guardHash(tool.effective), request: BoundActionRequestSchema.parse({
|
|
24417
24554
|
protocolVersion: 1,
|
|
24418
24555
|
requestId: binding2.executionId,
|
|
@@ -24432,13 +24569,13 @@ function guardAction(binding2, tool, config2, observedAt) {
|
|
|
24432
24569
|
adapter: guardAdapter,
|
|
24433
24570
|
actor: { kind: "human", subjectRef: binding2.accountId, authenticationClass: "delegated" },
|
|
24434
24571
|
agent: { agentRef: "grant:" + binding2.grantId },
|
|
24435
|
-
tool: { namespace: "local-commander", name },
|
|
24572
|
+
tool: { namespace: "local-commander", name: name2 },
|
|
24436
24573
|
resource: { kind: resourceKind, locatorFingerprint: guardHash({
|
|
24437
24574
|
workspace: binding2.workspaceGrantId,
|
|
24438
24575
|
resources: tool.claims,
|
|
24439
|
-
...
|
|
24576
|
+
...name2 === "localhost_request" ? { url: tool.call.args.url } : {}
|
|
24440
24577
|
}) },
|
|
24441
|
-
action: { kind, verb:
|
|
24578
|
+
action: { kind, verb: name2, effect: kind === "execute" ? "external-mutation" : kind === "write" ? "local-mutation" : kind === "localhost-access" ? "external-mutation" : "read-only" },
|
|
24442
24579
|
dataClassifications: ["unknown"],
|
|
24443
24580
|
environment: config2.environment
|
|
24444
24581
|
}
|
|
@@ -24448,7 +24585,7 @@ function guardSummary(tool) {
|
|
|
24448
24585
|
if (!tool.effective) throw Error("GUARD_ACTION_INVALID");
|
|
24449
24586
|
const call = tool.call;
|
|
24450
24587
|
const args = { ...call.args };
|
|
24451
|
-
if (args.headers) args.headers = Object.keys(args.headers).map((
|
|
24588
|
+
if (args.headers) args.headers = Object.keys(args.headers).map((name2) => name2 + " (value hidden)");
|
|
24452
24589
|
return JSON.stringify({
|
|
24453
24590
|
tool: call.name,
|
|
24454
24591
|
resources: tool.claims,
|
|
@@ -24468,14 +24605,14 @@ var GuardEventSchema = external_exports.object({
|
|
|
24468
24605
|
previousHash: hash3,
|
|
24469
24606
|
hash: hash3
|
|
24470
24607
|
}).strict();
|
|
24471
|
-
var
|
|
24608
|
+
var uuid10 = external_exports.string().uuid().toLowerCase();
|
|
24472
24609
|
var GuardEvidenceRecordSchema = external_exports.object({
|
|
24473
|
-
tenantId:
|
|
24474
|
-
deviceId:
|
|
24475
|
-
accountId:
|
|
24476
|
-
sessionId:
|
|
24477
|
-
operationId:
|
|
24478
|
-
executionId:
|
|
24610
|
+
tenantId: uuid10,
|
|
24611
|
+
deviceId: uuid10,
|
|
24612
|
+
accountId: uuid10.optional(),
|
|
24613
|
+
sessionId: uuid10,
|
|
24614
|
+
operationId: uuid10,
|
|
24615
|
+
executionId: uuid10,
|
|
24479
24616
|
state: external_exports.enum(["prepared", "accepted", "running", "finished", "failed", "cancelled", "rejected", "unknown"]),
|
|
24480
24617
|
events: external_exports.array(GuardEventSchema).min(1).max(12)
|
|
24481
24618
|
}).strict();
|
|
@@ -24494,8 +24631,8 @@ function appendGuardEvent(events, input2) {
|
|
|
24494
24631
|
}
|
|
24495
24632
|
var ExportSchema = external_exports.object({
|
|
24496
24633
|
formatVersion: external_exports.literal(1),
|
|
24497
|
-
tenantId:
|
|
24498
|
-
deviceId:
|
|
24634
|
+
tenantId: uuid10,
|
|
24635
|
+
deviceId: uuid10,
|
|
24499
24636
|
records: external_exports.array(GuardEvidenceRecordSchema).max(1e3)
|
|
24500
24637
|
}).strict();
|
|
24501
24638
|
var HeaderSchema = external_exports.object({ alg: external_exports.literal("EdDSA"), typ: external_exports.literal("lc-guard-evidence+jws"), kid: hash3 }).strict();
|
|
@@ -24538,7 +24675,7 @@ async function signGuardEvidence(records, identity) {
|
|
|
24538
24675
|
}
|
|
24539
24676
|
|
|
24540
24677
|
// agent/src/journal.ts
|
|
24541
|
-
var
|
|
24678
|
+
var uuid11 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
24542
24679
|
var hash4 = /^[0-9a-f]{64}$/;
|
|
24543
24680
|
var bindingKeys = ["executionId", "operationId", "sessionId", "tenantId", "grantId", "deviceId", "connectionEpoch", "payloadHash", "deadlineAt", "workspaceGrantId", "policyVersion", "accountId"];
|
|
24544
24681
|
var terminal = /* @__PURE__ */ new Set(["finished", "failed", "cancelled", "rejected"]);
|
|
@@ -24558,10 +24695,10 @@ function canonicalTime(value) {
|
|
|
24558
24695
|
}
|
|
24559
24696
|
function validateInput(value) {
|
|
24560
24697
|
if (!value || typeof value !== "object" || Object.keys(value).some((k) => !bindingKeys.includes(k))) throw failure2("JOURNAL_INPUT_INVALID");
|
|
24561
|
-
for (const
|
|
24562
|
-
if (value.accountId !== void 0 && !
|
|
24698
|
+
for (const name2 of bindingKeys.slice(0, 6)) if (typeof value[name2] !== "string" || !uuid11.test(value[name2])) throw failure2("JOURNAL_INPUT_INVALID");
|
|
24699
|
+
if (value.accountId !== void 0 && !uuid11.test(value.accountId)) throw failure2("JOURNAL_INPUT_INVALID");
|
|
24563
24700
|
if (typeof value.connectionEpoch !== "string" || !/^[1-9]\d{0,18}$/.test(value.connectionEpoch) || BigInt(value.connectionEpoch) > 9223372036854775807n || typeof value.payloadHash !== "string" || !hash4.test(value.payloadHash) || !canonicalTime(value.deadlineAt)) throw failure2("JOURNAL_INPUT_INVALID");
|
|
24564
|
-
if (value.workspaceGrantId === void 0 !== (value.policyVersion === void 0) || value.workspaceGrantId !== void 0 && (!
|
|
24701
|
+
if (value.workspaceGrantId === void 0 !== (value.policyVersion === void 0) || value.workspaceGrantId !== void 0 && (!uuid11.test(value.workspaceGrantId) || !Number.isInteger(value.policyVersion) || value.policyVersion < 1 || value.policyVersion > 2147483647)) throw failure2("JOURNAL_INPUT_INVALID");
|
|
24565
24702
|
}
|
|
24566
24703
|
function clone2(value) {
|
|
24567
24704
|
return structuredClone(value);
|
|
@@ -24660,7 +24797,7 @@ var NativeJournal = class _NativeJournal {
|
|
|
24660
24797
|
return path2.join(this.dir, id + ".entry");
|
|
24661
24798
|
}
|
|
24662
24799
|
need(id) {
|
|
24663
|
-
if (!
|
|
24800
|
+
if (!uuid11.test(id)) throw failure2("JOURNAL_INPUT_INVALID");
|
|
24664
24801
|
const e = this.entries.get(id);
|
|
24665
24802
|
if (!e) throw failure2("EXECUTION_UNKNOWN");
|
|
24666
24803
|
return clone2(e);
|
|
@@ -24680,10 +24817,10 @@ var NativeJournal = class _NativeJournal {
|
|
|
24680
24817
|
async load() {
|
|
24681
24818
|
const names = await readdir(this.dir);
|
|
24682
24819
|
if (names.length > this.options.maxEntries + 256) throw failure2("JOURNAL_CAPACITY_EXCEEDED");
|
|
24683
|
-
for (const
|
|
24684
|
-
if (!
|
|
24685
|
-
const id =
|
|
24686
|
-
if (!
|
|
24820
|
+
for (const name2 of names) {
|
|
24821
|
+
if (!name2.endsWith(".entry")) continue;
|
|
24822
|
+
const id = name2.slice(0, -6);
|
|
24823
|
+
if (!uuid11.test(id)) throw failure2("JOURNAL_CORRUPT");
|
|
24687
24824
|
const envelope = await this.readOwned(id);
|
|
24688
24825
|
this.totalBytes += envelope.length;
|
|
24689
24826
|
if (this.totalBytes > this.options.maxBytes || this.entries.size >= this.options.maxEntries) throw failure2("JOURNAL_CAPACITY_EXCEEDED");
|
|
@@ -24830,7 +24967,7 @@ var NativeJournal = class _NativeJournal {
|
|
|
24830
24967
|
}
|
|
24831
24968
|
get(id) {
|
|
24832
24969
|
return this.enqueue(async () => {
|
|
24833
|
-
if (!
|
|
24970
|
+
if (!uuid11.test(id)) throw failure2("JOURNAL_INPUT_INVALID");
|
|
24834
24971
|
const e = this.entries.get(id);
|
|
24835
24972
|
return e ? clone2(e) : null;
|
|
24836
24973
|
});
|
|
@@ -24946,10 +25083,10 @@ var NativeJournal = class _NativeJournal {
|
|
|
24946
25083
|
|
|
24947
25084
|
// agent/src/private-store.ts
|
|
24948
25085
|
import { constants as constants2 } from "node:fs";
|
|
24949
|
-
import { lstat as
|
|
24950
|
-
import
|
|
25086
|
+
import { lstat as lstat3, open as open3, readFile as readFile2, readdir as readdir2, realpath as realpath3, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
|
|
25087
|
+
import path5 from "node:path";
|
|
24951
25088
|
import os from "node:os";
|
|
24952
|
-
import { createHash as
|
|
25089
|
+
import { createHash as createHash8, createPrivateKey, createPublicKey as createPublicKey3, generateKeyPairSync, randomBytes as randomBytes3, randomUUID as randomUUID3 } from "node:crypto";
|
|
24953
25090
|
import { spawn } from "node:child_process";
|
|
24954
25091
|
|
|
24955
25092
|
// src/child-environment.ts
|
|
@@ -25066,13 +25203,123 @@ function buildChildEnvironment(source, platform = process.platform) {
|
|
|
25066
25203
|
return result2;
|
|
25067
25204
|
}
|
|
25068
25205
|
|
|
25206
|
+
// agent/src/access-selection.ts
|
|
25207
|
+
import path3 from "node:path";
|
|
25208
|
+
function parseAccessSelection(value) {
|
|
25209
|
+
const fail5 = () => {
|
|
25210
|
+
throw Error("ACCESS_SELECTION_INVALID");
|
|
25211
|
+
};
|
|
25212
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return fail5();
|
|
25213
|
+
const input2 = value;
|
|
25214
|
+
if (!Array.isArray(input2.paths)) return fail5();
|
|
25215
|
+
if (input2.mode === "cancelled") {
|
|
25216
|
+
if (input2.paths.length !== 0) return fail5();
|
|
25217
|
+
return null;
|
|
25218
|
+
}
|
|
25219
|
+
if (input2.mode !== "folders" && input2.mode !== "all-drives") return fail5();
|
|
25220
|
+
if (input2.paths.length < 1 || input2.paths.length > (input2.mode === "folders" ? 1 : 26)) return fail5();
|
|
25221
|
+
const roots = [];
|
|
25222
|
+
for (const candidate of input2.paths) {
|
|
25223
|
+
if (typeof candidate !== "string" || candidate.length > 4096 || /[\u0000-\u001f]/.test(candidate) || !path3.win32.isAbsolute(candidate)) return fail5();
|
|
25224
|
+
if (input2.mode === "all-drives" && !/^[a-z]:\\$/i.test(candidate)) return fail5();
|
|
25225
|
+
const normalized = path3.win32.normalize(candidate).toLowerCase();
|
|
25226
|
+
if (roots.some((root) => path3.win32.normalize(root).toLowerCase() === normalized)) return fail5();
|
|
25227
|
+
roots.push(candidate);
|
|
25228
|
+
}
|
|
25229
|
+
return { mode: input2.mode, paths: roots };
|
|
25230
|
+
}
|
|
25231
|
+
|
|
25232
|
+
// agent/src/owner-permissions.ts
|
|
25233
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
25234
|
+
import { lstat as lstat2, realpath as realpath2 } from "node:fs/promises";
|
|
25235
|
+
import path4 from "node:path";
|
|
25236
|
+
var uuid12 = external_exports.string().uuid().toLowerCase();
|
|
25237
|
+
var name = external_exports.string().regex(/^[a-zA-Z0-9_.-]{1,64}$/).toLowerCase();
|
|
25238
|
+
var changeSchema = external_exports.discriminatedUnion("kind", [
|
|
25239
|
+
external_exports.object({ workspaceGrantId: uuid12, kind: external_exports.literal("write"), enabled: external_exports.boolean() }).strict(),
|
|
25240
|
+
external_exports.object({ workspaceGrantId: uuid12, kind: external_exports.literal("localhost"), enabled: external_exports.boolean(), port: external_exports.number().int().min(1).max(65535) }).strict(),
|
|
25241
|
+
external_exports.object({ workspaceGrantId: uuid12, kind: external_exports.literal("command"), enabled: external_exports.boolean(), name, executable: external_exports.string().min(1).max(4096).optional() }).strict()
|
|
25242
|
+
]);
|
|
25243
|
+
var PERMISSION_HISTORY_LIMIT = 64;
|
|
25244
|
+
var PermissionHistorySchema = external_exports.array(external_exports.object({
|
|
25245
|
+
id: uuid12,
|
|
25246
|
+
changedAt: external_exports.string().datetime(),
|
|
25247
|
+
workspaceGrantId: uuid12,
|
|
25248
|
+
kind: external_exports.enum(["write", "command", "localhost"]),
|
|
25249
|
+
enabled: external_exports.boolean(),
|
|
25250
|
+
resourceHash: external_exports.string().regex(/^[a-f0-9]{64}$/),
|
|
25251
|
+
ownerSid: external_exports.string().max(184).regex(/^S-1-(?:[0-9]+-)+[0-9]+$/)
|
|
25252
|
+
}).strict()).max(PERMISSION_HISTORY_LIMIT);
|
|
25253
|
+
function permissionHash(value) {
|
|
25254
|
+
return createHash4("sha256").update(JSON.stringify(value)).digest("hex");
|
|
25255
|
+
}
|
|
25256
|
+
function invalid2(code = "PERMISSION_INVALID") {
|
|
25257
|
+
throw Object.assign(new Error(code), { code });
|
|
25258
|
+
}
|
|
25259
|
+
function parsePermissionChange(value) {
|
|
25260
|
+
const parsed = changeSchema.safeParse(value);
|
|
25261
|
+
if (!parsed.success) invalid2();
|
|
25262
|
+
const change = parsed.data;
|
|
25263
|
+
if (change.kind === "command" && (change.enabled ? !change.executable : change.executable !== void 0)) invalid2();
|
|
25264
|
+
return change;
|
|
25265
|
+
}
|
|
25266
|
+
function equalPath(a, b) {
|
|
25267
|
+
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
25268
|
+
}
|
|
25269
|
+
function permissionLabel(value) {
|
|
25270
|
+
return JSON.stringify(value).replace(
|
|
25271
|
+
/[\u007f-\u009f\u061c\u200b-\u200f\u2028-\u202e\u2060-\u2069\ufeff]/gu,
|
|
25272
|
+
(ch) => "\\u" + ch.charCodeAt(0).toString(16).padStart(4, "0")
|
|
25273
|
+
);
|
|
25274
|
+
}
|
|
25275
|
+
function nonAsciiNotice(value) {
|
|
25276
|
+
if (!value || !/[^\x20-\x7e]/.test(value)) return "";
|
|
25277
|
+
return "\nWarning: this path contains non-ASCII characters: " + value.replace(/[^\x20-\x7e]/g, (ch) => "\\u" + ch.charCodeAt(0).toString(16).padStart(4, "0"));
|
|
25278
|
+
}
|
|
25279
|
+
async function planPermissionChange(current2, programs, input2) {
|
|
25280
|
+
const change = parsePermissionChange(input2);
|
|
25281
|
+
if (current2.workspaceGrantId !== change.workspaceGrantId) invalid2("WORKSPACE_UNKNOWN");
|
|
25282
|
+
const workspace = structuredClone(current2), nextPrograms = { ...programs };
|
|
25283
|
+
let resource = { rootHash: workspace.rootHash, kind: change.kind };
|
|
25284
|
+
let detail;
|
|
25285
|
+
if (change.kind === "write") {
|
|
25286
|
+
workspace.permissions.writeFiles = change.enabled;
|
|
25287
|
+
detail = "File writes: " + (change.enabled ? "ALLOW" : "DENY");
|
|
25288
|
+
} else if (change.kind === "localhost") {
|
|
25289
|
+
workspace.localhostPorts = change.enabled ? [.../* @__PURE__ */ new Set([...workspace.localhostPorts, change.port])].sort((a, b) => a - b) : workspace.localhostPorts.filter((port) => port !== change.port);
|
|
25290
|
+
if (workspace.localhostPorts.length > 32) invalid2("PERMISSION_LIMIT");
|
|
25291
|
+
workspace.permissions.localhost = workspace.localhostPorts.length > 0;
|
|
25292
|
+
resource = { rootHash: workspace.rootHash, kind: change.kind, port: change.port };
|
|
25293
|
+
detail = "Localhost port " + change.port + ": " + (change.enabled ? "ALLOW" : "DENY");
|
|
25294
|
+
} else {
|
|
25295
|
+
let executableIdentity = null;
|
|
25296
|
+
if (change.enabled) {
|
|
25297
|
+
const executable = change.executable;
|
|
25298
|
+
if (!path4.isAbsolute(executable) || path4.extname(executable).toLowerCase() !== ".exe" || /[\u0000-\u001f\u007f-\u009f\u061c\u200b-\u200f\u2028-\u202e\u2060-\u2069\ufeff]/u.test(executable)) invalid2();
|
|
25299
|
+
const stat = await lstat2(executable).catch(() => invalid2());
|
|
25300
|
+
const canonical2 = await realpath2(executable).catch(() => invalid2());
|
|
25301
|
+
if (!stat.isFile() || stat.isSymbolicLink() || !equalPath(path4.resolve(executable), canonical2)) invalid2();
|
|
25302
|
+
if (Object.hasOwn(nextPrograms, change.name) && !equalPath(nextPrograms[change.name], canonical2)) invalid2("COMMAND_CONFLICT");
|
|
25303
|
+
nextPrograms[change.name] = canonical2;
|
|
25304
|
+
workspace.allowedCommands = [.../* @__PURE__ */ new Set([...workspace.allowedCommands, change.name])].sort();
|
|
25305
|
+
if (workspace.allowedCommands.length > 32 || Object.keys(nextPrograms).length > 32) invalid2("PERMISSION_LIMIT");
|
|
25306
|
+
executableIdentity = { executable: canonical2, dev: stat.dev, ino: stat.ino, size: stat.size, mtimeMs: stat.mtimeMs, ctimeMs: stat.ctimeMs };
|
|
25307
|
+
} else workspace.allowedCommands = workspace.allowedCommands.filter((value) => value !== change.name);
|
|
25308
|
+
workspace.permissions.executeCommands = workspace.allowedCommands.length > 0;
|
|
25309
|
+
resource = { rootHash: workspace.rootHash, kind: change.kind, name: change.name, executable: nextPrograms[change.name] ?? null, executableIdentity };
|
|
25310
|
+
detail = "Command " + permissionLabel(change.name) + ": " + (change.enabled ? "ALLOW" : "DENY") + "\nExact executable: " + permissionLabel(nextPrograms[change.name] ?? "not registered") + nonAsciiNotice(nextPrograms[change.name]) + "\nA permitted program can access resources available to your Windows account, including outside this folder. This is not an OS sandbox.";
|
|
25311
|
+
}
|
|
25312
|
+
const summary = "Change Local Commander permissions\nWorkspace: " + permissionLabel(current2.displayName) + "\nWorkspace ID: " + current2.workspaceGrantId + "\nFolder: " + permissionLabel(current2.root) + "\n\n" + detail + "\n\nThis change persists until you revoke it. Other workspaces are not granted this permission.\nReview before approving. Closing this window, rejecting or timing out changes nothing.\nA running agent may restart after the change; running work can be interrupted. Revocation does not undo completed effects.";
|
|
25313
|
+
return { workspace, programs: nextPrograms, change, summary, resourceHash: permissionHash(resource) };
|
|
25314
|
+
}
|
|
25315
|
+
|
|
25069
25316
|
// packages/policy/src/signed-bundle.ts
|
|
25070
|
-
import { createHash as
|
|
25317
|
+
import { createHash as createHash6, KeyObject as KeyObject2 } from "node:crypto";
|
|
25071
25318
|
|
|
25072
25319
|
// packages/policy/src/evaluator.ts
|
|
25073
|
-
import { createHash as
|
|
25320
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
25074
25321
|
import { isDeepStrictEqual } from "node:util";
|
|
25075
|
-
var
|
|
25322
|
+
var uuid13 = external_exports.string().uuid().toLowerCase();
|
|
25076
25323
|
var slug2 = external_exports.string().regex(/^[a-z][a-z0-9._-]{0,63}$/);
|
|
25077
25324
|
var utc = external_exports.iso.datetime({ offset: false });
|
|
25078
25325
|
var risk = external_exports.enum(["low", "moderate", "high", "critical"]);
|
|
@@ -25097,7 +25344,7 @@ var PolicyRuleSchema = external_exports.object({
|
|
|
25097
25344
|
}
|
|
25098
25345
|
});
|
|
25099
25346
|
var PolicySnapshotSchema = external_exports.object({
|
|
25100
|
-
tenantId:
|
|
25347
|
+
tenantId: uuid13,
|
|
25101
25348
|
policyId: slug2,
|
|
25102
25349
|
policyVersion: external_exports.string().trim().min(1).max(64),
|
|
25103
25350
|
issuedAt: utc,
|
|
@@ -25127,7 +25374,7 @@ function matches(rule, request, requestRisk) {
|
|
|
25127
25374
|
return (!rule.actionKinds || rule.actionKinds.includes(action.kind)) && (!rule.toolNamespaces || rule.toolNamespaces.includes(tool.namespace)) && (!rule.environments || rule.environments.includes(environment.environment)) && (!rule.anyDataClassifications || rule.anyDataClassifications.some((value) => dataClassifications.includes(value))) && (!rule.resourceKinds || rule.resourceKinds.includes(resource.kind)) && (!rule.resourceFingerprints || rule.resourceFingerprints.includes(resource.locatorFingerprint)) && (!rule.riskClasses || rule.riskClasses.includes(requestRisk));
|
|
25128
25375
|
}
|
|
25129
25376
|
function decisionId(requestId, policyId, policyVersion, ruleId) {
|
|
25130
|
-
const bytes3 =
|
|
25377
|
+
const bytes3 = createHash5("sha256").update(JSON.stringify([requestId, policyId, policyVersion, ruleId])).digest().subarray(0, 16);
|
|
25131
25378
|
bytes3[6] = bytes3[6] & 15 | 64;
|
|
25132
25379
|
bytes3[8] = bytes3[8] & 63 | 128;
|
|
25133
25380
|
const hex3 = bytes3.toString("hex");
|
|
@@ -25196,7 +25443,7 @@ async function verifySignedPolicyBundle(candidate, authority, checkpointInput, n
|
|
|
25196
25443
|
if (payload.byteLength > 256 * 1024) throw new Error();
|
|
25197
25444
|
const bundle = BundleSchema.parse(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(payload)));
|
|
25198
25445
|
const { snapshot: snapshot2 } = bundle;
|
|
25199
|
-
const payloadSha256 =
|
|
25446
|
+
const payloadSha256 = createHash6("sha256").update(payload).digest("hex");
|
|
25200
25447
|
if (snapshot2.tenantId !== expected.tenantId || snapshot2.policyId !== expected.policyId || at < Date.parse(snapshot2.issuedAt) || at >= Date.parse(snapshot2.expiresAt) || bundle.sequence < checkpoint.sequence || bundle.sequence === checkpoint.sequence && payloadSha256 !== checkpoint.payloadSha256) throw new Error();
|
|
25201
25448
|
return { snapshot: snapshot2, checkpoint: {
|
|
25202
25449
|
...expected,
|
|
@@ -25210,15 +25457,15 @@ async function verifySignedPolicyBundle(candidate, authority, checkpointInput, n
|
|
|
25210
25457
|
}
|
|
25211
25458
|
|
|
25212
25459
|
// packages/policy/src/approvals.ts
|
|
25213
|
-
import { createHash as
|
|
25214
|
-
var
|
|
25460
|
+
import { createHash as createHash7, randomUUID as randomUUID2 } from "node:crypto";
|
|
25461
|
+
var uuid14 = TrustedActionBindingSchema.shape.tenantId;
|
|
25215
25462
|
var utc3 = TrustedActionBindingSchema.shape.expiresAt;
|
|
25216
25463
|
var digest3 = ResourceRefSchema.shape.locatorFingerprint;
|
|
25217
25464
|
var requirement = PolicyDecisionSchema.shape.approval.unwrap();
|
|
25218
25465
|
var ApprovalActionSchema = external_exports.object({ request: BoundActionRequestSchema, payloadHash: digest3 }).strict();
|
|
25219
25466
|
var ApprovalAuthoritySchema = external_exports.object({
|
|
25220
|
-
tenantId:
|
|
25221
|
-
accountId:
|
|
25467
|
+
tenantId: uuid14,
|
|
25468
|
+
accountId: uuid14,
|
|
25222
25469
|
approvalClass: requirement.shape.approvalClass,
|
|
25223
25470
|
authenticatedAt: utc3,
|
|
25224
25471
|
expiresAt: utc3
|
|
@@ -25230,11 +25477,11 @@ var ContextSchema = external_exports.object({
|
|
|
25230
25477
|
policyExpiresAt: utc3
|
|
25231
25478
|
}).strict();
|
|
25232
25479
|
var GrantSchema = external_exports.object({
|
|
25233
|
-
approvalId:
|
|
25234
|
-
requestId:
|
|
25235
|
-
decisionId:
|
|
25480
|
+
approvalId: uuid14,
|
|
25481
|
+
requestId: uuid14,
|
|
25482
|
+
decisionId: uuid14,
|
|
25236
25483
|
bindingHash: digest3,
|
|
25237
|
-
approverAccountId:
|
|
25484
|
+
approverAccountId: uuid14,
|
|
25238
25485
|
approvalClass: requirement.shape.approvalClass,
|
|
25239
25486
|
scope: requirement.shape.scope,
|
|
25240
25487
|
issuedAt: utc3,
|
|
@@ -25243,8 +25490,8 @@ var GrantSchema = external_exports.object({
|
|
|
25243
25490
|
uses: external_exports.number().int().min(0).max(Number.MAX_SAFE_INTEGER)
|
|
25244
25491
|
}).strict().refine((value) => Date.parse(value.issuedAt) < Date.parse(value.expiresAt) && (value.scope === "once" ? value.uses === (value.state === "consumed" ? 1 : 0) : value.state !== "consumed"));
|
|
25245
25492
|
var ApprovalLedgerSchema = external_exports.object({
|
|
25246
|
-
tenantId:
|
|
25247
|
-
deviceId:
|
|
25493
|
+
tenantId: uuid14,
|
|
25494
|
+
deviceId: uuid14,
|
|
25248
25495
|
lastChangedAt: utc3,
|
|
25249
25496
|
grants: external_exports.array(GrantSchema).max(128)
|
|
25250
25497
|
}).strict().refine((value) => new Set(value.grants.map((grant) => grant.approvalId)).size === value.grants.length && new Set(value.grants.map((grant) => grant.requestId)).size === value.grants.length && value.grants.every((grant) => Date.parse(grant.issuedAt) <= Date.parse(value.lastChangedAt)));
|
|
@@ -25265,7 +25512,7 @@ function binding(ledger, input2, now) {
|
|
|
25265
25512
|
approval.expiresAt ? Date.parse(approval.expiresAt) : Infinity
|
|
25266
25513
|
);
|
|
25267
25514
|
if (at >= deadline) throw Error();
|
|
25268
|
-
const bindingHash =
|
|
25515
|
+
const bindingHash = createHash7("sha256").update(JSON.stringify([
|
|
25269
25516
|
owner.bindingSource,
|
|
25270
25517
|
owner.tenantId,
|
|
25271
25518
|
owner.accountId,
|
|
@@ -25321,7 +25568,7 @@ function issueApproval(ledgerInput, context, authorityInput, now, expiresAt) {
|
|
|
25321
25568
|
}
|
|
25322
25569
|
function consumeApproval(ledgerInput, context, approvalId, now) {
|
|
25323
25570
|
try {
|
|
25324
|
-
const ledger = current(ledgerInput, now), bound = binding(ledger, context, now), id =
|
|
25571
|
+
const ledger = current(ledgerInput, now), bound = binding(ledger, context, now), id = uuid14.parse(approvalId);
|
|
25325
25572
|
const grant = ledger.grants.find((candidate) => candidate.approvalId === id);
|
|
25326
25573
|
if (!grant || grant.state !== "active" || grant.bindingHash !== bound.bindingHash || grant.uses === Number.MAX_SAFE_INTEGER || Date.parse(now) < Date.parse(grant.issuedAt) || grant.scope === "once" && (grant.requestId !== bound.request.requestId || grant.decisionId !== bound.decision.decisionId)) throw Error();
|
|
25327
25574
|
const consumed = { ...grant, uses: grant.uses + 1, state: grant.scope === "once" ? "consumed" : "active" };
|
|
@@ -25332,7 +25579,7 @@ function consumeApproval(ledgerInput, context, approvalId, now) {
|
|
|
25332
25579
|
}
|
|
25333
25580
|
function revokeApproval(ledgerInput, approvalId, now) {
|
|
25334
25581
|
try {
|
|
25335
|
-
const ledger = current(ledgerInput, now), id =
|
|
25582
|
+
const ledger = current(ledgerInput, now), id = uuid14.parse(approvalId);
|
|
25336
25583
|
return { ...ledger, grants: ledger.grants.map((grant) => grant.approvalId === id && grant.state === "active" ? { ...grant, state: "revoked" } : grant) };
|
|
25337
25584
|
} catch {
|
|
25338
25585
|
throw Error("APPROVAL_INVALID");
|
|
@@ -25347,12 +25594,12 @@ var MAX_STATE_BYTES = 256 * 1024;
|
|
|
25347
25594
|
function fail(code) {
|
|
25348
25595
|
return Object.assign(new Error(code), { code });
|
|
25349
25596
|
}
|
|
25350
|
-
function
|
|
25351
|
-
return
|
|
25597
|
+
function equalPath2(a, b) {
|
|
25598
|
+
return path5.resolve(a).toLowerCase() === path5.resolve(b).toLowerCase();
|
|
25352
25599
|
}
|
|
25353
25600
|
function under(child, parent) {
|
|
25354
|
-
const rel =
|
|
25355
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
25601
|
+
const rel = path5.relative(parent, child);
|
|
25602
|
+
return rel !== "" && !rel.startsWith("..") && !path5.isAbsolute(rel);
|
|
25356
25603
|
}
|
|
25357
25604
|
function canonicalPublicKey(value) {
|
|
25358
25605
|
try {
|
|
@@ -25364,7 +25611,7 @@ function canonicalPublicKey(value) {
|
|
|
25364
25611
|
}
|
|
25365
25612
|
}
|
|
25366
25613
|
function fingerprint(publicKeyPem) {
|
|
25367
|
-
return
|
|
25614
|
+
return createHash8("sha256").update(canonicalPublicKey(publicKeyPem).der).digest("hex");
|
|
25368
25615
|
}
|
|
25369
25616
|
function publicFromPrivate(privateKeyPem) {
|
|
25370
25617
|
try {
|
|
@@ -25423,55 +25670,57 @@ function validateState(value) {
|
|
|
25423
25670
|
}
|
|
25424
25671
|
const approvals = value.approvals === void 0 ? void 0 : ApprovalLedgerSchema.safeParse(value.approvals);
|
|
25425
25672
|
if (approvals && (!approvals.success || approvals.data.tenantId !== enrollment?.tenantId || approvals.data.deviceId !== enrollment.deviceId)) throw fail("STATE_CORRUPT");
|
|
25673
|
+
const permissionHistory = PermissionHistorySchema.safeParse(value.permissionHistory ?? []);
|
|
25674
|
+
if (!permissionHistory.success) throw fail("STATE_CORRUPT");
|
|
25426
25675
|
const workspaces = value.workspaces ?? [];
|
|
25427
25676
|
const programs = value.programs ?? {};
|
|
25428
25677
|
const pendingWorkspaceRevokes = value.pendingWorkspaceRevokes ?? [];
|
|
25429
25678
|
if (!Array.isArray(pendingWorkspaceRevokes) || pendingWorkspaceRevokes.length > 32 || pendingWorkspaceRevokes.some((id) => typeof id !== "string" || !UUID.test(id) || id !== id.toLowerCase()) || new Set(pendingWorkspaceRevokes).size !== pendingWorkspaceRevokes.length) throw fail("STATE_CORRUPT");
|
|
25430
|
-
if (!programs || typeof programs !== "object" || Array.isArray(programs) || Object.keys(programs).length > 32 || Object.entries(programs).some(([
|
|
25431
|
-
if (!Array.isArray(workspaces) || workspaces.length > 32 || workspaces.some((w) => !w || !UUID.test(w.workspaceGrantId) || typeof w.root !== "string" || !
|
|
25679
|
+
if (!programs || typeof programs !== "object" || Array.isArray(programs) || Object.keys(programs).length > 32 || Object.entries(programs).some(([name2, executable]) => !/^[a-z0-9_.-]{1,64}$/.test(name2) || typeof executable !== "string" || !path5.isAbsolute(executable) || executable.length > 4096 || /[\u0000-\u001f]/.test(executable))) throw fail("STATE_CORRUPT");
|
|
25680
|
+
if (!Array.isArray(workspaces) || workspaces.length > 32 || workspaces.some((w) => !w || !UUID.test(w.workspaceGrantId) || typeof w.root !== "string" || !path5.isAbsolute(w.root) || w.root.length > 4096 || /[\u0000-\u001f]/.test(w.root) || !/^[a-f0-9]{64}$/.test(w.rootHash) || typeof w.displayName !== "string" || !w.displayName || w.displayName.length > 120 || w.policyVersion !== 1 || !w.permissions || w.permissions.readFiles !== true || typeof w.permissions.writeFiles !== "boolean" || typeof w.permissions.executeCommands !== "boolean" || typeof w.permissions.localhost !== "boolean" || !Array.isArray(w.allowedCommands) || w.allowedCommands.length > 32 || w.allowedCommands.some((name2) => typeof name2 !== "string" || !Object.hasOwn(programs, name2)) || new Set(w.allowedCommands).size !== w.allowedCommands.length || w.permissions.executeCommands !== w.allowedCommands.length > 0 || !Array.isArray(w.localhostPorts) || w.localhostPorts.length > 32 || w.localhostPorts.some((port) => !Number.isInteger(port) || port < 1 || port > 65535) || new Set(w.localhostPorts).size !== w.localhostPorts.length || w.permissions.localhost !== w.localhostPorts.length > 0)) throw fail("STATE_CORRUPT");
|
|
25432
25681
|
if (new Set(workspaces.map((w) => w.workspaceGrantId)).size !== workspaces.length || new Set(workspaces.map((w) => w.rootHash)).size !== workspaces.length) throw fail("STATE_CORRUPT");
|
|
25433
25682
|
if (workspaces.some((w) => pendingWorkspaceRevokes.includes(w.workspaceGrantId))) throw fail("STATE_CORRUPT");
|
|
25434
|
-
return { version: 1, publicKeyPem: value.publicKeyPem, privateKeyPem: value.privateKeyPem, fingerprint: value.fingerprint, dataKey: value.dataKey, ...enrollment ? { enrollment } : {}, workspaces, programs, pendingWorkspaceRevokes, ...policyBundle ? { policyBundle } : {}, ...approvals?.success ? { approvals: approvals.data } : {}, ...value.guardRequired ? { guardRequired: true } : {}, ...guard ? { guard } : {} };
|
|
25683
|
+
return { version: 1, publicKeyPem: value.publicKeyPem, privateKeyPem: value.privateKeyPem, fingerprint: value.fingerprint, dataKey: value.dataKey, ...enrollment ? { enrollment } : {}, workspaces, programs, pendingWorkspaceRevokes, ...value.permissionHistory ? { permissionHistory: permissionHistory.data } : {}, ...policyBundle ? { policyBundle } : {}, ...approvals?.success ? { approvals: approvals.data } : {}, ...value.guardRequired ? { guardRequired: true } : {}, ...guard ? { guard } : {} };
|
|
25435
25684
|
}
|
|
25436
25685
|
async function noSymlinkChain(target) {
|
|
25437
|
-
if (!
|
|
25438
|
-
const absolute2 =
|
|
25439
|
-
if (absolute2 ===
|
|
25686
|
+
if (!path5.isAbsolute(target)) throw fail("STORE_DIRECTORY_INVALID");
|
|
25687
|
+
const absolute2 = path5.resolve(target);
|
|
25688
|
+
if (absolute2 === path5.parse(absolute2).root) throw fail("STORE_DIRECTORY_INVALID");
|
|
25440
25689
|
const missing = [];
|
|
25441
25690
|
let cursor = absolute2;
|
|
25442
25691
|
for (; ; ) {
|
|
25443
25692
|
try {
|
|
25444
|
-
const stat = await
|
|
25693
|
+
const stat = await lstat3(cursor);
|
|
25445
25694
|
if (stat.isSymbolicLink()) throw fail("STORE_DIRECTORY_INVALID");
|
|
25446
25695
|
break;
|
|
25447
25696
|
} catch (error62) {
|
|
25448
25697
|
if (error62.code !== "ENOENT") throw error62;
|
|
25449
25698
|
missing.push(cursor);
|
|
25450
|
-
const parent =
|
|
25699
|
+
const parent = path5.dirname(cursor);
|
|
25451
25700
|
if (parent === cursor) throw fail("STORE_DIRECTORY_INVALID");
|
|
25452
25701
|
cursor = parent;
|
|
25453
25702
|
}
|
|
25454
25703
|
}
|
|
25455
|
-
const canonicalParent = await
|
|
25456
|
-
if (!
|
|
25704
|
+
const canonicalParent = await realpath3(cursor);
|
|
25705
|
+
if (!equalPath2(cursor, canonicalParent)) throw fail("STORE_DIRECTORY_INVALID");
|
|
25457
25706
|
return absolute2;
|
|
25458
25707
|
}
|
|
25459
25708
|
function allowedDirectory(absolute2) {
|
|
25460
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
25461
|
-
const appRoot =
|
|
25462
|
-
const tempRoot =
|
|
25709
|
+
const localAppData = process.env.LOCALAPPDATA || path5.join(os.homedir(), "AppData", "Local");
|
|
25710
|
+
const appRoot = path5.resolve(localAppData, "LocalCommander");
|
|
25711
|
+
const tempRoot = path5.resolve(os.tmpdir());
|
|
25463
25712
|
if (under(absolute2, appRoot)) return;
|
|
25464
|
-
if (under(absolute2, tempRoot) && /^lc-private-[A-Za-z0-9_.-]+$/i.test(
|
|
25713
|
+
if (under(absolute2, tempRoot) && /^lc-private-[A-Za-z0-9_.-]+$/i.test(path5.basename(absolute2))) return;
|
|
25465
25714
|
throw fail("STORE_DIRECTORY_POLICY");
|
|
25466
25715
|
}
|
|
25467
25716
|
async function canonicalBridge(value) {
|
|
25468
|
-
if (typeof value !== "string" || !
|
|
25469
|
-
const stat = await
|
|
25717
|
+
if (typeof value !== "string" || !path5.isAbsolute(value) || path5.extname(value).toLowerCase() !== ".exe") throw fail("BRIDGE_INVALID");
|
|
25718
|
+
const stat = await lstat3(value).catch(() => {
|
|
25470
25719
|
throw fail("BRIDGE_INVALID");
|
|
25471
25720
|
});
|
|
25472
25721
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size < 1 || stat.size > 4 * 1024 * 1024) throw fail("BRIDGE_INVALID");
|
|
25473
|
-
const canonical2 = await
|
|
25474
|
-
if (!
|
|
25722
|
+
const canonical2 = await realpath3(value);
|
|
25723
|
+
if (!equalPath2(value, canonical2)) throw fail("BRIDGE_INVALID");
|
|
25475
25724
|
return canonical2;
|
|
25476
25725
|
}
|
|
25477
25726
|
function parseBridgeData(value, max = MAX_STATE_BYTES * 4) {
|
|
@@ -25503,11 +25752,11 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25503
25752
|
}
|
|
25504
25753
|
const approved = /* @__PURE__ */ new Set([MARKER, "owner-state.dat", "owner-state.lock", "journal"]);
|
|
25505
25754
|
if (names.length && !names.includes(MARKER)) throw fail("STORE_DIRECTORY_UNKNOWN");
|
|
25506
|
-
if (names.some((
|
|
25755
|
+
if (names.some((name2) => !approved.has(name2))) throw fail("STORE_DIRECTORY_UNKNOWN");
|
|
25507
25756
|
await _WindowsPrivateStore.invoke(bridge, "init-directory", { path: absolute2 }, 5e3, false);
|
|
25508
|
-
const canonical2 = await
|
|
25509
|
-
if (!
|
|
25510
|
-
const markerPath =
|
|
25757
|
+
const canonical2 = await realpath3(absolute2);
|
|
25758
|
+
if (!equalPath2(absolute2, canonical2) || (await lstat3(canonical2)).isSymbolicLink()) throw fail("STORE_DIRECTORY_INVALID");
|
|
25759
|
+
const markerPath = path5.join(canonical2, MARKER);
|
|
25511
25760
|
try {
|
|
25512
25761
|
await writeFile(markerPath, "LocalCommander private state\n", { flag: "wx", mode: 384 });
|
|
25513
25762
|
} catch (error62) {
|
|
@@ -25522,10 +25771,10 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25522
25771
|
return result2;
|
|
25523
25772
|
}
|
|
25524
25773
|
statePath() {
|
|
25525
|
-
return
|
|
25774
|
+
return path5.join(this.dir, "owner-state.dat");
|
|
25526
25775
|
}
|
|
25527
25776
|
lockPath() {
|
|
25528
|
-
return
|
|
25777
|
+
return path5.join(this.dir, "owner-state.lock");
|
|
25529
25778
|
}
|
|
25530
25779
|
static invoke(bridge, arg, body, timeoutMs2, interactive, signal) {
|
|
25531
25780
|
return new Promise((resolve, reject) => {
|
|
@@ -25620,9 +25869,21 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25620
25869
|
}
|
|
25621
25870
|
}
|
|
25622
25871
|
}
|
|
25872
|
+
/** After an owner approval, a briefly busy lock (the running agent) must not discard the decision. */
|
|
25873
|
+
async withLockWait(fn, waitMs) {
|
|
25874
|
+
const deadline = Date.now() + waitMs;
|
|
25875
|
+
for (; ; ) {
|
|
25876
|
+
try {
|
|
25877
|
+
return await this.withLock(fn);
|
|
25878
|
+
} catch (error62) {
|
|
25879
|
+
if (error62.code !== "STORE_LOCKED" || Date.now() >= deadline) throw error62;
|
|
25880
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
25881
|
+
}
|
|
25882
|
+
}
|
|
25883
|
+
}
|
|
25623
25884
|
async readState() {
|
|
25624
25885
|
try {
|
|
25625
|
-
const stat = await
|
|
25886
|
+
const stat = await lstat3(this.statePath());
|
|
25626
25887
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size < 1 || stat.size > MAX_STATE_BYTES * 4) throw fail("STATE_CORRUPT");
|
|
25627
25888
|
const encrypted = await readFile2(this.statePath());
|
|
25628
25889
|
const plaintext = await this.unprotect(encrypted);
|
|
@@ -25636,9 +25897,9 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25636
25897
|
}
|
|
25637
25898
|
async rawHash() {
|
|
25638
25899
|
try {
|
|
25639
|
-
const stat = await
|
|
25900
|
+
const stat = await lstat3(this.statePath());
|
|
25640
25901
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_STATE_BYTES * 4) throw fail("STATE_CORRUPT");
|
|
25641
|
-
return
|
|
25902
|
+
return createHash8("sha256").update(await readFile2(this.statePath())).digest("hex");
|
|
25642
25903
|
} catch (error62) {
|
|
25643
25904
|
if (error62.code === "ENOENT") return null;
|
|
25644
25905
|
throw error62;
|
|
@@ -25649,7 +25910,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25649
25910
|
const plaintext = Buffer.from(JSON.stringify(validateState(state)), "utf8");
|
|
25650
25911
|
if (plaintext.length > MAX_STATE_BYTES) throw fail("STATE_TOO_LARGE");
|
|
25651
25912
|
const encrypted = await this.protect(plaintext);
|
|
25652
|
-
const temp =
|
|
25913
|
+
const temp = path5.join(this.dir, "owner-state." + randomBytes3(8).toString("hex") + ".tmp");
|
|
25653
25914
|
const handle = await open3(temp, constants2.O_CREAT | constants2.O_EXCL | constants2.O_WRONLY, 384);
|
|
25654
25915
|
let closed = false;
|
|
25655
25916
|
try {
|
|
@@ -25701,6 +25962,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25701
25962
|
state.workspaces = [];
|
|
25702
25963
|
state.programs = {};
|
|
25703
25964
|
state.pendingWorkspaceRevokes = [];
|
|
25965
|
+
delete state.permissionHistory;
|
|
25704
25966
|
}
|
|
25705
25967
|
state.enrollment = next;
|
|
25706
25968
|
await this.writeState(state, before);
|
|
@@ -25718,6 +25980,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25718
25980
|
state.workspaces = [];
|
|
25719
25981
|
state.programs = {};
|
|
25720
25982
|
state.pendingWorkspaceRevokes = [];
|
|
25983
|
+
delete state.permissionHistory;
|
|
25721
25984
|
await this.writeState(state, before);
|
|
25722
25985
|
}));
|
|
25723
25986
|
}
|
|
@@ -25837,7 +26100,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25837
26100
|
"guard-review",
|
|
25838
26101
|
{ data: Buffer.from(summary).toString("base64") },
|
|
25839
26102
|
timeoutMs2,
|
|
25840
|
-
|
|
26103
|
+
true,
|
|
25841
26104
|
signal
|
|
25842
26105
|
);
|
|
25843
26106
|
if (typeof answer?.approved !== "boolean" || typeof answer.ownerSid !== "string" || !/^S-1-(?:[0-9]+-)+[0-9]+$/.test(answer.ownerSid)) throw fail("GUARD_REVIEW_INVALID");
|
|
@@ -25879,7 +26142,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25879
26142
|
});
|
|
25880
26143
|
}
|
|
25881
26144
|
loadPrograms() {
|
|
25882
|
-
return this.run(async () => Object.fromEntries(Object.entries((await this.readState())?.programs ?? {}).map(([
|
|
26145
|
+
return this.run(async () => Object.fromEntries(Object.entries((await this.readState())?.programs ?? {}).map(([name2, executable]) => [name2, { executable }])));
|
|
25883
26146
|
}
|
|
25884
26147
|
loadPendingWorkspaceRevokes() {
|
|
25885
26148
|
return this.run(async () => [...(await this.readState())?.pendingWorkspaceRevokes ?? []]);
|
|
@@ -25899,7 +26162,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25899
26162
|
const before = await this.rawHash();
|
|
25900
26163
|
state.workspaces = state.workspaces.filter((w) => w.workspaceGrantId !== id);
|
|
25901
26164
|
state.pendingWorkspaceRevokes = [...state.pendingWorkspaceRevokes ?? [], id];
|
|
25902
|
-
for (const
|
|
26165
|
+
for (const name2 of Object.keys(state.programs ?? {})) if (!state.workspaces.some((w) => w.allowedCommands.includes(name2))) delete state.programs[name2];
|
|
25903
26166
|
await this.writeState(state, before);
|
|
25904
26167
|
}));
|
|
25905
26168
|
}
|
|
@@ -25912,51 +26175,112 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25912
26175
|
await this.writeState(state, before);
|
|
25913
26176
|
}));
|
|
25914
26177
|
}
|
|
25915
|
-
setWorkspacePermissions(change) {
|
|
25916
|
-
|
|
25917
|
-
|
|
26178
|
+
async setWorkspacePermissions(change) {
|
|
26179
|
+
const request = parsePermissionChange(change);
|
|
26180
|
+
const context = (state) => {
|
|
25918
26181
|
if (!state?.enrollment) throw fail("ENROLLMENT_REQUIRED");
|
|
25919
|
-
|
|
25920
|
-
|
|
25921
|
-
|
|
25922
|
-
|
|
25923
|
-
|
|
25924
|
-
|
|
25925
|
-
|
|
25926
|
-
|
|
25927
|
-
|
|
25928
|
-
}
|
|
25929
|
-
|
|
25930
|
-
|
|
25931
|
-
|
|
25932
|
-
|
|
25933
|
-
|
|
25934
|
-
|
|
25935
|
-
|
|
25936
|
-
|
|
25937
|
-
|
|
25938
|
-
|
|
25939
|
-
|
|
25940
|
-
|
|
25941
|
-
} else workspace.allowedCommands = workspace.allowedCommands.filter((value) => value !== name);
|
|
25942
|
-
workspace.permissions.executeCommands = workspace.allowedCommands.length > 0;
|
|
25943
|
-
} else throw fail("PERMISSION_INVALID");
|
|
25944
|
-
state.workspaces = state.workspaces.map((w) => w.workspaceGrantId === workspace.workspaceGrantId ? workspace : w);
|
|
25945
|
-
for (const name of Object.keys(programs)) if (!state.workspaces.some((w) => w.allowedCommands.includes(name))) delete programs[name];
|
|
25946
|
-
state.programs = programs;
|
|
26182
|
+
const workspace = state.workspaces?.find((w) => w.workspaceGrantId === request.workspaceGrantId);
|
|
26183
|
+
if (!workspace) throw fail("WORKSPACE_UNKNOWN");
|
|
26184
|
+
const programs = state.programs ?? {};
|
|
26185
|
+
return { workspace, programs, enrollment: state.enrollment, fingerprint: permissionHash({
|
|
26186
|
+
enrollment: state.enrollment,
|
|
26187
|
+
workspace,
|
|
26188
|
+
programs: Object.entries(programs).sort(([a], [b]) => a.localeCompare(b)),
|
|
26189
|
+
guard: state.guard ?? null,
|
|
26190
|
+
guardRequired: state.guardRequired ?? false
|
|
26191
|
+
}) };
|
|
26192
|
+
};
|
|
26193
|
+
const initial = await this.run(async () => context(await this.readState()));
|
|
26194
|
+
const proposal = await planPermissionChange(initial.workspace, initial.programs, request);
|
|
26195
|
+
const review = await this.reviewGuard("Account: " + permissionLabel(initial.enrollment.accountEmail) + "\n" + proposal.summary, void 0, 6e4);
|
|
26196
|
+
if (!review.approved) throw fail("PERMISSION_REJECTED");
|
|
26197
|
+
return this.run(() => this.withLockWait(async () => {
|
|
26198
|
+
const state = await this.readState();
|
|
26199
|
+
const current2 = context(state);
|
|
26200
|
+
if (current2.fingerprint !== initial.fingerprint) throw fail("PERMISSION_STATE_CHANGED");
|
|
26201
|
+
if (state.guard && state.guard.ownerSid !== review.ownerSid) throw fail("PERMISSION_OWNER_MISMATCH");
|
|
26202
|
+
const verified = await planPermissionChange(current2.workspace, current2.programs, request);
|
|
26203
|
+
if (verified.resourceHash !== proposal.resourceHash) throw fail("PERMISSION_STATE_CHANGED");
|
|
25947
26204
|
const before = await this.rawHash();
|
|
26205
|
+
state.workspaces = state.workspaces.map((w) => w.workspaceGrantId === verified.workspace.workspaceGrantId ? verified.workspace : w);
|
|
26206
|
+
state.programs = verified.programs;
|
|
26207
|
+
for (const name2 of Object.keys(state.programs)) if (!state.workspaces.some((w) => w.allowedCommands.includes(name2))) delete state.programs[name2];
|
|
26208
|
+
const record2 = {
|
|
26209
|
+
id: randomUUID3(),
|
|
26210
|
+
changedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26211
|
+
workspaceGrantId: request.workspaceGrantId,
|
|
26212
|
+
kind: request.kind,
|
|
26213
|
+
enabled: request.enabled,
|
|
26214
|
+
resourceHash: verified.resourceHash,
|
|
26215
|
+
ownerSid: review.ownerSid
|
|
26216
|
+
};
|
|
26217
|
+
state.permissionHistory = PermissionHistorySchema.parse([...state.permissionHistory ?? [], record2].slice(-PERMISSION_HISTORY_LIMIT));
|
|
25948
26218
|
await this.writeState(state, before);
|
|
25949
|
-
return workspace;
|
|
26219
|
+
return structuredClone(verified.workspace);
|
|
26220
|
+
}, 5e3));
|
|
26221
|
+
}
|
|
26222
|
+
/** Replace scope only after an explicit local dialog; updates never call this implicitly. */
|
|
26223
|
+
async configureAccess() {
|
|
26224
|
+
const expected = await this.run(() => this.withLock(async () => {
|
|
26225
|
+
if (!(await this.readState())?.enrollment) throw fail("ENROLLMENT_REQUIRED");
|
|
26226
|
+
return this.rawHash();
|
|
26227
|
+
}));
|
|
26228
|
+
const decision = await this.chooseAccess();
|
|
26229
|
+
if (decision === null) return null;
|
|
26230
|
+
const selected = parseAccessSelection(decision);
|
|
26231
|
+
if (!selected) return null;
|
|
26232
|
+
const roots = [];
|
|
26233
|
+
for (const chosen of selected.paths) {
|
|
26234
|
+
const stat = await lstat3(chosen);
|
|
26235
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) throw fail("WORKSPACE_INVALID");
|
|
26236
|
+
const root = await realpath3(chosen);
|
|
26237
|
+
const isDrive = equalPath2(root, path5.parse(root).root);
|
|
26238
|
+
if (!equalPath2(root, chosen) || (selected.mode === "all-drives" ? !isDrive : isDrive) || equalPath2(root, this.dir) || under(root, this.dir) || selected.mode === "folders" && under(this.dir, root)) throw fail("WORKSPACE_INVALID");
|
|
26239
|
+
roots.push(root);
|
|
26240
|
+
}
|
|
26241
|
+
return this.run(() => this.withLock(async () => {
|
|
26242
|
+
if (await this.rawHash() !== expected) throw fail("STATE_CHANGED");
|
|
26243
|
+
const state = await this.readState();
|
|
26244
|
+
if (!state?.enrollment) throw fail("ENROLLMENT_REQUIRED");
|
|
26245
|
+
const workspaces = roots.map((root) => {
|
|
26246
|
+
const rootHash = createHash8("sha256").update(process.platform === "win32" ? root.toLowerCase() : root).digest("hex");
|
|
26247
|
+
const existing = state.workspaces?.find((w) => w.rootHash === rootHash);
|
|
26248
|
+
return {
|
|
26249
|
+
workspaceGrantId: existing?.workspaceGrantId ?? randomUUID3(),
|
|
26250
|
+
root,
|
|
26251
|
+
rootHash,
|
|
26252
|
+
displayName: (path5.basename(root) || root).slice(0, 120),
|
|
26253
|
+
policyVersion: 1,
|
|
26254
|
+
permissions: { readFiles: true, writeFiles: true, executeCommands: false, localhost: false },
|
|
26255
|
+
allowedCommands: [],
|
|
26256
|
+
localhostPorts: []
|
|
26257
|
+
};
|
|
26258
|
+
});
|
|
26259
|
+
const retained = new Set(workspaces.map((w) => w.workspaceGrantId));
|
|
26260
|
+
const removed = (state.workspaces ?? []).filter((w) => !retained.has(w.workspaceGrantId)).map((w) => w.workspaceGrantId);
|
|
26261
|
+
const pending = [.../* @__PURE__ */ new Set([...state.pendingWorkspaceRevokes ?? [], ...removed])];
|
|
26262
|
+
if (pending.length > 32) throw fail("WORKSPACE_REVOKE_LIMIT");
|
|
26263
|
+
state.workspaces = workspaces;
|
|
26264
|
+
state.programs = {};
|
|
26265
|
+
state.pendingWorkspaceRevokes = pending;
|
|
26266
|
+
await this.writeState(state, expected);
|
|
26267
|
+
return structuredClone(workspaces);
|
|
25950
26268
|
}));
|
|
25951
26269
|
}
|
|
26270
|
+
chooseAccess() {
|
|
26271
|
+
return this.run(async () => parseAccessSelection(await _WindowsPrivateStore.invoke(this.bridge, "choose-access", {}, 24e4, true)));
|
|
26272
|
+
}
|
|
26273
|
+
loadPermissionHistory() {
|
|
26274
|
+
return this.run(async () => structuredClone((await this.readState())?.permissionHistory ?? []));
|
|
26275
|
+
}
|
|
25952
26276
|
async approveWorkspace() {
|
|
25953
26277
|
const chosen = await this.chooseFolder();
|
|
25954
26278
|
if (chosen === null) return null;
|
|
25955
|
-
const stat = await
|
|
26279
|
+
const stat = await lstat3(chosen);
|
|
25956
26280
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw fail("WORKSPACE_INVALID");
|
|
25957
|
-
const root = await
|
|
25958
|
-
if (!
|
|
25959
|
-
const rootHash =
|
|
26281
|
+
const root = await realpath3(chosen);
|
|
26282
|
+
if (!equalPath2(root, chosen) || equalPath2(root, path5.parse(root).root) || equalPath2(root, this.dir) || under(this.dir, root)) throw fail("WORKSPACE_INVALID");
|
|
26283
|
+
const rootHash = createHash8("sha256").update(process.platform === "win32" ? root.toLowerCase() : root).digest("hex");
|
|
25960
26284
|
return this.run(() => this.withLock(async () => {
|
|
25961
26285
|
const state = await this.readState();
|
|
25962
26286
|
if (!state?.enrollment) throw fail("ENROLLMENT_REQUIRED");
|
|
@@ -25964,7 +26288,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25964
26288
|
if (existing) return existing;
|
|
25965
26289
|
if ((state.workspaces?.length ?? 0) >= 32) throw fail("WORKSPACE_LIMIT");
|
|
25966
26290
|
const before = await this.rawHash();
|
|
25967
|
-
const workspace = { workspaceGrantId: randomUUID3(), root, rootHash, displayName:
|
|
26291
|
+
const workspace = { workspaceGrantId: randomUUID3(), root, rootHash, displayName: path5.basename(root).slice(0, 120), policyVersion: 1, permissions: { readFiles: true, writeFiles: true, executeCommands: false, localhost: false }, allowedCommands: [], localhostPorts: [] };
|
|
25968
26292
|
state.workspaces = [...state.workspaces ?? [], workspace];
|
|
25969
26293
|
await this.writeState(state, before);
|
|
25970
26294
|
return workspace;
|
|
@@ -25974,7 +26298,7 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25974
26298
|
return this.run(async () => {
|
|
25975
26299
|
const result2 = await _WindowsPrivateStore.invoke(this.bridge, "choose-folder", {}, 12e4, true);
|
|
25976
26300
|
if (result2.path === null) return null;
|
|
25977
|
-
if (typeof result2.path !== "string" || !
|
|
26301
|
+
if (typeof result2.path !== "string" || !path5.isAbsolute(result2.path) || result2.path.length > 4096 || /[\u0000-\u001f]/.test(result2.path)) throw fail("BRIDGE_OUTPUT_INVALID");
|
|
25978
26302
|
return result2.path;
|
|
25979
26303
|
});
|
|
25980
26304
|
}
|
|
@@ -25982,22 +26306,40 @@ var WindowsPrivateStore = class _WindowsPrivateStore {
|
|
|
25982
26306
|
|
|
25983
26307
|
// agent/src/tools.ts
|
|
25984
26308
|
import { constants as constants3 } from "node:fs";
|
|
25985
|
-
import { lstat as
|
|
25986
|
-
import
|
|
25987
|
-
import { createHash as
|
|
26309
|
+
import { lstat as lstat5, open as open4, readdir as readdir3, realpath as realpath5, rename as rename3, rm as rm3 } from "node:fs/promises";
|
|
26310
|
+
import path9 from "node:path";
|
|
26311
|
+
import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
|
|
25988
26312
|
|
|
25989
26313
|
// src/guard.ts
|
|
25990
|
-
import { lstat as
|
|
25991
|
-
import
|
|
26314
|
+
import { lstat as lstat4, realpath as realpath4 } from "node:fs/promises";
|
|
26315
|
+
import path6 from "node:path";
|
|
25992
26316
|
var SENSITIVE_NAMES = /* @__PURE__ */ new Set([
|
|
25993
26317
|
".npmrc",
|
|
25994
26318
|
".pypirc",
|
|
25995
26319
|
".git-credentials",
|
|
25996
26320
|
"id_rsa",
|
|
25997
26321
|
"id_ed25519",
|
|
25998
|
-
"
|
|
26322
|
+
"id_ecdsa",
|
|
26323
|
+
"id_dsa",
|
|
26324
|
+
".netrc",
|
|
26325
|
+
"_netrc",
|
|
26326
|
+
".pgpass",
|
|
26327
|
+
"credentials.json",
|
|
26328
|
+
"application_default_credentials.json"
|
|
25999
26329
|
]);
|
|
26000
|
-
var SENSITIVE_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".p12", ".pfx"]);
|
|
26330
|
+
var SENSITIVE_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".p12", ".pfx", ".ppk", ".kdbx"]);
|
|
26331
|
+
var SENSITIVE_IN_DIRECTORY = [
|
|
26332
|
+
[".aws", "credentials"],
|
|
26333
|
+
[".kube", "config"],
|
|
26334
|
+
[".docker", "config.json"],
|
|
26335
|
+
[".claude", ".credentials.json"],
|
|
26336
|
+
[".codex", "auth.json"],
|
|
26337
|
+
[".azure", "msal_token_cache.json"],
|
|
26338
|
+
[".azure", "accesstokens.json"],
|
|
26339
|
+
["gh", "hosts.yml"],
|
|
26340
|
+
["github cli", "hosts.yml"]
|
|
26341
|
+
];
|
|
26342
|
+
var SENSITIVE_DIRECTORIES = /* @__PURE__ */ new Set([".ssh", ".gnupg"]);
|
|
26001
26343
|
var PROTECTED_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
26002
26344
|
".local-commander-oauth.json",
|
|
26003
26345
|
"local-commander.config.json"
|
|
@@ -26007,12 +26349,12 @@ function comparePath(value) {
|
|
|
26007
26349
|
return process.platform === "win32" ? value.toLowerCase() : value;
|
|
26008
26350
|
}
|
|
26009
26351
|
function isInside(root, candidate) {
|
|
26010
|
-
const relative =
|
|
26011
|
-
return relative === "" || !
|
|
26352
|
+
const relative = path6.relative(root, candidate);
|
|
26353
|
+
return relative === "" || !path6.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path6.sep}`);
|
|
26012
26354
|
}
|
|
26013
26355
|
function splitPathSegments(filePath) {
|
|
26014
|
-
const parsed =
|
|
26015
|
-
return
|
|
26356
|
+
const parsed = path6.parse(path6.resolve(filePath));
|
|
26357
|
+
return path6.relative(parsed.root, path6.resolve(filePath)).split(path6.sep).filter((segment) => segment.length > 0);
|
|
26016
26358
|
}
|
|
26017
26359
|
function isProtectedAuditFile(base) {
|
|
26018
26360
|
return base === ".local-commander-audit.jsonl" || base.startsWith(".local-commander-audit.jsonl.");
|
|
@@ -26027,37 +26369,40 @@ function looksProtected(filePath) {
|
|
|
26027
26369
|
return false;
|
|
26028
26370
|
}
|
|
26029
26371
|
function looksSensitive(filePath) {
|
|
26030
|
-
const base =
|
|
26372
|
+
const base = path6.basename(filePath).toLowerCase();
|
|
26031
26373
|
if (base === ".env" || base.startsWith(".env.") && base !== ".env.example") return true;
|
|
26032
26374
|
if (SENSITIVE_NAMES.has(base)) return true;
|
|
26033
|
-
if (SENSITIVE_EXTENSIONS.has(
|
|
26034
|
-
|
|
26375
|
+
if (SENSITIVE_EXTENSIONS.has(path6.extname(base))) return true;
|
|
26376
|
+
const segments = splitPathSegments(filePath).map((segment) => segment.toLowerCase());
|
|
26377
|
+
if (segments.slice(0, -1).some((segment) => SENSITIVE_DIRECTORIES.has(segment))) return true;
|
|
26378
|
+
const parent = segments.at(-2);
|
|
26379
|
+
return SENSITIVE_IN_DIRECTORY.some(([directory, name2]) => directory === parent && name2 === base);
|
|
26035
26380
|
}
|
|
26036
26381
|
async function canonicalizePossiblyMissing(inputPath, base) {
|
|
26037
|
-
const absolute2 =
|
|
26038
|
-
const parsed =
|
|
26382
|
+
const absolute2 = path6.isAbsolute(inputPath) ? path6.resolve(inputPath) : path6.resolve(base, inputPath);
|
|
26383
|
+
const parsed = path6.parse(absolute2);
|
|
26039
26384
|
let current2 = absolute2;
|
|
26040
26385
|
const missing = [];
|
|
26041
26386
|
while (current2 !== parsed.root) {
|
|
26042
26387
|
try {
|
|
26043
|
-
const resolved = await
|
|
26044
|
-
return
|
|
26388
|
+
const resolved = await realpath4(current2);
|
|
26389
|
+
return path6.join(resolved, ...missing.reverse());
|
|
26045
26390
|
} catch (error62) {
|
|
26046
26391
|
if (error62.code !== "ENOENT") throw error62;
|
|
26047
26392
|
let exists = false;
|
|
26048
26393
|
try {
|
|
26049
|
-
await
|
|
26394
|
+
await lstat4(current2);
|
|
26050
26395
|
exists = true;
|
|
26051
26396
|
} catch (statError) {
|
|
26052
26397
|
if (statError.code !== "ENOENT") throw statError;
|
|
26053
26398
|
}
|
|
26054
26399
|
if (exists) throw error62;
|
|
26055
|
-
missing.push(
|
|
26056
|
-
current2 =
|
|
26400
|
+
missing.push(path6.basename(current2));
|
|
26401
|
+
current2 = path6.dirname(current2);
|
|
26057
26402
|
}
|
|
26058
26403
|
}
|
|
26059
|
-
const root = await
|
|
26060
|
-
return
|
|
26404
|
+
const root = await realpath4(parsed.root);
|
|
26405
|
+
return path6.join(root, ...missing.reverse());
|
|
26061
26406
|
}
|
|
26062
26407
|
var PathGuard = class _PathGuard {
|
|
26063
26408
|
constructor(roots, allowSensitiveFiles, protectedPaths) {
|
|
@@ -26073,11 +26418,11 @@ var PathGuard = class _PathGuard {
|
|
|
26073
26418
|
for (const root of roots) {
|
|
26074
26419
|
let resolved;
|
|
26075
26420
|
try {
|
|
26076
|
-
resolved = await
|
|
26421
|
+
resolved = await realpath4(path6.resolve(root));
|
|
26077
26422
|
} catch {
|
|
26078
26423
|
throw new Error(`Configured root does not exist: ${root}`);
|
|
26079
26424
|
}
|
|
26080
|
-
const stat = await
|
|
26425
|
+
const stat = await lstat4(resolved);
|
|
26081
26426
|
if (!stat.isDirectory()) throw new Error(`Configured root is not a directory: ${root}`);
|
|
26082
26427
|
if (!canonical2.some((existing) => comparePath(existing) === comparePath(resolved))) {
|
|
26083
26428
|
canonical2.push(resolved);
|
|
@@ -26086,8 +26431,8 @@ var PathGuard = class _PathGuard {
|
|
|
26086
26431
|
if (canonical2.length === 0) throw new Error("At least one allowed root is required");
|
|
26087
26432
|
const protectedPaths = [];
|
|
26088
26433
|
for (const protectedPath of options.protectedPaths ?? []) {
|
|
26089
|
-
const base =
|
|
26090
|
-
const absolute2 =
|
|
26434
|
+
const base = path6.isAbsolute(protectedPath) ? path6.parse(path6.resolve(protectedPath)).root : canonical2[0];
|
|
26435
|
+
const absolute2 = path6.resolve(base, protectedPath);
|
|
26091
26436
|
if (!protectedPaths.some((existing) => comparePath(existing) === comparePath(absolute2))) protectedPaths.push(absolute2);
|
|
26092
26437
|
const resolved = await canonicalizePossiblyMissing(protectedPath, base);
|
|
26093
26438
|
if (!protectedPaths.some((existing) => comparePath(existing) === comparePath(resolved))) {
|
|
@@ -26103,7 +26448,7 @@ var PathGuard = class _PathGuard {
|
|
|
26103
26448
|
}
|
|
26104
26449
|
assertNotProtected(candidate) {
|
|
26105
26450
|
if (looksProtected(candidate)) {
|
|
26106
|
-
throw new Error(`Local Commander protected state is blocked: ${
|
|
26451
|
+
throw new Error(`Local Commander protected state is blocked: ${path6.basename(candidate)}`);
|
|
26107
26452
|
}
|
|
26108
26453
|
const normalizedCandidate = comparePath(candidate);
|
|
26109
26454
|
for (const protectedPath of this.protectedPaths) {
|
|
@@ -26116,37 +26461,37 @@ var PathGuard = class _PathGuard {
|
|
|
26116
26461
|
this.assertNotProtected(filePath);
|
|
26117
26462
|
if (!this.allowSensitiveFiles && looksSensitive(filePath)) {
|
|
26118
26463
|
throw new Error(
|
|
26119
|
-
`Sensitive file access is blocked by default: ${
|
|
26464
|
+
`Sensitive file access is blocked by default: ${path6.basename(filePath)}. Enable files.allowSensitiveFiles only if you really need it.`
|
|
26120
26465
|
);
|
|
26121
26466
|
}
|
|
26122
26467
|
}
|
|
26123
26468
|
async resolveExisting(inputPath, cwd) {
|
|
26124
26469
|
const base = cwd ? await this.resolveExisting(cwd) : this.roots[0];
|
|
26125
|
-
const candidate =
|
|
26470
|
+
const candidate = path6.isAbsolute(inputPath) ? path6.resolve(inputPath) : path6.resolve(base, inputPath);
|
|
26126
26471
|
this.assertNotProtected(candidate);
|
|
26127
|
-
const resolved = await
|
|
26472
|
+
const resolved = await realpath4(candidate);
|
|
26128
26473
|
this.assertWithinRoots(resolved);
|
|
26129
26474
|
this.assertNotProtected(resolved);
|
|
26130
26475
|
return resolved;
|
|
26131
26476
|
}
|
|
26132
26477
|
async resolveDirectory(inputPath, cwd) {
|
|
26133
26478
|
const resolved = await this.resolveExisting(inputPath, cwd);
|
|
26134
|
-
const stat = await
|
|
26479
|
+
const stat = await lstat4(resolved);
|
|
26135
26480
|
if (!stat.isDirectory()) throw new Error(`Not a directory: ${resolved}`);
|
|
26136
26481
|
return resolved;
|
|
26137
26482
|
}
|
|
26138
26483
|
async resolveForWrite(inputPath, cwd) {
|
|
26139
26484
|
const base = cwd ? await this.resolveDirectory(cwd) : this.roots[0];
|
|
26140
|
-
const candidate =
|
|
26485
|
+
const candidate = path6.isAbsolute(inputPath) ? path6.resolve(inputPath) : path6.resolve(base, inputPath);
|
|
26141
26486
|
this.assertNotProtected(candidate);
|
|
26142
26487
|
let existing;
|
|
26143
26488
|
try {
|
|
26144
|
-
existing = await
|
|
26489
|
+
existing = await realpath4(candidate);
|
|
26145
26490
|
} catch (error62) {
|
|
26146
26491
|
if (error62.code !== "ENOENT") throw error62;
|
|
26147
26492
|
let exists = false;
|
|
26148
26493
|
try {
|
|
26149
|
-
await
|
|
26494
|
+
await lstat4(candidate);
|
|
26150
26495
|
exists = true;
|
|
26151
26496
|
} catch (statError) {
|
|
26152
26497
|
if (statError.code !== "ENOENT") throw statError;
|
|
@@ -26159,11 +26504,11 @@ var PathGuard = class _PathGuard {
|
|
|
26159
26504
|
this.assertSafeFile(existing);
|
|
26160
26505
|
return existing;
|
|
26161
26506
|
}
|
|
26162
|
-
const parent = await
|
|
26507
|
+
const parent = await realpath4(path6.dirname(candidate));
|
|
26163
26508
|
this.assertWithinRoots(parent);
|
|
26164
26509
|
this.assertNotProtected(parent);
|
|
26165
26510
|
this.assertSafeFile(candidate);
|
|
26166
|
-
const target =
|
|
26511
|
+
const target = path6.join(parent, path6.basename(candidate));
|
|
26167
26512
|
this.assertSafeFile(target);
|
|
26168
26513
|
return target;
|
|
26169
26514
|
}
|
|
@@ -26174,12 +26519,12 @@ var PathGuard = class _PathGuard {
|
|
|
26174
26519
|
|
|
26175
26520
|
// src/windows-file-read.ts
|
|
26176
26521
|
import { execFile } from "node:child_process";
|
|
26177
|
-
import
|
|
26522
|
+
import path7 from "node:path";
|
|
26178
26523
|
function readWindowsFile(bridge, file2, maxBytes, signal) {
|
|
26179
26524
|
return invokeRead(bridge, file2, maxBytes, false, signal);
|
|
26180
26525
|
}
|
|
26181
26526
|
function invokeRead(bridge, file2, maxBytes, prefix, signal) {
|
|
26182
|
-
if (process.platform !== "win32" || !
|
|
26527
|
+
if (process.platform !== "win32" || !path7.isAbsolute(bridge) || !path7.isAbsolute(file2) || !Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > (prefix ? 16777216 : 1048576)) {
|
|
26183
26528
|
return Promise.reject(new Error("FILE_READ_ARGUMENT_INVALID"));
|
|
26184
26529
|
}
|
|
26185
26530
|
if (signal?.aborted) return Promise.reject(new Error("CANCELLED"));
|
|
@@ -26208,9 +26553,9 @@ function invokeRead(bridge, file2, maxBytes, prefix, signal) {
|
|
|
26208
26553
|
|
|
26209
26554
|
// agent/src/job-supervisor.ts
|
|
26210
26555
|
import { spawn as spawn2 } from "node:child_process";
|
|
26211
|
-
import
|
|
26556
|
+
import path8 from "node:path";
|
|
26212
26557
|
function absolute(value) {
|
|
26213
|
-
return typeof value === "string" && value.length > 0 && value.length < 32767 && !value.includes("\0") &&
|
|
26558
|
+
return typeof value === "string" && value.length > 0 && value.length < 32767 && !value.includes("\0") && path8.isAbsolute(value) && path8.resolve(value) === value;
|
|
26214
26559
|
}
|
|
26215
26560
|
async function runSupervised(helper, request, options = {}) {
|
|
26216
26561
|
if (process.platform !== "win32") throw Error("WINDOWS_SUPERVISOR_REQUIRED");
|
|
@@ -26226,7 +26571,7 @@ async function runSupervised(helper, request, options = {}) {
|
|
|
26226
26571
|
let pid = null, outcome = null;
|
|
26227
26572
|
let buffer = "", failure5 = null, closed = false, cancelSent = false;
|
|
26228
26573
|
let killTimer, hardTimer;
|
|
26229
|
-
const child = spawn2(helper, [], { cwd:
|
|
26574
|
+
const child = spawn2(helper, [], { cwd: path8.dirname(helper), stdio: ["pipe", "pipe", "pipe"], windowsHide: true, shell: false, env: buildChildEnvironment(process.env) });
|
|
26230
26575
|
const cancel = () => {
|
|
26231
26576
|
if (closed || cancelSent) return;
|
|
26232
26577
|
cancelSent = true;
|
|
@@ -26328,9 +26673,9 @@ function fail2(code) {
|
|
|
26328
26673
|
throw new NativeToolError(code);
|
|
26329
26674
|
}
|
|
26330
26675
|
function hash5(value) {
|
|
26331
|
-
return
|
|
26676
|
+
return createHash9("sha256").update(value).digest("hex");
|
|
26332
26677
|
}
|
|
26333
|
-
function
|
|
26678
|
+
function equalPath3(a, b) {
|
|
26334
26679
|
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
26335
26680
|
}
|
|
26336
26681
|
function result(body) {
|
|
@@ -26342,7 +26687,7 @@ function stopped(signal) {
|
|
|
26342
26687
|
if (signal.aborted) fail2("CANCELLED");
|
|
26343
26688
|
}
|
|
26344
26689
|
async function readBoundedFile(file2, maxBytes, bridge, signal) {
|
|
26345
|
-
const stat = await
|
|
26690
|
+
const stat = await lstat5(file2);
|
|
26346
26691
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > maxBytes) fail2("FILE_UNSUPPORTED_OR_TOO_LARGE");
|
|
26347
26692
|
if (process.platform === "win32") return readWindowsFile(bridge, file2, maxBytes, signal);
|
|
26348
26693
|
const handle = await open4(file2, constants3.O_RDONLY | (constants3.O_NOFOLLOW ?? 0));
|
|
@@ -26380,7 +26725,7 @@ var NativeTools = class {
|
|
|
26380
26725
|
options;
|
|
26381
26726
|
async readFile(file2, maxBytes, signal) {
|
|
26382
26727
|
try {
|
|
26383
|
-
return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ??
|
|
26728
|
+
return await readBoundedFile(file2, maxBytes, this.options.ownerBridgePath ?? path9.join(path9.dirname(this.options.helperPath), "OwnerBridge.exe"), signal);
|
|
26384
26729
|
} catch (error62) {
|
|
26385
26730
|
if (error62.code === "ENOENT") throw error62;
|
|
26386
26731
|
if (error62 instanceof Error && /^[A-Z_]{1,40}$/.test(error62.message)) fail2(error62.message);
|
|
@@ -26403,9 +26748,19 @@ var NativeTools = class {
|
|
|
26403
26748
|
if (scope2 === "files:read" && !permission.readFiles || scope2 === "files:write" && !permission.writeFiles || scope2 === "commands:execute" && !permission.executeCommands || scope2 === "localhost:access" && !permission.localhost) fail2("LOCAL_PERMISSION_REQUIRED");
|
|
26404
26749
|
let guard;
|
|
26405
26750
|
try {
|
|
26406
|
-
const canonical2 = await
|
|
26407
|
-
if (!
|
|
26408
|
-
|
|
26751
|
+
const canonical2 = await realpath5(workspace.root);
|
|
26752
|
+
if (!equalPath3(canonical2, workspace.root) || hash5(process.platform === "win32" ? canonical2.toLowerCase() : canonical2) !== workspace.rootHash) fail2("WORKSPACE_CHANGED");
|
|
26753
|
+
const runtimeDirectory = path9.dirname(this.options.helperPath);
|
|
26754
|
+
const protectedPaths = [
|
|
26755
|
+
this.options.stateDirectory,
|
|
26756
|
+
this.options.helperPath,
|
|
26757
|
+
...["agent.mjs", "node.exe", "OwnerBridge.exe", "LocalCommanderAgent.exe"].map((name2) => path9.join(runtimeDirectory, name2))
|
|
26758
|
+
];
|
|
26759
|
+
if (this.options.ownerBridgePath) protectedPaths.push(this.options.ownerBridgePath);
|
|
26760
|
+
if (process.platform === "win32" && process.env.LOCALAPPDATA && path9.isAbsolute(process.env.LOCALAPPDATA)) {
|
|
26761
|
+
protectedPaths.push(path9.join(process.env.LOCALAPPDATA, "LocalCommander"));
|
|
26762
|
+
}
|
|
26763
|
+
guard = await PathGuard.create([canonical2], false, { protectedPaths });
|
|
26409
26764
|
} catch (e) {
|
|
26410
26765
|
if (e instanceof NativeToolError) throw e;
|
|
26411
26766
|
fail2("WORKSPACE_UNAVAILABLE");
|
|
@@ -26431,11 +26786,11 @@ var NativeTools = class {
|
|
|
26431
26786
|
return { call, claims: readClaim(filename), run: async (signal) => {
|
|
26432
26787
|
stopped(signal);
|
|
26433
26788
|
const verified = await resolve(call.args.path);
|
|
26434
|
-
if (!
|
|
26789
|
+
if (!equalPath3(verified, filename)) fail2("FILE_CHANGED");
|
|
26435
26790
|
const bytes3 = await this.readFile(filename, 1048576, signal), contents = utf8(bytes3), lines = contents.split(/\r?\n/);
|
|
26436
26791
|
const selected = lines.slice(first - 1, Math.min(last, lines.length)).join("\n");
|
|
26437
26792
|
if (Buffer.byteLength(selected) > 12e4) fail2("OUTPUT_LIMIT_EXCEEDED");
|
|
26438
|
-
return result({ path:
|
|
26793
|
+
return result({ path: path9.relative(workspace.root, filename), sha256: hash5(bytes3), startLine: first, endLine: Math.min(last, lines.length), totalLines: lines.length, content: selected, truncated: last < lines.length });
|
|
26439
26794
|
} };
|
|
26440
26795
|
}
|
|
26441
26796
|
if (call.name === "fs_write" || call.name === "fs_replace") {
|
|
@@ -26450,7 +26805,7 @@ var NativeTools = class {
|
|
|
26450
26805
|
return { call, claims: writeClaim(filename), run: async (signal) => {
|
|
26451
26806
|
stopped(signal);
|
|
26452
26807
|
const target = await guard.resolveForWrite(args.path);
|
|
26453
|
-
if (!
|
|
26808
|
+
if (!equalPath3(filename, target)) fail2("FILE_CHANGED");
|
|
26454
26809
|
let old = null;
|
|
26455
26810
|
try {
|
|
26456
26811
|
old = await this.readFile(target, 1048576, signal);
|
|
@@ -26470,8 +26825,8 @@ var NativeTools = class {
|
|
|
26470
26825
|
contents = pieces.join(call.args.newText);
|
|
26471
26826
|
}
|
|
26472
26827
|
const bytes3 = Buffer.from(contents, "utf8");
|
|
26473
|
-
if (bytes3.length >
|
|
26474
|
-
const temp =
|
|
26828
|
+
if (bytes3.length > MAX_FILE_WRITE_BYTES) fail2("FILE_WRITE_LIMIT");
|
|
26829
|
+
const temp = path9.join(path9.dirname(target), ".lc-write-" + randomUUID4() + ".tmp");
|
|
26475
26830
|
const handle = await open4(temp, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
|
|
26476
26831
|
try {
|
|
26477
26832
|
await handle.writeFile(bytes3);
|
|
@@ -26479,7 +26834,7 @@ var NativeTools = class {
|
|
|
26479
26834
|
await handle.close();
|
|
26480
26835
|
stopped(signal);
|
|
26481
26836
|
const again = await guard.resolveForWrite(args.path);
|
|
26482
|
-
if (!
|
|
26837
|
+
if (!equalPath3(target, again)) fail2("FILE_CHANGED");
|
|
26483
26838
|
if (old) {
|
|
26484
26839
|
if (hash5(await this.readFile(target, 1048576, signal)) !== hash5(old)) fail2("FILE_CHANGED");
|
|
26485
26840
|
await rename3(temp, target);
|
|
@@ -26488,7 +26843,7 @@ var NativeTools = class {
|
|
|
26488
26843
|
await link(temp, target);
|
|
26489
26844
|
await rm3(temp);
|
|
26490
26845
|
}
|
|
26491
|
-
return result({ path:
|
|
26846
|
+
return result({ path: path9.relative(workspace.root, target), bytes: bytes3.length, sha256: hash5(bytes3), ...call.name === "fs_replace" ? { replacements } : {} });
|
|
26492
26847
|
} catch (e) {
|
|
26493
26848
|
await handle.close().catch(() => {
|
|
26494
26849
|
});
|
|
@@ -26509,12 +26864,12 @@ var NativeTools = class {
|
|
|
26509
26864
|
stopped(signal);
|
|
26510
26865
|
if (matches2.length >= call.args.maxResults || scanned >= 300) break;
|
|
26511
26866
|
try {
|
|
26512
|
-
const filename = await guard.resolveExisting(
|
|
26867
|
+
const filename = await guard.resolveExisting(path9.join(base, entry.path));
|
|
26513
26868
|
guard.assertSafeFile(filename);
|
|
26514
26869
|
const data = utf8(await this.readFile(filename, 256e3, signal));
|
|
26515
26870
|
scanned++;
|
|
26516
26871
|
const lines = data.split(/\r?\n/);
|
|
26517
|
-
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:
|
|
26872
|
+
for (let i = 0; i < lines.length && matches2.length < call.args.maxResults; i++) if ((call.args.caseSensitive ? lines[i] : lines[i].toLowerCase()).includes(query)) matches2.push({ path: path9.relative(workspace.root, filename), line: i + 1, text: lines[i].slice(0, 500) });
|
|
26518
26873
|
} catch (error62) {
|
|
26519
26874
|
if (error62 instanceof NativeToolError && ["FILE_READ_FAILED", "CANCELLED"].includes(error62.code)) throw error62;
|
|
26520
26875
|
}
|
|
@@ -26526,9 +26881,9 @@ var NativeTools = class {
|
|
|
26526
26881
|
const url2 = new URL(call.args.url), port = Number(url2.port || (url2.protocol === "https:" ? 443 : 80));
|
|
26527
26882
|
if (!["http:", "https:"].includes(url2.protocol) || !["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname) || url2.username || url2.password || url2.hash || !workspace.localhostPorts.includes(port) || this.options.protectedPorts?.includes(port)) fail2("LOCALHOST_NOT_ALLOWED");
|
|
26528
26883
|
const headers = {};
|
|
26529
|
-
for (const [
|
|
26530
|
-
if (!/^[A-Za-z0-9-]+$/.test(
|
|
26531
|
-
headers[
|
|
26884
|
+
for (const [name2, value] of Object.entries(call.args.headers ?? {})) {
|
|
26885
|
+
if (!/^[A-Za-z0-9-]+$/.test(name2) || /[\r\n]/.test(value) || ["host", "connection", "content-length", "transfer-encoding", "upgrade", "proxy-authorization", "proxy-connection"].includes(name2.toLowerCase()) || Object.keys(headers).some((k) => k.toLowerCase() === name2.toLowerCase())) fail2("INVALID_HTTP_HEADER");
|
|
26886
|
+
headers[name2] = value;
|
|
26532
26887
|
}
|
|
26533
26888
|
if (Object.keys(headers).length > 32 || ["GET", "HEAD"].includes(call.args.method) && call.args.body !== void 0) fail2("INVALID_HTTP_ARGUMENTS");
|
|
26534
26889
|
if (url2.hostname === "localhost") url2.hostname = "127.0.0.1";
|
|
@@ -26536,9 +26891,9 @@ var NativeTools = class {
|
|
|
26536
26891
|
const combined = AbortSignal.any([signal, AbortSignal.timeout(1e4)]);
|
|
26537
26892
|
const response = await fetch(url2, { method: call.args.method, headers, body: call.args.body, redirect: "manual", signal: combined });
|
|
26538
26893
|
const selectedHeaders = {};
|
|
26539
|
-
for (const
|
|
26540
|
-
const value = response.headers.get(
|
|
26541
|
-
if (value) selectedHeaders[
|
|
26894
|
+
for (const name2 of ["content-type", "content-length", "location", "etag", "last-modified"]) {
|
|
26895
|
+
const value = response.headers.get(name2);
|
|
26896
|
+
if (value) selectedHeaders[name2] = value.slice(0, 2048);
|
|
26542
26897
|
}
|
|
26543
26898
|
const reader = response.body?.getReader(), chunks = [];
|
|
26544
26899
|
let count = 0, truncated = false;
|
|
@@ -26583,9 +26938,9 @@ var NativeTools = class {
|
|
|
26583
26938
|
else if (call.name === "git_diff") {
|
|
26584
26939
|
argv = ["diff", "--no-ext-diff", "--no-textconv", ...call.args.staged ? ["--cached"] : []];
|
|
26585
26940
|
if (call.args.file) {
|
|
26586
|
-
const file2 = await resolve(
|
|
26587
|
-
const relative =
|
|
26588
|
-
if (relative.startsWith(".." +
|
|
26941
|
+
const file2 = await resolve(path9.resolve(cwd, call.args.file));
|
|
26942
|
+
const relative = path9.relative(cwd, file2);
|
|
26943
|
+
if (relative.startsWith(".." + path9.sep) || relative === ".." || path9.isAbsolute(relative)) fail2("PATH_NOT_ALLOWED");
|
|
26589
26944
|
argv.push("--", relative);
|
|
26590
26945
|
} else argv.push("--stat");
|
|
26591
26946
|
} else fail2("TOOL_MISSING");
|
|
@@ -26596,9 +26951,9 @@ var NativeTools = class {
|
|
|
26596
26951
|
const listing = await this.list(guard, cwd, 1, 150, signal);
|
|
26597
26952
|
let packageInfo = null;
|
|
26598
26953
|
try {
|
|
26599
|
-
const
|
|
26600
|
-
guard.assertSafeFile(
|
|
26601
|
-
const value = JSON.parse(utf8(await this.readFile(
|
|
26954
|
+
const name2 = await guard.resolveExisting(path9.join(cwd, "package.json"));
|
|
26955
|
+
guard.assertSafeFile(name2);
|
|
26956
|
+
const value = JSON.parse(utf8(await this.readFile(name2, 64e3, signal)));
|
|
26602
26957
|
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) : [] };
|
|
26603
26958
|
} catch (error62) {
|
|
26604
26959
|
if (error62 instanceof NativeToolError && ["FILE_READ_FAILED", "CANCELLED"].includes(error62.code)) throw error62;
|
|
@@ -26612,14 +26967,14 @@ var NativeTools = class {
|
|
|
26612
26967
|
return { ...output2, resultCode: r.exitCode === 0 ? "SUCCESS" : "GIT_FAILED" };
|
|
26613
26968
|
} };
|
|
26614
26969
|
}
|
|
26615
|
-
resolveProgram(
|
|
26616
|
-
const entry = Object.entries(this.options.programs).find(([key, value]) => key.toLowerCase() ===
|
|
26617
|
-
if (!entry || !workspace.allowedCommands.some((v) => v.toLowerCase() === entry[0].toLowerCase()) || !
|
|
26970
|
+
resolveProgram(name2, workspace) {
|
|
26971
|
+
const entry = Object.entries(this.options.programs).find(([key, value]) => key.toLowerCase() === name2.toLowerCase() || path9.isAbsolute(name2) && equalPath3(value.executable, path9.resolve(name2)));
|
|
26972
|
+
if (!entry || !workspace.allowedCommands.some((v) => v.toLowerCase() === entry[0].toLowerCase()) || !path9.isAbsolute(entry[1].executable)) fail2("COMMAND_NOT_ALLOWED");
|
|
26618
26973
|
return { executable: entry[1].executable, prefixArgs: [...entry[1].prefixArgs ?? []] };
|
|
26619
26974
|
}
|
|
26620
26975
|
gitExecution(cwd, args) {
|
|
26621
26976
|
const program = this.options.programs.git;
|
|
26622
|
-
if (!program || !
|
|
26977
|
+
if (!program || !path9.isAbsolute(program.executable)) fail2("GIT_NOT_INSTALLED");
|
|
26623
26978
|
return { executable: program.executable, args: ["--no-pager", "--no-optional-locks", "-c", "core.fsmonitor=false", "-c", "core.hooksPath=" + (process.platform === "win32" ? "NUL" : "/dev/null"), "-c", "diff.external=", ...args], cwd };
|
|
26624
26979
|
}
|
|
26625
26980
|
async list(guard, root, depth, maxEntries, signal) {
|
|
@@ -26637,7 +26992,7 @@ var NativeTools = class {
|
|
|
26637
26992
|
break;
|
|
26638
26993
|
}
|
|
26639
26994
|
if (item.isSymbolicLink() || excluded.has(item.name.toLowerCase())) continue;
|
|
26640
|
-
const candidate =
|
|
26995
|
+
const candidate = path9.join(current2.path, item.name);
|
|
26641
26996
|
let resolved;
|
|
26642
26997
|
try {
|
|
26643
26998
|
resolved = await guard.resolveExisting(candidate);
|
|
@@ -26645,13 +27000,13 @@ var NativeTools = class {
|
|
|
26645
27000
|
} catch {
|
|
26646
27001
|
continue;
|
|
26647
27002
|
}
|
|
26648
|
-
if (!
|
|
27003
|
+
if (!equalPath3(candidate, resolved)) continue;
|
|
26649
27004
|
if (item.isDirectory()) {
|
|
26650
|
-
entries.push({ path:
|
|
27005
|
+
entries.push({ path: path9.relative(root, resolved), type: "directory" });
|
|
26651
27006
|
if (current2.level < depth) queue.push({ path: resolved, level: current2.level + 1 });
|
|
26652
27007
|
} else if (item.isFile()) {
|
|
26653
|
-
const stat = await
|
|
26654
|
-
entries.push({ path:
|
|
27008
|
+
const stat = await lstat5(resolved);
|
|
27009
|
+
entries.push({ path: path9.relative(root, resolved), type: "file", size: stat.size });
|
|
26655
27010
|
}
|
|
26656
27011
|
}
|
|
26657
27012
|
if (truncated) break;
|
|
@@ -26661,49 +27016,49 @@ var NativeTools = class {
|
|
|
26661
27016
|
async gitCommonDir(cwd, workspace, guard) {
|
|
26662
27017
|
let directory = cwd;
|
|
26663
27018
|
while (guard.isWithin(directory, workspace.root)) {
|
|
26664
|
-
const dotGit =
|
|
27019
|
+
const dotGit = path9.join(directory, ".git");
|
|
26665
27020
|
try {
|
|
26666
|
-
const stat = await
|
|
27021
|
+
const stat = await lstat5(dotGit);
|
|
26667
27022
|
if (stat.isSymbolicLink()) fail2("GIT_METADATA_CHANGED");
|
|
26668
27023
|
let gitDir;
|
|
26669
|
-
if (stat.isDirectory()) gitDir = await
|
|
27024
|
+
if (stat.isDirectory()) gitDir = await realpath5(dotGit);
|
|
26670
27025
|
else {
|
|
26671
27026
|
const content = utf8(await this.readFile(dotGit, 4096)).trim();
|
|
26672
27027
|
if (!content.startsWith("gitdir: ")) fail2("GIT_METADATA_CHANGED");
|
|
26673
|
-
gitDir = await
|
|
27028
|
+
gitDir = await realpath5(path9.resolve(directory, content.slice(8)));
|
|
26674
27029
|
}
|
|
26675
27030
|
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");
|
|
26676
27031
|
let common = gitDir;
|
|
26677
27032
|
try {
|
|
26678
|
-
const content = utf8(await this.readFile(
|
|
27033
|
+
const content = utf8(await this.readFile(path9.join(gitDir, "commondir"), 4096)).trim();
|
|
26679
27034
|
if (!content) fail2("GIT_METADATA_CHANGED");
|
|
26680
|
-
common = await
|
|
27035
|
+
common = await realpath5(path9.resolve(gitDir, content));
|
|
26681
27036
|
} catch (e) {
|
|
26682
27037
|
if (e.code !== "ENOENT") throw e;
|
|
26683
27038
|
}
|
|
26684
|
-
if (!(await
|
|
26685
|
-
if (!guard.isWithin(common, workspace.root) && (!workspace.gitCommonDir || !
|
|
27039
|
+
if (!(await lstat5(common)).isDirectory() || guard.isWithin(common, this.options.stateDirectory)) fail2("GIT_METADATA_CHANGED");
|
|
27040
|
+
if (!guard.isWithin(common, workspace.root) && (!workspace.gitCommonDir || !equalPath3(common, workspace.gitCommonDir))) fail2("GIT_COMMON_DIRECTORY_NOT_APPROVED");
|
|
26686
27041
|
return common;
|
|
26687
27042
|
} catch (e) {
|
|
26688
27043
|
if (e.code !== "ENOENT") throw e;
|
|
26689
27044
|
}
|
|
26690
|
-
if (
|
|
26691
|
-
directory =
|
|
27045
|
+
if (equalPath3(directory, workspace.root)) break;
|
|
27046
|
+
directory = path9.dirname(directory);
|
|
26692
27047
|
}
|
|
26693
27048
|
return null;
|
|
26694
27049
|
}
|
|
26695
27050
|
};
|
|
26696
27051
|
|
|
26697
27052
|
// agent/src/scheduler.ts
|
|
26698
|
-
import
|
|
27053
|
+
import path10 from "node:path";
|
|
26699
27054
|
import os2 from "node:os";
|
|
26700
27055
|
function canonical(value) {
|
|
26701
|
-
const p =
|
|
27056
|
+
const p = path10.resolve(value);
|
|
26702
27057
|
return process.platform === "win32" ? p.toLowerCase() : p;
|
|
26703
27058
|
}
|
|
26704
27059
|
function ancestor(a, b) {
|
|
26705
|
-
const relative =
|
|
26706
|
-
return relative === "" || !
|
|
27060
|
+
const relative = path10.relative(a, b);
|
|
27061
|
+
return relative === "" || !path10.isAbsolute(relative) && relative !== ".." && !relative.startsWith(".." + path10.sep);
|
|
26707
27062
|
}
|
|
26708
27063
|
function claimsConflict(a, b) {
|
|
26709
27064
|
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))));
|
|
@@ -26723,7 +27078,7 @@ var NativeScheduler = class {
|
|
|
26723
27078
|
schedule(id, claims, deadlineAt, run, signal) {
|
|
26724
27079
|
if (!this.accepting) return Promise.reject(Error("AGENT_PAUSED"));
|
|
26725
27080
|
if (!id || id.length > 100 || this.active.has(id) || this.waiting.some((j) => j.id === id)) return Promise.reject(Error("DUPLICATE_SCHEDULED_EXECUTION"));
|
|
26726
|
-
if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !
|
|
27081
|
+
if (!Array.isArray(claims) || !claims.length || claims.length > 32 || claims.some((c) => !c || !path10.isAbsolute(c.path) || !["read", "write"].includes(c.mode))) return Promise.reject(Error("INVALID_RESOURCE_CLAIM"));
|
|
26727
27082
|
const deadline = deadlineAt.getTime();
|
|
26728
27083
|
if (!Number.isFinite(deadline) || deadline <= Date.now()) return Promise.reject(Error("ADMISSION_DEADLINE_EXPIRED"));
|
|
26729
27084
|
if (signal?.aborted) return Promise.reject(Error("CANCELLED_BEFORE_ACCEPTANCE"));
|
|
@@ -27183,17 +27538,17 @@ function unshapedResultTelemetry(result2) {
|
|
|
27183
27538
|
|
|
27184
27539
|
// packages/optimization/src/live-telemetry.ts
|
|
27185
27540
|
var LIVE_EFFICIENCY_EVENT_VERSION = 1;
|
|
27186
|
-
var
|
|
27541
|
+
var uuid15 = external_exports.string().uuid().toLowerCase();
|
|
27187
27542
|
var bytes2 = external_exports.number().int().min(0).max(1e9);
|
|
27188
27543
|
var utc4 = external_exports.iso.datetime({ offset: false });
|
|
27189
27544
|
var LiveEfficiencyEventSchema = external_exports.object({
|
|
27190
27545
|
version: external_exports.literal(LIVE_EFFICIENCY_EVENT_VERSION),
|
|
27191
27546
|
occurredAt: utc4,
|
|
27192
|
-
tenantId:
|
|
27193
|
-
accountId:
|
|
27194
|
-
sessionId:
|
|
27195
|
-
operationId:
|
|
27196
|
-
executionId:
|
|
27547
|
+
tenantId: uuid15,
|
|
27548
|
+
accountId: uuid15.nullable(),
|
|
27549
|
+
sessionId: uuid15,
|
|
27550
|
+
operationId: uuid15,
|
|
27551
|
+
executionId: uuid15,
|
|
27197
27552
|
toolName: external_exports.string().trim().min(1).max(120),
|
|
27198
27553
|
outcome: external_exports.enum(["success", "failed", "timed_out", "cancelled", "unknown"]),
|
|
27199
27554
|
parserId: external_exports.string().trim().min(1).max(120).nullable(),
|
|
@@ -27675,10 +28030,10 @@ var NativeRelayBridge = class {
|
|
|
27675
28030
|
const { binding: binding2, tool } = parsed2.data;
|
|
27676
28031
|
this.binding(request, binding2);
|
|
27677
28032
|
const prepared = await this.wait(this.execution, binding2.executionId, request, () => this.runtime.receive({ type: "prepare", version: 1, binding: binding2, tool }));
|
|
27678
|
-
if (prepared.type === "not_accepted") return { accepted: false, provedNotStarted: prepared.provedNotStarted };
|
|
28033
|
+
if (prepared.type === "not_accepted") return { accepted: false, provedNotStarted: prepared.provedNotStarted, code: prepared.code };
|
|
27679
28034
|
if (prepared.type !== "prepared") throw failure3("INFRA_UNAVAILABLE");
|
|
27680
28035
|
const accepted = await this.wait(this.execution, binding2.executionId, request, () => this.runtime.receive({ type: "execute", version: 1, binding: binding2 }));
|
|
27681
|
-
if (accepted.type === "not_accepted") return { accepted: false, provedNotStarted: accepted.provedNotStarted };
|
|
28036
|
+
if (accepted.type === "not_accepted") return { accepted: false, provedNotStarted: accepted.provedNotStarted, code: accepted.code };
|
|
27682
28037
|
if (accepted.type !== "accepted") throw failure3("INFRA_UNAVAILABLE");
|
|
27683
28038
|
return { accepted: true };
|
|
27684
28039
|
}
|
|
@@ -27706,141 +28061,6 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
27706
28061
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
27707
28062
|
var wrapper_default = import_websocket.default;
|
|
27708
28063
|
|
|
27709
|
-
// packages/contracts/src/index.ts
|
|
27710
|
-
var protocolVersion = 1;
|
|
27711
|
-
var uuid14 = external_exports.string().uuid().toLowerCase();
|
|
27712
|
-
var nonEmpty = external_exports.string().trim().min(1);
|
|
27713
|
-
var utcDateTime2 = external_exports.iso.datetime({ offset: false }).refine((value) => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/.test(value), "Expected UTC timestamp with seconds");
|
|
27714
|
-
var units = external_exports.number().int().min(0).max(1e9);
|
|
27715
|
-
function validUsagePeriod(value) {
|
|
27716
|
-
const start = new Date(value.periodStartUtc);
|
|
27717
|
-
if (!Number.isFinite(start.getTime()) || start.getUTCDate() !== 1 || start.getUTCHours() !== 0 || start.getUTCMinutes() !== 0 || start.getUTCSeconds() !== 0 || start.getUTCMilliseconds() !== 0) return false;
|
|
27718
|
-
const end = new Date(start);
|
|
27719
|
-
end.setUTCMonth(end.getUTCMonth() + 1);
|
|
27720
|
-
return Date.parse(value.periodEndUtc) === end.getTime();
|
|
27721
|
-
}
|
|
27722
|
-
var PermissionScopeSchema = external_exports.enum([
|
|
27723
|
-
"devices:read",
|
|
27724
|
-
"sessions:manage",
|
|
27725
|
-
"files:read",
|
|
27726
|
-
"files:write",
|
|
27727
|
-
"commands:execute",
|
|
27728
|
-
"processes:control",
|
|
27729
|
-
"localhost:access"
|
|
27730
|
-
]);
|
|
27731
|
-
var OperationStateSchema = external_exports.enum([
|
|
27732
|
-
"queued",
|
|
27733
|
-
"prepared",
|
|
27734
|
-
"accepted",
|
|
27735
|
-
"running",
|
|
27736
|
-
"finished",
|
|
27737
|
-
"failed",
|
|
27738
|
-
"cancel_requested",
|
|
27739
|
-
"cancelled",
|
|
27740
|
-
"rejected",
|
|
27741
|
-
"unknown"
|
|
27742
|
-
]);
|
|
27743
|
-
var ErrorCodeSchema = external_exports.enum([
|
|
27744
|
-
"AUTH_REQUIRED",
|
|
27745
|
-
"GRANT_REVOKED",
|
|
27746
|
-
"DEVICE_OFFLINE",
|
|
27747
|
-
"SETUP_REQUIRED",
|
|
27748
|
-
"DEVICE_NOT_OWNED",
|
|
27749
|
-
"SESSION_EXPIRED",
|
|
27750
|
-
"LOCAL_PERMISSION_REQUIRED",
|
|
27751
|
-
"QUOTA_EXHAUSTED",
|
|
27752
|
-
"CAPACITY_BUSY",
|
|
27753
|
-
"RESOURCE_BUSY",
|
|
27754
|
-
"POLICY_DENIED",
|
|
27755
|
-
"TOOL_MISSING",
|
|
27756
|
-
"TIMEOUT",
|
|
27757
|
-
"CANCEL_REQUESTED",
|
|
27758
|
-
"EXECUTION_UNKNOWN",
|
|
27759
|
-
"OUTPUT_EXPIRED",
|
|
27760
|
-
"INFRA_UNAVAILABLE",
|
|
27761
|
-
"IDEMPOTENCY_CONFLICT"
|
|
27762
|
-
]);
|
|
27763
|
-
var LedgerEventKindSchema = external_exports.enum(["reserve", "charge", "release", "credit"]);
|
|
27764
|
-
var TrustedPrincipalSchema = external_exports.object({
|
|
27765
|
-
protocolVersion: external_exports.literal(protocolVersion),
|
|
27766
|
-
accountId: uuid14,
|
|
27767
|
-
tenantId: uuid14,
|
|
27768
|
-
grantId: uuid14,
|
|
27769
|
-
scopes: external_exports.array(PermissionScopeSchema).min(1).max(32),
|
|
27770
|
-
authenticatedAt: utcDateTime2,
|
|
27771
|
-
expiresAt: utcDateTime2
|
|
27772
|
-
}).strict().refine((value) => Date.parse(value.authenticatedAt) < Date.parse(value.expiresAt), { path: ["expiresAt"], message: "Expiry must follow authentication" });
|
|
27773
|
-
var ExecutionSessionSchema = external_exports.object({
|
|
27774
|
-
protocolVersion: external_exports.literal(protocolVersion),
|
|
27775
|
-
executionSessionId: uuid14,
|
|
27776
|
-
tenantId: uuid14,
|
|
27777
|
-
grantId: uuid14,
|
|
27778
|
-
deviceId: uuid14,
|
|
27779
|
-
workspaceGrantId: uuid14.optional(),
|
|
27780
|
-
policyVersion: external_exports.string().trim().min(1).max(64),
|
|
27781
|
-
openedAt: utcDateTime2,
|
|
27782
|
-
expiresAt: utcDateTime2,
|
|
27783
|
-
state: external_exports.enum(["open", "closing", "closed", "expired"])
|
|
27784
|
-
}).strict().refine((value) => Date.parse(value.openedAt) < Date.parse(value.expiresAt), { path: ["expiresAt"], message: "Expiry must follow session creation" });
|
|
27785
|
-
var ChildCommandSchema = external_exports.object({
|
|
27786
|
-
childExecutionId: uuid14,
|
|
27787
|
-
executable: nonEmpty.max(260),
|
|
27788
|
-
argv: external_exports.array(external_exports.string().max(8192)).max(128).default([]),
|
|
27789
|
-
cwd: external_exports.string().trim().min(1).max(2048).optional(),
|
|
27790
|
-
deadlineAt: utcDateTime2.optional()
|
|
27791
|
-
}).strict();
|
|
27792
|
-
var ClientCommandRequestSchema = external_exports.object({
|
|
27793
|
-
protocolVersion: external_exports.literal(protocolVersion),
|
|
27794
|
-
executionSessionId: uuid14,
|
|
27795
|
-
operationId: uuid14,
|
|
27796
|
-
idempotencyKey: external_exports.string().trim().min(8).max(128),
|
|
27797
|
-
children: external_exports.array(ChildCommandSchema).min(2).max(32)
|
|
27798
|
-
}).strict().superRefine((value, ctx) => {
|
|
27799
|
-
const seen = /* @__PURE__ */ new Set();
|
|
27800
|
-
value.children.forEach((child, index) => {
|
|
27801
|
-
if (seen.has(child.childExecutionId)) {
|
|
27802
|
-
ctx.addIssue({ code: "custom", path: ["children", index, "childExecutionId"], message: "childExecutionId must be unique within a batch" });
|
|
27803
|
-
}
|
|
27804
|
-
seen.add(child.childExecutionId);
|
|
27805
|
-
});
|
|
27806
|
-
});
|
|
27807
|
-
var ControlOperationSchema = external_exports.object({
|
|
27808
|
-
protocolVersion: external_exports.literal(protocolVersion),
|
|
27809
|
-
executionSessionId: uuid14,
|
|
27810
|
-
operationId: uuid14,
|
|
27811
|
-
kind: external_exports.enum(["status", "output", "cancel"]),
|
|
27812
|
-
cursor: external_exports.string().trim().min(1).max(512).optional()
|
|
27813
|
-
}).strict();
|
|
27814
|
-
var LedgerEventSchema = external_exports.object({
|
|
27815
|
-
protocolVersion: external_exports.literal(protocolVersion),
|
|
27816
|
-
tenantId: uuid14,
|
|
27817
|
-
executionId: uuid14,
|
|
27818
|
-
eventKind: LedgerEventKindSchema,
|
|
27819
|
-
units: external_exports.literal(1),
|
|
27820
|
-
periodStartUtc: utcDateTime2,
|
|
27821
|
-
periodEndUtc: utcDateTime2,
|
|
27822
|
-
occurredAt: utcDateTime2,
|
|
27823
|
-
adjustmentId: uuid14.optional()
|
|
27824
|
-
}).strict().refine(validUsagePeriod, { path: ["periodEndUtc"], message: "Expected one UTC calendar month" }).refine((value) => value.eventKind !== "credit" || value.adjustmentId !== void 0, { path: ["adjustmentId"], message: "Credit requires a unique adjustment ID" });
|
|
27825
|
-
var UsageCountersSchema = external_exports.object({
|
|
27826
|
-
protocolVersion: external_exports.literal(protocolVersion),
|
|
27827
|
-
tenantId: uuid14,
|
|
27828
|
-
periodStartUtc: utcDateTime2,
|
|
27829
|
-
periodEndUtc: utcDateTime2,
|
|
27830
|
-
limitUnits: units,
|
|
27831
|
-
reservedUnits: units,
|
|
27832
|
-
consumedUnits: units,
|
|
27833
|
-
creditedUnits: units
|
|
27834
|
-
}).strict().refine(validUsagePeriod, { path: ["periodEndUtc"], message: "Expected one UTC calendar month" });
|
|
27835
|
-
var OperationErrorSchema = external_exports.object({
|
|
27836
|
-
protocolVersion: external_exports.literal(protocolVersion),
|
|
27837
|
-
code: ErrorCodeSchema,
|
|
27838
|
-
message: external_exports.string().trim().min(1).max(512),
|
|
27839
|
-
retryable: external_exports.boolean(),
|
|
27840
|
-
dispatched: external_exports.boolean(),
|
|
27841
|
-
quotaEffect: external_exports.enum(["none", "reserved", "charged", "released", "credited", "unknown"])
|
|
27842
|
-
}).strict();
|
|
27843
|
-
|
|
27844
28064
|
// agent/src/relay-client.ts
|
|
27845
28065
|
var RelayClientError = class extends Error {
|
|
27846
28066
|
constructor(code) {
|
|
@@ -27853,7 +28073,7 @@ var RelayClientError = class extends Error {
|
|
|
27853
28073
|
var DEFAULT_PROTOCOL_VERSION = 1;
|
|
27854
28074
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
27855
28075
|
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
27856
|
-
var DEFAULT_MAX_FRAME_BYTES =
|
|
28076
|
+
var DEFAULT_MAX_FRAME_BYTES = MAX_RELAY_FRAME_BYTES;
|
|
27857
28077
|
var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
27858
28078
|
var EPOCH = /^[1-9]\d{0,18}$/;
|
|
27859
28079
|
var AGENT_VERSION = /^[A-Za-z0-9._+-]{1,64}$/;
|
|
@@ -27876,7 +28096,7 @@ function relayUrlFromEnrollment(enrollment) {
|
|
|
27876
28096
|
url2.pathname = "/api/agent/relay";
|
|
27877
28097
|
return url2.toString();
|
|
27878
28098
|
}
|
|
27879
|
-
function
|
|
28099
|
+
function uuid16(value, code) {
|
|
27880
28100
|
if (typeof value !== "string" || !UUID2.test(value)) fail3(code);
|
|
27881
28101
|
return value.toLowerCase();
|
|
27882
28102
|
}
|
|
@@ -28006,37 +28226,37 @@ function sendJson(socket, value, maxBytes) {
|
|
|
28006
28226
|
function validateChallenge(frame, expectedProtocol) {
|
|
28007
28227
|
if (frame.type !== "challenge") fail3("RELAY_HANDSHAKE_INVALID");
|
|
28008
28228
|
protocol(frame.protocolVersion, expectedProtocol);
|
|
28009
|
-
|
|
28229
|
+
uuid16(frame.gatewayId, "RELAY_HANDSHAKE_INVALID");
|
|
28010
28230
|
if (typeof frame.nonce !== "string" || frame.nonce.length < 32 || frame.nonce.length > 512 || /[\u0000-\u001f\u007f]/u.test(frame.nonce)) fail3("RELAY_HANDSHAKE_INVALID");
|
|
28011
28231
|
if (typeof frame.expiresAt !== "string" || !Number.isFinite(Date.parse(frame.expiresAt)) || Date.parse(frame.expiresAt) <= Date.now()) fail3("RELAY_HANDSHAKE_INVALID");
|
|
28012
28232
|
return {
|
|
28013
|
-
challengeId:
|
|
28233
|
+
challengeId: uuid16(frame.challengeId, "RELAY_HANDSHAKE_INVALID"),
|
|
28014
28234
|
nonce: frame.nonce
|
|
28015
28235
|
};
|
|
28016
28236
|
}
|
|
28017
28237
|
function validateReady(frame, enrollment, expectedProtocol) {
|
|
28018
28238
|
if (frame.type !== "connected") fail3("RELAY_HANDSHAKE_INVALID");
|
|
28019
28239
|
protocol(frame.protocolVersion, expectedProtocol);
|
|
28020
|
-
if (
|
|
28021
|
-
if (
|
|
28240
|
+
if (uuid16(frame.tenantId, "RELAY_HANDSHAKE_INVALID") !== enrollment.tenantId.toLowerCase()) fail3("RELAY_ID_MISMATCH");
|
|
28241
|
+
if (uuid16(frame.deviceId, "RELAY_HANDSHAKE_INVALID") !== enrollment.deviceId.toLowerCase()) fail3("RELAY_ID_MISMATCH");
|
|
28022
28242
|
return epoch2(frame.connectionEpoch);
|
|
28023
28243
|
}
|
|
28024
28244
|
function validateRequest(frame, enrollment, expectedProtocol, connectionEpoch) {
|
|
28025
28245
|
if (frame.type !== "relayFrame") fail3("RELAY_REQUEST_INVALID");
|
|
28026
28246
|
protocol(frame.protocolVersion, expectedProtocol);
|
|
28027
|
-
const tenantId =
|
|
28028
|
-
const deviceId =
|
|
28247
|
+
const tenantId = uuid16(frame.tenantId, "RELAY_REQUEST_INVALID");
|
|
28248
|
+
const deviceId = uuid16(frame.deviceId, "RELAY_REQUEST_INVALID");
|
|
28029
28249
|
if (tenantId !== enrollment.tenantId.toLowerCase() || deviceId !== enrollment.deviceId.toLowerCase()) fail3("RELAY_ID_MISMATCH");
|
|
28030
28250
|
if (epoch2(frame.connectionEpoch) !== connectionEpoch) fail3("RELAY_EPOCH_MISMATCH");
|
|
28031
28251
|
const kind = frame.kind;
|
|
28032
28252
|
if (typeof kind !== "string" || !REQUEST_KINDS.has(kind)) fail3("RELAY_REQUEST_INVALID");
|
|
28033
28253
|
return {
|
|
28034
|
-
requestId:
|
|
28254
|
+
requestId: uuid16(frame.requestId, "RELAY_REQUEST_INVALID"),
|
|
28035
28255
|
tenantId,
|
|
28036
28256
|
deviceId,
|
|
28037
28257
|
connectionEpoch,
|
|
28038
|
-
operationId:
|
|
28039
|
-
executionId:
|
|
28258
|
+
operationId: uuid16(frame.operationId, "RELAY_REQUEST_INVALID"),
|
|
28259
|
+
executionId: uuid16(frame.executionId, "RELAY_REQUEST_INVALID"),
|
|
28040
28260
|
kind,
|
|
28041
28261
|
payload: frame.payload,
|
|
28042
28262
|
deadlineAt: isoDate(frame.deadlineAt)
|
|
@@ -28070,14 +28290,14 @@ async function connectOnce(options) {
|
|
|
28070
28290
|
if (!Number.isInteger(protocolVersion2) || protocolVersion2 < 1 || protocolVersion2 > 100) fail3("RELAY_PROTOCOL_INVALID");
|
|
28071
28291
|
const connectTimeoutMs = boundedNumber(options.connectTimeoutMs, DEFAULT_CONNECT_TIMEOUT_MS, 100, 6e4, "CONNECT_TIMEOUT_INVALID");
|
|
28072
28292
|
const requestTimeoutMs = boundedNumber(options.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS, 100, 30 * 6e4, "REQUEST_TIMEOUT_INVALID");
|
|
28073
|
-
const maxFrameBytes = boundedNumber(options.maxFrameBytes, DEFAULT_MAX_FRAME_BYTES, 1024,
|
|
28293
|
+
const maxFrameBytes = boundedNumber(options.maxFrameBytes, DEFAULT_MAX_FRAME_BYTES, 1024, MAX_RELAY_FRAME_BYTES, "FRAME_LIMIT_INVALID");
|
|
28074
28294
|
agentVersion(options.agentVersion);
|
|
28075
28295
|
if (typeof options.handleRequest !== "function") fail3("HANDLER_INVALID");
|
|
28076
28296
|
const identity = await options.store.load();
|
|
28077
28297
|
if (!identity || !identity.enrollment) fail3("ENROLLMENT_MISSING");
|
|
28078
28298
|
const enrollment = identity.enrollment;
|
|
28079
|
-
const tenantId =
|
|
28080
|
-
const deviceId =
|
|
28299
|
+
const tenantId = uuid16(enrollment.tenantId, "ENROLLMENT_INVALID");
|
|
28300
|
+
const deviceId = uuid16(enrollment.deviceId, "ENROLLMENT_INVALID");
|
|
28081
28301
|
const url2 = relayUrlFromEnrollment(enrollment);
|
|
28082
28302
|
const socket = new wrapper_default(url2, [], {
|
|
28083
28303
|
followRedirects: false,
|
|
@@ -28297,10 +28517,10 @@ function canonicalOrigin2(value) {
|
|
|
28297
28517
|
fail4("ORIGIN_INVALID");
|
|
28298
28518
|
}
|
|
28299
28519
|
}
|
|
28300
|
-
function endpoint(origin,
|
|
28301
|
-
return origin +
|
|
28520
|
+
function endpoint(origin, path13) {
|
|
28521
|
+
return origin + path13;
|
|
28302
28522
|
}
|
|
28303
|
-
function
|
|
28523
|
+
function uuid17(value, code) {
|
|
28304
28524
|
if (typeof value !== "string" || !UUID3.test(value)) fail4(code);
|
|
28305
28525
|
return value.toLowerCase();
|
|
28306
28526
|
}
|
|
@@ -28420,7 +28640,7 @@ var PairingClient = class {
|
|
|
28420
28640
|
publicKey: identity.publicKeyPem,
|
|
28421
28641
|
agentVersion: this.version
|
|
28422
28642
|
}));
|
|
28423
|
-
const pairingId =
|
|
28643
|
+
const pairingId = uuid17(response.pairingId, "PAIRING_RESPONSE_INVALID");
|
|
28424
28644
|
const expiresAt = parseDate(response.expiresAt, "PAIRING_RESPONSE_INVALID");
|
|
28425
28645
|
const now = this.nowMs();
|
|
28426
28646
|
if (expiresAt.getTime() <= now || expiresAt.getTime() - now > 30 * 6e4) fail4("PAIRING_RESPONSE_INVALID");
|
|
@@ -28454,9 +28674,9 @@ var PairingClient = class {
|
|
|
28454
28674
|
}
|
|
28455
28675
|
async completeOnce(beginResult, approved, displayNameValue) {
|
|
28456
28676
|
const pairing = this.validateBeginResult(beginResult);
|
|
28457
|
-
const tenantId =
|
|
28677
|
+
const tenantId = uuid17(approved.tenantId, "PAIRING_RESPONSE_INVALID");
|
|
28458
28678
|
const email3 = accountEmail(approved.accountEmail);
|
|
28459
|
-
const
|
|
28679
|
+
const name2 = displayName(displayNameValue);
|
|
28460
28680
|
const identity = await this.currentIdentity();
|
|
28461
28681
|
const keyFingerprint = fingerprint2(identity.fingerprint);
|
|
28462
28682
|
if (keyFingerprint !== pairing.keyFingerprint) fail4("IDENTITY_CHANGED");
|
|
@@ -28465,18 +28685,18 @@ var PairingClient = class {
|
|
|
28465
28685
|
const response = assertJsonObject(await this.request(endpoint(this.origin, "/api/agent/pairings/" + pairing.pairingId + "/complete"), {
|
|
28466
28686
|
pairingSecret: pairing.pairingSecret,
|
|
28467
28687
|
signature,
|
|
28468
|
-
displayName:
|
|
28688
|
+
displayName: name2,
|
|
28469
28689
|
agentVersion: this.version
|
|
28470
28690
|
}));
|
|
28471
|
-
const completedTenant =
|
|
28691
|
+
const completedTenant = uuid17(response.tenantId, "PAIRING_RESPONSE_INVALID");
|
|
28472
28692
|
if (completedTenant !== tenantId) fail4("PAIRING_RESPONSE_INVALID");
|
|
28473
|
-
const deviceId =
|
|
28693
|
+
const deviceId = uuid17(response.deviceId, "PAIRING_RESPONSE_INVALID");
|
|
28474
28694
|
const enrollment = {
|
|
28475
28695
|
tenantId,
|
|
28476
28696
|
deviceId,
|
|
28477
28697
|
serverOrigin: this.origin,
|
|
28478
28698
|
accountEmail: email3,
|
|
28479
|
-
...response.accountId !== void 0 ? { accountId:
|
|
28699
|
+
...response.accountId !== void 0 ? { accountId: uuid17(response.accountId, "PAIRING_RESPONSE_INVALID") } : {}
|
|
28480
28700
|
};
|
|
28481
28701
|
await this.store.saveEnrollment(enrollment);
|
|
28482
28702
|
return { ...enrollment };
|
|
@@ -28490,7 +28710,7 @@ var PairingClient = class {
|
|
|
28490
28710
|
state: response.state,
|
|
28491
28711
|
expiresAt: parseDate(response.expiresAt, "PAIRING_RESPONSE_INVALID")
|
|
28492
28712
|
};
|
|
28493
|
-
if (response.tenantId !== void 0) result2.tenantId =
|
|
28713
|
+
if (response.tenantId !== void 0) result2.tenantId = uuid17(response.tenantId, "PAIRING_RESPONSE_INVALID");
|
|
28494
28714
|
if (response.accountEmail !== void 0) result2.accountEmail = accountEmail(response.accountEmail);
|
|
28495
28715
|
return result2;
|
|
28496
28716
|
}
|
|
@@ -28502,10 +28722,10 @@ var PairingClient = class {
|
|
|
28502
28722
|
}
|
|
28503
28723
|
validateBeginResult(value) {
|
|
28504
28724
|
return {
|
|
28505
|
-
pairingId:
|
|
28725
|
+
pairingId: uuid17(value.pairingId, "PAIRING_INVALID"),
|
|
28506
28726
|
pairingSecret: pairingSecret(value.pairingSecret),
|
|
28507
28727
|
confirmationCode: confirmationCode(value.confirmationCode),
|
|
28508
|
-
approvalUrl: approvalUrl(value.approvalUrl, this.origin,
|
|
28728
|
+
approvalUrl: approvalUrl(value.approvalUrl, this.origin, uuid17(value.pairingId, "PAIRING_INVALID")),
|
|
28509
28729
|
expiresAt: value.expiresAt instanceof Date ? new Date(value.expiresAt.getTime()) : parseDate(value.expiresAt, "PAIRING_INVALID"),
|
|
28510
28730
|
keyFingerprint: fingerprint2(value.keyFingerprint)
|
|
28511
28731
|
};
|
|
@@ -28800,30 +29020,30 @@ async function deliverGuardEvidence(target, packet, options = {}) {
|
|
|
28800
29020
|
|
|
28801
29021
|
// agent/src/optimization-ledger.ts
|
|
28802
29022
|
import { constants as constants4 } from "node:fs";
|
|
28803
|
-
import { lstat as
|
|
28804
|
-
import
|
|
29023
|
+
import { lstat as lstat6, mkdir as mkdir4, open as open5, readFile as readFile4, realpath as realpath6 } from "node:fs/promises";
|
|
29024
|
+
import path11 from "node:path";
|
|
28805
29025
|
var MAX_LEDGER_BYTES = 64 * 1024 * 1024;
|
|
28806
29026
|
var MAX_NOTICE_LEDGER_BYTES = 8 * 1024 * 1024;
|
|
28807
29027
|
function failure4(code) {
|
|
28808
29028
|
return Object.assign(new Error(code), { code });
|
|
28809
29029
|
}
|
|
28810
29030
|
async function safeDirectory2(directory) {
|
|
28811
|
-
const absolute2 =
|
|
29031
|
+
const absolute2 = path11.resolve(directory);
|
|
28812
29032
|
let current2 = absolute2;
|
|
28813
29033
|
for (; ; ) {
|
|
28814
29034
|
try {
|
|
28815
|
-
if ((await
|
|
29035
|
+
if ((await lstat6(current2)).isSymbolicLink()) throw failure4("OPTIMIZATION_LEDGER_DIRECTORY_INVALID");
|
|
28816
29036
|
} catch (error62) {
|
|
28817
29037
|
if (error62.code !== "ENOENT") throw error62;
|
|
28818
29038
|
}
|
|
28819
|
-
const parent =
|
|
29039
|
+
const parent = path11.dirname(current2);
|
|
28820
29040
|
if (parent === current2) break;
|
|
28821
29041
|
current2 = parent;
|
|
28822
29042
|
}
|
|
28823
29043
|
await mkdir4(absolute2, { recursive: true, mode: 448 });
|
|
28824
|
-
const stat = await
|
|
29044
|
+
const stat = await lstat6(absolute2);
|
|
28825
29045
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw failure4("OPTIMIZATION_LEDGER_DIRECTORY_INVALID");
|
|
28826
|
-
return
|
|
29046
|
+
return realpath6(absolute2);
|
|
28827
29047
|
}
|
|
28828
29048
|
var OptimizationLedger = class _OptimizationLedger {
|
|
28829
29049
|
constructor(filename, handle, noticesFilename) {
|
|
@@ -28841,11 +29061,11 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
28841
29061
|
closed = false;
|
|
28842
29062
|
static async open(directory) {
|
|
28843
29063
|
const dir = await safeDirectory2(directory);
|
|
28844
|
-
const filename =
|
|
28845
|
-
const noticesFilename =
|
|
29064
|
+
const filename = path11.join(dir, "live-efficiency.v1.jsonl");
|
|
29065
|
+
const noticesFilename = path11.join(dir, "live-efficiency-notices.v1.jsonl");
|
|
28846
29066
|
let existing = "";
|
|
28847
29067
|
try {
|
|
28848
|
-
const stat = await
|
|
29068
|
+
const stat = await lstat6(filename);
|
|
28849
29069
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_LEDGER_BYTES) {
|
|
28850
29070
|
throw failure4("OPTIMIZATION_LEDGER_INVALID");
|
|
28851
29071
|
}
|
|
@@ -28861,7 +29081,7 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
28861
29081
|
const ledger = new _OptimizationLedger(filename, handle, noticesFilename);
|
|
28862
29082
|
try {
|
|
28863
29083
|
try {
|
|
28864
|
-
const noticeStat = await
|
|
29084
|
+
const noticeStat = await lstat6(noticesFilename);
|
|
28865
29085
|
if (!noticeStat.isFile() || noticeStat.isSymbolicLink() || noticeStat.size > MAX_NOTICE_LEDGER_BYTES) throw failure4("OPTIMIZATION_NOTICE_LEDGER_INVALID");
|
|
28866
29086
|
const notices = await readFile4(noticesFilename, "utf8");
|
|
28867
29087
|
for (const line of notices.split("\n")) {
|
|
@@ -28928,7 +29148,7 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
28928
29148
|
const marker = JSON.stringify({ sessionId: event.sessionId, checkpointCalls, deliveredAt: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
|
|
28929
29149
|
let currentBytes = 0;
|
|
28930
29150
|
try {
|
|
28931
|
-
const stat = await
|
|
29151
|
+
const stat = await lstat6(this.noticesFilename);
|
|
28932
29152
|
if (!stat.isFile() || stat.isSymbolicLink()) throw failure4("OPTIMIZATION_NOTICE_LEDGER_INVALID");
|
|
28933
29153
|
currentBytes = stat.size;
|
|
28934
29154
|
} catch (error62) {
|
|
@@ -28975,7 +29195,7 @@ var OptimizationLedger = class _OptimizationLedger {
|
|
|
28975
29195
|
};
|
|
28976
29196
|
|
|
28977
29197
|
// agent/src/main.ts
|
|
28978
|
-
var AGENT_VERSION2 = true ? "0.3.
|
|
29198
|
+
var AGENT_VERSION2 = true ? "0.3.4" : "0.3.2";
|
|
28979
29199
|
function processAlive(pid) {
|
|
28980
29200
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
28981
29201
|
try {
|
|
@@ -28987,7 +29207,7 @@ function processAlive(pid) {
|
|
|
28987
29207
|
}
|
|
28988
29208
|
async function claimAgentProcess(stateDir, runtimeDir, version2) {
|
|
28989
29209
|
await mkdir5(stateDir, { recursive: true });
|
|
28990
|
-
const file2 =
|
|
29210
|
+
const file2 = path12.join(stateDir, "agent-process.json");
|
|
28991
29211
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
28992
29212
|
try {
|
|
28993
29213
|
const handle = await open6(file2, "wx", 384);
|
|
@@ -29098,10 +29318,10 @@ async function runAgent(options) {
|
|
|
29098
29318
|
async function main() {
|
|
29099
29319
|
if (process.platform !== "win32") throw Error("WINDOWS_REQUIRED");
|
|
29100
29320
|
const appData = process.env.LOCALAPPDATA;
|
|
29101
|
-
if (!appData || !
|
|
29102
|
-
const stateDir = process.env.LC_AGENT_STATE_DIR ??
|
|
29103
|
-
const binaryDir =
|
|
29104
|
-
const ownerBridgePath = process.env.LC_OWNER_BRIDGE ??
|
|
29321
|
+
if (!appData || !path12.isAbsolute(appData)) throw Error("APP_DATA_MISSING");
|
|
29322
|
+
const stateDir = process.env.LC_AGENT_STATE_DIR ?? path12.join(appData, "LocalCommander", "Agent");
|
|
29323
|
+
const binaryDir = path12.dirname(process.execPath);
|
|
29324
|
+
const ownerBridgePath = process.env.LC_OWNER_BRIDGE ?? path12.join(binaryDir, "OwnerBridge.exe");
|
|
29105
29325
|
const store = await WindowsPrivateStore.open(stateDir, ownerBridgePath);
|
|
29106
29326
|
const command = process.argv[2] ?? "run";
|
|
29107
29327
|
if (command === "pair") {
|
|
@@ -29123,18 +29343,33 @@ async function main() {
|
|
|
29123
29343
|
}) + "\n");
|
|
29124
29344
|
return;
|
|
29125
29345
|
}
|
|
29346
|
+
if (command === "configure-access") {
|
|
29347
|
+
if (process.argv.length !== 3) throw Error("AGENT_COMMAND_INVALID");
|
|
29348
|
+
process.stdout.write(await store.configureAccess() ? "ACCESS_CONFIGURED\n" : "ACCESS_CANCELLED\n");
|
|
29349
|
+
return;
|
|
29350
|
+
}
|
|
29126
29351
|
if (command === "approve-workspace") {
|
|
29127
29352
|
process.stdout.write(await store.approveWorkspace() ? "WORKSPACE_APPROVED\n" : "WORKSPACE_CANCELLED\n");
|
|
29128
29353
|
return;
|
|
29129
29354
|
}
|
|
29130
29355
|
if (command === "list-workspaces") {
|
|
29131
|
-
|
|
29356
|
+
const programs = await store.loadPrograms(), history = await store.loadPermissionHistory();
|
|
29357
|
+
process.stdout.write(JSON.stringify((await store.loadWorkspaces()).map((w) => ({
|
|
29358
|
+
workspaceGrantId: w.workspaceGrantId,
|
|
29359
|
+
displayName: w.displayName,
|
|
29360
|
+
path: w.root,
|
|
29361
|
+
permissions: w.permissions,
|
|
29362
|
+
allowedCommands: w.allowedCommands,
|
|
29363
|
+
executables: Object.fromEntries(w.allowedCommands.map((name2) => [name2, programs[name2]?.executable ?? null])),
|
|
29364
|
+
localhostPorts: w.localhostPorts,
|
|
29365
|
+
permissionHistory: history.filter((entry) => entry.workspaceGrantId === w.workspaceGrantId)
|
|
29366
|
+
}))) + "\n");
|
|
29132
29367
|
return;
|
|
29133
29368
|
}
|
|
29134
29369
|
const args = process.argv.slice(3);
|
|
29135
29370
|
if (command === "efficiency-report") {
|
|
29136
29371
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
29137
|
-
const ledger = await OptimizationLedger.open(
|
|
29372
|
+
const ledger = await OptimizationLedger.open(path12.join(stateDir, "optimization"));
|
|
29138
29373
|
try {
|
|
29139
29374
|
process.stdout.write(JSON.stringify(await ledger.report(), null, 2) + "\n");
|
|
29140
29375
|
} finally {
|
|
@@ -29144,7 +29379,7 @@ async function main() {
|
|
|
29144
29379
|
}
|
|
29145
29380
|
if (command === "guard-configure") {
|
|
29146
29381
|
if (args.length !== 1) throw Error("AGENT_COMMAND_INVALID");
|
|
29147
|
-
const filename = await (await import("node:fs/promises")).realpath(
|
|
29382
|
+
const filename = await (await import("node:fs/promises")).realpath(path12.resolve(args[0]));
|
|
29148
29383
|
const input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readWindowsFile(ownerBridgePath, filename, 2e5)));
|
|
29149
29384
|
if (!input2 || typeof input2 !== "object" || Object.keys(input2).sort().join(",") !== "compact,settings") throw Error("GUARD_CONFIGURATION_INVALID");
|
|
29150
29385
|
await store.configureGuard(input2.settings, input2.compact);
|
|
@@ -29163,7 +29398,7 @@ async function main() {
|
|
|
29163
29398
|
}
|
|
29164
29399
|
if (command === "guard-evidence") {
|
|
29165
29400
|
if (args.length) throw Error("AGENT_COMMAND_INVALID");
|
|
29166
|
-
const journal = await NativeJournal.open(
|
|
29401
|
+
const journal = await NativeJournal.open(path12.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
29167
29402
|
try {
|
|
29168
29403
|
process.stdout.write(JSON.stringify(await journal.guardEvidence()) + "\n");
|
|
29169
29404
|
} finally {
|
|
@@ -29175,7 +29410,7 @@ async function main() {
|
|
|
29175
29410
|
if (args.length !== (command === "guard-export" ? 0 : 1)) throw Error("AGENT_COMMAND_INVALID");
|
|
29176
29411
|
const identity = await store.load();
|
|
29177
29412
|
if (!identity?.enrollment) throw Error("ENROLLMENT_MISSING");
|
|
29178
|
-
const journal = await NativeJournal.open(
|
|
29413
|
+
const journal = await NativeJournal.open(path12.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
29179
29414
|
try {
|
|
29180
29415
|
const { tenantId, deviceId } = identity.enrollment;
|
|
29181
29416
|
const records = (await journal.guardEvidence()).filter((record2) => record2.tenantId === tenantId && record2.deviceId === deviceId);
|
|
@@ -29214,10 +29449,10 @@ async function main() {
|
|
|
29214
29449
|
if (!(await store.load())?.enrollment) throw Error("ENROLLMENT_MISSING");
|
|
29215
29450
|
const releaseProcess = await claimAgentProcess(stateDir, binaryDir, AGENT_VERSION2);
|
|
29216
29451
|
try {
|
|
29217
|
-
const journal = await NativeJournal.open(
|
|
29218
|
-
const efficiencyLedger = await OptimizationLedger.open(
|
|
29452
|
+
const journal = await NativeJournal.open(path12.join(stateDir, "journal"), new SecretBox({ "1": await store.loadDataKey() }));
|
|
29453
|
+
const efficiencyLedger = await OptimizationLedger.open(path12.join(stateDir, "optimization"));
|
|
29219
29454
|
try {
|
|
29220
|
-
const tools = new NativeTools({ stateDirectory: stateDir, helperPath: process.env.LC_JOB_HOST ??
|
|
29455
|
+
const tools = new NativeTools({ stateDirectory: stateDir, helperPath: process.env.LC_JOB_HOST ?? path12.join(binaryDir, "JobHost.exe"), ownerBridgePath, programs: await store.loadPrograms() });
|
|
29221
29456
|
const stop = new AbortController();
|
|
29222
29457
|
process.once("SIGINT", () => stop.abort());
|
|
29223
29458
|
process.once("SIGTERM", () => stop.abort());
|
|
@@ -29231,7 +29466,7 @@ async function main() {
|
|
|
29231
29466
|
await releaseProcess();
|
|
29232
29467
|
}
|
|
29233
29468
|
}
|
|
29234
|
-
if (process.argv[1] &&
|
|
29469
|
+
if (process.argv[1] && path12.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
29235
29470
|
void main().catch((error62) => {
|
|
29236
29471
|
const code = error62 instanceof Error && /^[A-Z0-9_]{1,64}$/.test(error62.message) ? error62.message : "AGENT_START_FAILED";
|
|
29237
29472
|
process.stderr.write(code + "\n");
|