@node9/proxy 1.30.0 → 1.31.0
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 +1314 -764
- package/dist/cli.mjs +1299 -749
- package/dist/dashboard.mjs +20 -2
- package/dist/index.js +414 -6
- package/dist/index.mjs +414 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -200,8 +200,8 @@ function sanitizeConfig(raw) {
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
const lines = result.error.issues.map((issue) => {
|
|
203
|
-
const
|
|
204
|
-
return ` \u2022 ${
|
|
203
|
+
const path52 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
204
|
+
return ` \u2022 ${path52}: ${issue.message}`;
|
|
205
205
|
});
|
|
206
206
|
return {
|
|
207
207
|
sanitized,
|
|
@@ -308,7 +308,15 @@ var init_config_schema = __esm({
|
|
|
308
308
|
}).optional(),
|
|
309
309
|
dlp: import_zod.z.object({
|
|
310
310
|
enabled: import_zod.z.boolean().optional(),
|
|
311
|
-
scanIgnoredTools: import_zod.z.boolean().optional()
|
|
311
|
+
scanIgnoredTools: import_zod.z.boolean().optional(),
|
|
312
|
+
pii: import_zod.z.enum(["off", "block"]).optional()
|
|
313
|
+
}).optional(),
|
|
314
|
+
egress: import_zod.z.object({
|
|
315
|
+
enabled: import_zod.z.boolean().optional(),
|
|
316
|
+
mode: import_zod.z.enum(["off", "review", "block"]).optional(),
|
|
317
|
+
allow: import_zod.z.array(import_zod.z.string()).optional(),
|
|
318
|
+
deny: import_zod.z.array(import_zod.z.string()).optional(),
|
|
319
|
+
allowPrivate: import_zod.z.boolean().optional()
|
|
312
320
|
}).optional(),
|
|
313
321
|
loopDetection: import_zod.z.object({
|
|
314
322
|
enabled: import_zod.z.boolean().optional(),
|
|
@@ -685,6 +693,116 @@ function extractLiteralArgs(callExpr) {
|
|
|
685
693
|
}
|
|
686
694
|
return { name, flags, paths };
|
|
687
695
|
}
|
|
696
|
+
function resolveWordLiteral(w) {
|
|
697
|
+
const parts = w?.Parts || [];
|
|
698
|
+
let s = "";
|
|
699
|
+
for (const p of parts) {
|
|
700
|
+
const t = syntax.NodeType(p);
|
|
701
|
+
if (t === "Lit") s += (p.Value ?? "").replace(/\\(.)/g, "$1");
|
|
702
|
+
else if (t === "SglQuoted") s += p.Value ?? "";
|
|
703
|
+
else if (t === "DblQuoted") {
|
|
704
|
+
const inner = p.Parts || [];
|
|
705
|
+
if (!inner.every((ip) => syntax.NodeType(ip) === "Lit")) return null;
|
|
706
|
+
s += inner.map((ip) => ip.Value ?? "").join("");
|
|
707
|
+
} else {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return s;
|
|
712
|
+
}
|
|
713
|
+
function parseDestHost(token) {
|
|
714
|
+
if (!token) return null;
|
|
715
|
+
let t = token.trim();
|
|
716
|
+
if (!t || t.startsWith("-")) return null;
|
|
717
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(t)) {
|
|
718
|
+
try {
|
|
719
|
+
const h = new URL(t).hostname.toLowerCase();
|
|
720
|
+
return h || null;
|
|
721
|
+
} catch {
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
const at = t.lastIndexOf("@");
|
|
726
|
+
if (at >= 0) t = t.slice(at + 1);
|
|
727
|
+
t = t.split("/")[0];
|
|
728
|
+
t = t.replace(/:\d+$/, "");
|
|
729
|
+
t = t.split(":")[0];
|
|
730
|
+
t = t.toLowerCase();
|
|
731
|
+
if (t.length > 253) return null;
|
|
732
|
+
if (t === "localhost") return t;
|
|
733
|
+
if (/^[a-z0-9.-]+\.[a-z0-9.-]+$/.test(t)) return t;
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
function destTokensForBinary(binary, args) {
|
|
737
|
+
const valueFlags = VALUE_FLAGS[binary] ?? /* @__PURE__ */ new Set();
|
|
738
|
+
const positionals = [];
|
|
739
|
+
const urlFlagValues = [];
|
|
740
|
+
for (let i = 0; i < args.length; i++) {
|
|
741
|
+
const tok = args[i];
|
|
742
|
+
if (tok === null) continue;
|
|
743
|
+
if (tok.startsWith("-")) {
|
|
744
|
+
if (tok.startsWith("--url=")) {
|
|
745
|
+
urlFlagValues.push(tok.slice("--url=".length));
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
if (tok === "--url") {
|
|
749
|
+
const next = args[i + 1];
|
|
750
|
+
if (typeof next === "string") urlFlagValues.push(next);
|
|
751
|
+
i++;
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
if (tok.includes("=")) continue;
|
|
755
|
+
if (valueFlags.has(tok)) i++;
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
positionals.push(tok);
|
|
759
|
+
}
|
|
760
|
+
switch (binary) {
|
|
761
|
+
case "curl":
|
|
762
|
+
case "wget":
|
|
763
|
+
return [...urlFlagValues, ...positionals];
|
|
764
|
+
case "ssh":
|
|
765
|
+
return positionals.slice(0, 1);
|
|
766
|
+
case "scp":
|
|
767
|
+
return positionals.filter((p) => p.includes(":") || p.includes("@"));
|
|
768
|
+
case "nc":
|
|
769
|
+
case "ncat":
|
|
770
|
+
case "netcat":
|
|
771
|
+
return positionals.slice(0, 1);
|
|
772
|
+
default:
|
|
773
|
+
return [];
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
function extractShellDestinations(command) {
|
|
777
|
+
const f = parseShared(command);
|
|
778
|
+
if (f === PARSE_FAIL) return [];
|
|
779
|
+
const out = [];
|
|
780
|
+
const seen = /* @__PURE__ */ new Set();
|
|
781
|
+
try {
|
|
782
|
+
syntax.Walk(f, (node) => {
|
|
783
|
+
if (!node) return false;
|
|
784
|
+
const n = node;
|
|
785
|
+
if (syntax.NodeType(n) !== "CallExpr") return true;
|
|
786
|
+
const callArgs = n.Args || [];
|
|
787
|
+
if (callArgs.length === 0) return true;
|
|
788
|
+
const name = (resolveWordLiteral(callArgs[0]) || "").toLowerCase();
|
|
789
|
+
if (!NET_BINARIES.has(name)) return true;
|
|
790
|
+
const rest = callArgs.slice(1).map((a) => resolveWordLiteral(a));
|
|
791
|
+
for (const raw of destTokensForBinary(name, rest)) {
|
|
792
|
+
const host = parseDestHost(raw);
|
|
793
|
+
if (!host) continue;
|
|
794
|
+
const key = `${name}:${host}`;
|
|
795
|
+
if (seen.has(key)) continue;
|
|
796
|
+
seen.add(key);
|
|
797
|
+
out.push({ host, binary: name, raw });
|
|
798
|
+
}
|
|
799
|
+
return true;
|
|
800
|
+
});
|
|
801
|
+
} catch {
|
|
802
|
+
return out;
|
|
803
|
+
}
|
|
804
|
+
return out;
|
|
805
|
+
}
|
|
688
806
|
function analyzeFsOperation(command) {
|
|
689
807
|
if (!FS_OP_PRESCREEN_RE.test(command)) return null;
|
|
690
808
|
if (fsOpCache.has(command)) {
|
|
@@ -812,6 +930,64 @@ function analyzeShellCommand(command) {
|
|
|
812
930
|
}
|
|
813
931
|
return { actions, paths, allTokens };
|
|
814
932
|
}
|
|
933
|
+
function hostMatches(host, pattern) {
|
|
934
|
+
const h = host.toLowerCase();
|
|
935
|
+
const p = pattern.toLowerCase().trim();
|
|
936
|
+
if (!p) return false;
|
|
937
|
+
if (p === "*") return true;
|
|
938
|
+
if (p.startsWith("*.")) {
|
|
939
|
+
const suffix = p.slice(2);
|
|
940
|
+
return h === suffix || h.endsWith("." + suffix);
|
|
941
|
+
}
|
|
942
|
+
return h === p;
|
|
943
|
+
}
|
|
944
|
+
function matchesAny(host, patterns) {
|
|
945
|
+
for (const p of patterns) if (hostMatches(host, p)) return true;
|
|
946
|
+
return false;
|
|
947
|
+
}
|
|
948
|
+
function isPrivateHost(host) {
|
|
949
|
+
const h = host.toLowerCase();
|
|
950
|
+
if (h === "localhost" || h === "0.0.0.0") return true;
|
|
951
|
+
if (h.endsWith(".local") || h.endsWith(".internal") || h.endsWith(".localhost")) return true;
|
|
952
|
+
if (/^127\./.test(h)) return true;
|
|
953
|
+
if (/^10\./.test(h)) return true;
|
|
954
|
+
if (/^192\.168\./.test(h)) return true;
|
|
955
|
+
if (/^172\.(1[6-9]|2\d|3[01])\./.test(h)) return true;
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
function evaluateEgress(dests, policy) {
|
|
959
|
+
if (!policy.enabled) return null;
|
|
960
|
+
let review = null;
|
|
961
|
+
for (const d of dests) {
|
|
962
|
+
if (matchesAny(d.host, policy.deny)) {
|
|
963
|
+
return {
|
|
964
|
+
verdict: "block",
|
|
965
|
+
host: d.host,
|
|
966
|
+
binary: d.binary,
|
|
967
|
+
reason: `Egress to ${d.host} is on the deny list.`
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
if (policy.allowPrivate && isPrivateHost(d.host)) continue;
|
|
971
|
+
if (matchesAny(d.host, policy.allow) || matchesAny(d.host, DEFAULT_EGRESS_ALLOWLIST)) continue;
|
|
972
|
+
if (policy.mode === "block") {
|
|
973
|
+
return {
|
|
974
|
+
verdict: "block",
|
|
975
|
+
host: d.host,
|
|
976
|
+
binary: d.binary,
|
|
977
|
+
reason: `Egress to unknown host ${d.host} is blocked (egress policy: block).`
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
if (policy.mode === "review" && !review) {
|
|
981
|
+
review = {
|
|
982
|
+
verdict: "review",
|
|
983
|
+
host: d.host,
|
|
984
|
+
binary: d.binary,
|
|
985
|
+
reason: `${d.binary} is sending data to an unrecognized host (${d.host}). Approve this destination?`
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return review;
|
|
990
|
+
}
|
|
815
991
|
function isSensitivePath(p) {
|
|
816
992
|
return SENSITIVE_PATTERNS.some((re) => re.test(p));
|
|
817
993
|
}
|
|
@@ -1039,9 +1215,9 @@ function matchesPattern(text, patterns) {
|
|
|
1039
1215
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
1040
1216
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
1041
1217
|
}
|
|
1042
|
-
function getNestedValue(obj,
|
|
1218
|
+
function getNestedValue(obj, path52) {
|
|
1043
1219
|
if (!obj || typeof obj !== "object") return null;
|
|
1044
|
-
const segments =
|
|
1220
|
+
const segments = path52.split(".");
|
|
1045
1221
|
for (const seg of segments) {
|
|
1046
1222
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
1047
1223
|
}
|
|
@@ -1244,6 +1420,22 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
1244
1420
|
}
|
|
1245
1421
|
const ptVerdict = pipeChainVerdict(shellCommand, isTrustedHost2);
|
|
1246
1422
|
if (ptVerdict) return ptVerdict;
|
|
1423
|
+
if (config.policy.egress?.enabled) {
|
|
1424
|
+
const dests = extractShellDestinations(shellCommand);
|
|
1425
|
+
if (dests.length > 0) {
|
|
1426
|
+
const eg = evaluateEgress(dests, config.policy.egress);
|
|
1427
|
+
if (eg) {
|
|
1428
|
+
return {
|
|
1429
|
+
decision: eg.verdict,
|
|
1430
|
+
blockedByLabel: eg.verdict === "block" ? "\u{1F310} Node9 Egress (Blocked)" : "\u{1F310} Node9 Egress (Review)",
|
|
1431
|
+
reason: eg.reason,
|
|
1432
|
+
ruleName: `egress:${eg.binary}:${eg.host}`,
|
|
1433
|
+
ruleDescription: eg.reason,
|
|
1434
|
+
tier: eg.verdict === "block" ? 3 : 4
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1247
1439
|
const firstToken = analyzed.actions[0] ?? "";
|
|
1248
1440
|
if (["ssh", "scp", "rsync"].includes(firstToken)) {
|
|
1249
1441
|
const rawTokens = shellCommand.trim().split(/\s+/);
|
|
@@ -1573,6 +1765,18 @@ function detectPii(text) {
|
|
|
1573
1765
|
if (PII_CC_RE.test(text)) found.add("Credit Card");
|
|
1574
1766
|
return [...found];
|
|
1575
1767
|
}
|
|
1768
|
+
function detectArgsPii(args) {
|
|
1769
|
+
if (args === null || args === void 0) return [];
|
|
1770
|
+
let text;
|
|
1771
|
+
try {
|
|
1772
|
+
text = typeof args === "string" ? args : JSON.stringify(args);
|
|
1773
|
+
} catch {
|
|
1774
|
+
return [];
|
|
1775
|
+
}
|
|
1776
|
+
if (typeof text !== "string") return [];
|
|
1777
|
+
if (text.length > MAX_PII_SCAN_BYTES) text = text.slice(0, MAX_PII_SCAN_BYTES);
|
|
1778
|
+
return detectPii(text).filter((p) => REALTIME_PII_PATTERNS.includes(p));
|
|
1779
|
+
}
|
|
1576
1780
|
function extractCanonicalFindings(call, ctx) {
|
|
1577
1781
|
const out = [];
|
|
1578
1782
|
const ts = call.timestamp;
|
|
@@ -1885,7 +2089,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
1885
2089
|
}
|
|
1886
2090
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
1887
2091
|
}
|
|
1888
|
-
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, FS_OP_CACHE_MAX, fsOpCache, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE;
|
|
2092
|
+
var import_safe_regex2, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto3, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE;
|
|
1889
2093
|
var init_dist = __esm({
|
|
1890
2094
|
"packages/policy-engine/dist/index.mjs"() {
|
|
1891
2095
|
"use strict";
|
|
@@ -2505,8 +2709,112 @@ var init_dist = __esm({
|
|
|
2505
2709
|
"shield:project-jail:block-read-env",
|
|
2506
2710
|
"shield:project-jail:review-read-credentials"
|
|
2507
2711
|
]);
|
|
2712
|
+
NET_BINARIES = /* @__PURE__ */ new Set(["curl", "wget", "scp", "ssh", "nc", "ncat", "netcat"]);
|
|
2713
|
+
VALUE_FLAGS = {
|
|
2714
|
+
curl: /* @__PURE__ */ new Set([
|
|
2715
|
+
"-d",
|
|
2716
|
+
"--data",
|
|
2717
|
+
"--data-ascii",
|
|
2718
|
+
"--data-binary",
|
|
2719
|
+
"--data-raw",
|
|
2720
|
+
"--data-urlencode",
|
|
2721
|
+
"-F",
|
|
2722
|
+
"--form",
|
|
2723
|
+
"-H",
|
|
2724
|
+
"--header",
|
|
2725
|
+
"-X",
|
|
2726
|
+
"--request",
|
|
2727
|
+
"-o",
|
|
2728
|
+
"--output",
|
|
2729
|
+
"-T",
|
|
2730
|
+
"--upload-file",
|
|
2731
|
+
"-u",
|
|
2732
|
+
"--user",
|
|
2733
|
+
"-e",
|
|
2734
|
+
"--referer",
|
|
2735
|
+
"-A",
|
|
2736
|
+
"--user-agent",
|
|
2737
|
+
"-b",
|
|
2738
|
+
"--cookie",
|
|
2739
|
+
"-c",
|
|
2740
|
+
"--cookie-jar",
|
|
2741
|
+
"--connect-to",
|
|
2742
|
+
"--resolve",
|
|
2743
|
+
"--cacert",
|
|
2744
|
+
"--cert",
|
|
2745
|
+
"--key",
|
|
2746
|
+
"-x",
|
|
2747
|
+
"--proxy",
|
|
2748
|
+
"-m",
|
|
2749
|
+
"--max-time",
|
|
2750
|
+
"--retry"
|
|
2751
|
+
]),
|
|
2752
|
+
wget: /* @__PURE__ */ new Set([
|
|
2753
|
+
"-O",
|
|
2754
|
+
"--output-document",
|
|
2755
|
+
"--post-data",
|
|
2756
|
+
"--post-file",
|
|
2757
|
+
"--header",
|
|
2758
|
+
"-U",
|
|
2759
|
+
"--user-agent",
|
|
2760
|
+
"--user",
|
|
2761
|
+
"--password",
|
|
2762
|
+
"-o",
|
|
2763
|
+
"--output-file",
|
|
2764
|
+
"-P",
|
|
2765
|
+
"--directory-prefix",
|
|
2766
|
+
"-t",
|
|
2767
|
+
"--tries",
|
|
2768
|
+
"-T",
|
|
2769
|
+
"--timeout"
|
|
2770
|
+
]),
|
|
2771
|
+
scp: /* @__PURE__ */ new Set(["-i", "-F", "-l", "-o", "-c", "-S", "-P", "-J", "-D", "-W"]),
|
|
2772
|
+
ssh: /* @__PURE__ */ new Set([
|
|
2773
|
+
"-i",
|
|
2774
|
+
"-p",
|
|
2775
|
+
"-o",
|
|
2776
|
+
"-l",
|
|
2777
|
+
"-F",
|
|
2778
|
+
"-c",
|
|
2779
|
+
"-L",
|
|
2780
|
+
"-R",
|
|
2781
|
+
"-D",
|
|
2782
|
+
"-W",
|
|
2783
|
+
"-b",
|
|
2784
|
+
"-e",
|
|
2785
|
+
"-m",
|
|
2786
|
+
"-O",
|
|
2787
|
+
"-Q",
|
|
2788
|
+
"-S",
|
|
2789
|
+
"-J",
|
|
2790
|
+
"-w",
|
|
2791
|
+
"-B",
|
|
2792
|
+
"-I",
|
|
2793
|
+
"-E"
|
|
2794
|
+
]),
|
|
2795
|
+
nc: /* @__PURE__ */ new Set(["-p", "-s", "-w", "-X", "-x", "-e", "-g", "-G", "-i", "-O", "-T", "-q", "-m"])
|
|
2796
|
+
};
|
|
2508
2797
|
FS_OP_CACHE_MAX = 5e3;
|
|
2509
2798
|
fsOpCache = /* @__PURE__ */ new Map();
|
|
2799
|
+
DEFAULT_EGRESS_ALLOWLIST = [
|
|
2800
|
+
"*.github.com",
|
|
2801
|
+
"*.githubusercontent.com",
|
|
2802
|
+
"*.npmjs.org",
|
|
2803
|
+
"pypi.org",
|
|
2804
|
+
"*.pythonhosted.org",
|
|
2805
|
+
"crates.io",
|
|
2806
|
+
"*.crates.io",
|
|
2807
|
+
"rubygems.org",
|
|
2808
|
+
"proxy.golang.org",
|
|
2809
|
+
"sum.golang.org",
|
|
2810
|
+
"*.anthropic.com",
|
|
2811
|
+
"*.openai.com",
|
|
2812
|
+
"*.googleapis.com",
|
|
2813
|
+
"*.docker.io",
|
|
2814
|
+
"*.docker.com",
|
|
2815
|
+
"deb.debian.org",
|
|
2816
|
+
"*.ubuntu.com"
|
|
2817
|
+
];
|
|
2510
2818
|
SOURCE_COMMANDS = /* @__PURE__ */ new Set([
|
|
2511
2819
|
"cat",
|
|
2512
2820
|
"head",
|
|
@@ -3436,6 +3744,8 @@ var init_dist = __esm({
|
|
|
3436
3744
|
PII_SSN_RE = /\b\d{3}-\d{2}-\d{4}\b/;
|
|
3437
3745
|
PII_PHONE_RE = /\b(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]\d{3}[-.\s]\d{4}\b/;
|
|
3438
3746
|
PII_CC_RE = /\b(?:4\d{3}|5[1-5]\d{2}|3[47]\d{2}|6\d{3})[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/;
|
|
3747
|
+
REALTIME_PII_PATTERNS = ["SSN", "Credit Card"];
|
|
3748
|
+
MAX_PII_SCAN_BYTES = 1e5;
|
|
3439
3749
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
3440
3750
|
CANONICAL_EXTRACTOR_VERSION = "canonical-v4";
|
|
3441
3751
|
DEDUPE_PREVIEW_LEN = 120;
|
|
@@ -3723,6 +4033,11 @@ function getConfig(cwd) {
|
|
|
3723
4033
|
ignorePaths: [...DEFAULT_CONFIG.policy.snapshot.ignorePaths]
|
|
3724
4034
|
},
|
|
3725
4035
|
dlp: { ...DEFAULT_CONFIG.policy.dlp },
|
|
4036
|
+
egress: {
|
|
4037
|
+
...DEFAULT_CONFIG.policy.egress,
|
|
4038
|
+
allow: [...DEFAULT_CONFIG.policy.egress.allow],
|
|
4039
|
+
deny: [...DEFAULT_CONFIG.policy.egress.deny]
|
|
4040
|
+
},
|
|
3726
4041
|
loopDetection: { ...DEFAULT_CONFIG.policy.loopDetection },
|
|
3727
4042
|
skillPinning: {
|
|
3728
4043
|
...DEFAULT_CONFIG.policy.skillPinning,
|
|
@@ -3773,6 +4088,15 @@ function getConfig(cwd) {
|
|
|
3773
4088
|
const d = p.dlp;
|
|
3774
4089
|
if (d.enabled !== void 0) mergedPolicy.dlp.enabled = d.enabled;
|
|
3775
4090
|
if (d.scanIgnoredTools !== void 0) mergedPolicy.dlp.scanIgnoredTools = d.scanIgnoredTools;
|
|
4091
|
+
if (d.pii !== void 0) mergedPolicy.dlp.pii = d.pii;
|
|
4092
|
+
}
|
|
4093
|
+
if (p.egress) {
|
|
4094
|
+
const e = p.egress;
|
|
4095
|
+
if (e.enabled !== void 0) mergedPolicy.egress.enabled = e.enabled;
|
|
4096
|
+
if (e.mode !== void 0) mergedPolicy.egress.mode = e.mode;
|
|
4097
|
+
if (Array.isArray(e.allow)) mergedPolicy.egress.allow.push(...e.allow);
|
|
4098
|
+
if (Array.isArray(e.deny)) mergedPolicy.egress.deny.push(...e.deny);
|
|
4099
|
+
if (e.allowPrivate !== void 0) mergedPolicy.egress.allowPrivate = e.allowPrivate;
|
|
3776
4100
|
}
|
|
3777
4101
|
if (p.loopDetection) {
|
|
3778
4102
|
const ld = p.loopDetection;
|
|
@@ -4126,7 +4450,8 @@ var init_config = __esm({
|
|
|
4126
4450
|
description: "The AI wants to download a script from the internet and run it immediately, without you seeing what it contains. This is one of the most common ways malware gets installed."
|
|
4127
4451
|
}
|
|
4128
4452
|
],
|
|
4129
|
-
dlp: { enabled: true, scanIgnoredTools: true },
|
|
4453
|
+
dlp: { enabled: true, scanIgnoredTools: true, pii: "off" },
|
|
4454
|
+
egress: { enabled: false, mode: "review", allow: [], deny: [], allowPrivate: true },
|
|
4130
4455
|
loopDetection: { enabled: true, threshold: 5, windowSeconds: 120 },
|
|
4131
4456
|
skillPinning: { enabled: false, mode: "warn", roots: [] }
|
|
4132
4457
|
},
|
|
@@ -5228,6 +5553,14 @@ var init_context_sniper = __esm({
|
|
|
5228
5553
|
});
|
|
5229
5554
|
|
|
5230
5555
|
// src/ui/native.ts
|
|
5556
|
+
function resolveNativeDecision(opts) {
|
|
5557
|
+
const { code, output, elapsedMs, locked } = opts;
|
|
5558
|
+
if (locked) return "deny";
|
|
5559
|
+
const tooFast = elapsedMs < MIN_INTERACTION_MS;
|
|
5560
|
+
if (output.includes("Always Allow")) return tooFast ? "deny" : "always_allow";
|
|
5561
|
+
if (code === 0) return tooFast ? "deny" : "allow";
|
|
5562
|
+
return "deny";
|
|
5563
|
+
}
|
|
5231
5564
|
function formatArgs(args, matchedField, matchedWord) {
|
|
5232
5565
|
if (args === null || args === void 0) return { message: "(none)", intent: "EXEC" };
|
|
5233
5566
|
let parsed = args;
|
|
@@ -5387,6 +5720,7 @@ async function askNativePopup(toolName, args, agent, explainableLabel, locked =
|
|
|
5387
5720
|
);
|
|
5388
5721
|
return new Promise((resolve) => {
|
|
5389
5722
|
let childProcess = null;
|
|
5723
|
+
const startedAt = Date.now();
|
|
5390
5724
|
const onAbort = () => {
|
|
5391
5725
|
if (childProcess && childProcess.pid) {
|
|
5392
5726
|
try {
|
|
@@ -5444,19 +5778,20 @@ end run`;
|
|
|
5444
5778
|
}
|
|
5445
5779
|
let output = "";
|
|
5446
5780
|
childProcess?.stdout?.on("data", (d) => output += d.toString());
|
|
5447
|
-
childProcess?.on("
|
|
5781
|
+
childProcess?.on("error", () => {
|
|
5448
5782
|
if (signal) signal.removeEventListener("abort", onAbort);
|
|
5449
|
-
if (locked) return resolve("deny");
|
|
5450
|
-
if (output.includes("Always Allow")) return resolve("always_allow");
|
|
5451
|
-
if (code === 0) return resolve("allow");
|
|
5452
5783
|
resolve("deny");
|
|
5453
5784
|
});
|
|
5785
|
+
childProcess?.on("close", (code) => {
|
|
5786
|
+
if (signal) signal.removeEventListener("abort", onAbort);
|
|
5787
|
+
resolve(resolveNativeDecision({ code, output, elapsedMs: Date.now() - startedAt, locked }));
|
|
5788
|
+
});
|
|
5454
5789
|
} catch {
|
|
5455
5790
|
resolve("deny");
|
|
5456
5791
|
}
|
|
5457
5792
|
});
|
|
5458
5793
|
}
|
|
5459
|
-
var import_child_process, import_path11, isTestEnv;
|
|
5794
|
+
var import_child_process, import_path11, isTestEnv, MIN_INTERACTION_MS;
|
|
5460
5795
|
var init_native = __esm({
|
|
5461
5796
|
"src/ui/native.ts"() {
|
|
5462
5797
|
"use strict";
|
|
@@ -5466,6 +5801,7 @@ var init_native = __esm({
|
|
|
5466
5801
|
isTestEnv = () => {
|
|
5467
5802
|
return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || !!process.env.VITEST || process.env.CI === "true" || !!process.env.CI || process.env.NODE9_TESTING === "1";
|
|
5468
5803
|
};
|
|
5804
|
+
MIN_INTERACTION_MS = 400;
|
|
5469
5805
|
}
|
|
5470
5806
|
});
|
|
5471
5807
|
|
|
@@ -5779,6 +6115,37 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
5779
6115
|
if (taintResult.tainted && taintResult.record) {
|
|
5780
6116
|
const { path: taintedPath, source: taintSource } = taintResult.record;
|
|
5781
6117
|
taintWarning = `\u26A0\uFE0F ${taintedPath} was flagged by ${taintSource} \u2014 this file may contain sensitive data`;
|
|
6118
|
+
if (config.policy.egress?.enabled) {
|
|
6119
|
+
const a = args && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
6120
|
+
const cmd = typeof a.command === "string" ? a.command : typeof a.cmd === "string" ? a.cmd : "";
|
|
6121
|
+
const dests = cmd ? extractShellDestinations(cmd) : [];
|
|
6122
|
+
const eg = dests.length > 0 ? evaluateEgress(dests, config.policy.egress) : null;
|
|
6123
|
+
if (eg) {
|
|
6124
|
+
if (!isManual)
|
|
6125
|
+
appendLocalAudit(
|
|
6126
|
+
toolName,
|
|
6127
|
+
args,
|
|
6128
|
+
"deny",
|
|
6129
|
+
isObserveMode ? "observe-mode-taint-egress-would-block" : "taint-egress-block",
|
|
6130
|
+
{ ...meta, ruleName: `taint-egress:${eg.host}` },
|
|
6131
|
+
hashAuditArgs
|
|
6132
|
+
);
|
|
6133
|
+
if (isObserveMode) {
|
|
6134
|
+
return {
|
|
6135
|
+
approved: true,
|
|
6136
|
+
checkedBy: "audit",
|
|
6137
|
+
observeWouldBlock: true,
|
|
6138
|
+
blockedByLabel: "\u{1F534} Node9 Taint+Egress (Exfiltration)"
|
|
6139
|
+
};
|
|
6140
|
+
}
|
|
6141
|
+
return {
|
|
6142
|
+
approved: false,
|
|
6143
|
+
reason: `\u{1F534} EXFILTRATION BLOCKED: the tainted file "${taintedPath}" is being sent to untrusted host "${eg.host}". A flagged file leaving to an unrecognized destination is blocked outright.`,
|
|
6144
|
+
blockedBy: "local-config",
|
|
6145
|
+
blockedByLabel: "\u{1F534} Node9 Taint+Egress (Exfiltration Blocked)"
|
|
6146
|
+
};
|
|
6147
|
+
}
|
|
6148
|
+
}
|
|
5782
6149
|
} else if (taintResult.daemonUnavailable) {
|
|
5783
6150
|
taintWarning = `\u26A0\uFE0F Taint service unavailable \u2014 cannot verify if ${filePaths.join(", ")} is clean`;
|
|
5784
6151
|
}
|
|
@@ -5827,6 +6194,35 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
5827
6194
|
explainableLabel = "\u{1F6A8} Node9 DLP (Credential Review)";
|
|
5828
6195
|
}
|
|
5829
6196
|
}
|
|
6197
|
+
if (config.policy.dlp.pii === "block" && (!isIgnoredTool2(toolName) || config.policy.dlp.scanIgnoredTools)) {
|
|
6198
|
+
const piiFound = detectArgsPii(args);
|
|
6199
|
+
if (piiFound.length > 0) {
|
|
6200
|
+
const piiReason = `\u{1F512} PII DETECTED: ${piiFound.join(", ")} found in tool arguments. Remove or tokenize personal data before passing it to a tool.`;
|
|
6201
|
+
if (!isManual)
|
|
6202
|
+
appendLocalAudit(
|
|
6203
|
+
toolName,
|
|
6204
|
+
args,
|
|
6205
|
+
"deny",
|
|
6206
|
+
isObserveMode ? "observe-mode-pii-would-block" : "pii-block",
|
|
6207
|
+
{ ...meta, piiPatterns: piiFound.join(",") },
|
|
6208
|
+
true
|
|
6209
|
+
);
|
|
6210
|
+
if (isObserveMode) {
|
|
6211
|
+
return {
|
|
6212
|
+
approved: true,
|
|
6213
|
+
checkedBy: "audit",
|
|
6214
|
+
observeWouldBlock: true,
|
|
6215
|
+
blockedByLabel: "\u{1F512} Node9 PII (Detected)"
|
|
6216
|
+
};
|
|
6217
|
+
}
|
|
6218
|
+
return {
|
|
6219
|
+
approved: false,
|
|
6220
|
+
reason: piiReason,
|
|
6221
|
+
blockedBy: "local-config",
|
|
6222
|
+
blockedByLabel: "\u{1F512} Node9 PII (Detected)"
|
|
6223
|
+
};
|
|
6224
|
+
}
|
|
6225
|
+
}
|
|
5830
6226
|
if (isObserveMode) {
|
|
5831
6227
|
if (!isIgnoredTool2(toolName)) {
|
|
5832
6228
|
const policyResult = await evaluatePolicy2(toolName, args, meta?.agent, options?.cwd);
|
|
@@ -6276,6 +6672,7 @@ var init_orchestrator = __esm({
|
|
|
6276
6672
|
init_native();
|
|
6277
6673
|
init_context_sniper();
|
|
6278
6674
|
init_dlp();
|
|
6675
|
+
init_dist();
|
|
6279
6676
|
init_audit();
|
|
6280
6677
|
init_config();
|
|
6281
6678
|
init_policy();
|
|
@@ -9629,15 +10026,115 @@ var init_litellm = __esm({
|
|
|
9629
10026
|
}
|
|
9630
10027
|
});
|
|
9631
10028
|
|
|
10029
|
+
// src/cost-codex.ts
|
|
10030
|
+
function codexLogPath() {
|
|
10031
|
+
return import_path19.default.join(import_os16.default.homedir(), ".codex", "log", "codex-tui.log");
|
|
10032
|
+
}
|
|
10033
|
+
function parseCodexUsageLine(line) {
|
|
10034
|
+
if (!line.includes("token_usage")) return null;
|
|
10035
|
+
const date = line.match(RE_DATE)?.[1];
|
|
10036
|
+
if (!date) return null;
|
|
10037
|
+
const model = line.match(RE_MODEL)?.[1];
|
|
10038
|
+
if (!model) return null;
|
|
10039
|
+
const num3 = (re) => {
|
|
10040
|
+
const m = line.match(re);
|
|
10041
|
+
return m ? Number(m[1]) : 0;
|
|
10042
|
+
};
|
|
10043
|
+
const totalInput = num3(RE_INPUT);
|
|
10044
|
+
const cached = num3(RE_CACHED);
|
|
10045
|
+
const nonCached = num3(RE_NON_CACHED);
|
|
10046
|
+
const output = num3(RE_OUTPUT);
|
|
10047
|
+
const inputTokens = nonCached || Math.max(0, totalInput - cached);
|
|
10048
|
+
if (inputTokens === 0 && output === 0 && cached === 0) return null;
|
|
10049
|
+
const runId = line.match(RE_THREAD)?.[1] ?? "";
|
|
10050
|
+
const norm = normalizeModel(model);
|
|
10051
|
+
const p = pricingFor(model);
|
|
10052
|
+
const costUSD = p ? inputTokens * p[0] + output * p[1] + cached * p[3] : 0;
|
|
10053
|
+
return {
|
|
10054
|
+
date,
|
|
10055
|
+
model: norm,
|
|
10056
|
+
workingDir: "",
|
|
10057
|
+
// Codex span carries no cwd — attribution is by runId (thread)
|
|
10058
|
+
runId,
|
|
10059
|
+
costUSD,
|
|
10060
|
+
inputTokens,
|
|
10061
|
+
outputTokens: output,
|
|
10062
|
+
cacheReadTokens: cached,
|
|
10063
|
+
cacheWriteTokens: 0
|
|
10064
|
+
};
|
|
10065
|
+
}
|
|
10066
|
+
var import_fs17, import_os16, import_path19, RE_INPUT, RE_CACHED, RE_NON_CACHED, RE_OUTPUT, RE_MODEL, RE_THREAD, RE_DATE, codexSource;
|
|
10067
|
+
var init_cost_codex = __esm({
|
|
10068
|
+
"src/cost-codex.ts"() {
|
|
10069
|
+
"use strict";
|
|
10070
|
+
import_fs17 = __toESM(require("fs"));
|
|
10071
|
+
import_os16 = __toESM(require("os"));
|
|
10072
|
+
import_path19 = __toESM(require("path"));
|
|
10073
|
+
init_litellm();
|
|
10074
|
+
RE_INPUT = /token_usage\.input_tokens=(\d+)/;
|
|
10075
|
+
RE_CACHED = /token_usage\.cached_input_tokens=(\d+)/;
|
|
10076
|
+
RE_NON_CACHED = /token_usage\.non_cached_input_tokens=(\d+)/;
|
|
10077
|
+
RE_OUTPUT = /token_usage\.output_tokens=(\d+)/;
|
|
10078
|
+
RE_MODEL = /\bmodel=([^\s}]+)/;
|
|
10079
|
+
RE_THREAD = /\bthread\.id=([0-9a-fA-F-]+)/;
|
|
10080
|
+
RE_DATE = /^(\d{4}-\d{2}-\d{2})T/;
|
|
10081
|
+
codexSource = {
|
|
10082
|
+
id: "codex",
|
|
10083
|
+
available() {
|
|
10084
|
+
try {
|
|
10085
|
+
return import_fs17.default.existsSync(codexLogPath());
|
|
10086
|
+
} catch {
|
|
10087
|
+
return false;
|
|
10088
|
+
}
|
|
10089
|
+
},
|
|
10090
|
+
collect(sinceMs) {
|
|
10091
|
+
const file = codexLogPath();
|
|
10092
|
+
let content;
|
|
10093
|
+
try {
|
|
10094
|
+
if (sinceMs !== void 0 && import_fs17.default.statSync(file).mtimeMs < sinceMs) return [];
|
|
10095
|
+
content = import_fs17.default.readFileSync(file, "utf8");
|
|
10096
|
+
} catch {
|
|
10097
|
+
return [];
|
|
10098
|
+
}
|
|
10099
|
+
const combined = /* @__PURE__ */ new Map();
|
|
10100
|
+
for (const line of content.split("\n")) {
|
|
10101
|
+
if (!line.includes("token_usage")) continue;
|
|
10102
|
+
if (sinceMs !== void 0) {
|
|
10103
|
+
const tsFull = line.match(/^(\S+)\s/)?.[1];
|
|
10104
|
+
if (tsFull) {
|
|
10105
|
+
const t = Date.parse(tsFull);
|
|
10106
|
+
if (!Number.isNaN(t) && t < sinceMs) continue;
|
|
10107
|
+
}
|
|
10108
|
+
}
|
|
10109
|
+
const e = parseCodexUsageLine(line);
|
|
10110
|
+
if (!e) continue;
|
|
10111
|
+
const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
|
|
10112
|
+
const prev = combined.get(key);
|
|
10113
|
+
if (prev) {
|
|
10114
|
+
prev.costUSD += e.costUSD;
|
|
10115
|
+
prev.inputTokens += e.inputTokens;
|
|
10116
|
+
prev.outputTokens += e.outputTokens;
|
|
10117
|
+
prev.cacheReadTokens += e.cacheReadTokens;
|
|
10118
|
+
prev.cacheWriteTokens += e.cacheWriteTokens;
|
|
10119
|
+
} else {
|
|
10120
|
+
combined.set(key, { ...e });
|
|
10121
|
+
}
|
|
10122
|
+
}
|
|
10123
|
+
return [...combined.values()];
|
|
10124
|
+
}
|
|
10125
|
+
};
|
|
10126
|
+
}
|
|
10127
|
+
});
|
|
10128
|
+
|
|
9632
10129
|
// src/costSync.ts
|
|
9633
10130
|
function decodeProjectDirName(dirName) {
|
|
9634
10131
|
return dirName.replace(/-/g, "/");
|
|
9635
10132
|
}
|
|
9636
10133
|
function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
9637
|
-
const runId =
|
|
10134
|
+
const runId = import_path20.default.basename(filePath, ".jsonl");
|
|
9638
10135
|
let content;
|
|
9639
10136
|
try {
|
|
9640
|
-
content =
|
|
10137
|
+
content = import_fs18.default.readFileSync(filePath, "utf8");
|
|
9641
10138
|
} catch {
|
|
9642
10139
|
return /* @__PURE__ */ new Map();
|
|
9643
10140
|
}
|
|
@@ -9692,51 +10189,30 @@ function parseJSONLFile(filePath, fallbackWorkingDir) {
|
|
|
9692
10189
|
}
|
|
9693
10190
|
return daily;
|
|
9694
10191
|
}
|
|
10192
|
+
function entryKey(e) {
|
|
10193
|
+
return `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
|
|
10194
|
+
}
|
|
9695
10195
|
function collectEntries(sinceMs) {
|
|
9696
|
-
const projectsDir = import_path19.default.join(import_os16.default.homedir(), ".claude", "projects");
|
|
9697
|
-
if (!import_fs17.default.existsSync(projectsDir)) return [];
|
|
9698
10196
|
const combined = /* @__PURE__ */ new Map();
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
dirs = import_fs17.default.readdirSync(projectsDir);
|
|
9702
|
-
} catch {
|
|
9703
|
-
return [];
|
|
9704
|
-
}
|
|
9705
|
-
for (const dir of dirs) {
|
|
9706
|
-
const dirPath = import_path19.default.join(projectsDir, dir);
|
|
9707
|
-
try {
|
|
9708
|
-
if (!import_fs17.default.statSync(dirPath).isDirectory()) continue;
|
|
9709
|
-
} catch {
|
|
9710
|
-
continue;
|
|
9711
|
-
}
|
|
9712
|
-
let files;
|
|
10197
|
+
for (const src of COST_SOURCES) {
|
|
10198
|
+
let rows;
|
|
9713
10199
|
try {
|
|
9714
|
-
|
|
10200
|
+
if (!src.available()) continue;
|
|
10201
|
+
rows = src.collect(sinceMs);
|
|
9715
10202
|
} catch {
|
|
9716
10203
|
continue;
|
|
9717
10204
|
}
|
|
9718
|
-
const
|
|
9719
|
-
|
|
9720
|
-
const
|
|
9721
|
-
if (
|
|
9722
|
-
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
}
|
|
9728
|
-
|
|
9729
|
-
for (const [key, e] of entries) {
|
|
9730
|
-
const prev = combined.get(key);
|
|
9731
|
-
if (prev) {
|
|
9732
|
-
prev.costUSD += e.costUSD;
|
|
9733
|
-
prev.inputTokens += e.inputTokens;
|
|
9734
|
-
prev.outputTokens += e.outputTokens;
|
|
9735
|
-
prev.cacheWriteTokens += e.cacheWriteTokens;
|
|
9736
|
-
prev.cacheReadTokens += e.cacheReadTokens;
|
|
9737
|
-
} else {
|
|
9738
|
-
combined.set(key, { ...e });
|
|
9739
|
-
}
|
|
10205
|
+
for (const e of rows) {
|
|
10206
|
+
const key = entryKey(e);
|
|
10207
|
+
const prev = combined.get(key);
|
|
10208
|
+
if (prev) {
|
|
10209
|
+
prev.costUSD += e.costUSD;
|
|
10210
|
+
prev.inputTokens += e.inputTokens;
|
|
10211
|
+
prev.outputTokens += e.outputTokens;
|
|
10212
|
+
prev.cacheWriteTokens += e.cacheWriteTokens;
|
|
10213
|
+
prev.cacheReadTokens += e.cacheReadTokens;
|
|
10214
|
+
} else {
|
|
10215
|
+
combined.set(key, { ...e });
|
|
9740
10216
|
}
|
|
9741
10217
|
}
|
|
9742
10218
|
}
|
|
@@ -9750,10 +10226,10 @@ async function syncCost() {
|
|
|
9750
10226
|
if (entries.length === 0) return;
|
|
9751
10227
|
let username = "unknown";
|
|
9752
10228
|
try {
|
|
9753
|
-
username =
|
|
10229
|
+
username = import_os17.default.userInfo().username;
|
|
9754
10230
|
} catch {
|
|
9755
10231
|
}
|
|
9756
|
-
const machineId = `${
|
|
10232
|
+
const machineId = `${import_os17.default.hostname()}:${username}`;
|
|
9757
10233
|
try {
|
|
9758
10234
|
const res = await fetch(`${creds.apiUrl}/cost-sync`, {
|
|
9759
10235
|
method: "POST",
|
|
@@ -9762,11 +10238,11 @@ async function syncCost() {
|
|
|
9762
10238
|
signal: AbortSignal.timeout(15e3)
|
|
9763
10239
|
});
|
|
9764
10240
|
if (!res.ok) {
|
|
9765
|
-
|
|
10241
|
+
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
|
|
9766
10242
|
`);
|
|
9767
10243
|
}
|
|
9768
10244
|
} catch (err2) {
|
|
9769
|
-
|
|
10245
|
+
import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
|
|
9770
10246
|
`);
|
|
9771
10247
|
}
|
|
9772
10248
|
}
|
|
@@ -9779,17 +10255,75 @@ function startCostSync() {
|
|
|
9779
10255
|
}, SYNC_INTERVAL_MS);
|
|
9780
10256
|
timer.unref();
|
|
9781
10257
|
}
|
|
9782
|
-
var
|
|
10258
|
+
var import_fs18, import_path20, import_os17, SYNC_INTERVAL_MS, claudeSource, COST_SOURCES;
|
|
9783
10259
|
var init_costSync = __esm({
|
|
9784
10260
|
"src/costSync.ts"() {
|
|
9785
10261
|
"use strict";
|
|
9786
|
-
|
|
9787
|
-
|
|
9788
|
-
|
|
10262
|
+
import_fs18 = __toESM(require("fs"));
|
|
10263
|
+
import_path20 = __toESM(require("path"));
|
|
10264
|
+
import_os17 = __toESM(require("os"));
|
|
9789
10265
|
init_config();
|
|
9790
10266
|
init_audit();
|
|
9791
10267
|
init_litellm();
|
|
10268
|
+
init_cost_codex();
|
|
9792
10269
|
SYNC_INTERVAL_MS = 10 * 60 * 1e3;
|
|
10270
|
+
claudeSource = {
|
|
10271
|
+
id: "claude",
|
|
10272
|
+
available() {
|
|
10273
|
+
return import_fs18.default.existsSync(import_path20.default.join(import_os17.default.homedir(), ".claude", "projects"));
|
|
10274
|
+
},
|
|
10275
|
+
collect(sinceMs) {
|
|
10276
|
+
const projectsDir = import_path20.default.join(import_os17.default.homedir(), ".claude", "projects");
|
|
10277
|
+
if (!import_fs18.default.existsSync(projectsDir)) return [];
|
|
10278
|
+
const combined = /* @__PURE__ */ new Map();
|
|
10279
|
+
let dirs;
|
|
10280
|
+
try {
|
|
10281
|
+
dirs = import_fs18.default.readdirSync(projectsDir);
|
|
10282
|
+
} catch {
|
|
10283
|
+
return [];
|
|
10284
|
+
}
|
|
10285
|
+
for (const dir of dirs) {
|
|
10286
|
+
const dirPath = import_path20.default.join(projectsDir, dir);
|
|
10287
|
+
try {
|
|
10288
|
+
if (!import_fs18.default.statSync(dirPath).isDirectory()) continue;
|
|
10289
|
+
} catch {
|
|
10290
|
+
continue;
|
|
10291
|
+
}
|
|
10292
|
+
let files;
|
|
10293
|
+
try {
|
|
10294
|
+
files = import_fs18.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
10295
|
+
} catch {
|
|
10296
|
+
continue;
|
|
10297
|
+
}
|
|
10298
|
+
const fallbackWorkingDir = decodeProjectDirName(dir);
|
|
10299
|
+
for (const file of files) {
|
|
10300
|
+
const filePath = import_path20.default.join(dirPath, file);
|
|
10301
|
+
if (sinceMs !== void 0) {
|
|
10302
|
+
try {
|
|
10303
|
+
if (import_fs18.default.statSync(filePath).mtimeMs < sinceMs) continue;
|
|
10304
|
+
} catch {
|
|
10305
|
+
continue;
|
|
10306
|
+
}
|
|
10307
|
+
}
|
|
10308
|
+
const entries = parseJSONLFile(filePath, fallbackWorkingDir);
|
|
10309
|
+
for (const [key, e] of entries) {
|
|
10310
|
+
const prev = combined.get(key);
|
|
10311
|
+
if (prev) {
|
|
10312
|
+
prev.costUSD += e.costUSD;
|
|
10313
|
+
prev.inputTokens += e.inputTokens;
|
|
10314
|
+
prev.outputTokens += e.outputTokens;
|
|
10315
|
+
prev.cacheWriteTokens += e.cacheWriteTokens;
|
|
10316
|
+
prev.cacheReadTokens += e.cacheReadTokens;
|
|
10317
|
+
} else {
|
|
10318
|
+
combined.set(key, { ...e });
|
|
10319
|
+
}
|
|
10320
|
+
}
|
|
10321
|
+
}
|
|
10322
|
+
}
|
|
10323
|
+
return [...combined.values()];
|
|
10324
|
+
}
|
|
10325
|
+
};
|
|
10326
|
+
COST_SOURCES = [claudeSource, codexSource];
|
|
9793
10327
|
}
|
|
9794
10328
|
});
|
|
9795
10329
|
|
|
@@ -9816,7 +10350,7 @@ function freshWatermark() {
|
|
|
9816
10350
|
function loadWatermark() {
|
|
9817
10351
|
let raw;
|
|
9818
10352
|
try {
|
|
9819
|
-
raw =
|
|
10353
|
+
raw = import_fs19.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
9820
10354
|
} catch {
|
|
9821
10355
|
return { status: "fresh", wm: freshWatermark() };
|
|
9822
10356
|
}
|
|
@@ -9868,28 +10402,28 @@ function loadWatermark() {
|
|
|
9868
10402
|
function saveWatermark(wm) {
|
|
9869
10403
|
if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
|
|
9870
10404
|
const target = WATERMARK_FILE();
|
|
9871
|
-
const dir =
|
|
9872
|
-
if (!
|
|
10405
|
+
const dir = import_path21.default.dirname(target);
|
|
10406
|
+
if (!import_fs19.default.existsSync(dir)) import_fs19.default.mkdirSync(dir, { recursive: true });
|
|
9873
10407
|
const tmp = target + ".tmp";
|
|
9874
|
-
|
|
9875
|
-
|
|
10408
|
+
import_fs19.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
|
|
10409
|
+
import_fs19.default.renameSync(tmp, target);
|
|
9876
10410
|
}
|
|
9877
10411
|
function listJsonlFiles() {
|
|
9878
10412
|
const root = PROJECTS_DIR();
|
|
9879
|
-
if (!
|
|
10413
|
+
if (!import_fs19.default.existsSync(root)) return [];
|
|
9880
10414
|
const out = [];
|
|
9881
|
-
for (const entry of
|
|
10415
|
+
for (const entry of import_fs19.default.readdirSync(root, { withFileTypes: true })) {
|
|
9882
10416
|
if (!entry.isDirectory()) continue;
|
|
9883
|
-
const projectDir =
|
|
10417
|
+
const projectDir = import_path21.default.join(root, entry.name);
|
|
9884
10418
|
let inner;
|
|
9885
10419
|
try {
|
|
9886
|
-
inner =
|
|
10420
|
+
inner = import_fs19.default.readdirSync(projectDir, { withFileTypes: true });
|
|
9887
10421
|
} catch {
|
|
9888
10422
|
continue;
|
|
9889
10423
|
}
|
|
9890
10424
|
for (const file of inner) {
|
|
9891
10425
|
if (file.isFile() && file.name.endsWith(".jsonl")) {
|
|
9892
|
-
out.push(
|
|
10426
|
+
out.push(import_path21.default.join(projectDir, file.name));
|
|
9893
10427
|
}
|
|
9894
10428
|
}
|
|
9895
10429
|
}
|
|
@@ -9897,7 +10431,7 @@ function listJsonlFiles() {
|
|
|
9897
10431
|
}
|
|
9898
10432
|
function fileSize(p) {
|
|
9899
10433
|
try {
|
|
9900
|
-
return
|
|
10434
|
+
return import_fs19.default.statSync(p).size;
|
|
9901
10435
|
} catch {
|
|
9902
10436
|
return 0;
|
|
9903
10437
|
}
|
|
@@ -9905,7 +10439,7 @@ function fileSize(p) {
|
|
|
9905
10439
|
async function scanDelta(filePath, fromByte, onLine) {
|
|
9906
10440
|
const size = fileSize(filePath);
|
|
9907
10441
|
if (size <= fromByte) return fromByte;
|
|
9908
|
-
const stream =
|
|
10442
|
+
const stream = import_fs19.default.createReadStream(filePath, {
|
|
9909
10443
|
start: fromByte,
|
|
9910
10444
|
end: size - 1,
|
|
9911
10445
|
highWaterMark: 64 * 1024
|
|
@@ -10017,7 +10551,7 @@ async function tickForensicBroadcast(offsets) {
|
|
|
10017
10551
|
continue;
|
|
10018
10552
|
}
|
|
10019
10553
|
if (size <= offset) continue;
|
|
10020
|
-
const sessionId =
|
|
10554
|
+
const sessionId = import_path21.default.basename(file, ".jsonl");
|
|
10021
10555
|
const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
|
|
10022
10556
|
out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
|
|
10023
10557
|
});
|
|
@@ -10076,7 +10610,7 @@ function emptyTick(uploadAs) {
|
|
|
10076
10610
|
function readRawWatermarkPreservingOffsets() {
|
|
10077
10611
|
let raw;
|
|
10078
10612
|
try {
|
|
10079
|
-
raw =
|
|
10613
|
+
raw = import_fs19.default.readFileSync(WATERMARK_FILE(), "utf-8");
|
|
10080
10614
|
} catch {
|
|
10081
10615
|
return null;
|
|
10082
10616
|
}
|
|
@@ -10110,13 +10644,13 @@ async function runActualTick(wm) {
|
|
|
10110
10644
|
if (!known) {
|
|
10111
10645
|
let mtimeMs = 0;
|
|
10112
10646
|
try {
|
|
10113
|
-
mtimeMs =
|
|
10647
|
+
mtimeMs = import_fs19.default.statSync(filePath).mtime.getTime();
|
|
10114
10648
|
} catch {
|
|
10115
10649
|
continue;
|
|
10116
10650
|
}
|
|
10117
10651
|
if (mtimeMs >= watermarkCreatedAt) {
|
|
10118
10652
|
filesNew++;
|
|
10119
|
-
const sessionId2 =
|
|
10653
|
+
const sessionId2 = import_path21.default.basename(filePath, ".jsonl");
|
|
10120
10654
|
const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
|
|
10121
10655
|
totalToolCalls++;
|
|
10122
10656
|
toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
|
|
@@ -10134,7 +10668,7 @@ async function runActualTick(wm) {
|
|
|
10134
10668
|
filesSkipped++;
|
|
10135
10669
|
continue;
|
|
10136
10670
|
}
|
|
10137
|
-
const sessionId =
|
|
10671
|
+
const sessionId = import_path21.default.basename(filePath, ".jsonl");
|
|
10138
10672
|
const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
|
|
10139
10673
|
totalToolCalls++;
|
|
10140
10674
|
toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
|
|
@@ -10156,18 +10690,18 @@ async function runActualTick(wm) {
|
|
|
10156
10690
|
schemaFuture: false
|
|
10157
10691
|
};
|
|
10158
10692
|
}
|
|
10159
|
-
var
|
|
10693
|
+
var import_fs19, import_os18, import_path21, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
|
|
10160
10694
|
var init_scan_watermark = __esm({
|
|
10161
10695
|
"src/daemon/scan-watermark.ts"() {
|
|
10162
10696
|
"use strict";
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10697
|
+
import_fs19 = __toESM(require("fs"));
|
|
10698
|
+
import_os18 = __toESM(require("os"));
|
|
10699
|
+
import_path21 = __toESM(require("path"));
|
|
10166
10700
|
import_readline = __toESM(require("readline"));
|
|
10167
10701
|
init_dlp();
|
|
10168
10702
|
init_dist();
|
|
10169
|
-
PROJECTS_DIR = () =>
|
|
10170
|
-
WATERMARK_FILE = () =>
|
|
10703
|
+
PROJECTS_DIR = () => import_path21.default.join(import_os18.default.homedir(), ".claude", "projects");
|
|
10704
|
+
WATERMARK_FILE = () => import_path21.default.join(import_os18.default.homedir(), ".node9", "scan-watermark.json");
|
|
10171
10705
|
MAX_LINE_BYTES = 2 * 1024 * 1024;
|
|
10172
10706
|
WATERMARK_SCHEMA_VERSION = 2;
|
|
10173
10707
|
LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
|
|
@@ -10178,6 +10712,7 @@ var init_scan_watermark = __esm({
|
|
|
10178
10712
|
var scan_upload_history_exports = {};
|
|
10179
10713
|
__export(scan_upload_history_exports, {
|
|
10180
10714
|
buildSessionTotals: () => buildSessionTotals,
|
|
10715
|
+
extractHistoricalLoops: () => extractHistoricalLoops,
|
|
10181
10716
|
iterateJsonlFiles: () => iterateJsonlFiles,
|
|
10182
10717
|
parseSinceCutoff: () => parseSinceCutoff,
|
|
10183
10718
|
runUploadHistory: () => runUploadHistory
|
|
@@ -10215,40 +10750,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
|
|
|
10215
10750
|
return now.getTime() - 90 * 864e5;
|
|
10216
10751
|
}
|
|
10217
10752
|
function* iterateJsonlFiles(cutoffMs) {
|
|
10218
|
-
const projectsDir =
|
|
10753
|
+
const projectsDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
|
|
10219
10754
|
let dirs;
|
|
10220
10755
|
try {
|
|
10221
|
-
dirs =
|
|
10756
|
+
dirs = import_fs20.default.readdirSync(projectsDir);
|
|
10222
10757
|
} catch {
|
|
10223
10758
|
return;
|
|
10224
10759
|
}
|
|
10225
10760
|
for (const dir of dirs) {
|
|
10226
|
-
const dirPath =
|
|
10761
|
+
const dirPath = import_path22.default.join(projectsDir, dir);
|
|
10227
10762
|
let stats;
|
|
10228
10763
|
try {
|
|
10229
|
-
stats =
|
|
10764
|
+
stats = import_fs20.default.statSync(dirPath);
|
|
10230
10765
|
} catch {
|
|
10231
10766
|
continue;
|
|
10232
10767
|
}
|
|
10233
10768
|
if (!stats.isDirectory()) continue;
|
|
10234
10769
|
let files;
|
|
10235
10770
|
try {
|
|
10236
|
-
files =
|
|
10771
|
+
files = import_fs20.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
10237
10772
|
} catch {
|
|
10238
10773
|
continue;
|
|
10239
10774
|
}
|
|
10240
10775
|
for (const file of files) {
|
|
10241
|
-
const filePath =
|
|
10776
|
+
const filePath = import_path22.default.join(dirPath, file);
|
|
10242
10777
|
let mtime = 0;
|
|
10243
10778
|
try {
|
|
10244
|
-
mtime =
|
|
10779
|
+
mtime = import_fs20.default.statSync(filePath).mtimeMs;
|
|
10245
10780
|
} catch {
|
|
10246
10781
|
continue;
|
|
10247
10782
|
}
|
|
10248
10783
|
if (mtime < cutoffMs) continue;
|
|
10249
10784
|
yield {
|
|
10250
10785
|
filePath,
|
|
10251
|
-
sessionId:
|
|
10786
|
+
sessionId: import_path22.default.basename(file, ".jsonl"),
|
|
10252
10787
|
projectDir: dir
|
|
10253
10788
|
};
|
|
10254
10789
|
}
|
|
@@ -10271,6 +10806,19 @@ function buildSessionTotals(findings, toolCallsBySession) {
|
|
|
10271
10806
|
signals
|
|
10272
10807
|
}));
|
|
10273
10808
|
}
|
|
10809
|
+
function extractHistoricalLoops(sessionCalls, ctx) {
|
|
10810
|
+
return extractSessionLevelFindings(sessionCalls, {
|
|
10811
|
+
sessionId: ctx.sessionId,
|
|
10812
|
+
project: ctx.project,
|
|
10813
|
+
agent: ctx.agent,
|
|
10814
|
+
loopDetection: {
|
|
10815
|
+
enabled: true,
|
|
10816
|
+
threshold: ctx.threshold,
|
|
10817
|
+
windowSeconds: 0
|
|
10818
|
+
// whole session — never the live blocker's window
|
|
10819
|
+
}
|
|
10820
|
+
});
|
|
10821
|
+
}
|
|
10274
10822
|
async function runUploadHistory(opts) {
|
|
10275
10823
|
const creds = getCredentials();
|
|
10276
10824
|
if (!creds?.apiKey) {
|
|
@@ -10301,7 +10849,7 @@ async function runUploadHistory(opts) {
|
|
|
10301
10849
|
filesScanned++;
|
|
10302
10850
|
let content;
|
|
10303
10851
|
try {
|
|
10304
|
-
content =
|
|
10852
|
+
content = import_fs20.default.readFileSync(filePath, "utf8");
|
|
10305
10853
|
} catch {
|
|
10306
10854
|
continue;
|
|
10307
10855
|
}
|
|
@@ -10340,15 +10888,11 @@ async function runUploadHistory(opts) {
|
|
|
10340
10888
|
lineIndex++;
|
|
10341
10889
|
}
|
|
10342
10890
|
if (loopCfg.enabled && sessionCalls.length > 0) {
|
|
10343
|
-
const loops =
|
|
10891
|
+
const loops = extractHistoricalLoops(sessionCalls, {
|
|
10344
10892
|
sessionId,
|
|
10345
10893
|
project: decodeProjectDirName(projectDir),
|
|
10346
10894
|
agent: "claude",
|
|
10347
|
-
|
|
10348
|
-
enabled: loopCfg.enabled,
|
|
10349
|
-
threshold: loopCfg.threshold,
|
|
10350
|
-
windowSeconds: loopCfg.windowSeconds
|
|
10351
|
-
}
|
|
10895
|
+
threshold: loopCfg.threshold
|
|
10352
10896
|
});
|
|
10353
10897
|
for (const cf of loops) {
|
|
10354
10898
|
const sf = toScanFinding(cf);
|
|
@@ -10387,10 +10931,10 @@ async function runUploadHistory(opts) {
|
|
|
10387
10931
|
const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
|
|
10388
10932
|
let username = "unknown";
|
|
10389
10933
|
try {
|
|
10390
|
-
username =
|
|
10934
|
+
username = import_os19.default.userInfo().username;
|
|
10391
10935
|
} catch {
|
|
10392
10936
|
}
|
|
10393
|
-
const machineId = `${
|
|
10937
|
+
const machineId = `${import_os19.default.hostname()}:${username}`;
|
|
10394
10938
|
await postJson(costUrl, creds.apiKey, {
|
|
10395
10939
|
machineId,
|
|
10396
10940
|
entries: dailyEntries
|
|
@@ -10440,14 +10984,14 @@ async function postJson(url, apiKey, body) {
|
|
|
10440
10984
|
req.end();
|
|
10441
10985
|
});
|
|
10442
10986
|
}
|
|
10443
|
-
var
|
|
10987
|
+
var import_fs20, import_https, import_os19, import_path22, import_chalk4, FINDING_TO_SIGNAL2;
|
|
10444
10988
|
var init_scan_upload_history = __esm({
|
|
10445
10989
|
"src/scan-upload-history.ts"() {
|
|
10446
10990
|
"use strict";
|
|
10447
|
-
|
|
10991
|
+
import_fs20 = __toESM(require("fs"));
|
|
10448
10992
|
import_https = __toESM(require("https"));
|
|
10449
|
-
|
|
10450
|
-
|
|
10993
|
+
import_os19 = __toESM(require("os"));
|
|
10994
|
+
import_path22 = __toESM(require("path"));
|
|
10451
10995
|
import_chalk4 = __toESM(require("chalk"));
|
|
10452
10996
|
init_dist();
|
|
10453
10997
|
init_config();
|
|
@@ -10693,14 +11237,14 @@ function buildRuleSources() {
|
|
|
10693
11237
|
}
|
|
10694
11238
|
function countScanFiles() {
|
|
10695
11239
|
let total = 0;
|
|
10696
|
-
const claudeDir =
|
|
10697
|
-
if (
|
|
11240
|
+
const claudeDir = import_path23.default.join(import_os20.default.homedir(), ".claude", "projects");
|
|
11241
|
+
if (import_fs21.default.existsSync(claudeDir)) {
|
|
10698
11242
|
try {
|
|
10699
|
-
for (const proj of
|
|
10700
|
-
const p =
|
|
11243
|
+
for (const proj of import_fs21.default.readdirSync(claudeDir)) {
|
|
11244
|
+
const p = import_path23.default.join(claudeDir, proj);
|
|
10701
11245
|
try {
|
|
10702
|
-
if (!
|
|
10703
|
-
total +=
|
|
11246
|
+
if (!import_fs21.default.statSync(p).isDirectory()) continue;
|
|
11247
|
+
total += import_fs21.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
|
|
10704
11248
|
} catch {
|
|
10705
11249
|
continue;
|
|
10706
11250
|
}
|
|
@@ -10708,17 +11252,17 @@ function countScanFiles() {
|
|
|
10708
11252
|
} catch {
|
|
10709
11253
|
}
|
|
10710
11254
|
}
|
|
10711
|
-
const geminiDir =
|
|
10712
|
-
if (
|
|
11255
|
+
const geminiDir = import_path23.default.join(import_os20.default.homedir(), ".gemini", "tmp");
|
|
11256
|
+
if (import_fs21.default.existsSync(geminiDir)) {
|
|
10713
11257
|
try {
|
|
10714
|
-
for (const slug of
|
|
10715
|
-
const p =
|
|
11258
|
+
for (const slug of import_fs21.default.readdirSync(geminiDir)) {
|
|
11259
|
+
const p = import_path23.default.join(geminiDir, slug);
|
|
10716
11260
|
try {
|
|
10717
|
-
if (!
|
|
10718
|
-
const chatsDir =
|
|
10719
|
-
if (
|
|
11261
|
+
if (!import_fs21.default.statSync(p).isDirectory()) continue;
|
|
11262
|
+
const chatsDir = import_path23.default.join(p, "chats");
|
|
11263
|
+
if (import_fs21.default.existsSync(chatsDir)) {
|
|
10720
11264
|
try {
|
|
10721
|
-
total +=
|
|
11265
|
+
total += import_fs21.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
|
|
10722
11266
|
} catch {
|
|
10723
11267
|
}
|
|
10724
11268
|
}
|
|
@@ -10730,15 +11274,15 @@ function countScanFiles() {
|
|
|
10730
11274
|
}
|
|
10731
11275
|
}
|
|
10732
11276
|
for (const surface of ["antigravity-cli", "antigravity-ide"]) {
|
|
10733
|
-
const brainDir =
|
|
10734
|
-
if (!
|
|
11277
|
+
const brainDir = import_path23.default.join(import_os20.default.homedir(), ".gemini", surface, "brain");
|
|
11278
|
+
if (!import_fs21.default.existsSync(brainDir)) continue;
|
|
10735
11279
|
try {
|
|
10736
|
-
for (const conv of
|
|
10737
|
-
const convPath =
|
|
11280
|
+
for (const conv of import_fs21.default.readdirSync(brainDir)) {
|
|
11281
|
+
const convPath = import_path23.default.join(brainDir, conv);
|
|
10738
11282
|
try {
|
|
10739
|
-
if (!
|
|
10740
|
-
const logsDir =
|
|
10741
|
-
if (
|
|
11283
|
+
if (!import_fs21.default.statSync(convPath).isDirectory()) continue;
|
|
11284
|
+
const logsDir = import_path23.default.join(convPath, ".system_generated", "logs");
|
|
11285
|
+
if (import_fs21.default.existsSync(import_path23.default.join(logsDir, "transcript_full.jsonl")) || import_fs21.default.existsSync(import_path23.default.join(logsDir, "transcript.jsonl"))) {
|
|
10742
11286
|
total += 1;
|
|
10743
11287
|
}
|
|
10744
11288
|
} catch {
|
|
@@ -10748,31 +11292,31 @@ function countScanFiles() {
|
|
|
10748
11292
|
} catch {
|
|
10749
11293
|
}
|
|
10750
11294
|
}
|
|
10751
|
-
const copilotDir =
|
|
10752
|
-
if (
|
|
11295
|
+
const copilotDir = import_path23.default.join(import_os20.default.homedir(), ".copilot", "session-state");
|
|
11296
|
+
if (import_fs21.default.existsSync(copilotDir)) {
|
|
10753
11297
|
try {
|
|
10754
|
-
for (const sid of
|
|
10755
|
-
if (
|
|
11298
|
+
for (const sid of import_fs21.default.readdirSync(copilotDir)) {
|
|
11299
|
+
if (import_fs21.default.existsSync(import_path23.default.join(copilotDir, sid, "events.jsonl"))) total += 1;
|
|
10756
11300
|
}
|
|
10757
11301
|
} catch {
|
|
10758
11302
|
}
|
|
10759
11303
|
}
|
|
10760
|
-
const codexDir =
|
|
10761
|
-
if (
|
|
11304
|
+
const codexDir = import_path23.default.join(import_os20.default.homedir(), ".codex", "sessions");
|
|
11305
|
+
if (import_fs21.default.existsSync(codexDir)) {
|
|
10762
11306
|
try {
|
|
10763
|
-
for (const year of
|
|
10764
|
-
const yp =
|
|
11307
|
+
for (const year of import_fs21.default.readdirSync(codexDir)) {
|
|
11308
|
+
const yp = import_path23.default.join(codexDir, year);
|
|
10765
11309
|
try {
|
|
10766
|
-
if (!
|
|
10767
|
-
for (const month of
|
|
10768
|
-
const mp =
|
|
11310
|
+
if (!import_fs21.default.statSync(yp).isDirectory()) continue;
|
|
11311
|
+
for (const month of import_fs21.default.readdirSync(yp)) {
|
|
11312
|
+
const mp = import_path23.default.join(yp, month);
|
|
10769
11313
|
try {
|
|
10770
|
-
if (!
|
|
10771
|
-
for (const day of
|
|
10772
|
-
const dp =
|
|
11314
|
+
if (!import_fs21.default.statSync(mp).isDirectory()) continue;
|
|
11315
|
+
for (const day of import_fs21.default.readdirSync(mp)) {
|
|
11316
|
+
const dp = import_path23.default.join(mp, day);
|
|
10773
11317
|
try {
|
|
10774
|
-
if (!
|
|
10775
|
-
total +=
|
|
11318
|
+
if (!import_fs21.default.statSync(dp).isDirectory()) continue;
|
|
11319
|
+
total += import_fs21.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
|
|
10776
11320
|
} catch {
|
|
10777
11321
|
continue;
|
|
10778
11322
|
}
|
|
@@ -10808,7 +11352,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
10808
11352
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
10809
11353
|
let raw;
|
|
10810
11354
|
try {
|
|
10811
|
-
raw =
|
|
11355
|
+
raw = import_fs21.default.readFileSync(import_path23.default.join(projPath, file), "utf-8");
|
|
10812
11356
|
} catch {
|
|
10813
11357
|
return;
|
|
10814
11358
|
}
|
|
@@ -10860,7 +11404,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
10860
11404
|
if (block.type !== "tool_result") continue;
|
|
10861
11405
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
10862
11406
|
if (filePath) {
|
|
10863
|
-
const ext =
|
|
11407
|
+
const ext = import_path23.default.extname(filePath).toLowerCase();
|
|
10864
11408
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
10865
11409
|
}
|
|
10866
11410
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -10917,7 +11461,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
10917
11461
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
10918
11462
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
10919
11463
|
const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
10920
|
-
const inputFileExt = inputFilePath ?
|
|
11464
|
+
const inputFileExt = inputFilePath ? import_path23.default.extname(inputFilePath).toLowerCase() : "";
|
|
10921
11465
|
if (CODE_EXTENSIONS.has(inputFileExt)) continue;
|
|
10922
11466
|
const dlpMatch = scanArgs(input);
|
|
10923
11467
|
if (dlpMatch) {
|
|
@@ -11014,19 +11558,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
11014
11558
|
}
|
|
11015
11559
|
}
|
|
11016
11560
|
function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
|
|
11017
|
-
const projPath =
|
|
11561
|
+
const projPath = import_path23.default.join(projectsDir, proj);
|
|
11018
11562
|
try {
|
|
11019
|
-
if (!
|
|
11563
|
+
if (!import_fs21.default.statSync(projPath).isDirectory()) return;
|
|
11020
11564
|
} catch {
|
|
11021
11565
|
return;
|
|
11022
11566
|
}
|
|
11023
|
-
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(
|
|
11567
|
+
const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os20.default.homedir(), "~")).slice(
|
|
11024
11568
|
0,
|
|
11025
11569
|
40
|
|
11026
11570
|
);
|
|
11027
11571
|
let files;
|
|
11028
11572
|
try {
|
|
11029
|
-
files =
|
|
11573
|
+
files = import_fs21.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
11030
11574
|
} catch {
|
|
11031
11575
|
return;
|
|
11032
11576
|
}
|
|
@@ -11060,12 +11604,12 @@ function emptyClaudeScan() {
|
|
|
11060
11604
|
};
|
|
11061
11605
|
}
|
|
11062
11606
|
function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
11063
|
-
const projectsDir =
|
|
11607
|
+
const projectsDir = import_path23.default.join(import_os20.default.homedir(), ".claude", "projects");
|
|
11064
11608
|
const result = emptyClaudeScan();
|
|
11065
|
-
if (!
|
|
11609
|
+
if (!import_fs21.default.existsSync(projectsDir)) return result;
|
|
11066
11610
|
let projDirs;
|
|
11067
11611
|
try {
|
|
11068
|
-
projDirs =
|
|
11612
|
+
projDirs = import_fs21.default.readdirSync(projectsDir);
|
|
11069
11613
|
} catch {
|
|
11070
11614
|
return result;
|
|
11071
11615
|
}
|
|
@@ -11086,7 +11630,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
|
|
|
11086
11630
|
return result;
|
|
11087
11631
|
}
|
|
11088
11632
|
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
11089
|
-
const tmpDir =
|
|
11633
|
+
const tmpDir = import_path23.default.join(import_os20.default.homedir(), ".gemini", "tmp");
|
|
11090
11634
|
const result = {
|
|
11091
11635
|
filesScanned: 0,
|
|
11092
11636
|
sessions: 0,
|
|
@@ -11101,33 +11645,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
11101
11645
|
sessionsWithEarlySecrets: 0
|
|
11102
11646
|
};
|
|
11103
11647
|
const dedup = emptyScanDedup();
|
|
11104
|
-
if (!
|
|
11648
|
+
if (!import_fs21.default.existsSync(tmpDir)) return result;
|
|
11105
11649
|
let slugDirs;
|
|
11106
11650
|
try {
|
|
11107
|
-
slugDirs =
|
|
11651
|
+
slugDirs = import_fs21.default.readdirSync(tmpDir);
|
|
11108
11652
|
} catch {
|
|
11109
11653
|
return result;
|
|
11110
11654
|
}
|
|
11111
11655
|
const ruleSources = buildRuleSources();
|
|
11112
11656
|
for (const slug of slugDirs) {
|
|
11113
|
-
const slugPath =
|
|
11657
|
+
const slugPath = import_path23.default.join(tmpDir, slug);
|
|
11114
11658
|
try {
|
|
11115
|
-
if (!
|
|
11659
|
+
if (!import_fs21.default.statSync(slugPath).isDirectory()) continue;
|
|
11116
11660
|
} catch {
|
|
11117
11661
|
continue;
|
|
11118
11662
|
}
|
|
11119
11663
|
let projLabel = stripTerminalEscapes(slug).slice(0, 40);
|
|
11120
11664
|
try {
|
|
11121
11665
|
projLabel = stripTerminalEscapes(
|
|
11122
|
-
|
|
11123
|
-
).replace(
|
|
11666
|
+
import_fs21.default.readFileSync(import_path23.default.join(slugPath, ".project_root"), "utf-8").trim()
|
|
11667
|
+
).replace(import_os20.default.homedir(), "~").slice(0, 40);
|
|
11124
11668
|
} catch {
|
|
11125
11669
|
}
|
|
11126
|
-
const chatsDir =
|
|
11127
|
-
if (!
|
|
11670
|
+
const chatsDir = import_path23.default.join(slugPath, "chats");
|
|
11671
|
+
if (!import_fs21.default.existsSync(chatsDir)) continue;
|
|
11128
11672
|
let chatFiles;
|
|
11129
11673
|
try {
|
|
11130
|
-
chatFiles =
|
|
11674
|
+
chatFiles = import_fs21.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
11131
11675
|
} catch {
|
|
11132
11676
|
continue;
|
|
11133
11677
|
}
|
|
@@ -11137,7 +11681,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
11137
11681
|
const sessionId = chatFile.replace(/\.json$/, "");
|
|
11138
11682
|
let raw;
|
|
11139
11683
|
try {
|
|
11140
|
-
raw =
|
|
11684
|
+
raw = import_fs21.default.readFileSync(import_path23.default.join(chatsDir, chatFile), "utf-8");
|
|
11141
11685
|
} catch {
|
|
11142
11686
|
continue;
|
|
11143
11687
|
}
|
|
@@ -11299,13 +11843,13 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
11299
11843
|
return result;
|
|
11300
11844
|
}
|
|
11301
11845
|
function antigravityBrainDirs() {
|
|
11302
|
-
return ["antigravity-cli", "antigravity-ide"].map((surface) =>
|
|
11846
|
+
return ["antigravity-cli", "antigravity-ide"].map((surface) => import_path23.default.join(import_os20.default.homedir(), ".gemini", surface, "brain")).filter((p) => import_fs21.default.existsSync(p));
|
|
11303
11847
|
}
|
|
11304
11848
|
function antigravityTranscriptPath(convPath) {
|
|
11305
|
-
const logsDir =
|
|
11849
|
+
const logsDir = import_path23.default.join(convPath, ".system_generated", "logs");
|
|
11306
11850
|
for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
|
|
11307
|
-
const p =
|
|
11308
|
-
if (
|
|
11851
|
+
const p = import_path23.default.join(logsDir, name);
|
|
11852
|
+
if (import_fs21.default.existsSync(p)) return p;
|
|
11309
11853
|
}
|
|
11310
11854
|
return null;
|
|
11311
11855
|
}
|
|
@@ -11331,14 +11875,14 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
11331
11875
|
for (const brainDir of brainDirs) {
|
|
11332
11876
|
let convDirs;
|
|
11333
11877
|
try {
|
|
11334
|
-
convDirs =
|
|
11878
|
+
convDirs = import_fs21.default.readdirSync(brainDir);
|
|
11335
11879
|
} catch {
|
|
11336
11880
|
continue;
|
|
11337
11881
|
}
|
|
11338
11882
|
for (const conv of convDirs) {
|
|
11339
|
-
const convPath =
|
|
11883
|
+
const convPath = import_path23.default.join(brainDir, conv);
|
|
11340
11884
|
try {
|
|
11341
|
-
if (!
|
|
11885
|
+
if (!import_fs21.default.statSync(convPath).isDirectory()) continue;
|
|
11342
11886
|
} catch {
|
|
11343
11887
|
continue;
|
|
11344
11888
|
}
|
|
@@ -11348,7 +11892,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
11348
11892
|
onProgress?.(result.filesScanned);
|
|
11349
11893
|
let raw;
|
|
11350
11894
|
try {
|
|
11351
|
-
raw =
|
|
11895
|
+
raw = import_fs21.default.readFileSync(transcriptFile, "utf-8");
|
|
11352
11896
|
} catch {
|
|
11353
11897
|
continue;
|
|
11354
11898
|
}
|
|
@@ -11405,7 +11949,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
11405
11949
|
result.bashCalls++;
|
|
11406
11950
|
const cwd = String(input.cwd ?? "");
|
|
11407
11951
|
if (cwd && projLabel === conv.slice(0, 8)) {
|
|
11408
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
11952
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os20.default.homedir(), "~").slice(0, 40);
|
|
11409
11953
|
}
|
|
11410
11954
|
}
|
|
11411
11955
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
@@ -11505,7 +12049,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
|
|
|
11505
12049
|
return result;
|
|
11506
12050
|
}
|
|
11507
12051
|
function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
11508
|
-
const sessionDir =
|
|
12052
|
+
const sessionDir = import_path23.default.join(import_os20.default.homedir(), ".copilot", "session-state");
|
|
11509
12053
|
const result = {
|
|
11510
12054
|
filesScanned: 0,
|
|
11511
12055
|
sessions: 0,
|
|
@@ -11521,22 +12065,22 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
11521
12065
|
sessionsWithEarlySecrets: 0
|
|
11522
12066
|
};
|
|
11523
12067
|
const dedup = emptyScanDedup();
|
|
11524
|
-
if (!
|
|
12068
|
+
if (!import_fs21.default.existsSync(sessionDir)) return result;
|
|
11525
12069
|
let sessionIds;
|
|
11526
12070
|
try {
|
|
11527
|
-
sessionIds =
|
|
12071
|
+
sessionIds = import_fs21.default.readdirSync(sessionDir);
|
|
11528
12072
|
} catch {
|
|
11529
12073
|
return result;
|
|
11530
12074
|
}
|
|
11531
12075
|
const ruleSources = buildRuleSources();
|
|
11532
12076
|
for (const sessionId of sessionIds) {
|
|
11533
|
-
const eventsPath =
|
|
11534
|
-
if (!
|
|
12077
|
+
const eventsPath = import_path23.default.join(sessionDir, sessionId, "events.jsonl");
|
|
12078
|
+
if (!import_fs21.default.existsSync(eventsPath)) continue;
|
|
11535
12079
|
result.filesScanned++;
|
|
11536
12080
|
onProgress?.(result.filesScanned);
|
|
11537
12081
|
let raw;
|
|
11538
12082
|
try {
|
|
11539
|
-
raw =
|
|
12083
|
+
raw = import_fs21.default.readFileSync(eventsPath, "utf-8");
|
|
11540
12084
|
} catch {
|
|
11541
12085
|
continue;
|
|
11542
12086
|
}
|
|
@@ -11556,7 +12100,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
11556
12100
|
if (ev.type === "session.start") {
|
|
11557
12101
|
const cwd = ev.data?.context?.cwd;
|
|
11558
12102
|
if (typeof cwd === "string" && cwd) {
|
|
11559
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
12103
|
+
projLabel = stripTerminalEscapes(cwd).replace(import_os20.default.homedir(), "~").slice(0, 40);
|
|
11560
12104
|
}
|
|
11561
12105
|
continue;
|
|
11562
12106
|
}
|
|
@@ -11688,7 +12232,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
|
|
|
11688
12232
|
return result;
|
|
11689
12233
|
}
|
|
11690
12234
|
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
11691
|
-
const sessionsBase =
|
|
12235
|
+
const sessionsBase = import_path23.default.join(import_os20.default.homedir(), ".codex", "sessions");
|
|
11692
12236
|
const result = {
|
|
11693
12237
|
filesScanned: 0,
|
|
11694
12238
|
sessions: 0,
|
|
@@ -11703,32 +12247,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
11703
12247
|
sessionsWithEarlySecrets: 0
|
|
11704
12248
|
};
|
|
11705
12249
|
const dedup = emptyScanDedup();
|
|
11706
|
-
if (!
|
|
12250
|
+
if (!import_fs21.default.existsSync(sessionsBase)) return result;
|
|
11707
12251
|
const jsonlFiles = [];
|
|
11708
12252
|
try {
|
|
11709
|
-
for (const year of
|
|
11710
|
-
const yearPath =
|
|
12253
|
+
for (const year of import_fs21.default.readdirSync(sessionsBase)) {
|
|
12254
|
+
const yearPath = import_path23.default.join(sessionsBase, year);
|
|
11711
12255
|
try {
|
|
11712
|
-
if (!
|
|
12256
|
+
if (!import_fs21.default.statSync(yearPath).isDirectory()) continue;
|
|
11713
12257
|
} catch {
|
|
11714
12258
|
continue;
|
|
11715
12259
|
}
|
|
11716
|
-
for (const month of
|
|
11717
|
-
const monthPath =
|
|
12260
|
+
for (const month of import_fs21.default.readdirSync(yearPath)) {
|
|
12261
|
+
const monthPath = import_path23.default.join(yearPath, month);
|
|
11718
12262
|
try {
|
|
11719
|
-
if (!
|
|
12263
|
+
if (!import_fs21.default.statSync(monthPath).isDirectory()) continue;
|
|
11720
12264
|
} catch {
|
|
11721
12265
|
continue;
|
|
11722
12266
|
}
|
|
11723
|
-
for (const day of
|
|
11724
|
-
const dayPath =
|
|
12267
|
+
for (const day of import_fs21.default.readdirSync(monthPath)) {
|
|
12268
|
+
const dayPath = import_path23.default.join(monthPath, day);
|
|
11725
12269
|
try {
|
|
11726
|
-
if (!
|
|
12270
|
+
if (!import_fs21.default.statSync(dayPath).isDirectory()) continue;
|
|
11727
12271
|
} catch {
|
|
11728
12272
|
continue;
|
|
11729
12273
|
}
|
|
11730
|
-
for (const file of
|
|
11731
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
12274
|
+
for (const file of import_fs21.default.readdirSync(dayPath)) {
|
|
12275
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path23.default.join(dayPath, file));
|
|
11732
12276
|
}
|
|
11733
12277
|
}
|
|
11734
12278
|
}
|
|
@@ -11742,7 +12286,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
11742
12286
|
onProgress?.(result.filesScanned);
|
|
11743
12287
|
let lines;
|
|
11744
12288
|
try {
|
|
11745
|
-
lines =
|
|
12289
|
+
lines = import_fs21.default.readFileSync(filePath, "utf-8").split("\n");
|
|
11746
12290
|
} catch {
|
|
11747
12291
|
continue;
|
|
11748
12292
|
}
|
|
@@ -11768,7 +12312,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
11768
12312
|
sessionId = String(payload["id"] ?? filePath);
|
|
11769
12313
|
startTime = String(payload["timestamp"] ?? "");
|
|
11770
12314
|
const cwd = String(payload["cwd"] ?? "");
|
|
11771
|
-
projLabel = stripTerminalEscapes(cwd.replace(
|
|
12315
|
+
projLabel = stripTerminalEscapes(cwd.replace(import_os20.default.homedir(), "~")).slice(0, 40);
|
|
11772
12316
|
continue;
|
|
11773
12317
|
}
|
|
11774
12318
|
if (entry.type === "event_msg" && payload["type"] === "token_count") {
|
|
@@ -11921,17 +12465,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
11921
12465
|
return result;
|
|
11922
12466
|
}
|
|
11923
12467
|
function scanShellConfig() {
|
|
11924
|
-
const home =
|
|
12468
|
+
const home = import_os20.default.homedir();
|
|
11925
12469
|
const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
|
|
11926
|
-
(f) =>
|
|
12470
|
+
(f) => import_path23.default.join(home, f)
|
|
11927
12471
|
);
|
|
11928
12472
|
const findings = [];
|
|
11929
12473
|
const seen = /* @__PURE__ */ new Set();
|
|
11930
12474
|
for (const filePath of configFiles) {
|
|
11931
|
-
if (!
|
|
12475
|
+
if (!import_fs21.default.existsSync(filePath)) continue;
|
|
11932
12476
|
let lines;
|
|
11933
12477
|
try {
|
|
11934
|
-
lines =
|
|
12478
|
+
lines = import_fs21.default.readFileSync(filePath, "utf-8").split("\n");
|
|
11935
12479
|
} catch {
|
|
11936
12480
|
continue;
|
|
11937
12481
|
}
|
|
@@ -12737,7 +13281,7 @@ function registerScanCommand(program2) {
|
|
|
12737
13281
|
if (!drillDown) {
|
|
12738
13282
|
const useInk2 = !options.classic;
|
|
12739
13283
|
if (useInk2) {
|
|
12740
|
-
const scanInkPath =
|
|
13284
|
+
const scanInkPath = import_path23.default.join(__dirname, "scan-ink.mjs");
|
|
12741
13285
|
const dynamicImport = new Function("id", "return import(id)");
|
|
12742
13286
|
const mod = await dynamicImport(`file://${scanInkPath}`);
|
|
12743
13287
|
const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
|
|
@@ -12962,14 +13506,14 @@ function registerScanCommand(program2) {
|
|
|
12962
13506
|
}
|
|
12963
13507
|
);
|
|
12964
13508
|
}
|
|
12965
|
-
var import_chalk5,
|
|
13509
|
+
var import_chalk5, import_fs21, import_path23, import_os20, import_string_width2, CLAUDE_PRICING, GEMINI_PRICING, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, FIXTURE_TOKEN_PATTERNS, TERMINAL_ESCAPE_RE2, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
|
|
12966
13510
|
var init_scan = __esm({
|
|
12967
13511
|
"src/cli/commands/scan.ts"() {
|
|
12968
13512
|
"use strict";
|
|
12969
13513
|
import_chalk5 = __toESM(require("chalk"));
|
|
12970
|
-
|
|
12971
|
-
|
|
12972
|
-
|
|
13514
|
+
import_fs21 = __toESM(require("fs"));
|
|
13515
|
+
import_path23 = __toESM(require("path"));
|
|
13516
|
+
import_os20 = __toESM(require("os"));
|
|
12973
13517
|
init_shields();
|
|
12974
13518
|
init_config();
|
|
12975
13519
|
init_policy();
|
|
@@ -13163,12 +13707,12 @@ var init_suggestion_tracker = __esm({
|
|
|
13163
13707
|
});
|
|
13164
13708
|
|
|
13165
13709
|
// src/daemon/taint-store.ts
|
|
13166
|
-
var
|
|
13710
|
+
var import_fs22, import_path24, DEFAULT_TTL_MS, TaintStore;
|
|
13167
13711
|
var init_taint_store = __esm({
|
|
13168
13712
|
"src/daemon/taint-store.ts"() {
|
|
13169
13713
|
"use strict";
|
|
13170
|
-
|
|
13171
|
-
|
|
13714
|
+
import_fs22 = __toESM(require("fs"));
|
|
13715
|
+
import_path24 = __toESM(require("path"));
|
|
13172
13716
|
DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
13173
13717
|
TaintStore = class {
|
|
13174
13718
|
records = /* @__PURE__ */ new Map();
|
|
@@ -13233,9 +13777,9 @@ var init_taint_store = __esm({
|
|
|
13233
13777
|
/** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
|
|
13234
13778
|
_resolve(filePath) {
|
|
13235
13779
|
try {
|
|
13236
|
-
return
|
|
13780
|
+
return import_fs22.default.realpathSync.native(import_path24.default.resolve(filePath));
|
|
13237
13781
|
} catch {
|
|
13238
|
-
return
|
|
13782
|
+
return import_path24.default.resolve(filePath);
|
|
13239
13783
|
}
|
|
13240
13784
|
}
|
|
13241
13785
|
};
|
|
@@ -13353,8 +13897,8 @@ var init_session_history = __esm({
|
|
|
13353
13897
|
// src/daemon/state.ts
|
|
13354
13898
|
function loadInsightCounts() {
|
|
13355
13899
|
try {
|
|
13356
|
-
if (!
|
|
13357
|
-
const data = JSON.parse(
|
|
13900
|
+
if (!import_fs23.default.existsSync(INSIGHT_COUNTS_FILE)) return;
|
|
13901
|
+
const data = JSON.parse(import_fs23.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
|
|
13358
13902
|
for (const [tool, count] of Object.entries(data)) {
|
|
13359
13903
|
if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
|
|
13360
13904
|
}
|
|
@@ -13393,23 +13937,23 @@ function markRejectionHandlerRegistered() {
|
|
|
13393
13937
|
daemonRejectionHandlerRegistered = true;
|
|
13394
13938
|
}
|
|
13395
13939
|
function atomicWriteSync2(filePath, data, options) {
|
|
13396
|
-
const dir =
|
|
13397
|
-
if (!
|
|
13940
|
+
const dir = import_path25.default.dirname(filePath);
|
|
13941
|
+
if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
|
|
13398
13942
|
const tmpPath = `${filePath}.${(0, import_crypto8.randomUUID)()}.tmp`;
|
|
13399
13943
|
try {
|
|
13400
|
-
|
|
13944
|
+
import_fs23.default.writeFileSync(tmpPath, data, options);
|
|
13401
13945
|
} catch (err2) {
|
|
13402
13946
|
try {
|
|
13403
|
-
|
|
13947
|
+
import_fs23.default.unlinkSync(tmpPath);
|
|
13404
13948
|
} catch {
|
|
13405
13949
|
}
|
|
13406
13950
|
throw err2;
|
|
13407
13951
|
}
|
|
13408
13952
|
try {
|
|
13409
|
-
|
|
13953
|
+
import_fs23.default.renameSync(tmpPath, filePath);
|
|
13410
13954
|
} catch (err2) {
|
|
13411
13955
|
try {
|
|
13412
|
-
|
|
13956
|
+
import_fs23.default.unlinkSync(tmpPath);
|
|
13413
13957
|
} catch {
|
|
13414
13958
|
}
|
|
13415
13959
|
throw err2;
|
|
@@ -13433,16 +13977,16 @@ function appendAuditLog(data) {
|
|
|
13433
13977
|
decision: data.decision,
|
|
13434
13978
|
source: "daemon"
|
|
13435
13979
|
};
|
|
13436
|
-
const dir =
|
|
13437
|
-
if (!
|
|
13438
|
-
|
|
13980
|
+
const dir = import_path25.default.dirname(AUDIT_LOG_FILE);
|
|
13981
|
+
if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
|
|
13982
|
+
import_fs23.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
13439
13983
|
} catch {
|
|
13440
13984
|
}
|
|
13441
13985
|
}
|
|
13442
13986
|
function getAuditHistory(limit = 20) {
|
|
13443
13987
|
try {
|
|
13444
|
-
if (!
|
|
13445
|
-
const lines =
|
|
13988
|
+
if (!import_fs23.default.existsSync(AUDIT_LOG_FILE)) return [];
|
|
13989
|
+
const lines = import_fs23.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
|
|
13446
13990
|
if (lines.length === 1 && lines[0] === "") return [];
|
|
13447
13991
|
return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
|
|
13448
13992
|
} catch {
|
|
@@ -13451,7 +13995,7 @@ function getAuditHistory(limit = 20) {
|
|
|
13451
13995
|
}
|
|
13452
13996
|
function getOrgName() {
|
|
13453
13997
|
try {
|
|
13454
|
-
if (
|
|
13998
|
+
if (import_fs23.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
|
|
13455
13999
|
} catch {
|
|
13456
14000
|
}
|
|
13457
14001
|
return null;
|
|
@@ -13459,8 +14003,8 @@ function getOrgName() {
|
|
|
13459
14003
|
function writeGlobalSetting(key, value) {
|
|
13460
14004
|
let config = {};
|
|
13461
14005
|
try {
|
|
13462
|
-
if (
|
|
13463
|
-
config = JSON.parse(
|
|
14006
|
+
if (import_fs23.default.existsSync(GLOBAL_CONFIG_FILE)) {
|
|
14007
|
+
config = JSON.parse(import_fs23.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
|
|
13464
14008
|
}
|
|
13465
14009
|
} catch {
|
|
13466
14010
|
}
|
|
@@ -13472,8 +14016,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
13472
14016
|
try {
|
|
13473
14017
|
let trust = { entries: [] };
|
|
13474
14018
|
try {
|
|
13475
|
-
if (
|
|
13476
|
-
trust = JSON.parse(
|
|
14019
|
+
if (import_fs23.default.existsSync(TRUST_FILE2))
|
|
14020
|
+
trust = JSON.parse(import_fs23.default.readFileSync(TRUST_FILE2, "utf-8"));
|
|
13477
14021
|
} catch {
|
|
13478
14022
|
}
|
|
13479
14023
|
trust.entries = trust.entries.filter(
|
|
@@ -13490,8 +14034,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
|
|
|
13490
14034
|
}
|
|
13491
14035
|
function readPersistentDecisions() {
|
|
13492
14036
|
try {
|
|
13493
|
-
if (
|
|
13494
|
-
return JSON.parse(
|
|
14037
|
+
if (import_fs23.default.existsSync(DECISIONS_FILE)) {
|
|
14038
|
+
return JSON.parse(import_fs23.default.readFileSync(DECISIONS_FILE, "utf-8"));
|
|
13495
14039
|
}
|
|
13496
14040
|
} catch {
|
|
13497
14041
|
}
|
|
@@ -13519,7 +14063,7 @@ function estimateToolCost(tool, args) {
|
|
|
13519
14063
|
const filePath = a.file_path ?? a.path;
|
|
13520
14064
|
if (filePath) {
|
|
13521
14065
|
try {
|
|
13522
|
-
const bytes =
|
|
14066
|
+
const bytes = import_fs23.default.statSync(filePath).size;
|
|
13523
14067
|
return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
|
|
13524
14068
|
} catch {
|
|
13525
14069
|
}
|
|
@@ -13590,7 +14134,7 @@ function abandonPending() {
|
|
|
13590
14134
|
});
|
|
13591
14135
|
if (autoStarted) {
|
|
13592
14136
|
try {
|
|
13593
|
-
|
|
14137
|
+
import_fs23.default.unlinkSync(DAEMON_PID_FILE);
|
|
13594
14138
|
} catch {
|
|
13595
14139
|
}
|
|
13596
14140
|
setTimeout(() => {
|
|
@@ -13601,8 +14145,8 @@ function abandonPending() {
|
|
|
13601
14145
|
}
|
|
13602
14146
|
function logActivitySocket(msg) {
|
|
13603
14147
|
try {
|
|
13604
|
-
|
|
13605
|
-
|
|
14148
|
+
import_fs23.default.appendFileSync(
|
|
14149
|
+
import_path25.default.join(homeDir, ".node9", "hook-debug.log"),
|
|
13606
14150
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
|
|
13607
14151
|
`
|
|
13608
14152
|
);
|
|
@@ -13624,13 +14168,13 @@ function shouldRebind(now = Date.now()) {
|
|
|
13624
14168
|
function startActivitySocket() {
|
|
13625
14169
|
bindActivitySocket();
|
|
13626
14170
|
activityHealthInterval = setInterval(() => {
|
|
13627
|
-
if (!
|
|
14171
|
+
if (!import_fs23.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
|
|
13628
14172
|
}, ACTIVITY_HEALTH_PROBE_MS);
|
|
13629
14173
|
activityHealthInterval.unref();
|
|
13630
14174
|
process.on("exit", () => {
|
|
13631
14175
|
if (activityHealthInterval) clearInterval(activityHealthInterval);
|
|
13632
14176
|
try {
|
|
13633
|
-
|
|
14177
|
+
import_fs23.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
13634
14178
|
} catch {
|
|
13635
14179
|
}
|
|
13636
14180
|
});
|
|
@@ -13658,7 +14202,7 @@ function attemptRebind(reason) {
|
|
|
13658
14202
|
}
|
|
13659
14203
|
function bindActivitySocket() {
|
|
13660
14204
|
try {
|
|
13661
|
-
|
|
14205
|
+
import_fs23.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
|
|
13662
14206
|
} catch {
|
|
13663
14207
|
}
|
|
13664
14208
|
const ACTIVITY_MAX_BYTES = 1024 * 1024;
|
|
@@ -13762,28 +14306,28 @@ function bindActivitySocket() {
|
|
|
13762
14306
|
});
|
|
13763
14307
|
activitySocketServer = unixServer;
|
|
13764
14308
|
}
|
|
13765
|
-
var import_net2,
|
|
14309
|
+
var import_net2, import_fs23, import_path25, import_os21, import_crypto8, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, 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;
|
|
13766
14310
|
var init_state2 = __esm({
|
|
13767
14311
|
"src/daemon/state.ts"() {
|
|
13768
14312
|
"use strict";
|
|
13769
14313
|
import_net2 = __toESM(require("net"));
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
14314
|
+
import_fs23 = __toESM(require("fs"));
|
|
14315
|
+
import_path25 = __toESM(require("path"));
|
|
14316
|
+
import_os21 = __toESM(require("os"));
|
|
13773
14317
|
import_crypto8 = require("crypto");
|
|
13774
14318
|
init_daemon();
|
|
13775
14319
|
init_suggestion_tracker();
|
|
13776
14320
|
init_taint_store();
|
|
13777
14321
|
init_session_counters();
|
|
13778
14322
|
init_session_history();
|
|
13779
|
-
homeDir =
|
|
13780
|
-
DAEMON_PID_FILE =
|
|
13781
|
-
DECISIONS_FILE =
|
|
13782
|
-
AUDIT_LOG_FILE =
|
|
13783
|
-
TRUST_FILE2 =
|
|
13784
|
-
GLOBAL_CONFIG_FILE =
|
|
13785
|
-
CREDENTIALS_FILE =
|
|
13786
|
-
INSIGHT_COUNTS_FILE =
|
|
14323
|
+
homeDir = import_os21.default.homedir();
|
|
14324
|
+
DAEMON_PID_FILE = import_path25.default.join(homeDir, ".node9", "daemon.pid");
|
|
14325
|
+
DECISIONS_FILE = import_path25.default.join(homeDir, ".node9", "decisions.json");
|
|
14326
|
+
AUDIT_LOG_FILE = import_path25.default.join(homeDir, ".node9", "audit.log");
|
|
14327
|
+
TRUST_FILE2 = import_path25.default.join(homeDir, ".node9", "trust.json");
|
|
14328
|
+
GLOBAL_CONFIG_FILE = import_path25.default.join(homeDir, ".node9", "config.json");
|
|
14329
|
+
CREDENTIALS_FILE = import_path25.default.join(homeDir, ".node9", "credentials.json");
|
|
14330
|
+
INSIGHT_COUNTS_FILE = import_path25.default.join(homeDir, ".node9", "insight-counts.json");
|
|
13787
14331
|
pending = /* @__PURE__ */ new Map();
|
|
13788
14332
|
sseClients = /* @__PURE__ */ new Set();
|
|
13789
14333
|
suggestionTracker = new SuggestionTracker(3);
|
|
@@ -13800,7 +14344,7 @@ var init_state2 = __esm({
|
|
|
13800
14344
|
"2h": 2 * 60 * 6e4
|
|
13801
14345
|
};
|
|
13802
14346
|
autoStarted = process.env.NODE9_AUTO_STARTED === "1";
|
|
13803
|
-
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
14347
|
+
ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path25.default.join(import_os21.default.tmpdir(), "node9-activity.sock");
|
|
13804
14348
|
ACTIVITY_RING_SIZE = 100;
|
|
13805
14349
|
activityRing = [];
|
|
13806
14350
|
LARGE_RESPONSE_RING_SIZE = 20;
|
|
@@ -13878,8 +14422,8 @@ function readCredentials() {
|
|
|
13878
14422
|
};
|
|
13879
14423
|
}
|
|
13880
14424
|
try {
|
|
13881
|
-
const credPath =
|
|
13882
|
-
const creds = JSON.parse(
|
|
14425
|
+
const credPath = import_path26.default.join(import_os22.default.homedir(), ".node9", "credentials.json");
|
|
14426
|
+
const creds = JSON.parse(import_fs24.default.readFileSync(credPath, "utf-8"));
|
|
13883
14427
|
const profileName = process.env.NODE9_PROFILE ?? "default";
|
|
13884
14428
|
const profile = creds[profileName];
|
|
13885
14429
|
if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
|
|
@@ -13905,7 +14449,7 @@ function readCredentials() {
|
|
|
13905
14449
|
}
|
|
13906
14450
|
function readCachedEtag() {
|
|
13907
14451
|
try {
|
|
13908
|
-
const raw = JSON.parse(
|
|
14452
|
+
const raw = JSON.parse(import_fs24.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
13909
14453
|
return typeof raw.etag === "string" ? raw.etag : void 0;
|
|
13910
14454
|
} catch {
|
|
13911
14455
|
return void 0;
|
|
@@ -13966,9 +14510,9 @@ function extractRules(body) {
|
|
|
13966
14510
|
return [];
|
|
13967
14511
|
}
|
|
13968
14512
|
function writeCache2(cache) {
|
|
13969
|
-
const dir =
|
|
13970
|
-
if (!
|
|
13971
|
-
|
|
14513
|
+
const dir = import_path26.default.dirname(rulesCacheFile());
|
|
14514
|
+
if (!import_fs24.default.existsSync(dir)) import_fs24.default.mkdirSync(dir, { recursive: true });
|
|
14515
|
+
import_fs24.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
13972
14516
|
}
|
|
13973
14517
|
async function syncOnce() {
|
|
13974
14518
|
const creds = readCredentials();
|
|
@@ -14125,7 +14669,7 @@ async function runCloudSync() {
|
|
|
14125
14669
|
}
|
|
14126
14670
|
function getCloudSyncStatus() {
|
|
14127
14671
|
try {
|
|
14128
|
-
const raw = JSON.parse(
|
|
14672
|
+
const raw = JSON.parse(import_fs24.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
14129
14673
|
if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
|
|
14130
14674
|
return {
|
|
14131
14675
|
cached: true,
|
|
@@ -14142,7 +14686,7 @@ function getCloudSyncStatus() {
|
|
|
14142
14686
|
}
|
|
14143
14687
|
function getCloudRules() {
|
|
14144
14688
|
try {
|
|
14145
|
-
const raw = JSON.parse(
|
|
14689
|
+
const raw = JSON.parse(import_fs24.default.readFileSync(rulesCacheFile(), "utf-8"));
|
|
14146
14690
|
return Array.isArray(raw.rules) ? raw.rules : null;
|
|
14147
14691
|
} catch {
|
|
14148
14692
|
return null;
|
|
@@ -14176,14 +14720,14 @@ function startForensicBroadcast() {
|
|
|
14176
14720
|
const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
|
|
14177
14721
|
recurring.unref();
|
|
14178
14722
|
}
|
|
14179
|
-
var
|
|
14723
|
+
var import_fs24, import_https2, import_os22, import_path26, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
|
|
14180
14724
|
var init_sync = __esm({
|
|
14181
14725
|
"src/daemon/sync.ts"() {
|
|
14182
14726
|
"use strict";
|
|
14183
|
-
|
|
14727
|
+
import_fs24 = __toESM(require("fs"));
|
|
14184
14728
|
import_https2 = __toESM(require("https"));
|
|
14185
|
-
|
|
14186
|
-
|
|
14729
|
+
import_os22 = __toESM(require("os"));
|
|
14730
|
+
import_path26 = __toESM(require("path"));
|
|
14187
14731
|
init_config();
|
|
14188
14732
|
init_blast();
|
|
14189
14733
|
init_dist();
|
|
@@ -14202,7 +14746,7 @@ var init_sync = __esm({
|
|
|
14202
14746
|
loop: "loops",
|
|
14203
14747
|
"long-output-redacted": "longOutputRedactions"
|
|
14204
14748
|
};
|
|
14205
|
-
rulesCacheFile = () =>
|
|
14749
|
+
rulesCacheFile = () => import_path26.default.join(import_os22.default.homedir(), ".node9", "rules-cache.json");
|
|
14206
14750
|
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
|
|
14207
14751
|
DEFAULT_INTERVAL_HOURS = 5;
|
|
14208
14752
|
MIN_INTERVAL_HOURS = 1;
|
|
@@ -14216,6 +14760,7 @@ var init_sync = __esm({
|
|
|
14216
14760
|
var audit_shipper_exports = {};
|
|
14217
14761
|
__export(audit_shipper_exports, {
|
|
14218
14762
|
AUDIT_SHIP_WATERMARK: () => AUDIT_SHIP_WATERMARK,
|
|
14763
|
+
buildBatchEndpoint: () => buildBatchEndpoint,
|
|
14219
14764
|
buildWireRows: () => buildWireRows,
|
|
14220
14765
|
fileSignature: () => fileSignature,
|
|
14221
14766
|
readWatermark: () => readWatermark,
|
|
@@ -14225,21 +14770,21 @@ __export(audit_shipper_exports, {
|
|
|
14225
14770
|
writeWatermark: () => writeWatermark
|
|
14226
14771
|
});
|
|
14227
14772
|
function fileSignature(filePath) {
|
|
14228
|
-
const fd =
|
|
14773
|
+
const fd = import_fs25.default.openSync(filePath, "r");
|
|
14229
14774
|
try {
|
|
14230
14775
|
const buf = Buffer.alloc(512);
|
|
14231
|
-
const read =
|
|
14776
|
+
const read = import_fs25.default.readSync(fd, buf, 0, 512, 0);
|
|
14232
14777
|
const slice = buf.subarray(0, read);
|
|
14233
14778
|
const nl = slice.indexOf(10);
|
|
14234
14779
|
const firstLine = nl === -1 ? slice : slice.subarray(0, nl);
|
|
14235
14780
|
return import_crypto9.default.createHash("sha256").update(firstLine).digest("hex").slice(0, 16);
|
|
14236
14781
|
} finally {
|
|
14237
|
-
|
|
14782
|
+
import_fs25.default.closeSync(fd);
|
|
14238
14783
|
}
|
|
14239
14784
|
}
|
|
14240
14785
|
function readWatermark(watermarkPath) {
|
|
14241
14786
|
try {
|
|
14242
|
-
const raw = JSON.parse(
|
|
14787
|
+
const raw = JSON.parse(import_fs25.default.readFileSync(watermarkPath, "utf-8"));
|
|
14243
14788
|
if (typeof raw.fileSig === "string" && typeof raw.offset === "number" && raw.offset >= 0)
|
|
14244
14789
|
return raw;
|
|
14245
14790
|
} catch {
|
|
@@ -14248,8 +14793,8 @@ function readWatermark(watermarkPath) {
|
|
|
14248
14793
|
}
|
|
14249
14794
|
function writeWatermark(watermarkPath, wm) {
|
|
14250
14795
|
const tmp = `${watermarkPath}.tmp`;
|
|
14251
|
-
|
|
14252
|
-
|
|
14796
|
+
import_fs25.default.writeFileSync(tmp, JSON.stringify(wm));
|
|
14797
|
+
import_fs25.default.renameSync(tmp, watermarkPath);
|
|
14253
14798
|
}
|
|
14254
14799
|
function buildWireRows(chunk) {
|
|
14255
14800
|
const lastNl = chunk.lastIndexOf(10);
|
|
@@ -14293,6 +14838,12 @@ function buildWireRows(chunk) {
|
|
|
14293
14838
|
}
|
|
14294
14839
|
return { rows, consumed: lastNl + 1 };
|
|
14295
14840
|
}
|
|
14841
|
+
function buildBatchEndpoint(rawApiUrl) {
|
|
14842
|
+
const validated = validateApiUrl(rawApiUrl);
|
|
14843
|
+
if (!validated) return null;
|
|
14844
|
+
const base = validated.toString().replace(/\/$/, "").replace(/\/policies\/sync$/, "");
|
|
14845
|
+
return `${base}/audit/batch`;
|
|
14846
|
+
}
|
|
14296
14847
|
async function shipOnce(deps = {}) {
|
|
14297
14848
|
const auditLogPath = deps.auditLogPath ?? LOCAL_AUDIT_LOG;
|
|
14298
14849
|
const watermarkPath = deps.watermarkPath ?? AUDIT_SHIP_WATERMARK;
|
|
@@ -14309,14 +14860,13 @@ async function shipOnce(deps = {}) {
|
|
|
14309
14860
|
if (!cloudEnabled) return { status: "disabled", shipped: 0 };
|
|
14310
14861
|
const creds = deps.creds !== void 0 ? deps.creds : readCredentials();
|
|
14311
14862
|
if (!creds?.apiKey) return { status: "no-creds", shipped: 0 };
|
|
14312
|
-
const
|
|
14313
|
-
if (!
|
|
14314
|
-
|
|
14315
|
-
if (!import_fs24.default.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
|
|
14863
|
+
const endpoint = buildBatchEndpoint(creds.apiUrl);
|
|
14864
|
+
if (!endpoint) return { status: "no-creds", shipped: 0 };
|
|
14865
|
+
if (!import_fs25.default.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
|
|
14316
14866
|
let shipped = 0;
|
|
14317
14867
|
try {
|
|
14318
14868
|
for (let chunkN = 0; chunkN < MAX_CHUNKS_PER_TICK; chunkN++) {
|
|
14319
|
-
const size =
|
|
14869
|
+
const size = import_fs25.default.statSync(auditLogPath).size;
|
|
14320
14870
|
if (size === 0) break;
|
|
14321
14871
|
const sig = fileSignature(auditLogPath);
|
|
14322
14872
|
const wm = readWatermark(watermarkPath);
|
|
@@ -14324,12 +14874,12 @@ async function shipOnce(deps = {}) {
|
|
|
14324
14874
|
if (offset >= size) break;
|
|
14325
14875
|
const toRead = Math.min(size - offset, MAX_CHUNK_BYTES);
|
|
14326
14876
|
const buf = Buffer.alloc(toRead);
|
|
14327
|
-
const fd =
|
|
14877
|
+
const fd = import_fs25.default.openSync(auditLogPath, "r");
|
|
14328
14878
|
let read;
|
|
14329
14879
|
try {
|
|
14330
|
-
read =
|
|
14880
|
+
read = import_fs25.default.readSync(fd, buf, 0, toRead, offset);
|
|
14331
14881
|
} finally {
|
|
14332
|
-
|
|
14882
|
+
import_fs25.default.closeSync(fd);
|
|
14333
14883
|
}
|
|
14334
14884
|
const { rows, consumed } = buildWireRows(buf.subarray(0, read));
|
|
14335
14885
|
if (consumed === 0) break;
|
|
@@ -14376,8 +14926,8 @@ async function shipOnce(deps = {}) {
|
|
|
14376
14926
|
}
|
|
14377
14927
|
function shipLagBytes(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHIP_WATERMARK) {
|
|
14378
14928
|
try {
|
|
14379
|
-
if (!
|
|
14380
|
-
const size =
|
|
14929
|
+
if (!import_fs25.default.existsSync(auditLogPath)) return 0;
|
|
14930
|
+
const size = import_fs25.default.statSync(auditLogPath).size;
|
|
14381
14931
|
const wm = readWatermark(watermarkPath);
|
|
14382
14932
|
if (!wm) return size;
|
|
14383
14933
|
if (wm.fileSig !== fileSignature(auditLogPath)) return size;
|
|
@@ -14400,19 +14950,19 @@ function startAuditShipper() {
|
|
|
14400
14950
|
setTimeout(() => void shipOnce(), 3e3);
|
|
14401
14951
|
setInterval(() => void shipOnce(), intervalMs);
|
|
14402
14952
|
}
|
|
14403
|
-
var
|
|
14953
|
+
var import_fs25, import_path27, import_os23, import_crypto9, AUDIT_SHIP_WATERMARK, DEFAULT_INTERVAL_MS, MAX_BATCH, MAX_CHUNK_BYTES, MAX_CHUNKS_PER_TICK, FETCH_TIMEOUT_MS, SKIP_CHECKED_BY, shipperStarted;
|
|
14404
14954
|
var init_audit_shipper = __esm({
|
|
14405
14955
|
"src/daemon/audit-shipper.ts"() {
|
|
14406
14956
|
"use strict";
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14957
|
+
import_fs25 = __toESM(require("fs"));
|
|
14958
|
+
import_path27 = __toESM(require("path"));
|
|
14959
|
+
import_os23 = __toESM(require("os"));
|
|
14410
14960
|
import_crypto9 = __toESM(require("crypto"));
|
|
14411
14961
|
init_audit();
|
|
14412
14962
|
init_config();
|
|
14413
14963
|
init_sync();
|
|
14414
14964
|
init_cloud();
|
|
14415
|
-
AUDIT_SHIP_WATERMARK =
|
|
14965
|
+
AUDIT_SHIP_WATERMARK = import_path27.default.join(import_os23.default.homedir(), ".node9", "audit-ship.json");
|
|
14416
14966
|
DEFAULT_INTERVAL_MS = 2e4;
|
|
14417
14967
|
MAX_BATCH = 500;
|
|
14418
14968
|
MAX_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
@@ -14426,68 +14976,68 @@ var init_audit_shipper = __esm({
|
|
|
14426
14976
|
// src/daemon/dlp-scanner.ts
|
|
14427
14977
|
function loadIndex() {
|
|
14428
14978
|
try {
|
|
14429
|
-
return JSON.parse(
|
|
14979
|
+
return JSON.parse(import_fs26.default.readFileSync(INDEX_FILE, "utf-8"));
|
|
14430
14980
|
} catch {
|
|
14431
14981
|
return {};
|
|
14432
14982
|
}
|
|
14433
14983
|
}
|
|
14434
14984
|
function saveIndex(index) {
|
|
14435
14985
|
try {
|
|
14436
|
-
|
|
14986
|
+
import_fs26.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
|
|
14437
14987
|
} catch {
|
|
14438
14988
|
}
|
|
14439
14989
|
}
|
|
14440
14990
|
function appendAuditEntry(entry) {
|
|
14441
14991
|
try {
|
|
14442
|
-
|
|
14992
|
+
import_fs26.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
|
|
14443
14993
|
} catch {
|
|
14444
14994
|
}
|
|
14445
14995
|
}
|
|
14446
14996
|
function runDlpScan() {
|
|
14447
|
-
if (!
|
|
14997
|
+
if (!import_fs26.default.existsSync(PROJECTS_DIR2)) return;
|
|
14448
14998
|
const index = loadIndex();
|
|
14449
14999
|
let updated = false;
|
|
14450
15000
|
let projDirs;
|
|
14451
15001
|
try {
|
|
14452
|
-
projDirs =
|
|
15002
|
+
projDirs = import_fs26.default.readdirSync(PROJECTS_DIR2);
|
|
14453
15003
|
} catch {
|
|
14454
15004
|
return;
|
|
14455
15005
|
}
|
|
14456
15006
|
for (const proj of projDirs) {
|
|
14457
|
-
const projPath =
|
|
15007
|
+
const projPath = import_path28.default.join(PROJECTS_DIR2, proj);
|
|
14458
15008
|
try {
|
|
14459
|
-
if (!
|
|
14460
|
-
const real =
|
|
14461
|
-
if (!real.startsWith(PROJECTS_DIR2 +
|
|
15009
|
+
if (!import_fs26.default.lstatSync(projPath).isDirectory()) continue;
|
|
15010
|
+
const real = import_fs26.default.realpathSync(projPath);
|
|
15011
|
+
if (!real.startsWith(PROJECTS_DIR2 + import_path28.default.sep) && real !== PROJECTS_DIR2) continue;
|
|
14462
15012
|
} catch {
|
|
14463
15013
|
continue;
|
|
14464
15014
|
}
|
|
14465
15015
|
let files;
|
|
14466
15016
|
try {
|
|
14467
|
-
files =
|
|
15017
|
+
files = import_fs26.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
14468
15018
|
} catch {
|
|
14469
15019
|
continue;
|
|
14470
15020
|
}
|
|
14471
15021
|
for (const file of files) {
|
|
14472
|
-
const filePath =
|
|
15022
|
+
const filePath = import_path28.default.join(projPath, file);
|
|
14473
15023
|
const lastOffset = index[filePath] ?? 0;
|
|
14474
15024
|
let size;
|
|
14475
15025
|
try {
|
|
14476
|
-
size =
|
|
15026
|
+
size = import_fs26.default.statSync(filePath).size;
|
|
14477
15027
|
} catch {
|
|
14478
15028
|
continue;
|
|
14479
15029
|
}
|
|
14480
15030
|
if (size <= lastOffset) continue;
|
|
14481
15031
|
let fd;
|
|
14482
15032
|
try {
|
|
14483
|
-
fd =
|
|
15033
|
+
fd = import_fs26.default.openSync(filePath, "r");
|
|
14484
15034
|
} catch {
|
|
14485
15035
|
continue;
|
|
14486
15036
|
}
|
|
14487
15037
|
try {
|
|
14488
15038
|
const chunkSize = size - lastOffset;
|
|
14489
15039
|
const buf = Buffer.alloc(chunkSize);
|
|
14490
|
-
|
|
15040
|
+
import_fs26.default.readSync(fd, buf, 0, chunkSize, lastOffset);
|
|
14491
15041
|
const chunk = buf.toString("utf-8");
|
|
14492
15042
|
for (const line of chunk.split("\n")) {
|
|
14493
15043
|
if (!line.trim()) continue;
|
|
@@ -14507,7 +15057,7 @@ function runDlpScan() {
|
|
|
14507
15057
|
if (typeof text !== "string") continue;
|
|
14508
15058
|
const match = scanText(text);
|
|
14509
15059
|
if (!match) continue;
|
|
14510
|
-
const projLabel = decodeURIComponent(proj).replace(
|
|
15060
|
+
const projLabel = decodeURIComponent(proj).replace(import_os24.default.homedir(), "~").slice(0, 40);
|
|
14511
15061
|
const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
14512
15062
|
appendAuditEntry({
|
|
14513
15063
|
ts,
|
|
@@ -14532,7 +15082,7 @@ Run: node9 report --period 30d`
|
|
|
14532
15082
|
updated = true;
|
|
14533
15083
|
} finally {
|
|
14534
15084
|
try {
|
|
14535
|
-
|
|
15085
|
+
import_fs26.default.closeSync(fd);
|
|
14536
15086
|
} catch {
|
|
14537
15087
|
}
|
|
14538
15088
|
}
|
|
@@ -14558,30 +15108,30 @@ function startDlpScanner() {
|
|
|
14558
15108
|
);
|
|
14559
15109
|
timer.unref();
|
|
14560
15110
|
}
|
|
14561
|
-
var
|
|
15111
|
+
var import_fs26, import_path28, import_os24, INDEX_FILE, PROJECTS_DIR2;
|
|
14562
15112
|
var init_dlp_scanner = __esm({
|
|
14563
15113
|
"src/daemon/dlp-scanner.ts"() {
|
|
14564
15114
|
"use strict";
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
15115
|
+
import_fs26 = __toESM(require("fs"));
|
|
15116
|
+
import_path28 = __toESM(require("path"));
|
|
15117
|
+
import_os24 = __toESM(require("os"));
|
|
14568
15118
|
init_dlp();
|
|
14569
15119
|
init_native();
|
|
14570
15120
|
init_state2();
|
|
14571
|
-
INDEX_FILE =
|
|
14572
|
-
PROJECTS_DIR2 =
|
|
15121
|
+
INDEX_FILE = import_path28.default.join(import_os24.default.homedir(), ".node9", "dlp-index.json");
|
|
15122
|
+
PROJECTS_DIR2 = import_path28.default.join(import_os24.default.homedir(), ".claude", "projects");
|
|
14573
15123
|
}
|
|
14574
15124
|
});
|
|
14575
15125
|
|
|
14576
15126
|
// src/daemon/mcp-tools.ts
|
|
14577
15127
|
function getMcpToolsFile() {
|
|
14578
|
-
return
|
|
15128
|
+
return import_path29.default.join(import_os25.default.homedir(), ".node9", "mcp-tools.json");
|
|
14579
15129
|
}
|
|
14580
15130
|
function readMcpToolsConfig() {
|
|
14581
15131
|
try {
|
|
14582
15132
|
const file = getMcpToolsFile();
|
|
14583
|
-
if (!
|
|
14584
|
-
const raw =
|
|
15133
|
+
if (!import_fs27.default.existsSync(file)) return {};
|
|
15134
|
+
const raw = import_fs27.default.readFileSync(file, "utf-8");
|
|
14585
15135
|
return JSON.parse(raw);
|
|
14586
15136
|
} catch {
|
|
14587
15137
|
return {};
|
|
@@ -14590,11 +15140,11 @@ function readMcpToolsConfig() {
|
|
|
14590
15140
|
function writeMcpToolsConfig(config) {
|
|
14591
15141
|
try {
|
|
14592
15142
|
const file = getMcpToolsFile();
|
|
14593
|
-
const dir =
|
|
14594
|
-
if (!
|
|
14595
|
-
const tmpPath = `${file}.${
|
|
14596
|
-
|
|
14597
|
-
|
|
15143
|
+
const dir = import_path29.default.dirname(file);
|
|
15144
|
+
if (!import_fs27.default.existsSync(dir)) import_fs27.default.mkdirSync(dir, { recursive: true });
|
|
15145
|
+
const tmpPath = `${file}.${import_os25.default.hostname()}.${process.pid}.tmp`;
|
|
15146
|
+
import_fs27.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
|
|
15147
|
+
import_fs27.default.renameSync(tmpPath, file);
|
|
14598
15148
|
} catch (e) {
|
|
14599
15149
|
console.error("Failed to write mcp-tools.json", e);
|
|
14600
15150
|
}
|
|
@@ -14633,13 +15183,13 @@ function approveServer(serverKey, disabledTools) {
|
|
|
14633
15183
|
writeMcpToolsConfig(config);
|
|
14634
15184
|
}
|
|
14635
15185
|
}
|
|
14636
|
-
var
|
|
15186
|
+
var import_fs27, import_path29, import_os25;
|
|
14637
15187
|
var init_mcp_tools = __esm({
|
|
14638
15188
|
"src/daemon/mcp-tools.ts"() {
|
|
14639
15189
|
"use strict";
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
15190
|
+
import_fs27 = __toESM(require("fs"));
|
|
15191
|
+
import_path29 = __toESM(require("path"));
|
|
15192
|
+
import_os25 = __toESM(require("os"));
|
|
14643
15193
|
}
|
|
14644
15194
|
});
|
|
14645
15195
|
|
|
@@ -14662,7 +15212,7 @@ function startDaemon() {
|
|
|
14662
15212
|
idleTimer = setTimeout(() => {
|
|
14663
15213
|
if (autoStarted) {
|
|
14664
15214
|
try {
|
|
14665
|
-
|
|
15215
|
+
import_fs28.default.unlinkSync(DAEMON_PID_FILE);
|
|
14666
15216
|
} catch {
|
|
14667
15217
|
}
|
|
14668
15218
|
}
|
|
@@ -14807,7 +15357,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
14807
15357
|
mcpServer: entry.mcpServer
|
|
14808
15358
|
});
|
|
14809
15359
|
}
|
|
14810
|
-
const projectCwd = typeof cwd === "string" &&
|
|
15360
|
+
const projectCwd = typeof cwd === "string" && import_path30.default.isAbsolute(cwd) ? cwd : void 0;
|
|
14811
15361
|
const projectConfig = getConfig(projectCwd);
|
|
14812
15362
|
const browserEnabled = projectConfig.settings.approvers?.browser !== false;
|
|
14813
15363
|
const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
|
|
@@ -15099,8 +15649,8 @@ data: ${JSON.stringify(item.data)}
|
|
|
15099
15649
|
if (!validToken(req)) return res.writeHead(403).end();
|
|
15100
15650
|
const periodParam = reqUrl.searchParams.get("period") || "7d";
|
|
15101
15651
|
const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
|
|
15102
|
-
const logPath =
|
|
15103
|
-
if (!
|
|
15652
|
+
const logPath = import_path30.default.join(import_os26.default.homedir(), ".node9", "audit.log");
|
|
15653
|
+
if (!import_fs28.default.existsSync(logPath)) {
|
|
15104
15654
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
15105
15655
|
return res.end(
|
|
15106
15656
|
JSON.stringify({
|
|
@@ -15113,7 +15663,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
15113
15663
|
);
|
|
15114
15664
|
}
|
|
15115
15665
|
try {
|
|
15116
|
-
const raw =
|
|
15666
|
+
const raw = import_fs28.default.readFileSync(logPath, "utf-8");
|
|
15117
15667
|
const allEntries = raw.split("\n").flatMap((line) => {
|
|
15118
15668
|
if (!line.trim()) return [];
|
|
15119
15669
|
try {
|
|
@@ -15436,14 +15986,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
15436
15986
|
server.on("error", (e) => {
|
|
15437
15987
|
if (e.code === "EADDRINUSE") {
|
|
15438
15988
|
try {
|
|
15439
|
-
if (
|
|
15440
|
-
const { pid } = JSON.parse(
|
|
15989
|
+
if (import_fs28.default.existsSync(DAEMON_PID_FILE)) {
|
|
15990
|
+
const { pid } = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
15441
15991
|
process.kill(pid, 0);
|
|
15442
15992
|
return process.exit(0);
|
|
15443
15993
|
}
|
|
15444
15994
|
} catch {
|
|
15445
15995
|
try {
|
|
15446
|
-
|
|
15996
|
+
import_fs28.default.unlinkSync(DAEMON_PID_FILE);
|
|
15447
15997
|
} catch {
|
|
15448
15998
|
}
|
|
15449
15999
|
server.listen(DAEMON_PORT, DAEMON_HOST);
|
|
@@ -15515,14 +16065,14 @@ data: ${JSON.stringify(item.data)}
|
|
|
15515
16065
|
}
|
|
15516
16066
|
startActivitySocket();
|
|
15517
16067
|
}
|
|
15518
|
-
var import_http,
|
|
16068
|
+
var import_http, import_fs28, import_path30, import_os26, import_crypto10, import_child_process2, import_chalk6;
|
|
15519
16069
|
var init_server = __esm({
|
|
15520
16070
|
"src/daemon/server.ts"() {
|
|
15521
16071
|
"use strict";
|
|
15522
16072
|
import_http = __toESM(require("http"));
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
|
|
16073
|
+
import_fs28 = __toESM(require("fs"));
|
|
16074
|
+
import_path30 = __toESM(require("path"));
|
|
16075
|
+
import_os26 = __toESM(require("os"));
|
|
15526
16076
|
import_crypto10 = require("crypto");
|
|
15527
16077
|
import_child_process2 = require("child_process");
|
|
15528
16078
|
import_chalk6 = __toESM(require("chalk"));
|
|
@@ -15543,8 +16093,8 @@ var init_server = __esm({
|
|
|
15543
16093
|
function resolveNode9Binary() {
|
|
15544
16094
|
try {
|
|
15545
16095
|
const script = process.argv[1];
|
|
15546
|
-
if (typeof script === "string" &&
|
|
15547
|
-
return
|
|
16096
|
+
if (typeof script === "string" && import_path31.default.isAbsolute(script) && import_fs29.default.existsSync(script)) {
|
|
16097
|
+
return import_fs29.default.realpathSync(script);
|
|
15548
16098
|
}
|
|
15549
16099
|
} catch {
|
|
15550
16100
|
}
|
|
@@ -15562,11 +16112,11 @@ function xmlEscape(s) {
|
|
|
15562
16112
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
15563
16113
|
}
|
|
15564
16114
|
function launchdPlist(binaryPath) {
|
|
15565
|
-
const logDir =
|
|
16115
|
+
const logDir = import_path31.default.join(import_os27.default.homedir(), ".node9");
|
|
15566
16116
|
const nodePath = xmlEscape(process.execPath);
|
|
15567
16117
|
const scriptPath = xmlEscape(binaryPath);
|
|
15568
|
-
const outLog = xmlEscape(
|
|
15569
|
-
const errLog = xmlEscape(
|
|
16118
|
+
const outLog = xmlEscape(import_path31.default.join(logDir, "daemon.log"));
|
|
16119
|
+
const errLog = xmlEscape(import_path31.default.join(logDir, "daemon-error.log"));
|
|
15570
16120
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
15571
16121
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
15572
16122
|
<plist version="1.0">
|
|
@@ -15599,9 +16149,9 @@ function launchdPlist(binaryPath) {
|
|
|
15599
16149
|
`;
|
|
15600
16150
|
}
|
|
15601
16151
|
function installLaunchd(binaryPath) {
|
|
15602
|
-
const dir =
|
|
15603
|
-
if (!
|
|
15604
|
-
|
|
16152
|
+
const dir = import_path31.default.dirname(LAUNCHD_PLIST);
|
|
16153
|
+
if (!import_fs29.default.existsSync(dir)) import_fs29.default.mkdirSync(dir, { recursive: true });
|
|
16154
|
+
import_fs29.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
|
|
15605
16155
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
|
|
15606
16156
|
const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
|
|
15607
16157
|
encoding: "utf8",
|
|
@@ -15612,13 +16162,13 @@ function installLaunchd(binaryPath) {
|
|
|
15612
16162
|
}
|
|
15613
16163
|
}
|
|
15614
16164
|
function uninstallLaunchd() {
|
|
15615
|
-
if (
|
|
16165
|
+
if (import_fs29.default.existsSync(LAUNCHD_PLIST)) {
|
|
15616
16166
|
(0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
|
|
15617
|
-
|
|
16167
|
+
import_fs29.default.unlinkSync(LAUNCHD_PLIST);
|
|
15618
16168
|
}
|
|
15619
16169
|
}
|
|
15620
16170
|
function isLaunchdInstalled() {
|
|
15621
|
-
return
|
|
16171
|
+
return import_fs29.default.existsSync(LAUNCHD_PLIST);
|
|
15622
16172
|
}
|
|
15623
16173
|
function systemdUnit(binaryPath) {
|
|
15624
16174
|
return `[Unit]
|
|
@@ -15637,12 +16187,12 @@ WantedBy=default.target
|
|
|
15637
16187
|
`;
|
|
15638
16188
|
}
|
|
15639
16189
|
function installSystemd(binaryPath) {
|
|
15640
|
-
if (!
|
|
15641
|
-
|
|
16190
|
+
if (!import_fs29.default.existsSync(SYSTEMD_UNIT_DIR)) {
|
|
16191
|
+
import_fs29.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
|
|
15642
16192
|
}
|
|
15643
|
-
|
|
16193
|
+
import_fs29.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
|
|
15644
16194
|
try {
|
|
15645
|
-
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger",
|
|
16195
|
+
(0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os27.default.userInfo().username], { timeout: 3e3 });
|
|
15646
16196
|
} catch {
|
|
15647
16197
|
}
|
|
15648
16198
|
const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
|
|
@@ -15662,23 +16212,23 @@ function installSystemd(binaryPath) {
|
|
|
15662
16212
|
}
|
|
15663
16213
|
}
|
|
15664
16214
|
function uninstallSystemd() {
|
|
15665
|
-
if (
|
|
16215
|
+
if (import_fs29.default.existsSync(SYSTEMD_UNIT)) {
|
|
15666
16216
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
|
|
15667
16217
|
encoding: "utf8",
|
|
15668
16218
|
timeout: 5e3
|
|
15669
16219
|
});
|
|
15670
16220
|
(0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
|
|
15671
|
-
|
|
16221
|
+
import_fs29.default.unlinkSync(SYSTEMD_UNIT);
|
|
15672
16222
|
}
|
|
15673
16223
|
}
|
|
15674
16224
|
function isSystemdInstalled() {
|
|
15675
|
-
return
|
|
16225
|
+
return import_fs29.default.existsSync(SYSTEMD_UNIT);
|
|
15676
16226
|
}
|
|
15677
16227
|
function stopRunningDaemon() {
|
|
15678
|
-
const pidFile =
|
|
15679
|
-
if (!
|
|
16228
|
+
const pidFile = import_path31.default.join(import_os27.default.homedir(), ".node9", "daemon.pid");
|
|
16229
|
+
if (!import_fs29.default.existsSync(pidFile)) return;
|
|
15680
16230
|
try {
|
|
15681
|
-
const data = JSON.parse(
|
|
16231
|
+
const data = JSON.parse(import_fs29.default.readFileSync(pidFile, "utf-8"));
|
|
15682
16232
|
const pid = data.pid;
|
|
15683
16233
|
const MAX_PID2 = 4194304;
|
|
15684
16234
|
if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
|
|
@@ -15698,7 +16248,7 @@ function stopRunningDaemon() {
|
|
|
15698
16248
|
}
|
|
15699
16249
|
}
|
|
15700
16250
|
try {
|
|
15701
|
-
|
|
16251
|
+
import_fs29.default.unlinkSync(pidFile);
|
|
15702
16252
|
} catch {
|
|
15703
16253
|
}
|
|
15704
16254
|
} catch {
|
|
@@ -15768,26 +16318,26 @@ function isDaemonServiceInstalled() {
|
|
|
15768
16318
|
if (process.platform === "linux") return isSystemdInstalled();
|
|
15769
16319
|
return false;
|
|
15770
16320
|
}
|
|
15771
|
-
var
|
|
16321
|
+
var import_fs29, import_path31, import_os27, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
|
|
15772
16322
|
var init_service = __esm({
|
|
15773
16323
|
"src/daemon/service.ts"() {
|
|
15774
16324
|
"use strict";
|
|
15775
|
-
|
|
15776
|
-
|
|
15777
|
-
|
|
16325
|
+
import_fs29 = __toESM(require("fs"));
|
|
16326
|
+
import_path31 = __toESM(require("path"));
|
|
16327
|
+
import_os27 = __toESM(require("os"));
|
|
15778
16328
|
import_child_process3 = require("child_process");
|
|
15779
16329
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
15780
|
-
LAUNCHD_PLIST =
|
|
15781
|
-
SYSTEMD_UNIT_DIR =
|
|
15782
|
-
SYSTEMD_UNIT =
|
|
16330
|
+
LAUNCHD_PLIST = import_path31.default.join(import_os27.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
16331
|
+
SYSTEMD_UNIT_DIR = import_path31.default.join(import_os27.default.homedir(), ".config", "systemd", "user");
|
|
16332
|
+
SYSTEMD_UNIT = import_path31.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
15783
16333
|
}
|
|
15784
16334
|
});
|
|
15785
16335
|
|
|
15786
16336
|
// src/daemon/index.ts
|
|
15787
16337
|
function stopDaemon() {
|
|
15788
|
-
if (!
|
|
16338
|
+
if (!import_fs30.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
|
|
15789
16339
|
try {
|
|
15790
|
-
const data = JSON.parse(
|
|
16340
|
+
const data = JSON.parse(import_fs30.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
15791
16341
|
const pid = data.pid;
|
|
15792
16342
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
15793
16343
|
console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
|
|
@@ -15799,7 +16349,7 @@ function stopDaemon() {
|
|
|
15799
16349
|
console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
|
|
15800
16350
|
} finally {
|
|
15801
16351
|
try {
|
|
15802
|
-
|
|
16352
|
+
import_fs30.default.unlinkSync(DAEMON_PID_FILE);
|
|
15803
16353
|
} catch {
|
|
15804
16354
|
}
|
|
15805
16355
|
}
|
|
@@ -15808,9 +16358,9 @@ function daemonStatus() {
|
|
|
15808
16358
|
const serviceInstalled = isDaemonServiceInstalled();
|
|
15809
16359
|
const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
|
|
15810
16360
|
let processStatus;
|
|
15811
|
-
if (
|
|
16361
|
+
if (import_fs30.default.existsSync(DAEMON_PID_FILE)) {
|
|
15812
16362
|
try {
|
|
15813
|
-
const data = JSON.parse(
|
|
16363
|
+
const data = JSON.parse(import_fs30.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
|
|
15814
16364
|
const pid = data.pid;
|
|
15815
16365
|
const port = data.port;
|
|
15816
16366
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
|
|
@@ -15832,11 +16382,11 @@ function daemonStatus() {
|
|
|
15832
16382
|
console.log(` Service : ${serviceLabel}
|
|
15833
16383
|
`);
|
|
15834
16384
|
}
|
|
15835
|
-
var
|
|
16385
|
+
var import_fs30, import_chalk7, MAX_PID;
|
|
15836
16386
|
var init_daemon2 = __esm({
|
|
15837
16387
|
"src/daemon/index.ts"() {
|
|
15838
16388
|
"use strict";
|
|
15839
|
-
|
|
16389
|
+
import_fs30 = __toESM(require("fs"));
|
|
15840
16390
|
import_chalk7 = __toESM(require("chalk"));
|
|
15841
16391
|
init_server();
|
|
15842
16392
|
init_state2();
|
|
@@ -15876,20 +16426,20 @@ function getModelContextLimit(model) {
|
|
|
15876
16426
|
return 2e5;
|
|
15877
16427
|
}
|
|
15878
16428
|
function readSessionUsage() {
|
|
15879
|
-
const projectsDir =
|
|
15880
|
-
if (!
|
|
16429
|
+
const projectsDir = import_path49.default.join(import_os43.default.homedir(), ".claude", "projects");
|
|
16430
|
+
if (!import_fs48.default.existsSync(projectsDir)) return null;
|
|
15881
16431
|
let latestFile = null;
|
|
15882
16432
|
let latestMtime = 0;
|
|
15883
16433
|
try {
|
|
15884
|
-
for (const dir of
|
|
15885
|
-
const dirPath =
|
|
16434
|
+
for (const dir of import_fs48.default.readdirSync(projectsDir)) {
|
|
16435
|
+
const dirPath = import_path49.default.join(projectsDir, dir);
|
|
15886
16436
|
try {
|
|
15887
|
-
if (!
|
|
15888
|
-
for (const file of
|
|
16437
|
+
if (!import_fs48.default.statSync(dirPath).isDirectory()) continue;
|
|
16438
|
+
for (const file of import_fs48.default.readdirSync(dirPath)) {
|
|
15889
16439
|
if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
|
|
15890
|
-
const filePath =
|
|
16440
|
+
const filePath = import_path49.default.join(dirPath, file);
|
|
15891
16441
|
try {
|
|
15892
|
-
const mtime =
|
|
16442
|
+
const mtime = import_fs48.default.statSync(filePath).mtimeMs;
|
|
15893
16443
|
if (mtime > latestMtime) {
|
|
15894
16444
|
latestMtime = mtime;
|
|
15895
16445
|
latestFile = filePath;
|
|
@@ -15904,7 +16454,7 @@ function readSessionUsage() {
|
|
|
15904
16454
|
}
|
|
15905
16455
|
if (!latestFile) return null;
|
|
15906
16456
|
try {
|
|
15907
|
-
const lines =
|
|
16457
|
+
const lines = import_fs48.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
15908
16458
|
let lastModel = "";
|
|
15909
16459
|
let lastInput = 0;
|
|
15910
16460
|
let lastOutput = 0;
|
|
@@ -15965,7 +16515,7 @@ function formatBase(activity) {
|
|
|
15965
16515
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
15966
16516
|
const icon = getIcon(activity.tool);
|
|
15967
16517
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
15968
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
16518
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os43.default.homedir(), "~");
|
|
15969
16519
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
15970
16520
|
return `${import_chalk29.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk29.default.white.bold(toolName)} ${import_chalk29.default.dim(argsPreview)}`;
|
|
15971
16521
|
}
|
|
@@ -16004,9 +16554,9 @@ function renderPending(activity) {
|
|
|
16004
16554
|
}
|
|
16005
16555
|
async function ensureDaemon() {
|
|
16006
16556
|
let pidPort = null;
|
|
16007
|
-
if (
|
|
16557
|
+
if (import_fs48.default.existsSync(PID_FILE)) {
|
|
16008
16558
|
try {
|
|
16009
|
-
const { port } = JSON.parse(
|
|
16559
|
+
const { port } = JSON.parse(import_fs48.default.readFileSync(PID_FILE, "utf-8"));
|
|
16010
16560
|
pidPort = port;
|
|
16011
16561
|
} catch {
|
|
16012
16562
|
console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -16162,9 +16712,9 @@ function buildRecoveryCardLines(req) {
|
|
|
16162
16712
|
];
|
|
16163
16713
|
}
|
|
16164
16714
|
function readApproversFromDisk() {
|
|
16165
|
-
const configPath =
|
|
16715
|
+
const configPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json");
|
|
16166
16716
|
try {
|
|
16167
|
-
const raw = JSON.parse(
|
|
16717
|
+
const raw = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
|
|
16168
16718
|
const settings = raw.settings ?? {};
|
|
16169
16719
|
return settings.approvers ?? {};
|
|
16170
16720
|
} catch {
|
|
@@ -16180,15 +16730,15 @@ function approverStatusLine() {
|
|
|
16180
16730
|
return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
|
|
16181
16731
|
}
|
|
16182
16732
|
function toggleApprover(channel) {
|
|
16183
|
-
const configPath =
|
|
16733
|
+
const configPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json");
|
|
16184
16734
|
try {
|
|
16185
|
-
const raw = JSON.parse(
|
|
16735
|
+
const raw = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
|
|
16186
16736
|
const settings = raw.settings ?? {};
|
|
16187
16737
|
const approvers = settings.approvers ?? {};
|
|
16188
16738
|
approvers[channel] = approvers[channel] === false;
|
|
16189
16739
|
settings.approvers = approvers;
|
|
16190
16740
|
raw.settings = settings;
|
|
16191
|
-
|
|
16741
|
+
import_fs48.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
16192
16742
|
} catch (err2) {
|
|
16193
16743
|
process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
|
|
16194
16744
|
`);
|
|
@@ -16360,8 +16910,8 @@ async function startTail(options = {}) {
|
|
|
16360
16910
|
}
|
|
16361
16911
|
postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
|
|
16362
16912
|
try {
|
|
16363
|
-
|
|
16364
|
-
|
|
16913
|
+
import_fs48.default.appendFileSync(
|
|
16914
|
+
import_path49.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log"),
|
|
16365
16915
|
`[tail] POST /decision failed: ${String(err2)}
|
|
16366
16916
|
`
|
|
16367
16917
|
);
|
|
@@ -16425,9 +16975,9 @@ async function startTail(options = {}) {
|
|
|
16425
16975
|
};
|
|
16426
16976
|
process.stdin.on("keypress", onKeypress);
|
|
16427
16977
|
}
|
|
16428
|
-
const auditLog =
|
|
16978
|
+
const auditLog = import_path49.default.join(import_os43.default.homedir(), ".node9", "audit.log");
|
|
16429
16979
|
try {
|
|
16430
|
-
const unackedDlp =
|
|
16980
|
+
const unackedDlp = import_fs48.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
16431
16981
|
if (unackedDlp > 0) {
|
|
16432
16982
|
console.log("");
|
|
16433
16983
|
console.log(
|
|
@@ -16467,7 +17017,7 @@ async function startTail(options = {}) {
|
|
|
16467
17017
|
if (stallWarned) return;
|
|
16468
17018
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
16469
17019
|
try {
|
|
16470
|
-
const auditMtime =
|
|
17020
|
+
const auditMtime = import_fs48.default.statSync(auditLog).mtimeMs;
|
|
16471
17021
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
16472
17022
|
console.log("");
|
|
16473
17023
|
console.log(
|
|
@@ -16652,20 +17202,20 @@ async function startTail(options = {}) {
|
|
|
16652
17202
|
process.exit(1);
|
|
16653
17203
|
});
|
|
16654
17204
|
}
|
|
16655
|
-
var import_http2, import_chalk29,
|
|
17205
|
+
var import_http2, import_chalk29, import_fs48, import_os43, import_path49, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
16656
17206
|
var init_tail = __esm({
|
|
16657
17207
|
"src/tui/tail.ts"() {
|
|
16658
17208
|
"use strict";
|
|
16659
17209
|
import_http2 = __toESM(require("http"));
|
|
16660
17210
|
import_chalk29 = __toESM(require("chalk"));
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
17211
|
+
import_fs48 = __toESM(require("fs"));
|
|
17212
|
+
import_os43 = __toESM(require("os"));
|
|
17213
|
+
import_path49 = __toESM(require("path"));
|
|
16664
17214
|
import_readline6 = __toESM(require("readline"));
|
|
16665
17215
|
import_child_process12 = require("child_process");
|
|
16666
17216
|
init_daemon2();
|
|
16667
17217
|
init_daemon();
|
|
16668
|
-
PID_FILE =
|
|
17218
|
+
PID_FILE = import_path49.default.join(import_os43.default.homedir(), ".node9", "daemon.pid");
|
|
16669
17219
|
ICONS = {
|
|
16670
17220
|
bash: "\u{1F4BB}",
|
|
16671
17221
|
shell: "\u{1F4BB}",
|
|
@@ -16787,9 +17337,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
16787
17337
|
return ` (${m}m left)`;
|
|
16788
17338
|
}
|
|
16789
17339
|
function safeReadJson(filePath) {
|
|
16790
|
-
if (!
|
|
17340
|
+
if (!import_fs49.default.existsSync(filePath)) return null;
|
|
16791
17341
|
try {
|
|
16792
|
-
return JSON.parse(
|
|
17342
|
+
return JSON.parse(import_fs49.default.readFileSync(filePath, "utf-8"));
|
|
16793
17343
|
} catch {
|
|
16794
17344
|
return null;
|
|
16795
17345
|
}
|
|
@@ -16810,12 +17360,12 @@ function countHooksInFile(filePath) {
|
|
|
16810
17360
|
return Object.keys(cfg.hooks).length;
|
|
16811
17361
|
}
|
|
16812
17362
|
function countRulesInDir(rulesDir) {
|
|
16813
|
-
if (!
|
|
17363
|
+
if (!import_fs49.default.existsSync(rulesDir)) return 0;
|
|
16814
17364
|
let count = 0;
|
|
16815
17365
|
try {
|
|
16816
|
-
for (const entry of
|
|
17366
|
+
for (const entry of import_fs49.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
16817
17367
|
if (entry.isDirectory()) {
|
|
16818
|
-
count += countRulesInDir(
|
|
17368
|
+
count += countRulesInDir(import_path50.default.join(rulesDir, entry.name));
|
|
16819
17369
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
16820
17370
|
count++;
|
|
16821
17371
|
}
|
|
@@ -16826,46 +17376,46 @@ function countRulesInDir(rulesDir) {
|
|
|
16826
17376
|
}
|
|
16827
17377
|
function isSamePath(a, b) {
|
|
16828
17378
|
try {
|
|
16829
|
-
return
|
|
17379
|
+
return import_path50.default.resolve(a) === import_path50.default.resolve(b);
|
|
16830
17380
|
} catch {
|
|
16831
17381
|
return false;
|
|
16832
17382
|
}
|
|
16833
17383
|
}
|
|
16834
17384
|
function countConfigs(cwd) {
|
|
16835
|
-
const homeDir2 =
|
|
16836
|
-
const claudeDir =
|
|
17385
|
+
const homeDir2 = import_os44.default.homedir();
|
|
17386
|
+
const claudeDir = import_path50.default.join(homeDir2, ".claude");
|
|
16837
17387
|
let claudeMdCount = 0;
|
|
16838
17388
|
let rulesCount = 0;
|
|
16839
17389
|
let hooksCount = 0;
|
|
16840
17390
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
16841
17391
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
16842
|
-
if (
|
|
16843
|
-
rulesCount += countRulesInDir(
|
|
16844
|
-
const userSettings =
|
|
17392
|
+
if (import_fs49.default.existsSync(import_path50.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17393
|
+
rulesCount += countRulesInDir(import_path50.default.join(claudeDir, "rules"));
|
|
17394
|
+
const userSettings = import_path50.default.join(claudeDir, "settings.json");
|
|
16845
17395
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
16846
17396
|
hooksCount += countHooksInFile(userSettings);
|
|
16847
|
-
const userClaudeJson =
|
|
17397
|
+
const userClaudeJson = import_path50.default.join(homeDir2, ".claude.json");
|
|
16848
17398
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
16849
17399
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
16850
17400
|
userMcpServers.delete(name);
|
|
16851
17401
|
}
|
|
16852
17402
|
if (cwd) {
|
|
16853
|
-
if (
|
|
16854
|
-
if (
|
|
16855
|
-
const projectClaudeDir =
|
|
17403
|
+
if (import_fs49.default.existsSync(import_path50.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
17404
|
+
if (import_fs49.default.existsSync(import_path50.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17405
|
+
const projectClaudeDir = import_path50.default.join(cwd, ".claude");
|
|
16856
17406
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
16857
17407
|
if (!overlapsUserScope) {
|
|
16858
|
-
if (
|
|
16859
|
-
rulesCount += countRulesInDir(
|
|
16860
|
-
const projSettings =
|
|
17408
|
+
if (import_fs49.default.existsSync(import_path50.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
17409
|
+
rulesCount += countRulesInDir(import_path50.default.join(projectClaudeDir, "rules"));
|
|
17410
|
+
const projSettings = import_path50.default.join(projectClaudeDir, "settings.json");
|
|
16861
17411
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
16862
17412
|
hooksCount += countHooksInFile(projSettings);
|
|
16863
17413
|
}
|
|
16864
|
-
if (
|
|
16865
|
-
const localSettings =
|
|
17414
|
+
if (import_fs49.default.existsSync(import_path50.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
17415
|
+
const localSettings = import_path50.default.join(projectClaudeDir, "settings.local.json");
|
|
16866
17416
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
16867
17417
|
hooksCount += countHooksInFile(localSettings);
|
|
16868
|
-
const mcpJsonServers = getMcpServerNames(
|
|
17418
|
+
const mcpJsonServers = getMcpServerNames(import_path50.default.join(cwd, ".mcp.json"));
|
|
16869
17419
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
16870
17420
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
16871
17421
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -16898,12 +17448,12 @@ function readActiveShieldsHud() {
|
|
|
16898
17448
|
return shieldsCache.value;
|
|
16899
17449
|
}
|
|
16900
17450
|
try {
|
|
16901
|
-
const shieldsPath =
|
|
16902
|
-
if (!
|
|
17451
|
+
const shieldsPath = import_path50.default.join(import_os44.default.homedir(), ".node9", "shields.json");
|
|
17452
|
+
if (!import_fs49.default.existsSync(shieldsPath)) {
|
|
16903
17453
|
shieldsCache = { value: [], ts: now };
|
|
16904
17454
|
return [];
|
|
16905
17455
|
}
|
|
16906
|
-
const parsed = JSON.parse(
|
|
17456
|
+
const parsed = JSON.parse(import_fs49.default.readFileSync(shieldsPath, "utf-8"));
|
|
16907
17457
|
if (!Array.isArray(parsed.active)) {
|
|
16908
17458
|
shieldsCache = { value: [], ts: now };
|
|
16909
17459
|
return [];
|
|
@@ -17005,17 +17555,17 @@ function renderContextLine(stdin) {
|
|
|
17005
17555
|
async function main() {
|
|
17006
17556
|
try {
|
|
17007
17557
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
17008
|
-
if (
|
|
17558
|
+
if (import_fs49.default.existsSync(import_path50.default.join(import_os44.default.homedir(), ".node9", "hud-debug"))) {
|
|
17009
17559
|
try {
|
|
17010
|
-
const logPath =
|
|
17560
|
+
const logPath = import_path50.default.join(import_os44.default.homedir(), ".node9", "hud-debug.log");
|
|
17011
17561
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
17012
17562
|
let size = 0;
|
|
17013
17563
|
try {
|
|
17014
|
-
size =
|
|
17564
|
+
size = import_fs49.default.statSync(logPath).size;
|
|
17015
17565
|
} catch {
|
|
17016
17566
|
}
|
|
17017
17567
|
if (size < MAX_LOG_SIZE) {
|
|
17018
|
-
|
|
17568
|
+
import_fs49.default.appendFileSync(
|
|
17019
17569
|
logPath,
|
|
17020
17570
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
17021
17571
|
);
|
|
@@ -17036,11 +17586,11 @@ async function main() {
|
|
|
17036
17586
|
try {
|
|
17037
17587
|
const cwd = stdin.cwd ?? process.cwd();
|
|
17038
17588
|
for (const configPath of [
|
|
17039
|
-
|
|
17040
|
-
|
|
17589
|
+
import_path50.default.join(cwd, "node9.config.json"),
|
|
17590
|
+
import_path50.default.join(import_os44.default.homedir(), ".node9", "config.json")
|
|
17041
17591
|
]) {
|
|
17042
|
-
if (!
|
|
17043
|
-
const cfg = JSON.parse(
|
|
17592
|
+
if (!import_fs49.default.existsSync(configPath)) continue;
|
|
17593
|
+
const cfg = JSON.parse(import_fs49.default.readFileSync(configPath, "utf-8"));
|
|
17044
17594
|
const hud = cfg.settings?.hud;
|
|
17045
17595
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
17046
17596
|
}
|
|
@@ -17058,13 +17608,13 @@ async function main() {
|
|
|
17058
17608
|
renderOffline();
|
|
17059
17609
|
}
|
|
17060
17610
|
}
|
|
17061
|
-
var
|
|
17611
|
+
var import_fs49, import_path50, import_os44, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
17062
17612
|
var init_hud = __esm({
|
|
17063
17613
|
"src/cli/hud.ts"() {
|
|
17064
17614
|
"use strict";
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17615
|
+
import_fs49 = __toESM(require("fs"));
|
|
17616
|
+
import_path50 = __toESM(require("path"));
|
|
17617
|
+
import_os44 = __toESM(require("os"));
|
|
17068
17618
|
import_http3 = __toESM(require("http"));
|
|
17069
17619
|
init_daemon();
|
|
17070
17620
|
RESET3 = "\x1B[0m";
|
|
@@ -17091,9 +17641,9 @@ init_core();
|
|
|
17091
17641
|
init_setup();
|
|
17092
17642
|
init_daemon2();
|
|
17093
17643
|
var import_chalk30 = __toESM(require("chalk"));
|
|
17094
|
-
var
|
|
17095
|
-
var
|
|
17096
|
-
var
|
|
17644
|
+
var import_fs50 = __toESM(require("fs"));
|
|
17645
|
+
var import_path51 = __toESM(require("path"));
|
|
17646
|
+
var import_os45 = __toESM(require("os"));
|
|
17097
17647
|
var import_prompts2 = require("@inquirer/prompts");
|
|
17098
17648
|
|
|
17099
17649
|
// src/utils/duration.ts
|
|
@@ -17275,18 +17825,18 @@ async function runProxy(targetCommand) {
|
|
|
17275
17825
|
|
|
17276
17826
|
// src/cli/daemon-starter.ts
|
|
17277
17827
|
var import_child_process5 = require("child_process");
|
|
17278
|
-
var
|
|
17279
|
-
var
|
|
17828
|
+
var import_path32 = __toESM(require("path"));
|
|
17829
|
+
var import_fs31 = __toESM(require("fs"));
|
|
17280
17830
|
init_daemon();
|
|
17281
17831
|
function isTestingMode() {
|
|
17282
17832
|
return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
|
|
17283
17833
|
}
|
|
17284
17834
|
async function autoStartDaemonAndWait() {
|
|
17285
17835
|
if (isTestingMode()) return false;
|
|
17286
|
-
if (!
|
|
17836
|
+
if (!import_path32.default.isAbsolute(process.argv[1])) return false;
|
|
17287
17837
|
let resolvedArgv1;
|
|
17288
17838
|
try {
|
|
17289
|
-
resolvedArgv1 =
|
|
17839
|
+
resolvedArgv1 = import_fs31.default.realpathSync(process.argv[1]);
|
|
17290
17840
|
} catch {
|
|
17291
17841
|
return false;
|
|
17292
17842
|
}
|
|
@@ -17313,10 +17863,10 @@ async function autoStartDaemonAndWait() {
|
|
|
17313
17863
|
|
|
17314
17864
|
// src/cli/commands/check.ts
|
|
17315
17865
|
var import_chalk9 = __toESM(require("chalk"));
|
|
17316
|
-
var
|
|
17866
|
+
var import_fs34 = __toESM(require("fs"));
|
|
17317
17867
|
var import_child_process7 = require("child_process");
|
|
17318
|
-
var
|
|
17319
|
-
var
|
|
17868
|
+
var import_path35 = __toESM(require("path"));
|
|
17869
|
+
var import_os30 = __toESM(require("os"));
|
|
17320
17870
|
init_orchestrator();
|
|
17321
17871
|
init_daemon();
|
|
17322
17872
|
init_config();
|
|
@@ -17325,11 +17875,11 @@ init_policy();
|
|
|
17325
17875
|
// src/undo.ts
|
|
17326
17876
|
var import_child_process6 = require("child_process");
|
|
17327
17877
|
var import_crypto11 = __toESM(require("crypto"));
|
|
17328
|
-
var
|
|
17878
|
+
var import_fs32 = __toESM(require("fs"));
|
|
17329
17879
|
var import_net3 = __toESM(require("net"));
|
|
17330
|
-
var
|
|
17331
|
-
var
|
|
17332
|
-
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
17880
|
+
var import_path33 = __toESM(require("path"));
|
|
17881
|
+
var import_os28 = __toESM(require("os"));
|
|
17882
|
+
var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path33.default.join(import_os28.default.tmpdir(), "node9-activity.sock");
|
|
17333
17883
|
function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
17334
17884
|
try {
|
|
17335
17885
|
const payload = JSON.stringify({
|
|
@@ -17349,22 +17899,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
|
|
|
17349
17899
|
} catch {
|
|
17350
17900
|
}
|
|
17351
17901
|
}
|
|
17352
|
-
var SNAPSHOT_STACK_PATH =
|
|
17353
|
-
var UNDO_LATEST_PATH =
|
|
17902
|
+
var SNAPSHOT_STACK_PATH = import_path33.default.join(import_os28.default.homedir(), ".node9", "snapshots.json");
|
|
17903
|
+
var UNDO_LATEST_PATH = import_path33.default.join(import_os28.default.homedir(), ".node9", "undo_latest.txt");
|
|
17354
17904
|
var MAX_SNAPSHOTS = 10;
|
|
17355
17905
|
var GIT_TIMEOUT = 15e3;
|
|
17356
17906
|
function readStack() {
|
|
17357
17907
|
try {
|
|
17358
|
-
if (
|
|
17359
|
-
return JSON.parse(
|
|
17908
|
+
if (import_fs32.default.existsSync(SNAPSHOT_STACK_PATH))
|
|
17909
|
+
return JSON.parse(import_fs32.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
|
|
17360
17910
|
} catch {
|
|
17361
17911
|
}
|
|
17362
17912
|
return [];
|
|
17363
17913
|
}
|
|
17364
17914
|
function writeStack(stack) {
|
|
17365
|
-
const dir =
|
|
17366
|
-
if (!
|
|
17367
|
-
|
|
17915
|
+
const dir = import_path33.default.dirname(SNAPSHOT_STACK_PATH);
|
|
17916
|
+
if (!import_fs32.default.existsSync(dir)) import_fs32.default.mkdirSync(dir, { recursive: true });
|
|
17917
|
+
import_fs32.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
|
|
17368
17918
|
}
|
|
17369
17919
|
function extractFilePath(args) {
|
|
17370
17920
|
if (!args || typeof args !== "object") return null;
|
|
@@ -17384,12 +17934,12 @@ function buildArgsSummary(tool, args) {
|
|
|
17384
17934
|
return "";
|
|
17385
17935
|
}
|
|
17386
17936
|
function findProjectRoot(filePath) {
|
|
17387
|
-
let dir =
|
|
17937
|
+
let dir = import_path33.default.dirname(filePath);
|
|
17388
17938
|
while (true) {
|
|
17389
|
-
if (
|
|
17939
|
+
if (import_fs32.default.existsSync(import_path33.default.join(dir, ".git")) || import_fs32.default.existsSync(import_path33.default.join(dir, "package.json"))) {
|
|
17390
17940
|
return dir;
|
|
17391
17941
|
}
|
|
17392
|
-
const parent =
|
|
17942
|
+
const parent = import_path33.default.dirname(dir);
|
|
17393
17943
|
if (parent === dir) return process.cwd();
|
|
17394
17944
|
dir = parent;
|
|
17395
17945
|
}
|
|
@@ -17397,7 +17947,7 @@ function findProjectRoot(filePath) {
|
|
|
17397
17947
|
function normalizeCwdForHash(cwd) {
|
|
17398
17948
|
let normalized;
|
|
17399
17949
|
try {
|
|
17400
|
-
normalized =
|
|
17950
|
+
normalized = import_fs32.default.realpathSync(cwd);
|
|
17401
17951
|
} catch {
|
|
17402
17952
|
normalized = cwd;
|
|
17403
17953
|
}
|
|
@@ -17407,16 +17957,16 @@ function normalizeCwdForHash(cwd) {
|
|
|
17407
17957
|
}
|
|
17408
17958
|
function getShadowRepoDir(cwd) {
|
|
17409
17959
|
const hash = import_crypto11.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
|
|
17410
|
-
return
|
|
17960
|
+
return import_path33.default.join(import_os28.default.homedir(), ".node9", "snapshots", hash);
|
|
17411
17961
|
}
|
|
17412
17962
|
function cleanOrphanedIndexFiles(shadowDir) {
|
|
17413
17963
|
try {
|
|
17414
17964
|
const cutoff = Date.now() - 6e4;
|
|
17415
|
-
for (const f of
|
|
17965
|
+
for (const f of import_fs32.default.readdirSync(shadowDir)) {
|
|
17416
17966
|
if (f.startsWith("index_")) {
|
|
17417
|
-
const fp =
|
|
17967
|
+
const fp = import_path33.default.join(shadowDir, f);
|
|
17418
17968
|
try {
|
|
17419
|
-
if (
|
|
17969
|
+
if (import_fs32.default.statSync(fp).mtimeMs < cutoff) import_fs32.default.unlinkSync(fp);
|
|
17420
17970
|
} catch {
|
|
17421
17971
|
}
|
|
17422
17972
|
}
|
|
@@ -17428,7 +17978,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
|
|
|
17428
17978
|
const hardcoded = [".git", ".node9"];
|
|
17429
17979
|
const lines = [...hardcoded, ...ignorePaths].join("\n");
|
|
17430
17980
|
try {
|
|
17431
|
-
|
|
17981
|
+
import_fs32.default.writeFileSync(import_path33.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
|
|
17432
17982
|
} catch {
|
|
17433
17983
|
}
|
|
17434
17984
|
}
|
|
@@ -17441,25 +17991,25 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
17441
17991
|
timeout: 3e3
|
|
17442
17992
|
});
|
|
17443
17993
|
if (check.status === 0) {
|
|
17444
|
-
const ptPath =
|
|
17994
|
+
const ptPath = import_path33.default.join(shadowDir, "project-path.txt");
|
|
17445
17995
|
try {
|
|
17446
|
-
const stored =
|
|
17996
|
+
const stored = import_fs32.default.readFileSync(ptPath, "utf8").trim();
|
|
17447
17997
|
if (stored === normalizedCwd) return true;
|
|
17448
17998
|
if (process.env.NODE9_DEBUG === "1")
|
|
17449
17999
|
console.error(
|
|
17450
18000
|
`[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
|
|
17451
18001
|
);
|
|
17452
|
-
|
|
18002
|
+
import_fs32.default.rmSync(shadowDir, { recursive: true, force: true });
|
|
17453
18003
|
} catch {
|
|
17454
18004
|
try {
|
|
17455
|
-
|
|
18005
|
+
import_fs32.default.writeFileSync(ptPath, normalizedCwd, "utf8");
|
|
17456
18006
|
} catch {
|
|
17457
18007
|
}
|
|
17458
18008
|
return true;
|
|
17459
18009
|
}
|
|
17460
18010
|
}
|
|
17461
18011
|
try {
|
|
17462
|
-
|
|
18012
|
+
import_fs32.default.mkdirSync(shadowDir, { recursive: true });
|
|
17463
18013
|
} catch {
|
|
17464
18014
|
}
|
|
17465
18015
|
const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
|
|
@@ -17468,7 +18018,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
17468
18018
|
if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
|
|
17469
18019
|
return false;
|
|
17470
18020
|
}
|
|
17471
|
-
const configFile =
|
|
18021
|
+
const configFile = import_path33.default.join(shadowDir, "config");
|
|
17472
18022
|
(0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
|
|
17473
18023
|
timeout: 3e3
|
|
17474
18024
|
});
|
|
@@ -17476,7 +18026,7 @@ function ensureShadowRepo(shadowDir, cwd) {
|
|
|
17476
18026
|
timeout: 3e3
|
|
17477
18027
|
});
|
|
17478
18028
|
try {
|
|
17479
|
-
|
|
18029
|
+
import_fs32.default.writeFileSync(import_path33.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
|
|
17480
18030
|
} catch {
|
|
17481
18031
|
}
|
|
17482
18032
|
return true;
|
|
@@ -17499,12 +18049,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
17499
18049
|
let indexFile = null;
|
|
17500
18050
|
try {
|
|
17501
18051
|
const rawFilePath = extractFilePath(args);
|
|
17502
|
-
const absFilePath = rawFilePath &&
|
|
18052
|
+
const absFilePath = rawFilePath && import_path33.default.isAbsolute(rawFilePath) ? rawFilePath : null;
|
|
17503
18053
|
const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
|
|
17504
18054
|
const shadowDir = getShadowRepoDir(cwd);
|
|
17505
18055
|
if (!ensureShadowRepo(shadowDir, cwd)) return null;
|
|
17506
18056
|
writeShadowExcludes(shadowDir, ignorePaths);
|
|
17507
|
-
indexFile =
|
|
18057
|
+
indexFile = import_path33.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
|
|
17508
18058
|
const shadowEnv = {
|
|
17509
18059
|
...process.env,
|
|
17510
18060
|
GIT_DIR: shadowDir,
|
|
@@ -17576,7 +18126,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
17576
18126
|
writeStack(stack);
|
|
17577
18127
|
const entry = stack[stack.length - 1];
|
|
17578
18128
|
notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
|
|
17579
|
-
|
|
18129
|
+
import_fs32.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
|
|
17580
18130
|
if (shouldGc) {
|
|
17581
18131
|
(0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
|
|
17582
18132
|
}
|
|
@@ -17587,7 +18137,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
|
|
|
17587
18137
|
} finally {
|
|
17588
18138
|
if (indexFile) {
|
|
17589
18139
|
try {
|
|
17590
|
-
|
|
18140
|
+
import_fs32.default.unlinkSync(indexFile);
|
|
17591
18141
|
} catch {
|
|
17592
18142
|
}
|
|
17593
18143
|
}
|
|
@@ -17663,9 +18213,9 @@ function applyUndo(hash, cwd) {
|
|
|
17663
18213
|
timeout: GIT_TIMEOUT
|
|
17664
18214
|
}).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
|
|
17665
18215
|
for (const file of [...tracked, ...untracked]) {
|
|
17666
|
-
const fullPath =
|
|
17667
|
-
if (!snapshotFiles.has(file) &&
|
|
17668
|
-
|
|
18216
|
+
const fullPath = import_path33.default.join(dir, file);
|
|
18217
|
+
if (!snapshotFiles.has(file) && import_fs32.default.existsSync(fullPath)) {
|
|
18218
|
+
import_fs32.default.unlinkSync(fullPath);
|
|
17669
18219
|
}
|
|
17670
18220
|
}
|
|
17671
18221
|
return true;
|
|
@@ -17675,12 +18225,12 @@ function applyUndo(hash, cwd) {
|
|
|
17675
18225
|
}
|
|
17676
18226
|
|
|
17677
18227
|
// src/skill-pin.ts
|
|
17678
|
-
var
|
|
17679
|
-
var
|
|
17680
|
-
var
|
|
18228
|
+
var import_fs33 = __toESM(require("fs"));
|
|
18229
|
+
var import_path34 = __toESM(require("path"));
|
|
18230
|
+
var import_os29 = __toESM(require("os"));
|
|
17681
18231
|
var import_crypto12 = __toESM(require("crypto"));
|
|
17682
18232
|
function getPinsFilePath2() {
|
|
17683
|
-
return
|
|
18233
|
+
return import_path34.default.join(import_os29.default.homedir(), ".node9", "skill-pins.json");
|
|
17684
18234
|
}
|
|
17685
18235
|
var MAX_FILES = 5e3;
|
|
17686
18236
|
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
@@ -17694,18 +18244,18 @@ function walkDir(root) {
|
|
|
17694
18244
|
if (out.length >= MAX_FILES) return;
|
|
17695
18245
|
let entries;
|
|
17696
18246
|
try {
|
|
17697
|
-
entries =
|
|
18247
|
+
entries = import_fs33.default.readdirSync(dir, { withFileTypes: true });
|
|
17698
18248
|
} catch {
|
|
17699
18249
|
return;
|
|
17700
18250
|
}
|
|
17701
18251
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
17702
18252
|
for (const entry of entries) {
|
|
17703
18253
|
if (out.length >= MAX_FILES) return;
|
|
17704
|
-
const full =
|
|
17705
|
-
const rel = relDir ?
|
|
18254
|
+
const full = import_path34.default.join(dir, entry.name);
|
|
18255
|
+
const rel = relDir ? import_path34.default.posix.join(relDir, entry.name) : entry.name;
|
|
17706
18256
|
let lst;
|
|
17707
18257
|
try {
|
|
17708
|
-
lst =
|
|
18258
|
+
lst = import_fs33.default.lstatSync(full);
|
|
17709
18259
|
} catch {
|
|
17710
18260
|
continue;
|
|
17711
18261
|
}
|
|
@@ -17717,7 +18267,7 @@ function walkDir(root) {
|
|
|
17717
18267
|
if (!lst.isFile()) continue;
|
|
17718
18268
|
if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
|
|
17719
18269
|
try {
|
|
17720
|
-
const buf =
|
|
18270
|
+
const buf = import_fs33.default.readFileSync(full);
|
|
17721
18271
|
totalBytes += buf.length;
|
|
17722
18272
|
out.push({ rel, hash: sha256Bytes(buf) });
|
|
17723
18273
|
} catch {
|
|
@@ -17731,14 +18281,14 @@ function walkDir(root) {
|
|
|
17731
18281
|
function hashSkillRoot(absPath) {
|
|
17732
18282
|
let lst;
|
|
17733
18283
|
try {
|
|
17734
|
-
lst =
|
|
18284
|
+
lst = import_fs33.default.lstatSync(absPath);
|
|
17735
18285
|
} catch {
|
|
17736
18286
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
17737
18287
|
}
|
|
17738
18288
|
if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
|
|
17739
18289
|
if (lst.isFile()) {
|
|
17740
18290
|
try {
|
|
17741
|
-
return { exists: true, contentHash: sha256Bytes(
|
|
18291
|
+
return { exists: true, contentHash: sha256Bytes(import_fs33.default.readFileSync(absPath)), fileCount: 1 };
|
|
17742
18292
|
} catch {
|
|
17743
18293
|
return { exists: false, contentHash: "", fileCount: 0 };
|
|
17744
18294
|
}
|
|
@@ -17756,7 +18306,7 @@ function getRootKey(absPath) {
|
|
|
17756
18306
|
function readSkillPinsSafe() {
|
|
17757
18307
|
const filePath = getPinsFilePath2();
|
|
17758
18308
|
try {
|
|
17759
|
-
const raw =
|
|
18309
|
+
const raw = import_fs33.default.readFileSync(filePath, "utf-8");
|
|
17760
18310
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
17761
18311
|
const parsed = JSON.parse(raw);
|
|
17762
18312
|
if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
|
|
@@ -17776,10 +18326,10 @@ function readSkillPins() {
|
|
|
17776
18326
|
}
|
|
17777
18327
|
function writeSkillPins(data) {
|
|
17778
18328
|
const filePath = getPinsFilePath2();
|
|
17779
|
-
|
|
18329
|
+
import_fs33.default.mkdirSync(import_path34.default.dirname(filePath), { recursive: true });
|
|
17780
18330
|
const tmp = `${filePath}.${import_crypto12.default.randomBytes(6).toString("hex")}.tmp`;
|
|
17781
|
-
|
|
17782
|
-
|
|
18331
|
+
import_fs33.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
18332
|
+
import_fs33.default.renameSync(tmp, filePath);
|
|
17783
18333
|
}
|
|
17784
18334
|
function removePin2(rootKey) {
|
|
17785
18335
|
const pins = readSkillPins();
|
|
@@ -17823,36 +18373,36 @@ function verifyAndPinRoots(roots) {
|
|
|
17823
18373
|
return { kind: "verified" };
|
|
17824
18374
|
}
|
|
17825
18375
|
function defaultSkillRoots(_cwd) {
|
|
17826
|
-
const marketplaces =
|
|
18376
|
+
const marketplaces = import_path34.default.join(import_os29.default.homedir(), ".claude", "plugins", "marketplaces");
|
|
17827
18377
|
const roots = [];
|
|
17828
18378
|
let registries;
|
|
17829
18379
|
try {
|
|
17830
|
-
registries =
|
|
18380
|
+
registries = import_fs33.default.readdirSync(marketplaces, { withFileTypes: true });
|
|
17831
18381
|
} catch {
|
|
17832
18382
|
return [];
|
|
17833
18383
|
}
|
|
17834
18384
|
for (const registry of registries) {
|
|
17835
18385
|
if (!registry.isDirectory()) continue;
|
|
17836
|
-
const pluginsDir =
|
|
18386
|
+
const pluginsDir = import_path34.default.join(marketplaces, registry.name, "plugins");
|
|
17837
18387
|
let plugins;
|
|
17838
18388
|
try {
|
|
17839
|
-
plugins =
|
|
18389
|
+
plugins = import_fs33.default.readdirSync(pluginsDir, { withFileTypes: true });
|
|
17840
18390
|
} catch {
|
|
17841
18391
|
continue;
|
|
17842
18392
|
}
|
|
17843
18393
|
for (const plugin of plugins) {
|
|
17844
18394
|
if (!plugin.isDirectory()) continue;
|
|
17845
|
-
roots.push(
|
|
18395
|
+
roots.push(import_path34.default.join(pluginsDir, plugin.name));
|
|
17846
18396
|
}
|
|
17847
18397
|
}
|
|
17848
18398
|
return roots;
|
|
17849
18399
|
}
|
|
17850
18400
|
function resolveUserSkillRoot(entry, cwd) {
|
|
17851
18401
|
if (!entry) return null;
|
|
17852
|
-
if (entry.startsWith("~/") || entry === "~") return
|
|
17853
|
-
if (
|
|
17854
|
-
if (!cwd || !
|
|
17855
|
-
return
|
|
18402
|
+
if (entry.startsWith("~/") || entry === "~") return import_path34.default.join(import_os29.default.homedir(), entry.slice(1));
|
|
18403
|
+
if (import_path34.default.isAbsolute(entry)) return entry;
|
|
18404
|
+
if (!cwd || !import_path34.default.isAbsolute(cwd)) return null;
|
|
18405
|
+
return import_path34.default.join(cwd, entry);
|
|
17856
18406
|
}
|
|
17857
18407
|
|
|
17858
18408
|
// src/cli/commands/check.ts
|
|
@@ -17921,9 +18471,9 @@ function registerCheckCommand(program2) {
|
|
|
17921
18471
|
} catch (err2) {
|
|
17922
18472
|
const tempConfig = getConfig();
|
|
17923
18473
|
if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
|
|
17924
|
-
const logPath =
|
|
18474
|
+
const logPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "hook-debug.log");
|
|
17925
18475
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
17926
|
-
|
|
18476
|
+
import_fs34.default.appendFileSync(
|
|
17927
18477
|
logPath,
|
|
17928
18478
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
|
|
17929
18479
|
RAW: ${raw}
|
|
@@ -17936,14 +18486,14 @@ RAW: ${raw}
|
|
|
17936
18486
|
const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
|
|
17937
18487
|
if (process.env.NODE9_DEBUG === "1") {
|
|
17938
18488
|
try {
|
|
17939
|
-
const logPath =
|
|
17940
|
-
if (!
|
|
17941
|
-
|
|
18489
|
+
const logPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "hook-debug.log");
|
|
18490
|
+
if (!import_fs34.default.existsSync(import_path35.default.dirname(logPath)))
|
|
18491
|
+
import_fs34.default.mkdirSync(import_path35.default.dirname(logPath), { recursive: true });
|
|
17942
18492
|
const sanitized = JSON.stringify({
|
|
17943
18493
|
...payload,
|
|
17944
18494
|
prompt: `<redacted, ${prompt.length} bytes>`
|
|
17945
18495
|
});
|
|
17946
|
-
|
|
18496
|
+
import_fs34.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
|
|
17947
18497
|
`);
|
|
17948
18498
|
} catch {
|
|
17949
18499
|
}
|
|
@@ -17963,8 +18513,8 @@ RAW: ${raw}
|
|
|
17963
18513
|
);
|
|
17964
18514
|
const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
|
|
17965
18515
|
try {
|
|
17966
|
-
const ttyFd =
|
|
17967
|
-
|
|
18516
|
+
const ttyFd = import_fs34.default.openSync("/dev/tty", "w");
|
|
18517
|
+
import_fs34.default.writeSync(
|
|
17968
18518
|
ttyFd,
|
|
17969
18519
|
import_chalk9.default.bgRed.white.bold(`
|
|
17970
18520
|
\u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
|
|
@@ -17974,7 +18524,7 @@ RAW: ${raw}
|
|
|
17974
18524
|
|
|
17975
18525
|
`)
|
|
17976
18526
|
);
|
|
17977
|
-
|
|
18527
|
+
import_fs34.default.closeSync(ttyFd);
|
|
17978
18528
|
} catch {
|
|
17979
18529
|
}
|
|
17980
18530
|
const isCodex = agent2 === "Codex";
|
|
@@ -17993,16 +18543,16 @@ RAW: ${raw}
|
|
|
17993
18543
|
process.exit(2);
|
|
17994
18544
|
}
|
|
17995
18545
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
17996
|
-
const safeCwdForConfig = typeof payloadCwd === "string" &&
|
|
18546
|
+
const safeCwdForConfig = typeof payloadCwd === "string" && import_path35.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
17997
18547
|
const config = getConfig(safeCwdForConfig);
|
|
17998
18548
|
if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
|
|
17999
18549
|
try {
|
|
18000
18550
|
const scriptPath = process.argv[1];
|
|
18001
|
-
if (typeof scriptPath !== "string" || !
|
|
18551
|
+
if (typeof scriptPath !== "string" || !import_path35.default.isAbsolute(scriptPath))
|
|
18002
18552
|
throw new Error("node9: argv[1] is not an absolute path");
|
|
18003
|
-
const resolvedScript =
|
|
18004
|
-
const packageDist =
|
|
18005
|
-
if (!resolvedScript.startsWith(packageDist +
|
|
18553
|
+
const resolvedScript = import_fs34.default.realpathSync(scriptPath);
|
|
18554
|
+
const packageDist = import_fs34.default.realpathSync(import_path35.default.resolve(__dirname, "../.."));
|
|
18555
|
+
if (!resolvedScript.startsWith(packageDist + import_path35.default.sep) && resolvedScript !== packageDist)
|
|
18006
18556
|
throw new Error(
|
|
18007
18557
|
`node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
|
|
18008
18558
|
);
|
|
@@ -18024,10 +18574,10 @@ RAW: ${raw}
|
|
|
18024
18574
|
});
|
|
18025
18575
|
d.unref();
|
|
18026
18576
|
} catch (spawnErr) {
|
|
18027
|
-
const logPath =
|
|
18577
|
+
const logPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "hook-debug.log");
|
|
18028
18578
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
18029
18579
|
try {
|
|
18030
|
-
|
|
18580
|
+
import_fs34.default.appendFileSync(
|
|
18031
18581
|
logPath,
|
|
18032
18582
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
|
|
18033
18583
|
`
|
|
@@ -18037,10 +18587,10 @@ RAW: ${raw}
|
|
|
18037
18587
|
}
|
|
18038
18588
|
}
|
|
18039
18589
|
if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
|
|
18040
|
-
const logPath =
|
|
18041
|
-
if (!
|
|
18042
|
-
|
|
18043
|
-
|
|
18590
|
+
const logPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "hook-debug.log");
|
|
18591
|
+
if (!import_fs34.default.existsSync(import_path35.default.dirname(logPath)))
|
|
18592
|
+
import_fs34.default.mkdirSync(import_path35.default.dirname(logPath), { recursive: true });
|
|
18593
|
+
import_fs34.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
|
|
18044
18594
|
`);
|
|
18045
18595
|
}
|
|
18046
18596
|
const rawToolName = sanitize2(extractToolName(payload));
|
|
@@ -18054,8 +18604,8 @@ RAW: ${raw}
|
|
|
18054
18604
|
const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
|
|
18055
18605
|
let ttyFd = null;
|
|
18056
18606
|
try {
|
|
18057
|
-
ttyFd =
|
|
18058
|
-
const writeTty = (line) =>
|
|
18607
|
+
ttyFd = import_fs34.default.openSync("/dev/tty", "w");
|
|
18608
|
+
const writeTty = (line) => import_fs34.default.writeSync(ttyFd, line + "\n");
|
|
18059
18609
|
if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
|
|
18060
18610
|
writeTty(import_chalk9.default.bgRed.white.bold(`
|
|
18061
18611
|
\u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
|
|
@@ -18074,7 +18624,7 @@ RAW: ${raw}
|
|
|
18074
18624
|
} finally {
|
|
18075
18625
|
if (ttyFd !== null)
|
|
18076
18626
|
try {
|
|
18077
|
-
|
|
18627
|
+
import_fs34.default.closeSync(ttyFd);
|
|
18078
18628
|
} catch {
|
|
18079
18629
|
}
|
|
18080
18630
|
}
|
|
@@ -18125,17 +18675,17 @@ RAW: ${raw}
|
|
|
18125
18675
|
const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
|
|
18126
18676
|
if (skillPinCfg.enabled && safeSessionId) {
|
|
18127
18677
|
try {
|
|
18128
|
-
const sessionsDir =
|
|
18129
|
-
const flagPath =
|
|
18678
|
+
const sessionsDir = import_path35.default.join(import_os30.default.homedir(), ".node9", "skill-sessions");
|
|
18679
|
+
const flagPath = import_path35.default.join(sessionsDir, `${safeSessionId}.json`);
|
|
18130
18680
|
let flag = null;
|
|
18131
18681
|
try {
|
|
18132
|
-
flag = JSON.parse(
|
|
18682
|
+
flag = JSON.parse(import_fs34.default.readFileSync(flagPath, "utf-8"));
|
|
18133
18683
|
} catch {
|
|
18134
18684
|
}
|
|
18135
18685
|
const writeFlag = (data2) => {
|
|
18136
18686
|
try {
|
|
18137
|
-
|
|
18138
|
-
|
|
18687
|
+
import_fs34.default.mkdirSync(sessionsDir, { recursive: true });
|
|
18688
|
+
import_fs34.default.writeFileSync(
|
|
18139
18689
|
flagPath,
|
|
18140
18690
|
JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
|
|
18141
18691
|
{ mode: 384 }
|
|
@@ -18146,8 +18696,8 @@ RAW: ${raw}
|
|
|
18146
18696
|
const sendSkillWarn = (detail, recoveryCmd) => {
|
|
18147
18697
|
let ttyFd = null;
|
|
18148
18698
|
try {
|
|
18149
|
-
ttyFd =
|
|
18150
|
-
const w = (line) =>
|
|
18699
|
+
ttyFd = import_fs34.default.openSync("/dev/tty", "w");
|
|
18700
|
+
const w = (line) => import_fs34.default.writeSync(ttyFd, line + "\n");
|
|
18151
18701
|
w(import_chalk9.default.yellow(`
|
|
18152
18702
|
\u26A0\uFE0F Node9: installed skill drift detected`));
|
|
18153
18703
|
w(import_chalk9.default.gray(` ${detail}`));
|
|
@@ -18162,7 +18712,7 @@ RAW: ${raw}
|
|
|
18162
18712
|
} finally {
|
|
18163
18713
|
if (ttyFd !== null)
|
|
18164
18714
|
try {
|
|
18165
|
-
|
|
18715
|
+
import_fs34.default.closeSync(ttyFd);
|
|
18166
18716
|
} catch {
|
|
18167
18717
|
}
|
|
18168
18718
|
}
|
|
@@ -18178,7 +18728,7 @@ RAW: ${raw}
|
|
|
18178
18728
|
return;
|
|
18179
18729
|
}
|
|
18180
18730
|
if (!flag || flag.state !== "verified" && flag.state !== "warned") {
|
|
18181
|
-
const absoluteCwd = typeof payloadCwd === "string" &&
|
|
18731
|
+
const absoluteCwd = typeof payloadCwd === "string" && import_path35.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18182
18732
|
const extraRoots = skillPinCfg.roots;
|
|
18183
18733
|
const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
|
|
18184
18734
|
const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
|
|
@@ -18219,10 +18769,10 @@ RAW: ${raw}
|
|
|
18219
18769
|
}
|
|
18220
18770
|
try {
|
|
18221
18771
|
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
18222
|
-
for (const name of
|
|
18223
|
-
const p =
|
|
18772
|
+
for (const name of import_fs34.default.readdirSync(sessionsDir)) {
|
|
18773
|
+
const p = import_path35.default.join(sessionsDir, name);
|
|
18224
18774
|
try {
|
|
18225
|
-
if (
|
|
18775
|
+
if (import_fs34.default.statSync(p).mtimeMs < cutoff) import_fs34.default.unlinkSync(p);
|
|
18226
18776
|
} catch {
|
|
18227
18777
|
}
|
|
18228
18778
|
}
|
|
@@ -18232,9 +18782,9 @@ RAW: ${raw}
|
|
|
18232
18782
|
} catch (err2) {
|
|
18233
18783
|
if (process.env.NODE9_DEBUG === "1") {
|
|
18234
18784
|
try {
|
|
18235
|
-
const dbg =
|
|
18785
|
+
const dbg = import_path35.default.join(import_os30.default.homedir(), ".node9", "hook-debug.log");
|
|
18236
18786
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18237
|
-
|
|
18787
|
+
import_fs34.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
|
|
18238
18788
|
`);
|
|
18239
18789
|
} catch {
|
|
18240
18790
|
}
|
|
@@ -18244,7 +18794,7 @@ RAW: ${raw}
|
|
|
18244
18794
|
if (shouldSnapshot(toolName, toolInput, config)) {
|
|
18245
18795
|
await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
|
|
18246
18796
|
}
|
|
18247
|
-
const safeCwdForAuth = typeof payloadCwd === "string" &&
|
|
18797
|
+
const safeCwdForAuth = typeof payloadCwd === "string" && import_path35.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18248
18798
|
const result = await authorizeHeadless(toolName, toolInput, meta, {
|
|
18249
18799
|
cwd: safeCwdForAuth
|
|
18250
18800
|
});
|
|
@@ -18256,12 +18806,12 @@ RAW: ${raw}
|
|
|
18256
18806
|
}
|
|
18257
18807
|
if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
|
|
18258
18808
|
try {
|
|
18259
|
-
const tty =
|
|
18260
|
-
|
|
18809
|
+
const tty = import_fs34.default.openSync("/dev/tty", "w");
|
|
18810
|
+
import_fs34.default.writeSync(
|
|
18261
18811
|
tty,
|
|
18262
18812
|
import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
|
|
18263
18813
|
);
|
|
18264
|
-
|
|
18814
|
+
import_fs34.default.closeSync(tty);
|
|
18265
18815
|
} catch {
|
|
18266
18816
|
}
|
|
18267
18817
|
const daemonReady = await autoStartDaemonAndWait();
|
|
@@ -18288,9 +18838,9 @@ RAW: ${raw}
|
|
|
18288
18838
|
});
|
|
18289
18839
|
} catch (err2) {
|
|
18290
18840
|
if (process.env.NODE9_DEBUG === "1") {
|
|
18291
|
-
const logPath =
|
|
18841
|
+
const logPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "hook-debug.log");
|
|
18292
18842
|
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
18293
|
-
|
|
18843
|
+
import_fs34.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
|
|
18294
18844
|
`);
|
|
18295
18845
|
}
|
|
18296
18846
|
process.exit(0);
|
|
@@ -18324,9 +18874,9 @@ RAW: ${raw}
|
|
|
18324
18874
|
}
|
|
18325
18875
|
|
|
18326
18876
|
// src/cli/commands/log.ts
|
|
18327
|
-
var
|
|
18328
|
-
var
|
|
18329
|
-
var
|
|
18877
|
+
var import_fs35 = __toESM(require("fs"));
|
|
18878
|
+
var import_path36 = __toESM(require("path"));
|
|
18879
|
+
var import_os31 = __toESM(require("os"));
|
|
18330
18880
|
init_audit();
|
|
18331
18881
|
init_config();
|
|
18332
18882
|
init_daemon();
|
|
@@ -18421,10 +18971,10 @@ function registerLogCommand(program2) {
|
|
|
18421
18971
|
if (rawToolName !== tool) entry.agentToolName = rawToolName;
|
|
18422
18972
|
const payloadSessionId = payload.session_id ?? payload.conversationId;
|
|
18423
18973
|
if (payloadSessionId) entry.sessionId = payloadSessionId;
|
|
18424
|
-
const logPath =
|
|
18425
|
-
if (!
|
|
18426
|
-
|
|
18427
|
-
|
|
18974
|
+
const logPath = import_path36.default.join(import_os31.default.homedir(), ".node9", "audit.log");
|
|
18975
|
+
if (!import_fs35.default.existsSync(import_path36.default.dirname(logPath)))
|
|
18976
|
+
import_fs35.default.mkdirSync(import_path36.default.dirname(logPath), { recursive: true });
|
|
18977
|
+
import_fs35.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
18428
18978
|
if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
|
|
18429
18979
|
const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
18430
18980
|
if (command) {
|
|
@@ -18458,7 +19008,7 @@ function registerLogCommand(program2) {
|
|
|
18458
19008
|
}
|
|
18459
19009
|
}
|
|
18460
19010
|
const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
|
|
18461
|
-
const safeCwd = typeof payloadCwd === "string" &&
|
|
19011
|
+
const safeCwd = typeof payloadCwd === "string" && import_path36.default.isAbsolute(payloadCwd) ? payloadCwd : void 0;
|
|
18462
19012
|
const config = getConfig(safeCwd);
|
|
18463
19013
|
if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
|
|
18464
19014
|
const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
|
|
@@ -18479,9 +19029,9 @@ function registerLogCommand(program2) {
|
|
|
18479
19029
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
18480
19030
|
process.stderr.write(`[Node9] audit log error: ${msg}
|
|
18481
19031
|
`);
|
|
18482
|
-
const debugPath =
|
|
19032
|
+
const debugPath = import_path36.default.join(import_os31.default.homedir(), ".node9", "hook-debug.log");
|
|
18483
19033
|
try {
|
|
18484
|
-
|
|
19034
|
+
import_fs35.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
|
|
18485
19035
|
`);
|
|
18486
19036
|
} catch {
|
|
18487
19037
|
}
|
|
@@ -18881,15 +19431,15 @@ function registerConfigShowCommand(program2) {
|
|
|
18881
19431
|
|
|
18882
19432
|
// src/cli/commands/doctor.ts
|
|
18883
19433
|
var import_chalk11 = __toESM(require("chalk"));
|
|
18884
|
-
var
|
|
18885
|
-
var
|
|
18886
|
-
var
|
|
19434
|
+
var import_fs36 = __toESM(require("fs"));
|
|
19435
|
+
var import_path37 = __toESM(require("path"));
|
|
19436
|
+
var import_os32 = __toESM(require("os"));
|
|
18887
19437
|
var import_child_process8 = require("child_process");
|
|
18888
19438
|
init_daemon();
|
|
18889
19439
|
init_config();
|
|
18890
19440
|
function registerDoctorCommand(program2, version2) {
|
|
18891
19441
|
program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
|
|
18892
|
-
const homeDir2 =
|
|
19442
|
+
const homeDir2 = import_os32.default.homedir();
|
|
18893
19443
|
let failures = 0;
|
|
18894
19444
|
function pass(msg) {
|
|
18895
19445
|
console.log(import_chalk11.default.green(" \u2705 ") + msg);
|
|
@@ -18938,10 +19488,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18938
19488
|
);
|
|
18939
19489
|
}
|
|
18940
19490
|
section("Configuration");
|
|
18941
|
-
const globalConfigPath =
|
|
18942
|
-
if (
|
|
19491
|
+
const globalConfigPath = import_path37.default.join(homeDir2, ".node9", "config.json");
|
|
19492
|
+
if (import_fs36.default.existsSync(globalConfigPath)) {
|
|
18943
19493
|
try {
|
|
18944
|
-
JSON.parse(
|
|
19494
|
+
JSON.parse(import_fs36.default.readFileSync(globalConfigPath, "utf-8"));
|
|
18945
19495
|
pass("~/.node9/config.json found and valid");
|
|
18946
19496
|
} catch {
|
|
18947
19497
|
fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
|
|
@@ -18949,10 +19499,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18949
19499
|
} else {
|
|
18950
19500
|
warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
|
|
18951
19501
|
}
|
|
18952
|
-
const projectConfigPath =
|
|
18953
|
-
if (
|
|
19502
|
+
const projectConfigPath = import_path37.default.join(process.cwd(), "node9.config.json");
|
|
19503
|
+
if (import_fs36.default.existsSync(projectConfigPath)) {
|
|
18954
19504
|
try {
|
|
18955
|
-
JSON.parse(
|
|
19505
|
+
JSON.parse(import_fs36.default.readFileSync(projectConfigPath, "utf-8"));
|
|
18956
19506
|
pass("node9.config.json found and valid (project)");
|
|
18957
19507
|
} catch {
|
|
18958
19508
|
fail(
|
|
@@ -18961,8 +19511,8 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18961
19511
|
);
|
|
18962
19512
|
}
|
|
18963
19513
|
}
|
|
18964
|
-
const credsPath =
|
|
18965
|
-
if (
|
|
19514
|
+
const credsPath = import_path37.default.join(homeDir2, ".node9", "credentials.json");
|
|
19515
|
+
if (import_fs36.default.existsSync(credsPath)) {
|
|
18966
19516
|
pass("Cloud credentials found (~/.node9/credentials.json)");
|
|
18967
19517
|
} else {
|
|
18968
19518
|
warn(
|
|
@@ -18971,10 +19521,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18971
19521
|
);
|
|
18972
19522
|
}
|
|
18973
19523
|
section("Agent Hooks");
|
|
18974
|
-
const claudeSettingsPath =
|
|
18975
|
-
if (
|
|
19524
|
+
const claudeSettingsPath = import_path37.default.join(homeDir2, ".claude", "settings.json");
|
|
19525
|
+
if (import_fs36.default.existsSync(claudeSettingsPath)) {
|
|
18976
19526
|
try {
|
|
18977
|
-
const cs = JSON.parse(
|
|
19527
|
+
const cs = JSON.parse(import_fs36.default.readFileSync(claudeSettingsPath, "utf-8"));
|
|
18978
19528
|
const hasHook = cs.hooks?.PreToolUse?.some(
|
|
18979
19529
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
18980
19530
|
);
|
|
@@ -18990,10 +19540,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
18990
19540
|
} else {
|
|
18991
19541
|
warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
|
|
18992
19542
|
}
|
|
18993
|
-
const geminiSettingsPath =
|
|
18994
|
-
if (
|
|
19543
|
+
const geminiSettingsPath = import_path37.default.join(homeDir2, ".gemini", "settings.json");
|
|
19544
|
+
if (import_fs36.default.existsSync(geminiSettingsPath)) {
|
|
18995
19545
|
try {
|
|
18996
|
-
const gs = JSON.parse(
|
|
19546
|
+
const gs = JSON.parse(import_fs36.default.readFileSync(geminiSettingsPath, "utf-8"));
|
|
18997
19547
|
const hasHook = gs.hooks?.BeforeTool?.some(
|
|
18998
19548
|
(m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
|
|
18999
19549
|
);
|
|
@@ -19009,10 +19559,10 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19009
19559
|
} else {
|
|
19010
19560
|
warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
|
|
19011
19561
|
}
|
|
19012
|
-
const cursorHooksPath =
|
|
19013
|
-
if (
|
|
19562
|
+
const cursorHooksPath = import_path37.default.join(homeDir2, ".cursor", "hooks.json");
|
|
19563
|
+
if (import_fs36.default.existsSync(cursorHooksPath)) {
|
|
19014
19564
|
try {
|
|
19015
|
-
const cur = JSON.parse(
|
|
19565
|
+
const cur = JSON.parse(import_fs36.default.readFileSync(cursorHooksPath, "utf-8"));
|
|
19016
19566
|
const hasHook = cur.hooks?.preToolUse?.some(
|
|
19017
19567
|
(h) => h.command?.includes("node9") || h.command?.includes("cli.js")
|
|
19018
19568
|
);
|
|
@@ -19043,7 +19593,7 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19043
19593
|
try {
|
|
19044
19594
|
const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
|
|
19045
19595
|
const cfg = getConfig();
|
|
19046
|
-
const creds =
|
|
19596
|
+
const creds = import_fs36.default.existsSync(import_path37.default.join(import_os32.default.homedir(), ".node9", "credentials.json"));
|
|
19047
19597
|
if (!creds) {
|
|
19048
19598
|
warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
|
|
19049
19599
|
} else if (!cfg.settings.approvers.cloud) {
|
|
@@ -19093,9 +19643,9 @@ function registerDoctorCommand(program2, version2) {
|
|
|
19093
19643
|
|
|
19094
19644
|
// src/cli/commands/audit.ts
|
|
19095
19645
|
var import_chalk12 = __toESM(require("chalk"));
|
|
19096
|
-
var
|
|
19097
|
-
var
|
|
19098
|
-
var
|
|
19646
|
+
var import_fs37 = __toESM(require("fs"));
|
|
19647
|
+
var import_path38 = __toESM(require("path"));
|
|
19648
|
+
var import_os33 = __toESM(require("os"));
|
|
19099
19649
|
function formatRelativeTime(timestamp) {
|
|
19100
19650
|
const diff = Date.now() - new Date(timestamp).getTime();
|
|
19101
19651
|
const sec = Math.floor(diff / 1e3);
|
|
@@ -19108,14 +19658,14 @@ function formatRelativeTime(timestamp) {
|
|
|
19108
19658
|
}
|
|
19109
19659
|
function registerAuditCommand(program2) {
|
|
19110
19660
|
program2.command("audit").description("View local execution audit log").option("--tail <n>", "Number of entries to show", "20").option("--tool <pattern>", "Filter by tool name (substring match)").option("--deny", "Show only denied actions").option("--json", "Output raw JSON").action((options) => {
|
|
19111
|
-
const logPath =
|
|
19112
|
-
if (!
|
|
19661
|
+
const logPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "audit.log");
|
|
19662
|
+
if (!import_fs37.default.existsSync(logPath)) {
|
|
19113
19663
|
console.log(
|
|
19114
19664
|
import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
|
|
19115
19665
|
);
|
|
19116
19666
|
return;
|
|
19117
19667
|
}
|
|
19118
|
-
const raw =
|
|
19668
|
+
const raw = import_fs37.default.readFileSync(logPath, "utf-8");
|
|
19119
19669
|
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
19120
19670
|
let entries = lines.flatMap((line) => {
|
|
19121
19671
|
try {
|
|
@@ -19171,9 +19721,9 @@ function registerAuditCommand(program2) {
|
|
|
19171
19721
|
var import_chalk13 = __toESM(require("chalk"));
|
|
19172
19722
|
|
|
19173
19723
|
// src/cli/aggregate/report-audit.ts
|
|
19174
|
-
var
|
|
19175
|
-
var
|
|
19176
|
-
var
|
|
19724
|
+
var import_fs38 = __toESM(require("fs"));
|
|
19725
|
+
var import_os34 = __toESM(require("os"));
|
|
19726
|
+
var import_path39 = __toESM(require("path"));
|
|
19177
19727
|
init_costSync();
|
|
19178
19728
|
init_litellm();
|
|
19179
19729
|
var TEST_COMMAND_RE3 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
@@ -19255,8 +19805,8 @@ function getDateRange(period, now) {
|
|
|
19255
19805
|
}
|
|
19256
19806
|
}
|
|
19257
19807
|
function parseAuditLog(logPath) {
|
|
19258
|
-
if (!
|
|
19259
|
-
const raw =
|
|
19808
|
+
if (!import_fs38.default.existsSync(logPath)) return [];
|
|
19809
|
+
const raw = import_fs38.default.readFileSync(logPath, "utf-8");
|
|
19260
19810
|
return raw.split("\n").flatMap((line) => {
|
|
19261
19811
|
if (!line.trim()) return [];
|
|
19262
19812
|
try {
|
|
@@ -19316,25 +19866,25 @@ function freezeClaudeCost(acc) {
|
|
|
19316
19866
|
};
|
|
19317
19867
|
}
|
|
19318
19868
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
19319
|
-
const projPath =
|
|
19869
|
+
const projPath = import_path39.default.join(projectsDir, proj);
|
|
19320
19870
|
let files;
|
|
19321
19871
|
try {
|
|
19322
|
-
const stat =
|
|
19872
|
+
const stat = import_fs38.default.statSync(projPath);
|
|
19323
19873
|
if (!stat.isDirectory()) return;
|
|
19324
|
-
files =
|
|
19874
|
+
files = import_fs38.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
19325
19875
|
} catch {
|
|
19326
19876
|
return;
|
|
19327
19877
|
}
|
|
19328
19878
|
const startMs = start.getTime();
|
|
19329
19879
|
for (const file of files) {
|
|
19330
|
-
const filePath =
|
|
19880
|
+
const filePath = import_path39.default.join(projPath, file);
|
|
19331
19881
|
try {
|
|
19332
|
-
if (
|
|
19882
|
+
if (import_fs38.default.statSync(filePath).mtimeMs < startMs) continue;
|
|
19333
19883
|
} catch {
|
|
19334
19884
|
continue;
|
|
19335
19885
|
}
|
|
19336
19886
|
try {
|
|
19337
|
-
const raw =
|
|
19887
|
+
const raw = import_fs38.default.readFileSync(filePath, "utf-8");
|
|
19338
19888
|
for (const line of raw.split("\n")) {
|
|
19339
19889
|
if (!line.trim()) continue;
|
|
19340
19890
|
let entry;
|
|
@@ -19384,10 +19934,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
19384
19934
|
}
|
|
19385
19935
|
function loadClaudeCost(start, end, projectsDir) {
|
|
19386
19936
|
const acc = emptyClaudeCostAccumulator();
|
|
19387
|
-
if (!
|
|
19937
|
+
if (!import_fs38.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
19388
19938
|
let dirs;
|
|
19389
19939
|
try {
|
|
19390
|
-
dirs =
|
|
19940
|
+
dirs = import_fs38.default.readdirSync(projectsDir);
|
|
19391
19941
|
} catch {
|
|
19392
19942
|
return freezeClaudeCost(acc);
|
|
19393
19943
|
}
|
|
@@ -19399,7 +19949,7 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
19399
19949
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
19400
19950
|
let lines;
|
|
19401
19951
|
try {
|
|
19402
|
-
lines =
|
|
19952
|
+
lines = import_fs38.default.readFileSync(filePath, "utf-8").split("\n");
|
|
19403
19953
|
} catch {
|
|
19404
19954
|
return;
|
|
19405
19955
|
}
|
|
@@ -19444,31 +19994,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
19444
19994
|
}
|
|
19445
19995
|
function listCodexSessionFiles(sessionsBase) {
|
|
19446
19996
|
const jsonlFiles = [];
|
|
19447
|
-
if (!
|
|
19997
|
+
if (!import_fs38.default.existsSync(sessionsBase)) return jsonlFiles;
|
|
19448
19998
|
try {
|
|
19449
|
-
for (const year of
|
|
19450
|
-
const yearPath =
|
|
19999
|
+
for (const year of import_fs38.default.readdirSync(sessionsBase)) {
|
|
20000
|
+
const yearPath = import_path39.default.join(sessionsBase, year);
|
|
19451
20001
|
try {
|
|
19452
|
-
if (!
|
|
20002
|
+
if (!import_fs38.default.statSync(yearPath).isDirectory()) continue;
|
|
19453
20003
|
} catch {
|
|
19454
20004
|
continue;
|
|
19455
20005
|
}
|
|
19456
|
-
for (const month of
|
|
19457
|
-
const monthPath =
|
|
20006
|
+
for (const month of import_fs38.default.readdirSync(yearPath)) {
|
|
20007
|
+
const monthPath = import_path39.default.join(yearPath, month);
|
|
19458
20008
|
try {
|
|
19459
|
-
if (!
|
|
20009
|
+
if (!import_fs38.default.statSync(monthPath).isDirectory()) continue;
|
|
19460
20010
|
} catch {
|
|
19461
20011
|
continue;
|
|
19462
20012
|
}
|
|
19463
|
-
for (const day of
|
|
19464
|
-
const dayPath =
|
|
20013
|
+
for (const day of import_fs38.default.readdirSync(monthPath)) {
|
|
20014
|
+
const dayPath = import_path39.default.join(monthPath, day);
|
|
19465
20015
|
try {
|
|
19466
|
-
if (!
|
|
20016
|
+
if (!import_fs38.default.statSync(dayPath).isDirectory()) continue;
|
|
19467
20017
|
} catch {
|
|
19468
20018
|
continue;
|
|
19469
20019
|
}
|
|
19470
|
-
for (const file of
|
|
19471
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
20020
|
+
for (const file of import_fs38.default.readdirSync(dayPath)) {
|
|
20021
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path39.default.join(dayPath, file));
|
|
19472
20022
|
}
|
|
19473
20023
|
}
|
|
19474
20024
|
}
|
|
@@ -19521,13 +20071,13 @@ function freezeGeminiCost(acc) {
|
|
|
19521
20071
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
19522
20072
|
const startMs = start.getTime();
|
|
19523
20073
|
try {
|
|
19524
|
-
if (
|
|
20074
|
+
if (import_fs38.default.statSync(filePath).mtimeMs < startMs) return;
|
|
19525
20075
|
} catch {
|
|
19526
20076
|
return;
|
|
19527
20077
|
}
|
|
19528
20078
|
let raw;
|
|
19529
20079
|
try {
|
|
19530
|
-
raw =
|
|
20080
|
+
raw = import_fs38.default.readFileSync(filePath, "utf-8");
|
|
19531
20081
|
} catch {
|
|
19532
20082
|
return;
|
|
19533
20083
|
}
|
|
@@ -19576,30 +20126,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
19576
20126
|
const out = [];
|
|
19577
20127
|
let dirs;
|
|
19578
20128
|
try {
|
|
19579
|
-
if (!
|
|
19580
|
-
dirs =
|
|
20129
|
+
if (!import_fs38.default.statSync(geminiTmpDir).isDirectory()) return out;
|
|
20130
|
+
dirs = import_fs38.default.readdirSync(geminiTmpDir);
|
|
19581
20131
|
} catch {
|
|
19582
20132
|
return out;
|
|
19583
20133
|
}
|
|
19584
20134
|
for (const proj of dirs) {
|
|
19585
|
-
const chatsDir =
|
|
20135
|
+
const chatsDir = import_path39.default.join(geminiTmpDir, proj, "chats");
|
|
19586
20136
|
let files;
|
|
19587
20137
|
try {
|
|
19588
|
-
if (!
|
|
19589
|
-
files =
|
|
20138
|
+
if (!import_fs38.default.statSync(chatsDir).isDirectory()) continue;
|
|
20139
|
+
files = import_fs38.default.readdirSync(chatsDir);
|
|
19590
20140
|
} catch {
|
|
19591
20141
|
continue;
|
|
19592
20142
|
}
|
|
19593
20143
|
for (const f of files) {
|
|
19594
20144
|
if (!f.endsWith(".jsonl")) continue;
|
|
19595
|
-
out.push({ projectKey: proj, file:
|
|
20145
|
+
out.push({ projectKey: proj, file: import_path39.default.join(chatsDir, f) });
|
|
19596
20146
|
}
|
|
19597
20147
|
}
|
|
19598
20148
|
return out;
|
|
19599
20149
|
}
|
|
19600
20150
|
function loadGeminiCost(start, end, geminiTmpDir) {
|
|
19601
20151
|
const acc = emptyGeminiAccumulator();
|
|
19602
|
-
if (!
|
|
20152
|
+
if (!import_fs38.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
|
|
19603
20153
|
for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
|
|
19604
20154
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
19605
20155
|
}
|
|
@@ -19607,11 +20157,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
|
|
|
19607
20157
|
}
|
|
19608
20158
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
19609
20159
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
19610
|
-
const auditLogPath = opts.auditLogPath ??
|
|
19611
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
19612
|
-
const codexSessionsDir = opts.codexSessionsDir ??
|
|
19613
|
-
const geminiTmpDir = opts.geminiTmpDir ??
|
|
19614
|
-
const hasAuditFile =
|
|
20160
|
+
const auditLogPath = opts.auditLogPath ?? import_path39.default.join(import_os34.default.homedir(), ".node9", "audit.log");
|
|
20161
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? import_path39.default.join(import_os34.default.homedir(), ".claude", "projects");
|
|
20162
|
+
const codexSessionsDir = opts.codexSessionsDir ?? import_path39.default.join(import_os34.default.homedir(), ".codex", "sessions");
|
|
20163
|
+
const geminiTmpDir = opts.geminiTmpDir ?? import_path39.default.join(import_os34.default.homedir(), ".gemini", "tmp");
|
|
20164
|
+
const hasAuditFile = import_fs38.default.existsSync(auditLogPath);
|
|
19615
20165
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
|
|
19616
20166
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
19617
20167
|
const { start, end } = getDateRange(period, now);
|
|
@@ -20307,14 +20857,14 @@ function registerDaemonCommand(program2) {
|
|
|
20307
20857
|
|
|
20308
20858
|
// src/cli/commands/status.ts
|
|
20309
20859
|
var import_chalk15 = __toESM(require("chalk"));
|
|
20310
|
-
var
|
|
20311
|
-
var
|
|
20312
|
-
var
|
|
20860
|
+
var import_fs39 = __toESM(require("fs"));
|
|
20861
|
+
var import_path40 = __toESM(require("path"));
|
|
20862
|
+
var import_os35 = __toESM(require("os"));
|
|
20313
20863
|
init_core();
|
|
20314
20864
|
init_daemon();
|
|
20315
20865
|
function readJson2(filePath) {
|
|
20316
20866
|
try {
|
|
20317
|
-
if (
|
|
20867
|
+
if (import_fs39.default.existsSync(filePath)) return JSON.parse(import_fs39.default.readFileSync(filePath, "utf-8"));
|
|
20318
20868
|
} catch {
|
|
20319
20869
|
}
|
|
20320
20870
|
return null;
|
|
@@ -20379,28 +20929,28 @@ function registerStatusCommand(program2) {
|
|
|
20379
20929
|
console.log("");
|
|
20380
20930
|
const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
|
|
20381
20931
|
console.log(` Mode: ${modeLabel}`);
|
|
20382
|
-
const projectConfig =
|
|
20383
|
-
const globalConfig =
|
|
20932
|
+
const projectConfig = import_path40.default.join(process.cwd(), "node9.config.json");
|
|
20933
|
+
const globalConfig = import_path40.default.join(import_os35.default.homedir(), ".node9", "config.json");
|
|
20384
20934
|
console.log(
|
|
20385
|
-
` Local: ${
|
|
20935
|
+
` Local: ${import_fs39.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
|
|
20386
20936
|
);
|
|
20387
20937
|
console.log(
|
|
20388
|
-
` Global: ${
|
|
20938
|
+
` Global: ${import_fs39.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
|
|
20389
20939
|
);
|
|
20390
20940
|
if (mergedConfig.policy.sandboxPaths.length > 0) {
|
|
20391
20941
|
console.log(
|
|
20392
20942
|
` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
|
|
20393
20943
|
);
|
|
20394
20944
|
}
|
|
20395
|
-
const homeDir2 =
|
|
20945
|
+
const homeDir2 = import_os35.default.homedir();
|
|
20396
20946
|
const claudeSettings = readJson2(
|
|
20397
|
-
|
|
20947
|
+
import_path40.default.join(homeDir2, ".claude", "settings.json")
|
|
20398
20948
|
);
|
|
20399
|
-
const claudeConfig = readJson2(
|
|
20949
|
+
const claudeConfig = readJson2(import_path40.default.join(homeDir2, ".claude.json"));
|
|
20400
20950
|
const geminiSettings = readJson2(
|
|
20401
|
-
|
|
20951
|
+
import_path40.default.join(homeDir2, ".gemini", "settings.json")
|
|
20402
20952
|
);
|
|
20403
|
-
const cursorConfig = readJson2(
|
|
20953
|
+
const cursorConfig = readJson2(import_path40.default.join(homeDir2, ".cursor", "mcp.json"));
|
|
20404
20954
|
const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
|
|
20405
20955
|
if (agentFound) {
|
|
20406
20956
|
console.log("");
|
|
@@ -20459,9 +21009,9 @@ function registerStatusCommand(program2) {
|
|
|
20459
21009
|
|
|
20460
21010
|
// src/cli/commands/init.ts
|
|
20461
21011
|
var import_chalk16 = __toESM(require("chalk"));
|
|
20462
|
-
var
|
|
20463
|
-
var
|
|
20464
|
-
var
|
|
21012
|
+
var import_fs40 = __toESM(require("fs"));
|
|
21013
|
+
var import_path41 = __toESM(require("path"));
|
|
21014
|
+
var import_os36 = __toESM(require("os"));
|
|
20465
21015
|
var import_https4 = __toESM(require("https"));
|
|
20466
21016
|
init_core();
|
|
20467
21017
|
init_setup();
|
|
@@ -20551,16 +21101,16 @@ function registerInitCommand(program2) {
|
|
|
20551
21101
|
}
|
|
20552
21102
|
console.log("");
|
|
20553
21103
|
}
|
|
20554
|
-
const configPath =
|
|
20555
|
-
const isFirstInstall = !
|
|
20556
|
-
if (
|
|
21104
|
+
const configPath = import_path41.default.join(import_os36.default.homedir(), ".node9", "config.json");
|
|
21105
|
+
const isFirstInstall = !import_fs40.default.existsSync(configPath);
|
|
21106
|
+
if (import_fs40.default.existsSync(configPath) && !options.force) {
|
|
20557
21107
|
try {
|
|
20558
|
-
const existing = JSON.parse(
|
|
21108
|
+
const existing = JSON.parse(import_fs40.default.readFileSync(configPath, "utf-8"));
|
|
20559
21109
|
const settings = existing.settings ?? {};
|
|
20560
21110
|
if (settings.mode !== chosenMode) {
|
|
20561
21111
|
settings.mode = chosenMode;
|
|
20562
21112
|
existing.settings = settings;
|
|
20563
|
-
|
|
21113
|
+
import_fs40.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
20564
21114
|
console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
|
|
20565
21115
|
} else {
|
|
20566
21116
|
console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
|
|
@@ -20573,9 +21123,9 @@ function registerInitCommand(program2) {
|
|
|
20573
21123
|
...DEFAULT_CONFIG,
|
|
20574
21124
|
settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
|
|
20575
21125
|
};
|
|
20576
|
-
const dir =
|
|
20577
|
-
if (!
|
|
20578
|
-
|
|
21126
|
+
const dir = import_path41.default.dirname(configPath);
|
|
21127
|
+
if (!import_fs40.default.existsSync(dir)) import_fs40.default.mkdirSync(dir, { recursive: true });
|
|
21128
|
+
import_fs40.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
|
|
20579
21129
|
console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
|
|
20580
21130
|
console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
|
|
20581
21131
|
}
|
|
@@ -20680,7 +21230,7 @@ function registerInitCommand(program2) {
|
|
|
20680
21230
|
}
|
|
20681
21231
|
|
|
20682
21232
|
// src/cli/commands/undo.ts
|
|
20683
|
-
var
|
|
21233
|
+
var import_path42 = __toESM(require("path"));
|
|
20684
21234
|
var import_chalk18 = __toESM(require("chalk"));
|
|
20685
21235
|
|
|
20686
21236
|
// src/tui/undo-navigator.ts
|
|
@@ -20839,7 +21389,7 @@ function findMatchingCwd(startDir, history) {
|
|
|
20839
21389
|
let dir = startDir;
|
|
20840
21390
|
while (true) {
|
|
20841
21391
|
if (cwds.has(dir)) return dir;
|
|
20842
|
-
const parent =
|
|
21392
|
+
const parent = import_path42.default.dirname(dir);
|
|
20843
21393
|
if (parent === dir) return null;
|
|
20844
21394
|
dir = parent;
|
|
20845
21395
|
}
|
|
@@ -21415,9 +21965,9 @@ function registerMcpGatewayCommand(program2) {
|
|
|
21415
21965
|
|
|
21416
21966
|
// src/mcp-server/index.ts
|
|
21417
21967
|
var import_readline5 = __toESM(require("readline"));
|
|
21418
|
-
var
|
|
21419
|
-
var
|
|
21420
|
-
var
|
|
21968
|
+
var import_fs41 = __toESM(require("fs"));
|
|
21969
|
+
var import_os37 = __toESM(require("os"));
|
|
21970
|
+
var import_path43 = __toESM(require("path"));
|
|
21421
21971
|
var import_child_process11 = require("child_process");
|
|
21422
21972
|
init_core();
|
|
21423
21973
|
init_daemon();
|
|
@@ -21668,13 +22218,13 @@ function handleStatus() {
|
|
|
21668
22218
|
lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
|
|
21669
22219
|
lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
|
|
21670
22220
|
lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
|
|
21671
|
-
const projectConfig =
|
|
21672
|
-
const globalConfig =
|
|
22221
|
+
const projectConfig = import_path43.default.join(process.cwd(), "node9.config.json");
|
|
22222
|
+
const globalConfig = import_path43.default.join(import_os37.default.homedir(), ".node9", "config.json");
|
|
21673
22223
|
lines.push(
|
|
21674
|
-
`Project config (node9.config.json): ${
|
|
22224
|
+
`Project config (node9.config.json): ${import_fs41.default.existsSync(projectConfig) ? "present" : "not found"}`
|
|
21675
22225
|
);
|
|
21676
22226
|
lines.push(
|
|
21677
|
-
`Global config (~/.node9/config.json): ${
|
|
22227
|
+
`Global config (~/.node9/config.json): ${import_fs41.default.existsSync(globalConfig) ? "present" : "not found"}`
|
|
21678
22228
|
);
|
|
21679
22229
|
return lines.join("\n");
|
|
21680
22230
|
}
|
|
@@ -21748,21 +22298,21 @@ function handleShieldDisable(args) {
|
|
|
21748
22298
|
writeActiveShields(active.filter((s) => s !== name));
|
|
21749
22299
|
return `Shield "${name}" disabled.`;
|
|
21750
22300
|
}
|
|
21751
|
-
var GLOBAL_CONFIG_PATH =
|
|
22301
|
+
var GLOBAL_CONFIG_PATH = import_path43.default.join(import_os37.default.homedir(), ".node9", "config.json");
|
|
21752
22302
|
var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
|
|
21753
22303
|
function readGlobalConfigRaw() {
|
|
21754
22304
|
try {
|
|
21755
|
-
if (
|
|
21756
|
-
return JSON.parse(
|
|
22305
|
+
if (import_fs41.default.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
22306
|
+
return JSON.parse(import_fs41.default.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
21757
22307
|
}
|
|
21758
22308
|
} catch {
|
|
21759
22309
|
}
|
|
21760
22310
|
return {};
|
|
21761
22311
|
}
|
|
21762
22312
|
function writeGlobalConfigRaw(data) {
|
|
21763
|
-
const dir =
|
|
21764
|
-
if (!
|
|
21765
|
-
|
|
22313
|
+
const dir = import_path43.default.dirname(GLOBAL_CONFIG_PATH);
|
|
22314
|
+
if (!import_fs41.default.existsSync(dir)) import_fs41.default.mkdirSync(dir, { recursive: true });
|
|
22315
|
+
import_fs41.default.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
|
|
21766
22316
|
}
|
|
21767
22317
|
function handleApproverList() {
|
|
21768
22318
|
const config = getConfig();
|
|
@@ -21806,9 +22356,9 @@ function handleApproverSet(args) {
|
|
|
21806
22356
|
function handleAuditGet(args) {
|
|
21807
22357
|
const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
|
|
21808
22358
|
const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
|
|
21809
|
-
const auditPath =
|
|
21810
|
-
if (!
|
|
21811
|
-
const rawLines =
|
|
22359
|
+
const auditPath = import_path43.default.join(import_os37.default.homedir(), ".node9", "audit.log");
|
|
22360
|
+
if (!import_fs41.default.existsSync(auditPath)) return "No audit log found.";
|
|
22361
|
+
const rawLines = import_fs41.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
21812
22362
|
const parsed = [];
|
|
21813
22363
|
for (const line of rawLines) {
|
|
21814
22364
|
try {
|
|
@@ -22143,7 +22693,7 @@ function registerTrustCommand(program2) {
|
|
|
22143
22693
|
// src/cli/commands/mcp-pin.ts
|
|
22144
22694
|
var import_chalk21 = __toESM(require("chalk"));
|
|
22145
22695
|
init_mcp_pin();
|
|
22146
|
-
var
|
|
22696
|
+
var import_fs42 = __toESM(require("fs"));
|
|
22147
22697
|
function registerMcpPinCommand(program2) {
|
|
22148
22698
|
const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
|
|
22149
22699
|
const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
|
|
@@ -22154,7 +22704,7 @@ function registerMcpPinCommand(program2) {
|
|
|
22154
22704
|
let repoCorrupt = false;
|
|
22155
22705
|
if (found.source === "repo") {
|
|
22156
22706
|
try {
|
|
22157
|
-
const raw =
|
|
22707
|
+
const raw = import_fs42.default.readFileSync(found.path, "utf-8");
|
|
22158
22708
|
const parsed = JSON.parse(raw);
|
|
22159
22709
|
repoEntries = parsed.servers ?? {};
|
|
22160
22710
|
} catch {
|
|
@@ -22467,9 +23017,9 @@ init_scan();
|
|
|
22467
23017
|
|
|
22468
23018
|
// src/cli/commands/sessions.ts
|
|
22469
23019
|
var import_chalk24 = __toESM(require("chalk"));
|
|
22470
|
-
var
|
|
22471
|
-
var
|
|
22472
|
-
var
|
|
23020
|
+
var import_fs43 = __toESM(require("fs"));
|
|
23021
|
+
var import_path44 = __toESM(require("path"));
|
|
23022
|
+
var import_os38 = __toESM(require("os"));
|
|
22473
23023
|
init_scan_summary();
|
|
22474
23024
|
var CLAUDE_PRICING3 = {
|
|
22475
23025
|
"claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
|
|
@@ -22511,10 +23061,10 @@ function encodeProjectPath(projectPath) {
|
|
|
22511
23061
|
}
|
|
22512
23062
|
function sessionJsonlPath(projectPath, sessionId) {
|
|
22513
23063
|
const encoded = encodeProjectPath(projectPath);
|
|
22514
|
-
return
|
|
23064
|
+
return import_path44.default.join(import_os38.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
22515
23065
|
}
|
|
22516
23066
|
function projectLabel(projectPath) {
|
|
22517
|
-
return projectPath.replace(
|
|
23067
|
+
return projectPath.replace(import_os38.default.homedir(), "~");
|
|
22518
23068
|
}
|
|
22519
23069
|
function parseHistoryLines(lines) {
|
|
22520
23070
|
const entries = [];
|
|
@@ -22583,10 +23133,10 @@ function parseSessionLines(lines) {
|
|
|
22583
23133
|
return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
|
|
22584
23134
|
}
|
|
22585
23135
|
function loadAuditEntries(auditPath) {
|
|
22586
|
-
const aPath = auditPath ??
|
|
23136
|
+
const aPath = auditPath ?? import_path44.default.join(import_os38.default.homedir(), ".node9", "audit.log");
|
|
22587
23137
|
let raw;
|
|
22588
23138
|
try {
|
|
22589
|
-
raw =
|
|
23139
|
+
raw = import_fs43.default.readFileSync(aPath, "utf-8");
|
|
22590
23140
|
} catch {
|
|
22591
23141
|
return [];
|
|
22592
23142
|
}
|
|
@@ -22622,8 +23172,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
|
|
|
22622
23172
|
return result;
|
|
22623
23173
|
}
|
|
22624
23174
|
function buildGeminiSessions(days, allAuditEntries) {
|
|
22625
|
-
const tmpDir =
|
|
22626
|
-
if (!
|
|
23175
|
+
const tmpDir = import_path44.default.join(import_os38.default.homedir(), ".gemini", "tmp");
|
|
23176
|
+
if (!import_fs43.default.existsSync(tmpDir)) return [];
|
|
22627
23177
|
const cutoff = days !== null ? (() => {
|
|
22628
23178
|
const d = /* @__PURE__ */ new Date();
|
|
22629
23179
|
d.setDate(d.getDate() - days);
|
|
@@ -22632,35 +23182,35 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
22632
23182
|
})() : null;
|
|
22633
23183
|
let slugDirs;
|
|
22634
23184
|
try {
|
|
22635
|
-
slugDirs =
|
|
23185
|
+
slugDirs = import_fs43.default.readdirSync(tmpDir);
|
|
22636
23186
|
} catch {
|
|
22637
23187
|
return [];
|
|
22638
23188
|
}
|
|
22639
23189
|
const summaries = [];
|
|
22640
23190
|
for (const slug of slugDirs) {
|
|
22641
|
-
const slugPath =
|
|
23191
|
+
const slugPath = import_path44.default.join(tmpDir, slug);
|
|
22642
23192
|
try {
|
|
22643
|
-
if (!
|
|
23193
|
+
if (!import_fs43.default.statSync(slugPath).isDirectory()) continue;
|
|
22644
23194
|
} catch {
|
|
22645
23195
|
continue;
|
|
22646
23196
|
}
|
|
22647
|
-
let projectRoot =
|
|
23197
|
+
let projectRoot = import_path44.default.join(import_os38.default.homedir(), slug);
|
|
22648
23198
|
try {
|
|
22649
|
-
projectRoot =
|
|
23199
|
+
projectRoot = import_fs43.default.readFileSync(import_path44.default.join(slugPath, ".project_root"), "utf-8").trim();
|
|
22650
23200
|
} catch {
|
|
22651
23201
|
}
|
|
22652
|
-
const chatsDir =
|
|
22653
|
-
if (!
|
|
23202
|
+
const chatsDir = import_path44.default.join(slugPath, "chats");
|
|
23203
|
+
if (!import_fs43.default.existsSync(chatsDir)) continue;
|
|
22654
23204
|
let chatFiles;
|
|
22655
23205
|
try {
|
|
22656
|
-
chatFiles =
|
|
23206
|
+
chatFiles = import_fs43.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
|
|
22657
23207
|
} catch {
|
|
22658
23208
|
continue;
|
|
22659
23209
|
}
|
|
22660
23210
|
for (const chatFile of chatFiles) {
|
|
22661
23211
|
let raw;
|
|
22662
23212
|
try {
|
|
22663
|
-
raw =
|
|
23213
|
+
raw = import_fs43.default.readFileSync(import_path44.default.join(chatsDir, chatFile), "utf-8");
|
|
22664
23214
|
} catch {
|
|
22665
23215
|
continue;
|
|
22666
23216
|
}
|
|
@@ -22740,8 +23290,8 @@ function buildGeminiSessions(days, allAuditEntries) {
|
|
|
22740
23290
|
return summaries;
|
|
22741
23291
|
}
|
|
22742
23292
|
function buildCodexSessions(days, allAuditEntries) {
|
|
22743
|
-
const sessionsBase =
|
|
22744
|
-
if (!
|
|
23293
|
+
const sessionsBase = import_path44.default.join(import_os38.default.homedir(), ".codex", "sessions");
|
|
23294
|
+
if (!import_fs43.default.existsSync(sessionsBase)) return [];
|
|
22745
23295
|
const cutoff = days !== null ? (() => {
|
|
22746
23296
|
const d = /* @__PURE__ */ new Date();
|
|
22747
23297
|
d.setDate(d.getDate() - days);
|
|
@@ -22750,29 +23300,29 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
22750
23300
|
})() : null;
|
|
22751
23301
|
const jsonlFiles = [];
|
|
22752
23302
|
try {
|
|
22753
|
-
for (const year of
|
|
22754
|
-
const yearPath =
|
|
23303
|
+
for (const year of import_fs43.default.readdirSync(sessionsBase)) {
|
|
23304
|
+
const yearPath = import_path44.default.join(sessionsBase, year);
|
|
22755
23305
|
try {
|
|
22756
|
-
if (!
|
|
23306
|
+
if (!import_fs43.default.statSync(yearPath).isDirectory()) continue;
|
|
22757
23307
|
} catch {
|
|
22758
23308
|
continue;
|
|
22759
23309
|
}
|
|
22760
|
-
for (const month of
|
|
22761
|
-
const monthPath =
|
|
23310
|
+
for (const month of import_fs43.default.readdirSync(yearPath)) {
|
|
23311
|
+
const monthPath = import_path44.default.join(yearPath, month);
|
|
22762
23312
|
try {
|
|
22763
|
-
if (!
|
|
23313
|
+
if (!import_fs43.default.statSync(monthPath).isDirectory()) continue;
|
|
22764
23314
|
} catch {
|
|
22765
23315
|
continue;
|
|
22766
23316
|
}
|
|
22767
|
-
for (const day of
|
|
22768
|
-
const dayPath =
|
|
23317
|
+
for (const day of import_fs43.default.readdirSync(monthPath)) {
|
|
23318
|
+
const dayPath = import_path44.default.join(monthPath, day);
|
|
22769
23319
|
try {
|
|
22770
|
-
if (!
|
|
23320
|
+
if (!import_fs43.default.statSync(dayPath).isDirectory()) continue;
|
|
22771
23321
|
} catch {
|
|
22772
23322
|
continue;
|
|
22773
23323
|
}
|
|
22774
|
-
for (const file of
|
|
22775
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
23324
|
+
for (const file of import_fs43.default.readdirSync(dayPath)) {
|
|
23325
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(import_path44.default.join(dayPath, file));
|
|
22776
23326
|
}
|
|
22777
23327
|
}
|
|
22778
23328
|
}
|
|
@@ -22784,7 +23334,7 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
22784
23334
|
for (const filePath of jsonlFiles) {
|
|
22785
23335
|
let lines;
|
|
22786
23336
|
try {
|
|
22787
|
-
lines =
|
|
23337
|
+
lines = import_fs43.default.readFileSync(filePath, "utf-8").split("\n");
|
|
22788
23338
|
} catch {
|
|
22789
23339
|
continue;
|
|
22790
23340
|
}
|
|
@@ -22862,10 +23412,10 @@ function buildCodexSessions(days, allAuditEntries) {
|
|
|
22862
23412
|
return summaries;
|
|
22863
23413
|
}
|
|
22864
23414
|
function buildSessions(days, historyPath) {
|
|
22865
|
-
const hPath = historyPath ??
|
|
23415
|
+
const hPath = historyPath ?? import_path44.default.join(import_os38.default.homedir(), ".claude", "history.jsonl");
|
|
22866
23416
|
let historyRaw;
|
|
22867
23417
|
try {
|
|
22868
|
-
historyRaw =
|
|
23418
|
+
historyRaw = import_fs43.default.readFileSync(hPath, "utf-8");
|
|
22869
23419
|
} catch {
|
|
22870
23420
|
return [];
|
|
22871
23421
|
}
|
|
@@ -22890,7 +23440,7 @@ function buildSessions(days, historyPath) {
|
|
|
22890
23440
|
const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
|
|
22891
23441
|
let sessionLines = [];
|
|
22892
23442
|
try {
|
|
22893
|
-
sessionLines =
|
|
23443
|
+
sessionLines = import_fs43.default.readFileSync(jsonlFile, "utf-8").split("\n");
|
|
22894
23444
|
} catch {
|
|
22895
23445
|
}
|
|
22896
23446
|
const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
|
|
@@ -23158,8 +23708,8 @@ function registerSessionsCommand(program2) {
|
|
|
23158
23708
|
console.log("");
|
|
23159
23709
|
console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
|
|
23160
23710
|
console.log("");
|
|
23161
|
-
const historyPath =
|
|
23162
|
-
if (!
|
|
23711
|
+
const historyPath = import_path44.default.join(import_os38.default.homedir(), ".claude", "history.jsonl");
|
|
23712
|
+
if (!import_fs43.default.existsSync(historyPath)) {
|
|
23163
23713
|
console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
|
|
23164
23714
|
console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
|
|
23165
23715
|
return;
|
|
@@ -23196,12 +23746,12 @@ function registerSessionsCommand(program2) {
|
|
|
23196
23746
|
|
|
23197
23747
|
// src/cli/commands/skill-pin.ts
|
|
23198
23748
|
var import_chalk25 = __toESM(require("chalk"));
|
|
23199
|
-
var
|
|
23200
|
-
var
|
|
23201
|
-
var
|
|
23749
|
+
var import_fs44 = __toESM(require("fs"));
|
|
23750
|
+
var import_os39 = __toESM(require("os"));
|
|
23751
|
+
var import_path45 = __toESM(require("path"));
|
|
23202
23752
|
function wipeSkillSessions() {
|
|
23203
23753
|
try {
|
|
23204
|
-
|
|
23754
|
+
import_fs44.default.rmSync(import_path45.default.join(import_os39.default.homedir(), ".node9", "skill-sessions"), {
|
|
23205
23755
|
recursive: true,
|
|
23206
23756
|
force: true
|
|
23207
23757
|
});
|
|
@@ -23283,15 +23833,15 @@ function registerSkillPinCommand(program2) {
|
|
|
23283
23833
|
}
|
|
23284
23834
|
|
|
23285
23835
|
// src/cli/commands/decisions.ts
|
|
23286
|
-
var
|
|
23287
|
-
var
|
|
23288
|
-
var
|
|
23836
|
+
var import_fs45 = __toESM(require("fs"));
|
|
23837
|
+
var import_os40 = __toESM(require("os"));
|
|
23838
|
+
var import_path46 = __toESM(require("path"));
|
|
23289
23839
|
var import_chalk26 = __toESM(require("chalk"));
|
|
23290
|
-
var DECISIONS_FILE2 =
|
|
23840
|
+
var DECISIONS_FILE2 = import_path46.default.join(import_os40.default.homedir(), ".node9", "decisions.json");
|
|
23291
23841
|
function readDecisions() {
|
|
23292
23842
|
try {
|
|
23293
|
-
if (!
|
|
23294
|
-
const raw =
|
|
23843
|
+
if (!import_fs45.default.existsSync(DECISIONS_FILE2)) return {};
|
|
23844
|
+
const raw = import_fs45.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
23295
23845
|
const parsed = JSON.parse(raw);
|
|
23296
23846
|
const out = {};
|
|
23297
23847
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -23303,11 +23853,11 @@ function readDecisions() {
|
|
|
23303
23853
|
}
|
|
23304
23854
|
}
|
|
23305
23855
|
function writeDecisions(d) {
|
|
23306
|
-
const dir =
|
|
23307
|
-
if (!
|
|
23856
|
+
const dir = import_path46.default.dirname(DECISIONS_FILE2);
|
|
23857
|
+
if (!import_fs45.default.existsSync(dir)) import_fs45.default.mkdirSync(dir, { recursive: true });
|
|
23308
23858
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
23309
|
-
|
|
23310
|
-
|
|
23859
|
+
import_fs45.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
23860
|
+
import_fs45.default.renameSync(tmp, DECISIONS_FILE2);
|
|
23311
23861
|
}
|
|
23312
23862
|
function registerDecisionsCommand(program2) {
|
|
23313
23863
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -23364,18 +23914,18 @@ Persistent decisions (${entries.length})
|
|
|
23364
23914
|
|
|
23365
23915
|
// src/cli/commands/dlp.ts
|
|
23366
23916
|
var import_chalk27 = __toESM(require("chalk"));
|
|
23367
|
-
var
|
|
23368
|
-
var
|
|
23369
|
-
var
|
|
23370
|
-
var AUDIT_LOG =
|
|
23371
|
-
var RESOLVED_FILE =
|
|
23917
|
+
var import_fs46 = __toESM(require("fs"));
|
|
23918
|
+
var import_path47 = __toESM(require("path"));
|
|
23919
|
+
var import_os41 = __toESM(require("os"));
|
|
23920
|
+
var AUDIT_LOG = import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
|
|
23921
|
+
var RESOLVED_FILE = import_path47.default.join(import_os41.default.homedir(), ".node9", "dlp-resolved.json");
|
|
23372
23922
|
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
23373
23923
|
function stripAnsi(s) {
|
|
23374
23924
|
return s.replace(ANSI_RE, "");
|
|
23375
23925
|
}
|
|
23376
23926
|
function loadResolved() {
|
|
23377
23927
|
try {
|
|
23378
|
-
const raw = JSON.parse(
|
|
23928
|
+
const raw = JSON.parse(import_fs46.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
23379
23929
|
return new Set(raw);
|
|
23380
23930
|
} catch {
|
|
23381
23931
|
return /* @__PURE__ */ new Set();
|
|
@@ -23383,13 +23933,13 @@ function loadResolved() {
|
|
|
23383
23933
|
}
|
|
23384
23934
|
function saveResolved(resolved) {
|
|
23385
23935
|
try {
|
|
23386
|
-
|
|
23936
|
+
import_fs46.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
23387
23937
|
} catch {
|
|
23388
23938
|
}
|
|
23389
23939
|
}
|
|
23390
23940
|
function loadDlpFindings() {
|
|
23391
|
-
if (!
|
|
23392
|
-
return
|
|
23941
|
+
if (!import_fs46.default.existsSync(AUDIT_LOG)) return [];
|
|
23942
|
+
return import_fs46.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
23393
23943
|
if (!line.trim()) return [];
|
|
23394
23944
|
try {
|
|
23395
23945
|
const e = JSON.parse(line);
|
|
@@ -23399,7 +23949,7 @@ function loadDlpFindings() {
|
|
|
23399
23949
|
}
|
|
23400
23950
|
});
|
|
23401
23951
|
}
|
|
23402
|
-
function
|
|
23952
|
+
function entryKey2(e) {
|
|
23403
23953
|
return `${e.ts}:${e.dlpPattern}:${e.dlpSample}`;
|
|
23404
23954
|
}
|
|
23405
23955
|
function fmtDate3(ts) {
|
|
@@ -23422,7 +23972,7 @@ function registerDlpCommand(program2) {
|
|
|
23422
23972
|
return;
|
|
23423
23973
|
}
|
|
23424
23974
|
const resolved = loadResolved();
|
|
23425
|
-
for (const e of findings) resolved.add(
|
|
23975
|
+
for (const e of findings) resolved.add(entryKey2(e));
|
|
23426
23976
|
saveResolved(resolved);
|
|
23427
23977
|
console.log(
|
|
23428
23978
|
import_chalk27.default.green(
|
|
@@ -23435,7 +23985,7 @@ function registerDlpCommand(program2) {
|
|
|
23435
23985
|
cmd.action(() => {
|
|
23436
23986
|
const findings = loadDlpFindings();
|
|
23437
23987
|
const resolved = loadResolved();
|
|
23438
|
-
const open = findings.filter((e) => !resolved.has(
|
|
23988
|
+
const open = findings.filter((e) => !resolved.has(entryKey2(e)));
|
|
23439
23989
|
const resolvedCount = findings.length - open.length;
|
|
23440
23990
|
console.log("");
|
|
23441
23991
|
console.log(
|
|
@@ -23487,15 +24037,15 @@ function registerDlpCommand(program2) {
|
|
|
23487
24037
|
|
|
23488
24038
|
// src/cli/commands/mask.ts
|
|
23489
24039
|
var import_chalk28 = __toESM(require("chalk"));
|
|
23490
|
-
var
|
|
23491
|
-
var
|
|
23492
|
-
var
|
|
24040
|
+
var import_fs47 = __toESM(require("fs"));
|
|
24041
|
+
var import_path48 = __toESM(require("path"));
|
|
24042
|
+
var import_os42 = __toESM(require("os"));
|
|
23493
24043
|
init_dlp();
|
|
23494
24044
|
function findJsonlFiles(dir) {
|
|
23495
24045
|
const results = [];
|
|
23496
|
-
if (!
|
|
23497
|
-
for (const entry of
|
|
23498
|
-
const full =
|
|
24046
|
+
if (!import_fs47.default.existsSync(dir)) return results;
|
|
24047
|
+
for (const entry of import_fs47.default.readdirSync(dir, { withFileTypes: true })) {
|
|
24048
|
+
const full = import_path48.default.join(dir, entry.name);
|
|
23499
24049
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
23500
24050
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
23501
24051
|
}
|
|
@@ -23538,7 +24088,7 @@ function redactJson(obj) {
|
|
|
23538
24088
|
function processFile(filePath, dryRun) {
|
|
23539
24089
|
let raw;
|
|
23540
24090
|
try {
|
|
23541
|
-
raw =
|
|
24091
|
+
raw = import_fs47.default.readFileSync(filePath, "utf-8");
|
|
23542
24092
|
} catch {
|
|
23543
24093
|
return { redactedLines: 0, patterns: [] };
|
|
23544
24094
|
}
|
|
@@ -23570,14 +24120,14 @@ function processFile(filePath, dryRun) {
|
|
|
23570
24120
|
}
|
|
23571
24121
|
}
|
|
23572
24122
|
if (!dryRun && redactedLines > 0) {
|
|
23573
|
-
|
|
24123
|
+
import_fs47.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
23574
24124
|
}
|
|
23575
24125
|
return { redactedLines, patterns };
|
|
23576
24126
|
}
|
|
23577
24127
|
function processJsonFile(filePath, dryRun) {
|
|
23578
24128
|
let raw;
|
|
23579
24129
|
try {
|
|
23580
|
-
raw =
|
|
24130
|
+
raw = import_fs47.default.readFileSync(filePath, "utf-8");
|
|
23581
24131
|
} catch {
|
|
23582
24132
|
return { redactedLines: 0, patterns: [] };
|
|
23583
24133
|
}
|
|
@@ -23590,15 +24140,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
23590
24140
|
const { value, modified, found } = redactJson(parsed);
|
|
23591
24141
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
23592
24142
|
if (!dryRun) {
|
|
23593
|
-
|
|
24143
|
+
import_fs47.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
23594
24144
|
}
|
|
23595
24145
|
return { redactedLines: 1, patterns: found };
|
|
23596
24146
|
}
|
|
23597
24147
|
function findJsonFiles(dir) {
|
|
23598
24148
|
const results = [];
|
|
23599
|
-
if (!
|
|
23600
|
-
for (const entry of
|
|
23601
|
-
const full =
|
|
24149
|
+
if (!import_fs47.default.existsSync(dir)) return results;
|
|
24150
|
+
for (const entry of import_fs47.default.readdirSync(dir, { withFileTypes: true })) {
|
|
24151
|
+
const full = import_path48.default.join(dir, entry.name);
|
|
23602
24152
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
23603
24153
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
23604
24154
|
}
|
|
@@ -23607,9 +24157,9 @@ function findJsonFiles(dir) {
|
|
|
23607
24157
|
function registerMaskCommand(program2) {
|
|
23608
24158
|
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) => {
|
|
23609
24159
|
const dryRun = !!options.dryRun;
|
|
23610
|
-
const home =
|
|
23611
|
-
const claudeDir =
|
|
23612
|
-
const geminiDir =
|
|
24160
|
+
const home = import_os42.default.homedir();
|
|
24161
|
+
const claudeDir = import_path48.default.join(home, ".claude", "projects");
|
|
24162
|
+
const geminiDir = import_path48.default.join(home, ".gemini", "tmp");
|
|
23613
24163
|
const allFiles = [
|
|
23614
24164
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
23615
24165
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -23617,7 +24167,7 @@ function registerMaskCommand(program2) {
|
|
|
23617
24167
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
23618
24168
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
23619
24169
|
try {
|
|
23620
|
-
return
|
|
24170
|
+
return import_fs47.default.statSync(f.path).mtime >= cutoff;
|
|
23621
24171
|
} catch {
|
|
23622
24172
|
return false;
|
|
23623
24173
|
}
|
|
@@ -23673,20 +24223,20 @@ function registerMaskCommand(program2) {
|
|
|
23673
24223
|
// src/cli.ts
|
|
23674
24224
|
init_blast();
|
|
23675
24225
|
var { version } = JSON.parse(
|
|
23676
|
-
|
|
24226
|
+
import_fs50.default.readFileSync(import_path51.default.join(__dirname, "../package.json"), "utf-8")
|
|
23677
24227
|
);
|
|
23678
24228
|
var program = new import_commander.Command();
|
|
23679
24229
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
23680
24230
|
program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
|
|
23681
24231
|
const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
|
|
23682
|
-
const credPath =
|
|
23683
|
-
if (!
|
|
23684
|
-
|
|
24232
|
+
const credPath = import_path51.default.join(import_os45.default.homedir(), ".node9", "credentials.json");
|
|
24233
|
+
if (!import_fs50.default.existsSync(import_path51.default.dirname(credPath)))
|
|
24234
|
+
import_fs50.default.mkdirSync(import_path51.default.dirname(credPath), { recursive: true });
|
|
23685
24235
|
const profileName = options.profile || "default";
|
|
23686
24236
|
let existingCreds = {};
|
|
23687
24237
|
try {
|
|
23688
|
-
if (
|
|
23689
|
-
const raw = JSON.parse(
|
|
24238
|
+
if (import_fs50.default.existsSync(credPath)) {
|
|
24239
|
+
const raw = JSON.parse(import_fs50.default.readFileSync(credPath, "utf-8"));
|
|
23690
24240
|
if (raw.apiKey) {
|
|
23691
24241
|
existingCreds = {
|
|
23692
24242
|
default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
|
|
@@ -23698,14 +24248,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
23698
24248
|
} catch {
|
|
23699
24249
|
}
|
|
23700
24250
|
existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
|
|
23701
|
-
|
|
24251
|
+
import_fs50.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
|
|
23702
24252
|
let effectiveCloud = null;
|
|
23703
24253
|
if (profileName === "default") {
|
|
23704
|
-
const configPath =
|
|
24254
|
+
const configPath = import_path51.default.join(import_os45.default.homedir(), ".node9", "config.json");
|
|
23705
24255
|
let config = {};
|
|
23706
24256
|
try {
|
|
23707
|
-
if (
|
|
23708
|
-
config = JSON.parse(
|
|
24257
|
+
if (import_fs50.default.existsSync(configPath))
|
|
24258
|
+
config = JSON.parse(import_fs50.default.readFileSync(configPath, "utf-8"));
|
|
23709
24259
|
} catch {
|
|
23710
24260
|
}
|
|
23711
24261
|
if (!config.settings || typeof config.settings !== "object") config.settings = {};
|
|
@@ -23720,9 +24270,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
|
|
|
23720
24270
|
approvers.cloud = false;
|
|
23721
24271
|
}
|
|
23722
24272
|
s.approvers = approvers;
|
|
23723
|
-
if (!
|
|
23724
|
-
|
|
23725
|
-
|
|
24273
|
+
if (!import_fs50.default.existsSync(import_path51.default.dirname(configPath)))
|
|
24274
|
+
import_fs50.default.mkdirSync(import_path51.default.dirname(configPath), { recursive: true });
|
|
24275
|
+
import_fs50.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
23726
24276
|
effectiveCloud = approvers.cloud === true;
|
|
23727
24277
|
}
|
|
23728
24278
|
if (options.profile && profileName !== "default") {
|
|
@@ -23881,15 +24431,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
23881
24431
|
}
|
|
23882
24432
|
}
|
|
23883
24433
|
if (options.purge) {
|
|
23884
|
-
const node9Dir =
|
|
23885
|
-
if (
|
|
24434
|
+
const node9Dir = import_path51.default.join(import_os45.default.homedir(), ".node9");
|
|
24435
|
+
if (import_fs50.default.existsSync(node9Dir)) {
|
|
23886
24436
|
const confirmed = await (0, import_prompts2.confirm)({
|
|
23887
24437
|
message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
|
|
23888
24438
|
default: false
|
|
23889
24439
|
});
|
|
23890
24440
|
if (confirmed) {
|
|
23891
|
-
|
|
23892
|
-
if (
|
|
24441
|
+
import_fs50.default.rmSync(node9Dir, { recursive: true });
|
|
24442
|
+
if (import_fs50.default.existsSync(node9Dir)) {
|
|
23893
24443
|
console.error(
|
|
23894
24444
|
import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
23895
24445
|
);
|
|
@@ -24004,7 +24554,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
24004
24554
|
});
|
|
24005
24555
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
24006
24556
|
try {
|
|
24007
|
-
const dashboardPath =
|
|
24557
|
+
const dashboardPath = import_path51.default.join(__dirname, "dashboard.mjs");
|
|
24008
24558
|
const dynamicImport = new Function("id", "return import(id)");
|
|
24009
24559
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
24010
24560
|
await mod.startMonitor();
|
|
@@ -24042,14 +24592,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
24042
24592
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
24043
24593
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
24044
24594
|
if (subcommand === "debug") {
|
|
24045
|
-
const flagFile =
|
|
24595
|
+
const flagFile = import_path51.default.join(import_os45.default.homedir(), ".node9", "hud-debug");
|
|
24046
24596
|
if (state === "on") {
|
|
24047
|
-
|
|
24048
|
-
|
|
24597
|
+
import_fs50.default.mkdirSync(import_path51.default.dirname(flagFile), { recursive: true });
|
|
24598
|
+
import_fs50.default.writeFileSync(flagFile, "");
|
|
24049
24599
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
24050
24600
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
24051
24601
|
} else if (state === "off") {
|
|
24052
|
-
if (
|
|
24602
|
+
if (import_fs50.default.existsSync(flagFile)) import_fs50.default.unlinkSync(flagFile);
|
|
24053
24603
|
console.log("HUD debug logging disabled.");
|
|
24054
24604
|
} else {
|
|
24055
24605
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -24166,9 +24716,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
24166
24716
|
const isCheckHook = process.argv[2] === "check";
|
|
24167
24717
|
if (isCheckHook) {
|
|
24168
24718
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
24169
|
-
const logPath =
|
|
24719
|
+
const logPath = import_path51.default.join(import_os45.default.homedir(), ".node9", "hook-debug.log");
|
|
24170
24720
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
24171
|
-
|
|
24721
|
+
import_fs50.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
24172
24722
|
`);
|
|
24173
24723
|
}
|
|
24174
24724
|
process.exit(0);
|