@node9/proxy 2.49.0 → 2.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-main.js +928 -480
- package/dist/dashboard.mjs +72 -27
- package/dist/hook.js +20 -13
- package/dist/index.js +7 -4
- package/dist/index.mjs +7 -4
- package/dist/scan-ink.mjs +4 -3
- package/package.json +2 -2
package/dist/cli-main.js
CHANGED
|
@@ -520,6 +520,9 @@ function levelChecks(mode) {
|
|
|
520
520
|
function levelPackageSignals(mode) {
|
|
521
521
|
return levelOf(mode) === "soft" ? { newPackage: "off", installScript: "off" } : void 0;
|
|
522
522
|
}
|
|
523
|
+
function isAsiId(v) {
|
|
524
|
+
return typeof v === "string" && Object.prototype.hasOwnProperty.call(ASI, v);
|
|
525
|
+
}
|
|
523
526
|
function packRowOwasp(id, shield) {
|
|
524
527
|
return PACK_RULE_OWASP[id] ?? PACK_SHIELD_OWASP[shield];
|
|
525
528
|
}
|
|
@@ -542,12 +545,13 @@ function packRows() {
|
|
|
542
545
|
if (!rule.name || SHIELD_RULES_FOLDED_INTO_PRODUCT[rule.name]) continue;
|
|
543
546
|
const id = packRowId(shield.name, rule.name);
|
|
544
547
|
if (!id) continue;
|
|
545
|
-
const owasp = packRowOwasp(id, shield.name);
|
|
546
|
-
if (!owasp) throw new Error(`pack row ${id} has no OWASP risk: add the shield to owasp.ts`);
|
|
547
548
|
rows.push({
|
|
548
549
|
id,
|
|
549
550
|
group: "commands",
|
|
550
|
-
|
|
551
|
+
// A shield missing from the table falls back to tool misuse instead of
|
|
552
|
+
// throwing here: this module loads on every hook call, and a mapping
|
|
553
|
+
// omission must fail a test (owasp.spec.ts), never the gate.
|
|
554
|
+
owasp: packRowOwasp(id, shield.name) ?? "ASI02",
|
|
551
555
|
title: rule.name.replace(SHIELD_RULE_NAME, "$3").replace(/-/g, " "),
|
|
552
556
|
catches: rule.description ?? rule.reason ?? "",
|
|
553
557
|
values: ALL,
|
|
@@ -19924,8 +19928,8 @@ var init_audit = __esm({
|
|
|
19924
19928
|
// src/config-schema.ts
|
|
19925
19929
|
function formatIssues(issues) {
|
|
19926
19930
|
const lines = issues.map((issue) => {
|
|
19927
|
-
const
|
|
19928
|
-
return ` \u2022 ${
|
|
19931
|
+
const path114 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
19932
|
+
return ` \u2022 ${path114}: ${issue.message}`;
|
|
19929
19933
|
});
|
|
19930
19934
|
return `Invalid config:
|
|
19931
19935
|
${lines.join("\n")}`;
|
|
@@ -19938,9 +19942,9 @@ function prunePaths(root, paths) {
|
|
|
19938
19942
|
const yi = y[y.length - 1];
|
|
19939
19943
|
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
19940
19944
|
});
|
|
19941
|
-
for (const
|
|
19945
|
+
for (const path114 of ordered) {
|
|
19942
19946
|
let cur = root;
|
|
19943
|
-
for (const key of
|
|
19947
|
+
for (const key of path114.slice(0, -1)) {
|
|
19944
19948
|
if (cur === null || typeof cur !== "object") {
|
|
19945
19949
|
cur = void 0;
|
|
19946
19950
|
break;
|
|
@@ -19948,7 +19952,7 @@ function prunePaths(root, paths) {
|
|
|
19948
19952
|
cur = cur[key];
|
|
19949
19953
|
}
|
|
19950
19954
|
if (cur === null || typeof cur !== "object") continue;
|
|
19951
|
-
const last =
|
|
19955
|
+
const last = path114[path114.length - 1];
|
|
19952
19956
|
if (Array.isArray(cur)) {
|
|
19953
19957
|
const i = Number(last);
|
|
19954
19958
|
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
@@ -19984,7 +19988,7 @@ function sanitizeConfig(raw) {
|
|
|
19984
19988
|
return issue.keys.map((k) => [...at, k]);
|
|
19985
19989
|
}
|
|
19986
19990
|
return [at.slice(0, -level || void 0)];
|
|
19987
|
-
}).filter((
|
|
19991
|
+
}).filter((path114) => path114.length > 0);
|
|
19988
19992
|
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
19989
19993
|
}
|
|
19990
19994
|
if (ConfigFileSchema.safeParse(working).success) break;
|
|
@@ -21578,13 +21582,13 @@ function getConfig(cwd) {
|
|
|
21578
21582
|
}
|
|
21579
21583
|
if (Array.isArray(mc.jailPaths)) {
|
|
21580
21584
|
for (const jp of mc.jailPaths) {
|
|
21581
|
-
const
|
|
21582
|
-
if (!
|
|
21585
|
+
const path114 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
21586
|
+
if (!path114) continue;
|
|
21583
21587
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
21584
|
-
for (const r of pathRules(
|
|
21588
|
+
for (const r of pathRules(path114, verdict, "org-managed jail")) {
|
|
21585
21589
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
21586
21590
|
}
|
|
21587
|
-
mergedPolicy.managedJailPaths.push({ path:
|
|
21591
|
+
mergedPolicy.managedJailPaths.push({ path: path114, verdict });
|
|
21588
21592
|
}
|
|
21589
21593
|
}
|
|
21590
21594
|
if (Array.isArray(mc.trustedHosts)) {
|
|
@@ -24527,13 +24531,15 @@ function privateDir(dir2) {
|
|
|
24527
24531
|
}
|
|
24528
24532
|
return isPrivateDir(dir2);
|
|
24529
24533
|
}
|
|
24534
|
+
function perHomeRuntimeDir(env, home) {
|
|
24535
|
+
const xdg = env.XDG_RUNTIME_DIR;
|
|
24536
|
+
if (!xdg || !import_path16.default.isAbsolute(xdg)) return null;
|
|
24537
|
+
return import_path16.default.join(xdg, `node9-${(0, import_crypto10.createHash)("sha256").update(home).digest("hex").slice(0, 12)}`);
|
|
24538
|
+
}
|
|
24530
24539
|
function chooseActivitySocketPath(env, home, platform = process.platform) {
|
|
24531
24540
|
const candidates2 = [];
|
|
24532
|
-
const
|
|
24533
|
-
if (
|
|
24534
|
-
candidates2.push(
|
|
24535
|
-
import_path16.default.join(xdg, `node9-${(0, import_crypto10.createHash)("sha256").update(home).digest("hex").slice(0, 12)}`)
|
|
24536
|
-
);
|
|
24541
|
+
const xdgDir = perHomeRuntimeDir(env, home);
|
|
24542
|
+
if (xdgDir && isPrivateDir(import_path16.default.dirname(xdgDir))) candidates2.push(xdgDir);
|
|
24537
24543
|
candidates2.push(import_path16.default.join(home, ".node9", "run"));
|
|
24538
24544
|
for (const dir2 of candidates2) {
|
|
24539
24545
|
const socketPath = import_path16.default.join(dir2, SOCKET_NAME);
|
|
@@ -24568,6 +24574,19 @@ function isOwnStaleSocket(socketPath) {
|
|
|
24568
24574
|
return false;
|
|
24569
24575
|
}
|
|
24570
24576
|
}
|
|
24577
|
+
function removeOwnSocketDir(socketPath, env, home, platform = process.platform) {
|
|
24578
|
+
if (platform === "win32") return false;
|
|
24579
|
+
const dir2 = import_path16.default.dirname(socketPath);
|
|
24580
|
+
if (dir2 !== perHomeRuntimeDir(env, home)) return false;
|
|
24581
|
+
if (!isPrivateDir(dir2)) return false;
|
|
24582
|
+
try {
|
|
24583
|
+
if (import_fs16.default.readdirSync(dir2).length > 0) return false;
|
|
24584
|
+
import_fs16.default.rmdirSync(dir2);
|
|
24585
|
+
return true;
|
|
24586
|
+
} catch {
|
|
24587
|
+
return false;
|
|
24588
|
+
}
|
|
24589
|
+
}
|
|
24571
24590
|
var import_fs16, import_path16, import_crypto10, SOCKET_NAME, currentUid, WINDOWS_PIPE;
|
|
24572
24591
|
var init_activity_socket = __esm({
|
|
24573
24592
|
"src/utils/activity-socket.ts"() {
|
|
@@ -28457,7 +28476,9 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
28457
28476
|
systemAccessHandled: !isManual && fileAccess.handledPaths.has(filePath)
|
|
28458
28477
|
}) : null) ?? argumentScan(),
|
|
28459
28478
|
pii: () => detectArgsPii(args),
|
|
28460
|
-
packageCheck: () => packageCheck?.enabled && !isManual ? runPackageCheck(toolName, args, packageCheck, options?.cwd, {
|
|
28479
|
+
packageCheck: () => packageCheck?.enabled && !isManual ? runPackageCheck(toolName, args, packageCheck, options?.cwd, {
|
|
28480
|
+
offline: !!forecast && forecast.onlinePackages !== true
|
|
28481
|
+
}) : Promise.resolve(null)
|
|
28461
28482
|
});
|
|
28462
28483
|
const dlpMatch = gates.stop?.dlpMatch ?? gates.reviews.dlp ?? null;
|
|
28463
28484
|
if (dlpMatch) {
|
|
@@ -34065,7 +34086,8 @@ async function forecastDecision(toolName, args, meta, opts = {}) {
|
|
|
34065
34086
|
session,
|
|
34066
34087
|
config,
|
|
34067
34088
|
unknown: /* @__PURE__ */ new Set(),
|
|
34068
|
-
now: opts.at ?? Date.now()
|
|
34089
|
+
now: opts.at ?? Date.now(),
|
|
34090
|
+
...opts.onlinePackages && { onlinePackages: true }
|
|
34069
34091
|
};
|
|
34070
34092
|
const result = await runForecast(
|
|
34071
34093
|
run,
|
|
@@ -34160,6 +34182,20 @@ var init_forecast = __esm({
|
|
|
34160
34182
|
}
|
|
34161
34183
|
});
|
|
34162
34184
|
|
|
34185
|
+
// src/exposure/shell-fetch.ts
|
|
34186
|
+
function shellFetch(tool, rawInput) {
|
|
34187
|
+
if (tool !== "Bash" && tool !== "bash") return null;
|
|
34188
|
+
const cmd = rawInput && typeof rawInput === "object" && !Array.isArray(rawInput) ? rawInput.command : void 0;
|
|
34189
|
+
return typeof cmd === "string" && cmd.length > 0 ? classifyShellExposure(cmd) : null;
|
|
34190
|
+
}
|
|
34191
|
+
var init_shell_fetch = __esm({
|
|
34192
|
+
"src/exposure/shell-fetch.ts"() {
|
|
34193
|
+
"use strict";
|
|
34194
|
+
init_cjs_shims();
|
|
34195
|
+
init_dist();
|
|
34196
|
+
}
|
|
34197
|
+
});
|
|
34198
|
+
|
|
34163
34199
|
// src/version.ts
|
|
34164
34200
|
function readVersion() {
|
|
34165
34201
|
let dir2 = __dirname;
|
|
@@ -34460,6 +34496,8 @@ var init_scan_judge = __esm({
|
|
|
34460
34496
|
init_forecast();
|
|
34461
34497
|
init_forecast_state();
|
|
34462
34498
|
init_roles();
|
|
34499
|
+
init_shell_fetch();
|
|
34500
|
+
init_dist();
|
|
34463
34501
|
init_scan_cache();
|
|
34464
34502
|
init_dlp();
|
|
34465
34503
|
import_fs45 = __toESM(require("fs"));
|
|
@@ -34534,16 +34572,26 @@ var init_scan_judge = __esm({
|
|
|
34534
34572
|
this.session(sessionId).noteOutputSecret(patternName, clockOf(timestamp2));
|
|
34535
34573
|
}
|
|
34536
34574
|
/** A tool that brings outside content returned something. */
|
|
34537
|
-
|
|
34575
|
+
/**
|
|
34576
|
+
* A tool result reached the session. A source read marks it exposed, as the
|
|
34577
|
+
* PostToolUse hook does (log.ts): a source tool, or a shell command that
|
|
34578
|
+
* fetches outside content (`gh issue view`). `read.output` is the result's
|
|
34579
|
+
* text: the destinations it names are recorded as the hook records them.
|
|
34580
|
+
*/
|
|
34581
|
+
noteToolResult(sessionId, toolName, timestamp2, cwd, read3 = {}) {
|
|
34538
34582
|
const policy = this.configFor(cwd).policy.untrustedContent;
|
|
34539
34583
|
if (!policy?.enabled) return;
|
|
34540
|
-
|
|
34584
|
+
const shell = shellFetch(toolName, read3.input);
|
|
34585
|
+
if (!toolRole(toolName, policy).source && !shell?.fetches) return;
|
|
34541
34586
|
const mcp = /^mcp__([^_]+(?:_[^_]+)*)__/.exec(toolName);
|
|
34542
|
-
this.session(sessionId).noteOutsideContent(
|
|
34543
|
-
|
|
34544
|
-
|
|
34545
|
-
|
|
34546
|
-
|
|
34587
|
+
this.session(sessionId).noteOutsideContent(
|
|
34588
|
+
{
|
|
34589
|
+
tool: toolName,
|
|
34590
|
+
...mcp && { server: mcp[1] },
|
|
34591
|
+
at: clockOf(timestamp2)
|
|
34592
|
+
},
|
|
34593
|
+
read3.output ? extractContentDestinations(read3.output) : []
|
|
34594
|
+
);
|
|
34547
34595
|
}
|
|
34548
34596
|
async judge(call, result, dedup) {
|
|
34549
34597
|
const config = this.configFor(call.cwd);
|
|
@@ -37034,8 +37082,8 @@ function isOfficialInstaller(u) {
|
|
|
37034
37082
|
if (u.username || u.password) return false;
|
|
37035
37083
|
const host2 = u.hostname.toLowerCase().replace(/^www\./, "");
|
|
37036
37084
|
if (OFFICIAL_HOSTS.has(host2)) return true;
|
|
37037
|
-
const
|
|
37038
|
-
return !!
|
|
37085
|
+
const path114 = OFFICIAL_PATHS[host2];
|
|
37086
|
+
return !!path114 && path114.test(u.pathname);
|
|
37039
37087
|
}
|
|
37040
37088
|
function onlyOfficialInstaller(s) {
|
|
37041
37089
|
const urls = s.match(URL_RE3);
|
|
@@ -37181,21 +37229,21 @@ function appSkillDirsOf(paths, skillDirs) {
|
|
|
37181
37229
|
}
|
|
37182
37230
|
return apps;
|
|
37183
37231
|
}
|
|
37184
|
-
function isSkillSupportFile(
|
|
37185
|
-
if (!
|
|
37186
|
-
for (let d =
|
|
37187
|
-
const dir2 =
|
|
37232
|
+
function isSkillSupportFile(path114, skillDirs, appDirs) {
|
|
37233
|
+
if (!path114.endsWith(".md") || /(^|\/)[Ss][Kk][Ii][Ll][Ll]\.md$/.test(path114)) return false;
|
|
37234
|
+
for (let d = path114.lastIndexOf("/"); d > 0; d = path114.lastIndexOf("/", d - 1)) {
|
|
37235
|
+
const dir2 = path114.slice(0, d);
|
|
37188
37236
|
if (!skillDirs.has(dir2)) continue;
|
|
37189
|
-
return !appDirs?.has(dir2) || SKILL_LAYOUT_RE.test(
|
|
37237
|
+
return !appDirs?.has(dir2) || SKILL_LAYOUT_RE.test(path114.slice(d + 1));
|
|
37190
37238
|
}
|
|
37191
37239
|
return false;
|
|
37192
37240
|
}
|
|
37193
|
-
function isAppDoc(
|
|
37194
|
-
if (!
|
|
37195
|
-
for (let d =
|
|
37196
|
-
const dir2 =
|
|
37241
|
+
function isAppDoc(path114, skillDirs, appDirs) {
|
|
37242
|
+
if (!path114.endsWith(".md") || INSTRUCTION_FILE_RE.test(path114)) return false;
|
|
37243
|
+
for (let d = path114.lastIndexOf("/"); d > 0; d = path114.lastIndexOf("/", d - 1)) {
|
|
37244
|
+
const dir2 = path114.slice(0, d);
|
|
37197
37245
|
if (!skillDirs.has(dir2)) continue;
|
|
37198
|
-
return appDirs.has(dir2) && !SKILL_LAYOUT_RE.test(
|
|
37246
|
+
return appDirs.has(dir2) && !SKILL_LAYOUT_RE.test(path114.slice(d + 1));
|
|
37199
37247
|
}
|
|
37200
37248
|
return false;
|
|
37201
37249
|
}
|
|
@@ -37217,20 +37265,20 @@ function namedDocs(dir2, skillMd) {
|
|
|
37217
37265
|
}
|
|
37218
37266
|
return out;
|
|
37219
37267
|
}
|
|
37220
|
-
function isHookScript(
|
|
37221
|
-
return /(^|\/)\.claude\/hooks\/.+/.test(
|
|
37268
|
+
function isHookScript(path114) {
|
|
37269
|
+
return /(^|\/)\.claude\/hooks\/.+/.test(path114) && SCRIPT_EXT_RE.test(path114);
|
|
37222
37270
|
}
|
|
37223
|
-
function isSkillScript(
|
|
37224
|
-
if (!SCRIPT_EXT_RE.test(
|
|
37225
|
-
for (let d =
|
|
37226
|
-
if (!skillDirs.has(
|
|
37227
|
-
const rel =
|
|
37271
|
+
function isSkillScript(path114, skillDirs) {
|
|
37272
|
+
if (!SCRIPT_EXT_RE.test(path114)) return false;
|
|
37273
|
+
for (let d = path114.lastIndexOf("/"); d > 0; d = path114.lastIndexOf("/", d - 1)) {
|
|
37274
|
+
if (!skillDirs.has(path114.slice(0, d))) continue;
|
|
37275
|
+
const rel = path114.slice(d + 1);
|
|
37228
37276
|
return !rel.includes("/") || /^(scripts|bin)\//.test(rel);
|
|
37229
37277
|
}
|
|
37230
37278
|
return false;
|
|
37231
37279
|
}
|
|
37232
|
-
function isInstructionFile(
|
|
37233
|
-
return INSTRUCTION_FILE_RE.test(
|
|
37280
|
+
function isInstructionFile(path114, skillDirs, appDirs) {
|
|
37281
|
+
return INSTRUCTION_FILE_RE.test(path114) || isSkillSupportFile(path114, skillDirs, appDirs);
|
|
37234
37282
|
}
|
|
37235
37283
|
function findFetchObeyUnless(text, skip) {
|
|
37236
37284
|
for (let start = 0; start <= text.length; ) {
|
|
@@ -37354,20 +37402,20 @@ function decodeSuspiciousBase64(text) {
|
|
|
37354
37402
|
}
|
|
37355
37403
|
return out;
|
|
37356
37404
|
}
|
|
37357
|
-
function mk2(rule, severity, title, signals, fix,
|
|
37405
|
+
function mk2(rule, severity, title, signals, fix, path114, line) {
|
|
37358
37406
|
return {
|
|
37359
37407
|
check: "CI-6",
|
|
37360
37408
|
rule,
|
|
37361
37409
|
dimension: "instructions",
|
|
37362
37410
|
severity,
|
|
37363
37411
|
title,
|
|
37364
|
-
file:
|
|
37412
|
+
file: path114,
|
|
37365
37413
|
...line ? { line } : {},
|
|
37366
37414
|
signals,
|
|
37367
37415
|
fix
|
|
37368
37416
|
};
|
|
37369
37417
|
}
|
|
37370
|
-
function analyzeInstructionFile(
|
|
37418
|
+
function analyzeInstructionFile(path114, content) {
|
|
37371
37419
|
const findings = [];
|
|
37372
37420
|
const decoded = decodeSuspiciousBase64(content);
|
|
37373
37421
|
const glyph = homoglyphWord(content);
|
|
@@ -37381,7 +37429,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37381
37429
|
`\`${glyph.folded}\` is written with ${glyph.count} non-Latin look-alike letter(s): it reads the same to a reviewer, but a search, a replace or a policy check on the real word misses it`
|
|
37382
37430
|
],
|
|
37383
37431
|
"Spell the word with plain Latin letters, or explain on the same line why the look-alikes are there.",
|
|
37384
|
-
|
|
37432
|
+
path114,
|
|
37385
37433
|
glyph.line
|
|
37386
37434
|
)
|
|
37387
37435
|
);
|
|
@@ -37395,7 +37443,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37395
37443
|
"contains Unicode tag characters (U+E0000\u2013E007F): an invisible instruction-smuggling channel with no legitimate use in text"
|
|
37396
37444
|
],
|
|
37397
37445
|
"Remove the tag characters. Instruction files must be plain, reviewable text.",
|
|
37398
|
-
|
|
37446
|
+
path114,
|
|
37399
37447
|
lineAt(content, content.search(TAG_CHARS))
|
|
37400
37448
|
)
|
|
37401
37449
|
);
|
|
@@ -37409,7 +37457,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37409
37457
|
"contains a bidi override (U+202D/U+202E): a Trojan-Source technique that visually reorders text so a human reads something different from what the agent parses"
|
|
37410
37458
|
],
|
|
37411
37459
|
"Remove the bidi override characters.",
|
|
37412
|
-
|
|
37460
|
+
path114,
|
|
37413
37461
|
lineAt(content, content.search(BIDI_OVERRIDE))
|
|
37414
37462
|
)
|
|
37415
37463
|
);
|
|
@@ -37423,7 +37471,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37423
37471
|
"contains bidi embed/isolate characters (U+202A\u2013202C / U+2066\u20132069): legitimate in right-to-left text, but confirm they are not being used to hide or reorder instructions"
|
|
37424
37472
|
],
|
|
37425
37473
|
"Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
|
|
37426
|
-
|
|
37474
|
+
path114,
|
|
37427
37475
|
lineAt(content, content.search(BIDI_EMBED_ISOLATE))
|
|
37428
37476
|
)
|
|
37429
37477
|
);
|
|
@@ -37439,7 +37487,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37439
37487
|
revealed ? "a zero-width character conceals a prompt-override directive that only appears once the hidden characters are stripped" : "a zero-width character splits a visible Latin word: a concealment technique (hides text from human review while the agent reads it as contiguous)"
|
|
37440
37488
|
],
|
|
37441
37489
|
"Remove the zero-width characters. Instruction files must be plain, reviewable text.",
|
|
37442
|
-
|
|
37490
|
+
path114,
|
|
37443
37491
|
lineAt(content, zw.first)
|
|
37444
37492
|
)
|
|
37445
37493
|
);
|
|
@@ -37458,7 +37506,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37458
37506
|
`contains a prompt-override / role-impersonation directive (\`${safeText(m[0].slice(0, 60).trim(), 60)}\`)${ovEnc ? ", concealed in a base64 blob" : ""}`
|
|
37459
37507
|
],
|
|
37460
37508
|
"Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
|
|
37461
|
-
|
|
37509
|
+
path114,
|
|
37462
37510
|
ov ? lineAt(content, ov.index) : void 0
|
|
37463
37511
|
// concealed in base64: no line, never a wrong one
|
|
37464
37512
|
)
|
|
@@ -37475,7 +37523,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37475
37523
|
`\`${safeText(fo[0].slice(0, 70).trim(), 70)}\`: fetch-and-obey, outside an install/setup section`
|
|
37476
37524
|
],
|
|
37477
37525
|
"Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
|
|
37478
|
-
|
|
37526
|
+
path114,
|
|
37479
37527
|
lineAt(content, fo.index)
|
|
37480
37528
|
)
|
|
37481
37529
|
);
|
|
@@ -37491,7 +37539,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37491
37539
|
`references \`${safeText(sp[0].slice(0, 50).trim(), 50)}\`: directs the agent toward secrets`
|
|
37492
37540
|
],
|
|
37493
37541
|
"Do not reference credential files or paths in agent instructions.",
|
|
37494
|
-
|
|
37542
|
+
path114,
|
|
37495
37543
|
lineAt(content, sp.index)
|
|
37496
37544
|
)
|
|
37497
37545
|
);
|
|
@@ -37514,7 +37562,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37514
37562
|
"Instruction directs the agent to send data to an external endpoint",
|
|
37515
37563
|
[`\`${safeText(ex[0].slice(0, 70).trim(), 70)}\`: possible exfiltration directive`],
|
|
37516
37564
|
"Remove external post/upload directives from agent instructions.",
|
|
37517
|
-
|
|
37565
|
+
path114,
|
|
37518
37566
|
lineAt(content, ex.index)
|
|
37519
37567
|
)
|
|
37520
37568
|
);
|
|
@@ -37747,7 +37795,7 @@ function cmdLine(content, cmd) {
|
|
|
37747
37795
|
const i = jsonValueIndex(content, cmd);
|
|
37748
37796
|
return i >= 0 ? lineAtIndex(content, i) : void 0;
|
|
37749
37797
|
}
|
|
37750
|
-
function analyzeAgentConfig(
|
|
37798
|
+
function analyzeAgentConfig(path114, content, tree) {
|
|
37751
37799
|
let cfg;
|
|
37752
37800
|
try {
|
|
37753
37801
|
cfg = JSON.parse(content);
|
|
@@ -37770,7 +37818,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37770
37818
|
dimension: "toolRules",
|
|
37771
37819
|
severity: high ? "high" : "medium",
|
|
37772
37820
|
title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
|
|
37773
|
-
file:
|
|
37821
|
+
file: path114,
|
|
37774
37822
|
...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
|
|
37775
37823
|
signals: [
|
|
37776
37824
|
`hook command: \`${safeText(cmd, 120)}\``,
|
|
@@ -37791,7 +37839,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37791
37839
|
dimension: "toolRules",
|
|
37792
37840
|
severity: "medium",
|
|
37793
37841
|
title: "Agent hook runs a script that is not committed",
|
|
37794
|
-
file:
|
|
37842
|
+
file: path114,
|
|
37795
37843
|
...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
|
|
37796
37844
|
signals: [
|
|
37797
37845
|
`hook command: \`${safeText(cmd, 120)}\``,
|
|
@@ -37807,7 +37855,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37807
37855
|
dimension: "toolRules",
|
|
37808
37856
|
severity: "advisory",
|
|
37809
37857
|
title: "Agent hook runs a committed script this scan did not read",
|
|
37810
|
-
file:
|
|
37858
|
+
file: path114,
|
|
37811
37859
|
...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
|
|
37812
37860
|
signals: [
|
|
37813
37861
|
`hook command: \`${safeText(cmd, 120)}\``,
|
|
@@ -37836,12 +37884,12 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37836
37884
|
dimension: "toolRules",
|
|
37837
37885
|
severity: high ? "high" : "medium",
|
|
37838
37886
|
title: high ? "Committed agent config pre-authorizes broad tools with no deny backstop" : "Committed agent config pre-authorizes broad tools",
|
|
37839
|
-
file:
|
|
37887
|
+
file: path114,
|
|
37840
37888
|
signals,
|
|
37841
37889
|
fix: "Scope the allow-list to specific read-only subcommands (e.g. `Bash(gh pr view:*)`); avoid bare `Bash`/`git:`/`Write`, or add a `deny` backstop.",
|
|
37842
37890
|
explain: explainGrant({
|
|
37843
37891
|
high,
|
|
37844
|
-
file:
|
|
37892
|
+
file: path114,
|
|
37845
37893
|
broad: grade.broad,
|
|
37846
37894
|
bareShell: grade.bareShell,
|
|
37847
37895
|
hasBackstop: grade.bareShell ? deny.some((d) => /^Bash\b/.test(d)) : deny.some((d) => /Bash|Write|Edit/.test(d))
|
|
@@ -37858,7 +37906,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37858
37906
|
dimension: "toolRules",
|
|
37859
37907
|
severity: "medium",
|
|
37860
37908
|
title: "Committed agent config pre-approves a command that can run other programs",
|
|
37861
|
-
file:
|
|
37909
|
+
file: path114,
|
|
37862
37910
|
signals: [
|
|
37863
37911
|
`pre-approved: ${escapes.slice(0, 5).map((e) => `\`${safeText(e, 80)}\``).join(", ")}`,
|
|
37864
37912
|
"`find -exec` and `make -n --eval` run other programs without a prompt"
|
|
@@ -37868,8 +37916,8 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37868
37916
|
}
|
|
37869
37917
|
return findings;
|
|
37870
37918
|
}
|
|
37871
|
-
function skillReadsUntrusted(
|
|
37872
|
-
if (!ROOT_SURFACE_RE.test(
|
|
37919
|
+
function skillReadsUntrusted(path114, content, allow, broad) {
|
|
37920
|
+
if (!ROOT_SURFACE_RE.test(path114)) return null;
|
|
37873
37921
|
const body = content.replace(/^---[\s\S]*?\n---/, "");
|
|
37874
37922
|
const runsCode = broad.map((a) => a.replace(/^PowerShell(?=$|\()/, "Bash")).some((a) => /^Bash$|^Bash\(\s*\*/.test(a) || openRunner(a) && !/^Bash\(\s*gh\b/.test(a));
|
|
37875
37923
|
const webGrant = allow.some((a) => /^(WebFetch|WebSearch)\b/.test(a));
|
|
@@ -37884,8 +37932,8 @@ function skillReadsUntrusted(path113, content, allow, broad) {
|
|
|
37884
37932
|
return "it reads pull request text that strangers write, and may edit files and run git/gh on it";
|
|
37885
37933
|
return null;
|
|
37886
37934
|
}
|
|
37887
|
-
function analyzeSkillGrants(
|
|
37888
|
-
if (!GRANT_CARRIER_RE.test(
|
|
37935
|
+
function analyzeSkillGrants(path114, content) {
|
|
37936
|
+
if (!GRANT_CARRIER_RE.test(path114)) return [];
|
|
37889
37937
|
const allow = allowedToolsOf(parseFrontmatter(content));
|
|
37890
37938
|
if (allow.length === 0) return [];
|
|
37891
37939
|
const grade = gradeBroadGrant(allow, [], {
|
|
@@ -37893,9 +37941,9 @@ function analyzeSkillGrants(path113, content) {
|
|
|
37893
37941
|
scope: "whenever this skill or command is active, for everyone who opens this repo with the agent"
|
|
37894
37942
|
});
|
|
37895
37943
|
if (!grade) return [];
|
|
37896
|
-
const kind = /commands\//.test(
|
|
37944
|
+
const kind = /commands\//.test(path114) ? "slash command" : "skill";
|
|
37897
37945
|
const at = content.search(/^allowed-tools\s*:/m);
|
|
37898
|
-
const untrusted = skillReadsUntrusted(
|
|
37946
|
+
const untrusted = skillReadsUntrusted(path114, content, allow, grade.broad);
|
|
37899
37947
|
if (untrusted)
|
|
37900
37948
|
return [
|
|
37901
37949
|
{
|
|
@@ -37905,7 +37953,7 @@ function analyzeSkillGrants(path113, content) {
|
|
|
37905
37953
|
dimension: "toolRules",
|
|
37906
37954
|
severity: "advisory",
|
|
37907
37955
|
title: `Committed ${kind} runs code or writes with text strangers control`,
|
|
37908
|
-
file:
|
|
37956
|
+
file: path114,
|
|
37909
37957
|
signals: [...grade.signals, untrusted],
|
|
37910
37958
|
fix: "Drop the shell or interpreter grant from a skill that reads PRs, issues or the web, or have it treat that text as data in a read-only step first."
|
|
37911
37959
|
}
|
|
@@ -37922,7 +37970,7 @@ function analyzeSkillGrants(path113, content) {
|
|
|
37922
37970
|
// shell — the cap is on reach, not on honesty.
|
|
37923
37971
|
severity: "medium",
|
|
37924
37972
|
title: grade.high ? `Committed ${kind} pre-authorizes an unrestricted shell while active` : `Committed ${kind} pre-authorizes broad tools while active`,
|
|
37925
|
-
file:
|
|
37973
|
+
file: path114,
|
|
37926
37974
|
signals: grade.signals,
|
|
37927
37975
|
fix: "Scope `allowed-tools` to the specific commands the skill needs (e.g. `Bash(git status:*)`); avoid a bare `Bash`, `Write` or `Edit`."
|
|
37928
37976
|
}
|
|
@@ -38054,7 +38102,7 @@ function ownPackageNames(manifests) {
|
|
|
38054
38102
|
}
|
|
38055
38103
|
return out;
|
|
38056
38104
|
}
|
|
38057
|
-
function analyzeMcp(
|
|
38105
|
+
function analyzeMcp(path114, content, own = /* @__PURE__ */ new Set()) {
|
|
38058
38106
|
let cfg;
|
|
38059
38107
|
try {
|
|
38060
38108
|
cfg = JSON.parse(content);
|
|
@@ -38090,9 +38138,9 @@ function analyzeMcp(path113, content, own = /* @__PURE__ */ new Set()) {
|
|
|
38090
38138
|
const key = (count.get(name) ?? 0) > 1 ? `${section}.${name}` : name;
|
|
38091
38139
|
servers[key] = { ...spec, anchor: name };
|
|
38092
38140
|
}
|
|
38093
|
-
return analyzeMcpServers(servers,
|
|
38141
|
+
return analyzeMcpServers(servers, path114, content, own);
|
|
38094
38142
|
}
|
|
38095
|
-
function analyzeMcpServers(servers,
|
|
38143
|
+
function analyzeMcpServers(servers, path114, content = "", own = /* @__PURE__ */ new Set()) {
|
|
38096
38144
|
const findings = [];
|
|
38097
38145
|
for (const [name, srv] of Object.entries(servers ?? {})) {
|
|
38098
38146
|
if (!srv || srv.disabled) continue;
|
|
@@ -38111,7 +38159,7 @@ function analyzeMcpServers(servers, path113, content = "", own = /* @__PURE__ */
|
|
|
38111
38159
|
dimension: "mcp",
|
|
38112
38160
|
severity: "medium",
|
|
38113
38161
|
title: `MCP server "${name}" runs an unpinned executable`,
|
|
38114
|
-
file:
|
|
38162
|
+
file: path114,
|
|
38115
38163
|
...line ? { line } : {},
|
|
38116
38164
|
signals: [
|
|
38117
38165
|
why.launcher === "npx" ? `\`${safeText(argv, 120)}\`: unversioned/@latest npx` : `\`${safeText(argv, 120)}\`: unversioned/latest ${why.launcher}`
|
|
@@ -38136,7 +38184,7 @@ function analyzeMcpServers(servers, path113, content = "", own = /* @__PURE__ */
|
|
|
38136
38184
|
dimension: "mcp",
|
|
38137
38185
|
severity: "high",
|
|
38138
38186
|
title: `MCP server "${name}" has an inline credential`,
|
|
38139
|
-
file:
|
|
38187
|
+
file: path114,
|
|
38140
38188
|
...line ? { line } : {},
|
|
38141
38189
|
signals: [
|
|
38142
38190
|
`env.${k} matches ${hit.patternName}: agent-reachable secret committed to the repo`
|
|
@@ -38195,7 +38243,7 @@ var init_mcp = __esm({
|
|
|
38195
38243
|
});
|
|
38196
38244
|
|
|
38197
38245
|
// src/ci-check/codex.ts
|
|
38198
|
-
function analyzeCodexConfig(
|
|
38246
|
+
function analyzeCodexConfig(path114, content, own = /* @__PURE__ */ new Set()) {
|
|
38199
38247
|
let cfg;
|
|
38200
38248
|
try {
|
|
38201
38249
|
cfg = (0, import_smol_toml6.parse)(content);
|
|
@@ -38203,7 +38251,7 @@ function analyzeCodexConfig(path113, content, own = /* @__PURE__ */ new Set()) {
|
|
|
38203
38251
|
return [];
|
|
38204
38252
|
}
|
|
38205
38253
|
const findings = [];
|
|
38206
|
-
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {},
|
|
38254
|
+
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path114, content, own));
|
|
38207
38255
|
const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
|
|
38208
38256
|
const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
|
|
38209
38257
|
const fullAccess = /danger-full-access/i.test(sandbox);
|
|
@@ -38226,7 +38274,7 @@ function analyzeCodexConfig(path113, content, own = /* @__PURE__ */ new Set()) {
|
|
|
38226
38274
|
dimension: "toolRules",
|
|
38227
38275
|
severity: fullAccess ? "high" : "medium",
|
|
38228
38276
|
title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
|
|
38229
|
-
file:
|
|
38277
|
+
file: path114,
|
|
38230
38278
|
signals,
|
|
38231
38279
|
fix: 'Commit a least-privilege Codex config: prefer `sandbox_mode = "read-only"` (or `"workspace-write"`) and `approval_policy = "on-request"`/`"on-failure"`. A repo-committed config applies to every contributor who runs Codex here.'
|
|
38232
38280
|
});
|
|
@@ -38395,7 +38443,7 @@ var init_agent_permissions = __esm({
|
|
|
38395
38443
|
init_codex();
|
|
38396
38444
|
init_read_small_file();
|
|
38397
38445
|
CATEGORY = "Agent permissions";
|
|
38398
|
-
CLAUDE_NO_PROMPT_MODES = /* @__PURE__ */ new Set(["bypassPermissions"
|
|
38446
|
+
CLAUDE_NO_PROMPT_MODES = /* @__PURE__ */ new Set(["bypassPermissions"]);
|
|
38399
38447
|
MAX_FILE_BYTES3 = 2 * 1024 * 1024;
|
|
38400
38448
|
CI_SEVERITY = {
|
|
38401
38449
|
critical: "critical",
|
|
@@ -38430,6 +38478,15 @@ function checkOutsideContent(ctx) {
|
|
|
38430
38478
|
const roles = config.policy.untrustedContent?.roles ?? {};
|
|
38431
38479
|
const sources = outsideSources(home, roles);
|
|
38432
38480
|
if (sources.length === 0) return [];
|
|
38481
|
+
const byServer = /* @__PURE__ */ new Map();
|
|
38482
|
+
for (const src of sources) {
|
|
38483
|
+
const e = byServer.get(src.server);
|
|
38484
|
+
if (e) {
|
|
38485
|
+
if (!e.agents.includes(src.agent)) e.agents.push(src.agent);
|
|
38486
|
+
if (src.how === "role") e.how = "role";
|
|
38487
|
+
} else byServer.set(src.server, { agents: [src.agent], how: src.how });
|
|
38488
|
+
}
|
|
38489
|
+
const servers = byServer.size;
|
|
38433
38490
|
const egress = config.policy.egress;
|
|
38434
38491
|
const egressGated = !!egress?.enabled && (egress.mode === "block" || egress.mode === "review");
|
|
38435
38492
|
const hold = checkValue(
|
|
@@ -38446,11 +38503,14 @@ function checkOutsideContent(ctx) {
|
|
|
38446
38503
|
{
|
|
38447
38504
|
category: CATEGORY2,
|
|
38448
38505
|
severity: "high",
|
|
38449
|
-
title: `${
|
|
38506
|
+
title: `${servers} MCP server${servers === 1 ? "" : "s"} bring${servers === 1 ? "s" : ""} outside content in, and the way out is open`,
|
|
38450
38507
|
what: "An agent here reads pages, issues or messages written by others, and what it does next is not held.",
|
|
38451
38508
|
why: gaps.join("; ") + ".",
|
|
38452
38509
|
who: "One poisoned page or issue is enough: the agent reads it, then sends or deletes as it says.",
|
|
38453
|
-
detail: [
|
|
38510
|
+
detail: [
|
|
38511
|
+
...[...byServer].slice(0, 8).map(([name, e]) => `${name} (${e.agents.join(", ")}, by ${e.how})`),
|
|
38512
|
+
...gaps
|
|
38513
|
+
],
|
|
38454
38514
|
owner: "node9",
|
|
38455
38515
|
fix: 'Run `node9 egress watch` (or `node9 egress lock`), keep behavior.untrusted-content on, and mark each server\'s reading tools as "Brings outside content" on the Apps page so the hold applies to them.'
|
|
38456
38516
|
}
|
|
@@ -38597,8 +38657,8 @@ var init_instruction_files = __esm({
|
|
|
38597
38657
|
});
|
|
38598
38658
|
|
|
38599
38659
|
// src/skill-pin.ts
|
|
38600
|
-
function getPinsFilePath2() {
|
|
38601
|
-
return import_path57.default.join(
|
|
38660
|
+
function getPinsFilePath2(home = import_os46.default.homedir()) {
|
|
38661
|
+
return import_path57.default.join(home, ".node9", "skill-pins.json");
|
|
38602
38662
|
}
|
|
38603
38663
|
function sha256Bytes(buf) {
|
|
38604
38664
|
return import_crypto17.default.createHash("sha256").update(buf).digest("hex");
|
|
@@ -38668,8 +38728,8 @@ function hashSkillRoot(absPath) {
|
|
|
38668
38728
|
function getRootKey(absPath) {
|
|
38669
38729
|
return import_crypto17.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
|
|
38670
38730
|
}
|
|
38671
|
-
function readSkillPinsSafe() {
|
|
38672
|
-
const filePath = getPinsFilePath2();
|
|
38731
|
+
function readSkillPinsSafe(home) {
|
|
38732
|
+
const filePath = getPinsFilePath2(home);
|
|
38673
38733
|
try {
|
|
38674
38734
|
const raw = import_fs55.default.readFileSync(filePath, "utf-8");
|
|
38675
38735
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
@@ -38853,7 +38913,7 @@ function checkSupplyChain(ctx) {
|
|
|
38853
38913
|
}
|
|
38854
38914
|
function pluginPinState(home) {
|
|
38855
38915
|
const roots = defaultSkillRoots(void 0, home);
|
|
38856
|
-
const pins = readSkillPinsSafe();
|
|
38916
|
+
const pins = readSkillPinsSafe(home);
|
|
38857
38917
|
const pinned = pins.ok ? pins.pins.roots : {};
|
|
38858
38918
|
return { roots, unpinned: roots.filter((r) => !pinned[getRootKey(r)]) };
|
|
38859
38919
|
}
|
|
@@ -38866,7 +38926,7 @@ function pluginsAndPackages(ctx, home) {
|
|
|
38866
38926
|
if (roots.length > 0 && tamper === "off") {
|
|
38867
38927
|
findings.push({
|
|
38868
38928
|
category: "Supply chain",
|
|
38869
|
-
severity: "
|
|
38929
|
+
severity: "advisory",
|
|
38870
38930
|
title: `${roots.length} installed plugin${roots.length === 1 ? "" : "s"} load${roots.length === 1 ? "s" : ""} unverified`,
|
|
38871
38931
|
what: "Plugins and skills the agent loads are code that runs with its rights, and no content hash is kept for them.",
|
|
38872
38932
|
why: "The check loading.skill-tamper is off, so node9 does not pin them.",
|
|
@@ -38878,7 +38938,7 @@ function pluginsAndPackages(ctx, home) {
|
|
|
38878
38938
|
} else if (unpinned.length > 0) {
|
|
38879
38939
|
findings.push({
|
|
38880
38940
|
category: "Supply chain",
|
|
38881
|
-
severity: "
|
|
38941
|
+
severity: "advisory",
|
|
38882
38942
|
title: `${unpinned.length} of ${roots.length} installed plugin${roots.length === 1 ? "" : "s"} ${unpinned.length === 1 ? "has" : "have"} no pin yet`,
|
|
38883
38943
|
what: "A plugin the agent can load has no recorded content hash yet.",
|
|
38884
38944
|
why: "node9 pins a plugin the first time it loads; these have not loaded since pinning was turned on.",
|
|
@@ -39244,7 +39304,8 @@ function checkCoverage(ctx) {
|
|
|
39244
39304
|
});
|
|
39245
39305
|
return findings;
|
|
39246
39306
|
}
|
|
39247
|
-
const
|
|
39307
|
+
const config = getConfig(ctx.cwd);
|
|
39308
|
+
const mode = config.settings.mode;
|
|
39248
39309
|
if (isRecordOnly(mode)) {
|
|
39249
39310
|
const level = levelOf(mode);
|
|
39250
39311
|
findings.push({
|
|
@@ -39259,7 +39320,6 @@ function checkCoverage(ctx) {
|
|
|
39259
39320
|
fix: "Set mode to `standard` (or `strict`) to enforce in-path."
|
|
39260
39321
|
});
|
|
39261
39322
|
}
|
|
39262
|
-
const config = getConfig(ctx.cwd);
|
|
39263
39323
|
if (config.settings.autoStartDaemon !== false) {
|
|
39264
39324
|
const state = autostartState();
|
|
39265
39325
|
if (state === "disabled" || state === "absent") {
|
|
@@ -39580,8 +39640,6 @@ async function annotateCoverage(findings, ctx) {
|
|
|
39580
39640
|
}
|
|
39581
39641
|
if (probe.kind === "egress") {
|
|
39582
39642
|
f.coverage = egressCoverage(env);
|
|
39583
|
-
if (f.coverage.state === "open" && config.policy.egress.enabled && config.policy.egress.mode !== "off" && isRecordOnly(mode))
|
|
39584
|
-
f.fix = auditModeFix(mode, "node9 egress is set");
|
|
39585
39643
|
continue;
|
|
39586
39644
|
}
|
|
39587
39645
|
if (probe.kind === "gateWired") {
|
|
@@ -41318,6 +41376,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
41318
41376
|
const sessionCalls = [];
|
|
41319
41377
|
const toolUseFilePaths = /* @__PURE__ */ new Map();
|
|
41320
41378
|
const toolUseNames = /* @__PURE__ */ new Map();
|
|
41379
|
+
const toolUseInputs = /* @__PURE__ */ new Map();
|
|
41321
41380
|
let firstDlpTs = null;
|
|
41322
41381
|
let firstEditTs = null;
|
|
41323
41382
|
for (const line of raw.split("\n")) {
|
|
@@ -41388,7 +41447,10 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
41388
41447
|
if (isNode9SelfOutput(resultText)) continue;
|
|
41389
41448
|
const resultTool = block.tool_use_id ? toolUseNames.get(block.tool_use_id) : void 0;
|
|
41390
41449
|
if (resultTool)
|
|
41391
|
-
judge.noteToolResult(sessionId, resultTool, entry.timestamp ?? "", entry.cwd
|
|
41450
|
+
judge.noteToolResult(sessionId, resultTool, entry.timestamp ?? "", entry.cwd, {
|
|
41451
|
+
input: block.tool_use_id ? toolUseInputs.get(block.tool_use_id) : void 0,
|
|
41452
|
+
output: resultText
|
|
41453
|
+
});
|
|
41392
41454
|
const decoysHere1 = recordCanaries(
|
|
41393
41455
|
{ text: resultText },
|
|
41394
41456
|
"tool-result",
|
|
@@ -41453,6 +41515,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
41453
41515
|
toolUseFilePaths.set(block.id, input.file_path);
|
|
41454
41516
|
}
|
|
41455
41517
|
if (block.id) toolUseNames.set(block.id, toolName);
|
|
41518
|
+
if (block.id) toolUseInputs.set(block.id, input);
|
|
41456
41519
|
sessionCalls.push({ toolName, input, timestamp: entry.timestamp ?? "" });
|
|
41457
41520
|
if (toolNameLower === "bash" || toolNameLower === "execute_bash") {
|
|
41458
41521
|
result.bashCalls++;
|
|
@@ -44412,6 +44475,9 @@ function getDaemonServer() {
|
|
|
44412
44475
|
function markRejectionHandlerRegistered() {
|
|
44413
44476
|
daemonRejectionHandlerRegistered = true;
|
|
44414
44477
|
}
|
|
44478
|
+
function markSignalHandlersRegistered() {
|
|
44479
|
+
daemonSignalHandlersRegistered = true;
|
|
44480
|
+
}
|
|
44415
44481
|
function getActivitySocketPath() {
|
|
44416
44482
|
return ACTIVITY_SOCKET_PATH;
|
|
44417
44483
|
}
|
|
@@ -44635,14 +44701,23 @@ function startActivitySocket() {
|
|
|
44635
44701
|
if (ACTIVITY_SOCKET_PATH && !import_fs65.default.existsSync(ACTIVITY_SOCKET_PATH)) attemptRebind("health-probe");
|
|
44636
44702
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
44637
44703
|
activityHealthInterval.unref();
|
|
44638
|
-
process.on("exit",
|
|
44639
|
-
|
|
44640
|
-
|
|
44641
|
-
|
|
44642
|
-
|
|
44643
|
-
|
|
44644
|
-
|
|
44645
|
-
|
|
44704
|
+
process.on("exit", stopActivitySocket);
|
|
44705
|
+
}
|
|
44706
|
+
function stopActivitySocket() {
|
|
44707
|
+
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
44708
|
+
activityHealthInterval = null;
|
|
44709
|
+
const socketPath = ACTIVITY_SOCKET_PATH;
|
|
44710
|
+
const bound = activitySocketIdentity;
|
|
44711
|
+
ACTIVITY_SOCKET_PATH = null;
|
|
44712
|
+
activitySocketIdentity = null;
|
|
44713
|
+
if (!socketPath || !bound || process.platform === "win32") return;
|
|
44714
|
+
try {
|
|
44715
|
+
const st = import_fs65.default.lstatSync(socketPath);
|
|
44716
|
+
if (isOwnStaleSocket(socketPath) && st.dev === bound.dev && st.ino === bound.ino)
|
|
44717
|
+
import_fs65.default.unlinkSync(socketPath);
|
|
44718
|
+
} catch {
|
|
44719
|
+
}
|
|
44720
|
+
removeOwnSocketDir(socketPath, process.env, import_os55.default.homedir());
|
|
44646
44721
|
}
|
|
44647
44722
|
function attemptRebind(reason) {
|
|
44648
44723
|
if (!shouldRebind()) {
|
|
@@ -44776,6 +44851,8 @@ function bindActivitySocket() {
|
|
|
44776
44851
|
if (process.platform !== "win32") {
|
|
44777
44852
|
try {
|
|
44778
44853
|
import_fs65.default.chmodSync(socketPath, 384);
|
|
44854
|
+
const st = import_fs65.default.lstatSync(socketPath);
|
|
44855
|
+
activitySocketIdentity = { dev: st.dev, ino: st.ino };
|
|
44779
44856
|
} catch {
|
|
44780
44857
|
}
|
|
44781
44858
|
}
|
|
@@ -44783,7 +44860,7 @@ function bindActivitySocket() {
|
|
|
44783
44860
|
});
|
|
44784
44861
|
activitySocketServer = unixServer;
|
|
44785
44862
|
}
|
|
44786
|
-
var import_net5, import_fs65, import_path68, import_os55, import_crypto20, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, sseClients, cards, suggestionTracker, taintStore, sessionTaintStore, sessionExposureStore, sessionWriteStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH, activitySocketPathListeners, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
|
|
44863
|
+
var import_net5, import_fs65, import_path68, import_os55, import_crypto20, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, sseClients, cards, suggestionTracker, taintStore, sessionTaintStore, sessionExposureStore, sessionWriteStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, daemonSignalHandlersRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH, activitySocketPathListeners, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activitySocketIdentity, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
|
|
44787
44864
|
var init_state3 = __esm({
|
|
44788
44865
|
"src/daemon/state.ts"() {
|
|
44789
44866
|
"use strict";
|
|
@@ -44828,6 +44905,7 @@ var init_state3 = __esm({
|
|
|
44828
44905
|
_hadBrowserClient = false;
|
|
44829
44906
|
_daemonServer = null;
|
|
44830
44907
|
daemonRejectionHandlerRegistered = false;
|
|
44908
|
+
daemonSignalHandlersRegistered = false;
|
|
44831
44909
|
AUTO_DENY_MS = 12e4;
|
|
44832
44910
|
TRUST_DURATIONS = {
|
|
44833
44911
|
"30m": 30 * 6e4,
|
|
@@ -44868,6 +44946,7 @@ var init_state3 = __esm({
|
|
|
44868
44946
|
ACTIVITY_REBIND_WINDOW_MS = 6e4;
|
|
44869
44947
|
ACTIVITY_HEALTH_PROBE_MS = 2e3;
|
|
44870
44948
|
activitySocketServer = null;
|
|
44949
|
+
activitySocketIdentity = null;
|
|
44871
44950
|
activityHealthInterval = null;
|
|
44872
44951
|
activityRebindAttempts = [];
|
|
44873
44952
|
activityCircuitTripped = false;
|
|
@@ -45667,6 +45746,23 @@ function writeCache2(cache7) {
|
|
|
45667
45746
|
} catch {
|
|
45668
45747
|
}
|
|
45669
45748
|
}
|
|
45749
|
+
function cacheFromSyncBody(body, etag) {
|
|
45750
|
+
return {
|
|
45751
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45752
|
+
rules: extractRules(body),
|
|
45753
|
+
etag,
|
|
45754
|
+
panicMode: body.panicMode,
|
|
45755
|
+
shadowMode: body.shadowMode,
|
|
45756
|
+
syncIntervalHours: body.syncIntervalHours,
|
|
45757
|
+
workspaceId: body.workspaceId,
|
|
45758
|
+
shields: extractShields(body),
|
|
45759
|
+
managedConfig: extractManagedConfig(body),
|
|
45760
|
+
config: extractWorkspaceConfig(body)
|
|
45761
|
+
};
|
|
45762
|
+
}
|
|
45763
|
+
function writePolicyCache(body, etag) {
|
|
45764
|
+
writeCache2(cacheFromSyncBody(body, etag));
|
|
45765
|
+
}
|
|
45670
45766
|
async function syncOnce() {
|
|
45671
45767
|
const creds = readCredentials();
|
|
45672
45768
|
if (!creds) return;
|
|
@@ -45675,19 +45771,7 @@ async function syncOnce() {
|
|
|
45675
45771
|
if (result.kind === "unchanged") {
|
|
45676
45772
|
recordSyncHealth({ ok: true });
|
|
45677
45773
|
} else {
|
|
45678
|
-
|
|
45679
|
-
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45680
|
-
rules: extractRules(result.body),
|
|
45681
|
-
etag: result.etag,
|
|
45682
|
-
panicMode: result.body.panicMode,
|
|
45683
|
-
shadowMode: result.body.shadowMode,
|
|
45684
|
-
syncIntervalHours: result.body.syncIntervalHours,
|
|
45685
|
-
workspaceId: result.body.workspaceId,
|
|
45686
|
-
shields: extractShields(result.body),
|
|
45687
|
-
managedConfig: extractManagedConfig(result.body),
|
|
45688
|
-
config: extractWorkspaceConfig(result.body)
|
|
45689
|
-
};
|
|
45690
|
-
writeCache2(cache7);
|
|
45774
|
+
writeCache2(cacheFromSyncBody(result.body, result.etag));
|
|
45691
45775
|
recordSyncHealth({ ok: true, changed: true });
|
|
45692
45776
|
}
|
|
45693
45777
|
} catch (err2) {
|
|
@@ -45905,18 +45989,7 @@ async function runCloudSync() {
|
|
|
45905
45989
|
recordSyncHealth({ ok: true });
|
|
45906
45990
|
return status.cached ? { ok: true, rules: status.rules, fetchedAt: status.fetchedAt, unchanged: true } : { ok: true, rules: 0, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), unchanged: true };
|
|
45907
45991
|
}
|
|
45908
|
-
const cache7 =
|
|
45909
|
-
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45910
|
-
rules: extractRules(result.body),
|
|
45911
|
-
etag: result.etag,
|
|
45912
|
-
panicMode: result.body.panicMode,
|
|
45913
|
-
shadowMode: result.body.shadowMode,
|
|
45914
|
-
syncIntervalHours: result.body.syncIntervalHours,
|
|
45915
|
-
workspaceId: result.body.workspaceId,
|
|
45916
|
-
shields: extractShields(result.body),
|
|
45917
|
-
managedConfig: extractManagedConfig(result.body),
|
|
45918
|
-
config: extractWorkspaceConfig(result.body)
|
|
45919
|
-
};
|
|
45992
|
+
const cache7 = cacheFromSyncBody(result.body, result.etag);
|
|
45920
45993
|
writeCache2(cache7);
|
|
45921
45994
|
recordSyncHealth({ ok: true, changed: true });
|
|
45922
45995
|
return { ok: true, rules: cache7.rules.length, fetchedAt: cache7.fetchedAt };
|
|
@@ -46040,6 +46113,7 @@ var init_sync = __esm({
|
|
|
46040
46113
|
var audit_shipper_exports = {};
|
|
46041
46114
|
__export(audit_shipper_exports, {
|
|
46042
46115
|
AUDIT_SHIP_WATERMARK: () => AUDIT_SHIP_WATERMARK,
|
|
46116
|
+
OWASP_FIELDS_RETRY_MS: () => OWASP_FIELDS_RETRY_MS,
|
|
46043
46117
|
_resetOwaspWireFields: () => _resetOwaspWireFields,
|
|
46044
46118
|
buildBatchEndpoint: () => buildBatchEndpoint,
|
|
46045
46119
|
buildWireRows: () => buildWireRows,
|
|
@@ -46052,7 +46126,7 @@ __export(audit_shipper_exports, {
|
|
|
46052
46126
|
writeWatermark: () => writeWatermark
|
|
46053
46127
|
});
|
|
46054
46128
|
function _resetOwaspWireFields() {
|
|
46055
|
-
|
|
46129
|
+
owaspFieldsRejectedAt = null;
|
|
46056
46130
|
}
|
|
46057
46131
|
function withoutOwaspFields(rows) {
|
|
46058
46132
|
return rows.map((r) => {
|
|
@@ -46176,6 +46250,7 @@ async function shipOnce(deps = {}) {
|
|
|
46176
46250
|
const auditLogPath = deps.auditLogPath ?? LOCAL_AUDIT_LOG;
|
|
46177
46251
|
const watermarkPath = deps.watermarkPath ?? AUDIT_SHIP_WATERMARK;
|
|
46178
46252
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
46253
|
+
const now = deps.now ?? Date.now;
|
|
46179
46254
|
let cloudEnabled = deps.cloudEnabled;
|
|
46180
46255
|
if (cloudEnabled === void 0) {
|
|
46181
46256
|
try {
|
|
@@ -46213,7 +46288,8 @@ async function shipOnce(deps = {}) {
|
|
|
46213
46288
|
if (consumed === 0) break;
|
|
46214
46289
|
for (let i = 0; i < rows.length; i += MAX_BATCH) {
|
|
46215
46290
|
const slice = rows.slice(i, i + MAX_BATCH);
|
|
46216
|
-
|
|
46291
|
+
const stripFields = owaspFieldsRejectedAt !== null && now() - owaspFieldsRejectedAt < OWASP_FIELDS_RETRY_MS;
|
|
46292
|
+
let batch = stripFields ? withoutOwaspFields(slice) : slice;
|
|
46217
46293
|
const post = async (body) => {
|
|
46218
46294
|
const controller = new AbortController();
|
|
46219
46295
|
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
@@ -46235,7 +46311,7 @@ async function shipOnce(deps = {}) {
|
|
|
46235
46311
|
if (res.status === 400 && hasOwaspFields(batch)) {
|
|
46236
46312
|
batch = withoutOwaspFields(batch);
|
|
46237
46313
|
res = await post(batch);
|
|
46238
|
-
if (res.ok)
|
|
46314
|
+
if (res.ok) owaspFieldsRejectedAt = now();
|
|
46239
46315
|
}
|
|
46240
46316
|
if (!res.ok) throw new Error(`audit/batch HTTP ${res.status}`);
|
|
46241
46317
|
shipped += batch.length;
|
|
@@ -46322,7 +46398,7 @@ function outboxBacklog(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHI
|
|
|
46322
46398
|
};
|
|
46323
46399
|
}
|
|
46324
46400
|
}
|
|
46325
|
-
var import_fs67, import_path70, import_os57, import_crypto21, DECIDED_BY_VALUES, AUDIT_SHIP_WATERMARK, DEFAULT_INTERVAL_MS, MAX_BATCH, MAX_CHUNK_BYTES, MAX_CHUNKS_PER_TICK, FETCH_TIMEOUT_MS, SKIP_CHECKED_BY, CHECK_ID_RE, CANARY_KINDS, OWASP_WIRE_FIELDS,
|
|
46401
|
+
var import_fs67, import_path70, import_os57, import_crypto21, DECIDED_BY_VALUES, AUDIT_SHIP_WATERMARK, DEFAULT_INTERVAL_MS, MAX_BATCH, MAX_CHUNK_BYTES, MAX_CHUNKS_PER_TICK, FETCH_TIMEOUT_MS, SKIP_CHECKED_BY, CHECK_ID_RE, CANARY_KINDS, OWASP_WIRE_FIELDS, owaspFieldsRejectedAt, OWASP_FIELDS_RETRY_MS, shipperStarted;
|
|
46326
46402
|
var init_audit_shipper = __esm({
|
|
46327
46403
|
"src/daemon/audit-shipper.ts"() {
|
|
46328
46404
|
"use strict";
|
|
@@ -46358,7 +46434,8 @@ var init_audit_shipper = __esm({
|
|
|
46358
46434
|
"ssh-key"
|
|
46359
46435
|
]);
|
|
46360
46436
|
OWASP_WIRE_FIELDS = ["checkId", "canary", "canaryKind"];
|
|
46361
|
-
|
|
46437
|
+
owaspFieldsRejectedAt = null;
|
|
46438
|
+
OWASP_FIELDS_RETRY_MS = 60 * 60 * 1e3;
|
|
46362
46439
|
shipperStarted = false;
|
|
46363
46440
|
}
|
|
46364
46441
|
});
|
|
@@ -48482,6 +48559,12 @@ data: ${JSON.stringify(item.data)}
|
|
|
48482
48559
|
console.error(import_chalk8.default.red("[node9 daemon] unhandled rejection \u2014 keeping daemon alive:"), stack);
|
|
48483
48560
|
});
|
|
48484
48561
|
}
|
|
48562
|
+
if (!daemonSignalHandlersRegistered) {
|
|
48563
|
+
markSignalHandlersRegistered();
|
|
48564
|
+
process.once("SIGTERM", () => process.exit(0));
|
|
48565
|
+
process.once("SIGINT", () => process.exit(130));
|
|
48566
|
+
process.once("SIGHUP", () => process.exit(129));
|
|
48567
|
+
}
|
|
48485
48568
|
const writeOwnPidFile = () => atomicWriteSync(
|
|
48486
48569
|
DAEMON_PID_FILE,
|
|
48487
48570
|
JSON.stringify({
|
|
@@ -48498,6 +48581,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
48498
48581
|
{ mode: 384 }
|
|
48499
48582
|
);
|
|
48500
48583
|
server.listen(DAEMON_PORT, DAEMON_HOST, () => {
|
|
48584
|
+
startActivitySocket();
|
|
48501
48585
|
writeOwnPidFile();
|
|
48502
48586
|
onActivitySocketPathChange(() => {
|
|
48503
48587
|
try {
|
|
@@ -48512,7 +48596,6 @@ data: ${JSON.stringify(item.data)}
|
|
|
48512
48596
|
if (watchMode) {
|
|
48513
48597
|
console.error(import_chalk8.default.cyan("\u{1F6F0}\uFE0F Flight Recorder active \u2014 daemon will not idle-timeout"));
|
|
48514
48598
|
}
|
|
48515
|
-
startActivitySocket();
|
|
48516
48599
|
}
|
|
48517
48600
|
var import_http4, import_fs72, import_path74, import_os60, import_crypto23, import_child_process5, import_chalk8;
|
|
48518
48601
|
var init_server = __esm({
|
|
@@ -50892,14 +50975,14 @@ var require_util = __commonJS({
|
|
|
50892
50975
|
}
|
|
50893
50976
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
50894
50977
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
50895
|
-
let
|
|
50978
|
+
let path114 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
50896
50979
|
if (origin[origin.length - 1] === "/") {
|
|
50897
50980
|
origin = origin.slice(0, origin.length - 1);
|
|
50898
50981
|
}
|
|
50899
|
-
if (
|
|
50900
|
-
|
|
50982
|
+
if (path114 && path114[0] !== "/") {
|
|
50983
|
+
path114 = `/${path114}`;
|
|
50901
50984
|
}
|
|
50902
|
-
return new URL(`${origin}${
|
|
50985
|
+
return new URL(`${origin}${path114}`);
|
|
50903
50986
|
}
|
|
50904
50987
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
50905
50988
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -51722,9 +51805,9 @@ var require_diagnostics = __commonJS({
|
|
|
51722
51805
|
"undici:client:sendHeaders",
|
|
51723
51806
|
(evt) => {
|
|
51724
51807
|
const {
|
|
51725
|
-
request: { method, path:
|
|
51808
|
+
request: { method, path: path114, origin }
|
|
51726
51809
|
} = evt;
|
|
51727
|
-
debugLog2("sending request to %s %s%s", method, origin,
|
|
51810
|
+
debugLog2("sending request to %s %s%s", method, origin, path114);
|
|
51728
51811
|
}
|
|
51729
51812
|
);
|
|
51730
51813
|
}
|
|
@@ -51742,14 +51825,14 @@ var require_diagnostics = __commonJS({
|
|
|
51742
51825
|
"undici:request:headers",
|
|
51743
51826
|
(evt) => {
|
|
51744
51827
|
const {
|
|
51745
|
-
request: { method, path:
|
|
51828
|
+
request: { method, path: path114, origin },
|
|
51746
51829
|
response: { statusCode }
|
|
51747
51830
|
} = evt;
|
|
51748
51831
|
debugLog2(
|
|
51749
51832
|
"received response to %s %s%s - HTTP %d",
|
|
51750
51833
|
method,
|
|
51751
51834
|
origin,
|
|
51752
|
-
|
|
51835
|
+
path114,
|
|
51753
51836
|
statusCode
|
|
51754
51837
|
);
|
|
51755
51838
|
}
|
|
@@ -51758,23 +51841,23 @@ var require_diagnostics = __commonJS({
|
|
|
51758
51841
|
"undici:request:trailers",
|
|
51759
51842
|
(evt) => {
|
|
51760
51843
|
const {
|
|
51761
|
-
request: { method, path:
|
|
51844
|
+
request: { method, path: path114, origin }
|
|
51762
51845
|
} = evt;
|
|
51763
|
-
debugLog2("trailers received from %s %s%s", method, origin,
|
|
51846
|
+
debugLog2("trailers received from %s %s%s", method, origin, path114);
|
|
51764
51847
|
}
|
|
51765
51848
|
);
|
|
51766
51849
|
diagnosticsChannel.subscribe(
|
|
51767
51850
|
"undici:request:error",
|
|
51768
51851
|
(evt) => {
|
|
51769
51852
|
const {
|
|
51770
|
-
request: { method, path:
|
|
51853
|
+
request: { method, path: path114, origin },
|
|
51771
51854
|
error
|
|
51772
51855
|
} = evt;
|
|
51773
51856
|
debugLog2(
|
|
51774
51857
|
"request to %s %s%s errored - %s",
|
|
51775
51858
|
method,
|
|
51776
51859
|
origin,
|
|
51777
|
-
|
|
51860
|
+
path114,
|
|
51778
51861
|
error.message
|
|
51779
51862
|
);
|
|
51780
51863
|
}
|
|
@@ -51890,7 +51973,7 @@ var require_request = __commonJS({
|
|
|
51890
51973
|
var kHandler = /* @__PURE__ */ Symbol("handler");
|
|
51891
51974
|
var Request = class {
|
|
51892
51975
|
constructor(origin, {
|
|
51893
|
-
path:
|
|
51976
|
+
path: path114,
|
|
51894
51977
|
method,
|
|
51895
51978
|
body,
|
|
51896
51979
|
headers,
|
|
@@ -51907,11 +51990,11 @@ var require_request = __commonJS({
|
|
|
51907
51990
|
maxRedirections,
|
|
51908
51991
|
typeOfService
|
|
51909
51992
|
}, handler) {
|
|
51910
|
-
if (typeof
|
|
51993
|
+
if (typeof path114 !== "string") {
|
|
51911
51994
|
throw new InvalidArgumentError("path must be a string");
|
|
51912
|
-
} else if (
|
|
51995
|
+
} else if (path114[0] !== "/" && !(path114.startsWith("http://") || path114.startsWith("https://")) && method !== "CONNECT") {
|
|
51913
51996
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
51914
|
-
} else if (invalidPathRegex.test(
|
|
51997
|
+
} else if (invalidPathRegex.test(path114)) {
|
|
51915
51998
|
throw new InvalidArgumentError("invalid request path");
|
|
51916
51999
|
}
|
|
51917
52000
|
if (typeof method !== "string") {
|
|
@@ -51986,7 +52069,7 @@ var require_request = __commonJS({
|
|
|
51986
52069
|
this.completed = false;
|
|
51987
52070
|
this.aborted = false;
|
|
51988
52071
|
this.upgrade = upgrade || null;
|
|
51989
|
-
this.path = query ? serializePathWithQuery(
|
|
52072
|
+
this.path = query ? serializePathWithQuery(path114, query) : path114;
|
|
51990
52073
|
this.origin = origin;
|
|
51991
52074
|
this.protocol = getProtocolFromUrlString(origin);
|
|
51992
52075
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -57233,7 +57316,7 @@ var require_client_h1 = __commonJS({
|
|
|
57233
57316
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
57234
57317
|
}
|
|
57235
57318
|
function writeH1(client, request2) {
|
|
57236
|
-
const { method, path:
|
|
57319
|
+
const { method, path: path114, host: host2, upgrade, blocking, reset } = request2;
|
|
57237
57320
|
let { body, headers, contentLength } = request2;
|
|
57238
57321
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
57239
57322
|
if (util.isFormDataLike(body)) {
|
|
@@ -57311,7 +57394,7 @@ var require_client_h1 = __commonJS({
|
|
|
57311
57394
|
if (socket.setTypeOfService) {
|
|
57312
57395
|
socket.setTypeOfService(request2.typeOfService);
|
|
57313
57396
|
}
|
|
57314
|
-
let header = `${method} ${
|
|
57397
|
+
let header = `${method} ${path114} HTTP/1.1\r
|
|
57315
57398
|
`;
|
|
57316
57399
|
if (typeof host2 === "string") {
|
|
57317
57400
|
header += `host: ${host2}\r
|
|
@@ -57989,7 +58072,7 @@ var require_client_h2 = __commonJS({
|
|
|
57989
58072
|
const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout];
|
|
57990
58073
|
const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
|
|
57991
58074
|
const session = client[kHTTP2Session];
|
|
57992
|
-
const { method, path:
|
|
58075
|
+
const { method, path: path114, host: host2, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
|
|
57993
58076
|
let { body } = request2;
|
|
57994
58077
|
if (upgrade != null && upgrade !== "websocket") {
|
|
57995
58078
|
util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -58058,7 +58141,7 @@ var require_client_h2 = __commonJS({
|
|
|
58058
58141
|
}
|
|
58059
58142
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
58060
58143
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
58061
|
-
headers[HTTP2_HEADER_PATH] =
|
|
58144
|
+
headers[HTTP2_HEADER_PATH] = path114;
|
|
58062
58145
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
58063
58146
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
58064
58147
|
} else {
|
|
@@ -58110,7 +58193,7 @@ var require_client_h2 = __commonJS({
|
|
|
58110
58193
|
stream.setTimeout(headersTimeout);
|
|
58111
58194
|
return true;
|
|
58112
58195
|
}
|
|
58113
|
-
headers[HTTP2_HEADER_PATH] =
|
|
58196
|
+
headers[HTTP2_HEADER_PATH] = path114;
|
|
58114
58197
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
58115
58198
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
58116
58199
|
if (body && typeof body.read === "function") {
|
|
@@ -60477,10 +60560,10 @@ var require_proxy_agent = __commonJS({
|
|
|
60477
60560
|
};
|
|
60478
60561
|
const {
|
|
60479
60562
|
origin,
|
|
60480
|
-
path:
|
|
60563
|
+
path: path114 = "/",
|
|
60481
60564
|
headers = {}
|
|
60482
60565
|
} = opts;
|
|
60483
|
-
opts.path = origin +
|
|
60566
|
+
opts.path = origin + path114;
|
|
60484
60567
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
60485
60568
|
const { host: host2 } = new URL(origin);
|
|
60486
60569
|
headers.host = host2;
|
|
@@ -62655,20 +62738,20 @@ var require_mock_utils = __commonJS({
|
|
|
62655
62738
|
}
|
|
62656
62739
|
return normalizedQp;
|
|
62657
62740
|
}
|
|
62658
|
-
function safeUrl(
|
|
62659
|
-
if (typeof
|
|
62660
|
-
return
|
|
62741
|
+
function safeUrl(path114) {
|
|
62742
|
+
if (typeof path114 !== "string") {
|
|
62743
|
+
return path114;
|
|
62661
62744
|
}
|
|
62662
|
-
const pathSegments =
|
|
62745
|
+
const pathSegments = path114.split("?", 3);
|
|
62663
62746
|
if (pathSegments.length !== 2) {
|
|
62664
|
-
return
|
|
62747
|
+
return path114;
|
|
62665
62748
|
}
|
|
62666
62749
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
62667
62750
|
qp.sort();
|
|
62668
62751
|
return [...pathSegments, qp.toString()].join("?");
|
|
62669
62752
|
}
|
|
62670
|
-
function matchKey(mockDispatch2, { path:
|
|
62671
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
62753
|
+
function matchKey(mockDispatch2, { path: path114, method, body, headers }) {
|
|
62754
|
+
const pathMatch = matchValue(mockDispatch2.path, path114);
|
|
62672
62755
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
62673
62756
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
62674
62757
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -62693,8 +62776,8 @@ var require_mock_utils = __commonJS({
|
|
|
62693
62776
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
62694
62777
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
62695
62778
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
62696
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
62697
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
62779
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path114, ignoreTrailingSlash }) => {
|
|
62780
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path114)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path114), resolvedPath);
|
|
62698
62781
|
});
|
|
62699
62782
|
if (matchedMockDispatches.length === 0) {
|
|
62700
62783
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -62733,19 +62816,19 @@ var require_mock_utils = __commonJS({
|
|
|
62733
62816
|
mockDispatches.splice(index, 1);
|
|
62734
62817
|
}
|
|
62735
62818
|
}
|
|
62736
|
-
function removeTrailingSlash(
|
|
62737
|
-
while (
|
|
62738
|
-
|
|
62819
|
+
function removeTrailingSlash(path114) {
|
|
62820
|
+
while (path114.endsWith("/")) {
|
|
62821
|
+
path114 = path114.slice(0, -1);
|
|
62739
62822
|
}
|
|
62740
|
-
if (
|
|
62741
|
-
|
|
62823
|
+
if (path114.length === 0) {
|
|
62824
|
+
path114 = "/";
|
|
62742
62825
|
}
|
|
62743
|
-
return
|
|
62826
|
+
return path114;
|
|
62744
62827
|
}
|
|
62745
62828
|
function buildKey(opts) {
|
|
62746
|
-
const { path:
|
|
62829
|
+
const { path: path114, method, body, headers, query } = opts;
|
|
62747
62830
|
return {
|
|
62748
|
-
path:
|
|
62831
|
+
path: path114,
|
|
62749
62832
|
method,
|
|
62750
62833
|
body,
|
|
62751
62834
|
headers,
|
|
@@ -63440,10 +63523,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
63440
63523
|
}
|
|
63441
63524
|
format(pendingInterceptors) {
|
|
63442
63525
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
63443
|
-
({ method, path:
|
|
63526
|
+
({ method, path: path114, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
63444
63527
|
Method: method,
|
|
63445
63528
|
Origin: origin,
|
|
63446
|
-
Path:
|
|
63529
|
+
Path: path114,
|
|
63447
63530
|
"Status code": statusCode,
|
|
63448
63531
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
63449
63532
|
Invocations: timesInvoked,
|
|
@@ -63526,9 +63609,9 @@ var require_mock_agent = __commonJS({
|
|
|
63526
63609
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
63527
63610
|
const dispatchOpts = { ...opts };
|
|
63528
63611
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
63529
|
-
const [
|
|
63612
|
+
const [path114, searchParams] = dispatchOpts.path.split("?");
|
|
63530
63613
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
63531
|
-
dispatchOpts.path = `${
|
|
63614
|
+
dispatchOpts.path = `${path114}?${normalizedSearchParams}`;
|
|
63532
63615
|
}
|
|
63533
63616
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
63534
63617
|
}
|
|
@@ -63931,12 +64014,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63931
64014
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
63932
64015
|
*/
|
|
63933
64016
|
async loadSnapshots(filePath) {
|
|
63934
|
-
const
|
|
63935
|
-
if (!
|
|
64017
|
+
const path114 = filePath || this.#snapshotPath;
|
|
64018
|
+
if (!path114) {
|
|
63936
64019
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
63937
64020
|
}
|
|
63938
64021
|
try {
|
|
63939
|
-
const data = await readFile(resolve2(
|
|
64022
|
+
const data = await readFile(resolve2(path114), "utf8");
|
|
63940
64023
|
const parsed = JSON.parse(data);
|
|
63941
64024
|
if (Array.isArray(parsed)) {
|
|
63942
64025
|
this.#snapshots.clear();
|
|
@@ -63950,7 +64033,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63950
64033
|
if (error.code === "ENOENT") {
|
|
63951
64034
|
this.#snapshots.clear();
|
|
63952
64035
|
} else {
|
|
63953
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
64036
|
+
throw new UndiciError(`Failed to load snapshots from ${path114}`, { cause: error });
|
|
63954
64037
|
}
|
|
63955
64038
|
}
|
|
63956
64039
|
}
|
|
@@ -63961,11 +64044,11 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63961
64044
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
63962
64045
|
*/
|
|
63963
64046
|
async saveSnapshots(filePath) {
|
|
63964
|
-
const
|
|
63965
|
-
if (!
|
|
64047
|
+
const path114 = filePath || this.#snapshotPath;
|
|
64048
|
+
if (!path114) {
|
|
63966
64049
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
63967
64050
|
}
|
|
63968
|
-
const resolvedPath = resolve2(
|
|
64051
|
+
const resolvedPath = resolve2(path114);
|
|
63969
64052
|
await mkdir(dirname3(resolvedPath), { recursive: true });
|
|
63970
64053
|
const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
|
|
63971
64054
|
hash: hash2,
|
|
@@ -64606,15 +64689,15 @@ var require_redirect_handler = __commonJS({
|
|
|
64606
64689
|
}
|
|
64607
64690
|
this.history[kRedirectCacheControl].push(headers["cache-control"]);
|
|
64608
64691
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
64609
|
-
const
|
|
64610
|
-
const redirectUrlString = `${origin}${
|
|
64692
|
+
const path114 = search ? `${pathname}${search}` : pathname;
|
|
64693
|
+
const redirectUrlString = `${origin}${path114}`;
|
|
64611
64694
|
for (const historyUrl of this.history) {
|
|
64612
64695
|
if (historyUrl.toString() === redirectUrlString) {
|
|
64613
64696
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
64614
64697
|
}
|
|
64615
64698
|
}
|
|
64616
64699
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
64617
|
-
this.opts.path =
|
|
64700
|
+
this.opts.path = path114;
|
|
64618
64701
|
this.opts.origin = origin;
|
|
64619
64702
|
this.opts.query = null;
|
|
64620
64703
|
}
|
|
@@ -66390,10 +66473,10 @@ var require_cache_handler = __commonJS({
|
|
|
66390
66473
|
}
|
|
66391
66474
|
return locationUrl.pathname + locationUrl.search;
|
|
66392
66475
|
}
|
|
66393
|
-
function deleteCachedUri(store, cacheKey,
|
|
66476
|
+
function deleteCachedUri(store, cacheKey, path114) {
|
|
66394
66477
|
deleteCachedValue(store, {
|
|
66395
66478
|
...cacheKey,
|
|
66396
|
-
path:
|
|
66479
|
+
path: path114
|
|
66397
66480
|
});
|
|
66398
66481
|
for (let i = 0; i < util.safeHTTPMethods.length; i++) {
|
|
66399
66482
|
const method = util.safeHTTPMethods[i];
|
|
@@ -66401,7 +66484,7 @@ var require_cache_handler = __commonJS({
|
|
|
66401
66484
|
deleteCachedValue(store, {
|
|
66402
66485
|
...cacheKey,
|
|
66403
66486
|
method,
|
|
66404
|
-
path:
|
|
66487
|
+
path: path114
|
|
66405
66488
|
});
|
|
66406
66489
|
}
|
|
66407
66490
|
}
|
|
@@ -66412,9 +66495,9 @@ var require_cache_handler = __commonJS({
|
|
|
66412
66495
|
}
|
|
66413
66496
|
const values = Array.isArray(headerValue) ? headerValue : [headerValue];
|
|
66414
66497
|
for (let i = 0; i < values.length; i++) {
|
|
66415
|
-
const
|
|
66416
|
-
if (
|
|
66417
|
-
deleteCachedUri(store, cacheKey,
|
|
66498
|
+
const path114 = getSameOriginPath(cacheKey, values[i]);
|
|
66499
|
+
if (path114 !== void 0) {
|
|
66500
|
+
deleteCachedUri(store, cacheKey, path114);
|
|
66418
66501
|
}
|
|
66419
66502
|
}
|
|
66420
66503
|
}
|
|
@@ -71637,11 +71720,11 @@ var require_fetch = __commonJS({
|
|
|
71637
71720
|
function dispatch({ body }) {
|
|
71638
71721
|
const url = requestCurrentURL(request2);
|
|
71639
71722
|
const agent = fetchParams.controller.dispatcher;
|
|
71640
|
-
const
|
|
71723
|
+
const path114 = url.pathname + url.search;
|
|
71641
71724
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
71642
71725
|
return new Promise((resolve2, reject) => agent.dispatch(
|
|
71643
71726
|
{
|
|
71644
|
-
path: hasTrailingQuestionMark ? `${
|
|
71727
|
+
path: hasTrailingQuestionMark ? `${path114}?` : path114,
|
|
71645
71728
|
origin: url.origin,
|
|
71646
71729
|
method: request2.method,
|
|
71647
71730
|
body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
|
|
@@ -72593,9 +72676,9 @@ var require_util4 = __commonJS({
|
|
|
72593
72676
|
}
|
|
72594
72677
|
}
|
|
72595
72678
|
}
|
|
72596
|
-
function validateCookiePath(
|
|
72597
|
-
for (let i = 0; i <
|
|
72598
|
-
const code2 =
|
|
72679
|
+
function validateCookiePath(path114) {
|
|
72680
|
+
for (let i = 0; i < path114.length; ++i) {
|
|
72681
|
+
const code2 = path114.charCodeAt(i);
|
|
72599
72682
|
if (code2 < 32 || // exclude CTLs (0-31)
|
|
72600
72683
|
code2 > 126 || // exclude DEL and non-ascii
|
|
72601
72684
|
code2 === 59) {
|
|
@@ -76048,11 +76131,11 @@ var require_undici = __commonJS({
|
|
|
76048
76131
|
if (typeof opts.path !== "string") {
|
|
76049
76132
|
throw new InvalidArgumentError("invalid opts.path");
|
|
76050
76133
|
}
|
|
76051
|
-
let
|
|
76134
|
+
let path114 = opts.path;
|
|
76052
76135
|
if (!opts.path.startsWith("/")) {
|
|
76053
|
-
|
|
76136
|
+
path114 = `/${path114}`;
|
|
76054
76137
|
}
|
|
76055
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
76138
|
+
url = new URL(util.parseOrigin(url).origin + path114);
|
|
76056
76139
|
} else {
|
|
76057
76140
|
if (!opts) {
|
|
76058
76141
|
opts = typeof url === "object" ? url : {};
|
|
@@ -76174,10 +76257,10 @@ function readFirstRunEnv() {
|
|
|
76174
76257
|
stdinTTY: !!process.stdin.isTTY,
|
|
76175
76258
|
stdoutTTY: !!process.stdout.isTTY,
|
|
76176
76259
|
ci: isCI() || process.env.NODE9_NONINTERACTIVE === "1",
|
|
76177
|
-
hasConfig:
|
|
76260
|
+
hasConfig: import_fs107.default.existsSync(import_path106.default.join(import_os87.default.homedir(), ".node9/config.json")),
|
|
76178
76261
|
// Any stored profile means this is not a never-configured machine. Treat
|
|
76179
76262
|
// malformed credential files conservatively and leave repair to explicit setup.
|
|
76180
|
-
hasCredentials: !!getCredentials() ||
|
|
76263
|
+
hasCredentials: !!getCredentials() || import_fs107.default.existsSync(import_path106.default.join(import_os87.default.homedir(), ".node9/credentials.json"))
|
|
76181
76264
|
};
|
|
76182
76265
|
}
|
|
76183
76266
|
function shouldOfferFirstRun(env) {
|
|
@@ -76282,14 +76365,14 @@ async function runSetupWizard(opts) {
|
|
|
76282
76365
|
process.exitCode = 130;
|
|
76283
76366
|
}
|
|
76284
76367
|
}
|
|
76285
|
-
var
|
|
76368
|
+
var import_fs107, import_os87, import_path106;
|
|
76286
76369
|
var init_first_run = __esm({
|
|
76287
76370
|
"src/cli/first-run.ts"() {
|
|
76288
76371
|
"use strict";
|
|
76289
76372
|
init_cjs_shims();
|
|
76290
|
-
|
|
76291
|
-
|
|
76292
|
-
|
|
76373
|
+
import_fs107 = __toESM(require("fs"));
|
|
76374
|
+
import_os87 = __toESM(require("os"));
|
|
76375
|
+
import_path106 = __toESM(require("path"));
|
|
76293
76376
|
init_config();
|
|
76294
76377
|
init_agent_wiring();
|
|
76295
76378
|
init_browser_login();
|
|
@@ -76335,20 +76418,20 @@ function getModelContextLimit(model) {
|
|
|
76335
76418
|
return 2e5;
|
|
76336
76419
|
}
|
|
76337
76420
|
function readSessionUsage() {
|
|
76338
|
-
const projectsDir =
|
|
76339
|
-
if (!
|
|
76421
|
+
const projectsDir = import_path107.default.join(import_os88.default.homedir(), ".claude", "projects");
|
|
76422
|
+
if (!import_fs108.default.existsSync(projectsDir)) return null;
|
|
76340
76423
|
let latestFile = null;
|
|
76341
76424
|
let latestMtime = 0;
|
|
76342
76425
|
try {
|
|
76343
|
-
for (const dir2 of
|
|
76344
|
-
const dirPath =
|
|
76426
|
+
for (const dir2 of import_fs108.default.readdirSync(projectsDir)) {
|
|
76427
|
+
const dirPath = import_path107.default.join(projectsDir, dir2);
|
|
76345
76428
|
try {
|
|
76346
|
-
if (!
|
|
76347
|
-
for (const file2 of
|
|
76429
|
+
if (!import_fs108.default.statSync(dirPath).isDirectory()) continue;
|
|
76430
|
+
for (const file2 of import_fs108.default.readdirSync(dirPath)) {
|
|
76348
76431
|
if (!file2.endsWith(".jsonl") || file2.startsWith("agent-")) continue;
|
|
76349
|
-
const filePath =
|
|
76432
|
+
const filePath = import_path107.default.join(dirPath, file2);
|
|
76350
76433
|
try {
|
|
76351
|
-
const mtime =
|
|
76434
|
+
const mtime = import_fs108.default.statSync(filePath).mtimeMs;
|
|
76352
76435
|
if (mtime > latestMtime) {
|
|
76353
76436
|
latestMtime = mtime;
|
|
76354
76437
|
latestFile = filePath;
|
|
@@ -76363,7 +76446,7 @@ function readSessionUsage() {
|
|
|
76363
76446
|
}
|
|
76364
76447
|
if (!latestFile) return null;
|
|
76365
76448
|
try {
|
|
76366
|
-
const lines =
|
|
76449
|
+
const lines = import_fs108.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
76367
76450
|
let lastModel = "";
|
|
76368
76451
|
let lastInput = 0;
|
|
76369
76452
|
let lastOutput = 0;
|
|
@@ -76424,7 +76507,7 @@ function formatBase(activity) {
|
|
|
76424
76507
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
76425
76508
|
const icon = getIcon(activity.tool);
|
|
76426
76509
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
76427
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
76510
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os88.default.homedir(), "~");
|
|
76428
76511
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
76429
76512
|
return `${import_chalk49.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk49.default.white.bold(toolName)} ${import_chalk49.default.dim(argsPreview)}`;
|
|
76430
76513
|
}
|
|
@@ -76442,12 +76525,12 @@ function renderResult(activity, result) {
|
|
|
76442
76525
|
const costSuffix = cost == null ? "" : import_chalk49.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
|
|
76443
76526
|
if (process.stdout.isTTY) {
|
|
76444
76527
|
if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
|
|
76445
|
-
|
|
76446
|
-
|
|
76528
|
+
import_readline6.default.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
|
|
76529
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
76447
76530
|
process.stdout.write(ERASE_DOWN);
|
|
76448
76531
|
} else {
|
|
76449
|
-
|
|
76450
|
-
|
|
76532
|
+
import_readline6.default.clearLine(process.stdout, 0);
|
|
76533
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
76451
76534
|
}
|
|
76452
76535
|
pendingShownForId = null;
|
|
76453
76536
|
pendingWrappedLines = 0;
|
|
@@ -76463,9 +76546,9 @@ function renderPending(activity) {
|
|
|
76463
76546
|
}
|
|
76464
76547
|
async function ensureDaemon() {
|
|
76465
76548
|
let pidPort = null;
|
|
76466
|
-
if (
|
|
76549
|
+
if (import_fs108.default.existsSync(PID_FILE)) {
|
|
76467
76550
|
try {
|
|
76468
|
-
const { port } = JSON.parse(
|
|
76551
|
+
const { port } = JSON.parse(import_fs108.default.readFileSync(PID_FILE, "utf-8"));
|
|
76469
76552
|
pidPort = port;
|
|
76470
76553
|
} catch {
|
|
76471
76554
|
console.error(import_chalk49.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -76491,7 +76574,7 @@ async function ensureDaemon() {
|
|
|
76491
76574
|
child.unref();
|
|
76492
76575
|
if (startupFd !== void 0) {
|
|
76493
76576
|
try {
|
|
76494
|
-
|
|
76577
|
+
import_fs108.default.closeSync(startupFd);
|
|
76495
76578
|
} catch {
|
|
76496
76579
|
}
|
|
76497
76580
|
}
|
|
@@ -76735,7 +76818,7 @@ async function startTail(options = {}) {
|
|
|
76735
76818
|
let cancelActiveCard = null;
|
|
76736
76819
|
const localAllowCounts = /* @__PURE__ */ new Map();
|
|
76737
76820
|
const canApprove = process.stdout.isTTY && process.stdin.isTTY;
|
|
76738
|
-
if (canApprove)
|
|
76821
|
+
if (canApprove) import_readline6.default.emitKeypressEvents(process.stdin);
|
|
76739
76822
|
let idleKeypressHandler = null;
|
|
76740
76823
|
function enterIdleMode() {
|
|
76741
76824
|
if (!canApprove || idleKeypressHandler !== null) return;
|
|
@@ -76776,7 +76859,7 @@ async function startTail(options = {}) {
|
|
|
76776
76859
|
}
|
|
76777
76860
|
function clearCard() {
|
|
76778
76861
|
if (cardLineCount > 0) {
|
|
76779
|
-
|
|
76862
|
+
import_readline6.default.moveCursor(process.stdout, 0, -cardLineCount);
|
|
76780
76863
|
process.stdout.write(ERASE_DOWN);
|
|
76781
76864
|
cardLineCount = 0;
|
|
76782
76865
|
}
|
|
@@ -76861,8 +76944,8 @@ async function startTail(options = {}) {
|
|
|
76861
76944
|
);
|
|
76862
76945
|
}).catch((err2) => {
|
|
76863
76946
|
try {
|
|
76864
|
-
|
|
76865
|
-
|
|
76947
|
+
import_fs108.default.appendFileSync(
|
|
76948
|
+
import_path107.default.join(import_os88.default.homedir(), ".node9", "hook-debug.log"),
|
|
76866
76949
|
`[tail] POST /decision failed: ${String(err2)}
|
|
76867
76950
|
`
|
|
76868
76951
|
);
|
|
@@ -76928,9 +77011,9 @@ async function startTail(options = {}) {
|
|
|
76928
77011
|
};
|
|
76929
77012
|
process.stdin.on("keypress", onKeypress);
|
|
76930
77013
|
}
|
|
76931
|
-
const auditLog =
|
|
77014
|
+
const auditLog = import_path107.default.join(import_os88.default.homedir(), ".node9", "audit.log");
|
|
76932
77015
|
try {
|
|
76933
|
-
const unackedDlp =
|
|
77016
|
+
const unackedDlp = import_fs108.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
76934
77017
|
if (unackedDlp > 0) {
|
|
76935
77018
|
console.log("");
|
|
76936
77019
|
console.log(
|
|
@@ -76959,8 +77042,8 @@ async function startTail(options = {}) {
|
|
|
76959
77042
|
clearCard();
|
|
76960
77043
|
process.stdout.write(SHOW_CURSOR);
|
|
76961
77044
|
if (process.stdout.isTTY) {
|
|
76962
|
-
|
|
76963
|
-
|
|
77045
|
+
import_readline6.default.clearLine(process.stdout, 0);
|
|
77046
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
76964
77047
|
}
|
|
76965
77048
|
console.log(import_chalk49.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
|
|
76966
77049
|
process.exit(0);
|
|
@@ -76970,7 +77053,7 @@ async function startTail(options = {}) {
|
|
|
76970
77053
|
if (stallWarned) return;
|
|
76971
77054
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
76972
77055
|
try {
|
|
76973
|
-
const auditMtime =
|
|
77056
|
+
const auditMtime = import_fs108.default.statSync(auditLog).mtimeMs;
|
|
76974
77057
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
76975
77058
|
console.log("");
|
|
76976
77059
|
console.log(
|
|
@@ -76999,7 +77082,7 @@ async function startTail(options = {}) {
|
|
|
76999
77082
|
let currentData = "";
|
|
77000
77083
|
res.on("error", () => {
|
|
77001
77084
|
});
|
|
77002
|
-
const rl =
|
|
77085
|
+
const rl = import_readline6.default.createInterface({ input: res, crlfDelay: Infinity });
|
|
77003
77086
|
rl.on("error", () => {
|
|
77004
77087
|
});
|
|
77005
77088
|
rl.on("line", (line) => {
|
|
@@ -77019,8 +77102,8 @@ async function startTail(options = {}) {
|
|
|
77019
77102
|
clearCard();
|
|
77020
77103
|
process.stdout.write(SHOW_CURSOR);
|
|
77021
77104
|
if (process.stdout.isTTY) {
|
|
77022
|
-
|
|
77023
|
-
|
|
77105
|
+
import_readline6.default.clearLine(process.stdout, 0);
|
|
77106
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
77024
77107
|
}
|
|
77025
77108
|
console.log(import_chalk49.default.red("\n\u274C Daemon disconnected."));
|
|
77026
77109
|
process.exit(1);
|
|
@@ -77142,7 +77225,7 @@ async function startTail(options = {}) {
|
|
|
77142
77225
|
process.exit(1);
|
|
77143
77226
|
});
|
|
77144
77227
|
}
|
|
77145
|
-
var import_http6, import_chalk49,
|
|
77228
|
+
var import_http6, import_chalk49, import_fs108, import_os88, import_path107, import_readline6, import_child_process17, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET, BOLD, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
77146
77229
|
var init_tail = __esm({
|
|
77147
77230
|
"src/tui/tail.ts"() {
|
|
77148
77231
|
"use strict";
|
|
@@ -77150,16 +77233,16 @@ var init_tail = __esm({
|
|
|
77150
77233
|
import_http6 = __toESM(require("http"));
|
|
77151
77234
|
init_write();
|
|
77152
77235
|
import_chalk49 = __toESM(require("chalk"));
|
|
77153
|
-
|
|
77154
|
-
|
|
77155
|
-
|
|
77156
|
-
|
|
77236
|
+
import_fs108 = __toESM(require("fs"));
|
|
77237
|
+
import_os88 = __toESM(require("os"));
|
|
77238
|
+
import_path107 = __toESM(require("path"));
|
|
77239
|
+
import_readline6 = __toESM(require("readline"));
|
|
77157
77240
|
import_child_process17 = require("child_process");
|
|
77158
77241
|
init_startup_log();
|
|
77159
77242
|
init_daemon3();
|
|
77160
77243
|
init_daemon();
|
|
77161
77244
|
init_safe_text();
|
|
77162
|
-
PID_FILE =
|
|
77245
|
+
PID_FILE = import_path107.default.join(import_os88.default.homedir(), ".node9", "daemon.pid");
|
|
77163
77246
|
ICONS = {
|
|
77164
77247
|
bash: "\u{1F4BB}",
|
|
77165
77248
|
shell: "\u{1F4BB}",
|
|
@@ -77281,9 +77364,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
77281
77364
|
return ` (${m}m left)`;
|
|
77282
77365
|
}
|
|
77283
77366
|
function safeReadJson(filePath) {
|
|
77284
|
-
if (!
|
|
77367
|
+
if (!import_fs109.default.existsSync(filePath)) return null;
|
|
77285
77368
|
try {
|
|
77286
|
-
return JSON.parse(
|
|
77369
|
+
return JSON.parse(import_fs109.default.readFileSync(filePath, "utf-8"));
|
|
77287
77370
|
} catch {
|
|
77288
77371
|
return null;
|
|
77289
77372
|
}
|
|
@@ -77304,12 +77387,12 @@ function countHooksInFile(filePath) {
|
|
|
77304
77387
|
return Object.keys(cfg.hooks).length;
|
|
77305
77388
|
}
|
|
77306
77389
|
function countRulesInDir(rulesDir) {
|
|
77307
|
-
if (!
|
|
77390
|
+
if (!import_fs109.default.existsSync(rulesDir)) return 0;
|
|
77308
77391
|
let count = 0;
|
|
77309
77392
|
try {
|
|
77310
|
-
for (const entry of
|
|
77393
|
+
for (const entry of import_fs109.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
77311
77394
|
if (entry.isDirectory()) {
|
|
77312
|
-
count += countRulesInDir(
|
|
77395
|
+
count += countRulesInDir(import_path108.default.join(rulesDir, entry.name));
|
|
77313
77396
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
77314
77397
|
count++;
|
|
77315
77398
|
}
|
|
@@ -77320,46 +77403,46 @@ function countRulesInDir(rulesDir) {
|
|
|
77320
77403
|
}
|
|
77321
77404
|
function isSamePath(a, b) {
|
|
77322
77405
|
try {
|
|
77323
|
-
return
|
|
77406
|
+
return import_path108.default.resolve(a) === import_path108.default.resolve(b);
|
|
77324
77407
|
} catch {
|
|
77325
77408
|
return false;
|
|
77326
77409
|
}
|
|
77327
77410
|
}
|
|
77328
77411
|
function countConfigs(cwd) {
|
|
77329
|
-
const homeDir2 =
|
|
77330
|
-
const claudeDir =
|
|
77412
|
+
const homeDir2 = import_os89.default.homedir();
|
|
77413
|
+
const claudeDir = import_path108.default.join(homeDir2, ".claude");
|
|
77331
77414
|
let claudeMdCount = 0;
|
|
77332
77415
|
let rulesCount = 0;
|
|
77333
77416
|
let hooksCount = 0;
|
|
77334
77417
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
77335
77418
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
77336
|
-
if (
|
|
77337
|
-
rulesCount += countRulesInDir(
|
|
77338
|
-
const userSettings =
|
|
77419
|
+
if (import_fs109.default.existsSync(import_path108.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
77420
|
+
rulesCount += countRulesInDir(import_path108.default.join(claudeDir, "rules"));
|
|
77421
|
+
const userSettings = import_path108.default.join(claudeDir, "settings.json");
|
|
77339
77422
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
77340
77423
|
hooksCount += countHooksInFile(userSettings);
|
|
77341
|
-
const userClaudeJson =
|
|
77424
|
+
const userClaudeJson = import_path108.default.join(homeDir2, ".claude.json");
|
|
77342
77425
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
77343
77426
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
77344
77427
|
userMcpServers.delete(name);
|
|
77345
77428
|
}
|
|
77346
77429
|
if (cwd) {
|
|
77347
|
-
if (
|
|
77348
|
-
if (
|
|
77349
|
-
const projectClaudeDir =
|
|
77430
|
+
if (import_fs109.default.existsSync(import_path108.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
77431
|
+
if (import_fs109.default.existsSync(import_path108.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
77432
|
+
const projectClaudeDir = import_path108.default.join(cwd, ".claude");
|
|
77350
77433
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
77351
77434
|
if (!overlapsUserScope) {
|
|
77352
|
-
if (
|
|
77353
|
-
rulesCount += countRulesInDir(
|
|
77354
|
-
const projSettings =
|
|
77435
|
+
if (import_fs109.default.existsSync(import_path108.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
77436
|
+
rulesCount += countRulesInDir(import_path108.default.join(projectClaudeDir, "rules"));
|
|
77437
|
+
const projSettings = import_path108.default.join(projectClaudeDir, "settings.json");
|
|
77355
77438
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
77356
77439
|
hooksCount += countHooksInFile(projSettings);
|
|
77357
77440
|
}
|
|
77358
|
-
if (
|
|
77359
|
-
const localSettings =
|
|
77441
|
+
if (import_fs109.default.existsSync(import_path108.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
77442
|
+
const localSettings = import_path108.default.join(projectClaudeDir, "settings.local.json");
|
|
77360
77443
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
77361
77444
|
hooksCount += countHooksInFile(localSettings);
|
|
77362
|
-
const mcpJsonServers = getMcpServerNames(
|
|
77445
|
+
const mcpJsonServers = getMcpServerNames(import_path108.default.join(cwd, ".mcp.json"));
|
|
77363
77446
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
77364
77447
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
77365
77448
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -77392,12 +77475,12 @@ function readActiveShieldsHud() {
|
|
|
77392
77475
|
return shieldsCache.value;
|
|
77393
77476
|
}
|
|
77394
77477
|
try {
|
|
77395
|
-
const shieldsPath =
|
|
77396
|
-
if (!
|
|
77478
|
+
const shieldsPath = import_path108.default.join(import_os89.default.homedir(), ".node9", "shields.json");
|
|
77479
|
+
if (!import_fs109.default.existsSync(shieldsPath)) {
|
|
77397
77480
|
shieldsCache = { value: [], ts: now };
|
|
77398
77481
|
return [];
|
|
77399
77482
|
}
|
|
77400
|
-
const parsed = JSON.parse(
|
|
77483
|
+
const parsed = JSON.parse(import_fs109.default.readFileSync(shieldsPath, "utf-8"));
|
|
77401
77484
|
if (!Array.isArray(parsed.active)) {
|
|
77402
77485
|
shieldsCache = { value: [], ts: now };
|
|
77403
77486
|
return [];
|
|
@@ -77499,17 +77582,17 @@ function renderContextLine(stdin) {
|
|
|
77499
77582
|
async function main() {
|
|
77500
77583
|
try {
|
|
77501
77584
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
77502
|
-
if (
|
|
77585
|
+
if (import_fs109.default.existsSync(import_path108.default.join(import_os89.default.homedir(), ".node9", "hud-debug"))) {
|
|
77503
77586
|
try {
|
|
77504
|
-
const logPath =
|
|
77587
|
+
const logPath = import_path108.default.join(import_os89.default.homedir(), ".node9", "hud-debug.log");
|
|
77505
77588
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
77506
77589
|
let size = 0;
|
|
77507
77590
|
try {
|
|
77508
|
-
size =
|
|
77591
|
+
size = import_fs109.default.statSync(logPath).size;
|
|
77509
77592
|
} catch {
|
|
77510
77593
|
}
|
|
77511
77594
|
if (size < MAX_LOG_SIZE) {
|
|
77512
|
-
|
|
77595
|
+
import_fs109.default.appendFileSync(
|
|
77513
77596
|
logPath,
|
|
77514
77597
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
77515
77598
|
);
|
|
@@ -77530,11 +77613,11 @@ async function main() {
|
|
|
77530
77613
|
try {
|
|
77531
77614
|
const cwd = stdin.cwd ?? process.cwd();
|
|
77532
77615
|
for (const configPath2 of [
|
|
77533
|
-
|
|
77534
|
-
|
|
77616
|
+
import_path108.default.join(cwd, "node9.config.json"),
|
|
77617
|
+
import_path108.default.join(import_os89.default.homedir(), ".node9", "config.json")
|
|
77535
77618
|
]) {
|
|
77536
|
-
if (!
|
|
77537
|
-
const cfg = JSON.parse(
|
|
77619
|
+
if (!import_fs109.default.existsSync(configPath2)) continue;
|
|
77620
|
+
const cfg = JSON.parse(import_fs109.default.readFileSync(configPath2, "utf-8"));
|
|
77538
77621
|
const hud = cfg.settings?.hud;
|
|
77539
77622
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
77540
77623
|
}
|
|
@@ -77552,14 +77635,14 @@ async function main() {
|
|
|
77552
77635
|
renderOffline();
|
|
77553
77636
|
}
|
|
77554
77637
|
}
|
|
77555
|
-
var
|
|
77638
|
+
var import_fs109, import_path108, import_os89, import_http7, RESET2, BOLD2, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
77556
77639
|
var init_hud = __esm({
|
|
77557
77640
|
"src/cli/hud.ts"() {
|
|
77558
77641
|
"use strict";
|
|
77559
77642
|
init_cjs_shims();
|
|
77560
|
-
|
|
77561
|
-
|
|
77562
|
-
|
|
77643
|
+
import_fs109 = __toESM(require("fs"));
|
|
77644
|
+
import_path108 = __toESM(require("path"));
|
|
77645
|
+
import_os89 = __toESM(require("os"));
|
|
77563
77646
|
import_http7 = __toESM(require("http"));
|
|
77564
77647
|
init_daemon();
|
|
77565
77648
|
init_dist();
|
|
@@ -77624,9 +77707,9 @@ init_agent_wiring();
|
|
|
77624
77707
|
init_credentials();
|
|
77625
77708
|
init_daemon3();
|
|
77626
77709
|
var import_chalk50 = __toESM(require("chalk"));
|
|
77627
|
-
var
|
|
77628
|
-
var
|
|
77629
|
-
var
|
|
77710
|
+
var import_fs110 = __toESM(require("fs"));
|
|
77711
|
+
var import_path109 = __toESM(require("path"));
|
|
77712
|
+
var import_os90 = __toESM(require("os"));
|
|
77630
77713
|
var import_prompts4 = require("@inquirer/prompts");
|
|
77631
77714
|
|
|
77632
77715
|
// src/utils/duration.ts
|
|
@@ -78697,6 +78780,7 @@ init_audit();
|
|
|
78697
78780
|
init_config();
|
|
78698
78781
|
init_daemon();
|
|
78699
78782
|
init_dist();
|
|
78783
|
+
init_shell_fetch();
|
|
78700
78784
|
|
|
78701
78785
|
// src/exposure/source.ts
|
|
78702
78786
|
init_cjs_shims();
|
|
@@ -78921,11 +79005,6 @@ function buildArgsField(rawInput) {
|
|
|
78921
79005
|
return hashed;
|
|
78922
79006
|
}
|
|
78923
79007
|
}
|
|
78924
|
-
function shellFetch(tool, rawInput) {
|
|
78925
|
-
if (tool !== "Bash" && tool !== "bash") return null;
|
|
78926
|
-
const cmd = rawInput && typeof rawInput === "object" && !Array.isArray(rawInput) ? rawInput.command : void 0;
|
|
78927
|
-
return typeof cmd === "string" && cmd.length > 0 ? classifyShellExposure(cmd) : null;
|
|
78928
|
-
}
|
|
78929
79008
|
function registerLogCommand(program2) {
|
|
78930
79009
|
program2.command("log", { hidden: true }).description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").option(
|
|
78931
79010
|
"--agent <name>",
|
|
@@ -85566,6 +85645,374 @@ function registerAgentsCommand(program2) {
|
|
|
85566
85645
|
// src/cli.ts
|
|
85567
85646
|
init_scan();
|
|
85568
85647
|
|
|
85648
|
+
// src/cli/commands/forecast-cases.ts
|
|
85649
|
+
init_cjs_shims();
|
|
85650
|
+
var import_fs96 = __toESM(require("fs"));
|
|
85651
|
+
var import_os80 = __toESM(require("os"));
|
|
85652
|
+
var import_path95 = __toESM(require("path"));
|
|
85653
|
+
var import_readline5 = __toESM(require("readline"));
|
|
85654
|
+
init_dist();
|
|
85655
|
+
init_config();
|
|
85656
|
+
init_forecast();
|
|
85657
|
+
init_scan_judge();
|
|
85658
|
+
init_dlp();
|
|
85659
|
+
init_jail();
|
|
85660
|
+
init_registry2();
|
|
85661
|
+
init_version();
|
|
85662
|
+
init_sync();
|
|
85663
|
+
function materialize(t, env) {
|
|
85664
|
+
if (typeof t === "string")
|
|
85665
|
+
return t.replaceAll("{{HOME}}", env.home).replaceAll("{{CWD}}", env.cwd);
|
|
85666
|
+
if (t === null || typeof t !== "object") return t;
|
|
85667
|
+
if (Array.isArray(t)) return t.map((x) => materialize(x, env));
|
|
85668
|
+
const o = t;
|
|
85669
|
+
const keys = Object.keys(o);
|
|
85670
|
+
if (keys.length === 1 && keys[0] === "$join" && Array.isArray(o.$join))
|
|
85671
|
+
return materialize(o.$join.join(""), env);
|
|
85672
|
+
const out = {};
|
|
85673
|
+
for (const [k, v] of Object.entries(o)) out[k] = materialize(v, env);
|
|
85674
|
+
return out;
|
|
85675
|
+
}
|
|
85676
|
+
var PROFILE_NEEDS = {
|
|
85677
|
+
clean: null,
|
|
85678
|
+
"asb-sandbox": null,
|
|
85679
|
+
"git-guardrails": null,
|
|
85680
|
+
"jailed-agent": "user-jail-path",
|
|
85681
|
+
"user-jail": "user-jail-path",
|
|
85682
|
+
"org-jail": "managed-jail-path",
|
|
85683
|
+
canary: "decoy",
|
|
85684
|
+
"egress-lock": "egress-block",
|
|
85685
|
+
"egress-watch": "egress-gated",
|
|
85686
|
+
"exposure-org": "organisation-domain",
|
|
85687
|
+
"ask-before-dangerous-actions": "hold-action-checks",
|
|
85688
|
+
"injection-optin": "injection-scan"
|
|
85689
|
+
};
|
|
85690
|
+
function profileNeed(setup) {
|
|
85691
|
+
if (setup in PROFILE_NEEDS) return PROFILE_NEEDS[setup];
|
|
85692
|
+
if (setup.startsWith("egress-deny-")) return "egress-deny-list";
|
|
85693
|
+
return void 0;
|
|
85694
|
+
}
|
|
85695
|
+
function homeHas(config) {
|
|
85696
|
+
const settings = catalogSettingsFrom(config.settings, config.policy);
|
|
85697
|
+
const value = (id) => checkValue(settings, id);
|
|
85698
|
+
const egress = config.policy.egress;
|
|
85699
|
+
const gated = !!egress?.enabled && (egress.mode === "block" || egress.mode === "review");
|
|
85700
|
+
let userJail = false;
|
|
85701
|
+
try {
|
|
85702
|
+
userJail = readJailPaths().length > 0;
|
|
85703
|
+
} catch {
|
|
85704
|
+
userJail = false;
|
|
85705
|
+
}
|
|
85706
|
+
let decoy = false;
|
|
85707
|
+
try {
|
|
85708
|
+
decoy = loadCanaries().length > 0;
|
|
85709
|
+
} catch {
|
|
85710
|
+
decoy = false;
|
|
85711
|
+
}
|
|
85712
|
+
const held = (id) => value(id) === "review" || value(id) === "block";
|
|
85713
|
+
return {
|
|
85714
|
+
"user-jail-path": userJail,
|
|
85715
|
+
"managed-jail-path": (config.policy.managedJailPaths ?? []).length > 0,
|
|
85716
|
+
decoy,
|
|
85717
|
+
"egress-block": !!egress?.enabled && egress.mode === "block",
|
|
85718
|
+
"egress-gated": gated,
|
|
85719
|
+
"egress-deny-list": gated && (egress?.deny?.length ?? 0) > 0,
|
|
85720
|
+
"organisation-domain": (config.policy.untrustedContent?.orgDomains ?? []).length > 0,
|
|
85721
|
+
"hold-action-checks": held("actions.money") && held("actions.access") && held("actions.publish"),
|
|
85722
|
+
"injection-scan": value("behavior.prompt-injection") !== "off"
|
|
85723
|
+
};
|
|
85724
|
+
}
|
|
85725
|
+
var emptyCell = () => ({
|
|
85726
|
+
attacks: 0,
|
|
85727
|
+
stopped: 0,
|
|
85728
|
+
loggedOnly: 0,
|
|
85729
|
+
passed: 0,
|
|
85730
|
+
benign: 0,
|
|
85731
|
+
interrupted: 0,
|
|
85732
|
+
notApplicable: 0,
|
|
85733
|
+
notSimulated: 0,
|
|
85734
|
+
volatile: 0,
|
|
85735
|
+
undetermined: 0,
|
|
85736
|
+
errors: 0
|
|
85737
|
+
});
|
|
85738
|
+
function summarize(results, config) {
|
|
85739
|
+
const settings = catalogSettingsFrom(config.settings, config.policy);
|
|
85740
|
+
const byRisk = {};
|
|
85741
|
+
const passedByCheck = {};
|
|
85742
|
+
const passedUnattributed = {};
|
|
85743
|
+
const notApplicableBy = {};
|
|
85744
|
+
const cell = (r) => {
|
|
85745
|
+
const risk = byRisk[r.owasp] ??= {
|
|
85746
|
+
headline: emptyCell(),
|
|
85747
|
+
vendor: emptyCell(),
|
|
85748
|
+
unknown: emptyCell()
|
|
85749
|
+
};
|
|
85750
|
+
return risk[r.section];
|
|
85751
|
+
};
|
|
85752
|
+
for (const r of results) {
|
|
85753
|
+
const c = cell(r);
|
|
85754
|
+
if (r.error) {
|
|
85755
|
+
c.errors++;
|
|
85756
|
+
continue;
|
|
85757
|
+
}
|
|
85758
|
+
if (r.notApplicable) {
|
|
85759
|
+
c.notApplicable++;
|
|
85760
|
+
notApplicableBy[r.notApplicable] = (notApplicableBy[r.notApplicable] ?? 0) + 1;
|
|
85761
|
+
continue;
|
|
85762
|
+
}
|
|
85763
|
+
if (r.notSimulated) {
|
|
85764
|
+
c.notSimulated++;
|
|
85765
|
+
continue;
|
|
85766
|
+
}
|
|
85767
|
+
if (r.volatile) {
|
|
85768
|
+
c.volatile++;
|
|
85769
|
+
continue;
|
|
85770
|
+
}
|
|
85771
|
+
const stopped = r.enforced === true && (r.decision === "review" || r.decision === "block");
|
|
85772
|
+
const recorded = !stopped && r.decision !== void 0 && r.decision !== "allow";
|
|
85773
|
+
if (r.expected === "allow") {
|
|
85774
|
+
c.benign++;
|
|
85775
|
+
if (stopped) c.interrupted++;
|
|
85776
|
+
continue;
|
|
85777
|
+
}
|
|
85778
|
+
const notEnforcedStop = r.enforced === false && (r.decision === "review" || r.decision === "block");
|
|
85779
|
+
if (!stopped && !notEnforcedStop && (r.unknown?.length ?? 0) > 0) {
|
|
85780
|
+
c.undetermined++;
|
|
85781
|
+
continue;
|
|
85782
|
+
}
|
|
85783
|
+
c.attacks++;
|
|
85784
|
+
if (stopped) c.stopped++;
|
|
85785
|
+
else if (recorded) {
|
|
85786
|
+
c.loggedOnly++;
|
|
85787
|
+
if (r.checkId) {
|
|
85788
|
+
const e = passedByCheck[r.checkId] ??= {
|
|
85789
|
+
value: checkValue(settings, r.checkId),
|
|
85790
|
+
count: 0
|
|
85791
|
+
};
|
|
85792
|
+
e.count++;
|
|
85793
|
+
} else passedUnattributed[r.owasp] = (passedUnattributed[r.owasp] ?? 0) + 1;
|
|
85794
|
+
} else {
|
|
85795
|
+
c.passed++;
|
|
85796
|
+
passedUnattributed[r.owasp] = (passedUnattributed[r.owasp] ?? 0) + 1;
|
|
85797
|
+
}
|
|
85798
|
+
}
|
|
85799
|
+
return {
|
|
85800
|
+
engineVersion: PROXY_VERSION,
|
|
85801
|
+
mode: config.settings.mode ?? "standard",
|
|
85802
|
+
policySource: config.policySource,
|
|
85803
|
+
cases: results.length,
|
|
85804
|
+
byRisk,
|
|
85805
|
+
passedByCheck,
|
|
85806
|
+
passedUnattributed,
|
|
85807
|
+
notApplicableBy
|
|
85808
|
+
};
|
|
85809
|
+
}
|
|
85810
|
+
function toolOf(payload, fallback) {
|
|
85811
|
+
return typeof payload.tool_name === "string" && payload.tool_name ? payload.tool_name : fallback;
|
|
85812
|
+
}
|
|
85813
|
+
function notePostCall(judge, sessionId, tool, input, output, at, cwd) {
|
|
85814
|
+
const m = scanArgs(output);
|
|
85815
|
+
if (m) judge.noteOutputSecret(sessionId, m.patternName, at);
|
|
85816
|
+
judge.noteToolResult(sessionId, tool, at, cwd, {
|
|
85817
|
+
input,
|
|
85818
|
+
output: collectToolOutputText(output).text
|
|
85819
|
+
});
|
|
85820
|
+
}
|
|
85821
|
+
async function runCase(judge, rec, env, has2, at, online = false) {
|
|
85822
|
+
const base3 = {
|
|
85823
|
+
id: rec.id,
|
|
85824
|
+
owasp: isAsiId(rec.owasp) ? rec.owasp : "unknown",
|
|
85825
|
+
section: rec.section === "headline" || rec.section === "vendor" ? rec.section : "unknown",
|
|
85826
|
+
setup: rec.setup,
|
|
85827
|
+
expected: rec.expected,
|
|
85828
|
+
...rec.volatile && { volatile: true }
|
|
85829
|
+
};
|
|
85830
|
+
const need = profileNeed(rec.setup);
|
|
85831
|
+
if (need && !has2[need]) return { ...base3, notApplicable: need };
|
|
85832
|
+
if (rec.stage === "post") return { ...base3, notSimulated: "post-stage" };
|
|
85833
|
+
const sessionId = `forecast-cases:${rec.id}`;
|
|
85834
|
+
const cwd = env.cwd;
|
|
85835
|
+
const config = judge.configFor(cwd);
|
|
85836
|
+
const meta = { agent: "claude", sessionId };
|
|
85837
|
+
for (const p of rec.prior ?? []) {
|
|
85838
|
+
const payload2 = materialize(p.input, env) ?? {};
|
|
85839
|
+
const tool = toolOf(payload2, rec.tool);
|
|
85840
|
+
if (p.stage === "post") {
|
|
85841
|
+
notePostCall(judge, sessionId, tool, payload2.tool_input, materialize(p.output, env), at, cwd);
|
|
85842
|
+
continue;
|
|
85843
|
+
}
|
|
85844
|
+
await forecastDecision(tool, payload2.tool_input ?? {}, meta, {
|
|
85845
|
+
cwd,
|
|
85846
|
+
config,
|
|
85847
|
+
session: judge.session(sessionId),
|
|
85848
|
+
at: Date.parse(at),
|
|
85849
|
+
...online && { onlinePackages: true }
|
|
85850
|
+
});
|
|
85851
|
+
}
|
|
85852
|
+
const payload = materialize(rec.input, env) ?? {};
|
|
85853
|
+
const v = await forecastDecision(toolOf(payload, rec.tool), payload.tool_input ?? {}, meta, {
|
|
85854
|
+
cwd,
|
|
85855
|
+
config,
|
|
85856
|
+
session: judge.session(sessionId),
|
|
85857
|
+
at: Date.parse(at),
|
|
85858
|
+
...online && { onlinePackages: true }
|
|
85859
|
+
});
|
|
85860
|
+
return {
|
|
85861
|
+
...base3,
|
|
85862
|
+
decision: v.decision,
|
|
85863
|
+
enforced: v.enforced,
|
|
85864
|
+
...v.checkId && { checkId: v.checkId },
|
|
85865
|
+
layer: v.layer,
|
|
85866
|
+
...v.notEnforcedBecause && { notEnforcedBecause: v.notEnforcedBecause },
|
|
85867
|
+
...v.unknown.length > 0 && { unknown: v.unknown }
|
|
85868
|
+
};
|
|
85869
|
+
}
|
|
85870
|
+
function materializeProfileFiles(profile, env) {
|
|
85871
|
+
for (const f of profile.files ?? []) {
|
|
85872
|
+
const target = materialize(f.path, env);
|
|
85873
|
+
const rel = import_path95.default.relative(env.home, target);
|
|
85874
|
+
if (rel.startsWith("..") || import_path95.default.isAbsolute(rel)) continue;
|
|
85875
|
+
import_fs96.default.mkdirSync(import_path95.default.dirname(target), { recursive: true });
|
|
85876
|
+
const content = materialize(f.content, env);
|
|
85877
|
+
import_fs96.default.writeFileSync(target, typeof content === "string" ? content : JSON.stringify(content));
|
|
85878
|
+
}
|
|
85879
|
+
}
|
|
85880
|
+
var POLICY_HOME_GUARDS = ["rules-cache.json", "credentials.json"];
|
|
85881
|
+
var PolicyHomeTaken = class extends Error {
|
|
85882
|
+
};
|
|
85883
|
+
async function runForecastCases(opts) {
|
|
85884
|
+
const env = {
|
|
85885
|
+
home: opts.home,
|
|
85886
|
+
cwd: opts.cwd ?? import_path95.default.join(opts.home, "bench-project")
|
|
85887
|
+
};
|
|
85888
|
+
import_fs96.default.mkdirSync(env.cwd, { recursive: true });
|
|
85889
|
+
if (opts.policy) {
|
|
85890
|
+
const taken = POLICY_HOME_GUARDS.filter(
|
|
85891
|
+
(f) => import_fs96.default.existsSync(import_path95.default.join(opts.home, ".node9", f))
|
|
85892
|
+
);
|
|
85893
|
+
if (taken.length > 0)
|
|
85894
|
+
throw new PolicyHomeTaken(
|
|
85895
|
+
`--policy needs a fresh HOME; ${opts.home} already has ${taken.map((f) => `.node9/${f}`).join(" and ")}`
|
|
85896
|
+
);
|
|
85897
|
+
writePolicyCache(opts.policy, opts.policy.etag);
|
|
85898
|
+
if (!process.env.NODE9_API_KEY) process.env.NODE9_API_KEY = "forecast-cases";
|
|
85899
|
+
}
|
|
85900
|
+
const judge = new HistoryJudge();
|
|
85901
|
+
const config = judge.configFor(env.cwd);
|
|
85902
|
+
const has2 = homeHas(config);
|
|
85903
|
+
const profiles = /* @__PURE__ */ new Map();
|
|
85904
|
+
const profileOf = (name) => {
|
|
85905
|
+
if (!opts.profilesDir) return null;
|
|
85906
|
+
if (profiles.has(name)) return profiles.get(name);
|
|
85907
|
+
let p = null;
|
|
85908
|
+
try {
|
|
85909
|
+
p = JSON.parse(
|
|
85910
|
+
import_fs96.default.readFileSync(import_path95.default.join(opts.profilesDir, `${name}.json`), "utf8")
|
|
85911
|
+
);
|
|
85912
|
+
materializeProfileFiles(p, env);
|
|
85913
|
+
} catch {
|
|
85914
|
+
p = null;
|
|
85915
|
+
}
|
|
85916
|
+
profiles.set(name, p);
|
|
85917
|
+
return p;
|
|
85918
|
+
};
|
|
85919
|
+
const results = [];
|
|
85920
|
+
const rl = import_readline5.default.createInterface({
|
|
85921
|
+
input: import_fs96.default.createReadStream(opts.casesPath, { encoding: "utf8" }),
|
|
85922
|
+
crlfDelay: Infinity
|
|
85923
|
+
});
|
|
85924
|
+
for await (const line of rl) {
|
|
85925
|
+
if (!line.trim()) continue;
|
|
85926
|
+
let rec;
|
|
85927
|
+
try {
|
|
85928
|
+
rec = JSON.parse(line);
|
|
85929
|
+
} catch {
|
|
85930
|
+
continue;
|
|
85931
|
+
}
|
|
85932
|
+
if (!rec || typeof rec.id !== "string") continue;
|
|
85933
|
+
profileOf(rec.setup);
|
|
85934
|
+
let result;
|
|
85935
|
+
try {
|
|
85936
|
+
result = await runCase(judge, rec, env, has2, opts.at, opts.onlinePackages === true);
|
|
85937
|
+
} catch (err2) {
|
|
85938
|
+
result = {
|
|
85939
|
+
id: rec.id,
|
|
85940
|
+
owasp: isAsiId(rec.owasp) ? rec.owasp : "unknown",
|
|
85941
|
+
section: rec.section === "headline" || rec.section === "vendor" ? rec.section : "unknown",
|
|
85942
|
+
setup: rec.setup,
|
|
85943
|
+
expected: rec.expected,
|
|
85944
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
85945
|
+
};
|
|
85946
|
+
}
|
|
85947
|
+
results.push(result);
|
|
85948
|
+
opts.write(JSON.stringify({ case: result }));
|
|
85949
|
+
}
|
|
85950
|
+
const summary = summarize(results, config);
|
|
85951
|
+
opts.write(JSON.stringify({ summary }));
|
|
85952
|
+
return summary;
|
|
85953
|
+
}
|
|
85954
|
+
function registerForecastCasesCommand(program2) {
|
|
85955
|
+
program2.command("forecast-cases <cases>", { hidden: true }).description(
|
|
85956
|
+
"Judge a file of benchmark cases through the forecast entry under this HOME; JSON per case, then a summary"
|
|
85957
|
+
).option(
|
|
85958
|
+
"--profiles <dir>",
|
|
85959
|
+
"The benchmark profiles directory: its fixture files are created under HOME"
|
|
85960
|
+
).option("--at <iso>", "The clock every case is judged at", "2026-01-01T00:00:00.000Z").option(
|
|
85961
|
+
"--online-packages",
|
|
85962
|
+
"Let the package check query the advisory service and the registries, as the hook does (default: offline)"
|
|
85963
|
+
).option(
|
|
85964
|
+
"--cwd <dir>",
|
|
85965
|
+
"The project directory the cases are judged in ({{CWD}}); default HOME/bench-project"
|
|
85966
|
+
).option(
|
|
85967
|
+
"--policy <file>",
|
|
85968
|
+
"A cloud policy sync response body (JSON), written as this HOME's rules cache first"
|
|
85969
|
+
).action(
|
|
85970
|
+
async (cases, opts) => {
|
|
85971
|
+
const casesPath = import_path95.default.resolve(cases);
|
|
85972
|
+
if (!import_fs96.default.existsSync(casesPath)) {
|
|
85973
|
+
console.error(`forecast-cases: no such file: ${casesPath}`);
|
|
85974
|
+
process.exitCode = 2;
|
|
85975
|
+
return;
|
|
85976
|
+
}
|
|
85977
|
+
let policy;
|
|
85978
|
+
if (opts.policy) {
|
|
85979
|
+
const parsed = readPolicyBody(import_path95.default.resolve(opts.policy));
|
|
85980
|
+
if (!parsed) {
|
|
85981
|
+
console.error(`forecast-cases: --policy is not a JSON object: ${opts.policy}`);
|
|
85982
|
+
process.exitCode = 2;
|
|
85983
|
+
return;
|
|
85984
|
+
}
|
|
85985
|
+
policy = parsed;
|
|
85986
|
+
}
|
|
85987
|
+
try {
|
|
85988
|
+
await runForecastCases({
|
|
85989
|
+
casesPath,
|
|
85990
|
+
profilesDir: opts.profiles ? import_path95.default.resolve(opts.profiles) : void 0,
|
|
85991
|
+
home: import_os80.default.homedir(),
|
|
85992
|
+
cwd: opts.cwd ? import_path95.default.resolve(opts.cwd) : void 0,
|
|
85993
|
+
policy,
|
|
85994
|
+
onlinePackages: opts.onlinePackages === true,
|
|
85995
|
+
at: opts.at,
|
|
85996
|
+
write: (line) => process.stdout.write(line + "\n")
|
|
85997
|
+
});
|
|
85998
|
+
} catch (err2) {
|
|
85999
|
+
if (!(err2 instanceof PolicyHomeTaken)) throw err2;
|
|
86000
|
+
console.error(`forecast-cases: ${err2.message}`);
|
|
86001
|
+
process.exitCode = 2;
|
|
86002
|
+
}
|
|
86003
|
+
}
|
|
86004
|
+
);
|
|
86005
|
+
}
|
|
86006
|
+
function readPolicyBody(file2) {
|
|
86007
|
+
try {
|
|
86008
|
+
const v = JSON.parse(import_fs96.default.readFileSync(file2, "utf8"));
|
|
86009
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
|
|
86010
|
+
return v;
|
|
86011
|
+
} catch {
|
|
86012
|
+
return void 0;
|
|
86013
|
+
}
|
|
86014
|
+
}
|
|
86015
|
+
|
|
85569
86016
|
// src/cli/commands/posture.ts
|
|
85570
86017
|
init_cjs_shims();
|
|
85571
86018
|
var import_chalk35 = __toESM(require("chalk"));
|
|
@@ -85605,8 +86052,8 @@ init_cjs_shims();
|
|
|
85605
86052
|
|
|
85606
86053
|
// src/ci-check/fetch.ts
|
|
85607
86054
|
init_cjs_shims();
|
|
85608
|
-
var
|
|
85609
|
-
var
|
|
86055
|
+
var import_fs97 = __toESM(require("fs"));
|
|
86056
|
+
var import_path96 = __toESM(require("path"));
|
|
85610
86057
|
var import_node_child_process = require("child_process");
|
|
85611
86058
|
var import_undici = __toESM(require_undici());
|
|
85612
86059
|
|
|
@@ -85616,18 +86063,18 @@ init_instructions();
|
|
|
85616
86063
|
init_suppress();
|
|
85617
86064
|
var MCP_CONFIG_RE = /\.mcp\.json$|\.cursor\/mcp\.json$|(^|\/)\.vscode\/mcp\.json$|(^|\/)\.kiro\/settings\/mcp\.json$|(^|\/)\.gemini\/settings\.json$|(^|\/)opencode\.json$|(^|\/)\.opencode\/config\.json$/;
|
|
85618
86065
|
var ISSUE_FORM_RE = /^\.github\/ISSUE_TEMPLATE\/[^/]+\.(ya?ml|md)$/i;
|
|
85619
|
-
function routeOf(
|
|
85620
|
-
if (
|
|
85621
|
-
if (/\.github\/workflows\/.+\.ya?ml$/.test(
|
|
85622
|
-
if (ISSUE_FORM_RE.test(
|
|
85623
|
-
if (
|
|
85624
|
-
if (/\.claude\/settings(\.local)?\.json$/.test(
|
|
85625
|
-
if (isHookScript(
|
|
85626
|
-
if (isSkillScript(
|
|
85627
|
-
if (MCP_CONFIG_RE.test(
|
|
85628
|
-
if (/(^|\/)\.codex\/config\.toml$/.test(
|
|
85629
|
-
if (isInstructionFile(
|
|
85630
|
-
if (isAppDoc(
|
|
86066
|
+
function routeOf(path114, skillDirs, appDirs = /* @__PURE__ */ new Set()) {
|
|
86067
|
+
if (path114 === SUPPRESSIONS_FILE) return "suppressions";
|
|
86068
|
+
if (/\.github\/workflows\/.+\.ya?ml$/.test(path114)) return "workflow";
|
|
86069
|
+
if (ISSUE_FORM_RE.test(path114)) return "issue-form";
|
|
86070
|
+
if (path114 === "package.json" || path114 === "pyproject.toml") return "manifest";
|
|
86071
|
+
if (/\.claude\/settings(\.local)?\.json$/.test(path114)) return "agent-config";
|
|
86072
|
+
if (isHookScript(path114)) return "hook-script";
|
|
86073
|
+
if (isSkillScript(path114, skillDirs)) return "skill-script";
|
|
86074
|
+
if (MCP_CONFIG_RE.test(path114)) return "mcp";
|
|
86075
|
+
if (/(^|\/)\.codex\/config\.toml$/.test(path114)) return "codex";
|
|
86076
|
+
if (isInstructionFile(path114, skillDirs, appDirs)) return "instruction";
|
|
86077
|
+
if (isAppDoc(path114, skillDirs, appDirs)) return "app-doc";
|
|
85631
86078
|
return null;
|
|
85632
86079
|
}
|
|
85633
86080
|
|
|
@@ -85757,7 +86204,7 @@ function parseRepoUrl(input) {
|
|
|
85757
86204
|
function isLocalPath(input) {
|
|
85758
86205
|
if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
|
|
85759
86206
|
try {
|
|
85760
|
-
return
|
|
86207
|
+
return import_fs97.default.existsSync(input) && import_fs97.default.statSync(input).isDirectory();
|
|
85761
86208
|
} catch {
|
|
85762
86209
|
return false;
|
|
85763
86210
|
}
|
|
@@ -86118,7 +86565,7 @@ function capNested(reads, cap, notes) {
|
|
|
86118
86565
|
}
|
|
86119
86566
|
var overLimit = (text) => Buffer.byteLength(text, "utf8") > MAX_FILE_BYTES5;
|
|
86120
86567
|
var RAW_LIMIT = 2 * MAX_FILE_BYTES5;
|
|
86121
|
-
var OPEN_READ =
|
|
86568
|
+
var OPEN_READ = import_fs97.default.constants.O_RDONLY | (import_fs97.default.constants.O_NOFOLLOW ?? 0) | (import_fs97.default.constants.O_NONBLOCK ?? 0);
|
|
86122
86569
|
var MAX_WALK_ENTRIES = 1e6;
|
|
86123
86570
|
var direntKind = (e) => e.isSymbolicLink() ? "link" : e.isDirectory() ? "dir" : e.isFile() ? "file" : "other";
|
|
86124
86571
|
function walkDisk(root, notes) {
|
|
@@ -86133,7 +86580,7 @@ function walkDisk(root, notes) {
|
|
|
86133
86580
|
const relDir = stack.pop();
|
|
86134
86581
|
let dirents;
|
|
86135
86582
|
try {
|
|
86136
|
-
dirents =
|
|
86583
|
+
dirents = import_fs97.default.readdirSync(import_path96.default.join(root, relDir), { withFileTypes: true });
|
|
86137
86584
|
} catch (e) {
|
|
86138
86585
|
unlistable.push(`${relDir || "."} (${e?.code ?? "error"})`);
|
|
86139
86586
|
continue;
|
|
@@ -86147,7 +86594,7 @@ function walkDisk(root, notes) {
|
|
|
86147
86594
|
const k = direntKind(e);
|
|
86148
86595
|
kinds2.set(rel, k);
|
|
86149
86596
|
if (k !== "dir" || isUnwalked(`${rel}/`)) continue;
|
|
86150
|
-
if (
|
|
86597
|
+
if (import_fs97.default.existsSync(import_path96.default.join(root, rel, ".git"))) {
|
|
86151
86598
|
sealed.add(rel);
|
|
86152
86599
|
nestedRepos.push(rel);
|
|
86153
86600
|
} else stack.push(rel);
|
|
@@ -86170,7 +86617,7 @@ function walkDisk(root, notes) {
|
|
|
86170
86617
|
}
|
|
86171
86618
|
function gitmodulePaths(root) {
|
|
86172
86619
|
try {
|
|
86173
|
-
const text = readLocalFile(
|
|
86620
|
+
const text = readLocalFile(import_path96.default.join(root, ".gitmodules"), ".gitmodules");
|
|
86174
86621
|
return [...text.matchAll(/^\s*path\s*=\s*(.+?)\s*$/gm)].map((m) => m[1].replace(/\/+$/, ""));
|
|
86175
86622
|
} catch {
|
|
86176
86623
|
return [];
|
|
@@ -86178,9 +86625,9 @@ function gitmodulePaths(root) {
|
|
|
86178
86625
|
}
|
|
86179
86626
|
function localLinkText(root, rel) {
|
|
86180
86627
|
try {
|
|
86181
|
-
const t =
|
|
86628
|
+
const t = import_fs97.default.readlinkSync(import_path96.default.join(root, rel));
|
|
86182
86629
|
if (process.platform !== "win32") return t;
|
|
86183
|
-
return
|
|
86630
|
+
return import_path96.default.win32.isAbsolute(t) ? `/${t.replace(/\\/g, "/")}` : t.replace(/\\/g, "/");
|
|
86184
86631
|
} catch {
|
|
86185
86632
|
return null;
|
|
86186
86633
|
}
|
|
@@ -86188,11 +86635,11 @@ function localLinkText(root, rel) {
|
|
|
86188
86635
|
function readLocalFile(abs, rel) {
|
|
86189
86636
|
let fd;
|
|
86190
86637
|
try {
|
|
86191
|
-
fd =
|
|
86192
|
-
const st =
|
|
86638
|
+
fd = import_fs97.default.openSync(abs, OPEN_READ);
|
|
86639
|
+
const st = import_fs97.default.fstatSync(fd);
|
|
86193
86640
|
if (!st.isFile()) throw new Error(unreadNote(rel, "no longer a regular file"));
|
|
86194
86641
|
if (st.size > RAW_LIMIT) throw new Error(tooLargeNote(rel));
|
|
86195
|
-
const text = lf(
|
|
86642
|
+
const text = lf(import_fs97.default.readFileSync(fd, "utf8"));
|
|
86196
86643
|
if (overLimit(text)) throw new Error(tooLargeNote(rel));
|
|
86197
86644
|
return text;
|
|
86198
86645
|
} catch (e) {
|
|
@@ -86200,7 +86647,7 @@ function readLocalFile(abs, rel) {
|
|
|
86200
86647
|
if (msg.includes(INCOMPLETE)) throw e;
|
|
86201
86648
|
throw new Error(unreadNote(rel, e?.code ?? "error"));
|
|
86202
86649
|
} finally {
|
|
86203
|
-
if (fd !== void 0)
|
|
86650
|
+
if (fd !== void 0) import_fs97.default.closeSync(fd);
|
|
86204
86651
|
}
|
|
86205
86652
|
}
|
|
86206
86653
|
function localGitHubRepo(root) {
|
|
@@ -86221,10 +86668,10 @@ function readLocalTree(dir2) {
|
|
|
86221
86668
|
notes.push(...plan.notes);
|
|
86222
86669
|
const files = [];
|
|
86223
86670
|
for (const { rel, real, route } of plan.reads) {
|
|
86224
|
-
const abs =
|
|
86671
|
+
const abs = import_path96.default.join(root, real);
|
|
86225
86672
|
let size = 0;
|
|
86226
86673
|
try {
|
|
86227
|
-
size =
|
|
86674
|
+
size = import_fs97.default.lstatSync(abs).size;
|
|
86228
86675
|
} catch {
|
|
86229
86676
|
}
|
|
86230
86677
|
if (size > RAW_LIMIT) {
|
|
@@ -87386,17 +87833,17 @@ function localTarget(uses, self) {
|
|
|
87386
87833
|
if (!f) return null;
|
|
87387
87834
|
return f[1].toLowerCase() === self.owner.toLowerCase() && f[2].toLowerCase() === self.repo.toLowerCase() ? `.github/workflows/${f[3]}` : null;
|
|
87388
87835
|
}
|
|
87389
|
-
function localCallsOf(
|
|
87836
|
+
function localCallsOf(path114, content, autoLabels, trustedRunSources, self) {
|
|
87390
87837
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
87391
87838
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
87392
87839
|
try {
|
|
87393
|
-
return localCallsOfInner(
|
|
87840
|
+
return localCallsOfInner(path114, content, self);
|
|
87394
87841
|
} finally {
|
|
87395
87842
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
87396
87843
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
87397
87844
|
}
|
|
87398
87845
|
}
|
|
87399
|
-
function localCallsOfInner(
|
|
87846
|
+
function localCallsOfInner(path114, content, self) {
|
|
87400
87847
|
let raw;
|
|
87401
87848
|
try {
|
|
87402
87849
|
raw = loadWorkflow(content).raw;
|
|
@@ -87414,7 +87861,7 @@ function localCallsOfInner(path113, content, self) {
|
|
|
87414
87861
|
out.push({
|
|
87415
87862
|
target,
|
|
87416
87863
|
caller: {
|
|
87417
|
-
file:
|
|
87864
|
+
file: path114,
|
|
87418
87865
|
keys: reach.keys,
|
|
87419
87866
|
untrusted: reach.untrusted,
|
|
87420
87867
|
secretExposed: reach.secretExposed,
|
|
@@ -87650,7 +88097,7 @@ function upstreamRunTrusted(wf, raw) {
|
|
|
87650
88097
|
const names = Array.isArray(run?.workflows) ? run.workflows.map(String) : [];
|
|
87651
88098
|
return names.length > 0 && names.every((n) => TRUSTED_RUN_SOURCES.has(n));
|
|
87652
88099
|
}
|
|
87653
|
-
function runSourceOf(
|
|
88100
|
+
function runSourceOf(path114, content, autoLabels) {
|
|
87654
88101
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
87655
88102
|
try {
|
|
87656
88103
|
let raw;
|
|
@@ -87663,7 +88110,7 @@ function runSourceOf(path113, content, autoLabels) {
|
|
|
87663
88110
|
const wf = raw;
|
|
87664
88111
|
CALLERS.delete(wf);
|
|
87665
88112
|
const reach = triggerReach(wf, raw);
|
|
87666
|
-
const name = typeof raw["name"] === "string" && raw["name"] ? raw["name"] :
|
|
88113
|
+
const name = typeof raw["name"] === "string" && raw["name"] ? raw["name"] : path114;
|
|
87667
88114
|
return { name, trusted: !reach.untrusted && !reach.reusable };
|
|
87668
88115
|
} finally {
|
|
87669
88116
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
@@ -88133,18 +88580,18 @@ function severityFromScore(score) {
|
|
|
88133
88580
|
if (score >= 1) return "advisory";
|
|
88134
88581
|
return null;
|
|
88135
88582
|
}
|
|
88136
|
-
function analyzeWorkflow(
|
|
88583
|
+
function analyzeWorkflow(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88137
88584
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88138
88585
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88139
88586
|
try {
|
|
88140
|
-
return analyzeWorkflowInner(
|
|
88587
|
+
return analyzeWorkflowInner(path114, content, callers);
|
|
88141
88588
|
} finally {
|
|
88142
88589
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88143
88590
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88144
88591
|
UPSTREAM_TRUSTED = false;
|
|
88145
88592
|
}
|
|
88146
88593
|
}
|
|
88147
|
-
function analyzeWorkflowInner(
|
|
88594
|
+
function analyzeWorkflowInner(path114, content, callers) {
|
|
88148
88595
|
let raw;
|
|
88149
88596
|
try {
|
|
88150
88597
|
raw = loadWorkflow(content).raw;
|
|
@@ -88353,7 +88800,7 @@ function analyzeWorkflowInner(path113, content, callers) {
|
|
|
88353
88800
|
dimension: "workflows",
|
|
88354
88801
|
severity,
|
|
88355
88802
|
title,
|
|
88356
|
-
file:
|
|
88803
|
+
file: path114,
|
|
88357
88804
|
signals,
|
|
88358
88805
|
mitigations: mitigations.length ? mitigations : void 0,
|
|
88359
88806
|
fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run): check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today: keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
|
|
@@ -88457,18 +88904,18 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
|
|
|
88457
88904
|
if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
|
|
88458
88905
|
return { severity, secrets, injectable, canReadEnv };
|
|
88459
88906
|
}
|
|
88460
|
-
function analyzeWorkflowSecrets(
|
|
88907
|
+
function analyzeWorkflowSecrets(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88461
88908
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88462
88909
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88463
88910
|
try {
|
|
88464
|
-
return analyzeWorkflowSecretsInner(
|
|
88911
|
+
return analyzeWorkflowSecretsInner(path114, content, callers);
|
|
88465
88912
|
} finally {
|
|
88466
88913
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88467
88914
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88468
88915
|
UPSTREAM_TRUSTED = false;
|
|
88469
88916
|
}
|
|
88470
88917
|
}
|
|
88471
|
-
function analyzeWorkflowSecretsInner(
|
|
88918
|
+
function analyzeWorkflowSecretsInner(path114, content, callers) {
|
|
88472
88919
|
let raw;
|
|
88473
88920
|
try {
|
|
88474
88921
|
raw = loadWorkflow(content).raw;
|
|
@@ -88495,7 +88942,7 @@ function analyzeWorkflowSecretsInner(path113, content, callers) {
|
|
|
88495
88942
|
dimension: "data",
|
|
88496
88943
|
severity: worst.severity,
|
|
88497
88944
|
title: worst.severity === "advisory" ? "Secrets reachable by the agent: hardening" : "Exfiltratable secrets reachable by an injectable agent",
|
|
88498
|
-
file:
|
|
88945
|
+
file: path114,
|
|
88499
88946
|
signals: [
|
|
88500
88947
|
`agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
|
|
88501
88948
|
worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable: latent risk only",
|
|
@@ -88517,7 +88964,7 @@ function marketplaceOwner(market) {
|
|
|
88517
88964
|
market
|
|
88518
88965
|
)?.[1] ?? /^([\w.-]{1,100})\/[\w.-]{1,100}(?:[#@].*)?$/.exec(market)?.[1];
|
|
88519
88966
|
}
|
|
88520
|
-
function analyzeWorkflowPlugins(
|
|
88967
|
+
function analyzeWorkflowPlugins(path114, content, owner) {
|
|
88521
88968
|
let raw;
|
|
88522
88969
|
try {
|
|
88523
88970
|
raw = loadWorkflow(content).raw;
|
|
@@ -88547,7 +88994,7 @@ function analyzeWorkflowPlugins(path113, content, owner) {
|
|
|
88547
88994
|
dimension: "mcp",
|
|
88548
88995
|
severity: "medium",
|
|
88549
88996
|
title: "Agent installs plugins from a third-party marketplace on every run",
|
|
88550
|
-
file:
|
|
88997
|
+
file: path114,
|
|
88551
88998
|
signals: [
|
|
88552
88999
|
`\`plugin_marketplaces: ${safeText(market, 120)}\` is not pinned to a commit: whoever controls it changes the code and prompts the agent runs`
|
|
88553
89000
|
],
|
|
@@ -88563,11 +89010,11 @@ function readsItemList(text) {
|
|
|
88563
89010
|
if (text.length > 2e5) return ITEM_LIST_RE.test(text);
|
|
88564
89011
|
return text.replace(/\\\r?\n/g, " ").split("\n").some((l) => ITEM_LIST_RE.test(l) && !sanitizedListing(l));
|
|
88565
89012
|
}
|
|
88566
|
-
function analyzeTrustedReaders(
|
|
89013
|
+
function analyzeTrustedReaders(path114, content, autoLabels, callers, trustedRunSources) {
|
|
88567
89014
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88568
89015
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88569
89016
|
try {
|
|
88570
|
-
return analyzeTrustedReadersInner(
|
|
89017
|
+
return analyzeTrustedReadersInner(path114, content, callers);
|
|
88571
89018
|
} finally {
|
|
88572
89019
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88573
89020
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
@@ -88576,7 +89023,7 @@ function analyzeTrustedReaders(path113, content, autoLabels, callers, trustedRun
|
|
|
88576
89023
|
function keysWithCallers(keys, callers) {
|
|
88577
89024
|
return [.../* @__PURE__ */ new Set([...keys, ...(callers ?? []).flatMap((c) => c.keys)])];
|
|
88578
89025
|
}
|
|
88579
|
-
function analyzeTrustedReadersInner(
|
|
89026
|
+
function analyzeTrustedReadersInner(path114, content, callers) {
|
|
88580
89027
|
let raw;
|
|
88581
89028
|
try {
|
|
88582
89029
|
raw = loadWorkflow(content).raw;
|
|
@@ -88637,7 +89084,7 @@ function analyzeTrustedReadersInner(path113, content, callers) {
|
|
|
88637
89084
|
dimension: "workflows",
|
|
88638
89085
|
severity: "advisory",
|
|
88639
89086
|
title: "Agent on a trusted trigger reads content strangers write, with a write token",
|
|
88640
|
-
file:
|
|
89087
|
+
file: path114,
|
|
88641
89088
|
signals: [
|
|
88642
89089
|
`runs on ${keys.map((k) => safeText(k, 40)).join(", ")}: no stranger starts it`,
|
|
88643
89090
|
...reads.map((r) => `the agent ${r}`),
|
|
@@ -88725,17 +89172,17 @@ function requiresTrustedAuthor(src) {
|
|
|
88725
89172
|
};
|
|
88726
89173
|
return req(x);
|
|
88727
89174
|
}
|
|
88728
|
-
function analyzeForkCodeOnTrust(
|
|
89175
|
+
function analyzeForkCodeOnTrust(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88729
89176
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88730
89177
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88731
89178
|
try {
|
|
88732
|
-
return analyzeForkCodeOnTrustInner(
|
|
89179
|
+
return analyzeForkCodeOnTrustInner(path114, content, callers);
|
|
88733
89180
|
} finally {
|
|
88734
89181
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88735
89182
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88736
89183
|
}
|
|
88737
89184
|
}
|
|
88738
|
-
function analyzeForkCodeOnTrustInner(
|
|
89185
|
+
function analyzeForkCodeOnTrustInner(path114, content, callers) {
|
|
88739
89186
|
let raw;
|
|
88740
89187
|
try {
|
|
88741
89188
|
raw = loadWorkflow(content).raw;
|
|
@@ -88774,7 +89221,7 @@ function analyzeForkCodeOnTrustInner(path113, content, callers) {
|
|
|
88774
89221
|
dimension: "workflows",
|
|
88775
89222
|
severity: "advisory",
|
|
88776
89223
|
title: "A maintainer's action runs the agent inside the fork's code",
|
|
88777
|
-
file:
|
|
89224
|
+
file: path114,
|
|
88778
89225
|
signals: [
|
|
88779
89226
|
`triggered by ${forkKeys.map((k) => safeText(k, 40)).join(", ")}, behind a gate a maintainer passes (a comment, a label, a push to the PR branch, a reopen)`,
|
|
88780
89227
|
"checks out the untrusted PR head into the workspace root",
|
|
@@ -88806,18 +89253,18 @@ function laterSecrets(wf, job, from) {
|
|
|
88806
89253
|
if (!/^GITHUB_TOKEN$/i.test(m[1])) out.add(m[1]);
|
|
88807
89254
|
return [...out];
|
|
88808
89255
|
}
|
|
88809
|
-
function analyzeAgentOutputToEnv(
|
|
89256
|
+
function analyzeAgentOutputToEnv(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88810
89257
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88811
89258
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88812
89259
|
try {
|
|
88813
|
-
return analyzeAgentOutputToEnvInner(
|
|
89260
|
+
return analyzeAgentOutputToEnvInner(path114, content, callers);
|
|
88814
89261
|
} finally {
|
|
88815
89262
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88816
89263
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88817
89264
|
UPSTREAM_TRUSTED = false;
|
|
88818
89265
|
}
|
|
88819
89266
|
}
|
|
88820
|
-
function analyzeAgentOutputToEnvInner(
|
|
89267
|
+
function analyzeAgentOutputToEnvInner(path114, content, callers) {
|
|
88821
89268
|
let raw;
|
|
88822
89269
|
try {
|
|
88823
89270
|
raw = loadWorkflow(content).raw;
|
|
@@ -88913,7 +89360,7 @@ function analyzeAgentOutputToEnvInner(path113, content, callers) {
|
|
|
88913
89360
|
dimension: "workflows",
|
|
88914
89361
|
severity,
|
|
88915
89362
|
title: sink.target === "GITHUB_PATH" ? "The agent's output is added to the job's PATH" : "The agent's output is written into the job's environment",
|
|
88916
|
-
file:
|
|
89363
|
+
file: path114,
|
|
88917
89364
|
signals,
|
|
88918
89365
|
fix: `Write the agent's result to a file and read it with a strict parser in the next step (a fixed set of values, or a number); never append free text from the agent to \`${target}\`. If a value must go there, strip newlines (\`tr -d '\\n'\`) and write it under a fixed name, or use a delimiter generated at run time.`,
|
|
88919
89366
|
explain: explainAgentOutputEnv({
|
|
@@ -88991,7 +89438,7 @@ function reviewQuestion(rule) {
|
|
|
88991
89438
|
return "Is this an instruction the agent follows, or text for a person?";
|
|
88992
89439
|
}
|
|
88993
89440
|
var RANK2 = { critical: 4, high: 3, medium: 2, advisory: 1 };
|
|
88994
|
-
var worstRank = (
|
|
89441
|
+
var worstRank = (fs115) => Math.max(...fs115.map((f) => RANK2[f.severity] ?? 0));
|
|
88995
89442
|
var fileOrder = (a, b) => worstRank(b[1]) - worstRank(a[1]) || b[1].length - a[1].length;
|
|
88996
89443
|
function groupReview(findings) {
|
|
88997
89444
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -89062,7 +89509,7 @@ function logicalLines2(content) {
|
|
|
89062
89509
|
}
|
|
89063
89510
|
return out;
|
|
89064
89511
|
}
|
|
89065
|
-
function analyzeScript(
|
|
89512
|
+
function analyzeScript(path114, content, rulePrefix) {
|
|
89066
89513
|
const check = rulePrefix.startsWith("CI-1") ? "CI-1" : "CI-6";
|
|
89067
89514
|
const dimension = check === "CI-1" ? "toolRules" : "instructions";
|
|
89068
89515
|
const mk3 = (suffix, severity, title, signal, fix, line) => ({
|
|
@@ -89071,7 +89518,7 @@ function analyzeScript(path113, content, rulePrefix) {
|
|
|
89071
89518
|
dimension,
|
|
89072
89519
|
severity,
|
|
89073
89520
|
title,
|
|
89074
|
-
file:
|
|
89521
|
+
file: path114,
|
|
89075
89522
|
...line ? { line } : {},
|
|
89076
89523
|
signals: [signal],
|
|
89077
89524
|
fix
|
|
@@ -89501,7 +89948,7 @@ async function scanRepo(input, onProgress) {
|
|
|
89501
89948
|
init_cjs_shims();
|
|
89502
89949
|
var import_chalk36 = __toESM(require("chalk"));
|
|
89503
89950
|
init_suppress();
|
|
89504
|
-
var listed = (
|
|
89951
|
+
var listed = (fs115) => fs115.filter((f) => f.tier !== "review");
|
|
89505
89952
|
function excerpt(f) {
|
|
89506
89953
|
const m = /`([^`]+)`/.exec(f.signals[0] ?? "");
|
|
89507
89954
|
return safeText(m ? m[1] : f.title, 120).replace(/`/g, "'");
|
|
@@ -89517,14 +89964,14 @@ function reviewMd(findings) {
|
|
|
89517
89964
|
L.push("");
|
|
89518
89965
|
const files = [...byFile.keys()];
|
|
89519
89966
|
for (const file2 of files.slice(0, REVIEW_FILES)) {
|
|
89520
|
-
const
|
|
89967
|
+
const fs115 = byFile.get(file2);
|
|
89521
89968
|
L.push(`- \`${safeText(file2, 300)}\``);
|
|
89522
|
-
for (const f of
|
|
89969
|
+
for (const f of fs115.slice(0, REVIEW_LINES_PER_FILE))
|
|
89523
89970
|
L.push(
|
|
89524
89971
|
` - ${f.line ? `line ${Number(f.line)}: ` : ""}\`${excerpt(f)}\`. Check: ${reviewQuestion(f.rule)}`
|
|
89525
89972
|
);
|
|
89526
|
-
if (
|
|
89527
|
-
L.push(` - and ${
|
|
89973
|
+
if (fs115.length > REVIEW_LINES_PER_FILE)
|
|
89974
|
+
L.push(` - and ${fs115.length - REVIEW_LINES_PER_FILE} similar lines in this file`);
|
|
89528
89975
|
}
|
|
89529
89976
|
const more = files.length - REVIEW_FILES;
|
|
89530
89977
|
if (more > 0) L.push(`- and ${more} more file${more === 1 ? "" : "s"}`);
|
|
@@ -89540,7 +89987,7 @@ function reviewMd(findings) {
|
|
|
89540
89987
|
}
|
|
89541
89988
|
function reviewTerminal(findings) {
|
|
89542
89989
|
const { byFile, grants } = groupReview(findings);
|
|
89543
|
-
const items = [...byFile.values()].reduce((a,
|
|
89990
|
+
const items = [...byFile.values()].reduce((a, fs115) => a + fs115.length, 0);
|
|
89544
89991
|
if (!items && !grants) return [];
|
|
89545
89992
|
const L = [];
|
|
89546
89993
|
if (items) {
|
|
@@ -89549,12 +89996,12 @@ function reviewTerminal(findings) {
|
|
|
89549
89996
|
);
|
|
89550
89997
|
const files = [...byFile.keys()];
|
|
89551
89998
|
for (const file2 of files.slice(0, REVIEW_FILES)) {
|
|
89552
|
-
const
|
|
89999
|
+
const fs115 = byFile.get(file2);
|
|
89553
90000
|
L.push(import_chalk36.default.gray(` ${file2}`));
|
|
89554
|
-
for (const f of
|
|
90001
|
+
for (const f of fs115.slice(0, REVIEW_LINES_PER_FILE))
|
|
89555
90002
|
L.push(` \u2022 ${f.line ? `line ${f.line}: ` : ""}${excerpt(f)}`);
|
|
89556
|
-
if (
|
|
89557
|
-
L.push(import_chalk36.default.gray(` and ${
|
|
90003
|
+
if (fs115.length > REVIEW_LINES_PER_FILE)
|
|
90004
|
+
L.push(import_chalk36.default.gray(` and ${fs115.length - REVIEW_LINES_PER_FILE} similar lines`));
|
|
89558
90005
|
}
|
|
89559
90006
|
const more = files.length - REVIEW_FILES;
|
|
89560
90007
|
if (more > 0) L.push(import_chalk36.default.gray(` and ${more} more file${more === 1 ? "" : "s"}`));
|
|
@@ -90208,16 +90655,16 @@ var import_chalk40 = __toESM(require("chalk"));
|
|
|
90208
90655
|
|
|
90209
90656
|
// src/canary/plant.ts
|
|
90210
90657
|
init_cjs_shims();
|
|
90211
|
-
var
|
|
90212
|
-
var
|
|
90213
|
-
var
|
|
90658
|
+
var import_fs99 = __toESM(require("fs"));
|
|
90659
|
+
var import_os81 = __toESM(require("os"));
|
|
90660
|
+
var import_path98 = __toESM(require("path"));
|
|
90214
90661
|
init_jail();
|
|
90215
90662
|
init_registry2();
|
|
90216
90663
|
|
|
90217
90664
|
// src/canary/sites.ts
|
|
90218
90665
|
init_cjs_shims();
|
|
90219
|
-
var
|
|
90220
|
-
var
|
|
90666
|
+
var import_fs98 = __toESM(require("fs"));
|
|
90667
|
+
var import_path97 = __toESM(require("path"));
|
|
90221
90668
|
|
|
90222
90669
|
// src/canary/generate.ts
|
|
90223
90670
|
init_cjs_shims();
|
|
@@ -90312,26 +90759,26 @@ function generateSshKey() {
|
|
|
90312
90759
|
var SITES = {
|
|
90313
90760
|
"aws-profile": {
|
|
90314
90761
|
kind: "aws-profile",
|
|
90315
|
-
primary: (h) =>
|
|
90316
|
-
fallback: (h) =>
|
|
90762
|
+
primary: (h) => import_path97.default.join(h, ".aws", "credentials"),
|
|
90763
|
+
fallback: (h) => import_path97.default.join(h, ".aws", "credentials.bak"),
|
|
90317
90764
|
// SSO / profile-only / credential_process setups have ~/.aws/config and no
|
|
90318
90765
|
// credentials file; the SDK and CLI then parse ~/.aws/credentials on every
|
|
90319
90766
|
// profile lookup. A planted primary would be a file real tools read.
|
|
90320
|
-
preferFallback: (h) =>
|
|
90767
|
+
preferFallback: (h) => import_fs98.default.existsSync(import_path97.default.join(h, ".aws", "config")),
|
|
90321
90768
|
dirMode: 448,
|
|
90322
90769
|
generate: generateAwsProfile
|
|
90323
90770
|
},
|
|
90324
90771
|
"env-file": {
|
|
90325
90772
|
kind: "env-file",
|
|
90326
|
-
primary: (h) =>
|
|
90327
|
-
fallback: (h) =>
|
|
90773
|
+
primary: (h) => import_path97.default.join(h, ".env.bak"),
|
|
90774
|
+
fallback: (h) => import_path97.default.join(h, ".env.local.bak"),
|
|
90328
90775
|
dirMode: 493,
|
|
90329
90776
|
generate: generateEnvFile
|
|
90330
90777
|
},
|
|
90331
90778
|
"ssh-key": {
|
|
90332
90779
|
kind: "ssh-key",
|
|
90333
|
-
primary: (h) =>
|
|
90334
|
-
fallback: (h) =>
|
|
90780
|
+
primary: (h) => import_path97.default.join(h, ".ssh", "id_rsa_backup"),
|
|
90781
|
+
fallback: (h) => import_path97.default.join(h, ".ssh", "id_rsa.old"),
|
|
90335
90782
|
// ssh refuses a group-writable ~/.ssh for config / known_hosts reads.
|
|
90336
90783
|
dirMode: 448,
|
|
90337
90784
|
generate: generateSshKey
|
|
@@ -90344,12 +90791,12 @@ var isKind = (s) => ALL_KINDS.includes(s);
|
|
|
90344
90791
|
var liveRecords = (kind) => loadCanaries().filter((r) => r.kind === kind && !r.retiredAt);
|
|
90345
90792
|
var fileHashOf = (p) => {
|
|
90346
90793
|
try {
|
|
90347
|
-
return sha256Hex(
|
|
90794
|
+
return sha256Hex(import_fs99.default.readFileSync(p));
|
|
90348
90795
|
} catch {
|
|
90349
90796
|
return null;
|
|
90350
90797
|
}
|
|
90351
90798
|
};
|
|
90352
|
-
function plantKind(kind, home =
|
|
90799
|
+
function plantKind(kind, home = import_os81.default.homedir()) {
|
|
90353
90800
|
const site = SITES[kind];
|
|
90354
90801
|
const live = liveRecords(kind);
|
|
90355
90802
|
if (live.length > 0) {
|
|
@@ -90368,8 +90815,8 @@ function plantKind(kind, home = import_os80.default.homedir()) {
|
|
|
90368
90815
|
const primary = site.primary(home);
|
|
90369
90816
|
const fallback = site.fallback(home);
|
|
90370
90817
|
let target;
|
|
90371
|
-
if (!
|
|
90372
|
-
else if (!
|
|
90818
|
+
if (!import_fs99.default.existsSync(primary) && !site.preferFallback?.(home)) target = primary;
|
|
90819
|
+
else if (!import_fs99.default.existsSync(fallback)) target = fallback;
|
|
90373
90820
|
else {
|
|
90374
90821
|
return {
|
|
90375
90822
|
kind,
|
|
@@ -90380,11 +90827,11 @@ function plantKind(kind, home = import_os80.default.homedir()) {
|
|
|
90380
90827
|
recordIds: []
|
|
90381
90828
|
};
|
|
90382
90829
|
}
|
|
90383
|
-
const dir2 =
|
|
90830
|
+
const dir2 = import_path98.default.dirname(target);
|
|
90384
90831
|
const gen = site.generate();
|
|
90385
|
-
const createdDir =
|
|
90386
|
-
|
|
90387
|
-
|
|
90832
|
+
const createdDir = import_fs99.default.mkdirSync(dir2, { recursive: true, mode: site.dirMode }) !== void 0;
|
|
90833
|
+
import_fs99.default.writeFileSync(target, gen.text, { mode: 384, flag: "wx" });
|
|
90834
|
+
import_fs99.default.chmodSync(target, 384);
|
|
90388
90835
|
const fileHash = sha256Hex(gen.text);
|
|
90389
90836
|
regenerateUserJail(addJailPath(target, "block"));
|
|
90390
90837
|
const recordIds = gen.values.map(
|
|
@@ -90402,14 +90849,14 @@ function plantKind(kind, home = import_os80.default.homedir()) {
|
|
|
90402
90849
|
}
|
|
90403
90850
|
function allowedPathsFor(kind, home) {
|
|
90404
90851
|
const site = SITES[kind];
|
|
90405
|
-
return [site.primary(home), site.fallback(home)].map((x) =>
|
|
90852
|
+
return [site.primary(home), site.fallback(home)].map((x) => import_path98.default.resolve(x));
|
|
90406
90853
|
}
|
|
90407
|
-
function removeKind(kind, home =
|
|
90854
|
+
function removeKind(kind, home = import_os81.default.homedir()) {
|
|
90408
90855
|
const live = liveRecords(kind);
|
|
90409
90856
|
if (live.length === 0) return { kind, action: "absent" };
|
|
90410
90857
|
const p = live[0].path;
|
|
90411
90858
|
const { fileHash, createdDir } = live[0];
|
|
90412
|
-
if (!allowedPathsFor(kind, home).includes(
|
|
90859
|
+
if (!allowedPathsFor(kind, home).includes(import_path98.default.resolve(p))) {
|
|
90413
90860
|
return {
|
|
90414
90861
|
kind,
|
|
90415
90862
|
action: "refused",
|
|
@@ -90417,7 +90864,7 @@ function removeKind(kind, home = import_os80.default.homedir()) {
|
|
|
90417
90864
|
reason: `${p} is not a path node9 plants a ${kind} decoy at; refusing to delete it. If you believe this is a decoy, remove it by hand.`
|
|
90418
90865
|
};
|
|
90419
90866
|
}
|
|
90420
|
-
if (!
|
|
90867
|
+
if (!import_fs99.default.existsSync(p)) {
|
|
90421
90868
|
for (const r of live) retireCanary(r.id);
|
|
90422
90869
|
unjail(p);
|
|
90423
90870
|
return { kind, action: "already-gone", path: p };
|
|
@@ -90430,13 +90877,13 @@ function removeKind(kind, home = import_os80.default.homedir()) {
|
|
|
90430
90877
|
reason: `${p} changed since node9 wrote it; inspect and remove it by hand`
|
|
90431
90878
|
};
|
|
90432
90879
|
}
|
|
90433
|
-
|
|
90880
|
+
import_fs99.default.unlinkSync(p);
|
|
90434
90881
|
let dirRemoved = false;
|
|
90435
90882
|
if (createdDir) {
|
|
90436
|
-
const dir2 =
|
|
90883
|
+
const dir2 = import_path98.default.dirname(p);
|
|
90437
90884
|
try {
|
|
90438
|
-
if (
|
|
90439
|
-
|
|
90885
|
+
if (import_fs99.default.readdirSync(dir2).length === 0) {
|
|
90886
|
+
import_fs99.default.rmdirSync(dir2);
|
|
90440
90887
|
dirRemoved = true;
|
|
90441
90888
|
}
|
|
90442
90889
|
} catch {
|
|
@@ -90460,14 +90907,14 @@ function statusAll() {
|
|
|
90460
90907
|
const p = live[0].path;
|
|
90461
90908
|
return {
|
|
90462
90909
|
kind,
|
|
90463
|
-
state:
|
|
90910
|
+
state: import_fs99.default.existsSync(p) ? "planted" : "missing",
|
|
90464
90911
|
path: p,
|
|
90465
90912
|
records: live.length,
|
|
90466
90913
|
plantedAt: live[0].plantedAt
|
|
90467
90914
|
};
|
|
90468
90915
|
});
|
|
90469
90916
|
}
|
|
90470
|
-
function rotateKind(kind, home =
|
|
90917
|
+
function rotateKind(kind, home = import_os81.default.homedir()) {
|
|
90471
90918
|
const removed = removeKind(kind);
|
|
90472
90919
|
if (removed.action === "refused") return { removed };
|
|
90473
90920
|
return { removed, planted: plantKind(kind, home) };
|
|
@@ -90556,15 +91003,15 @@ init_daemon3();
|
|
|
90556
91003
|
// src/cli/commands/sandbox.ts
|
|
90557
91004
|
init_cjs_shims();
|
|
90558
91005
|
var import_chalk41 = __toESM(require("chalk"));
|
|
90559
|
-
var
|
|
90560
|
-
var
|
|
91006
|
+
var import_fs102 = __toESM(require("fs"));
|
|
91007
|
+
var import_path101 = __toESM(require("path"));
|
|
90561
91008
|
var import_child_process16 = require("child_process");
|
|
90562
91009
|
init_config();
|
|
90563
91010
|
|
|
90564
91011
|
// src/sandbox/config.ts
|
|
90565
91012
|
init_cjs_shims();
|
|
90566
|
-
var
|
|
90567
|
-
var
|
|
91013
|
+
var import_fs100 = __toESM(require("fs"));
|
|
91014
|
+
var import_path99 = __toESM(require("path"));
|
|
90568
91015
|
var import_yaml2 = require("yaml");
|
|
90569
91016
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
90570
91017
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -90637,16 +91084,16 @@ function scaffoldSandboxYaml(agent) {
|
|
|
90637
91084
|
return header + (0, import_yaml2.stringify)(defaultSandboxConfig(agent));
|
|
90638
91085
|
}
|
|
90639
91086
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
90640
|
-
return
|
|
91087
|
+
return import_path99.default.join(cwd, SANDBOX_CONFIG_FILE);
|
|
90641
91088
|
}
|
|
90642
91089
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
90643
91090
|
const p = sandboxConfigPath(cwd);
|
|
90644
|
-
if (!
|
|
91091
|
+
if (!import_fs100.default.existsSync(p)) {
|
|
90645
91092
|
throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
|
|
90646
91093
|
}
|
|
90647
91094
|
let raw;
|
|
90648
91095
|
try {
|
|
90649
|
-
raw = (0, import_yaml2.parse)(
|
|
91096
|
+
raw = (0, import_yaml2.parse)(import_fs100.default.readFileSync(p, "utf-8"));
|
|
90650
91097
|
} catch (err2) {
|
|
90651
91098
|
throw new Error(
|
|
90652
91099
|
`sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
|
|
@@ -90707,14 +91154,14 @@ init_atomic_write();
|
|
|
90707
91154
|
|
|
90708
91155
|
// src/sandbox/runtime.ts
|
|
90709
91156
|
init_cjs_shims();
|
|
90710
|
-
var
|
|
90711
|
-
var
|
|
90712
|
-
var
|
|
91157
|
+
var import_fs101 = __toESM(require("fs"));
|
|
91158
|
+
var import_os82 = __toESM(require("os"));
|
|
91159
|
+
var import_path100 = __toESM(require("path"));
|
|
90713
91160
|
var import_crypto27 = __toESM(require("crypto"));
|
|
90714
91161
|
var import_child_process15 = require("child_process");
|
|
90715
91162
|
init_templates();
|
|
90716
91163
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
90717
|
-
return
|
|
91164
|
+
return import_path100.default.join(cwd, ".node9", "sandbox", "data");
|
|
90718
91165
|
}
|
|
90719
91166
|
function detectEngine(engine) {
|
|
90720
91167
|
const r = (0, import_child_process15.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -90725,7 +91172,7 @@ function detectEngine(engine) {
|
|
|
90725
91172
|
}
|
|
90726
91173
|
function agentCredentialsMount(agent) {
|
|
90727
91174
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
90728
|
-
return { hostPath:
|
|
91175
|
+
return { hostPath: import_path100.default.join(import_os82.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
90729
91176
|
}
|
|
90730
91177
|
function buildRunArgs(opts) {
|
|
90731
91178
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -90735,7 +91182,7 @@ function buildRunArgs(opts) {
|
|
|
90735
91182
|
args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
|
|
90736
91183
|
if (config.node9.mountAgentCredentials) {
|
|
90737
91184
|
const creds = agentCredentialsMount(config.agent);
|
|
90738
|
-
if (
|
|
91185
|
+
if (import_fs101.default.existsSync(creds.hostPath)) {
|
|
90739
91186
|
args.push("-v", `${creds.hostPath}:${creds.target}`);
|
|
90740
91187
|
}
|
|
90741
91188
|
}
|
|
@@ -90753,30 +91200,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
90753
91200
|
return import_crypto27.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
90754
91201
|
}
|
|
90755
91202
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
90756
|
-
return
|
|
91203
|
+
return import_path100.default.join(cwd, ".node9", "sandbox", "build");
|
|
90757
91204
|
}
|
|
90758
91205
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
90759
91206
|
const dir2 = sandboxBuildDir(cwd);
|
|
90760
|
-
|
|
90761
|
-
|
|
90762
|
-
|
|
91207
|
+
import_fs101.default.mkdirSync(dir2, { recursive: true });
|
|
91208
|
+
import_fs101.default.writeFileSync(import_path100.default.join(dir2, "Dockerfile"), dockerfile);
|
|
91209
|
+
import_fs101.default.writeFileSync(import_path100.default.join(dir2, "entrypoint.sh"), entrypoint);
|
|
90763
91210
|
return dir2;
|
|
90764
91211
|
}
|
|
90765
91212
|
function writeAllowlist(cwd, hosts) {
|
|
90766
|
-
const dir2 =
|
|
90767
|
-
|
|
90768
|
-
const p =
|
|
90769
|
-
|
|
91213
|
+
const dir2 = import_path100.default.join(cwd, ".node9", "sandbox");
|
|
91214
|
+
import_fs101.default.mkdirSync(dir2, { recursive: true });
|
|
91215
|
+
const p = import_path100.default.join(dir2, "allowed-domains.txt");
|
|
91216
|
+
import_fs101.default.writeFileSync(p, hosts.join("\n") + "\n");
|
|
90770
91217
|
return p;
|
|
90771
91218
|
}
|
|
90772
91219
|
function resolveHomePath(p) {
|
|
90773
|
-
return p.startsWith("~") ?
|
|
91220
|
+
return p.startsWith("~") ? import_path100.default.join(import_os82.default.homedir(), p.slice(1)) : import_path100.default.resolve(p);
|
|
90774
91221
|
}
|
|
90775
91222
|
|
|
90776
91223
|
// src/cli/commands/sandbox.ts
|
|
90777
91224
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
90778
|
-
|
|
90779
|
-
const configPath2 =
|
|
91225
|
+
import_fs102.default.mkdirSync(dataDir, { recursive: true });
|
|
91226
|
+
const configPath2 = import_path101.default.join(dataDir, "config.json");
|
|
90780
91227
|
const seed = {
|
|
90781
91228
|
settings: {
|
|
90782
91229
|
approvers: {
|
|
@@ -90787,7 +91234,7 @@ function seedDataDirConfig(dataDir, sandbox) {
|
|
|
90787
91234
|
}
|
|
90788
91235
|
}
|
|
90789
91236
|
};
|
|
90790
|
-
|
|
91237
|
+
import_fs102.default.writeFileSync(configPath2, JSON.stringify(seed, null, 2), { mode: 384 });
|
|
90791
91238
|
}
|
|
90792
91239
|
function registerSandboxCommand(program2, version2) {
|
|
90793
91240
|
const node9Version2 = pinnedNode9Version(version2);
|
|
@@ -90796,7 +91243,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90796
91243
|
const agent = opts.agent === "codex" ? "codex" : "claude";
|
|
90797
91244
|
const p = sandboxConfigPath();
|
|
90798
91245
|
try {
|
|
90799
|
-
|
|
91246
|
+
import_fs102.default.writeFileSync(p, scaffoldSandboxYaml(agent), { flag: "wx" });
|
|
90800
91247
|
} catch (e) {
|
|
90801
91248
|
if (e.code !== "EEXIST") throw e;
|
|
90802
91249
|
console.log(
|
|
@@ -90843,8 +91290,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90843
91290
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
90844
91291
|
const hash2 = imageContentHash(dockerfile, entrypoint);
|
|
90845
91292
|
const image = sandbox.runtime.image;
|
|
90846
|
-
const hashFile =
|
|
90847
|
-
const lastHash =
|
|
91293
|
+
const hashFile = import_path101.default.join(sandboxBuildDir(cwd), ".image-hash");
|
|
91294
|
+
const lastHash = import_fs102.default.existsSync(hashFile) ? import_fs102.default.readFileSync(hashFile, "utf-8").trim() : "";
|
|
90848
91295
|
const imageExists = (0, import_child_process16.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
90849
91296
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash2;
|
|
90850
91297
|
if (needBuild) {
|
|
@@ -90870,7 +91317,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90870
91317
|
});
|
|
90871
91318
|
if (sandbox.node9.mountAgentCredentials) {
|
|
90872
91319
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
90873
|
-
if (
|
|
91320
|
+
if (import_fs102.default.existsSync(creds.hostPath)) {
|
|
90874
91321
|
console.log(import_chalk41.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
90875
91322
|
} else {
|
|
90876
91323
|
console.log(
|
|
@@ -90886,20 +91333,20 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90886
91333
|
process.exit(r.status ?? 0);
|
|
90887
91334
|
});
|
|
90888
91335
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
90889
|
-
const auditPath =
|
|
90890
|
-
if (!
|
|
91336
|
+
const auditPath = import_path101.default.join(sandboxDataDir(), "audit.log");
|
|
91337
|
+
if (!import_fs102.default.existsSync(auditPath)) {
|
|
90891
91338
|
console.log(import_chalk41.default.dim(" no sandbox audit yet."));
|
|
90892
91339
|
return;
|
|
90893
91340
|
}
|
|
90894
91341
|
(0, import_child_process16.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
90895
91342
|
});
|
|
90896
91343
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
90897
|
-
const auditPath =
|
|
90898
|
-
if (!
|
|
91344
|
+
const auditPath = import_path101.default.join(sandboxDataDir(), "audit.log");
|
|
91345
|
+
if (!import_fs102.default.existsSync(auditPath)) {
|
|
90899
91346
|
console.log(import_chalk41.default.dim(" no sandbox audit yet."));
|
|
90900
91347
|
return;
|
|
90901
91348
|
}
|
|
90902
|
-
process.stdout.write(
|
|
91349
|
+
process.stdout.write(import_fs102.default.readFileSync(auditPath, "utf-8"));
|
|
90903
91350
|
});
|
|
90904
91351
|
cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
|
|
90905
91352
|
const cwd = process.cwd();
|
|
@@ -90913,7 +91360,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90913
91360
|
stdio: "ignore"
|
|
90914
91361
|
});
|
|
90915
91362
|
}
|
|
90916
|
-
|
|
91363
|
+
import_fs102.default.rmSync(import_path101.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
90917
91364
|
console.log(import_chalk41.default.green(" \u2713 sandbox image + build + data removed."));
|
|
90918
91365
|
});
|
|
90919
91366
|
}
|
|
@@ -91142,13 +91589,13 @@ function registerPackageIndexCommand(program2) {
|
|
|
91142
91589
|
// src/cli/commands/skill-pin.ts
|
|
91143
91590
|
init_cjs_shims();
|
|
91144
91591
|
var import_chalk45 = __toESM(require("chalk"));
|
|
91145
|
-
var
|
|
91146
|
-
var
|
|
91147
|
-
var
|
|
91592
|
+
var import_fs103 = __toESM(require("fs"));
|
|
91593
|
+
var import_os83 = __toESM(require("os"));
|
|
91594
|
+
var import_path102 = __toESM(require("path"));
|
|
91148
91595
|
init_skill_pin();
|
|
91149
91596
|
function wipeSkillSessions() {
|
|
91150
91597
|
try {
|
|
91151
|
-
|
|
91598
|
+
import_fs103.default.rmSync(import_path102.default.join(import_os83.default.homedir(), ".node9", "skill-sessions"), {
|
|
91152
91599
|
recursive: true,
|
|
91153
91600
|
force: true
|
|
91154
91601
|
});
|
|
@@ -91231,15 +91678,15 @@ function registerSkillPinCommand(program2) {
|
|
|
91231
91678
|
|
|
91232
91679
|
// src/cli/commands/decisions.ts
|
|
91233
91680
|
init_cjs_shims();
|
|
91234
|
-
var
|
|
91235
|
-
var
|
|
91236
|
-
var
|
|
91681
|
+
var import_fs104 = __toESM(require("fs"));
|
|
91682
|
+
var import_os84 = __toESM(require("os"));
|
|
91683
|
+
var import_path103 = __toESM(require("path"));
|
|
91237
91684
|
var import_chalk46 = __toESM(require("chalk"));
|
|
91238
|
-
var DECISIONS_FILE2 =
|
|
91685
|
+
var DECISIONS_FILE2 = import_path103.default.join(import_os84.default.homedir(), ".node9", "decisions.json");
|
|
91239
91686
|
function readDecisions() {
|
|
91240
91687
|
try {
|
|
91241
|
-
if (!
|
|
91242
|
-
const raw =
|
|
91688
|
+
if (!import_fs104.default.existsSync(DECISIONS_FILE2)) return {};
|
|
91689
|
+
const raw = import_fs104.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
91243
91690
|
const parsed = JSON.parse(raw);
|
|
91244
91691
|
const out = {};
|
|
91245
91692
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -91251,11 +91698,11 @@ function readDecisions() {
|
|
|
91251
91698
|
}
|
|
91252
91699
|
}
|
|
91253
91700
|
function writeDecisions(d) {
|
|
91254
|
-
const dir2 =
|
|
91255
|
-
if (!
|
|
91701
|
+
const dir2 = import_path103.default.dirname(DECISIONS_FILE2);
|
|
91702
|
+
if (!import_fs104.default.existsSync(dir2)) import_fs104.default.mkdirSync(dir2, { recursive: true });
|
|
91256
91703
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
91257
|
-
|
|
91258
|
-
|
|
91704
|
+
import_fs104.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
91705
|
+
import_fs104.default.renameSync(tmp, DECISIONS_FILE2);
|
|
91259
91706
|
}
|
|
91260
91707
|
function registerDecisionsCommand(program2) {
|
|
91261
91708
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -91313,15 +91760,15 @@ Persistent decisions (${entries.length})
|
|
|
91313
91760
|
// src/cli/commands/dlp.ts
|
|
91314
91761
|
init_cjs_shims();
|
|
91315
91762
|
var import_chalk47 = __toESM(require("chalk"));
|
|
91316
|
-
var
|
|
91317
|
-
var
|
|
91318
|
-
var
|
|
91763
|
+
var import_fs105 = __toESM(require("fs"));
|
|
91764
|
+
var import_path104 = __toESM(require("path"));
|
|
91765
|
+
var import_os85 = __toESM(require("os"));
|
|
91319
91766
|
init_safe_text();
|
|
91320
|
-
var AUDIT_LOG =
|
|
91321
|
-
var RESOLVED_FILE =
|
|
91767
|
+
var AUDIT_LOG = import_path104.default.join(import_os85.default.homedir(), ".node9", "audit.log");
|
|
91768
|
+
var RESOLVED_FILE = import_path104.default.join(import_os85.default.homedir(), ".node9", "dlp-resolved.json");
|
|
91322
91769
|
function loadResolved() {
|
|
91323
91770
|
try {
|
|
91324
|
-
const raw = JSON.parse(
|
|
91771
|
+
const raw = JSON.parse(import_fs105.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
91325
91772
|
return new Set(raw);
|
|
91326
91773
|
} catch {
|
|
91327
91774
|
return /* @__PURE__ */ new Set();
|
|
@@ -91329,13 +91776,13 @@ function loadResolved() {
|
|
|
91329
91776
|
}
|
|
91330
91777
|
function saveResolved(resolved) {
|
|
91331
91778
|
try {
|
|
91332
|
-
|
|
91779
|
+
import_fs105.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
91333
91780
|
} catch {
|
|
91334
91781
|
}
|
|
91335
91782
|
}
|
|
91336
91783
|
function loadDlpFindings() {
|
|
91337
|
-
if (!
|
|
91338
|
-
return
|
|
91784
|
+
if (!import_fs105.default.existsSync(AUDIT_LOG)) return [];
|
|
91785
|
+
return import_fs105.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
91339
91786
|
if (!line.trim()) return [];
|
|
91340
91787
|
try {
|
|
91341
91788
|
const e = JSON.parse(line);
|
|
@@ -91434,15 +91881,15 @@ function registerDlpCommand(program2) {
|
|
|
91434
91881
|
// src/cli/commands/mask.ts
|
|
91435
91882
|
init_cjs_shims();
|
|
91436
91883
|
var import_chalk48 = __toESM(require("chalk"));
|
|
91437
|
-
var
|
|
91438
|
-
var
|
|
91439
|
-
var
|
|
91884
|
+
var import_fs106 = __toESM(require("fs"));
|
|
91885
|
+
var import_path105 = __toESM(require("path"));
|
|
91886
|
+
var import_os86 = __toESM(require("os"));
|
|
91440
91887
|
init_dlp();
|
|
91441
91888
|
function findJsonlFiles(dir2) {
|
|
91442
91889
|
const results = [];
|
|
91443
|
-
if (!
|
|
91444
|
-
for (const entry of
|
|
91445
|
-
const full =
|
|
91890
|
+
if (!import_fs106.default.existsSync(dir2)) return results;
|
|
91891
|
+
for (const entry of import_fs106.default.readdirSync(dir2, { withFileTypes: true })) {
|
|
91892
|
+
const full = import_path105.default.join(dir2, entry.name);
|
|
91446
91893
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
91447
91894
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
91448
91895
|
}
|
|
@@ -91485,7 +91932,7 @@ function redactJson(obj) {
|
|
|
91485
91932
|
function processFile(filePath, dryRun) {
|
|
91486
91933
|
let raw;
|
|
91487
91934
|
try {
|
|
91488
|
-
raw =
|
|
91935
|
+
raw = import_fs106.default.readFileSync(filePath, "utf-8");
|
|
91489
91936
|
} catch {
|
|
91490
91937
|
return { redactedLines: 0, patterns: [] };
|
|
91491
91938
|
}
|
|
@@ -91517,14 +91964,14 @@ function processFile(filePath, dryRun) {
|
|
|
91517
91964
|
}
|
|
91518
91965
|
}
|
|
91519
91966
|
if (!dryRun && redactedLines > 0) {
|
|
91520
|
-
|
|
91967
|
+
import_fs106.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
91521
91968
|
}
|
|
91522
91969
|
return { redactedLines, patterns };
|
|
91523
91970
|
}
|
|
91524
91971
|
function processJsonFile(filePath, dryRun) {
|
|
91525
91972
|
let raw;
|
|
91526
91973
|
try {
|
|
91527
|
-
raw =
|
|
91974
|
+
raw = import_fs106.default.readFileSync(filePath, "utf-8");
|
|
91528
91975
|
} catch {
|
|
91529
91976
|
return { redactedLines: 0, patterns: [] };
|
|
91530
91977
|
}
|
|
@@ -91537,15 +91984,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
91537
91984
|
const { value, modified, found } = redactJson(parsed);
|
|
91538
91985
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
91539
91986
|
if (!dryRun) {
|
|
91540
|
-
|
|
91987
|
+
import_fs106.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
91541
91988
|
}
|
|
91542
91989
|
return { redactedLines: 1, patterns: found };
|
|
91543
91990
|
}
|
|
91544
91991
|
function findJsonFiles(dir2) {
|
|
91545
91992
|
const results = [];
|
|
91546
|
-
if (!
|
|
91547
|
-
for (const entry of
|
|
91548
|
-
const full =
|
|
91993
|
+
if (!import_fs106.default.existsSync(dir2)) return results;
|
|
91994
|
+
for (const entry of import_fs106.default.readdirSync(dir2, { withFileTypes: true })) {
|
|
91995
|
+
const full = import_path105.default.join(dir2, entry.name);
|
|
91549
91996
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
91550
91997
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
91551
91998
|
}
|
|
@@ -91554,9 +92001,9 @@ function findJsonFiles(dir2) {
|
|
|
91554
92001
|
function registerMaskCommand(program2) {
|
|
91555
92002
|
program2.command("mask").description("Redact plaintext secrets from local AI session history files").option("--dry-run", "show what would be redacted without making changes").option("--all", "scan all history (default: last 30 days)").action(async (options) => {
|
|
91556
92003
|
const dryRun = !!options.dryRun;
|
|
91557
|
-
const home =
|
|
91558
|
-
const claudeDir =
|
|
91559
|
-
const geminiDir =
|
|
92004
|
+
const home = import_os86.default.homedir();
|
|
92005
|
+
const claudeDir = import_path105.default.join(home, ".claude", "projects");
|
|
92006
|
+
const geminiDir = import_path105.default.join(home, ".gemini", "tmp");
|
|
91560
92007
|
const allFiles = [
|
|
91561
92008
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
91562
92009
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -91564,7 +92011,7 @@ function registerMaskCommand(program2) {
|
|
|
91564
92011
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
91565
92012
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
91566
92013
|
try {
|
|
91567
|
-
return
|
|
92014
|
+
return import_fs106.default.statSync(f.path).mtime >= cutoff;
|
|
91568
92015
|
} catch {
|
|
91569
92016
|
return false;
|
|
91570
92017
|
}
|
|
@@ -91621,7 +92068,7 @@ function registerMaskCommand(program2) {
|
|
|
91621
92068
|
init_blast();
|
|
91622
92069
|
init_safe_text();
|
|
91623
92070
|
var { version } = JSON.parse(
|
|
91624
|
-
|
|
92071
|
+
import_fs110.default.readFileSync(import_path109.default.join(__dirname, "../package.json"), "utf-8")
|
|
91625
92072
|
);
|
|
91626
92073
|
var program = new import_commander.Command();
|
|
91627
92074
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
@@ -91779,8 +92226,8 @@ function undoLeftoverNote() {
|
|
|
91779
92226
|
program.command("uninstall").description("Remove all Node9 hooks and optionally delete config files").option("--purge", "Also delete ~/.node9/ directory (config, audit log, credentials)").action(async (options) => {
|
|
91780
92227
|
console.log(import_chalk50.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
|
|
91781
92228
|
try {
|
|
91782
|
-
const credRaw =
|
|
91783
|
-
|
|
92229
|
+
const credRaw = import_fs110.default.readFileSync(
|
|
92230
|
+
import_path109.default.join(import_os90.default.homedir(), ".node9", "credentials.json"),
|
|
91784
92231
|
"utf-8"
|
|
91785
92232
|
);
|
|
91786
92233
|
const prof = JSON.parse(credRaw)[process.env.NODE9_PROFILE || "default"];
|
|
@@ -91855,7 +92302,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
91855
92302
|
if (removed.length > 0 || refused.length > 0) {
|
|
91856
92303
|
console.log(import_chalk50.default.bold("\nRemoving decoy credentials..."));
|
|
91857
92304
|
for (const r of removed) {
|
|
91858
|
-
if (r.path) console.log(import_chalk50.default.green(` \u2705 ${r.path.replace(
|
|
92305
|
+
if (r.path) console.log(import_chalk50.default.green(` \u2705 ${r.path.replace(import_os90.default.homedir(), "~")}`));
|
|
91859
92306
|
}
|
|
91860
92307
|
for (const r of refused) {
|
|
91861
92308
|
decoysLeft.push(r.path ?? "(unknown path)");
|
|
@@ -91872,8 +92319,8 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
91872
92319
|
decoysLeft = ["(the decoy registry could not be read)"];
|
|
91873
92320
|
}
|
|
91874
92321
|
if (options.purge) {
|
|
91875
|
-
const node9Dir =
|
|
91876
|
-
if (
|
|
92322
|
+
const node9Dir = import_path109.default.join(import_os90.default.homedir(), ".node9");
|
|
92323
|
+
if (import_fs110.default.existsSync(node9Dir)) {
|
|
91877
92324
|
const alsoSnapshots = undoLeftoverPaths().length > 0 ? ", old undo snapshots" : "";
|
|
91878
92325
|
if (decoysLeft.length > 0) {
|
|
91879
92326
|
console.error(import_chalk50.default.red("\n \u26A0\uFE0F Decoy credential files are still on disk:"));
|
|
@@ -91889,8 +92336,8 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
91889
92336
|
default: false
|
|
91890
92337
|
});
|
|
91891
92338
|
if (confirmed) {
|
|
91892
|
-
|
|
91893
|
-
if (
|
|
92339
|
+
import_fs110.default.rmSync(node9Dir, { recursive: true });
|
|
92340
|
+
if (import_fs110.default.existsSync(node9Dir)) {
|
|
91894
92341
|
console.error(
|
|
91895
92342
|
import_chalk50.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
91896
92343
|
);
|
|
@@ -92046,7 +92493,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
92046
92493
|
});
|
|
92047
92494
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
92048
92495
|
try {
|
|
92049
|
-
const dashboardPath =
|
|
92496
|
+
const dashboardPath = import_path109.default.join(__dirname, "dashboard.mjs");
|
|
92050
92497
|
const dynamicImport = new Function("id", "return import(id)");
|
|
92051
92498
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
92052
92499
|
await mod.startMonitor();
|
|
@@ -92084,14 +92531,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
92084
92531
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
92085
92532
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
92086
92533
|
if (subcommand === "debug") {
|
|
92087
|
-
const flagFile =
|
|
92534
|
+
const flagFile = import_path109.default.join(import_os90.default.homedir(), ".node9", "hud-debug");
|
|
92088
92535
|
if (state === "on") {
|
|
92089
|
-
|
|
92090
|
-
|
|
92536
|
+
import_fs110.default.mkdirSync(import_path109.default.dirname(flagFile), { recursive: true });
|
|
92537
|
+
import_fs110.default.writeFileSync(flagFile, "");
|
|
92091
92538
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
92092
92539
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
92093
92540
|
} else if (state === "off") {
|
|
92094
|
-
if (
|
|
92541
|
+
if (import_fs110.default.existsSync(flagFile)) import_fs110.default.unlinkSync(flagFile);
|
|
92095
92542
|
console.log("HUD debug logging disabled.");
|
|
92096
92543
|
} else {
|
|
92097
92544
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -92206,6 +92653,7 @@ registerTrustCommand(program);
|
|
|
92206
92653
|
registerSyncCommand(program);
|
|
92207
92654
|
registerAgentsCommand(program);
|
|
92208
92655
|
registerScanCommand(program);
|
|
92656
|
+
registerForecastCasesCommand(program);
|
|
92209
92657
|
registerPostureCommand(program);
|
|
92210
92658
|
registerScanRepoCommand(program);
|
|
92211
92659
|
registerEgressCommand(program);
|
|
@@ -92225,9 +92673,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
92225
92673
|
const isCheckHook = process.argv[2] === "check";
|
|
92226
92674
|
if (isCheckHook) {
|
|
92227
92675
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
92228
|
-
const logPath =
|
|
92676
|
+
const logPath = import_path109.default.join(import_os90.default.homedir(), ".node9", "hook-debug.log");
|
|
92229
92677
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
92230
|
-
|
|
92678
|
+
import_fs110.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
92231
92679
|
`);
|
|
92232
92680
|
}
|
|
92233
92681
|
process.exit(0);
|