@node9/proxy 2.43.0 → 2.43.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.js +103 -26
- package/dist/cli.mjs +103 -26
- package/dist/dashboard.mjs +213 -135
- package/dist/index.js +185 -105
- package/dist/index.mjs +185 -105
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -881,12 +881,12 @@ function judgeInlineCode(language, code, isProtected) {
|
|
|
881
881
|
category
|
|
882
882
|
};
|
|
883
883
|
}
|
|
884
|
-
const
|
|
885
|
-
if (
|
|
884
|
+
const path45 = protectedLiteral(text, isProtected);
|
|
885
|
+
if (path45) {
|
|
886
886
|
return {
|
|
887
887
|
outcome: "dangerous",
|
|
888
888
|
what: WHAT["reads-protected"],
|
|
889
|
-
evidence:
|
|
889
|
+
evidence: path45.slice(0, 60),
|
|
890
890
|
category: "reads-protected"
|
|
891
891
|
};
|
|
892
892
|
}
|
|
@@ -3049,9 +3049,9 @@ function ruleServerMatches(rule, serverLabel) {
|
|
|
3049
3049
|
if (rule.notServer && label2 && matchesPattern(label2, rule.notServer)) return false;
|
|
3050
3050
|
return true;
|
|
3051
3051
|
}
|
|
3052
|
-
function getNestedValue(obj,
|
|
3052
|
+
function getNestedValue(obj, path45) {
|
|
3053
3053
|
if (!obj || typeof obj !== "object") return null;
|
|
3054
|
-
const segments2 =
|
|
3054
|
+
const segments2 = path45.split(".");
|
|
3055
3055
|
for (const seg of segments2) {
|
|
3056
3056
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
3057
3057
|
}
|
|
@@ -4031,8 +4031,8 @@ function collectFileAccesses(tool, args, context = {}, inspection = {}) {
|
|
|
4031
4031
|
}
|
|
4032
4032
|
return out;
|
|
4033
4033
|
}
|
|
4034
|
-
function within(
|
|
4035
|
-
return
|
|
4034
|
+
function within(path45, root) {
|
|
4035
|
+
return path45 === root || path45.startsWith(root === "/" ? "/" : root + "/");
|
|
4036
4036
|
}
|
|
4037
4037
|
function hits(access, paths, directories, context) {
|
|
4038
4038
|
const home = context.homeDirs?.[0] ?? "~";
|
|
@@ -5420,7 +5420,10 @@ function classify(inv) {
|
|
|
5420
5420
|
out.push({ ...f, shown: inv.shown, reason: `${f.reason}: ${inv.shown}` });
|
|
5421
5421
|
};
|
|
5422
5422
|
if (hooksBypass(inv)) found(HOOKS_BYPASS);
|
|
5423
|
-
|
|
5423
|
+
const staged = stagesEverything(inv);
|
|
5424
|
+
if (staged) {
|
|
5425
|
+
found(staged.ifWorkTreeTop === void 0 ? STAGE_ALL : { ...STAGE_ALL, ...staged });
|
|
5426
|
+
}
|
|
5424
5427
|
if (inv.sub === null) {
|
|
5425
5428
|
found(UNREADABLE);
|
|
5426
5429
|
return out;
|
|
@@ -5481,12 +5484,35 @@ function appliedValue(env, name) {
|
|
|
5481
5484
|
const word = f?.Stmts?.[0]?.Cmd?.Args?.[1];
|
|
5482
5485
|
return word ? resolveWordLiteral(word) : null;
|
|
5483
5486
|
}
|
|
5487
|
+
function lexicalPath(p) {
|
|
5488
|
+
if (/^[\\/~$]/.test(p) || /^[A-Za-z]:/.test(p)) return null;
|
|
5489
|
+
const parts = [];
|
|
5490
|
+
let climbed = false;
|
|
5491
|
+
for (const part of p.split(/[\\/]+/)) {
|
|
5492
|
+
if (part === "" || part === ".") continue;
|
|
5493
|
+
if (part === "..") {
|
|
5494
|
+
if (parts.length === 0) climbed = true;
|
|
5495
|
+
else parts.pop();
|
|
5496
|
+
} else parts.push(part);
|
|
5497
|
+
}
|
|
5498
|
+
return { parts, climbed };
|
|
5499
|
+
}
|
|
5500
|
+
function hooksPathBypasses(value) {
|
|
5501
|
+
if (value === null || value === void 0) return true;
|
|
5502
|
+
const v = value.trim();
|
|
5503
|
+
if (v === "" || v === "true") return true;
|
|
5504
|
+
const lp = lexicalPath(v);
|
|
5505
|
+
if (lp === null || lp.climbed || lp.parts.length === 0) return true;
|
|
5506
|
+
return lp.parts[0] === ".git" && lp.parts[1] !== "hooks";
|
|
5507
|
+
}
|
|
5484
5508
|
function hooksBypass(inv) {
|
|
5485
|
-
if (inv.config.has("core.hookspath")
|
|
5509
|
+
if (inv.config.has("core.hookspath") && hooksPathBypasses(inv.config.get("core.hookspath")))
|
|
5510
|
+
return true;
|
|
5486
5511
|
for (const [name, value] of inv.env) {
|
|
5487
5512
|
if (name === "GIT_CONFIG_PARAMETERS" && value !== null && /core\.hookspath/i.test(value))
|
|
5488
5513
|
return true;
|
|
5489
|
-
|
|
5514
|
+
const key = /^GIT_CONFIG_KEY_(\d+)$/.exec(name);
|
|
5515
|
+
if (key && value !== null && value.toLowerCase() === "core.hookspath" && hooksPathBypasses(inv.env.get(`GIT_CONFIG_VALUE_${key[1]}`)))
|
|
5490
5516
|
return true;
|
|
5491
5517
|
}
|
|
5492
5518
|
for (const name of HOOK_KILL_SWITCHES) {
|
|
@@ -5528,7 +5554,10 @@ function configWritesHooksPath(args) {
|
|
|
5528
5554
|
}
|
|
5529
5555
|
const key = args[i];
|
|
5530
5556
|
if (key === null || key === void 0 || key.toLowerCase() !== "core.hookspath") return false;
|
|
5531
|
-
|
|
5557
|
+
const unset = args.slice(0, i).some((w) => w === "--unset" || w === "--unset-all") || args[0] === "unset";
|
|
5558
|
+
if (unset) return true;
|
|
5559
|
+
if (i + 1 < args.length) return hooksPathBypasses(args[i + 1]);
|
|
5560
|
+
return write;
|
|
5532
5561
|
}
|
|
5533
5562
|
function isHookPath(word) {
|
|
5534
5563
|
return /(^|[\\/])(\.git[\\/]hooks|\.husky)([\\/]|$)/.test(word);
|
|
@@ -5563,31 +5592,49 @@ function chmodDisarmsHook(args, shown) {
|
|
|
5563
5592
|
function wholeTree(operand) {
|
|
5564
5593
|
if (/^:\(top\)\.?$/.test(operand) || operand === ":/" || operand === "*") return true;
|
|
5565
5594
|
if (operand.startsWith(":")) return false;
|
|
5595
|
+
const lp = lexicalPath(operand);
|
|
5596
|
+
return lp !== null && lp.parts.length === 0;
|
|
5597
|
+
}
|
|
5598
|
+
function chdirPrefix(inv) {
|
|
5599
|
+
const dirs = inv.chdir ?? [];
|
|
5600
|
+
if (dirs.length === 0) return null;
|
|
5566
5601
|
const parts = [];
|
|
5567
|
-
for (const
|
|
5568
|
-
if (
|
|
5569
|
-
|
|
5570
|
-
|
|
5602
|
+
for (const d of dirs) {
|
|
5603
|
+
if (d === null || d === "") return null;
|
|
5604
|
+
const lp = lexicalPath(d);
|
|
5605
|
+
if (lp === null || lp.climbed) return null;
|
|
5606
|
+
parts.push(...lp.parts);
|
|
5571
5607
|
}
|
|
5572
|
-
return parts.length === 0
|
|
5608
|
+
return parts.length === 0 ? null : parts.join("/");
|
|
5573
5609
|
}
|
|
5574
5610
|
function stagesEverything(inv) {
|
|
5575
5611
|
const sub = inv.sub?.toLowerCase();
|
|
5612
|
+
const prefix = chdirPrefix(inv);
|
|
5613
|
+
const judge = (operands2) => {
|
|
5614
|
+
let conditional = false;
|
|
5615
|
+
for (const operand of operands2) {
|
|
5616
|
+
if (!wholeTree(operand)) continue;
|
|
5617
|
+
if (prefix === null || operand.startsWith(":") || operand.startsWith("/")) return {};
|
|
5618
|
+
if (wholeTree(`${prefix}/${operand === "*" ? "." : operand}`)) return {};
|
|
5619
|
+
conditional = true;
|
|
5620
|
+
}
|
|
5621
|
+
return conditional && prefix !== null ? { ifWorkTreeTop: prefix } : null;
|
|
5622
|
+
};
|
|
5576
5623
|
if (sub === "add") {
|
|
5577
5624
|
const o = parseOptions(inv.args, "", ADD_LONG_VALUE);
|
|
5578
5625
|
if (o.flags.has("-n") || o.flags.has("--dry-run") || o.flags.has("-i") || o.flags.has("--interactive") || o.flags.has("-p") || o.flags.has("--patch") || o.flags.has("-e") || o.flags.has("--edit"))
|
|
5579
|
-
return
|
|
5626
|
+
return null;
|
|
5580
5627
|
const all = o.flags.has("-A") || o.flags.has("--all") || o.flags.has("--no-ignore-removal") || o.flags.has("-u") || o.flags.has("--update");
|
|
5581
|
-
if (all && o.operands.length === 0) return
|
|
5582
|
-
return o.operands
|
|
5628
|
+
if (all && o.operands.length === 0) return {};
|
|
5629
|
+
return judge(o.operands);
|
|
5583
5630
|
}
|
|
5584
5631
|
if (sub === "commit") {
|
|
5585
5632
|
const o = parseOptions(inv.args, "mFCcut", COMMIT_LONG_VALUE);
|
|
5586
|
-
if (o.flags.has("--dry-run")) return
|
|
5587
|
-
if (o.flags.has("-a") || o.flags.has("--all")) return
|
|
5588
|
-
return o.operands
|
|
5633
|
+
if (o.flags.has("--dry-run")) return null;
|
|
5634
|
+
if (o.flags.has("-a") || o.flags.has("--all")) return {};
|
|
5635
|
+
return judge(o.operands);
|
|
5589
5636
|
}
|
|
5590
|
-
return
|
|
5637
|
+
return null;
|
|
5591
5638
|
}
|
|
5592
5639
|
function hookTextRunsNothing(text) {
|
|
5593
5640
|
return text.split(/\r?\n/).every((line) => INERT_LINE_RE.test(line.trim()));
|
|
@@ -7243,9 +7290,9 @@ function bareToolName(toolName) {
|
|
|
7243
7290
|
const parts = toolName.split("__");
|
|
7244
7291
|
return (parts.length >= 3 ? parts.slice(2).join("__") : toolName).toLowerCase();
|
|
7245
7292
|
}
|
|
7246
|
-
function valuesAt(args,
|
|
7293
|
+
function valuesAt(args, path45) {
|
|
7247
7294
|
let cursors = [args];
|
|
7248
|
-
for (const rawSegment of
|
|
7295
|
+
for (const rawSegment of path45.split(".")) {
|
|
7249
7296
|
const isArray = rawSegment.endsWith("[]");
|
|
7250
7297
|
const key = isArray ? rawSegment.slice(0, -2) : rawSegment;
|
|
7251
7298
|
const next = [];
|
|
@@ -7276,8 +7323,8 @@ function extractToolDestinations(toolName, args) {
|
|
|
7276
7323
|
try {
|
|
7277
7324
|
const out = [];
|
|
7278
7325
|
const paths = DESTINATION_ARGS.get(bareToolName(toolName)) ?? [];
|
|
7279
|
-
for (const
|
|
7280
|
-
for (const value of valuesAt(args,
|
|
7326
|
+
for (const path45 of paths) {
|
|
7327
|
+
for (const value of valuesAt(args, path45)) {
|
|
7281
7328
|
const host2 = hostOf(value);
|
|
7282
7329
|
if (host2) out.push({ host: host2, binary: toolName, raw: value });
|
|
7283
7330
|
}
|
|
@@ -7303,8 +7350,8 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
|
|
|
7303
7350
|
try {
|
|
7304
7351
|
const paths = DESTINATION_ARGS.get(bareToolName(toolName));
|
|
7305
7352
|
if (!paths) return null;
|
|
7306
|
-
for (const
|
|
7307
|
-
for (const value of valuesAt(args,
|
|
7353
|
+
for (const path45 of paths) {
|
|
7354
|
+
for (const value of valuesAt(args, path45)) {
|
|
7308
7355
|
const host2 = hostOf(value);
|
|
7309
7356
|
if (!host2) continue;
|
|
7310
7357
|
const m = classifySsrf(host2);
|
|
@@ -7313,7 +7360,7 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
|
|
|
7313
7360
|
const decision = ssrfFloorDecision(m, written, opts);
|
|
7314
7361
|
if (decision === null) continue;
|
|
7315
7362
|
const reason = decision === "review" ? ssrfDisguisedReason(m, written) : ssrfReason(m, host2);
|
|
7316
|
-
return { ...m, argPath:
|
|
7363
|
+
return { ...m, argPath: path45, host: host2, reason, decision };
|
|
7317
7364
|
}
|
|
7318
7365
|
}
|
|
7319
7366
|
return null;
|
|
@@ -7595,7 +7642,7 @@ async function evaluatePolicy(config, toolName, args, context = {}, hostHooks =
|
|
|
7595
7642
|
}
|
|
7596
7643
|
async function evaluatePolicyCore(config, toolName, args, context = {}, hooks = {}) {
|
|
7597
7644
|
const { agent, cwd, activeEnvironment } = context;
|
|
7598
|
-
const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry } = hooks;
|
|
7645
|
+
const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry, isGitWorkTreeTop: isGitWorkTreeTop2 } = hooks;
|
|
7599
7646
|
const settingsView = catalogSettings(config);
|
|
7600
7647
|
const layers = inspectionLayers(config.policy);
|
|
7601
7648
|
const cv = (id) => checkValue(settingsView, id);
|
|
@@ -7749,6 +7796,8 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
|
|
|
7749
7796
|
const action = cv(id);
|
|
7750
7797
|
const finding = action === "off" ? void 0 : git.findings.find((f) => f.checkId === id);
|
|
7751
7798
|
if (!finding) continue;
|
|
7799
|
+
if (finding.ifWorkTreeTop !== void 0 && isGitWorkTreeTop2 && cwd && !isGitWorkTreeTop2(finding.ifWorkTreeTop, cwd))
|
|
7800
|
+
continue;
|
|
7752
7801
|
const v = applyCheckValue(action, {
|
|
7753
7802
|
decision: "review",
|
|
7754
7803
|
blockedByLabel: `Node9 (AST): ${finding.ruleName}`,
|
|
@@ -16360,6 +16409,7 @@ zoo`.split("\n");
|
|
|
16360
16409
|
/** The words after `git`: global options, then the subcommand. */
|
|
16361
16410
|
visitGit(rest, env, depth, viaXargs, fromAlias, shown) {
|
|
16362
16411
|
const config = /* @__PURE__ */ new Map();
|
|
16412
|
+
const chdir = [];
|
|
16363
16413
|
let i = 0;
|
|
16364
16414
|
while (i < rest.length) {
|
|
16365
16415
|
const w = rest[i];
|
|
@@ -16374,6 +16424,7 @@ zoo`.split("\n");
|
|
|
16374
16424
|
i++;
|
|
16375
16425
|
value = i < rest.length ? rest[i] : null;
|
|
16376
16426
|
}
|
|
16427
|
+
if (name === "-C") chdir.push(viaXargs || (value ?? "").includes("{}") ? null : value);
|
|
16377
16428
|
if (name === "-c" && value !== null) {
|
|
16378
16429
|
const ceq = value.indexOf("=");
|
|
16379
16430
|
const key = (ceq > 0 ? value.slice(0, ceq) : value).toLowerCase();
|
|
@@ -16390,7 +16441,7 @@ zoo`.split("\n");
|
|
|
16390
16441
|
}
|
|
16391
16442
|
const subWord = i < rest.length ? rest[i] : void 0;
|
|
16392
16443
|
const args = rest.slice(i + 1);
|
|
16393
|
-
const inv = { sub: null, args, config, env, shown };
|
|
16444
|
+
const inv = { sub: null, args, config, env, shown, chdir };
|
|
16394
16445
|
if (subWord === void 0) {
|
|
16395
16446
|
if (!viaXargs) return;
|
|
16396
16447
|
this.emit(inv);
|
|
@@ -16404,16 +16455,23 @@ zoo`.split("\n");
|
|
|
16404
16455
|
const fromConfig = config.get(`alias.${subWord.toLowerCase()}`);
|
|
16405
16456
|
const alias = fromConfig !== void 0 ? fromConfig : this.aliases.get(subWord);
|
|
16406
16457
|
if (alias !== void 0 && !fromAlias) {
|
|
16407
|
-
this.expandAlias(subWord, alias, args, env, depth, 0, shown);
|
|
16458
|
+
this.expandAlias(subWord, alias, args, env, depth, 0, shown, chdir);
|
|
16408
16459
|
return;
|
|
16409
16460
|
}
|
|
16410
16461
|
inv.sub = subWord;
|
|
16411
16462
|
this.emit(inv);
|
|
16412
16463
|
this.recordAliasDefinition(inv, env, depth);
|
|
16413
16464
|
}
|
|
16414
|
-
expandAlias(name, value, args, env, depth, level, shown) {
|
|
16465
|
+
expandAlias(name, value, args, env, depth, level, shown, chdir) {
|
|
16415
16466
|
if (value === null) {
|
|
16416
|
-
this.emit({
|
|
16467
|
+
this.emit({
|
|
16468
|
+
sub: null,
|
|
16469
|
+
args,
|
|
16470
|
+
config: /* @__PURE__ */ new Map(),
|
|
16471
|
+
env,
|
|
16472
|
+
shown: `${shown} (alias ${name})`,
|
|
16473
|
+
chdir
|
|
16474
|
+
});
|
|
16417
16475
|
return;
|
|
16418
16476
|
}
|
|
16419
16477
|
if (value.startsWith("!")) {
|
|
@@ -16427,7 +16485,16 @@ zoo`.split("\n");
|
|
|
16427
16485
|
const nested = this.aliases.get(sub);
|
|
16428
16486
|
const expandedShown = `${shown} (alias ${name} = ${value})`;
|
|
16429
16487
|
if (nested !== void 0 && level < MAX_ALIAS_DEPTH) {
|
|
16430
|
-
this.expandAlias(
|
|
16488
|
+
this.expandAlias(
|
|
16489
|
+
sub,
|
|
16490
|
+
nested,
|
|
16491
|
+
[...words.slice(1), ...args],
|
|
16492
|
+
env,
|
|
16493
|
+
depth,
|
|
16494
|
+
level + 1,
|
|
16495
|
+
shown,
|
|
16496
|
+
chdir
|
|
16497
|
+
);
|
|
16431
16498
|
return;
|
|
16432
16499
|
}
|
|
16433
16500
|
this.emit({
|
|
@@ -16435,7 +16502,8 @@ zoo`.split("\n");
|
|
|
16435
16502
|
args: [...words.slice(1), ...args],
|
|
16436
16503
|
config: /* @__PURE__ */ new Map(),
|
|
16437
16504
|
env,
|
|
16438
|
-
shown: expandedShown
|
|
16505
|
+
shown: expandedShown,
|
|
16506
|
+
chdir
|
|
16439
16507
|
});
|
|
16440
16508
|
}
|
|
16441
16509
|
/**
|
|
@@ -16469,7 +16537,7 @@ zoo`.split("\n");
|
|
|
16469
16537
|
if (i + 1 >= args.length) return;
|
|
16470
16538
|
const value = args[i + 1];
|
|
16471
16539
|
this.aliases.set(m[1], value);
|
|
16472
|
-
this.expandAlias(m[1], value, [], env, depth, 0, `${inv.shown}
|
|
16540
|
+
this.expandAlias(m[1], value, [], env, depth, 0, `${inv.shown}`, []);
|
|
16473
16541
|
}
|
|
16474
16542
|
};
|
|
16475
16543
|
POSITIONAL2 = "\0positional";
|
|
@@ -17971,7 +18039,7 @@ zoo`.split("\n");
|
|
|
17971
18039
|
{ view: "separators-stripped", decoder: "separators", stripped: true }
|
|
17972
18040
|
];
|
|
17973
18041
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
17974
|
-
CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
18042
|
+
CANONICAL_EXTRACTOR_VERSION = "canonical-v35";
|
|
17975
18043
|
}
|
|
17976
18044
|
});
|
|
17977
18045
|
|
|
@@ -19316,8 +19384,8 @@ var init_daemon = __esm({
|
|
|
19316
19384
|
import { z } from "zod";
|
|
19317
19385
|
function formatIssues(issues) {
|
|
19318
19386
|
const lines = issues.map((issue) => {
|
|
19319
|
-
const
|
|
19320
|
-
return ` \u2022 ${
|
|
19387
|
+
const path45 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
19388
|
+
return ` \u2022 ${path45}: ${issue.message}`;
|
|
19321
19389
|
});
|
|
19322
19390
|
return `Invalid config:
|
|
19323
19391
|
${lines.join("\n")}`;
|
|
@@ -19330,9 +19398,9 @@ function prunePaths(root, paths) {
|
|
|
19330
19398
|
const yi = y[y.length - 1];
|
|
19331
19399
|
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
19332
19400
|
});
|
|
19333
|
-
for (const
|
|
19401
|
+
for (const path45 of ordered) {
|
|
19334
19402
|
let cur = root;
|
|
19335
|
-
for (const key of
|
|
19403
|
+
for (const key of path45.slice(0, -1)) {
|
|
19336
19404
|
if (cur === null || typeof cur !== "object") {
|
|
19337
19405
|
cur = void 0;
|
|
19338
19406
|
break;
|
|
@@ -19340,7 +19408,7 @@ function prunePaths(root, paths) {
|
|
|
19340
19408
|
cur = cur[key];
|
|
19341
19409
|
}
|
|
19342
19410
|
if (cur === null || typeof cur !== "object") continue;
|
|
19343
|
-
const last =
|
|
19411
|
+
const last = path45[path45.length - 1];
|
|
19344
19412
|
if (Array.isArray(cur)) {
|
|
19345
19413
|
const i = Number(last);
|
|
19346
19414
|
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
@@ -19376,7 +19444,7 @@ function sanitizeConfig(raw) {
|
|
|
19376
19444
|
return issue.keys.map((k) => [...at, k]);
|
|
19377
19445
|
}
|
|
19378
19446
|
return [at.slice(0, -level || void 0)];
|
|
19379
|
-
}).filter((
|
|
19447
|
+
}).filter((path45) => path45.length > 0);
|
|
19380
19448
|
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
19381
19449
|
}
|
|
19382
19450
|
if (ConfigFileSchema.safeParse(working).success) break;
|
|
@@ -20700,13 +20768,13 @@ function getConfig(cwd) {
|
|
|
20700
20768
|
}
|
|
20701
20769
|
if (Array.isArray(mc.jailPaths)) {
|
|
20702
20770
|
for (const jp of mc.jailPaths) {
|
|
20703
|
-
const
|
|
20704
|
-
if (!
|
|
20771
|
+
const path45 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
20772
|
+
if (!path45) continue;
|
|
20705
20773
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
20706
|
-
for (const r of pathRules(
|
|
20774
|
+
for (const r of pathRules(path45, verdict, "org-managed jail")) {
|
|
20707
20775
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
20708
20776
|
}
|
|
20709
|
-
mergedPolicy.managedJailPaths.push({ path:
|
|
20777
|
+
mergedPolicy.managedJailPaths.push({ path: path45, verdict });
|
|
20710
20778
|
}
|
|
20711
20779
|
}
|
|
20712
20780
|
if (Array.isArray(mc.trustedHosts)) {
|
|
@@ -24920,6 +24988,7 @@ var init_provenance2 = __esm({
|
|
|
24920
24988
|
|
|
24921
24989
|
// src/policy/index.ts
|
|
24922
24990
|
import fs30 from "fs";
|
|
24991
|
+
import path32 from "path";
|
|
24923
24992
|
async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
|
|
24924
24993
|
const config = opts?.config ?? getConfig(cwd);
|
|
24925
24994
|
const prepared = opts?.fileAccess ?? prepareFileAccesses(toolName, args, cwd, inspectionLayers(config.policy));
|
|
@@ -24945,10 +25014,19 @@ async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
|
|
|
24945
25014
|
// reaches a long-lived in-process authorizer (the gateway) within seconds.
|
|
24946
25015
|
isTrustedHost: config.policy.trustedHostsManaged ? (host2) => matchesTrustedHost(host2, config.policy.trustedHosts) : isTrustedHost,
|
|
24947
25016
|
readAgentSettings,
|
|
24948
|
-
isConfiguredRegistry: (host2, at) => configuredRegistryHosts(at).has(host2)
|
|
25017
|
+
isConfiguredRegistry: (host2, at) => configuredRegistryHosts(at).has(host2),
|
|
25018
|
+
isGitWorkTreeTop
|
|
24949
25019
|
}
|
|
24950
25020
|
);
|
|
24951
25021
|
}
|
|
25022
|
+
function isGitWorkTreeTop(dir2, cwd) {
|
|
25023
|
+
if (!path32.isAbsolute(cwd)) return true;
|
|
25024
|
+
try {
|
|
25025
|
+
return fs30.existsSync(path32.join(path32.resolve(cwd, dir2), ".git"));
|
|
25026
|
+
} catch {
|
|
25027
|
+
return true;
|
|
25028
|
+
}
|
|
25029
|
+
}
|
|
24952
25030
|
function readAgentSettings(absPath) {
|
|
24953
25031
|
const r = readCappedText(
|
|
24954
25032
|
absPath,
|
|
@@ -24983,7 +25061,7 @@ var init_policy = __esm({
|
|
|
24983
25061
|
|
|
24984
25062
|
// src/auth/state.ts
|
|
24985
25063
|
import fs31 from "fs";
|
|
24986
|
-
import
|
|
25064
|
+
import path33 from "path";
|
|
24987
25065
|
import os22 from "os";
|
|
24988
25066
|
function extractCommandPattern(toolName, args) {
|
|
24989
25067
|
const lower2 = toolName.toLowerCase();
|
|
@@ -25061,7 +25139,7 @@ function writeTrustSession(toolName, durationMs, args) {
|
|
|
25061
25139
|
}
|
|
25062
25140
|
function getPersistentDecision(toolName) {
|
|
25063
25141
|
try {
|
|
25064
|
-
const file2 =
|
|
25142
|
+
const file2 = path33.join(os22.homedir(), ".node9", "decisions.json");
|
|
25065
25143
|
if (!fs31.existsSync(file2)) return null;
|
|
25066
25144
|
const decisions = JSON.parse(fs31.readFileSync(file2, "utf-8"));
|
|
25067
25145
|
const d = decisions[toolName];
|
|
@@ -25077,15 +25155,15 @@ var init_state2 = __esm({
|
|
|
25077
25155
|
init_policy();
|
|
25078
25156
|
init_atomic_write();
|
|
25079
25157
|
init_forecast_context();
|
|
25080
|
-
PAUSED_FILE =
|
|
25081
|
-
TRUST_FILE =
|
|
25158
|
+
PAUSED_FILE = path33.join(os22.homedir(), ".node9", "PAUSED");
|
|
25159
|
+
TRUST_FILE = path33.join(os22.homedir(), ".node9", "trust.json");
|
|
25082
25160
|
}
|
|
25083
25161
|
});
|
|
25084
25162
|
|
|
25085
25163
|
// src/auth/cloud.ts
|
|
25086
25164
|
import fs32 from "fs";
|
|
25087
25165
|
import os23 from "os";
|
|
25088
|
-
import
|
|
25166
|
+
import path34 from "path";
|
|
25089
25167
|
function maskArgsForCloud(args) {
|
|
25090
25168
|
if (args === void 0 || args === null) return args;
|
|
25091
25169
|
try {
|
|
@@ -25118,7 +25196,7 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPol
|
|
|
25118
25196
|
let ciContext;
|
|
25119
25197
|
if (process.env.CI) {
|
|
25120
25198
|
try {
|
|
25121
|
-
const ciContextPath =
|
|
25199
|
+
const ciContextPath = path34.join(os23.homedir(), ".node9", "ci-context.json");
|
|
25122
25200
|
const ci = readCappedText(ciContextPath, 1e4);
|
|
25123
25201
|
if (!ci) throw new Error("ci-context.json unreadable");
|
|
25124
25202
|
if (ci.truncated) throw new Error("ci-context.json exceeds 10 KB");
|
|
@@ -25265,10 +25343,10 @@ var init_cloud = __esm({
|
|
|
25265
25343
|
|
|
25266
25344
|
// src/loop-detector.ts
|
|
25267
25345
|
import fs33 from "fs";
|
|
25268
|
-
import
|
|
25346
|
+
import path35 from "path";
|
|
25269
25347
|
import os24 from "os";
|
|
25270
25348
|
function loopStateFile() {
|
|
25271
|
-
return
|
|
25349
|
+
return path35.join(os24.homedir(), ".node9", "loop-state.json");
|
|
25272
25350
|
}
|
|
25273
25351
|
function readState() {
|
|
25274
25352
|
try {
|
|
@@ -25282,7 +25360,7 @@ function readState() {
|
|
|
25282
25360
|
}
|
|
25283
25361
|
}
|
|
25284
25362
|
function writeState(records) {
|
|
25285
|
-
const dir2 =
|
|
25363
|
+
const dir2 = path35.dirname(loopStateFile());
|
|
25286
25364
|
if (!fs33.existsSync(dir2)) fs33.mkdirSync(dir2, { recursive: true });
|
|
25287
25365
|
const tmpPath = `${loopStateFile()}.${os24.hostname()}.${process.pid}.tmp`;
|
|
25288
25366
|
fs33.writeFileSync(tmpPath, JSON.stringify(records));
|
|
@@ -25445,7 +25523,7 @@ var init_card_result = __esm({
|
|
|
25445
25523
|
|
|
25446
25524
|
// src/auth/orchestrator.ts
|
|
25447
25525
|
import os25 from "os";
|
|
25448
|
-
import
|
|
25526
|
+
import path36 from "path";
|
|
25449
25527
|
function isProtectedPathRule(ruleName) {
|
|
25450
25528
|
if (!ruleName) return false;
|
|
25451
25529
|
return /^(?:org:)?block-path-/.test(ruleName) || /^shield:project-jail:block-read-/.test(ruleName);
|
|
@@ -25492,9 +25570,9 @@ function isMcpToolName(toolName) {
|
|
|
25492
25570
|
return /^mcp__[^_](?:[^_]|_(?!_))*?__/i.test(toolName);
|
|
25493
25571
|
}
|
|
25494
25572
|
function absoluteUploadPath(spelled, cwd) {
|
|
25495
|
-
const expanded = spelled === "~" || spelled.startsWith("~/") ?
|
|
25496
|
-
if (
|
|
25497
|
-
return cwd &&
|
|
25573
|
+
const expanded = spelled === "~" || spelled.startsWith("~/") ? path36.join(os25.homedir(), spelled.slice(1)) : spelled;
|
|
25574
|
+
if (path36.isAbsolute(expanded)) return expanded;
|
|
25575
|
+
return cwd && path36.isAbsolute(cwd) ? path36.resolve(cwd, expanded) : expanded;
|
|
25498
25576
|
}
|
|
25499
25577
|
function extractFilePaths(toolName, args, shellCommand) {
|
|
25500
25578
|
const paths = [];
|
|
@@ -27111,17 +27189,17 @@ var init_forecast = __esm({
|
|
|
27111
27189
|
|
|
27112
27190
|
// src/version.ts
|
|
27113
27191
|
import fs34 from "fs";
|
|
27114
|
-
import
|
|
27192
|
+
import path37 from "path";
|
|
27115
27193
|
function readVersion() {
|
|
27116
27194
|
let dir2 = __dirname;
|
|
27117
27195
|
for (let i = 0; i < 5; i++) {
|
|
27118
|
-
const p =
|
|
27196
|
+
const p = path37.join(dir2, "package.json");
|
|
27119
27197
|
try {
|
|
27120
27198
|
const pkg = JSON.parse(fs34.readFileSync(p, "utf-8"));
|
|
27121
27199
|
if (pkg.name === "@node9/proxy" && typeof pkg.version === "string") return pkg.version;
|
|
27122
27200
|
} catch {
|
|
27123
27201
|
}
|
|
27124
|
-
const parent =
|
|
27202
|
+
const parent = path37.dirname(dir2);
|
|
27125
27203
|
if (parent === dir2) break;
|
|
27126
27204
|
dir2 = parent;
|
|
27127
27205
|
}
|
|
@@ -27138,10 +27216,10 @@ var init_version = __esm({
|
|
|
27138
27216
|
// src/cli/commands/scan-cache.ts
|
|
27139
27217
|
import fs35 from "fs";
|
|
27140
27218
|
import os26 from "os";
|
|
27141
|
-
import
|
|
27219
|
+
import path38 from "path";
|
|
27142
27220
|
import { createHash as createHash5 } from "crypto";
|
|
27143
27221
|
function scanCacheRoot() {
|
|
27144
|
-
return
|
|
27222
|
+
return path38.join(os26.homedir(), ".node9", "scan-cache");
|
|
27145
27223
|
}
|
|
27146
27224
|
function configHashOf(config) {
|
|
27147
27225
|
const h = createHash5("sha256");
|
|
@@ -27149,7 +27227,7 @@ function configHashOf(config) {
|
|
|
27149
27227
|
h.update(JSON.stringify(config.policySource));
|
|
27150
27228
|
h.update(JSON.stringify(config.policy));
|
|
27151
27229
|
for (const name of SIDECAR_FILES) {
|
|
27152
|
-
const st = fileStamp(
|
|
27230
|
+
const st = fileStamp(path38.join(os26.homedir(), ".node9", name));
|
|
27153
27231
|
h.update(`|${name}:${st ? `${st.size}:${st.mtimeMs}` : "absent"}`);
|
|
27154
27232
|
}
|
|
27155
27233
|
return h.digest("hex").slice(0, 16);
|
|
@@ -27180,8 +27258,8 @@ var init_scan_cache = __esm({
|
|
|
27180
27258
|
"trusted-hosts.json",
|
|
27181
27259
|
"trusted-recipients.json",
|
|
27182
27260
|
"rules-cache.json",
|
|
27183
|
-
|
|
27184
|
-
|
|
27261
|
+
path38.join("osv", "npm", "meta.json"),
|
|
27262
|
+
path38.join("osv", "PyPI", "meta.json")
|
|
27185
27263
|
];
|
|
27186
27264
|
ScanCache = class {
|
|
27187
27265
|
root;
|
|
@@ -27210,7 +27288,7 @@ var init_scan_cache = __esm({
|
|
|
27210
27288
|
if (!this.enabled) return fresh;
|
|
27211
27289
|
try {
|
|
27212
27290
|
const raw = JSON.parse(
|
|
27213
|
-
fs35.readFileSync(
|
|
27291
|
+
fs35.readFileSync(path38.join(this.root, "index.json"), "utf8")
|
|
27214
27292
|
);
|
|
27215
27293
|
if (raw.cacheVersion !== SCAN_CACHE_VERSION || raw.engineVersion !== CANONICAL_EXTRACTOR_VERSION || raw.proxyVersion !== PROXY_VERSION || raw.configHash !== configHash || typeof raw.files !== "object") {
|
|
27216
27294
|
this.dropAll();
|
|
@@ -27247,7 +27325,7 @@ var init_scan_cache = __esm({
|
|
|
27247
27325
|
}
|
|
27248
27326
|
}
|
|
27249
27327
|
try {
|
|
27250
|
-
const stored = JSON.parse(fs35.readFileSync(
|
|
27328
|
+
const stored = JSON.parse(fs35.readFileSync(path38.join(this.root, e.result), "utf8"));
|
|
27251
27329
|
if ((stored.judgedFrom ?? null) !== (e.judgedFrom ?? null) || !stored.result) {
|
|
27252
27330
|
this.misses++;
|
|
27253
27331
|
return null;
|
|
@@ -27262,13 +27340,13 @@ var init_scan_cache = __esm({
|
|
|
27262
27340
|
put(filePath, stamp, agent, result, hasher, judgeFrom = null) {
|
|
27263
27341
|
if (!this.enabled) return;
|
|
27264
27342
|
const name = createHash5("sha256").update(`${agent}|${filePath}`).digest("hex").slice(0, 40);
|
|
27265
|
-
const rel =
|
|
27343
|
+
const rel = path38.join("files", name.slice(0, 2), `${name}.json`);
|
|
27266
27344
|
const configHashes = {};
|
|
27267
27345
|
if (hasher)
|
|
27268
27346
|
for (const cwd of result.configCwds ?? []) configHashes[cwd] = hasher.configHashFor(cwd);
|
|
27269
27347
|
try {
|
|
27270
|
-
const abs =
|
|
27271
|
-
fs35.mkdirSync(
|
|
27348
|
+
const abs = path38.join(this.root, rel);
|
|
27349
|
+
fs35.mkdirSync(path38.dirname(abs), { recursive: true, mode: 448 });
|
|
27272
27350
|
fs35.writeFileSync(
|
|
27273
27351
|
abs,
|
|
27274
27352
|
JSON.stringify({ judgedFrom: judgeFrom ? judgeFrom.toISOString() : null, result }),
|
|
@@ -27294,7 +27372,7 @@ var init_scan_cache = __esm({
|
|
|
27294
27372
|
for (const [key, e] of Object.entries(this.index.files)) {
|
|
27295
27373
|
if (fs35.existsSync(key)) continue;
|
|
27296
27374
|
try {
|
|
27297
|
-
fs35.rmSync(
|
|
27375
|
+
fs35.rmSync(path38.join(this.root, e.result), { force: true });
|
|
27298
27376
|
} catch {
|
|
27299
27377
|
}
|
|
27300
27378
|
delete this.index.files[key];
|
|
@@ -27316,9 +27394,9 @@ var init_scan_cache = __esm({
|
|
|
27316
27394
|
if (!this.dirty) return;
|
|
27317
27395
|
try {
|
|
27318
27396
|
fs35.mkdirSync(this.root, { recursive: true, mode: 448 });
|
|
27319
|
-
const tmp =
|
|
27397
|
+
const tmp = path38.join(this.root, `index.${process.pid}.tmp`);
|
|
27320
27398
|
fs35.writeFileSync(tmp, JSON.stringify(this.index), { mode: 384 });
|
|
27321
|
-
fs35.renameSync(tmp,
|
|
27399
|
+
fs35.renameSync(tmp, path38.join(this.root, "index.json"));
|
|
27322
27400
|
this.dirty = false;
|
|
27323
27401
|
} catch {
|
|
27324
27402
|
}
|
|
@@ -27330,7 +27408,7 @@ var init_scan_cache = __esm({
|
|
|
27330
27408
|
// src/cli/commands/scan-judge.ts
|
|
27331
27409
|
import fs36 from "fs";
|
|
27332
27410
|
import os27 from "os";
|
|
27333
|
-
import
|
|
27411
|
+
import path39 from "path";
|
|
27334
27412
|
function findingDedupKey(f) {
|
|
27335
27413
|
return `${f.source.rule.name ?? "<unnamed>"}|${preview(f.input)}|${f.project}|${f.repo ?? ""}`;
|
|
27336
27414
|
}
|
|
@@ -27429,20 +27507,20 @@ var init_scan_judge = __esm({
|
|
|
27429
27507
|
* file, so worktrees count), home-relative; undefined when none. Cached per
|
|
27430
27508
|
* directory: history repeats the same few cwds thousands of times. */
|
|
27431
27509
|
repoOf(cwd) {
|
|
27432
|
-
if (!cwd || !
|
|
27510
|
+
if (!cwd || !path39.isAbsolute(cwd)) return void 0;
|
|
27433
27511
|
if (this.repos.has(cwd)) return this.repos.get(cwd);
|
|
27434
27512
|
let dir2 = cwd;
|
|
27435
27513
|
let found;
|
|
27436
27514
|
for (; ; ) {
|
|
27437
27515
|
try {
|
|
27438
|
-
if (fs36.existsSync(
|
|
27516
|
+
if (fs36.existsSync(path39.join(dir2, ".git"))) {
|
|
27439
27517
|
found = dir2;
|
|
27440
27518
|
break;
|
|
27441
27519
|
}
|
|
27442
27520
|
} catch {
|
|
27443
27521
|
break;
|
|
27444
27522
|
}
|
|
27445
|
-
const parent =
|
|
27523
|
+
const parent = path39.dirname(dir2);
|
|
27446
27524
|
if (parent === dir2) break;
|
|
27447
27525
|
dir2 = parent;
|
|
27448
27526
|
}
|
|
@@ -27609,7 +27687,7 @@ var init_scan_summary = __esm({
|
|
|
27609
27687
|
|
|
27610
27688
|
// src/agent-wiring.ts
|
|
27611
27689
|
import fs37 from "fs";
|
|
27612
|
-
import
|
|
27690
|
+
import path40 from "path";
|
|
27613
27691
|
import * as yaml from "yaml";
|
|
27614
27692
|
import { parse as parseToml } from "smol-toml";
|
|
27615
27693
|
var exists, ck, lg, AGENT_SPECS;
|
|
@@ -27631,55 +27709,55 @@ var init_agent_wiring = __esm({
|
|
|
27631
27709
|
id: "claude",
|
|
27632
27710
|
label: "Claude Code",
|
|
27633
27711
|
setupCommand: "node9 agents add claude",
|
|
27634
|
-
hookFile: (h) =>
|
|
27712
|
+
hookFile: (h) => path40.join(h, ".claude", "settings.json"),
|
|
27635
27713
|
hookFormat: "matcher",
|
|
27636
27714
|
// UserPromptSubmit is prompt DLP. setup.ts has written it for Claude since
|
|
27637
27715
|
// that shipped; the spec must name it too, or status/doctor never show the
|
|
27638
27716
|
// row and heal (which repairs via setupAgent) has no signal it is missing.
|
|
27639
27717
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
27640
|
-
mcpFile: (h) =>
|
|
27641
|
-
present: (h) => exists(
|
|
27718
|
+
mcpFile: (h) => path40.join(h, ".claude.json"),
|
|
27719
|
+
present: (h) => exists(path40.join(h, ".claude", "settings.json")) || exists(path40.join(h, ".claude.json"))
|
|
27642
27720
|
},
|
|
27643
27721
|
{
|
|
27644
27722
|
id: "gemini",
|
|
27645
27723
|
label: "Gemini CLI",
|
|
27646
27724
|
setupCommand: "node9 agents add gemini",
|
|
27647
|
-
hookFile: (h) =>
|
|
27725
|
+
hookFile: (h) => path40.join(h, ".gemini", "settings.json"),
|
|
27648
27726
|
hookFormat: "matcher",
|
|
27649
27727
|
hookEvents: [ck("BeforeTool"), lg("AfterTool")],
|
|
27650
|
-
mcpFile: (h) =>
|
|
27651
|
-
present: (h) => exists(
|
|
27728
|
+
mcpFile: (h) => path40.join(h, ".gemini", "settings.json"),
|
|
27729
|
+
present: (h) => exists(path40.join(h, ".gemini", "settings.json"))
|
|
27652
27730
|
},
|
|
27653
27731
|
{
|
|
27654
27732
|
id: "codex",
|
|
27655
27733
|
label: "Codex",
|
|
27656
27734
|
setupCommand: "node9 agents add codex",
|
|
27657
|
-
hookFile: (h) =>
|
|
27735
|
+
hookFile: (h) => path40.join(h, ".codex", "hooks.json"),
|
|
27658
27736
|
hookFormat: "matcher",
|
|
27659
27737
|
hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
|
|
27660
|
-
mcpFile: (h) =>
|
|
27738
|
+
mcpFile: (h) => path40.join(h, ".codex", "config.toml"),
|
|
27661
27739
|
mcpFormat: "toml",
|
|
27662
|
-
present: (h) => exists(
|
|
27740
|
+
present: (h) => exists(path40.join(h, ".codex"))
|
|
27663
27741
|
},
|
|
27664
27742
|
{
|
|
27665
27743
|
id: "antigravity",
|
|
27666
27744
|
label: "Antigravity",
|
|
27667
27745
|
setupCommand: "node9 agents add antigravity",
|
|
27668
|
-
hookFile: (h) =>
|
|
27746
|
+
hookFile: (h) => path40.join(h, ".gemini", "config", "hooks.json"),
|
|
27669
27747
|
hookFormat: "matcher",
|
|
27670
27748
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
|
|
27671
|
-
mcpFile: (h) =>
|
|
27672
|
-
present: (h) => exists(
|
|
27749
|
+
mcpFile: (h) => path40.join(h, ".gemini", "config", "mcp_config.json"),
|
|
27750
|
+
present: (h) => exists(path40.join(h, ".gemini", "config", "hooks.json")) || exists(path40.join(h, ".gemini", "antigravity-cli")) || exists(path40.join(h, ".gemini", "antigravity-ide"))
|
|
27673
27751
|
},
|
|
27674
27752
|
{
|
|
27675
27753
|
id: "copilot",
|
|
27676
27754
|
label: "GitHub Copilot",
|
|
27677
27755
|
setupCommand: "node9 agents add copilot",
|
|
27678
|
-
hookFile: (h) =>
|
|
27756
|
+
hookFile: (h) => path40.join(h, ".copilot", "hooks", "node9.json"),
|
|
27679
27757
|
hookFormat: "flat",
|
|
27680
27758
|
hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
|
|
27681
|
-
mcpFile: (h) =>
|
|
27682
|
-
present: (h) => exists(
|
|
27759
|
+
mcpFile: (h) => path40.join(h, ".copilot", "mcp-config.json"),
|
|
27760
|
+
present: (h) => exists(path40.join(h, ".copilot"))
|
|
27683
27761
|
},
|
|
27684
27762
|
{
|
|
27685
27763
|
id: "cursor",
|
|
@@ -27688,8 +27766,8 @@ var init_agent_wiring = __esm({
|
|
|
27688
27766
|
// MCP-only — no hook file (see note above).
|
|
27689
27767
|
hookFormat: "flat",
|
|
27690
27768
|
hookEvents: [],
|
|
27691
|
-
mcpFile: (h) =>
|
|
27692
|
-
present: (h) => exists(
|
|
27769
|
+
mcpFile: (h) => path40.join(h, ".cursor", "mcp.json"),
|
|
27770
|
+
present: (h) => exists(path40.join(h, ".cursor", "mcp.json"))
|
|
27693
27771
|
},
|
|
27694
27772
|
{
|
|
27695
27773
|
id: "hermes",
|
|
@@ -27710,8 +27788,8 @@ var init_agent_wiring = __esm({
|
|
|
27710
27788
|
setupCommand: "node9 agents add opencode",
|
|
27711
27789
|
hookFormat: "flat",
|
|
27712
27790
|
hookEvents: [],
|
|
27713
|
-
shimFile: (h) =>
|
|
27714
|
-
present: (h) => exists(opencodeConfigDir(h)) || exists(
|
|
27791
|
+
shimFile: (h) => path40.join(opencodeConfigDir(h), "plugins", "node9.js"),
|
|
27792
|
+
present: (h) => exists(opencodeConfigDir(h)) || exists(path40.join(opencodeConfigDir(h), "plugins", "node9.js"))
|
|
27715
27793
|
},
|
|
27716
27794
|
{
|
|
27717
27795
|
id: "pi",
|
|
@@ -27719,8 +27797,8 @@ var init_agent_wiring = __esm({
|
|
|
27719
27797
|
setupCommand: "node9 agents add pi",
|
|
27720
27798
|
hookFormat: "flat",
|
|
27721
27799
|
hookEvents: [],
|
|
27722
|
-
shimFile: (h) =>
|
|
27723
|
-
present: (h) => exists(
|
|
27800
|
+
shimFile: (h) => path40.join(h, ".pi", "agent", "extensions", "node9.js"),
|
|
27801
|
+
present: (h) => exists(path40.join(h, ".pi", "agent")) || exists(path40.join(h, ".pi", "agent", "extensions", "node9.js"))
|
|
27724
27802
|
}
|
|
27725
27803
|
];
|
|
27726
27804
|
}
|
|
@@ -27771,14 +27849,14 @@ var init_codex_trust = __esm({
|
|
|
27771
27849
|
});
|
|
27772
27850
|
|
|
27773
27851
|
// src/daemon/hook-baseline.ts
|
|
27774
|
-
import
|
|
27852
|
+
import path41 from "path";
|
|
27775
27853
|
import os28 from "os";
|
|
27776
27854
|
var BASELINE_FILE, NOTIFIED_FILE;
|
|
27777
27855
|
var init_hook_baseline = __esm({
|
|
27778
27856
|
"src/daemon/hook-baseline.ts"() {
|
|
27779
27857
|
"use strict";
|
|
27780
|
-
BASELINE_FILE =
|
|
27781
|
-
NOTIFIED_FILE =
|
|
27858
|
+
BASELINE_FILE = path41.join(os28.homedir(), ".node9", "hooks-baseline.json");
|
|
27859
|
+
NOTIFIED_FILE = path41.join(os28.homedir(), ".node9", "hook-heal-notified.json");
|
|
27782
27860
|
}
|
|
27783
27861
|
});
|
|
27784
27862
|
|
|
@@ -27797,7 +27875,7 @@ var init_setup_pi_shim = __esm({
|
|
|
27797
27875
|
});
|
|
27798
27876
|
|
|
27799
27877
|
// src/setup.ts
|
|
27800
|
-
import
|
|
27878
|
+
import path42 from "path";
|
|
27801
27879
|
import os29 from "os";
|
|
27802
27880
|
import chalk3 from "chalk";
|
|
27803
27881
|
import { confirm as rawConfirm } from "@inquirer/prompts";
|
|
@@ -27805,16 +27883,16 @@ import { parse as parseToml5, stringify as stringifyToml2 } from "smol-toml";
|
|
|
27805
27883
|
import * as yaml2 from "yaml";
|
|
27806
27884
|
function opencodeConfigDir(home = os29.homedir()) {
|
|
27807
27885
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
27808
|
-
const base2 = xdg &&
|
|
27809
|
-
return
|
|
27886
|
+
const base2 = xdg && path42.isAbsolute(xdg) ? xdg : path42.join(home, ".config");
|
|
27887
|
+
return path42.join(base2, "opencode");
|
|
27810
27888
|
}
|
|
27811
27889
|
function hermesHomeDir(homeDir = os29.homedir()) {
|
|
27812
27890
|
const env = process.env.HERMES_HOME?.trim();
|
|
27813
|
-
if (env &&
|
|
27814
|
-
return
|
|
27891
|
+
if (env && path42.isAbsolute(env)) return env;
|
|
27892
|
+
return path42.join(homeDir, ".hermes");
|
|
27815
27893
|
}
|
|
27816
27894
|
function hermesConfigPath(homeDir = os29.homedir()) {
|
|
27817
|
-
return
|
|
27895
|
+
return path42.join(hermesHomeDir(homeDir), HERMES_CONFIG_FILENAME);
|
|
27818
27896
|
}
|
|
27819
27897
|
var HERMES_CONFIG_FILENAME;
|
|
27820
27898
|
var init_setup = __esm({
|
|
@@ -27860,7 +27938,7 @@ var init_scan_history = __esm({
|
|
|
27860
27938
|
// src/cli/commands/scan.ts
|
|
27861
27939
|
import chalk5 from "chalk";
|
|
27862
27940
|
import fs38 from "fs";
|
|
27863
|
-
import
|
|
27941
|
+
import path43 from "path";
|
|
27864
27942
|
import os30 from "os";
|
|
27865
27943
|
import stringWidth2 from "string-width";
|
|
27866
27944
|
function dayKey(ts) {
|
|
@@ -28074,7 +28152,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
28074
28152
|
const session = { sessionId, costUSD: 0, toolCalls: 0 };
|
|
28075
28153
|
let raw;
|
|
28076
28154
|
try {
|
|
28077
|
-
raw = fs38.readFileSync(
|
|
28155
|
+
raw = fs38.readFileSync(path43.join(projPath, file2), "utf-8");
|
|
28078
28156
|
} catch {
|
|
28079
28157
|
return false;
|
|
28080
28158
|
}
|
|
@@ -28143,7 +28221,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
28143
28221
|
if (block.type !== "tool_result") continue;
|
|
28144
28222
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
28145
28223
|
if (filePath) {
|
|
28146
|
-
const ext =
|
|
28224
|
+
const ext = path43.extname(filePath).toLowerCase();
|
|
28147
28225
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
28148
28226
|
}
|
|
28149
28227
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -28263,7 +28341,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
28263
28341
|
return true;
|
|
28264
28342
|
}
|
|
28265
28343
|
async function processClaudeProjectAsync(proj, projectsDir, judge, cache7, startDate, result, dedup, canaryVals, onProgress, onLine) {
|
|
28266
|
-
const projPath =
|
|
28344
|
+
const projPath = path43.join(projectsDir, proj);
|
|
28267
28345
|
try {
|
|
28268
28346
|
if (!fs38.statSync(projPath).isDirectory()) return;
|
|
28269
28347
|
} catch {
|
|
@@ -28277,7 +28355,7 @@ async function processClaudeProjectAsync(proj, projectsDir, judge, cache7, start
|
|
|
28277
28355
|
return;
|
|
28278
28356
|
}
|
|
28279
28357
|
for (const file2 of files) {
|
|
28280
|
-
const filePath =
|
|
28358
|
+
const filePath = path43.join(projPath, file2);
|
|
28281
28359
|
const stamp = fileStamp(filePath);
|
|
28282
28360
|
if (!fileMayHoldWindow(stamp, startDate)) continue;
|
|
28283
28361
|
result.filesScanned++;
|
|
@@ -28420,7 +28498,7 @@ function mergeFileScan(result, file2, dedup, startDate = null) {
|
|
|
28420
28498
|
}
|
|
28421
28499
|
}
|
|
28422
28500
|
async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {}) {
|
|
28423
|
-
const projectsDir =
|
|
28501
|
+
const projectsDir = path43.join(os30.homedir(), ".claude", "projects");
|
|
28424
28502
|
const result = emptyClaudeScan();
|
|
28425
28503
|
if (!fs38.existsSync(projectsDir)) return result;
|
|
28426
28504
|
let projDirs;
|
|
@@ -28453,7 +28531,7 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {})
|
|
|
28453
28531
|
}
|
|
28454
28532
|
async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
28455
28533
|
const canaryVals = safeCanaryScanValues();
|
|
28456
|
-
const tmpDir =
|
|
28534
|
+
const tmpDir = path43.join(os30.homedir(), ".gemini", "tmp");
|
|
28457
28535
|
const result = {
|
|
28458
28536
|
filesScanned: 0,
|
|
28459
28537
|
sessions: 0,
|
|
@@ -28480,7 +28558,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
28480
28558
|
const judge = new HistoryJudge();
|
|
28481
28559
|
const cache7 = openScanCache(judge, opts);
|
|
28482
28560
|
for (const slug2 of slugDirs) {
|
|
28483
|
-
const slugPath =
|
|
28561
|
+
const slugPath = path43.join(tmpDir, slug2);
|
|
28484
28562
|
try {
|
|
28485
28563
|
if (!fs38.statSync(slugPath).isDirectory()) continue;
|
|
28486
28564
|
} catch {
|
|
@@ -28489,11 +28567,11 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
28489
28567
|
let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
|
|
28490
28568
|
try {
|
|
28491
28569
|
projLabel = stripTerminalEscapes(
|
|
28492
|
-
fs38.readFileSync(
|
|
28570
|
+
fs38.readFileSync(path43.join(slugPath, ".project_root"), "utf-8").trim()
|
|
28493
28571
|
).replace(os30.homedir(), "~").slice(0, 40);
|
|
28494
28572
|
} catch {
|
|
28495
28573
|
}
|
|
28496
|
-
const chatsDir =
|
|
28574
|
+
const chatsDir = path43.join(slugPath, "chats");
|
|
28497
28575
|
if (!fs38.existsSync(chatsDir)) continue;
|
|
28498
28576
|
let chatFiles;
|
|
28499
28577
|
try {
|
|
@@ -28503,7 +28581,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
28503
28581
|
}
|
|
28504
28582
|
for (const chatFile of chatFiles) {
|
|
28505
28583
|
const sessionId = chatFile.replace(/\.jsonl?$/, "");
|
|
28506
|
-
const filePath =
|
|
28584
|
+
const filePath = path43.join(chatsDir, chatFile);
|
|
28507
28585
|
const stamp = fileStamp(filePath);
|
|
28508
28586
|
if (!fileMayHoldWindow(stamp, startDate)) continue;
|
|
28509
28587
|
result.filesScanned++;
|
|
@@ -28517,7 +28595,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
28517
28595
|
const fileDedup = emptyScanDedup();
|
|
28518
28596
|
let raw;
|
|
28519
28597
|
try {
|
|
28520
|
-
raw = fs38.readFileSync(
|
|
28598
|
+
raw = fs38.readFileSync(path43.join(chatsDir, chatFile), "utf-8");
|
|
28521
28599
|
} catch {
|
|
28522
28600
|
continue;
|
|
28523
28601
|
}
|
|
@@ -28712,7 +28790,7 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
28712
28790
|
startTime = String(payload["timestamp"] ?? "");
|
|
28713
28791
|
const cwd = String(payload["cwd"] ?? "");
|
|
28714
28792
|
projLabel = stripTerminalEscapes(cwd.replace(os30.homedir(), "~")).slice(0, 40);
|
|
28715
|
-
if (
|
|
28793
|
+
if (path43.isAbsolute(cwd)) sessionCwd = cwd;
|
|
28716
28794
|
continue;
|
|
28717
28795
|
}
|
|
28718
28796
|
if (entry.type === "event_msg" && payload["type"] === "user_message") {
|
|
@@ -28912,10 +28990,10 @@ var init_scan = __esm({
|
|
|
28912
28990
|
// src/tui/dashboard/data.ts
|
|
28913
28991
|
import fs39 from "fs";
|
|
28914
28992
|
import os31 from "os";
|
|
28915
|
-
import
|
|
28993
|
+
import path44 from "path";
|
|
28916
28994
|
import http2 from "http";
|
|
28917
28995
|
function auditLogPath() {
|
|
28918
|
-
return
|
|
28996
|
+
return path44.join(os31.homedir(), ".node9", "audit.log");
|
|
28919
28997
|
}
|
|
28920
28998
|
function readAuditEntriesAsync(chunkSize = 1e3, customPath) {
|
|
28921
28999
|
return new Promise((resolve) => {
|
|
@@ -29062,9 +29140,9 @@ function shortenPath(p) {
|
|
|
29062
29140
|
return p.startsWith(home) ? p.replace(home, "~") : p;
|
|
29063
29141
|
}
|
|
29064
29142
|
async function loadReportAuditAsync(period) {
|
|
29065
|
-
const claudeProjectsDir =
|
|
29143
|
+
const claudeProjectsDir = path44.join(os31.homedir(), ".claude", "projects");
|
|
29066
29144
|
const codexSessionsDir2 = codexSessionsDir();
|
|
29067
|
-
const geminiTmpDir =
|
|
29145
|
+
const geminiTmpDir = path44.join(os31.homedir(), ".gemini", "tmp");
|
|
29068
29146
|
const { start, end } = getDateRange(period, /* @__PURE__ */ new Date());
|
|
29069
29147
|
const entries = await readAuditEntriesAsync();
|
|
29070
29148
|
void ensurePricingLoaded();
|
|
@@ -30176,8 +30254,8 @@ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-run
|
|
|
30176
30254
|
function TopToolsProjects({ audit }) {
|
|
30177
30255
|
const data = audit?.data;
|
|
30178
30256
|
const tools = data ? [...data.toolMap.entries()].sort(([, a], [, b]) => b.calls - a.calls).slice(0, ROW_LIMIT) : [];
|
|
30179
|
-
const projects = data ? [...data.cost.byProject.entries()].map(([
|
|
30180
|
-
name: basenameOf(
|
|
30257
|
+
const projects = data ? [...data.cost.byProject.entries()].map(([path45, r]) => ({
|
|
30258
|
+
name: basenameOf(path45),
|
|
30181
30259
|
cost: r.cost,
|
|
30182
30260
|
tokens: r.inputTokens + r.outputTokens
|
|
30183
30261
|
})).sort((a, b) => b.cost - a.cost).slice(0, ROW_LIMIT) : [];
|
|
@@ -30614,8 +30692,8 @@ function pickTopLoopFile(loops) {
|
|
|
30614
30692
|
map.set(k, (map.get(k) ?? 0) + (l.count ?? 0));
|
|
30615
30693
|
}
|
|
30616
30694
|
if (map.size === 0) return void 0;
|
|
30617
|
-
const [
|
|
30618
|
-
return { path:
|
|
30695
|
+
const [path45, count] = [...map.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
30696
|
+
return { path: path45, count };
|
|
30619
30697
|
}
|
|
30620
30698
|
var EMPTY_FILTERED_SCAN;
|
|
30621
30699
|
var init_derive = __esm({
|