@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.mjs CHANGED
@@ -179,8 +179,8 @@ function sanitizeConfig(raw) {
179
179
  }
180
180
  }
181
181
  const lines = result.error.issues.map((issue) => {
182
- const path51 = issue.path.length > 0 ? issue.path.join(".") : "root";
183
- return ` \u2022 ${path51}: ${issue.message}`;
182
+ const path52 = issue.path.length > 0 ? issue.path.join(".") : "root";
183
+ return ` \u2022 ${path52}: ${issue.message}`;
184
184
  });
185
185
  return {
186
186
  sanitized,
@@ -286,7 +286,15 @@ var init_config_schema = __esm({
286
286
  }).optional(),
287
287
  dlp: z.object({
288
288
  enabled: z.boolean().optional(),
289
- scanIgnoredTools: z.boolean().optional()
289
+ scanIgnoredTools: z.boolean().optional(),
290
+ pii: z.enum(["off", "block"]).optional()
291
+ }).optional(),
292
+ egress: z.object({
293
+ enabled: z.boolean().optional(),
294
+ mode: z.enum(["off", "review", "block"]).optional(),
295
+ allow: z.array(z.string()).optional(),
296
+ deny: z.array(z.string()).optional(),
297
+ allowPrivate: z.boolean().optional()
290
298
  }).optional(),
291
299
  loopDetection: z.object({
292
300
  enabled: z.boolean().optional(),
@@ -669,6 +677,116 @@ function extractLiteralArgs(callExpr) {
669
677
  }
670
678
  return { name, flags, paths };
671
679
  }
680
+ function resolveWordLiteral(w) {
681
+ const parts = w?.Parts || [];
682
+ let s = "";
683
+ for (const p of parts) {
684
+ const t = syntax.NodeType(p);
685
+ if (t === "Lit") s += (p.Value ?? "").replace(/\\(.)/g, "$1");
686
+ else if (t === "SglQuoted") s += p.Value ?? "";
687
+ else if (t === "DblQuoted") {
688
+ const inner = p.Parts || [];
689
+ if (!inner.every((ip) => syntax.NodeType(ip) === "Lit")) return null;
690
+ s += inner.map((ip) => ip.Value ?? "").join("");
691
+ } else {
692
+ return null;
693
+ }
694
+ }
695
+ return s;
696
+ }
697
+ function parseDestHost(token) {
698
+ if (!token) return null;
699
+ let t = token.trim();
700
+ if (!t || t.startsWith("-")) return null;
701
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(t)) {
702
+ try {
703
+ const h = new URL(t).hostname.toLowerCase();
704
+ return h || null;
705
+ } catch {
706
+ return null;
707
+ }
708
+ }
709
+ const at = t.lastIndexOf("@");
710
+ if (at >= 0) t = t.slice(at + 1);
711
+ t = t.split("/")[0];
712
+ t = t.replace(/:\d+$/, "");
713
+ t = t.split(":")[0];
714
+ t = t.toLowerCase();
715
+ if (t.length > 253) return null;
716
+ if (t === "localhost") return t;
717
+ if (/^[a-z0-9.-]+\.[a-z0-9.-]+$/.test(t)) return t;
718
+ return null;
719
+ }
720
+ function destTokensForBinary(binary, args) {
721
+ const valueFlags = VALUE_FLAGS[binary] ?? /* @__PURE__ */ new Set();
722
+ const positionals = [];
723
+ const urlFlagValues = [];
724
+ for (let i = 0; i < args.length; i++) {
725
+ const tok = args[i];
726
+ if (tok === null) continue;
727
+ if (tok.startsWith("-")) {
728
+ if (tok.startsWith("--url=")) {
729
+ urlFlagValues.push(tok.slice("--url=".length));
730
+ continue;
731
+ }
732
+ if (tok === "--url") {
733
+ const next = args[i + 1];
734
+ if (typeof next === "string") urlFlagValues.push(next);
735
+ i++;
736
+ continue;
737
+ }
738
+ if (tok.includes("=")) continue;
739
+ if (valueFlags.has(tok)) i++;
740
+ continue;
741
+ }
742
+ positionals.push(tok);
743
+ }
744
+ switch (binary) {
745
+ case "curl":
746
+ case "wget":
747
+ return [...urlFlagValues, ...positionals];
748
+ case "ssh":
749
+ return positionals.slice(0, 1);
750
+ case "scp":
751
+ return positionals.filter((p) => p.includes(":") || p.includes("@"));
752
+ case "nc":
753
+ case "ncat":
754
+ case "netcat":
755
+ return positionals.slice(0, 1);
756
+ default:
757
+ return [];
758
+ }
759
+ }
760
+ function extractShellDestinations(command) {
761
+ const f = parseShared(command);
762
+ if (f === PARSE_FAIL) return [];
763
+ const out = [];
764
+ const seen = /* @__PURE__ */ new Set();
765
+ try {
766
+ syntax.Walk(f, (node) => {
767
+ if (!node) return false;
768
+ const n = node;
769
+ if (syntax.NodeType(n) !== "CallExpr") return true;
770
+ const callArgs = n.Args || [];
771
+ if (callArgs.length === 0) return true;
772
+ const name = (resolveWordLiteral(callArgs[0]) || "").toLowerCase();
773
+ if (!NET_BINARIES.has(name)) return true;
774
+ const rest = callArgs.slice(1).map((a) => resolveWordLiteral(a));
775
+ for (const raw of destTokensForBinary(name, rest)) {
776
+ const host = parseDestHost(raw);
777
+ if (!host) continue;
778
+ const key = `${name}:${host}`;
779
+ if (seen.has(key)) continue;
780
+ seen.add(key);
781
+ out.push({ host, binary: name, raw });
782
+ }
783
+ return true;
784
+ });
785
+ } catch {
786
+ return out;
787
+ }
788
+ return out;
789
+ }
672
790
  function analyzeFsOperation(command) {
673
791
  if (!FS_OP_PRESCREEN_RE.test(command)) return null;
674
792
  if (fsOpCache.has(command)) {
@@ -796,6 +914,64 @@ function analyzeShellCommand(command) {
796
914
  }
797
915
  return { actions, paths, allTokens };
798
916
  }
917
+ function hostMatches(host, pattern) {
918
+ const h = host.toLowerCase();
919
+ const p = pattern.toLowerCase().trim();
920
+ if (!p) return false;
921
+ if (p === "*") return true;
922
+ if (p.startsWith("*.")) {
923
+ const suffix = p.slice(2);
924
+ return h === suffix || h.endsWith("." + suffix);
925
+ }
926
+ return h === p;
927
+ }
928
+ function matchesAny(host, patterns) {
929
+ for (const p of patterns) if (hostMatches(host, p)) return true;
930
+ return false;
931
+ }
932
+ function isPrivateHost(host) {
933
+ const h = host.toLowerCase();
934
+ if (h === "localhost" || h === "0.0.0.0") return true;
935
+ if (h.endsWith(".local") || h.endsWith(".internal") || h.endsWith(".localhost")) return true;
936
+ if (/^127\./.test(h)) return true;
937
+ if (/^10\./.test(h)) return true;
938
+ if (/^192\.168\./.test(h)) return true;
939
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(h)) return true;
940
+ return false;
941
+ }
942
+ function evaluateEgress(dests, policy) {
943
+ if (!policy.enabled) return null;
944
+ let review = null;
945
+ for (const d of dests) {
946
+ if (matchesAny(d.host, policy.deny)) {
947
+ return {
948
+ verdict: "block",
949
+ host: d.host,
950
+ binary: d.binary,
951
+ reason: `Egress to ${d.host} is on the deny list.`
952
+ };
953
+ }
954
+ if (policy.allowPrivate && isPrivateHost(d.host)) continue;
955
+ if (matchesAny(d.host, policy.allow) || matchesAny(d.host, DEFAULT_EGRESS_ALLOWLIST)) continue;
956
+ if (policy.mode === "block") {
957
+ return {
958
+ verdict: "block",
959
+ host: d.host,
960
+ binary: d.binary,
961
+ reason: `Egress to unknown host ${d.host} is blocked (egress policy: block).`
962
+ };
963
+ }
964
+ if (policy.mode === "review" && !review) {
965
+ review = {
966
+ verdict: "review",
967
+ host: d.host,
968
+ binary: d.binary,
969
+ reason: `${d.binary} is sending data to an unrecognized host (${d.host}). Approve this destination?`
970
+ };
971
+ }
972
+ }
973
+ return review;
974
+ }
799
975
  function isSensitivePath(p) {
800
976
  return SENSITIVE_PATTERNS.some((re) => re.test(p));
801
977
  }
@@ -1023,9 +1199,9 @@ function matchesPattern(text, patterns) {
1023
1199
  const withoutDotSlash = text.replace(/^\.\//, "");
1024
1200
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1025
1201
  }
1026
- function getNestedValue(obj, path51) {
1202
+ function getNestedValue(obj, path52) {
1027
1203
  if (!obj || typeof obj !== "object") return null;
1028
- const segments = path51.split(".");
1204
+ const segments = path52.split(".");
1029
1205
  for (const seg of segments) {
1030
1206
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1031
1207
  }
@@ -1228,6 +1404,22 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
1228
1404
  }
1229
1405
  const ptVerdict = pipeChainVerdict(shellCommand, isTrustedHost2);
1230
1406
  if (ptVerdict) return ptVerdict;
1407
+ if (config.policy.egress?.enabled) {
1408
+ const dests = extractShellDestinations(shellCommand);
1409
+ if (dests.length > 0) {
1410
+ const eg = evaluateEgress(dests, config.policy.egress);
1411
+ if (eg) {
1412
+ return {
1413
+ decision: eg.verdict,
1414
+ blockedByLabel: eg.verdict === "block" ? "\u{1F310} Node9 Egress (Blocked)" : "\u{1F310} Node9 Egress (Review)",
1415
+ reason: eg.reason,
1416
+ ruleName: `egress:${eg.binary}:${eg.host}`,
1417
+ ruleDescription: eg.reason,
1418
+ tier: eg.verdict === "block" ? 3 : 4
1419
+ };
1420
+ }
1421
+ }
1422
+ }
1231
1423
  const firstToken = analyzed.actions[0] ?? "";
1232
1424
  if (["ssh", "scp", "rsync"].includes(firstToken)) {
1233
1425
  const rawTokens = shellCommand.trim().split(/\s+/);
@@ -1557,6 +1749,18 @@ function detectPii(text) {
1557
1749
  if (PII_CC_RE.test(text)) found.add("Credit Card");
1558
1750
  return [...found];
1559
1751
  }
1752
+ function detectArgsPii(args) {
1753
+ if (args === null || args === void 0) return [];
1754
+ let text;
1755
+ try {
1756
+ text = typeof args === "string" ? args : JSON.stringify(args);
1757
+ } catch {
1758
+ return [];
1759
+ }
1760
+ if (typeof text !== "string") return [];
1761
+ if (text.length > MAX_PII_SCAN_BYTES) text = text.slice(0, MAX_PII_SCAN_BYTES);
1762
+ return detectPii(text).filter((p) => REALTIME_PII_PATTERNS.includes(p));
1763
+ }
1560
1764
  function extractCanonicalFindings(call, ctx) {
1561
1765
  const out = [];
1562
1766
  const ts = call.timestamp;
@@ -1869,7 +2073,7 @@ function* stringValues(obj, depth = 0) {
1869
2073
  }
1870
2074
  for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
1871
2075
  }
1872
- var 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;
2076
+ var 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;
1873
2077
  var init_dist = __esm({
1874
2078
  "packages/policy-engine/dist/index.mjs"() {
1875
2079
  "use strict";
@@ -2483,8 +2687,112 @@ var init_dist = __esm({
2483
2687
  "shield:project-jail:block-read-env",
2484
2688
  "shield:project-jail:review-read-credentials"
2485
2689
  ]);
2690
+ NET_BINARIES = /* @__PURE__ */ new Set(["curl", "wget", "scp", "ssh", "nc", "ncat", "netcat"]);
2691
+ VALUE_FLAGS = {
2692
+ curl: /* @__PURE__ */ new Set([
2693
+ "-d",
2694
+ "--data",
2695
+ "--data-ascii",
2696
+ "--data-binary",
2697
+ "--data-raw",
2698
+ "--data-urlencode",
2699
+ "-F",
2700
+ "--form",
2701
+ "-H",
2702
+ "--header",
2703
+ "-X",
2704
+ "--request",
2705
+ "-o",
2706
+ "--output",
2707
+ "-T",
2708
+ "--upload-file",
2709
+ "-u",
2710
+ "--user",
2711
+ "-e",
2712
+ "--referer",
2713
+ "-A",
2714
+ "--user-agent",
2715
+ "-b",
2716
+ "--cookie",
2717
+ "-c",
2718
+ "--cookie-jar",
2719
+ "--connect-to",
2720
+ "--resolve",
2721
+ "--cacert",
2722
+ "--cert",
2723
+ "--key",
2724
+ "-x",
2725
+ "--proxy",
2726
+ "-m",
2727
+ "--max-time",
2728
+ "--retry"
2729
+ ]),
2730
+ wget: /* @__PURE__ */ new Set([
2731
+ "-O",
2732
+ "--output-document",
2733
+ "--post-data",
2734
+ "--post-file",
2735
+ "--header",
2736
+ "-U",
2737
+ "--user-agent",
2738
+ "--user",
2739
+ "--password",
2740
+ "-o",
2741
+ "--output-file",
2742
+ "-P",
2743
+ "--directory-prefix",
2744
+ "-t",
2745
+ "--tries",
2746
+ "-T",
2747
+ "--timeout"
2748
+ ]),
2749
+ scp: /* @__PURE__ */ new Set(["-i", "-F", "-l", "-o", "-c", "-S", "-P", "-J", "-D", "-W"]),
2750
+ ssh: /* @__PURE__ */ new Set([
2751
+ "-i",
2752
+ "-p",
2753
+ "-o",
2754
+ "-l",
2755
+ "-F",
2756
+ "-c",
2757
+ "-L",
2758
+ "-R",
2759
+ "-D",
2760
+ "-W",
2761
+ "-b",
2762
+ "-e",
2763
+ "-m",
2764
+ "-O",
2765
+ "-Q",
2766
+ "-S",
2767
+ "-J",
2768
+ "-w",
2769
+ "-B",
2770
+ "-I",
2771
+ "-E"
2772
+ ]),
2773
+ nc: /* @__PURE__ */ new Set(["-p", "-s", "-w", "-X", "-x", "-e", "-g", "-G", "-i", "-O", "-T", "-q", "-m"])
2774
+ };
2486
2775
  FS_OP_CACHE_MAX = 5e3;
2487
2776
  fsOpCache = /* @__PURE__ */ new Map();
2777
+ DEFAULT_EGRESS_ALLOWLIST = [
2778
+ "*.github.com",
2779
+ "*.githubusercontent.com",
2780
+ "*.npmjs.org",
2781
+ "pypi.org",
2782
+ "*.pythonhosted.org",
2783
+ "crates.io",
2784
+ "*.crates.io",
2785
+ "rubygems.org",
2786
+ "proxy.golang.org",
2787
+ "sum.golang.org",
2788
+ "*.anthropic.com",
2789
+ "*.openai.com",
2790
+ "*.googleapis.com",
2791
+ "*.docker.io",
2792
+ "*.docker.com",
2793
+ "deb.debian.org",
2794
+ "*.ubuntu.com"
2795
+ ];
2488
2796
  SOURCE_COMMANDS = /* @__PURE__ */ new Set([
2489
2797
  "cat",
2490
2798
  "head",
@@ -3414,6 +3722,8 @@ var init_dist = __esm({
3414
3722
  PII_SSN_RE = /\b\d{3}-\d{2}-\d{4}\b/;
3415
3723
  PII_PHONE_RE = /\b(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]\d{3}[-.\s]\d{4}\b/;
3416
3724
  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/;
3725
+ REALTIME_PII_PATTERNS = ["SSN", "Credit Card"];
3726
+ MAX_PII_SCAN_BYTES = 1e5;
3417
3727
  LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
3418
3728
  CANONICAL_EXTRACTOR_VERSION = "canonical-v4";
3419
3729
  DEDUPE_PREVIEW_LEN = 120;
@@ -3704,6 +4014,11 @@ function getConfig(cwd) {
3704
4014
  ignorePaths: [...DEFAULT_CONFIG.policy.snapshot.ignorePaths]
3705
4015
  },
3706
4016
  dlp: { ...DEFAULT_CONFIG.policy.dlp },
4017
+ egress: {
4018
+ ...DEFAULT_CONFIG.policy.egress,
4019
+ allow: [...DEFAULT_CONFIG.policy.egress.allow],
4020
+ deny: [...DEFAULT_CONFIG.policy.egress.deny]
4021
+ },
3707
4022
  loopDetection: { ...DEFAULT_CONFIG.policy.loopDetection },
3708
4023
  skillPinning: {
3709
4024
  ...DEFAULT_CONFIG.policy.skillPinning,
@@ -3754,6 +4069,15 @@ function getConfig(cwd) {
3754
4069
  const d = p.dlp;
3755
4070
  if (d.enabled !== void 0) mergedPolicy.dlp.enabled = d.enabled;
3756
4071
  if (d.scanIgnoredTools !== void 0) mergedPolicy.dlp.scanIgnoredTools = d.scanIgnoredTools;
4072
+ if (d.pii !== void 0) mergedPolicy.dlp.pii = d.pii;
4073
+ }
4074
+ if (p.egress) {
4075
+ const e = p.egress;
4076
+ if (e.enabled !== void 0) mergedPolicy.egress.enabled = e.enabled;
4077
+ if (e.mode !== void 0) mergedPolicy.egress.mode = e.mode;
4078
+ if (Array.isArray(e.allow)) mergedPolicy.egress.allow.push(...e.allow);
4079
+ if (Array.isArray(e.deny)) mergedPolicy.egress.deny.push(...e.deny);
4080
+ if (e.allowPrivate !== void 0) mergedPolicy.egress.allowPrivate = e.allowPrivate;
3757
4081
  }
3758
4082
  if (p.loopDetection) {
3759
4083
  const ld = p.loopDetection;
@@ -4104,7 +4428,8 @@ var init_config = __esm({
4104
4428
  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."
4105
4429
  }
4106
4430
  ],
4107
- dlp: { enabled: true, scanIgnoredTools: true },
4431
+ dlp: { enabled: true, scanIgnoredTools: true, pii: "off" },
4432
+ egress: { enabled: false, mode: "review", allow: [], deny: [], allowPrivate: true },
4108
4433
  loopDetection: { enabled: true, threshold: 5, windowSeconds: 120 },
4109
4434
  skillPinning: { enabled: false, mode: "warn", roots: [] }
4110
4435
  },
@@ -5207,6 +5532,14 @@ var init_context_sniper = __esm({
5207
5532
  // src/ui/native.ts
5208
5533
  import { spawn } from "child_process";
5209
5534
  import path11 from "path";
5535
+ function resolveNativeDecision(opts) {
5536
+ const { code, output, elapsedMs, locked } = opts;
5537
+ if (locked) return "deny";
5538
+ const tooFast = elapsedMs < MIN_INTERACTION_MS;
5539
+ if (output.includes("Always Allow")) return tooFast ? "deny" : "always_allow";
5540
+ if (code === 0) return tooFast ? "deny" : "allow";
5541
+ return "deny";
5542
+ }
5210
5543
  function formatArgs(args, matchedField, matchedWord) {
5211
5544
  if (args === null || args === void 0) return { message: "(none)", intent: "EXEC" };
5212
5545
  let parsed = args;
@@ -5366,6 +5699,7 @@ async function askNativePopup(toolName, args, agent, explainableLabel, locked =
5366
5699
  );
5367
5700
  return new Promise((resolve) => {
5368
5701
  let childProcess = null;
5702
+ const startedAt = Date.now();
5369
5703
  const onAbort = () => {
5370
5704
  if (childProcess && childProcess.pid) {
5371
5705
  try {
@@ -5423,19 +5757,20 @@ end run`;
5423
5757
  }
5424
5758
  let output = "";
5425
5759
  childProcess?.stdout?.on("data", (d) => output += d.toString());
5426
- childProcess?.on("close", (code) => {
5760
+ childProcess?.on("error", () => {
5427
5761
  if (signal) signal.removeEventListener("abort", onAbort);
5428
- if (locked) return resolve("deny");
5429
- if (output.includes("Always Allow")) return resolve("always_allow");
5430
- if (code === 0) return resolve("allow");
5431
5762
  resolve("deny");
5432
5763
  });
5764
+ childProcess?.on("close", (code) => {
5765
+ if (signal) signal.removeEventListener("abort", onAbort);
5766
+ resolve(resolveNativeDecision({ code, output, elapsedMs: Date.now() - startedAt, locked }));
5767
+ });
5433
5768
  } catch {
5434
5769
  resolve("deny");
5435
5770
  }
5436
5771
  });
5437
5772
  }
5438
- var isTestEnv;
5773
+ var isTestEnv, MIN_INTERACTION_MS;
5439
5774
  var init_native = __esm({
5440
5775
  "src/ui/native.ts"() {
5441
5776
  "use strict";
@@ -5443,6 +5778,7 @@ var init_native = __esm({
5443
5778
  isTestEnv = () => {
5444
5779
  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";
5445
5780
  };
5781
+ MIN_INTERACTION_MS = 400;
5446
5782
  }
5447
5783
  });
5448
5784
 
@@ -5755,6 +6091,37 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
5755
6091
  if (taintResult.tainted && taintResult.record) {
5756
6092
  const { path: taintedPath, source: taintSource } = taintResult.record;
5757
6093
  taintWarning = `\u26A0\uFE0F ${taintedPath} was flagged by ${taintSource} \u2014 this file may contain sensitive data`;
6094
+ if (config.policy.egress?.enabled) {
6095
+ const a = args && typeof args === "object" && !Array.isArray(args) ? args : {};
6096
+ const cmd = typeof a.command === "string" ? a.command : typeof a.cmd === "string" ? a.cmd : "";
6097
+ const dests = cmd ? extractShellDestinations(cmd) : [];
6098
+ const eg = dests.length > 0 ? evaluateEgress(dests, config.policy.egress) : null;
6099
+ if (eg) {
6100
+ if (!isManual)
6101
+ appendLocalAudit(
6102
+ toolName,
6103
+ args,
6104
+ "deny",
6105
+ isObserveMode ? "observe-mode-taint-egress-would-block" : "taint-egress-block",
6106
+ { ...meta, ruleName: `taint-egress:${eg.host}` },
6107
+ hashAuditArgs
6108
+ );
6109
+ if (isObserveMode) {
6110
+ return {
6111
+ approved: true,
6112
+ checkedBy: "audit",
6113
+ observeWouldBlock: true,
6114
+ blockedByLabel: "\u{1F534} Node9 Taint+Egress (Exfiltration)"
6115
+ };
6116
+ }
6117
+ return {
6118
+ approved: false,
6119
+ 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.`,
6120
+ blockedBy: "local-config",
6121
+ blockedByLabel: "\u{1F534} Node9 Taint+Egress (Exfiltration Blocked)"
6122
+ };
6123
+ }
6124
+ }
5758
6125
  } else if (taintResult.daemonUnavailable) {
5759
6126
  taintWarning = `\u26A0\uFE0F Taint service unavailable \u2014 cannot verify if ${filePaths.join(", ")} is clean`;
5760
6127
  }
@@ -5803,6 +6170,35 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
5803
6170
  explainableLabel = "\u{1F6A8} Node9 DLP (Credential Review)";
5804
6171
  }
5805
6172
  }
6173
+ if (config.policy.dlp.pii === "block" && (!isIgnoredTool2(toolName) || config.policy.dlp.scanIgnoredTools)) {
6174
+ const piiFound = detectArgsPii(args);
6175
+ if (piiFound.length > 0) {
6176
+ const piiReason = `\u{1F512} PII DETECTED: ${piiFound.join(", ")} found in tool arguments. Remove or tokenize personal data before passing it to a tool.`;
6177
+ if (!isManual)
6178
+ appendLocalAudit(
6179
+ toolName,
6180
+ args,
6181
+ "deny",
6182
+ isObserveMode ? "observe-mode-pii-would-block" : "pii-block",
6183
+ { ...meta, piiPatterns: piiFound.join(",") },
6184
+ true
6185
+ );
6186
+ if (isObserveMode) {
6187
+ return {
6188
+ approved: true,
6189
+ checkedBy: "audit",
6190
+ observeWouldBlock: true,
6191
+ blockedByLabel: "\u{1F512} Node9 PII (Detected)"
6192
+ };
6193
+ }
6194
+ return {
6195
+ approved: false,
6196
+ reason: piiReason,
6197
+ blockedBy: "local-config",
6198
+ blockedByLabel: "\u{1F512} Node9 PII (Detected)"
6199
+ };
6200
+ }
6201
+ }
5806
6202
  if (isObserveMode) {
5807
6203
  if (!isIgnoredTool2(toolName)) {
5808
6204
  const policyResult = await evaluatePolicy2(toolName, args, meta?.agent, options?.cwd);
@@ -6251,6 +6647,7 @@ var init_orchestrator = __esm({
6251
6647
  init_native();
6252
6648
  init_context_sniper();
6253
6649
  init_dlp();
6650
+ init_dist();
6254
6651
  init_audit();
6255
6652
  init_config();
6256
6653
  init_policy();
@@ -9602,18 +9999,118 @@ var init_litellm = __esm({
9602
9999
  }
9603
10000
  });
9604
10001
 
9605
- // src/costSync.ts
10002
+ // src/cost-codex.ts
9606
10003
  import fs17 from "fs";
9607
- import path19 from "path";
9608
10004
  import os16 from "os";
10005
+ import path19 from "path";
10006
+ function codexLogPath() {
10007
+ return path19.join(os16.homedir(), ".codex", "log", "codex-tui.log");
10008
+ }
10009
+ function parseCodexUsageLine(line) {
10010
+ if (!line.includes("token_usage")) return null;
10011
+ const date = line.match(RE_DATE)?.[1];
10012
+ if (!date) return null;
10013
+ const model = line.match(RE_MODEL)?.[1];
10014
+ if (!model) return null;
10015
+ const num3 = (re) => {
10016
+ const m = line.match(re);
10017
+ return m ? Number(m[1]) : 0;
10018
+ };
10019
+ const totalInput = num3(RE_INPUT);
10020
+ const cached = num3(RE_CACHED);
10021
+ const nonCached = num3(RE_NON_CACHED);
10022
+ const output = num3(RE_OUTPUT);
10023
+ const inputTokens = nonCached || Math.max(0, totalInput - cached);
10024
+ if (inputTokens === 0 && output === 0 && cached === 0) return null;
10025
+ const runId = line.match(RE_THREAD)?.[1] ?? "";
10026
+ const norm = normalizeModel(model);
10027
+ const p = pricingFor(model);
10028
+ const costUSD = p ? inputTokens * p[0] + output * p[1] + cached * p[3] : 0;
10029
+ return {
10030
+ date,
10031
+ model: norm,
10032
+ workingDir: "",
10033
+ // Codex span carries no cwd — attribution is by runId (thread)
10034
+ runId,
10035
+ costUSD,
10036
+ inputTokens,
10037
+ outputTokens: output,
10038
+ cacheReadTokens: cached,
10039
+ cacheWriteTokens: 0
10040
+ };
10041
+ }
10042
+ var RE_INPUT, RE_CACHED, RE_NON_CACHED, RE_OUTPUT, RE_MODEL, RE_THREAD, RE_DATE, codexSource;
10043
+ var init_cost_codex = __esm({
10044
+ "src/cost-codex.ts"() {
10045
+ "use strict";
10046
+ init_litellm();
10047
+ RE_INPUT = /token_usage\.input_tokens=(\d+)/;
10048
+ RE_CACHED = /token_usage\.cached_input_tokens=(\d+)/;
10049
+ RE_NON_CACHED = /token_usage\.non_cached_input_tokens=(\d+)/;
10050
+ RE_OUTPUT = /token_usage\.output_tokens=(\d+)/;
10051
+ RE_MODEL = /\bmodel=([^\s}]+)/;
10052
+ RE_THREAD = /\bthread\.id=([0-9a-fA-F-]+)/;
10053
+ RE_DATE = /^(\d{4}-\d{2}-\d{2})T/;
10054
+ codexSource = {
10055
+ id: "codex",
10056
+ available() {
10057
+ try {
10058
+ return fs17.existsSync(codexLogPath());
10059
+ } catch {
10060
+ return false;
10061
+ }
10062
+ },
10063
+ collect(sinceMs) {
10064
+ const file = codexLogPath();
10065
+ let content;
10066
+ try {
10067
+ if (sinceMs !== void 0 && fs17.statSync(file).mtimeMs < sinceMs) return [];
10068
+ content = fs17.readFileSync(file, "utf8");
10069
+ } catch {
10070
+ return [];
10071
+ }
10072
+ const combined = /* @__PURE__ */ new Map();
10073
+ for (const line of content.split("\n")) {
10074
+ if (!line.includes("token_usage")) continue;
10075
+ if (sinceMs !== void 0) {
10076
+ const tsFull = line.match(/^(\S+)\s/)?.[1];
10077
+ if (tsFull) {
10078
+ const t = Date.parse(tsFull);
10079
+ if (!Number.isNaN(t) && t < sinceMs) continue;
10080
+ }
10081
+ }
10082
+ const e = parseCodexUsageLine(line);
10083
+ if (!e) continue;
10084
+ const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
10085
+ const prev = combined.get(key);
10086
+ if (prev) {
10087
+ prev.costUSD += e.costUSD;
10088
+ prev.inputTokens += e.inputTokens;
10089
+ prev.outputTokens += e.outputTokens;
10090
+ prev.cacheReadTokens += e.cacheReadTokens;
10091
+ prev.cacheWriteTokens += e.cacheWriteTokens;
10092
+ } else {
10093
+ combined.set(key, { ...e });
10094
+ }
10095
+ }
10096
+ return [...combined.values()];
10097
+ }
10098
+ };
10099
+ }
10100
+ });
10101
+
10102
+ // src/costSync.ts
10103
+ import fs18 from "fs";
10104
+ import path20 from "path";
10105
+ import os17 from "os";
9609
10106
  function decodeProjectDirName(dirName) {
9610
10107
  return dirName.replace(/-/g, "/");
9611
10108
  }
9612
10109
  function parseJSONLFile(filePath, fallbackWorkingDir) {
9613
- const runId = path19.basename(filePath, ".jsonl");
10110
+ const runId = path20.basename(filePath, ".jsonl");
9614
10111
  let content;
9615
10112
  try {
9616
- content = fs17.readFileSync(filePath, "utf8");
10113
+ content = fs18.readFileSync(filePath, "utf8");
9617
10114
  } catch {
9618
10115
  return /* @__PURE__ */ new Map();
9619
10116
  }
@@ -9668,51 +10165,30 @@ function parseJSONLFile(filePath, fallbackWorkingDir) {
9668
10165
  }
9669
10166
  return daily;
9670
10167
  }
10168
+ function entryKey(e) {
10169
+ return `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
10170
+ }
9671
10171
  function collectEntries(sinceMs) {
9672
- const projectsDir = path19.join(os16.homedir(), ".claude", "projects");
9673
- if (!fs17.existsSync(projectsDir)) return [];
9674
10172
  const combined = /* @__PURE__ */ new Map();
9675
- let dirs;
9676
- try {
9677
- dirs = fs17.readdirSync(projectsDir);
9678
- } catch {
9679
- return [];
9680
- }
9681
- for (const dir of dirs) {
9682
- const dirPath = path19.join(projectsDir, dir);
9683
- try {
9684
- if (!fs17.statSync(dirPath).isDirectory()) continue;
9685
- } catch {
9686
- continue;
9687
- }
9688
- let files;
10173
+ for (const src of COST_SOURCES) {
10174
+ let rows;
9689
10175
  try {
9690
- files = fs17.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10176
+ if (!src.available()) continue;
10177
+ rows = src.collect(sinceMs);
9691
10178
  } catch {
9692
10179
  continue;
9693
10180
  }
9694
- const fallbackWorkingDir = decodeProjectDirName(dir);
9695
- for (const file of files) {
9696
- const filePath = path19.join(dirPath, file);
9697
- if (sinceMs !== void 0) {
9698
- try {
9699
- if (fs17.statSync(filePath).mtimeMs < sinceMs) continue;
9700
- } catch {
9701
- continue;
9702
- }
9703
- }
9704
- const entries = parseJSONLFile(filePath, fallbackWorkingDir);
9705
- for (const [key, e] of entries) {
9706
- const prev = combined.get(key);
9707
- if (prev) {
9708
- prev.costUSD += e.costUSD;
9709
- prev.inputTokens += e.inputTokens;
9710
- prev.outputTokens += e.outputTokens;
9711
- prev.cacheWriteTokens += e.cacheWriteTokens;
9712
- prev.cacheReadTokens += e.cacheReadTokens;
9713
- } else {
9714
- combined.set(key, { ...e });
9715
- }
10181
+ for (const e of rows) {
10182
+ const key = entryKey(e);
10183
+ const prev = combined.get(key);
10184
+ if (prev) {
10185
+ prev.costUSD += e.costUSD;
10186
+ prev.inputTokens += e.inputTokens;
10187
+ prev.outputTokens += e.outputTokens;
10188
+ prev.cacheWriteTokens += e.cacheWriteTokens;
10189
+ prev.cacheReadTokens += e.cacheReadTokens;
10190
+ } else {
10191
+ combined.set(key, { ...e });
9716
10192
  }
9717
10193
  }
9718
10194
  }
@@ -9726,10 +10202,10 @@ async function syncCost() {
9726
10202
  if (entries.length === 0) return;
9727
10203
  let username = "unknown";
9728
10204
  try {
9729
- username = os16.userInfo().username;
10205
+ username = os17.userInfo().username;
9730
10206
  } catch {
9731
10207
  }
9732
- const machineId = `${os16.hostname()}:${username}`;
10208
+ const machineId = `${os17.hostname()}:${username}`;
9733
10209
  try {
9734
10210
  const res = await fetch(`${creds.apiUrl}/cost-sync`, {
9735
10211
  method: "POST",
@@ -9738,11 +10214,11 @@ async function syncCost() {
9738
10214
  signal: AbortSignal.timeout(15e3)
9739
10215
  });
9740
10216
  if (!res.ok) {
9741
- fs17.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
10217
+ fs18.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
9742
10218
  `);
9743
10219
  }
9744
10220
  } catch (err2) {
9745
- fs17.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
10221
+ fs18.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
9746
10222
  `);
9747
10223
  }
9748
10224
  }
@@ -9755,14 +10231,72 @@ function startCostSync() {
9755
10231
  }, SYNC_INTERVAL_MS);
9756
10232
  timer.unref();
9757
10233
  }
9758
- var SYNC_INTERVAL_MS;
10234
+ var SYNC_INTERVAL_MS, claudeSource, COST_SOURCES;
9759
10235
  var init_costSync = __esm({
9760
10236
  "src/costSync.ts"() {
9761
10237
  "use strict";
9762
10238
  init_config();
9763
10239
  init_audit();
9764
10240
  init_litellm();
10241
+ init_cost_codex();
9765
10242
  SYNC_INTERVAL_MS = 10 * 60 * 1e3;
10243
+ claudeSource = {
10244
+ id: "claude",
10245
+ available() {
10246
+ return fs18.existsSync(path20.join(os17.homedir(), ".claude", "projects"));
10247
+ },
10248
+ collect(sinceMs) {
10249
+ const projectsDir = path20.join(os17.homedir(), ".claude", "projects");
10250
+ if (!fs18.existsSync(projectsDir)) return [];
10251
+ const combined = /* @__PURE__ */ new Map();
10252
+ let dirs;
10253
+ try {
10254
+ dirs = fs18.readdirSync(projectsDir);
10255
+ } catch {
10256
+ return [];
10257
+ }
10258
+ for (const dir of dirs) {
10259
+ const dirPath = path20.join(projectsDir, dir);
10260
+ try {
10261
+ if (!fs18.statSync(dirPath).isDirectory()) continue;
10262
+ } catch {
10263
+ continue;
10264
+ }
10265
+ let files;
10266
+ try {
10267
+ files = fs18.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10268
+ } catch {
10269
+ continue;
10270
+ }
10271
+ const fallbackWorkingDir = decodeProjectDirName(dir);
10272
+ for (const file of files) {
10273
+ const filePath = path20.join(dirPath, file);
10274
+ if (sinceMs !== void 0) {
10275
+ try {
10276
+ if (fs18.statSync(filePath).mtimeMs < sinceMs) continue;
10277
+ } catch {
10278
+ continue;
10279
+ }
10280
+ }
10281
+ const entries = parseJSONLFile(filePath, fallbackWorkingDir);
10282
+ for (const [key, e] of entries) {
10283
+ const prev = combined.get(key);
10284
+ if (prev) {
10285
+ prev.costUSD += e.costUSD;
10286
+ prev.inputTokens += e.inputTokens;
10287
+ prev.outputTokens += e.outputTokens;
10288
+ prev.cacheWriteTokens += e.cacheWriteTokens;
10289
+ prev.cacheReadTokens += e.cacheReadTokens;
10290
+ } else {
10291
+ combined.set(key, { ...e });
10292
+ }
10293
+ }
10294
+ }
10295
+ }
10296
+ return [...combined.values()];
10297
+ }
10298
+ };
10299
+ COST_SOURCES = [claudeSource, codexSource];
9766
10300
  }
9767
10301
  });
9768
10302
 
@@ -9778,9 +10312,9 @@ __export(scan_watermark_exports, {
9778
10312
  tickForensicBroadcast: () => tickForensicBroadcast,
9779
10313
  tickScanWatcher: () => tickScanWatcher
9780
10314
  });
9781
- import fs18 from "fs";
9782
- import os17 from "os";
9783
- import path20 from "path";
10315
+ import fs19 from "fs";
10316
+ import os18 from "os";
10317
+ import path21 from "path";
9784
10318
  import readline from "readline";
9785
10319
  function freshWatermark() {
9786
10320
  return {
@@ -9793,7 +10327,7 @@ function freshWatermark() {
9793
10327
  function loadWatermark() {
9794
10328
  let raw;
9795
10329
  try {
9796
- raw = fs18.readFileSync(WATERMARK_FILE(), "utf-8");
10330
+ raw = fs19.readFileSync(WATERMARK_FILE(), "utf-8");
9797
10331
  } catch {
9798
10332
  return { status: "fresh", wm: freshWatermark() };
9799
10333
  }
@@ -9845,28 +10379,28 @@ function loadWatermark() {
9845
10379
  function saveWatermark(wm) {
9846
10380
  if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
9847
10381
  const target = WATERMARK_FILE();
9848
- const dir = path20.dirname(target);
9849
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
10382
+ const dir = path21.dirname(target);
10383
+ if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
9850
10384
  const tmp = target + ".tmp";
9851
- fs18.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
9852
- fs18.renameSync(tmp, target);
10385
+ fs19.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
10386
+ fs19.renameSync(tmp, target);
9853
10387
  }
9854
10388
  function listJsonlFiles() {
9855
10389
  const root = PROJECTS_DIR();
9856
- if (!fs18.existsSync(root)) return [];
10390
+ if (!fs19.existsSync(root)) return [];
9857
10391
  const out = [];
9858
- for (const entry of fs18.readdirSync(root, { withFileTypes: true })) {
10392
+ for (const entry of fs19.readdirSync(root, { withFileTypes: true })) {
9859
10393
  if (!entry.isDirectory()) continue;
9860
- const projectDir = path20.join(root, entry.name);
10394
+ const projectDir = path21.join(root, entry.name);
9861
10395
  let inner;
9862
10396
  try {
9863
- inner = fs18.readdirSync(projectDir, { withFileTypes: true });
10397
+ inner = fs19.readdirSync(projectDir, { withFileTypes: true });
9864
10398
  } catch {
9865
10399
  continue;
9866
10400
  }
9867
10401
  for (const file of inner) {
9868
10402
  if (file.isFile() && file.name.endsWith(".jsonl")) {
9869
- out.push(path20.join(projectDir, file.name));
10403
+ out.push(path21.join(projectDir, file.name));
9870
10404
  }
9871
10405
  }
9872
10406
  }
@@ -9874,7 +10408,7 @@ function listJsonlFiles() {
9874
10408
  }
9875
10409
  function fileSize(p) {
9876
10410
  try {
9877
- return fs18.statSync(p).size;
10411
+ return fs19.statSync(p).size;
9878
10412
  } catch {
9879
10413
  return 0;
9880
10414
  }
@@ -9882,7 +10416,7 @@ function fileSize(p) {
9882
10416
  async function scanDelta(filePath, fromByte, onLine) {
9883
10417
  const size = fileSize(filePath);
9884
10418
  if (size <= fromByte) return fromByte;
9885
- const stream = fs18.createReadStream(filePath, {
10419
+ const stream = fs19.createReadStream(filePath, {
9886
10420
  start: fromByte,
9887
10421
  end: size - 1,
9888
10422
  highWaterMark: 64 * 1024
@@ -9994,7 +10528,7 @@ async function tickForensicBroadcast(offsets) {
9994
10528
  continue;
9995
10529
  }
9996
10530
  if (size <= offset) continue;
9997
- const sessionId = path20.basename(file, ".jsonl");
10531
+ const sessionId = path21.basename(file, ".jsonl");
9998
10532
  const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
9999
10533
  out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
10000
10534
  });
@@ -10053,7 +10587,7 @@ function emptyTick(uploadAs) {
10053
10587
  function readRawWatermarkPreservingOffsets() {
10054
10588
  let raw;
10055
10589
  try {
10056
- raw = fs18.readFileSync(WATERMARK_FILE(), "utf-8");
10590
+ raw = fs19.readFileSync(WATERMARK_FILE(), "utf-8");
10057
10591
  } catch {
10058
10592
  return null;
10059
10593
  }
@@ -10087,13 +10621,13 @@ async function runActualTick(wm) {
10087
10621
  if (!known) {
10088
10622
  let mtimeMs = 0;
10089
10623
  try {
10090
- mtimeMs = fs18.statSync(filePath).mtime.getTime();
10624
+ mtimeMs = fs19.statSync(filePath).mtime.getTime();
10091
10625
  } catch {
10092
10626
  continue;
10093
10627
  }
10094
10628
  if (mtimeMs >= watermarkCreatedAt) {
10095
10629
  filesNew++;
10096
- const sessionId2 = path20.basename(filePath, ".jsonl");
10630
+ const sessionId2 = path21.basename(filePath, ".jsonl");
10097
10631
  const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
10098
10632
  totalToolCalls++;
10099
10633
  toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
@@ -10111,7 +10645,7 @@ async function runActualTick(wm) {
10111
10645
  filesSkipped++;
10112
10646
  continue;
10113
10647
  }
10114
- const sessionId = path20.basename(filePath, ".jsonl");
10648
+ const sessionId = path21.basename(filePath, ".jsonl");
10115
10649
  const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
10116
10650
  totalToolCalls++;
10117
10651
  toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
@@ -10139,8 +10673,8 @@ var init_scan_watermark = __esm({
10139
10673
  "use strict";
10140
10674
  init_dlp();
10141
10675
  init_dist();
10142
- PROJECTS_DIR = () => path20.join(os17.homedir(), ".claude", "projects");
10143
- WATERMARK_FILE = () => path20.join(os17.homedir(), ".node9", "scan-watermark.json");
10676
+ PROJECTS_DIR = () => path21.join(os18.homedir(), ".claude", "projects");
10677
+ WATERMARK_FILE = () => path21.join(os18.homedir(), ".node9", "scan-watermark.json");
10144
10678
  MAX_LINE_BYTES = 2 * 1024 * 1024;
10145
10679
  WATERMARK_SCHEMA_VERSION = 2;
10146
10680
  LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
@@ -10151,14 +10685,15 @@ var init_scan_watermark = __esm({
10151
10685
  var scan_upload_history_exports = {};
10152
10686
  __export(scan_upload_history_exports, {
10153
10687
  buildSessionTotals: () => buildSessionTotals,
10688
+ extractHistoricalLoops: () => extractHistoricalLoops,
10154
10689
  iterateJsonlFiles: () => iterateJsonlFiles,
10155
10690
  parseSinceCutoff: () => parseSinceCutoff,
10156
10691
  runUploadHistory: () => runUploadHistory
10157
10692
  });
10158
- import fs19 from "fs";
10693
+ import fs20 from "fs";
10159
10694
  import https from "https";
10160
- import os18 from "os";
10161
- import path21 from "path";
10695
+ import os19 from "os";
10696
+ import path22 from "path";
10162
10697
  import chalk4 from "chalk";
10163
10698
  function emptySignals2() {
10164
10699
  return {
@@ -10193,40 +10728,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
10193
10728
  return now.getTime() - 90 * 864e5;
10194
10729
  }
10195
10730
  function* iterateJsonlFiles(cutoffMs) {
10196
- const projectsDir = path21.join(os18.homedir(), ".claude", "projects");
10731
+ const projectsDir = path22.join(os19.homedir(), ".claude", "projects");
10197
10732
  let dirs;
10198
10733
  try {
10199
- dirs = fs19.readdirSync(projectsDir);
10734
+ dirs = fs20.readdirSync(projectsDir);
10200
10735
  } catch {
10201
10736
  return;
10202
10737
  }
10203
10738
  for (const dir of dirs) {
10204
- const dirPath = path21.join(projectsDir, dir);
10739
+ const dirPath = path22.join(projectsDir, dir);
10205
10740
  let stats;
10206
10741
  try {
10207
- stats = fs19.statSync(dirPath);
10742
+ stats = fs20.statSync(dirPath);
10208
10743
  } catch {
10209
10744
  continue;
10210
10745
  }
10211
10746
  if (!stats.isDirectory()) continue;
10212
10747
  let files;
10213
10748
  try {
10214
- files = fs19.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10749
+ files = fs20.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10215
10750
  } catch {
10216
10751
  continue;
10217
10752
  }
10218
10753
  for (const file of files) {
10219
- const filePath = path21.join(dirPath, file);
10754
+ const filePath = path22.join(dirPath, file);
10220
10755
  let mtime = 0;
10221
10756
  try {
10222
- mtime = fs19.statSync(filePath).mtimeMs;
10757
+ mtime = fs20.statSync(filePath).mtimeMs;
10223
10758
  } catch {
10224
10759
  continue;
10225
10760
  }
10226
10761
  if (mtime < cutoffMs) continue;
10227
10762
  yield {
10228
10763
  filePath,
10229
- sessionId: path21.basename(file, ".jsonl"),
10764
+ sessionId: path22.basename(file, ".jsonl"),
10230
10765
  projectDir: dir
10231
10766
  };
10232
10767
  }
@@ -10249,6 +10784,19 @@ function buildSessionTotals(findings, toolCallsBySession) {
10249
10784
  signals
10250
10785
  }));
10251
10786
  }
10787
+ function extractHistoricalLoops(sessionCalls, ctx) {
10788
+ return extractSessionLevelFindings(sessionCalls, {
10789
+ sessionId: ctx.sessionId,
10790
+ project: ctx.project,
10791
+ agent: ctx.agent,
10792
+ loopDetection: {
10793
+ enabled: true,
10794
+ threshold: ctx.threshold,
10795
+ windowSeconds: 0
10796
+ // whole session — never the live blocker's window
10797
+ }
10798
+ });
10799
+ }
10252
10800
  async function runUploadHistory(opts) {
10253
10801
  const creds = getCredentials();
10254
10802
  if (!creds?.apiKey) {
@@ -10279,7 +10827,7 @@ async function runUploadHistory(opts) {
10279
10827
  filesScanned++;
10280
10828
  let content;
10281
10829
  try {
10282
- content = fs19.readFileSync(filePath, "utf8");
10830
+ content = fs20.readFileSync(filePath, "utf8");
10283
10831
  } catch {
10284
10832
  continue;
10285
10833
  }
@@ -10318,15 +10866,11 @@ async function runUploadHistory(opts) {
10318
10866
  lineIndex++;
10319
10867
  }
10320
10868
  if (loopCfg.enabled && sessionCalls.length > 0) {
10321
- const loops = extractSessionLevelFindings(sessionCalls, {
10869
+ const loops = extractHistoricalLoops(sessionCalls, {
10322
10870
  sessionId,
10323
10871
  project: decodeProjectDirName(projectDir),
10324
10872
  agent: "claude",
10325
- loopDetection: {
10326
- enabled: loopCfg.enabled,
10327
- threshold: loopCfg.threshold,
10328
- windowSeconds: loopCfg.windowSeconds
10329
- }
10873
+ threshold: loopCfg.threshold
10330
10874
  });
10331
10875
  for (const cf of loops) {
10332
10876
  const sf = toScanFinding(cf);
@@ -10365,10 +10909,10 @@ async function runUploadHistory(opts) {
10365
10909
  const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
10366
10910
  let username = "unknown";
10367
10911
  try {
10368
- username = os18.userInfo().username;
10912
+ username = os19.userInfo().username;
10369
10913
  } catch {
10370
10914
  }
10371
- const machineId = `${os18.hostname()}:${username}`;
10915
+ const machineId = `${os19.hostname()}:${username}`;
10372
10916
  await postJson(costUrl, creds.apiKey, {
10373
10917
  machineId,
10374
10918
  entries: dailyEntries
@@ -10442,9 +10986,9 @@ var init_scan_upload_history = __esm({
10442
10986
 
10443
10987
  // src/cli/commands/scan.ts
10444
10988
  import chalk5 from "chalk";
10445
- import fs20 from "fs";
10446
- import path22 from "path";
10447
- import os19 from "os";
10989
+ import fs21 from "fs";
10990
+ import path23 from "path";
10991
+ import os20 from "os";
10448
10992
  import stringWidth2 from "string-width";
10449
10993
  function claudeModelPrice(model) {
10450
10994
  const base = model.replace(/@.*$/, "").replace(/-\d{8}$/, "");
@@ -10671,14 +11215,14 @@ function buildRuleSources() {
10671
11215
  }
10672
11216
  function countScanFiles() {
10673
11217
  let total = 0;
10674
- const claudeDir = path22.join(os19.homedir(), ".claude", "projects");
10675
- if (fs20.existsSync(claudeDir)) {
11218
+ const claudeDir = path23.join(os20.homedir(), ".claude", "projects");
11219
+ if (fs21.existsSync(claudeDir)) {
10676
11220
  try {
10677
- for (const proj of fs20.readdirSync(claudeDir)) {
10678
- const p = path22.join(claudeDir, proj);
11221
+ for (const proj of fs21.readdirSync(claudeDir)) {
11222
+ const p = path23.join(claudeDir, proj);
10679
11223
  try {
10680
- if (!fs20.statSync(p).isDirectory()) continue;
10681
- total += fs20.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
11224
+ if (!fs21.statSync(p).isDirectory()) continue;
11225
+ total += fs21.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
10682
11226
  } catch {
10683
11227
  continue;
10684
11228
  }
@@ -10686,17 +11230,17 @@ function countScanFiles() {
10686
11230
  } catch {
10687
11231
  }
10688
11232
  }
10689
- const geminiDir = path22.join(os19.homedir(), ".gemini", "tmp");
10690
- if (fs20.existsSync(geminiDir)) {
11233
+ const geminiDir = path23.join(os20.homedir(), ".gemini", "tmp");
11234
+ if (fs21.existsSync(geminiDir)) {
10691
11235
  try {
10692
- for (const slug of fs20.readdirSync(geminiDir)) {
10693
- const p = path22.join(geminiDir, slug);
11236
+ for (const slug of fs21.readdirSync(geminiDir)) {
11237
+ const p = path23.join(geminiDir, slug);
10694
11238
  try {
10695
- if (!fs20.statSync(p).isDirectory()) continue;
10696
- const chatsDir = path22.join(p, "chats");
10697
- if (fs20.existsSync(chatsDir)) {
11239
+ if (!fs21.statSync(p).isDirectory()) continue;
11240
+ const chatsDir = path23.join(p, "chats");
11241
+ if (fs21.existsSync(chatsDir)) {
10698
11242
  try {
10699
- total += fs20.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
11243
+ total += fs21.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
10700
11244
  } catch {
10701
11245
  }
10702
11246
  }
@@ -10708,15 +11252,15 @@ function countScanFiles() {
10708
11252
  }
10709
11253
  }
10710
11254
  for (const surface of ["antigravity-cli", "antigravity-ide"]) {
10711
- const brainDir = path22.join(os19.homedir(), ".gemini", surface, "brain");
10712
- if (!fs20.existsSync(brainDir)) continue;
11255
+ const brainDir = path23.join(os20.homedir(), ".gemini", surface, "brain");
11256
+ if (!fs21.existsSync(brainDir)) continue;
10713
11257
  try {
10714
- for (const conv of fs20.readdirSync(brainDir)) {
10715
- const convPath = path22.join(brainDir, conv);
11258
+ for (const conv of fs21.readdirSync(brainDir)) {
11259
+ const convPath = path23.join(brainDir, conv);
10716
11260
  try {
10717
- if (!fs20.statSync(convPath).isDirectory()) continue;
10718
- const logsDir = path22.join(convPath, ".system_generated", "logs");
10719
- if (fs20.existsSync(path22.join(logsDir, "transcript_full.jsonl")) || fs20.existsSync(path22.join(logsDir, "transcript.jsonl"))) {
11261
+ if (!fs21.statSync(convPath).isDirectory()) continue;
11262
+ const logsDir = path23.join(convPath, ".system_generated", "logs");
11263
+ if (fs21.existsSync(path23.join(logsDir, "transcript_full.jsonl")) || fs21.existsSync(path23.join(logsDir, "transcript.jsonl"))) {
10720
11264
  total += 1;
10721
11265
  }
10722
11266
  } catch {
@@ -10726,31 +11270,31 @@ function countScanFiles() {
10726
11270
  } catch {
10727
11271
  }
10728
11272
  }
10729
- const copilotDir = path22.join(os19.homedir(), ".copilot", "session-state");
10730
- if (fs20.existsSync(copilotDir)) {
11273
+ const copilotDir = path23.join(os20.homedir(), ".copilot", "session-state");
11274
+ if (fs21.existsSync(copilotDir)) {
10731
11275
  try {
10732
- for (const sid of fs20.readdirSync(copilotDir)) {
10733
- if (fs20.existsSync(path22.join(copilotDir, sid, "events.jsonl"))) total += 1;
11276
+ for (const sid of fs21.readdirSync(copilotDir)) {
11277
+ if (fs21.existsSync(path23.join(copilotDir, sid, "events.jsonl"))) total += 1;
10734
11278
  }
10735
11279
  } catch {
10736
11280
  }
10737
11281
  }
10738
- const codexDir = path22.join(os19.homedir(), ".codex", "sessions");
10739
- if (fs20.existsSync(codexDir)) {
11282
+ const codexDir = path23.join(os20.homedir(), ".codex", "sessions");
11283
+ if (fs21.existsSync(codexDir)) {
10740
11284
  try {
10741
- for (const year of fs20.readdirSync(codexDir)) {
10742
- const yp = path22.join(codexDir, year);
11285
+ for (const year of fs21.readdirSync(codexDir)) {
11286
+ const yp = path23.join(codexDir, year);
10743
11287
  try {
10744
- if (!fs20.statSync(yp).isDirectory()) continue;
10745
- for (const month of fs20.readdirSync(yp)) {
10746
- const mp = path22.join(yp, month);
11288
+ if (!fs21.statSync(yp).isDirectory()) continue;
11289
+ for (const month of fs21.readdirSync(yp)) {
11290
+ const mp = path23.join(yp, month);
10747
11291
  try {
10748
- if (!fs20.statSync(mp).isDirectory()) continue;
10749
- for (const day of fs20.readdirSync(mp)) {
10750
- const dp = path22.join(mp, day);
11292
+ if (!fs21.statSync(mp).isDirectory()) continue;
11293
+ for (const day of fs21.readdirSync(mp)) {
11294
+ const dp = path23.join(mp, day);
10751
11295
  try {
10752
- if (!fs20.statSync(dp).isDirectory()) continue;
10753
- total += fs20.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
11296
+ if (!fs21.statSync(dp).isDirectory()) continue;
11297
+ total += fs21.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
10754
11298
  } catch {
10755
11299
  continue;
10756
11300
  }
@@ -10786,7 +11330,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
10786
11330
  const sessionId = file.replace(/\.jsonl$/, "");
10787
11331
  let raw;
10788
11332
  try {
10789
- raw = fs20.readFileSync(path22.join(projPath, file), "utf-8");
11333
+ raw = fs21.readFileSync(path23.join(projPath, file), "utf-8");
10790
11334
  } catch {
10791
11335
  return;
10792
11336
  }
@@ -10838,7 +11382,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
10838
11382
  if (block.type !== "tool_result") continue;
10839
11383
  const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
10840
11384
  if (filePath) {
10841
- const ext = path22.extname(filePath).toLowerCase();
11385
+ const ext = path23.extname(filePath).toLowerCase();
10842
11386
  if (CODE_EXTENSIONS.has(ext)) continue;
10843
11387
  }
10844
11388
  const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
@@ -10895,7 +11439,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
10895
11439
  const rawCmd = String(input.command ?? "").trimStart();
10896
11440
  if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
10897
11441
  const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
10898
- const inputFileExt = inputFilePath ? path22.extname(inputFilePath).toLowerCase() : "";
11442
+ const inputFileExt = inputFilePath ? path23.extname(inputFilePath).toLowerCase() : "";
10899
11443
  if (CODE_EXTENSIONS.has(inputFileExt)) continue;
10900
11444
  const dlpMatch = scanArgs(input);
10901
11445
  if (dlpMatch) {
@@ -10992,19 +11536,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
10992
11536
  }
10993
11537
  }
10994
11538
  function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
10995
- const projPath = path22.join(projectsDir, proj);
11539
+ const projPath = path23.join(projectsDir, proj);
10996
11540
  try {
10997
- if (!fs20.statSync(projPath).isDirectory()) return;
11541
+ if (!fs21.statSync(projPath).isDirectory()) return;
10998
11542
  } catch {
10999
11543
  return;
11000
11544
  }
11001
- const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(os19.homedir(), "~")).slice(
11545
+ const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(os20.homedir(), "~")).slice(
11002
11546
  0,
11003
11547
  40
11004
11548
  );
11005
11549
  let files;
11006
11550
  try {
11007
- files = fs20.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
11551
+ files = fs21.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
11008
11552
  } catch {
11009
11553
  return;
11010
11554
  }
@@ -11038,12 +11582,12 @@ function emptyClaudeScan() {
11038
11582
  };
11039
11583
  }
11040
11584
  function scanClaudeHistory(startDate, onProgress, onLine) {
11041
- const projectsDir = path22.join(os19.homedir(), ".claude", "projects");
11585
+ const projectsDir = path23.join(os20.homedir(), ".claude", "projects");
11042
11586
  const result = emptyClaudeScan();
11043
- if (!fs20.existsSync(projectsDir)) return result;
11587
+ if (!fs21.existsSync(projectsDir)) return result;
11044
11588
  let projDirs;
11045
11589
  try {
11046
- projDirs = fs20.readdirSync(projectsDir);
11590
+ projDirs = fs21.readdirSync(projectsDir);
11047
11591
  } catch {
11048
11592
  return result;
11049
11593
  }
@@ -11064,7 +11608,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
11064
11608
  return result;
11065
11609
  }
11066
11610
  function scanGeminiHistory(startDate, onProgress, onLine) {
11067
- const tmpDir = path22.join(os19.homedir(), ".gemini", "tmp");
11611
+ const tmpDir = path23.join(os20.homedir(), ".gemini", "tmp");
11068
11612
  const result = {
11069
11613
  filesScanned: 0,
11070
11614
  sessions: 0,
@@ -11079,33 +11623,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
11079
11623
  sessionsWithEarlySecrets: 0
11080
11624
  };
11081
11625
  const dedup = emptyScanDedup();
11082
- if (!fs20.existsSync(tmpDir)) return result;
11626
+ if (!fs21.existsSync(tmpDir)) return result;
11083
11627
  let slugDirs;
11084
11628
  try {
11085
- slugDirs = fs20.readdirSync(tmpDir);
11629
+ slugDirs = fs21.readdirSync(tmpDir);
11086
11630
  } catch {
11087
11631
  return result;
11088
11632
  }
11089
11633
  const ruleSources = buildRuleSources();
11090
11634
  for (const slug of slugDirs) {
11091
- const slugPath = path22.join(tmpDir, slug);
11635
+ const slugPath = path23.join(tmpDir, slug);
11092
11636
  try {
11093
- if (!fs20.statSync(slugPath).isDirectory()) continue;
11637
+ if (!fs21.statSync(slugPath).isDirectory()) continue;
11094
11638
  } catch {
11095
11639
  continue;
11096
11640
  }
11097
11641
  let projLabel = stripTerminalEscapes(slug).slice(0, 40);
11098
11642
  try {
11099
11643
  projLabel = stripTerminalEscapes(
11100
- fs20.readFileSync(path22.join(slugPath, ".project_root"), "utf-8").trim()
11101
- ).replace(os19.homedir(), "~").slice(0, 40);
11644
+ fs21.readFileSync(path23.join(slugPath, ".project_root"), "utf-8").trim()
11645
+ ).replace(os20.homedir(), "~").slice(0, 40);
11102
11646
  } catch {
11103
11647
  }
11104
- const chatsDir = path22.join(slugPath, "chats");
11105
- if (!fs20.existsSync(chatsDir)) continue;
11648
+ const chatsDir = path23.join(slugPath, "chats");
11649
+ if (!fs21.existsSync(chatsDir)) continue;
11106
11650
  let chatFiles;
11107
11651
  try {
11108
- chatFiles = fs20.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
11652
+ chatFiles = fs21.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
11109
11653
  } catch {
11110
11654
  continue;
11111
11655
  }
@@ -11115,7 +11659,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
11115
11659
  const sessionId = chatFile.replace(/\.json$/, "");
11116
11660
  let raw;
11117
11661
  try {
11118
- raw = fs20.readFileSync(path22.join(chatsDir, chatFile), "utf-8");
11662
+ raw = fs21.readFileSync(path23.join(chatsDir, chatFile), "utf-8");
11119
11663
  } catch {
11120
11664
  continue;
11121
11665
  }
@@ -11277,13 +11821,13 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
11277
11821
  return result;
11278
11822
  }
11279
11823
  function antigravityBrainDirs() {
11280
- return ["antigravity-cli", "antigravity-ide"].map((surface) => path22.join(os19.homedir(), ".gemini", surface, "brain")).filter((p) => fs20.existsSync(p));
11824
+ return ["antigravity-cli", "antigravity-ide"].map((surface) => path23.join(os20.homedir(), ".gemini", surface, "brain")).filter((p) => fs21.existsSync(p));
11281
11825
  }
11282
11826
  function antigravityTranscriptPath(convPath) {
11283
- const logsDir = path22.join(convPath, ".system_generated", "logs");
11827
+ const logsDir = path23.join(convPath, ".system_generated", "logs");
11284
11828
  for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
11285
- const p = path22.join(logsDir, name);
11286
- if (fs20.existsSync(p)) return p;
11829
+ const p = path23.join(logsDir, name);
11830
+ if (fs21.existsSync(p)) return p;
11287
11831
  }
11288
11832
  return null;
11289
11833
  }
@@ -11309,14 +11853,14 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
11309
11853
  for (const brainDir of brainDirs) {
11310
11854
  let convDirs;
11311
11855
  try {
11312
- convDirs = fs20.readdirSync(brainDir);
11856
+ convDirs = fs21.readdirSync(brainDir);
11313
11857
  } catch {
11314
11858
  continue;
11315
11859
  }
11316
11860
  for (const conv of convDirs) {
11317
- const convPath = path22.join(brainDir, conv);
11861
+ const convPath = path23.join(brainDir, conv);
11318
11862
  try {
11319
- if (!fs20.statSync(convPath).isDirectory()) continue;
11863
+ if (!fs21.statSync(convPath).isDirectory()) continue;
11320
11864
  } catch {
11321
11865
  continue;
11322
11866
  }
@@ -11326,7 +11870,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
11326
11870
  onProgress?.(result.filesScanned);
11327
11871
  let raw;
11328
11872
  try {
11329
- raw = fs20.readFileSync(transcriptFile, "utf-8");
11873
+ raw = fs21.readFileSync(transcriptFile, "utf-8");
11330
11874
  } catch {
11331
11875
  continue;
11332
11876
  }
@@ -11383,7 +11927,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
11383
11927
  result.bashCalls++;
11384
11928
  const cwd = String(input.cwd ?? "");
11385
11929
  if (cwd && projLabel === conv.slice(0, 8)) {
11386
- projLabel = stripTerminalEscapes(cwd).replace(os19.homedir(), "~").slice(0, 40);
11930
+ projLabel = stripTerminalEscapes(cwd).replace(os20.homedir(), "~").slice(0, 40);
11387
11931
  }
11388
11932
  }
11389
11933
  const rawCmd = String(input.command ?? "").trimStart();
@@ -11483,7 +12027,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
11483
12027
  return result;
11484
12028
  }
11485
12029
  function scanCopilotHistory(startDate, onProgress, onLine) {
11486
- const sessionDir = path22.join(os19.homedir(), ".copilot", "session-state");
12030
+ const sessionDir = path23.join(os20.homedir(), ".copilot", "session-state");
11487
12031
  const result = {
11488
12032
  filesScanned: 0,
11489
12033
  sessions: 0,
@@ -11499,22 +12043,22 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
11499
12043
  sessionsWithEarlySecrets: 0
11500
12044
  };
11501
12045
  const dedup = emptyScanDedup();
11502
- if (!fs20.existsSync(sessionDir)) return result;
12046
+ if (!fs21.existsSync(sessionDir)) return result;
11503
12047
  let sessionIds;
11504
12048
  try {
11505
- sessionIds = fs20.readdirSync(sessionDir);
12049
+ sessionIds = fs21.readdirSync(sessionDir);
11506
12050
  } catch {
11507
12051
  return result;
11508
12052
  }
11509
12053
  const ruleSources = buildRuleSources();
11510
12054
  for (const sessionId of sessionIds) {
11511
- const eventsPath = path22.join(sessionDir, sessionId, "events.jsonl");
11512
- if (!fs20.existsSync(eventsPath)) continue;
12055
+ const eventsPath = path23.join(sessionDir, sessionId, "events.jsonl");
12056
+ if (!fs21.existsSync(eventsPath)) continue;
11513
12057
  result.filesScanned++;
11514
12058
  onProgress?.(result.filesScanned);
11515
12059
  let raw;
11516
12060
  try {
11517
- raw = fs20.readFileSync(eventsPath, "utf-8");
12061
+ raw = fs21.readFileSync(eventsPath, "utf-8");
11518
12062
  } catch {
11519
12063
  continue;
11520
12064
  }
@@ -11534,7 +12078,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
11534
12078
  if (ev.type === "session.start") {
11535
12079
  const cwd = ev.data?.context?.cwd;
11536
12080
  if (typeof cwd === "string" && cwd) {
11537
- projLabel = stripTerminalEscapes(cwd).replace(os19.homedir(), "~").slice(0, 40);
12081
+ projLabel = stripTerminalEscapes(cwd).replace(os20.homedir(), "~").slice(0, 40);
11538
12082
  }
11539
12083
  continue;
11540
12084
  }
@@ -11666,7 +12210,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
11666
12210
  return result;
11667
12211
  }
11668
12212
  function scanCodexHistory(startDate, onProgress, onLine) {
11669
- const sessionsBase = path22.join(os19.homedir(), ".codex", "sessions");
12213
+ const sessionsBase = path23.join(os20.homedir(), ".codex", "sessions");
11670
12214
  const result = {
11671
12215
  filesScanned: 0,
11672
12216
  sessions: 0,
@@ -11681,32 +12225,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
11681
12225
  sessionsWithEarlySecrets: 0
11682
12226
  };
11683
12227
  const dedup = emptyScanDedup();
11684
- if (!fs20.existsSync(sessionsBase)) return result;
12228
+ if (!fs21.existsSync(sessionsBase)) return result;
11685
12229
  const jsonlFiles = [];
11686
12230
  try {
11687
- for (const year of fs20.readdirSync(sessionsBase)) {
11688
- const yearPath = path22.join(sessionsBase, year);
12231
+ for (const year of fs21.readdirSync(sessionsBase)) {
12232
+ const yearPath = path23.join(sessionsBase, year);
11689
12233
  try {
11690
- if (!fs20.statSync(yearPath).isDirectory()) continue;
12234
+ if (!fs21.statSync(yearPath).isDirectory()) continue;
11691
12235
  } catch {
11692
12236
  continue;
11693
12237
  }
11694
- for (const month of fs20.readdirSync(yearPath)) {
11695
- const monthPath = path22.join(yearPath, month);
12238
+ for (const month of fs21.readdirSync(yearPath)) {
12239
+ const monthPath = path23.join(yearPath, month);
11696
12240
  try {
11697
- if (!fs20.statSync(monthPath).isDirectory()) continue;
12241
+ if (!fs21.statSync(monthPath).isDirectory()) continue;
11698
12242
  } catch {
11699
12243
  continue;
11700
12244
  }
11701
- for (const day of fs20.readdirSync(monthPath)) {
11702
- const dayPath = path22.join(monthPath, day);
12245
+ for (const day of fs21.readdirSync(monthPath)) {
12246
+ const dayPath = path23.join(monthPath, day);
11703
12247
  try {
11704
- if (!fs20.statSync(dayPath).isDirectory()) continue;
12248
+ if (!fs21.statSync(dayPath).isDirectory()) continue;
11705
12249
  } catch {
11706
12250
  continue;
11707
12251
  }
11708
- for (const file of fs20.readdirSync(dayPath)) {
11709
- if (file.endsWith(".jsonl")) jsonlFiles.push(path22.join(dayPath, file));
12252
+ for (const file of fs21.readdirSync(dayPath)) {
12253
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path23.join(dayPath, file));
11710
12254
  }
11711
12255
  }
11712
12256
  }
@@ -11720,7 +12264,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
11720
12264
  onProgress?.(result.filesScanned);
11721
12265
  let lines;
11722
12266
  try {
11723
- lines = fs20.readFileSync(filePath, "utf-8").split("\n");
12267
+ lines = fs21.readFileSync(filePath, "utf-8").split("\n");
11724
12268
  } catch {
11725
12269
  continue;
11726
12270
  }
@@ -11746,7 +12290,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
11746
12290
  sessionId = String(payload["id"] ?? filePath);
11747
12291
  startTime = String(payload["timestamp"] ?? "");
11748
12292
  const cwd = String(payload["cwd"] ?? "");
11749
- projLabel = stripTerminalEscapes(cwd.replace(os19.homedir(), "~")).slice(0, 40);
12293
+ projLabel = stripTerminalEscapes(cwd.replace(os20.homedir(), "~")).slice(0, 40);
11750
12294
  continue;
11751
12295
  }
11752
12296
  if (entry.type === "event_msg" && payload["type"] === "token_count") {
@@ -11899,17 +12443,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
11899
12443
  return result;
11900
12444
  }
11901
12445
  function scanShellConfig() {
11902
- const home = os19.homedir();
12446
+ const home = os20.homedir();
11903
12447
  const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
11904
- (f) => path22.join(home, f)
12448
+ (f) => path23.join(home, f)
11905
12449
  );
11906
12450
  const findings = [];
11907
12451
  const seen = /* @__PURE__ */ new Set();
11908
12452
  for (const filePath of configFiles) {
11909
- if (!fs20.existsSync(filePath)) continue;
12453
+ if (!fs21.existsSync(filePath)) continue;
11910
12454
  let lines;
11911
12455
  try {
11912
- lines = fs20.readFileSync(filePath, "utf-8").split("\n");
12456
+ lines = fs21.readFileSync(filePath, "utf-8").split("\n");
11913
12457
  } catch {
11914
12458
  continue;
11915
12459
  }
@@ -12715,7 +13259,7 @@ function registerScanCommand(program2) {
12715
13259
  if (!drillDown) {
12716
13260
  const useInk2 = !options.classic;
12717
13261
  if (useInk2) {
12718
- const scanInkPath = path22.join(__dirname, "scan-ink.mjs");
13262
+ const scanInkPath = path23.join(__dirname, "scan-ink.mjs");
12719
13263
  const dynamicImport = new Function("id", "return import(id)");
12720
13264
  const mod = await dynamicImport(`file://${scanInkPath}`);
12721
13265
  const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
@@ -13136,8 +13680,8 @@ var init_suggestion_tracker = __esm({
13136
13680
  });
13137
13681
 
13138
13682
  // src/daemon/taint-store.ts
13139
- import fs21 from "fs";
13140
- import path23 from "path";
13683
+ import fs22 from "fs";
13684
+ import path24 from "path";
13141
13685
  var DEFAULT_TTL_MS, TaintStore;
13142
13686
  var init_taint_store = __esm({
13143
13687
  "src/daemon/taint-store.ts"() {
@@ -13206,9 +13750,9 @@ var init_taint_store = __esm({
13206
13750
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
13207
13751
  _resolve(filePath) {
13208
13752
  try {
13209
- return fs21.realpathSync.native(path23.resolve(filePath));
13753
+ return fs22.realpathSync.native(path24.resolve(filePath));
13210
13754
  } catch {
13211
- return path23.resolve(filePath);
13755
+ return path24.resolve(filePath);
13212
13756
  }
13213
13757
  }
13214
13758
  };
@@ -13325,14 +13869,14 @@ var init_session_history = __esm({
13325
13869
 
13326
13870
  // src/daemon/state.ts
13327
13871
  import net2 from "net";
13328
- import fs22 from "fs";
13329
- import path24 from "path";
13330
- import os20 from "os";
13872
+ import fs23 from "fs";
13873
+ import path25 from "path";
13874
+ import os21 from "os";
13331
13875
  import { randomUUID as randomUUID3 } from "crypto";
13332
13876
  function loadInsightCounts() {
13333
13877
  try {
13334
- if (!fs22.existsSync(INSIGHT_COUNTS_FILE)) return;
13335
- const data = JSON.parse(fs22.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
13878
+ if (!fs23.existsSync(INSIGHT_COUNTS_FILE)) return;
13879
+ const data = JSON.parse(fs23.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
13336
13880
  for (const [tool, count] of Object.entries(data)) {
13337
13881
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
13338
13882
  }
@@ -13371,23 +13915,23 @@ function markRejectionHandlerRegistered() {
13371
13915
  daemonRejectionHandlerRegistered = true;
13372
13916
  }
13373
13917
  function atomicWriteSync2(filePath, data, options) {
13374
- const dir = path24.dirname(filePath);
13375
- if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
13918
+ const dir = path25.dirname(filePath);
13919
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
13376
13920
  const tmpPath = `${filePath}.${randomUUID3()}.tmp`;
13377
13921
  try {
13378
- fs22.writeFileSync(tmpPath, data, options);
13922
+ fs23.writeFileSync(tmpPath, data, options);
13379
13923
  } catch (err2) {
13380
13924
  try {
13381
- fs22.unlinkSync(tmpPath);
13925
+ fs23.unlinkSync(tmpPath);
13382
13926
  } catch {
13383
13927
  }
13384
13928
  throw err2;
13385
13929
  }
13386
13930
  try {
13387
- fs22.renameSync(tmpPath, filePath);
13931
+ fs23.renameSync(tmpPath, filePath);
13388
13932
  } catch (err2) {
13389
13933
  try {
13390
- fs22.unlinkSync(tmpPath);
13934
+ fs23.unlinkSync(tmpPath);
13391
13935
  } catch {
13392
13936
  }
13393
13937
  throw err2;
@@ -13411,16 +13955,16 @@ function appendAuditLog(data) {
13411
13955
  decision: data.decision,
13412
13956
  source: "daemon"
13413
13957
  };
13414
- const dir = path24.dirname(AUDIT_LOG_FILE);
13415
- if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
13416
- fs22.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
13958
+ const dir = path25.dirname(AUDIT_LOG_FILE);
13959
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
13960
+ fs23.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
13417
13961
  } catch {
13418
13962
  }
13419
13963
  }
13420
13964
  function getAuditHistory(limit = 20) {
13421
13965
  try {
13422
- if (!fs22.existsSync(AUDIT_LOG_FILE)) return [];
13423
- const lines = fs22.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
13966
+ if (!fs23.existsSync(AUDIT_LOG_FILE)) return [];
13967
+ const lines = fs23.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
13424
13968
  if (lines.length === 1 && lines[0] === "") return [];
13425
13969
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
13426
13970
  } catch {
@@ -13429,7 +13973,7 @@ function getAuditHistory(limit = 20) {
13429
13973
  }
13430
13974
  function getOrgName() {
13431
13975
  try {
13432
- if (fs22.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
13976
+ if (fs23.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
13433
13977
  } catch {
13434
13978
  }
13435
13979
  return null;
@@ -13437,8 +13981,8 @@ function getOrgName() {
13437
13981
  function writeGlobalSetting(key, value) {
13438
13982
  let config = {};
13439
13983
  try {
13440
- if (fs22.existsSync(GLOBAL_CONFIG_FILE)) {
13441
- config = JSON.parse(fs22.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
13984
+ if (fs23.existsSync(GLOBAL_CONFIG_FILE)) {
13985
+ config = JSON.parse(fs23.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
13442
13986
  }
13443
13987
  } catch {
13444
13988
  }
@@ -13450,8 +13994,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
13450
13994
  try {
13451
13995
  let trust = { entries: [] };
13452
13996
  try {
13453
- if (fs22.existsSync(TRUST_FILE2))
13454
- trust = JSON.parse(fs22.readFileSync(TRUST_FILE2, "utf-8"));
13997
+ if (fs23.existsSync(TRUST_FILE2))
13998
+ trust = JSON.parse(fs23.readFileSync(TRUST_FILE2, "utf-8"));
13455
13999
  } catch {
13456
14000
  }
13457
14001
  trust.entries = trust.entries.filter(
@@ -13468,8 +14012,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
13468
14012
  }
13469
14013
  function readPersistentDecisions() {
13470
14014
  try {
13471
- if (fs22.existsSync(DECISIONS_FILE)) {
13472
- return JSON.parse(fs22.readFileSync(DECISIONS_FILE, "utf-8"));
14015
+ if (fs23.existsSync(DECISIONS_FILE)) {
14016
+ return JSON.parse(fs23.readFileSync(DECISIONS_FILE, "utf-8"));
13473
14017
  }
13474
14018
  } catch {
13475
14019
  }
@@ -13497,7 +14041,7 @@ function estimateToolCost(tool, args) {
13497
14041
  const filePath = a.file_path ?? a.path;
13498
14042
  if (filePath) {
13499
14043
  try {
13500
- const bytes = fs22.statSync(filePath).size;
14044
+ const bytes = fs23.statSync(filePath).size;
13501
14045
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
13502
14046
  } catch {
13503
14047
  }
@@ -13568,7 +14112,7 @@ function abandonPending() {
13568
14112
  });
13569
14113
  if (autoStarted) {
13570
14114
  try {
13571
- fs22.unlinkSync(DAEMON_PID_FILE);
14115
+ fs23.unlinkSync(DAEMON_PID_FILE);
13572
14116
  } catch {
13573
14117
  }
13574
14118
  setTimeout(() => {
@@ -13579,8 +14123,8 @@ function abandonPending() {
13579
14123
  }
13580
14124
  function logActivitySocket(msg) {
13581
14125
  try {
13582
- fs22.appendFileSync(
13583
- path24.join(homeDir, ".node9", "hook-debug.log"),
14126
+ fs23.appendFileSync(
14127
+ path25.join(homeDir, ".node9", "hook-debug.log"),
13584
14128
  `[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
13585
14129
  `
13586
14130
  );
@@ -13602,13 +14146,13 @@ function shouldRebind(now = Date.now()) {
13602
14146
  function startActivitySocket() {
13603
14147
  bindActivitySocket();
13604
14148
  activityHealthInterval = setInterval(() => {
13605
- if (!fs22.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
14149
+ if (!fs23.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
13606
14150
  }, ACTIVITY_HEALTH_PROBE_MS);
13607
14151
  activityHealthInterval.unref();
13608
14152
  process.on("exit", () => {
13609
14153
  if (activityHealthInterval) clearInterval(activityHealthInterval);
13610
14154
  try {
13611
- fs22.unlinkSync(ACTIVITY_SOCKET_PATH2);
14155
+ fs23.unlinkSync(ACTIVITY_SOCKET_PATH2);
13612
14156
  } catch {
13613
14157
  }
13614
14158
  });
@@ -13636,7 +14180,7 @@ function attemptRebind(reason) {
13636
14180
  }
13637
14181
  function bindActivitySocket() {
13638
14182
  try {
13639
- fs22.unlinkSync(ACTIVITY_SOCKET_PATH2);
14183
+ fs23.unlinkSync(ACTIVITY_SOCKET_PATH2);
13640
14184
  } catch {
13641
14185
  }
13642
14186
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
@@ -13749,14 +14293,14 @@ var init_state2 = __esm({
13749
14293
  init_taint_store();
13750
14294
  init_session_counters();
13751
14295
  init_session_history();
13752
- homeDir = os20.homedir();
13753
- DAEMON_PID_FILE = path24.join(homeDir, ".node9", "daemon.pid");
13754
- DECISIONS_FILE = path24.join(homeDir, ".node9", "decisions.json");
13755
- AUDIT_LOG_FILE = path24.join(homeDir, ".node9", "audit.log");
13756
- TRUST_FILE2 = path24.join(homeDir, ".node9", "trust.json");
13757
- GLOBAL_CONFIG_FILE = path24.join(homeDir, ".node9", "config.json");
13758
- CREDENTIALS_FILE = path24.join(homeDir, ".node9", "credentials.json");
13759
- INSIGHT_COUNTS_FILE = path24.join(homeDir, ".node9", "insight-counts.json");
14296
+ homeDir = os21.homedir();
14297
+ DAEMON_PID_FILE = path25.join(homeDir, ".node9", "daemon.pid");
14298
+ DECISIONS_FILE = path25.join(homeDir, ".node9", "decisions.json");
14299
+ AUDIT_LOG_FILE = path25.join(homeDir, ".node9", "audit.log");
14300
+ TRUST_FILE2 = path25.join(homeDir, ".node9", "trust.json");
14301
+ GLOBAL_CONFIG_FILE = path25.join(homeDir, ".node9", "config.json");
14302
+ CREDENTIALS_FILE = path25.join(homeDir, ".node9", "credentials.json");
14303
+ INSIGHT_COUNTS_FILE = path25.join(homeDir, ".node9", "insight-counts.json");
13760
14304
  pending = /* @__PURE__ */ new Map();
13761
14305
  sseClients = /* @__PURE__ */ new Set();
13762
14306
  suggestionTracker = new SuggestionTracker(3);
@@ -13773,7 +14317,7 @@ var init_state2 = __esm({
13773
14317
  "2h": 2 * 60 * 6e4
13774
14318
  };
13775
14319
  autoStarted = process.env.NODE9_AUTO_STARTED === "1";
13776
- ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path24.join(os20.tmpdir(), "node9-activity.sock");
14320
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path25.join(os21.tmpdir(), "node9-activity.sock");
13777
14321
  ACTIVITY_RING_SIZE = 100;
13778
14322
  activityRing = [];
13779
14323
  LARGE_RESPONSE_RING_SIZE = 20;
@@ -13812,10 +14356,10 @@ var init_state2 = __esm({
13812
14356
  });
13813
14357
 
13814
14358
  // src/daemon/sync.ts
13815
- import fs23 from "fs";
14359
+ import fs24 from "fs";
13816
14360
  import https2 from "https";
13817
- import os21 from "os";
13818
- import path25 from "path";
14361
+ import os22 from "os";
14362
+ import path26 from "path";
13819
14363
  function emptySignals3() {
13820
14364
  return {
13821
14365
  dlpFindings: 0,
@@ -13855,8 +14399,8 @@ function readCredentials() {
13855
14399
  };
13856
14400
  }
13857
14401
  try {
13858
- const credPath = path25.join(os21.homedir(), ".node9", "credentials.json");
13859
- const creds = JSON.parse(fs23.readFileSync(credPath, "utf-8"));
14402
+ const credPath = path26.join(os22.homedir(), ".node9", "credentials.json");
14403
+ const creds = JSON.parse(fs24.readFileSync(credPath, "utf-8"));
13860
14404
  const profileName = process.env.NODE9_PROFILE ?? "default";
13861
14405
  const profile = creds[profileName];
13862
14406
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -13882,7 +14426,7 @@ function readCredentials() {
13882
14426
  }
13883
14427
  function readCachedEtag() {
13884
14428
  try {
13885
- const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
14429
+ const raw = JSON.parse(fs24.readFileSync(rulesCacheFile(), "utf-8"));
13886
14430
  return typeof raw.etag === "string" ? raw.etag : void 0;
13887
14431
  } catch {
13888
14432
  return void 0;
@@ -13943,9 +14487,9 @@ function extractRules(body) {
13943
14487
  return [];
13944
14488
  }
13945
14489
  function writeCache2(cache) {
13946
- const dir = path25.dirname(rulesCacheFile());
13947
- if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
13948
- fs23.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
14490
+ const dir = path26.dirname(rulesCacheFile());
14491
+ if (!fs24.existsSync(dir)) fs24.mkdirSync(dir, { recursive: true });
14492
+ fs24.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
13949
14493
  }
13950
14494
  async function syncOnce() {
13951
14495
  const creds = readCredentials();
@@ -14102,7 +14646,7 @@ async function runCloudSync() {
14102
14646
  }
14103
14647
  function getCloudSyncStatus() {
14104
14648
  try {
14105
- const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
14649
+ const raw = JSON.parse(fs24.readFileSync(rulesCacheFile(), "utf-8"));
14106
14650
  if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
14107
14651
  return {
14108
14652
  cached: true,
@@ -14119,7 +14663,7 @@ function getCloudSyncStatus() {
14119
14663
  }
14120
14664
  function getCloudRules() {
14121
14665
  try {
14122
- const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
14666
+ const raw = JSON.parse(fs24.readFileSync(rulesCacheFile(), "utf-8"));
14123
14667
  return Array.isArray(raw.rules) ? raw.rules : null;
14124
14668
  } catch {
14125
14669
  return null;
@@ -14175,7 +14719,7 @@ var init_sync = __esm({
14175
14719
  loop: "loops",
14176
14720
  "long-output-redacted": "longOutputRedactions"
14177
14721
  };
14178
- rulesCacheFile = () => path25.join(os21.homedir(), ".node9", "rules-cache.json");
14722
+ rulesCacheFile = () => path26.join(os22.homedir(), ".node9", "rules-cache.json");
14179
14723
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
14180
14724
  DEFAULT_INTERVAL_HOURS = 5;
14181
14725
  MIN_INTERVAL_HOURS = 1;
@@ -14189,6 +14733,7 @@ var init_sync = __esm({
14189
14733
  var audit_shipper_exports = {};
14190
14734
  __export(audit_shipper_exports, {
14191
14735
  AUDIT_SHIP_WATERMARK: () => AUDIT_SHIP_WATERMARK,
14736
+ buildBatchEndpoint: () => buildBatchEndpoint,
14192
14737
  buildWireRows: () => buildWireRows,
14193
14738
  fileSignature: () => fileSignature,
14194
14739
  readWatermark: () => readWatermark,
@@ -14197,26 +14742,26 @@ __export(audit_shipper_exports, {
14197
14742
  startAuditShipper: () => startAuditShipper,
14198
14743
  writeWatermark: () => writeWatermark
14199
14744
  });
14200
- import fs24 from "fs";
14201
- import path26 from "path";
14202
- import os22 from "os";
14745
+ import fs25 from "fs";
14746
+ import path27 from "path";
14747
+ import os23 from "os";
14203
14748
  import crypto5 from "crypto";
14204
14749
  function fileSignature(filePath) {
14205
- const fd = fs24.openSync(filePath, "r");
14750
+ const fd = fs25.openSync(filePath, "r");
14206
14751
  try {
14207
14752
  const buf = Buffer.alloc(512);
14208
- const read = fs24.readSync(fd, buf, 0, 512, 0);
14753
+ const read = fs25.readSync(fd, buf, 0, 512, 0);
14209
14754
  const slice = buf.subarray(0, read);
14210
14755
  const nl = slice.indexOf(10);
14211
14756
  const firstLine = nl === -1 ? slice : slice.subarray(0, nl);
14212
14757
  return crypto5.createHash("sha256").update(firstLine).digest("hex").slice(0, 16);
14213
14758
  } finally {
14214
- fs24.closeSync(fd);
14759
+ fs25.closeSync(fd);
14215
14760
  }
14216
14761
  }
14217
14762
  function readWatermark(watermarkPath) {
14218
14763
  try {
14219
- const raw = JSON.parse(fs24.readFileSync(watermarkPath, "utf-8"));
14764
+ const raw = JSON.parse(fs25.readFileSync(watermarkPath, "utf-8"));
14220
14765
  if (typeof raw.fileSig === "string" && typeof raw.offset === "number" && raw.offset >= 0)
14221
14766
  return raw;
14222
14767
  } catch {
@@ -14225,8 +14770,8 @@ function readWatermark(watermarkPath) {
14225
14770
  }
14226
14771
  function writeWatermark(watermarkPath, wm) {
14227
14772
  const tmp = `${watermarkPath}.tmp`;
14228
- fs24.writeFileSync(tmp, JSON.stringify(wm));
14229
- fs24.renameSync(tmp, watermarkPath);
14773
+ fs25.writeFileSync(tmp, JSON.stringify(wm));
14774
+ fs25.renameSync(tmp, watermarkPath);
14230
14775
  }
14231
14776
  function buildWireRows(chunk) {
14232
14777
  const lastNl = chunk.lastIndexOf(10);
@@ -14270,6 +14815,12 @@ function buildWireRows(chunk) {
14270
14815
  }
14271
14816
  return { rows, consumed: lastNl + 1 };
14272
14817
  }
14818
+ function buildBatchEndpoint(rawApiUrl) {
14819
+ const validated = validateApiUrl(rawApiUrl);
14820
+ if (!validated) return null;
14821
+ const base = validated.toString().replace(/\/$/, "").replace(/\/policies\/sync$/, "");
14822
+ return `${base}/audit/batch`;
14823
+ }
14273
14824
  async function shipOnce(deps = {}) {
14274
14825
  const auditLogPath = deps.auditLogPath ?? LOCAL_AUDIT_LOG;
14275
14826
  const watermarkPath = deps.watermarkPath ?? AUDIT_SHIP_WATERMARK;
@@ -14286,14 +14837,13 @@ async function shipOnce(deps = {}) {
14286
14837
  if (!cloudEnabled) return { status: "disabled", shipped: 0 };
14287
14838
  const creds = deps.creds !== void 0 ? deps.creds : readCredentials();
14288
14839
  if (!creds?.apiKey) return { status: "no-creds", shipped: 0 };
14289
- const validated = validateApiUrl(creds.apiUrl);
14290
- if (!validated) return { status: "no-creds", shipped: 0 };
14291
- const endpoint = `${validated.toString().replace(/\/$/, "")}/audit/batch`;
14292
- if (!fs24.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
14840
+ const endpoint = buildBatchEndpoint(creds.apiUrl);
14841
+ if (!endpoint) return { status: "no-creds", shipped: 0 };
14842
+ if (!fs25.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
14293
14843
  let shipped = 0;
14294
14844
  try {
14295
14845
  for (let chunkN = 0; chunkN < MAX_CHUNKS_PER_TICK; chunkN++) {
14296
- const size = fs24.statSync(auditLogPath).size;
14846
+ const size = fs25.statSync(auditLogPath).size;
14297
14847
  if (size === 0) break;
14298
14848
  const sig = fileSignature(auditLogPath);
14299
14849
  const wm = readWatermark(watermarkPath);
@@ -14301,12 +14851,12 @@ async function shipOnce(deps = {}) {
14301
14851
  if (offset >= size) break;
14302
14852
  const toRead = Math.min(size - offset, MAX_CHUNK_BYTES);
14303
14853
  const buf = Buffer.alloc(toRead);
14304
- const fd = fs24.openSync(auditLogPath, "r");
14854
+ const fd = fs25.openSync(auditLogPath, "r");
14305
14855
  let read;
14306
14856
  try {
14307
- read = fs24.readSync(fd, buf, 0, toRead, offset);
14857
+ read = fs25.readSync(fd, buf, 0, toRead, offset);
14308
14858
  } finally {
14309
- fs24.closeSync(fd);
14859
+ fs25.closeSync(fd);
14310
14860
  }
14311
14861
  const { rows, consumed } = buildWireRows(buf.subarray(0, read));
14312
14862
  if (consumed === 0) break;
@@ -14353,8 +14903,8 @@ async function shipOnce(deps = {}) {
14353
14903
  }
14354
14904
  function shipLagBytes(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHIP_WATERMARK) {
14355
14905
  try {
14356
- if (!fs24.existsSync(auditLogPath)) return 0;
14357
- const size = fs24.statSync(auditLogPath).size;
14906
+ if (!fs25.existsSync(auditLogPath)) return 0;
14907
+ const size = fs25.statSync(auditLogPath).size;
14358
14908
  const wm = readWatermark(watermarkPath);
14359
14909
  if (!wm) return size;
14360
14910
  if (wm.fileSig !== fileSignature(auditLogPath)) return size;
@@ -14385,7 +14935,7 @@ var init_audit_shipper = __esm({
14385
14935
  init_config();
14386
14936
  init_sync();
14387
14937
  init_cloud();
14388
- AUDIT_SHIP_WATERMARK = path26.join(os22.homedir(), ".node9", "audit-ship.json");
14938
+ AUDIT_SHIP_WATERMARK = path27.join(os23.homedir(), ".node9", "audit-ship.json");
14389
14939
  DEFAULT_INTERVAL_MS = 2e4;
14390
14940
  MAX_BATCH = 500;
14391
14941
  MAX_CHUNK_BYTES = 4 * 1024 * 1024;
@@ -14397,73 +14947,73 @@ var init_audit_shipper = __esm({
14397
14947
  });
14398
14948
 
14399
14949
  // src/daemon/dlp-scanner.ts
14400
- import fs25 from "fs";
14401
- import path27 from "path";
14402
- import os23 from "os";
14950
+ import fs26 from "fs";
14951
+ import path28 from "path";
14952
+ import os24 from "os";
14403
14953
  function loadIndex() {
14404
14954
  try {
14405
- return JSON.parse(fs25.readFileSync(INDEX_FILE, "utf-8"));
14955
+ return JSON.parse(fs26.readFileSync(INDEX_FILE, "utf-8"));
14406
14956
  } catch {
14407
14957
  return {};
14408
14958
  }
14409
14959
  }
14410
14960
  function saveIndex(index) {
14411
14961
  try {
14412
- fs25.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
14962
+ fs26.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
14413
14963
  } catch {
14414
14964
  }
14415
14965
  }
14416
14966
  function appendAuditEntry(entry) {
14417
14967
  try {
14418
- fs25.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
14968
+ fs26.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
14419
14969
  } catch {
14420
14970
  }
14421
14971
  }
14422
14972
  function runDlpScan() {
14423
- if (!fs25.existsSync(PROJECTS_DIR2)) return;
14973
+ if (!fs26.existsSync(PROJECTS_DIR2)) return;
14424
14974
  const index = loadIndex();
14425
14975
  let updated = false;
14426
14976
  let projDirs;
14427
14977
  try {
14428
- projDirs = fs25.readdirSync(PROJECTS_DIR2);
14978
+ projDirs = fs26.readdirSync(PROJECTS_DIR2);
14429
14979
  } catch {
14430
14980
  return;
14431
14981
  }
14432
14982
  for (const proj of projDirs) {
14433
- const projPath = path27.join(PROJECTS_DIR2, proj);
14983
+ const projPath = path28.join(PROJECTS_DIR2, proj);
14434
14984
  try {
14435
- if (!fs25.lstatSync(projPath).isDirectory()) continue;
14436
- const real = fs25.realpathSync(projPath);
14437
- if (!real.startsWith(PROJECTS_DIR2 + path27.sep) && real !== PROJECTS_DIR2) continue;
14985
+ if (!fs26.lstatSync(projPath).isDirectory()) continue;
14986
+ const real = fs26.realpathSync(projPath);
14987
+ if (!real.startsWith(PROJECTS_DIR2 + path28.sep) && real !== PROJECTS_DIR2) continue;
14438
14988
  } catch {
14439
14989
  continue;
14440
14990
  }
14441
14991
  let files;
14442
14992
  try {
14443
- files = fs25.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
14993
+ files = fs26.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
14444
14994
  } catch {
14445
14995
  continue;
14446
14996
  }
14447
14997
  for (const file of files) {
14448
- const filePath = path27.join(projPath, file);
14998
+ const filePath = path28.join(projPath, file);
14449
14999
  const lastOffset = index[filePath] ?? 0;
14450
15000
  let size;
14451
15001
  try {
14452
- size = fs25.statSync(filePath).size;
15002
+ size = fs26.statSync(filePath).size;
14453
15003
  } catch {
14454
15004
  continue;
14455
15005
  }
14456
15006
  if (size <= lastOffset) continue;
14457
15007
  let fd;
14458
15008
  try {
14459
- fd = fs25.openSync(filePath, "r");
15009
+ fd = fs26.openSync(filePath, "r");
14460
15010
  } catch {
14461
15011
  continue;
14462
15012
  }
14463
15013
  try {
14464
15014
  const chunkSize = size - lastOffset;
14465
15015
  const buf = Buffer.alloc(chunkSize);
14466
- fs25.readSync(fd, buf, 0, chunkSize, lastOffset);
15016
+ fs26.readSync(fd, buf, 0, chunkSize, lastOffset);
14467
15017
  const chunk = buf.toString("utf-8");
14468
15018
  for (const line of chunk.split("\n")) {
14469
15019
  if (!line.trim()) continue;
@@ -14483,7 +15033,7 @@ function runDlpScan() {
14483
15033
  if (typeof text !== "string") continue;
14484
15034
  const match = scanText(text);
14485
15035
  if (!match) continue;
14486
- const projLabel = decodeURIComponent(proj).replace(os23.homedir(), "~").slice(0, 40);
15036
+ const projLabel = decodeURIComponent(proj).replace(os24.homedir(), "~").slice(0, 40);
14487
15037
  const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
14488
15038
  appendAuditEntry({
14489
15039
  ts,
@@ -14508,7 +15058,7 @@ Run: node9 report --period 30d`
14508
15058
  updated = true;
14509
15059
  } finally {
14510
15060
  try {
14511
- fs25.closeSync(fd);
15061
+ fs26.closeSync(fd);
14512
15062
  } catch {
14513
15063
  }
14514
15064
  }
@@ -14541,23 +15091,23 @@ var init_dlp_scanner = __esm({
14541
15091
  init_dlp();
14542
15092
  init_native();
14543
15093
  init_state2();
14544
- INDEX_FILE = path27.join(os23.homedir(), ".node9", "dlp-index.json");
14545
- PROJECTS_DIR2 = path27.join(os23.homedir(), ".claude", "projects");
15094
+ INDEX_FILE = path28.join(os24.homedir(), ".node9", "dlp-index.json");
15095
+ PROJECTS_DIR2 = path28.join(os24.homedir(), ".claude", "projects");
14546
15096
  }
14547
15097
  });
14548
15098
 
14549
15099
  // src/daemon/mcp-tools.ts
14550
- import fs26 from "fs";
14551
- import path28 from "path";
14552
- import os24 from "os";
15100
+ import fs27 from "fs";
15101
+ import path29 from "path";
15102
+ import os25 from "os";
14553
15103
  function getMcpToolsFile() {
14554
- return path28.join(os24.homedir(), ".node9", "mcp-tools.json");
15104
+ return path29.join(os25.homedir(), ".node9", "mcp-tools.json");
14555
15105
  }
14556
15106
  function readMcpToolsConfig() {
14557
15107
  try {
14558
15108
  const file = getMcpToolsFile();
14559
- if (!fs26.existsSync(file)) return {};
14560
- const raw = fs26.readFileSync(file, "utf-8");
15109
+ if (!fs27.existsSync(file)) return {};
15110
+ const raw = fs27.readFileSync(file, "utf-8");
14561
15111
  return JSON.parse(raw);
14562
15112
  } catch {
14563
15113
  return {};
@@ -14566,11 +15116,11 @@ function readMcpToolsConfig() {
14566
15116
  function writeMcpToolsConfig(config) {
14567
15117
  try {
14568
15118
  const file = getMcpToolsFile();
14569
- const dir = path28.dirname(file);
14570
- if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
14571
- const tmpPath = `${file}.${os24.hostname()}.${process.pid}.tmp`;
14572
- fs26.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
14573
- fs26.renameSync(tmpPath, file);
15119
+ const dir = path29.dirname(file);
15120
+ if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
15121
+ const tmpPath = `${file}.${os25.hostname()}.${process.pid}.tmp`;
15122
+ fs27.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
15123
+ fs27.renameSync(tmpPath, file);
14574
15124
  } catch (e) {
14575
15125
  console.error("Failed to write mcp-tools.json", e);
14576
15126
  }
@@ -14617,9 +15167,9 @@ var init_mcp_tools = __esm({
14617
15167
 
14618
15168
  // src/daemon/server.ts
14619
15169
  import http from "http";
14620
- import fs27 from "fs";
14621
- import path29 from "path";
14622
- import os25 from "os";
15170
+ import fs28 from "fs";
15171
+ import path30 from "path";
15172
+ import os26 from "os";
14623
15173
  import { randomUUID as randomUUID4 } from "crypto";
14624
15174
  import { spawnSync } from "child_process";
14625
15175
  import chalk6 from "chalk";
@@ -14641,7 +15191,7 @@ function startDaemon() {
14641
15191
  idleTimer = setTimeout(() => {
14642
15192
  if (autoStarted) {
14643
15193
  try {
14644
- fs27.unlinkSync(DAEMON_PID_FILE);
15194
+ fs28.unlinkSync(DAEMON_PID_FILE);
14645
15195
  } catch {
14646
15196
  }
14647
15197
  }
@@ -14786,7 +15336,7 @@ data: ${JSON.stringify(item.data)}
14786
15336
  mcpServer: entry.mcpServer
14787
15337
  });
14788
15338
  }
14789
- const projectCwd = typeof cwd === "string" && path29.isAbsolute(cwd) ? cwd : void 0;
15339
+ const projectCwd = typeof cwd === "string" && path30.isAbsolute(cwd) ? cwd : void 0;
14790
15340
  const projectConfig = getConfig(projectCwd);
14791
15341
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
14792
15342
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -15078,8 +15628,8 @@ data: ${JSON.stringify(item.data)}
15078
15628
  if (!validToken(req)) return res.writeHead(403).end();
15079
15629
  const periodParam = reqUrl.searchParams.get("period") || "7d";
15080
15630
  const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
15081
- const logPath = path29.join(os25.homedir(), ".node9", "audit.log");
15082
- if (!fs27.existsSync(logPath)) {
15631
+ const logPath = path30.join(os26.homedir(), ".node9", "audit.log");
15632
+ if (!fs28.existsSync(logPath)) {
15083
15633
  res.writeHead(200, { "Content-Type": "application/json" });
15084
15634
  return res.end(
15085
15635
  JSON.stringify({
@@ -15092,7 +15642,7 @@ data: ${JSON.stringify(item.data)}
15092
15642
  );
15093
15643
  }
15094
15644
  try {
15095
- const raw = fs27.readFileSync(logPath, "utf-8");
15645
+ const raw = fs28.readFileSync(logPath, "utf-8");
15096
15646
  const allEntries = raw.split("\n").flatMap((line) => {
15097
15647
  if (!line.trim()) return [];
15098
15648
  try {
@@ -15415,14 +15965,14 @@ data: ${JSON.stringify(item.data)}
15415
15965
  server.on("error", (e) => {
15416
15966
  if (e.code === "EADDRINUSE") {
15417
15967
  try {
15418
- if (fs27.existsSync(DAEMON_PID_FILE)) {
15419
- const { pid } = JSON.parse(fs27.readFileSync(DAEMON_PID_FILE, "utf-8"));
15968
+ if (fs28.existsSync(DAEMON_PID_FILE)) {
15969
+ const { pid } = JSON.parse(fs28.readFileSync(DAEMON_PID_FILE, "utf-8"));
15420
15970
  process.kill(pid, 0);
15421
15971
  return process.exit(0);
15422
15972
  }
15423
15973
  } catch {
15424
15974
  try {
15425
- fs27.unlinkSync(DAEMON_PID_FILE);
15975
+ fs28.unlinkSync(DAEMON_PID_FILE);
15426
15976
  } catch {
15427
15977
  }
15428
15978
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -15511,15 +16061,15 @@ var init_server = __esm({
15511
16061
  });
15512
16062
 
15513
16063
  // src/daemon/service.ts
15514
- import fs28 from "fs";
15515
- import path30 from "path";
15516
- import os26 from "os";
16064
+ import fs29 from "fs";
16065
+ import path31 from "path";
16066
+ import os27 from "os";
15517
16067
  import { spawnSync as spawnSync2, execFileSync } from "child_process";
15518
16068
  function resolveNode9Binary() {
15519
16069
  try {
15520
16070
  const script = process.argv[1];
15521
- if (typeof script === "string" && path30.isAbsolute(script) && fs28.existsSync(script)) {
15522
- return fs28.realpathSync(script);
16071
+ if (typeof script === "string" && path31.isAbsolute(script) && fs29.existsSync(script)) {
16072
+ return fs29.realpathSync(script);
15523
16073
  }
15524
16074
  } catch {
15525
16075
  }
@@ -15537,11 +16087,11 @@ function xmlEscape(s) {
15537
16087
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
15538
16088
  }
15539
16089
  function launchdPlist(binaryPath) {
15540
- const logDir = path30.join(os26.homedir(), ".node9");
16090
+ const logDir = path31.join(os27.homedir(), ".node9");
15541
16091
  const nodePath = xmlEscape(process.execPath);
15542
16092
  const scriptPath = xmlEscape(binaryPath);
15543
- const outLog = xmlEscape(path30.join(logDir, "daemon.log"));
15544
- const errLog = xmlEscape(path30.join(logDir, "daemon-error.log"));
16093
+ const outLog = xmlEscape(path31.join(logDir, "daemon.log"));
16094
+ const errLog = xmlEscape(path31.join(logDir, "daemon-error.log"));
15545
16095
  return `<?xml version="1.0" encoding="UTF-8"?>
15546
16096
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
15547
16097
  <plist version="1.0">
@@ -15574,9 +16124,9 @@ function launchdPlist(binaryPath) {
15574
16124
  `;
15575
16125
  }
15576
16126
  function installLaunchd(binaryPath) {
15577
- const dir = path30.dirname(LAUNCHD_PLIST);
15578
- if (!fs28.existsSync(dir)) fs28.mkdirSync(dir, { recursive: true });
15579
- fs28.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
16127
+ const dir = path31.dirname(LAUNCHD_PLIST);
16128
+ if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
16129
+ fs29.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
15580
16130
  spawnSync2("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
15581
16131
  const r = spawnSync2("launchctl", ["load", "-w", LAUNCHD_PLIST], {
15582
16132
  encoding: "utf8",
@@ -15587,13 +16137,13 @@ function installLaunchd(binaryPath) {
15587
16137
  }
15588
16138
  }
15589
16139
  function uninstallLaunchd() {
15590
- if (fs28.existsSync(LAUNCHD_PLIST)) {
16140
+ if (fs29.existsSync(LAUNCHD_PLIST)) {
15591
16141
  spawnSync2("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
15592
- fs28.unlinkSync(LAUNCHD_PLIST);
16142
+ fs29.unlinkSync(LAUNCHD_PLIST);
15593
16143
  }
15594
16144
  }
15595
16145
  function isLaunchdInstalled() {
15596
- return fs28.existsSync(LAUNCHD_PLIST);
16146
+ return fs29.existsSync(LAUNCHD_PLIST);
15597
16147
  }
15598
16148
  function systemdUnit(binaryPath) {
15599
16149
  return `[Unit]
@@ -15612,12 +16162,12 @@ WantedBy=default.target
15612
16162
  `;
15613
16163
  }
15614
16164
  function installSystemd(binaryPath) {
15615
- if (!fs28.existsSync(SYSTEMD_UNIT_DIR)) {
15616
- fs28.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
16165
+ if (!fs29.existsSync(SYSTEMD_UNIT_DIR)) {
16166
+ fs29.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
15617
16167
  }
15618
- fs28.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
16168
+ fs29.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
15619
16169
  try {
15620
- execFileSync("loginctl", ["enable-linger", os26.userInfo().username], { timeout: 3e3 });
16170
+ execFileSync("loginctl", ["enable-linger", os27.userInfo().username], { timeout: 3e3 });
15621
16171
  } catch {
15622
16172
  }
15623
16173
  const reload = spawnSync2("systemctl", ["--user", "daemon-reload"], {
@@ -15637,23 +16187,23 @@ function installSystemd(binaryPath) {
15637
16187
  }
15638
16188
  }
15639
16189
  function uninstallSystemd() {
15640
- if (fs28.existsSync(SYSTEMD_UNIT)) {
16190
+ if (fs29.existsSync(SYSTEMD_UNIT)) {
15641
16191
  spawnSync2("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
15642
16192
  encoding: "utf8",
15643
16193
  timeout: 5e3
15644
16194
  });
15645
16195
  spawnSync2("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
15646
- fs28.unlinkSync(SYSTEMD_UNIT);
16196
+ fs29.unlinkSync(SYSTEMD_UNIT);
15647
16197
  }
15648
16198
  }
15649
16199
  function isSystemdInstalled() {
15650
- return fs28.existsSync(SYSTEMD_UNIT);
16200
+ return fs29.existsSync(SYSTEMD_UNIT);
15651
16201
  }
15652
16202
  function stopRunningDaemon() {
15653
- const pidFile = path30.join(os26.homedir(), ".node9", "daemon.pid");
15654
- if (!fs28.existsSync(pidFile)) return;
16203
+ const pidFile = path31.join(os27.homedir(), ".node9", "daemon.pid");
16204
+ if (!fs29.existsSync(pidFile)) return;
15655
16205
  try {
15656
- const data = JSON.parse(fs28.readFileSync(pidFile, "utf-8"));
16206
+ const data = JSON.parse(fs29.readFileSync(pidFile, "utf-8"));
15657
16207
  const pid = data.pid;
15658
16208
  const MAX_PID2 = 4194304;
15659
16209
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -15673,7 +16223,7 @@ function stopRunningDaemon() {
15673
16223
  }
15674
16224
  }
15675
16225
  try {
15676
- fs28.unlinkSync(pidFile);
16226
+ fs29.unlinkSync(pidFile);
15677
16227
  } catch {
15678
16228
  }
15679
16229
  } catch {
@@ -15748,19 +16298,19 @@ var init_service = __esm({
15748
16298
  "src/daemon/service.ts"() {
15749
16299
  "use strict";
15750
16300
  LAUNCHD_LABEL = "ai.node9.daemon";
15751
- LAUNCHD_PLIST = path30.join(os26.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
15752
- SYSTEMD_UNIT_DIR = path30.join(os26.homedir(), ".config", "systemd", "user");
15753
- SYSTEMD_UNIT = path30.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
16301
+ LAUNCHD_PLIST = path31.join(os27.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
16302
+ SYSTEMD_UNIT_DIR = path31.join(os27.homedir(), ".config", "systemd", "user");
16303
+ SYSTEMD_UNIT = path31.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
15754
16304
  }
15755
16305
  });
15756
16306
 
15757
16307
  // src/daemon/index.ts
15758
- import fs29 from "fs";
16308
+ import fs30 from "fs";
15759
16309
  import chalk7 from "chalk";
15760
16310
  function stopDaemon() {
15761
- if (!fs29.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
16311
+ if (!fs30.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
15762
16312
  try {
15763
- const data = JSON.parse(fs29.readFileSync(DAEMON_PID_FILE, "utf-8"));
16313
+ const data = JSON.parse(fs30.readFileSync(DAEMON_PID_FILE, "utf-8"));
15764
16314
  const pid = data.pid;
15765
16315
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
15766
16316
  console.log(chalk7.gray("Cleaned up invalid PID file."));
@@ -15772,7 +16322,7 @@ function stopDaemon() {
15772
16322
  console.log(chalk7.gray("Cleaned up stale PID file."));
15773
16323
  } finally {
15774
16324
  try {
15775
- fs29.unlinkSync(DAEMON_PID_FILE);
16325
+ fs30.unlinkSync(DAEMON_PID_FILE);
15776
16326
  } catch {
15777
16327
  }
15778
16328
  }
@@ -15781,9 +16331,9 @@ function daemonStatus() {
15781
16331
  const serviceInstalled = isDaemonServiceInstalled();
15782
16332
  const serviceLabel = serviceInstalled ? chalk7.green("installed (starts on login)") : chalk7.yellow("not installed \u2014 run: node9 daemon install");
15783
16333
  let processStatus;
15784
- if (fs29.existsSync(DAEMON_PID_FILE)) {
16334
+ if (fs30.existsSync(DAEMON_PID_FILE)) {
15785
16335
  try {
15786
- const data = JSON.parse(fs29.readFileSync(DAEMON_PID_FILE, "utf-8"));
16336
+ const data = JSON.parse(fs30.readFileSync(DAEMON_PID_FILE, "utf-8"));
15787
16337
  const pid = data.pid;
15788
16338
  const port = data.port;
15789
16339
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -15828,9 +16378,9 @@ __export(tail_exports, {
15828
16378
  });
15829
16379
  import http2 from "http";
15830
16380
  import chalk29 from "chalk";
15831
- import fs47 from "fs";
15832
- import os42 from "os";
15833
- import path48 from "path";
16381
+ import fs48 from "fs";
16382
+ import os43 from "os";
16383
+ import path49 from "path";
15834
16384
  import readline6 from "readline";
15835
16385
  import { spawn as spawn8 } from "child_process";
15836
16386
  function shortenPathSummary(s) {
@@ -15854,20 +16404,20 @@ function getModelContextLimit(model) {
15854
16404
  return 2e5;
15855
16405
  }
15856
16406
  function readSessionUsage() {
15857
- const projectsDir = path48.join(os42.homedir(), ".claude", "projects");
15858
- if (!fs47.existsSync(projectsDir)) return null;
16407
+ const projectsDir = path49.join(os43.homedir(), ".claude", "projects");
16408
+ if (!fs48.existsSync(projectsDir)) return null;
15859
16409
  let latestFile = null;
15860
16410
  let latestMtime = 0;
15861
16411
  try {
15862
- for (const dir of fs47.readdirSync(projectsDir)) {
15863
- const dirPath = path48.join(projectsDir, dir);
16412
+ for (const dir of fs48.readdirSync(projectsDir)) {
16413
+ const dirPath = path49.join(projectsDir, dir);
15864
16414
  try {
15865
- if (!fs47.statSync(dirPath).isDirectory()) continue;
15866
- for (const file of fs47.readdirSync(dirPath)) {
16415
+ if (!fs48.statSync(dirPath).isDirectory()) continue;
16416
+ for (const file of fs48.readdirSync(dirPath)) {
15867
16417
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
15868
- const filePath = path48.join(dirPath, file);
16418
+ const filePath = path49.join(dirPath, file);
15869
16419
  try {
15870
- const mtime = fs47.statSync(filePath).mtimeMs;
16420
+ const mtime = fs48.statSync(filePath).mtimeMs;
15871
16421
  if (mtime > latestMtime) {
15872
16422
  latestMtime = mtime;
15873
16423
  latestFile = filePath;
@@ -15882,7 +16432,7 @@ function readSessionUsage() {
15882
16432
  }
15883
16433
  if (!latestFile) return null;
15884
16434
  try {
15885
- const lines = fs47.readFileSync(latestFile, "utf-8").split("\n");
16435
+ const lines = fs48.readFileSync(latestFile, "utf-8").split("\n");
15886
16436
  let lastModel = "";
15887
16437
  let lastInput = 0;
15888
16438
  let lastOutput = 0;
@@ -15943,7 +16493,7 @@ function formatBase(activity) {
15943
16493
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
15944
16494
  const icon = getIcon(activity.tool);
15945
16495
  const toolName = activity.tool.slice(0, 16).padEnd(16);
15946
- const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os42.homedir(), "~");
16496
+ const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os43.homedir(), "~");
15947
16497
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
15948
16498
  return `${chalk29.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk29.white.bold(toolName)} ${chalk29.dim(argsPreview)}`;
15949
16499
  }
@@ -15982,9 +16532,9 @@ function renderPending(activity) {
15982
16532
  }
15983
16533
  async function ensureDaemon() {
15984
16534
  let pidPort = null;
15985
- if (fs47.existsSync(PID_FILE)) {
16535
+ if (fs48.existsSync(PID_FILE)) {
15986
16536
  try {
15987
- const { port } = JSON.parse(fs47.readFileSync(PID_FILE, "utf-8"));
16537
+ const { port } = JSON.parse(fs48.readFileSync(PID_FILE, "utf-8"));
15988
16538
  pidPort = port;
15989
16539
  } catch {
15990
16540
  console.error(chalk29.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -16140,9 +16690,9 @@ function buildRecoveryCardLines(req) {
16140
16690
  ];
16141
16691
  }
16142
16692
  function readApproversFromDisk() {
16143
- const configPath = path48.join(os42.homedir(), ".node9", "config.json");
16693
+ const configPath = path49.join(os43.homedir(), ".node9", "config.json");
16144
16694
  try {
16145
- const raw = JSON.parse(fs47.readFileSync(configPath, "utf-8"));
16695
+ const raw = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
16146
16696
  const settings = raw.settings ?? {};
16147
16697
  return settings.approvers ?? {};
16148
16698
  } catch {
@@ -16158,15 +16708,15 @@ function approverStatusLine() {
16158
16708
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
16159
16709
  }
16160
16710
  function toggleApprover(channel) {
16161
- const configPath = path48.join(os42.homedir(), ".node9", "config.json");
16711
+ const configPath = path49.join(os43.homedir(), ".node9", "config.json");
16162
16712
  try {
16163
- const raw = JSON.parse(fs47.readFileSync(configPath, "utf-8"));
16713
+ const raw = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
16164
16714
  const settings = raw.settings ?? {};
16165
16715
  const approvers = settings.approvers ?? {};
16166
16716
  approvers[channel] = approvers[channel] === false;
16167
16717
  settings.approvers = approvers;
16168
16718
  raw.settings = settings;
16169
- fs47.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
16719
+ fs48.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
16170
16720
  } catch (err2) {
16171
16721
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
16172
16722
  `);
@@ -16338,8 +16888,8 @@ async function startTail(options = {}) {
16338
16888
  }
16339
16889
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
16340
16890
  try {
16341
- fs47.appendFileSync(
16342
- path48.join(os42.homedir(), ".node9", "hook-debug.log"),
16891
+ fs48.appendFileSync(
16892
+ path49.join(os43.homedir(), ".node9", "hook-debug.log"),
16343
16893
  `[tail] POST /decision failed: ${String(err2)}
16344
16894
  `
16345
16895
  );
@@ -16403,9 +16953,9 @@ async function startTail(options = {}) {
16403
16953
  };
16404
16954
  process.stdin.on("keypress", onKeypress);
16405
16955
  }
16406
- const auditLog = path48.join(os42.homedir(), ".node9", "audit.log");
16956
+ const auditLog = path49.join(os43.homedir(), ".node9", "audit.log");
16407
16957
  try {
16408
- const unackedDlp = fs47.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
16958
+ const unackedDlp = fs48.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
16409
16959
  if (unackedDlp > 0) {
16410
16960
  console.log("");
16411
16961
  console.log(
@@ -16445,7 +16995,7 @@ async function startTail(options = {}) {
16445
16995
  if (stallWarned) return;
16446
16996
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
16447
16997
  try {
16448
- const auditMtime = fs47.statSync(auditLog).mtimeMs;
16998
+ const auditMtime = fs48.statSync(auditLog).mtimeMs;
16449
16999
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
16450
17000
  console.log("");
16451
17001
  console.log(
@@ -16636,7 +17186,7 @@ var init_tail = __esm({
16636
17186
  "use strict";
16637
17187
  init_daemon2();
16638
17188
  init_daemon();
16639
- PID_FILE = path48.join(os42.homedir(), ".node9", "daemon.pid");
17189
+ PID_FILE = path49.join(os43.homedir(), ".node9", "daemon.pid");
16640
17190
  ICONS = {
16641
17191
  bash: "\u{1F4BB}",
16642
17192
  shell: "\u{1F4BB}",
@@ -16684,9 +17234,9 @@ __export(hud_exports, {
16684
17234
  main: () => main,
16685
17235
  renderEnvironmentLine: () => renderEnvironmentLine
16686
17236
  });
16687
- import fs48 from "fs";
16688
- import path49 from "path";
16689
- import os43 from "os";
17237
+ import fs49 from "fs";
17238
+ import path50 from "path";
17239
+ import os44 from "os";
16690
17240
  import http3 from "http";
16691
17241
  async function readStdin() {
16692
17242
  const chunks = [];
@@ -16762,9 +17312,9 @@ function formatTimeLeft(resetsAt) {
16762
17312
  return ` (${m}m left)`;
16763
17313
  }
16764
17314
  function safeReadJson(filePath) {
16765
- if (!fs48.existsSync(filePath)) return null;
17315
+ if (!fs49.existsSync(filePath)) return null;
16766
17316
  try {
16767
- return JSON.parse(fs48.readFileSync(filePath, "utf-8"));
17317
+ return JSON.parse(fs49.readFileSync(filePath, "utf-8"));
16768
17318
  } catch {
16769
17319
  return null;
16770
17320
  }
@@ -16785,12 +17335,12 @@ function countHooksInFile(filePath) {
16785
17335
  return Object.keys(cfg.hooks).length;
16786
17336
  }
16787
17337
  function countRulesInDir(rulesDir) {
16788
- if (!fs48.existsSync(rulesDir)) return 0;
17338
+ if (!fs49.existsSync(rulesDir)) return 0;
16789
17339
  let count = 0;
16790
17340
  try {
16791
- for (const entry of fs48.readdirSync(rulesDir, { withFileTypes: true })) {
17341
+ for (const entry of fs49.readdirSync(rulesDir, { withFileTypes: true })) {
16792
17342
  if (entry.isDirectory()) {
16793
- count += countRulesInDir(path49.join(rulesDir, entry.name));
17343
+ count += countRulesInDir(path50.join(rulesDir, entry.name));
16794
17344
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
16795
17345
  count++;
16796
17346
  }
@@ -16801,46 +17351,46 @@ function countRulesInDir(rulesDir) {
16801
17351
  }
16802
17352
  function isSamePath(a, b) {
16803
17353
  try {
16804
- return path49.resolve(a) === path49.resolve(b);
17354
+ return path50.resolve(a) === path50.resolve(b);
16805
17355
  } catch {
16806
17356
  return false;
16807
17357
  }
16808
17358
  }
16809
17359
  function countConfigs(cwd) {
16810
- const homeDir2 = os43.homedir();
16811
- const claudeDir = path49.join(homeDir2, ".claude");
17360
+ const homeDir2 = os44.homedir();
17361
+ const claudeDir = path50.join(homeDir2, ".claude");
16812
17362
  let claudeMdCount = 0;
16813
17363
  let rulesCount = 0;
16814
17364
  let hooksCount = 0;
16815
17365
  const userMcpServers = /* @__PURE__ */ new Set();
16816
17366
  const projectMcpServers = /* @__PURE__ */ new Set();
16817
- if (fs48.existsSync(path49.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
16818
- rulesCount += countRulesInDir(path49.join(claudeDir, "rules"));
16819
- const userSettings = path49.join(claudeDir, "settings.json");
17367
+ if (fs49.existsSync(path50.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
17368
+ rulesCount += countRulesInDir(path50.join(claudeDir, "rules"));
17369
+ const userSettings = path50.join(claudeDir, "settings.json");
16820
17370
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
16821
17371
  hooksCount += countHooksInFile(userSettings);
16822
- const userClaudeJson = path49.join(homeDir2, ".claude.json");
17372
+ const userClaudeJson = path50.join(homeDir2, ".claude.json");
16823
17373
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
16824
17374
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
16825
17375
  userMcpServers.delete(name);
16826
17376
  }
16827
17377
  if (cwd) {
16828
- if (fs48.existsSync(path49.join(cwd, "CLAUDE.md"))) claudeMdCount++;
16829
- if (fs48.existsSync(path49.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
16830
- const projectClaudeDir = path49.join(cwd, ".claude");
17378
+ if (fs49.existsSync(path50.join(cwd, "CLAUDE.md"))) claudeMdCount++;
17379
+ if (fs49.existsSync(path50.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
17380
+ const projectClaudeDir = path50.join(cwd, ".claude");
16831
17381
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
16832
17382
  if (!overlapsUserScope) {
16833
- if (fs48.existsSync(path49.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
16834
- rulesCount += countRulesInDir(path49.join(projectClaudeDir, "rules"));
16835
- const projSettings = path49.join(projectClaudeDir, "settings.json");
17383
+ if (fs49.existsSync(path50.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
17384
+ rulesCount += countRulesInDir(path50.join(projectClaudeDir, "rules"));
17385
+ const projSettings = path50.join(projectClaudeDir, "settings.json");
16836
17386
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
16837
17387
  hooksCount += countHooksInFile(projSettings);
16838
17388
  }
16839
- if (fs48.existsSync(path49.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
16840
- const localSettings = path49.join(projectClaudeDir, "settings.local.json");
17389
+ if (fs49.existsSync(path50.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
17390
+ const localSettings = path50.join(projectClaudeDir, "settings.local.json");
16841
17391
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
16842
17392
  hooksCount += countHooksInFile(localSettings);
16843
- const mcpJsonServers = getMcpServerNames(path49.join(cwd, ".mcp.json"));
17393
+ const mcpJsonServers = getMcpServerNames(path50.join(cwd, ".mcp.json"));
16844
17394
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
16845
17395
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
16846
17396
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -16873,12 +17423,12 @@ function readActiveShieldsHud() {
16873
17423
  return shieldsCache.value;
16874
17424
  }
16875
17425
  try {
16876
- const shieldsPath = path49.join(os43.homedir(), ".node9", "shields.json");
16877
- if (!fs48.existsSync(shieldsPath)) {
17426
+ const shieldsPath = path50.join(os44.homedir(), ".node9", "shields.json");
17427
+ if (!fs49.existsSync(shieldsPath)) {
16878
17428
  shieldsCache = { value: [], ts: now };
16879
17429
  return [];
16880
17430
  }
16881
- const parsed = JSON.parse(fs48.readFileSync(shieldsPath, "utf-8"));
17431
+ const parsed = JSON.parse(fs49.readFileSync(shieldsPath, "utf-8"));
16882
17432
  if (!Array.isArray(parsed.active)) {
16883
17433
  shieldsCache = { value: [], ts: now };
16884
17434
  return [];
@@ -16980,17 +17530,17 @@ function renderContextLine(stdin) {
16980
17530
  async function main() {
16981
17531
  try {
16982
17532
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
16983
- if (fs48.existsSync(path49.join(os43.homedir(), ".node9", "hud-debug"))) {
17533
+ if (fs49.existsSync(path50.join(os44.homedir(), ".node9", "hud-debug"))) {
16984
17534
  try {
16985
- const logPath = path49.join(os43.homedir(), ".node9", "hud-debug.log");
17535
+ const logPath = path50.join(os44.homedir(), ".node9", "hud-debug.log");
16986
17536
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
16987
17537
  let size = 0;
16988
17538
  try {
16989
- size = fs48.statSync(logPath).size;
17539
+ size = fs49.statSync(logPath).size;
16990
17540
  } catch {
16991
17541
  }
16992
17542
  if (size < MAX_LOG_SIZE) {
16993
- fs48.appendFileSync(
17543
+ fs49.appendFileSync(
16994
17544
  logPath,
16995
17545
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
16996
17546
  );
@@ -17011,11 +17561,11 @@ async function main() {
17011
17561
  try {
17012
17562
  const cwd = stdin.cwd ?? process.cwd();
17013
17563
  for (const configPath of [
17014
- path49.join(cwd, "node9.config.json"),
17015
- path49.join(os43.homedir(), ".node9", "config.json")
17564
+ path50.join(cwd, "node9.config.json"),
17565
+ path50.join(os44.homedir(), ".node9", "config.json")
17016
17566
  ]) {
17017
- if (!fs48.existsSync(configPath)) continue;
17018
- const cfg = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
17567
+ if (!fs49.existsSync(configPath)) continue;
17568
+ const cfg = JSON.parse(fs49.readFileSync(configPath, "utf-8"));
17019
17569
  const hud = cfg.settings?.hud;
17020
17570
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
17021
17571
  }
@@ -17062,9 +17612,9 @@ init_setup();
17062
17612
  init_daemon2();
17063
17613
  import { Command } from "commander";
17064
17614
  import chalk30 from "chalk";
17065
- import fs49 from "fs";
17066
- import path50 from "path";
17067
- import os44 from "os";
17615
+ import fs50 from "fs";
17616
+ import path51 from "path";
17617
+ import os45 from "os";
17068
17618
  import { confirm as confirm2 } from "@inquirer/prompts";
17069
17619
 
17070
17620
  // src/utils/duration.ts
@@ -17247,17 +17797,17 @@ async function runProxy(targetCommand) {
17247
17797
  // src/cli/daemon-starter.ts
17248
17798
  init_daemon();
17249
17799
  import { spawn as spawn3 } from "child_process";
17250
- import path31 from "path";
17251
- import fs30 from "fs";
17800
+ import path32 from "path";
17801
+ import fs31 from "fs";
17252
17802
  function isTestingMode() {
17253
17803
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
17254
17804
  }
17255
17805
  async function autoStartDaemonAndWait() {
17256
17806
  if (isTestingMode()) return false;
17257
- if (!path31.isAbsolute(process.argv[1])) return false;
17807
+ if (!path32.isAbsolute(process.argv[1])) return false;
17258
17808
  let resolvedArgv1;
17259
17809
  try {
17260
- resolvedArgv1 = fs30.realpathSync(process.argv[1]);
17810
+ resolvedArgv1 = fs31.realpathSync(process.argv[1]);
17261
17811
  } catch {
17262
17812
  return false;
17263
17813
  }
@@ -17288,19 +17838,19 @@ init_daemon();
17288
17838
  init_config();
17289
17839
  init_policy();
17290
17840
  import chalk9 from "chalk";
17291
- import fs33 from "fs";
17841
+ import fs34 from "fs";
17292
17842
  import { spawn as spawn5 } from "child_process";
17293
- import path34 from "path";
17294
- import os29 from "os";
17843
+ import path35 from "path";
17844
+ import os30 from "os";
17295
17845
 
17296
17846
  // src/undo.ts
17297
17847
  import { spawnSync as spawnSync3, spawn as spawn4 } from "child_process";
17298
17848
  import crypto6 from "crypto";
17299
- import fs31 from "fs";
17849
+ import fs32 from "fs";
17300
17850
  import net3 from "net";
17301
- import path32 from "path";
17302
- import os27 from "os";
17303
- var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path32.join(os27.tmpdir(), "node9-activity.sock");
17851
+ import path33 from "path";
17852
+ import os28 from "os";
17853
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path33.join(os28.tmpdir(), "node9-activity.sock");
17304
17854
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
17305
17855
  try {
17306
17856
  const payload = JSON.stringify({
@@ -17320,22 +17870,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
17320
17870
  } catch {
17321
17871
  }
17322
17872
  }
17323
- var SNAPSHOT_STACK_PATH = path32.join(os27.homedir(), ".node9", "snapshots.json");
17324
- var UNDO_LATEST_PATH = path32.join(os27.homedir(), ".node9", "undo_latest.txt");
17873
+ var SNAPSHOT_STACK_PATH = path33.join(os28.homedir(), ".node9", "snapshots.json");
17874
+ var UNDO_LATEST_PATH = path33.join(os28.homedir(), ".node9", "undo_latest.txt");
17325
17875
  var MAX_SNAPSHOTS = 10;
17326
17876
  var GIT_TIMEOUT = 15e3;
17327
17877
  function readStack() {
17328
17878
  try {
17329
- if (fs31.existsSync(SNAPSHOT_STACK_PATH))
17330
- return JSON.parse(fs31.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
17879
+ if (fs32.existsSync(SNAPSHOT_STACK_PATH))
17880
+ return JSON.parse(fs32.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
17331
17881
  } catch {
17332
17882
  }
17333
17883
  return [];
17334
17884
  }
17335
17885
  function writeStack(stack) {
17336
- const dir = path32.dirname(SNAPSHOT_STACK_PATH);
17337
- if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
17338
- fs31.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
17886
+ const dir = path33.dirname(SNAPSHOT_STACK_PATH);
17887
+ if (!fs32.existsSync(dir)) fs32.mkdirSync(dir, { recursive: true });
17888
+ fs32.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
17339
17889
  }
17340
17890
  function extractFilePath(args) {
17341
17891
  if (!args || typeof args !== "object") return null;
@@ -17355,12 +17905,12 @@ function buildArgsSummary(tool, args) {
17355
17905
  return "";
17356
17906
  }
17357
17907
  function findProjectRoot(filePath) {
17358
- let dir = path32.dirname(filePath);
17908
+ let dir = path33.dirname(filePath);
17359
17909
  while (true) {
17360
- if (fs31.existsSync(path32.join(dir, ".git")) || fs31.existsSync(path32.join(dir, "package.json"))) {
17910
+ if (fs32.existsSync(path33.join(dir, ".git")) || fs32.existsSync(path33.join(dir, "package.json"))) {
17361
17911
  return dir;
17362
17912
  }
17363
- const parent = path32.dirname(dir);
17913
+ const parent = path33.dirname(dir);
17364
17914
  if (parent === dir) return process.cwd();
17365
17915
  dir = parent;
17366
17916
  }
@@ -17368,7 +17918,7 @@ function findProjectRoot(filePath) {
17368
17918
  function normalizeCwdForHash(cwd) {
17369
17919
  let normalized;
17370
17920
  try {
17371
- normalized = fs31.realpathSync(cwd);
17921
+ normalized = fs32.realpathSync(cwd);
17372
17922
  } catch {
17373
17923
  normalized = cwd;
17374
17924
  }
@@ -17378,16 +17928,16 @@ function normalizeCwdForHash(cwd) {
17378
17928
  }
17379
17929
  function getShadowRepoDir(cwd) {
17380
17930
  const hash = crypto6.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
17381
- return path32.join(os27.homedir(), ".node9", "snapshots", hash);
17931
+ return path33.join(os28.homedir(), ".node9", "snapshots", hash);
17382
17932
  }
17383
17933
  function cleanOrphanedIndexFiles(shadowDir) {
17384
17934
  try {
17385
17935
  const cutoff = Date.now() - 6e4;
17386
- for (const f of fs31.readdirSync(shadowDir)) {
17936
+ for (const f of fs32.readdirSync(shadowDir)) {
17387
17937
  if (f.startsWith("index_")) {
17388
- const fp = path32.join(shadowDir, f);
17938
+ const fp = path33.join(shadowDir, f);
17389
17939
  try {
17390
- if (fs31.statSync(fp).mtimeMs < cutoff) fs31.unlinkSync(fp);
17940
+ if (fs32.statSync(fp).mtimeMs < cutoff) fs32.unlinkSync(fp);
17391
17941
  } catch {
17392
17942
  }
17393
17943
  }
@@ -17399,7 +17949,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
17399
17949
  const hardcoded = [".git", ".node9"];
17400
17950
  const lines = [...hardcoded, ...ignorePaths].join("\n");
17401
17951
  try {
17402
- fs31.writeFileSync(path32.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
17952
+ fs32.writeFileSync(path33.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
17403
17953
  } catch {
17404
17954
  }
17405
17955
  }
@@ -17412,25 +17962,25 @@ function ensureShadowRepo(shadowDir, cwd) {
17412
17962
  timeout: 3e3
17413
17963
  });
17414
17964
  if (check.status === 0) {
17415
- const ptPath = path32.join(shadowDir, "project-path.txt");
17965
+ const ptPath = path33.join(shadowDir, "project-path.txt");
17416
17966
  try {
17417
- const stored = fs31.readFileSync(ptPath, "utf8").trim();
17967
+ const stored = fs32.readFileSync(ptPath, "utf8").trim();
17418
17968
  if (stored === normalizedCwd) return true;
17419
17969
  if (process.env.NODE9_DEBUG === "1")
17420
17970
  console.error(
17421
17971
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
17422
17972
  );
17423
- fs31.rmSync(shadowDir, { recursive: true, force: true });
17973
+ fs32.rmSync(shadowDir, { recursive: true, force: true });
17424
17974
  } catch {
17425
17975
  try {
17426
- fs31.writeFileSync(ptPath, normalizedCwd, "utf8");
17976
+ fs32.writeFileSync(ptPath, normalizedCwd, "utf8");
17427
17977
  } catch {
17428
17978
  }
17429
17979
  return true;
17430
17980
  }
17431
17981
  }
17432
17982
  try {
17433
- fs31.mkdirSync(shadowDir, { recursive: true });
17983
+ fs32.mkdirSync(shadowDir, { recursive: true });
17434
17984
  } catch {
17435
17985
  }
17436
17986
  const init = spawnSync3("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -17439,7 +17989,7 @@ function ensureShadowRepo(shadowDir, cwd) {
17439
17989
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
17440
17990
  return false;
17441
17991
  }
17442
- const configFile = path32.join(shadowDir, "config");
17992
+ const configFile = path33.join(shadowDir, "config");
17443
17993
  spawnSync3("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
17444
17994
  timeout: 3e3
17445
17995
  });
@@ -17447,7 +17997,7 @@ function ensureShadowRepo(shadowDir, cwd) {
17447
17997
  timeout: 3e3
17448
17998
  });
17449
17999
  try {
17450
- fs31.writeFileSync(path32.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
18000
+ fs32.writeFileSync(path33.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
17451
18001
  } catch {
17452
18002
  }
17453
18003
  return true;
@@ -17470,12 +18020,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
17470
18020
  let indexFile = null;
17471
18021
  try {
17472
18022
  const rawFilePath = extractFilePath(args);
17473
- const absFilePath = rawFilePath && path32.isAbsolute(rawFilePath) ? rawFilePath : null;
18023
+ const absFilePath = rawFilePath && path33.isAbsolute(rawFilePath) ? rawFilePath : null;
17474
18024
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
17475
18025
  const shadowDir = getShadowRepoDir(cwd);
17476
18026
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
17477
18027
  writeShadowExcludes(shadowDir, ignorePaths);
17478
- indexFile = path32.join(shadowDir, `index_${process.pid}_${Date.now()}`);
18028
+ indexFile = path33.join(shadowDir, `index_${process.pid}_${Date.now()}`);
17479
18029
  const shadowEnv = {
17480
18030
  ...process.env,
17481
18031
  GIT_DIR: shadowDir,
@@ -17547,7 +18097,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
17547
18097
  writeStack(stack);
17548
18098
  const entry = stack[stack.length - 1];
17549
18099
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
17550
- fs31.writeFileSync(UNDO_LATEST_PATH, commitHash);
18100
+ fs32.writeFileSync(UNDO_LATEST_PATH, commitHash);
17551
18101
  if (shouldGc) {
17552
18102
  spawn4("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
17553
18103
  }
@@ -17558,7 +18108,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
17558
18108
  } finally {
17559
18109
  if (indexFile) {
17560
18110
  try {
17561
- fs31.unlinkSync(indexFile);
18111
+ fs32.unlinkSync(indexFile);
17562
18112
  } catch {
17563
18113
  }
17564
18114
  }
@@ -17634,9 +18184,9 @@ function applyUndo(hash, cwd) {
17634
18184
  timeout: GIT_TIMEOUT
17635
18185
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
17636
18186
  for (const file of [...tracked, ...untracked]) {
17637
- const fullPath = path32.join(dir, file);
17638
- if (!snapshotFiles.has(file) && fs31.existsSync(fullPath)) {
17639
- fs31.unlinkSync(fullPath);
18187
+ const fullPath = path33.join(dir, file);
18188
+ if (!snapshotFiles.has(file) && fs32.existsSync(fullPath)) {
18189
+ fs32.unlinkSync(fullPath);
17640
18190
  }
17641
18191
  }
17642
18192
  return true;
@@ -17646,12 +18196,12 @@ function applyUndo(hash, cwd) {
17646
18196
  }
17647
18197
 
17648
18198
  // src/skill-pin.ts
17649
- import fs32 from "fs";
17650
- import path33 from "path";
17651
- import os28 from "os";
18199
+ import fs33 from "fs";
18200
+ import path34 from "path";
18201
+ import os29 from "os";
17652
18202
  import crypto7 from "crypto";
17653
18203
  function getPinsFilePath2() {
17654
- return path33.join(os28.homedir(), ".node9", "skill-pins.json");
18204
+ return path34.join(os29.homedir(), ".node9", "skill-pins.json");
17655
18205
  }
17656
18206
  var MAX_FILES = 5e3;
17657
18207
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
@@ -17665,18 +18215,18 @@ function walkDir(root) {
17665
18215
  if (out.length >= MAX_FILES) return;
17666
18216
  let entries;
17667
18217
  try {
17668
- entries = fs32.readdirSync(dir, { withFileTypes: true });
18218
+ entries = fs33.readdirSync(dir, { withFileTypes: true });
17669
18219
  } catch {
17670
18220
  return;
17671
18221
  }
17672
18222
  entries.sort((a, b) => a.name.localeCompare(b.name));
17673
18223
  for (const entry of entries) {
17674
18224
  if (out.length >= MAX_FILES) return;
17675
- const full = path33.join(dir, entry.name);
17676
- const rel = relDir ? path33.posix.join(relDir, entry.name) : entry.name;
18225
+ const full = path34.join(dir, entry.name);
18226
+ const rel = relDir ? path34.posix.join(relDir, entry.name) : entry.name;
17677
18227
  let lst;
17678
18228
  try {
17679
- lst = fs32.lstatSync(full);
18229
+ lst = fs33.lstatSync(full);
17680
18230
  } catch {
17681
18231
  continue;
17682
18232
  }
@@ -17688,7 +18238,7 @@ function walkDir(root) {
17688
18238
  if (!lst.isFile()) continue;
17689
18239
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
17690
18240
  try {
17691
- const buf = fs32.readFileSync(full);
18241
+ const buf = fs33.readFileSync(full);
17692
18242
  totalBytes += buf.length;
17693
18243
  out.push({ rel, hash: sha256Bytes(buf) });
17694
18244
  } catch {
@@ -17702,14 +18252,14 @@ function walkDir(root) {
17702
18252
  function hashSkillRoot(absPath) {
17703
18253
  let lst;
17704
18254
  try {
17705
- lst = fs32.lstatSync(absPath);
18255
+ lst = fs33.lstatSync(absPath);
17706
18256
  } catch {
17707
18257
  return { exists: false, contentHash: "", fileCount: 0 };
17708
18258
  }
17709
18259
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
17710
18260
  if (lst.isFile()) {
17711
18261
  try {
17712
- return { exists: true, contentHash: sha256Bytes(fs32.readFileSync(absPath)), fileCount: 1 };
18262
+ return { exists: true, contentHash: sha256Bytes(fs33.readFileSync(absPath)), fileCount: 1 };
17713
18263
  } catch {
17714
18264
  return { exists: false, contentHash: "", fileCount: 0 };
17715
18265
  }
@@ -17727,7 +18277,7 @@ function getRootKey(absPath) {
17727
18277
  function readSkillPinsSafe() {
17728
18278
  const filePath = getPinsFilePath2();
17729
18279
  try {
17730
- const raw = fs32.readFileSync(filePath, "utf-8");
18280
+ const raw = fs33.readFileSync(filePath, "utf-8");
17731
18281
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
17732
18282
  const parsed = JSON.parse(raw);
17733
18283
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -17747,10 +18297,10 @@ function readSkillPins() {
17747
18297
  }
17748
18298
  function writeSkillPins(data) {
17749
18299
  const filePath = getPinsFilePath2();
17750
- fs32.mkdirSync(path33.dirname(filePath), { recursive: true });
18300
+ fs33.mkdirSync(path34.dirname(filePath), { recursive: true });
17751
18301
  const tmp = `${filePath}.${crypto7.randomBytes(6).toString("hex")}.tmp`;
17752
- fs32.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
17753
- fs32.renameSync(tmp, filePath);
18302
+ fs33.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
18303
+ fs33.renameSync(tmp, filePath);
17754
18304
  }
17755
18305
  function removePin2(rootKey) {
17756
18306
  const pins = readSkillPins();
@@ -17794,36 +18344,36 @@ function verifyAndPinRoots(roots) {
17794
18344
  return { kind: "verified" };
17795
18345
  }
17796
18346
  function defaultSkillRoots(_cwd) {
17797
- const marketplaces = path33.join(os28.homedir(), ".claude", "plugins", "marketplaces");
18347
+ const marketplaces = path34.join(os29.homedir(), ".claude", "plugins", "marketplaces");
17798
18348
  const roots = [];
17799
18349
  let registries;
17800
18350
  try {
17801
- registries = fs32.readdirSync(marketplaces, { withFileTypes: true });
18351
+ registries = fs33.readdirSync(marketplaces, { withFileTypes: true });
17802
18352
  } catch {
17803
18353
  return [];
17804
18354
  }
17805
18355
  for (const registry of registries) {
17806
18356
  if (!registry.isDirectory()) continue;
17807
- const pluginsDir = path33.join(marketplaces, registry.name, "plugins");
18357
+ const pluginsDir = path34.join(marketplaces, registry.name, "plugins");
17808
18358
  let plugins;
17809
18359
  try {
17810
- plugins = fs32.readdirSync(pluginsDir, { withFileTypes: true });
18360
+ plugins = fs33.readdirSync(pluginsDir, { withFileTypes: true });
17811
18361
  } catch {
17812
18362
  continue;
17813
18363
  }
17814
18364
  for (const plugin of plugins) {
17815
18365
  if (!plugin.isDirectory()) continue;
17816
- roots.push(path33.join(pluginsDir, plugin.name));
18366
+ roots.push(path34.join(pluginsDir, plugin.name));
17817
18367
  }
17818
18368
  }
17819
18369
  return roots;
17820
18370
  }
17821
18371
  function resolveUserSkillRoot(entry, cwd) {
17822
18372
  if (!entry) return null;
17823
- if (entry.startsWith("~/") || entry === "~") return path33.join(os28.homedir(), entry.slice(1));
17824
- if (path33.isAbsolute(entry)) return entry;
17825
- if (!cwd || !path33.isAbsolute(cwd)) return null;
17826
- return path33.join(cwd, entry);
18373
+ if (entry.startsWith("~/") || entry === "~") return path34.join(os29.homedir(), entry.slice(1));
18374
+ if (path34.isAbsolute(entry)) return entry;
18375
+ if (!cwd || !path34.isAbsolute(cwd)) return null;
18376
+ return path34.join(cwd, entry);
17827
18377
  }
17828
18378
 
17829
18379
  // src/cli/commands/check.ts
@@ -17892,9 +18442,9 @@ function registerCheckCommand(program2) {
17892
18442
  } catch (err2) {
17893
18443
  const tempConfig = getConfig();
17894
18444
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
17895
- const logPath = path34.join(os29.homedir(), ".node9", "hook-debug.log");
18445
+ const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
17896
18446
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
17897
- fs33.appendFileSync(
18447
+ fs34.appendFileSync(
17898
18448
  logPath,
17899
18449
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
17900
18450
  RAW: ${raw}
@@ -17907,14 +18457,14 @@ RAW: ${raw}
17907
18457
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
17908
18458
  if (process.env.NODE9_DEBUG === "1") {
17909
18459
  try {
17910
- const logPath = path34.join(os29.homedir(), ".node9", "hook-debug.log");
17911
- if (!fs33.existsSync(path34.dirname(logPath)))
17912
- fs33.mkdirSync(path34.dirname(logPath), { recursive: true });
18460
+ const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18461
+ if (!fs34.existsSync(path35.dirname(logPath)))
18462
+ fs34.mkdirSync(path35.dirname(logPath), { recursive: true });
17913
18463
  const sanitized = JSON.stringify({
17914
18464
  ...payload,
17915
18465
  prompt: `<redacted, ${prompt.length} bytes>`
17916
18466
  });
17917
- fs33.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
18467
+ fs34.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
17918
18468
  `);
17919
18469
  } catch {
17920
18470
  }
@@ -17934,8 +18484,8 @@ RAW: ${raw}
17934
18484
  );
17935
18485
  const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
17936
18486
  try {
17937
- const ttyFd = fs33.openSync("/dev/tty", "w");
17938
- fs33.writeSync(
18487
+ const ttyFd = fs34.openSync("/dev/tty", "w");
18488
+ fs34.writeSync(
17939
18489
  ttyFd,
17940
18490
  chalk9.bgRed.white.bold(`
17941
18491
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -17945,7 +18495,7 @@ RAW: ${raw}
17945
18495
 
17946
18496
  `)
17947
18497
  );
17948
- fs33.closeSync(ttyFd);
18498
+ fs34.closeSync(ttyFd);
17949
18499
  } catch {
17950
18500
  }
17951
18501
  const isCodex = agent2 === "Codex";
@@ -17964,16 +18514,16 @@ RAW: ${raw}
17964
18514
  process.exit(2);
17965
18515
  }
17966
18516
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
17967
- const safeCwdForConfig = typeof payloadCwd === "string" && path34.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18517
+ const safeCwdForConfig = typeof payloadCwd === "string" && path35.isAbsolute(payloadCwd) ? payloadCwd : void 0;
17968
18518
  const config = getConfig(safeCwdForConfig);
17969
18519
  if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
17970
18520
  try {
17971
18521
  const scriptPath = process.argv[1];
17972
- if (typeof scriptPath !== "string" || !path34.isAbsolute(scriptPath))
18522
+ if (typeof scriptPath !== "string" || !path35.isAbsolute(scriptPath))
17973
18523
  throw new Error("node9: argv[1] is not an absolute path");
17974
- const resolvedScript = fs33.realpathSync(scriptPath);
17975
- const packageDist = fs33.realpathSync(path34.resolve(__dirname, "../.."));
17976
- if (!resolvedScript.startsWith(packageDist + path34.sep) && resolvedScript !== packageDist)
18524
+ const resolvedScript = fs34.realpathSync(scriptPath);
18525
+ const packageDist = fs34.realpathSync(path35.resolve(__dirname, "../.."));
18526
+ if (!resolvedScript.startsWith(packageDist + path35.sep) && resolvedScript !== packageDist)
17977
18527
  throw new Error(
17978
18528
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
17979
18529
  );
@@ -17995,10 +18545,10 @@ RAW: ${raw}
17995
18545
  });
17996
18546
  d.unref();
17997
18547
  } catch (spawnErr) {
17998
- const logPath = path34.join(os29.homedir(), ".node9", "hook-debug.log");
18548
+ const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
17999
18549
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
18000
18550
  try {
18001
- fs33.appendFileSync(
18551
+ fs34.appendFileSync(
18002
18552
  logPath,
18003
18553
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
18004
18554
  `
@@ -18008,10 +18558,10 @@ RAW: ${raw}
18008
18558
  }
18009
18559
  }
18010
18560
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
18011
- const logPath = path34.join(os29.homedir(), ".node9", "hook-debug.log");
18012
- if (!fs33.existsSync(path34.dirname(logPath)))
18013
- fs33.mkdirSync(path34.dirname(logPath), { recursive: true });
18014
- fs33.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
18561
+ const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18562
+ if (!fs34.existsSync(path35.dirname(logPath)))
18563
+ fs34.mkdirSync(path35.dirname(logPath), { recursive: true });
18564
+ fs34.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
18015
18565
  `);
18016
18566
  }
18017
18567
  const rawToolName = sanitize2(extractToolName(payload));
@@ -18025,8 +18575,8 @@ RAW: ${raw}
18025
18575
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
18026
18576
  let ttyFd = null;
18027
18577
  try {
18028
- ttyFd = fs33.openSync("/dev/tty", "w");
18029
- const writeTty = (line) => fs33.writeSync(ttyFd, line + "\n");
18578
+ ttyFd = fs34.openSync("/dev/tty", "w");
18579
+ const writeTty = (line) => fs34.writeSync(ttyFd, line + "\n");
18030
18580
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
18031
18581
  writeTty(chalk9.bgRed.white.bold(`
18032
18582
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -18045,7 +18595,7 @@ RAW: ${raw}
18045
18595
  } finally {
18046
18596
  if (ttyFd !== null)
18047
18597
  try {
18048
- fs33.closeSync(ttyFd);
18598
+ fs34.closeSync(ttyFd);
18049
18599
  } catch {
18050
18600
  }
18051
18601
  }
@@ -18096,17 +18646,17 @@ RAW: ${raw}
18096
18646
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
18097
18647
  if (skillPinCfg.enabled && safeSessionId) {
18098
18648
  try {
18099
- const sessionsDir = path34.join(os29.homedir(), ".node9", "skill-sessions");
18100
- const flagPath = path34.join(sessionsDir, `${safeSessionId}.json`);
18649
+ const sessionsDir = path35.join(os30.homedir(), ".node9", "skill-sessions");
18650
+ const flagPath = path35.join(sessionsDir, `${safeSessionId}.json`);
18101
18651
  let flag = null;
18102
18652
  try {
18103
- flag = JSON.parse(fs33.readFileSync(flagPath, "utf-8"));
18653
+ flag = JSON.parse(fs34.readFileSync(flagPath, "utf-8"));
18104
18654
  } catch {
18105
18655
  }
18106
18656
  const writeFlag = (data2) => {
18107
18657
  try {
18108
- fs33.mkdirSync(sessionsDir, { recursive: true });
18109
- fs33.writeFileSync(
18658
+ fs34.mkdirSync(sessionsDir, { recursive: true });
18659
+ fs34.writeFileSync(
18110
18660
  flagPath,
18111
18661
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
18112
18662
  { mode: 384 }
@@ -18117,8 +18667,8 @@ RAW: ${raw}
18117
18667
  const sendSkillWarn = (detail, recoveryCmd) => {
18118
18668
  let ttyFd = null;
18119
18669
  try {
18120
- ttyFd = fs33.openSync("/dev/tty", "w");
18121
- const w = (line) => fs33.writeSync(ttyFd, line + "\n");
18670
+ ttyFd = fs34.openSync("/dev/tty", "w");
18671
+ const w = (line) => fs34.writeSync(ttyFd, line + "\n");
18122
18672
  w(chalk9.yellow(`
18123
18673
  \u26A0\uFE0F Node9: installed skill drift detected`));
18124
18674
  w(chalk9.gray(` ${detail}`));
@@ -18133,7 +18683,7 @@ RAW: ${raw}
18133
18683
  } finally {
18134
18684
  if (ttyFd !== null)
18135
18685
  try {
18136
- fs33.closeSync(ttyFd);
18686
+ fs34.closeSync(ttyFd);
18137
18687
  } catch {
18138
18688
  }
18139
18689
  }
@@ -18149,7 +18699,7 @@ RAW: ${raw}
18149
18699
  return;
18150
18700
  }
18151
18701
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
18152
- const absoluteCwd = typeof payloadCwd === "string" && path34.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18702
+ const absoluteCwd = typeof payloadCwd === "string" && path35.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18153
18703
  const extraRoots = skillPinCfg.roots;
18154
18704
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
18155
18705
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -18190,10 +18740,10 @@ RAW: ${raw}
18190
18740
  }
18191
18741
  try {
18192
18742
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
18193
- for (const name of fs33.readdirSync(sessionsDir)) {
18194
- const p = path34.join(sessionsDir, name);
18743
+ for (const name of fs34.readdirSync(sessionsDir)) {
18744
+ const p = path35.join(sessionsDir, name);
18195
18745
  try {
18196
- if (fs33.statSync(p).mtimeMs < cutoff) fs33.unlinkSync(p);
18746
+ if (fs34.statSync(p).mtimeMs < cutoff) fs34.unlinkSync(p);
18197
18747
  } catch {
18198
18748
  }
18199
18749
  }
@@ -18203,9 +18753,9 @@ RAW: ${raw}
18203
18753
  } catch (err2) {
18204
18754
  if (process.env.NODE9_DEBUG === "1") {
18205
18755
  try {
18206
- const dbg = path34.join(os29.homedir(), ".node9", "hook-debug.log");
18756
+ const dbg = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18207
18757
  const msg = err2 instanceof Error ? err2.message : String(err2);
18208
- fs33.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
18758
+ fs34.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
18209
18759
  `);
18210
18760
  } catch {
18211
18761
  }
@@ -18215,7 +18765,7 @@ RAW: ${raw}
18215
18765
  if (shouldSnapshot(toolName, toolInput, config)) {
18216
18766
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
18217
18767
  }
18218
- const safeCwdForAuth = typeof payloadCwd === "string" && path34.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18768
+ const safeCwdForAuth = typeof payloadCwd === "string" && path35.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18219
18769
  const result = await authorizeHeadless(toolName, toolInput, meta, {
18220
18770
  cwd: safeCwdForAuth
18221
18771
  });
@@ -18227,12 +18777,12 @@ RAW: ${raw}
18227
18777
  }
18228
18778
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
18229
18779
  try {
18230
- const tty = fs33.openSync("/dev/tty", "w");
18231
- fs33.writeSync(
18780
+ const tty = fs34.openSync("/dev/tty", "w");
18781
+ fs34.writeSync(
18232
18782
  tty,
18233
18783
  chalk9.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
18234
18784
  );
18235
- fs33.closeSync(tty);
18785
+ fs34.closeSync(tty);
18236
18786
  } catch {
18237
18787
  }
18238
18788
  const daemonReady = await autoStartDaemonAndWait();
@@ -18259,9 +18809,9 @@ RAW: ${raw}
18259
18809
  });
18260
18810
  } catch (err2) {
18261
18811
  if (process.env.NODE9_DEBUG === "1") {
18262
- const logPath = path34.join(os29.homedir(), ".node9", "hook-debug.log");
18812
+ const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18263
18813
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
18264
- fs33.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
18814
+ fs34.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
18265
18815
  `);
18266
18816
  }
18267
18817
  process.exit(0);
@@ -18297,9 +18847,9 @@ RAW: ${raw}
18297
18847
  // src/cli/commands/log.ts
18298
18848
  init_audit();
18299
18849
  init_config();
18300
- import fs34 from "fs";
18301
- import path35 from "path";
18302
- import os30 from "os";
18850
+ import fs35 from "fs";
18851
+ import path36 from "path";
18852
+ import os31 from "os";
18303
18853
  init_daemon();
18304
18854
 
18305
18855
  // src/utils/cp-mv-parser.ts
@@ -18392,10 +18942,10 @@ function registerLogCommand(program2) {
18392
18942
  if (rawToolName !== tool) entry.agentToolName = rawToolName;
18393
18943
  const payloadSessionId = payload.session_id ?? payload.conversationId;
18394
18944
  if (payloadSessionId) entry.sessionId = payloadSessionId;
18395
- const logPath = path35.join(os30.homedir(), ".node9", "audit.log");
18396
- if (!fs34.existsSync(path35.dirname(logPath)))
18397
- fs34.mkdirSync(path35.dirname(logPath), { recursive: true });
18398
- fs34.appendFileSync(logPath, JSON.stringify(entry) + "\n");
18945
+ const logPath = path36.join(os31.homedir(), ".node9", "audit.log");
18946
+ if (!fs35.existsSync(path36.dirname(logPath)))
18947
+ fs35.mkdirSync(path36.dirname(logPath), { recursive: true });
18948
+ fs35.appendFileSync(logPath, JSON.stringify(entry) + "\n");
18399
18949
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
18400
18950
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
18401
18951
  if (command) {
@@ -18429,7 +18979,7 @@ function registerLogCommand(program2) {
18429
18979
  }
18430
18980
  }
18431
18981
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
18432
- const safeCwd = typeof payloadCwd === "string" && path35.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18982
+ const safeCwd = typeof payloadCwd === "string" && path36.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18433
18983
  const config = getConfig(safeCwd);
18434
18984
  if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
18435
18985
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
@@ -18450,9 +19000,9 @@ function registerLogCommand(program2) {
18450
19000
  const msg = err2 instanceof Error ? err2.message : String(err2);
18451
19001
  process.stderr.write(`[Node9] audit log error: ${msg}
18452
19002
  `);
18453
- const debugPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
19003
+ const debugPath = path36.join(os31.homedir(), ".node9", "hook-debug.log");
18454
19004
  try {
18455
- fs34.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
19005
+ fs35.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
18456
19006
  `);
18457
19007
  } catch {
18458
19008
  }
@@ -18854,13 +19404,13 @@ function registerConfigShowCommand(program2) {
18854
19404
  init_daemon();
18855
19405
  init_config();
18856
19406
  import chalk11 from "chalk";
18857
- import fs35 from "fs";
18858
- import path36 from "path";
18859
- import os31 from "os";
19407
+ import fs36 from "fs";
19408
+ import path37 from "path";
19409
+ import os32 from "os";
18860
19410
  import { execSync } from "child_process";
18861
19411
  function registerDoctorCommand(program2, version2) {
18862
19412
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
18863
- const homeDir2 = os31.homedir();
19413
+ const homeDir2 = os32.homedir();
18864
19414
  let failures = 0;
18865
19415
  function pass(msg) {
18866
19416
  console.log(chalk11.green(" \u2705 ") + msg);
@@ -18909,10 +19459,10 @@ function registerDoctorCommand(program2, version2) {
18909
19459
  );
18910
19460
  }
18911
19461
  section("Configuration");
18912
- const globalConfigPath = path36.join(homeDir2, ".node9", "config.json");
18913
- if (fs35.existsSync(globalConfigPath)) {
19462
+ const globalConfigPath = path37.join(homeDir2, ".node9", "config.json");
19463
+ if (fs36.existsSync(globalConfigPath)) {
18914
19464
  try {
18915
- JSON.parse(fs35.readFileSync(globalConfigPath, "utf-8"));
19465
+ JSON.parse(fs36.readFileSync(globalConfigPath, "utf-8"));
18916
19466
  pass("~/.node9/config.json found and valid");
18917
19467
  } catch {
18918
19468
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -18920,10 +19470,10 @@ function registerDoctorCommand(program2, version2) {
18920
19470
  } else {
18921
19471
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
18922
19472
  }
18923
- const projectConfigPath = path36.join(process.cwd(), "node9.config.json");
18924
- if (fs35.existsSync(projectConfigPath)) {
19473
+ const projectConfigPath = path37.join(process.cwd(), "node9.config.json");
19474
+ if (fs36.existsSync(projectConfigPath)) {
18925
19475
  try {
18926
- JSON.parse(fs35.readFileSync(projectConfigPath, "utf-8"));
19476
+ JSON.parse(fs36.readFileSync(projectConfigPath, "utf-8"));
18927
19477
  pass("node9.config.json found and valid (project)");
18928
19478
  } catch {
18929
19479
  fail(
@@ -18932,8 +19482,8 @@ function registerDoctorCommand(program2, version2) {
18932
19482
  );
18933
19483
  }
18934
19484
  }
18935
- const credsPath = path36.join(homeDir2, ".node9", "credentials.json");
18936
- if (fs35.existsSync(credsPath)) {
19485
+ const credsPath = path37.join(homeDir2, ".node9", "credentials.json");
19486
+ if (fs36.existsSync(credsPath)) {
18937
19487
  pass("Cloud credentials found (~/.node9/credentials.json)");
18938
19488
  } else {
18939
19489
  warn(
@@ -18942,10 +19492,10 @@ function registerDoctorCommand(program2, version2) {
18942
19492
  );
18943
19493
  }
18944
19494
  section("Agent Hooks");
18945
- const claudeSettingsPath = path36.join(homeDir2, ".claude", "settings.json");
18946
- if (fs35.existsSync(claudeSettingsPath)) {
19495
+ const claudeSettingsPath = path37.join(homeDir2, ".claude", "settings.json");
19496
+ if (fs36.existsSync(claudeSettingsPath)) {
18947
19497
  try {
18948
- const cs = JSON.parse(fs35.readFileSync(claudeSettingsPath, "utf-8"));
19498
+ const cs = JSON.parse(fs36.readFileSync(claudeSettingsPath, "utf-8"));
18949
19499
  const hasHook = cs.hooks?.PreToolUse?.some(
18950
19500
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
18951
19501
  );
@@ -18961,10 +19511,10 @@ function registerDoctorCommand(program2, version2) {
18961
19511
  } else {
18962
19512
  warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
18963
19513
  }
18964
- const geminiSettingsPath = path36.join(homeDir2, ".gemini", "settings.json");
18965
- if (fs35.existsSync(geminiSettingsPath)) {
19514
+ const geminiSettingsPath = path37.join(homeDir2, ".gemini", "settings.json");
19515
+ if (fs36.existsSync(geminiSettingsPath)) {
18966
19516
  try {
18967
- const gs = JSON.parse(fs35.readFileSync(geminiSettingsPath, "utf-8"));
19517
+ const gs = JSON.parse(fs36.readFileSync(geminiSettingsPath, "utf-8"));
18968
19518
  const hasHook = gs.hooks?.BeforeTool?.some(
18969
19519
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
18970
19520
  );
@@ -18980,10 +19530,10 @@ function registerDoctorCommand(program2, version2) {
18980
19530
  } else {
18981
19531
  warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
18982
19532
  }
18983
- const cursorHooksPath = path36.join(homeDir2, ".cursor", "hooks.json");
18984
- if (fs35.existsSync(cursorHooksPath)) {
19533
+ const cursorHooksPath = path37.join(homeDir2, ".cursor", "hooks.json");
19534
+ if (fs36.existsSync(cursorHooksPath)) {
18985
19535
  try {
18986
- const cur = JSON.parse(fs35.readFileSync(cursorHooksPath, "utf-8"));
19536
+ const cur = JSON.parse(fs36.readFileSync(cursorHooksPath, "utf-8"));
18987
19537
  const hasHook = cur.hooks?.preToolUse?.some(
18988
19538
  (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
18989
19539
  );
@@ -19014,7 +19564,7 @@ function registerDoctorCommand(program2, version2) {
19014
19564
  try {
19015
19565
  const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
19016
19566
  const cfg = getConfig();
19017
- const creds = fs35.existsSync(path36.join(os31.homedir(), ".node9", "credentials.json"));
19567
+ const creds = fs36.existsSync(path37.join(os32.homedir(), ".node9", "credentials.json"));
19018
19568
  if (!creds) {
19019
19569
  warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
19020
19570
  } else if (!cfg.settings.approvers.cloud) {
@@ -19064,9 +19614,9 @@ function registerDoctorCommand(program2, version2) {
19064
19614
 
19065
19615
  // src/cli/commands/audit.ts
19066
19616
  import chalk12 from "chalk";
19067
- import fs36 from "fs";
19068
- import path37 from "path";
19069
- import os32 from "os";
19617
+ import fs37 from "fs";
19618
+ import path38 from "path";
19619
+ import os33 from "os";
19070
19620
  function formatRelativeTime(timestamp) {
19071
19621
  const diff = Date.now() - new Date(timestamp).getTime();
19072
19622
  const sec = Math.floor(diff / 1e3);
@@ -19079,14 +19629,14 @@ function formatRelativeTime(timestamp) {
19079
19629
  }
19080
19630
  function registerAuditCommand(program2) {
19081
19631
  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) => {
19082
- const logPath = path37.join(os32.homedir(), ".node9", "audit.log");
19083
- if (!fs36.existsSync(logPath)) {
19632
+ const logPath = path38.join(os33.homedir(), ".node9", "audit.log");
19633
+ if (!fs37.existsSync(logPath)) {
19084
19634
  console.log(
19085
19635
  chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
19086
19636
  );
19087
19637
  return;
19088
19638
  }
19089
- const raw = fs36.readFileSync(logPath, "utf-8");
19639
+ const raw = fs37.readFileSync(logPath, "utf-8");
19090
19640
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
19091
19641
  let entries = lines.flatMap((line) => {
19092
19642
  try {
@@ -19144,9 +19694,9 @@ import chalk13 from "chalk";
19144
19694
  // src/cli/aggregate/report-audit.ts
19145
19695
  init_costSync();
19146
19696
  init_litellm();
19147
- import fs37 from "fs";
19148
- import os33 from "os";
19149
- import path38 from "path";
19697
+ import fs38 from "fs";
19698
+ import os34 from "os";
19699
+ import path39 from "path";
19150
19700
  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;
19151
19701
  function buildTestTimestamps(allEntries) {
19152
19702
  const testTs = /* @__PURE__ */ new Set();
@@ -19226,8 +19776,8 @@ function getDateRange(period, now) {
19226
19776
  }
19227
19777
  }
19228
19778
  function parseAuditLog(logPath) {
19229
- if (!fs37.existsSync(logPath)) return [];
19230
- const raw = fs37.readFileSync(logPath, "utf-8");
19779
+ if (!fs38.existsSync(logPath)) return [];
19780
+ const raw = fs38.readFileSync(logPath, "utf-8");
19231
19781
  return raw.split("\n").flatMap((line) => {
19232
19782
  if (!line.trim()) return [];
19233
19783
  try {
@@ -19287,25 +19837,25 @@ function freezeClaudeCost(acc) {
19287
19837
  };
19288
19838
  }
19289
19839
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
19290
- const projPath = path38.join(projectsDir, proj);
19840
+ const projPath = path39.join(projectsDir, proj);
19291
19841
  let files;
19292
19842
  try {
19293
- const stat = fs37.statSync(projPath);
19843
+ const stat = fs38.statSync(projPath);
19294
19844
  if (!stat.isDirectory()) return;
19295
- files = fs37.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
19845
+ files = fs38.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
19296
19846
  } catch {
19297
19847
  return;
19298
19848
  }
19299
19849
  const startMs = start.getTime();
19300
19850
  for (const file of files) {
19301
- const filePath = path38.join(projPath, file);
19851
+ const filePath = path39.join(projPath, file);
19302
19852
  try {
19303
- if (fs37.statSync(filePath).mtimeMs < startMs) continue;
19853
+ if (fs38.statSync(filePath).mtimeMs < startMs) continue;
19304
19854
  } catch {
19305
19855
  continue;
19306
19856
  }
19307
19857
  try {
19308
- const raw = fs37.readFileSync(filePath, "utf-8");
19858
+ const raw = fs38.readFileSync(filePath, "utf-8");
19309
19859
  for (const line of raw.split("\n")) {
19310
19860
  if (!line.trim()) continue;
19311
19861
  let entry;
@@ -19355,10 +19905,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
19355
19905
  }
19356
19906
  function loadClaudeCost(start, end, projectsDir) {
19357
19907
  const acc = emptyClaudeCostAccumulator();
19358
- if (!fs37.existsSync(projectsDir)) return freezeClaudeCost(acc);
19908
+ if (!fs38.existsSync(projectsDir)) return freezeClaudeCost(acc);
19359
19909
  let dirs;
19360
19910
  try {
19361
- dirs = fs37.readdirSync(projectsDir);
19911
+ dirs = fs38.readdirSync(projectsDir);
19362
19912
  } catch {
19363
19913
  return freezeClaudeCost(acc);
19364
19914
  }
@@ -19370,7 +19920,7 @@ function loadClaudeCost(start, end, projectsDir) {
19370
19920
  function processCodexCostFile(filePath, start, end, acc) {
19371
19921
  let lines;
19372
19922
  try {
19373
- lines = fs37.readFileSync(filePath, "utf-8").split("\n");
19923
+ lines = fs38.readFileSync(filePath, "utf-8").split("\n");
19374
19924
  } catch {
19375
19925
  return;
19376
19926
  }
@@ -19415,31 +19965,31 @@ function processCodexCostFile(filePath, start, end, acc) {
19415
19965
  }
19416
19966
  function listCodexSessionFiles(sessionsBase) {
19417
19967
  const jsonlFiles = [];
19418
- if (!fs37.existsSync(sessionsBase)) return jsonlFiles;
19968
+ if (!fs38.existsSync(sessionsBase)) return jsonlFiles;
19419
19969
  try {
19420
- for (const year of fs37.readdirSync(sessionsBase)) {
19421
- const yearPath = path38.join(sessionsBase, year);
19970
+ for (const year of fs38.readdirSync(sessionsBase)) {
19971
+ const yearPath = path39.join(sessionsBase, year);
19422
19972
  try {
19423
- if (!fs37.statSync(yearPath).isDirectory()) continue;
19973
+ if (!fs38.statSync(yearPath).isDirectory()) continue;
19424
19974
  } catch {
19425
19975
  continue;
19426
19976
  }
19427
- for (const month of fs37.readdirSync(yearPath)) {
19428
- const monthPath = path38.join(yearPath, month);
19977
+ for (const month of fs38.readdirSync(yearPath)) {
19978
+ const monthPath = path39.join(yearPath, month);
19429
19979
  try {
19430
- if (!fs37.statSync(monthPath).isDirectory()) continue;
19980
+ if (!fs38.statSync(monthPath).isDirectory()) continue;
19431
19981
  } catch {
19432
19982
  continue;
19433
19983
  }
19434
- for (const day of fs37.readdirSync(monthPath)) {
19435
- const dayPath = path38.join(monthPath, day);
19984
+ for (const day of fs38.readdirSync(monthPath)) {
19985
+ const dayPath = path39.join(monthPath, day);
19436
19986
  try {
19437
- if (!fs37.statSync(dayPath).isDirectory()) continue;
19987
+ if (!fs38.statSync(dayPath).isDirectory()) continue;
19438
19988
  } catch {
19439
19989
  continue;
19440
19990
  }
19441
- for (const file of fs37.readdirSync(dayPath)) {
19442
- if (file.endsWith(".jsonl")) jsonlFiles.push(path38.join(dayPath, file));
19991
+ for (const file of fs38.readdirSync(dayPath)) {
19992
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path39.join(dayPath, file));
19443
19993
  }
19444
19994
  }
19445
19995
  }
@@ -19492,13 +20042,13 @@ function freezeGeminiCost(acc) {
19492
20042
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
19493
20043
  const startMs = start.getTime();
19494
20044
  try {
19495
- if (fs37.statSync(filePath).mtimeMs < startMs) return;
20045
+ if (fs38.statSync(filePath).mtimeMs < startMs) return;
19496
20046
  } catch {
19497
20047
  return;
19498
20048
  }
19499
20049
  let raw;
19500
20050
  try {
19501
- raw = fs37.readFileSync(filePath, "utf-8");
20051
+ raw = fs38.readFileSync(filePath, "utf-8");
19502
20052
  } catch {
19503
20053
  return;
19504
20054
  }
@@ -19547,30 +20097,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
19547
20097
  const out = [];
19548
20098
  let dirs;
19549
20099
  try {
19550
- if (!fs37.statSync(geminiTmpDir).isDirectory()) return out;
19551
- dirs = fs37.readdirSync(geminiTmpDir);
20100
+ if (!fs38.statSync(geminiTmpDir).isDirectory()) return out;
20101
+ dirs = fs38.readdirSync(geminiTmpDir);
19552
20102
  } catch {
19553
20103
  return out;
19554
20104
  }
19555
20105
  for (const proj of dirs) {
19556
- const chatsDir = path38.join(geminiTmpDir, proj, "chats");
20106
+ const chatsDir = path39.join(geminiTmpDir, proj, "chats");
19557
20107
  let files;
19558
20108
  try {
19559
- if (!fs37.statSync(chatsDir).isDirectory()) continue;
19560
- files = fs37.readdirSync(chatsDir);
20109
+ if (!fs38.statSync(chatsDir).isDirectory()) continue;
20110
+ files = fs38.readdirSync(chatsDir);
19561
20111
  } catch {
19562
20112
  continue;
19563
20113
  }
19564
20114
  for (const f of files) {
19565
20115
  if (!f.endsWith(".jsonl")) continue;
19566
- out.push({ projectKey: proj, file: path38.join(chatsDir, f) });
20116
+ out.push({ projectKey: proj, file: path39.join(chatsDir, f) });
19567
20117
  }
19568
20118
  }
19569
20119
  return out;
19570
20120
  }
19571
20121
  function loadGeminiCost(start, end, geminiTmpDir) {
19572
20122
  const acc = emptyGeminiAccumulator();
19573
- if (!fs37.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
20123
+ if (!fs38.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
19574
20124
  for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
19575
20125
  processGeminiCostFile(file, projectKey, start, end, acc);
19576
20126
  }
@@ -19578,11 +20128,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
19578
20128
  }
19579
20129
  function aggregateReportFromAudit(period, opts = {}) {
19580
20130
  const now = opts.now ?? /* @__PURE__ */ new Date();
19581
- const auditLogPath = opts.auditLogPath ?? path38.join(os33.homedir(), ".node9", "audit.log");
19582
- const claudeProjectsDir = opts.claudeProjectsDir ?? path38.join(os33.homedir(), ".claude", "projects");
19583
- const codexSessionsDir = opts.codexSessionsDir ?? path38.join(os33.homedir(), ".codex", "sessions");
19584
- const geminiTmpDir = opts.geminiTmpDir ?? path38.join(os33.homedir(), ".gemini", "tmp");
19585
- const hasAuditFile = fs37.existsSync(auditLogPath);
20131
+ const auditLogPath = opts.auditLogPath ?? path39.join(os34.homedir(), ".node9", "audit.log");
20132
+ const claudeProjectsDir = opts.claudeProjectsDir ?? path39.join(os34.homedir(), ".claude", "projects");
20133
+ const codexSessionsDir = opts.codexSessionsDir ?? path39.join(os34.homedir(), ".codex", "sessions");
20134
+ const geminiTmpDir = opts.geminiTmpDir ?? path39.join(os34.homedir(), ".gemini", "tmp");
20135
+ const hasAuditFile = fs38.existsSync(auditLogPath);
19586
20136
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
19587
20137
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
19588
20138
  const { start, end } = getDateRange(period, now);
@@ -20280,12 +20830,12 @@ function registerDaemonCommand(program2) {
20280
20830
  init_core();
20281
20831
  init_daemon();
20282
20832
  import chalk15 from "chalk";
20283
- import fs38 from "fs";
20284
- import path39 from "path";
20285
- import os34 from "os";
20833
+ import fs39 from "fs";
20834
+ import path40 from "path";
20835
+ import os35 from "os";
20286
20836
  function readJson2(filePath) {
20287
20837
  try {
20288
- if (fs38.existsSync(filePath)) return JSON.parse(fs38.readFileSync(filePath, "utf-8"));
20838
+ if (fs39.existsSync(filePath)) return JSON.parse(fs39.readFileSync(filePath, "utf-8"));
20289
20839
  } catch {
20290
20840
  }
20291
20841
  return null;
@@ -20350,28 +20900,28 @@ function registerStatusCommand(program2) {
20350
20900
  console.log("");
20351
20901
  const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
20352
20902
  console.log(` Mode: ${modeLabel}`);
20353
- const projectConfig = path39.join(process.cwd(), "node9.config.json");
20354
- const globalConfig = path39.join(os34.homedir(), ".node9", "config.json");
20903
+ const projectConfig = path40.join(process.cwd(), "node9.config.json");
20904
+ const globalConfig = path40.join(os35.homedir(), ".node9", "config.json");
20355
20905
  console.log(
20356
- ` Local: ${fs38.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
20906
+ ` Local: ${fs39.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
20357
20907
  );
20358
20908
  console.log(
20359
- ` Global: ${fs38.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
20909
+ ` Global: ${fs39.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
20360
20910
  );
20361
20911
  if (mergedConfig.policy.sandboxPaths.length > 0) {
20362
20912
  console.log(
20363
20913
  ` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
20364
20914
  );
20365
20915
  }
20366
- const homeDir2 = os34.homedir();
20916
+ const homeDir2 = os35.homedir();
20367
20917
  const claudeSettings = readJson2(
20368
- path39.join(homeDir2, ".claude", "settings.json")
20918
+ path40.join(homeDir2, ".claude", "settings.json")
20369
20919
  );
20370
- const claudeConfig = readJson2(path39.join(homeDir2, ".claude.json"));
20920
+ const claudeConfig = readJson2(path40.join(homeDir2, ".claude.json"));
20371
20921
  const geminiSettings = readJson2(
20372
- path39.join(homeDir2, ".gemini", "settings.json")
20922
+ path40.join(homeDir2, ".gemini", "settings.json")
20373
20923
  );
20374
- const cursorConfig = readJson2(path39.join(homeDir2, ".cursor", "mcp.json"));
20924
+ const cursorConfig = readJson2(path40.join(homeDir2, ".cursor", "mcp.json"));
20375
20925
  const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
20376
20926
  if (agentFound) {
20377
20927
  console.log("");
@@ -20434,9 +20984,9 @@ init_setup();
20434
20984
  init_shields();
20435
20985
  init_service();
20436
20986
  import chalk16 from "chalk";
20437
- import fs39 from "fs";
20438
- import path40 from "path";
20439
- import os35 from "os";
20987
+ import fs40 from "fs";
20988
+ import path41 from "path";
20989
+ import os36 from "os";
20440
20990
  import https4 from "https";
20441
20991
  var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
20442
20992
  function buildTelemetryPayload(agents, firstInstall) {
@@ -20522,16 +21072,16 @@ function registerInitCommand(program2) {
20522
21072
  }
20523
21073
  console.log("");
20524
21074
  }
20525
- const configPath = path40.join(os35.homedir(), ".node9", "config.json");
20526
- const isFirstInstall = !fs39.existsSync(configPath);
20527
- if (fs39.existsSync(configPath) && !options.force) {
21075
+ const configPath = path41.join(os36.homedir(), ".node9", "config.json");
21076
+ const isFirstInstall = !fs40.existsSync(configPath);
21077
+ if (fs40.existsSync(configPath) && !options.force) {
20528
21078
  try {
20529
- const existing = JSON.parse(fs39.readFileSync(configPath, "utf-8"));
21079
+ const existing = JSON.parse(fs40.readFileSync(configPath, "utf-8"));
20530
21080
  const settings = existing.settings ?? {};
20531
21081
  if (settings.mode !== chosenMode) {
20532
21082
  settings.mode = chosenMode;
20533
21083
  existing.settings = settings;
20534
- fs39.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
21084
+ fs40.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
20535
21085
  console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
20536
21086
  } else {
20537
21087
  console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -20544,9 +21094,9 @@ function registerInitCommand(program2) {
20544
21094
  ...DEFAULT_CONFIG,
20545
21095
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
20546
21096
  };
20547
- const dir = path40.dirname(configPath);
20548
- if (!fs39.existsSync(dir)) fs39.mkdirSync(dir, { recursive: true });
20549
- fs39.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
21097
+ const dir = path41.dirname(configPath);
21098
+ if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
21099
+ fs40.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
20550
21100
  console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
20551
21101
  console.log(chalk16.gray(` Mode: ${chosenMode}`));
20552
21102
  }
@@ -20651,7 +21201,7 @@ function registerInitCommand(program2) {
20651
21201
  }
20652
21202
 
20653
21203
  // src/cli/commands/undo.ts
20654
- import path41 from "path";
21204
+ import path42 from "path";
20655
21205
  import chalk18 from "chalk";
20656
21206
 
20657
21207
  // src/tui/undo-navigator.ts
@@ -20810,7 +21360,7 @@ function findMatchingCwd(startDir, history) {
20810
21360
  let dir = startDir;
20811
21361
  while (true) {
20812
21362
  if (cwds.has(dir)) return dir;
20813
- const parent = path41.dirname(dir);
21363
+ const parent = path42.dirname(dir);
20814
21364
  if (parent === dir) return null;
20815
21365
  dir = parent;
20816
21366
  }
@@ -21386,9 +21936,9 @@ function registerMcpGatewayCommand(program2) {
21386
21936
 
21387
21937
  // src/mcp-server/index.ts
21388
21938
  import readline5 from "readline";
21389
- import fs40 from "fs";
21390
- import os36 from "os";
21391
- import path42 from "path";
21939
+ import fs41 from "fs";
21940
+ import os37 from "os";
21941
+ import path43 from "path";
21392
21942
  import { spawnSync as spawnSync4 } from "child_process";
21393
21943
  init_core();
21394
21944
  init_daemon();
@@ -21639,13 +22189,13 @@ function handleStatus() {
21639
22189
  lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
21640
22190
  lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
21641
22191
  lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
21642
- const projectConfig = path42.join(process.cwd(), "node9.config.json");
21643
- const globalConfig = path42.join(os36.homedir(), ".node9", "config.json");
22192
+ const projectConfig = path43.join(process.cwd(), "node9.config.json");
22193
+ const globalConfig = path43.join(os37.homedir(), ".node9", "config.json");
21644
22194
  lines.push(
21645
- `Project config (node9.config.json): ${fs40.existsSync(projectConfig) ? "present" : "not found"}`
22195
+ `Project config (node9.config.json): ${fs41.existsSync(projectConfig) ? "present" : "not found"}`
21646
22196
  );
21647
22197
  lines.push(
21648
- `Global config (~/.node9/config.json): ${fs40.existsSync(globalConfig) ? "present" : "not found"}`
22198
+ `Global config (~/.node9/config.json): ${fs41.existsSync(globalConfig) ? "present" : "not found"}`
21649
22199
  );
21650
22200
  return lines.join("\n");
21651
22201
  }
@@ -21719,21 +22269,21 @@ function handleShieldDisable(args) {
21719
22269
  writeActiveShields(active.filter((s) => s !== name));
21720
22270
  return `Shield "${name}" disabled.`;
21721
22271
  }
21722
- var GLOBAL_CONFIG_PATH = path42.join(os36.homedir(), ".node9", "config.json");
22272
+ var GLOBAL_CONFIG_PATH = path43.join(os37.homedir(), ".node9", "config.json");
21723
22273
  var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
21724
22274
  function readGlobalConfigRaw() {
21725
22275
  try {
21726
- if (fs40.existsSync(GLOBAL_CONFIG_PATH)) {
21727
- return JSON.parse(fs40.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
22276
+ if (fs41.existsSync(GLOBAL_CONFIG_PATH)) {
22277
+ return JSON.parse(fs41.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
21728
22278
  }
21729
22279
  } catch {
21730
22280
  }
21731
22281
  return {};
21732
22282
  }
21733
22283
  function writeGlobalConfigRaw(data) {
21734
- const dir = path42.dirname(GLOBAL_CONFIG_PATH);
21735
- if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
21736
- fs40.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
22284
+ const dir = path43.dirname(GLOBAL_CONFIG_PATH);
22285
+ if (!fs41.existsSync(dir)) fs41.mkdirSync(dir, { recursive: true });
22286
+ fs41.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
21737
22287
  }
21738
22288
  function handleApproverList() {
21739
22289
  const config = getConfig();
@@ -21777,9 +22327,9 @@ function handleApproverSet(args) {
21777
22327
  function handleAuditGet(args) {
21778
22328
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
21779
22329
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
21780
- const auditPath = path42.join(os36.homedir(), ".node9", "audit.log");
21781
- if (!fs40.existsSync(auditPath)) return "No audit log found.";
21782
- const rawLines = fs40.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
22330
+ const auditPath = path43.join(os37.homedir(), ".node9", "audit.log");
22331
+ if (!fs41.existsSync(auditPath)) return "No audit log found.";
22332
+ const rawLines = fs41.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
21783
22333
  const parsed = [];
21784
22334
  for (const line of rawLines) {
21785
22335
  try {
@@ -22114,7 +22664,7 @@ function registerTrustCommand(program2) {
22114
22664
  // src/cli/commands/mcp-pin.ts
22115
22665
  init_mcp_pin();
22116
22666
  import chalk21 from "chalk";
22117
- import fs41 from "fs";
22667
+ import fs42 from "fs";
22118
22668
  function registerMcpPinCommand(program2) {
22119
22669
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
22120
22670
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
@@ -22125,7 +22675,7 @@ function registerMcpPinCommand(program2) {
22125
22675
  let repoCorrupt = false;
22126
22676
  if (found.source === "repo") {
22127
22677
  try {
22128
- const raw = fs41.readFileSync(found.path, "utf-8");
22678
+ const raw = fs42.readFileSync(found.path, "utf-8");
22129
22679
  const parsed = JSON.parse(raw);
22130
22680
  repoEntries = parsed.servers ?? {};
22131
22681
  } catch {
@@ -22439,9 +22989,9 @@ init_scan();
22439
22989
  // src/cli/commands/sessions.ts
22440
22990
  init_scan_summary();
22441
22991
  import chalk24 from "chalk";
22442
- import fs42 from "fs";
22443
- import path43 from "path";
22444
- import os37 from "os";
22992
+ import fs43 from "fs";
22993
+ import path44 from "path";
22994
+ import os38 from "os";
22445
22995
  var CLAUDE_PRICING3 = {
22446
22996
  "claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
22447
22997
  "claude-opus-4-5": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
@@ -22482,10 +23032,10 @@ function encodeProjectPath(projectPath) {
22482
23032
  }
22483
23033
  function sessionJsonlPath(projectPath, sessionId) {
22484
23034
  const encoded = encodeProjectPath(projectPath);
22485
- return path43.join(os37.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
23035
+ return path44.join(os38.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
22486
23036
  }
22487
23037
  function projectLabel(projectPath) {
22488
- return projectPath.replace(os37.homedir(), "~");
23038
+ return projectPath.replace(os38.homedir(), "~");
22489
23039
  }
22490
23040
  function parseHistoryLines(lines) {
22491
23041
  const entries = [];
@@ -22554,10 +23104,10 @@ function parseSessionLines(lines) {
22554
23104
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
22555
23105
  }
22556
23106
  function loadAuditEntries(auditPath) {
22557
- const aPath = auditPath ?? path43.join(os37.homedir(), ".node9", "audit.log");
23107
+ const aPath = auditPath ?? path44.join(os38.homedir(), ".node9", "audit.log");
22558
23108
  let raw;
22559
23109
  try {
22560
- raw = fs42.readFileSync(aPath, "utf-8");
23110
+ raw = fs43.readFileSync(aPath, "utf-8");
22561
23111
  } catch {
22562
23112
  return [];
22563
23113
  }
@@ -22593,8 +23143,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
22593
23143
  return result;
22594
23144
  }
22595
23145
  function buildGeminiSessions(days, allAuditEntries) {
22596
- const tmpDir = path43.join(os37.homedir(), ".gemini", "tmp");
22597
- if (!fs42.existsSync(tmpDir)) return [];
23146
+ const tmpDir = path44.join(os38.homedir(), ".gemini", "tmp");
23147
+ if (!fs43.existsSync(tmpDir)) return [];
22598
23148
  const cutoff = days !== null ? (() => {
22599
23149
  const d = /* @__PURE__ */ new Date();
22600
23150
  d.setDate(d.getDate() - days);
@@ -22603,35 +23153,35 @@ function buildGeminiSessions(days, allAuditEntries) {
22603
23153
  })() : null;
22604
23154
  let slugDirs;
22605
23155
  try {
22606
- slugDirs = fs42.readdirSync(tmpDir);
23156
+ slugDirs = fs43.readdirSync(tmpDir);
22607
23157
  } catch {
22608
23158
  return [];
22609
23159
  }
22610
23160
  const summaries = [];
22611
23161
  for (const slug of slugDirs) {
22612
- const slugPath = path43.join(tmpDir, slug);
23162
+ const slugPath = path44.join(tmpDir, slug);
22613
23163
  try {
22614
- if (!fs42.statSync(slugPath).isDirectory()) continue;
23164
+ if (!fs43.statSync(slugPath).isDirectory()) continue;
22615
23165
  } catch {
22616
23166
  continue;
22617
23167
  }
22618
- let projectRoot = path43.join(os37.homedir(), slug);
23168
+ let projectRoot = path44.join(os38.homedir(), slug);
22619
23169
  try {
22620
- projectRoot = fs42.readFileSync(path43.join(slugPath, ".project_root"), "utf-8").trim();
23170
+ projectRoot = fs43.readFileSync(path44.join(slugPath, ".project_root"), "utf-8").trim();
22621
23171
  } catch {
22622
23172
  }
22623
- const chatsDir = path43.join(slugPath, "chats");
22624
- if (!fs42.existsSync(chatsDir)) continue;
23173
+ const chatsDir = path44.join(slugPath, "chats");
23174
+ if (!fs43.existsSync(chatsDir)) continue;
22625
23175
  let chatFiles;
22626
23176
  try {
22627
- chatFiles = fs42.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
23177
+ chatFiles = fs43.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
22628
23178
  } catch {
22629
23179
  continue;
22630
23180
  }
22631
23181
  for (const chatFile of chatFiles) {
22632
23182
  let raw;
22633
23183
  try {
22634
- raw = fs42.readFileSync(path43.join(chatsDir, chatFile), "utf-8");
23184
+ raw = fs43.readFileSync(path44.join(chatsDir, chatFile), "utf-8");
22635
23185
  } catch {
22636
23186
  continue;
22637
23187
  }
@@ -22711,8 +23261,8 @@ function buildGeminiSessions(days, allAuditEntries) {
22711
23261
  return summaries;
22712
23262
  }
22713
23263
  function buildCodexSessions(days, allAuditEntries) {
22714
- const sessionsBase = path43.join(os37.homedir(), ".codex", "sessions");
22715
- if (!fs42.existsSync(sessionsBase)) return [];
23264
+ const sessionsBase = path44.join(os38.homedir(), ".codex", "sessions");
23265
+ if (!fs43.existsSync(sessionsBase)) return [];
22716
23266
  const cutoff = days !== null ? (() => {
22717
23267
  const d = /* @__PURE__ */ new Date();
22718
23268
  d.setDate(d.getDate() - days);
@@ -22721,29 +23271,29 @@ function buildCodexSessions(days, allAuditEntries) {
22721
23271
  })() : null;
22722
23272
  const jsonlFiles = [];
22723
23273
  try {
22724
- for (const year of fs42.readdirSync(sessionsBase)) {
22725
- const yearPath = path43.join(sessionsBase, year);
23274
+ for (const year of fs43.readdirSync(sessionsBase)) {
23275
+ const yearPath = path44.join(sessionsBase, year);
22726
23276
  try {
22727
- if (!fs42.statSync(yearPath).isDirectory()) continue;
23277
+ if (!fs43.statSync(yearPath).isDirectory()) continue;
22728
23278
  } catch {
22729
23279
  continue;
22730
23280
  }
22731
- for (const month of fs42.readdirSync(yearPath)) {
22732
- const monthPath = path43.join(yearPath, month);
23281
+ for (const month of fs43.readdirSync(yearPath)) {
23282
+ const monthPath = path44.join(yearPath, month);
22733
23283
  try {
22734
- if (!fs42.statSync(monthPath).isDirectory()) continue;
23284
+ if (!fs43.statSync(monthPath).isDirectory()) continue;
22735
23285
  } catch {
22736
23286
  continue;
22737
23287
  }
22738
- for (const day of fs42.readdirSync(monthPath)) {
22739
- const dayPath = path43.join(monthPath, day);
23288
+ for (const day of fs43.readdirSync(monthPath)) {
23289
+ const dayPath = path44.join(monthPath, day);
22740
23290
  try {
22741
- if (!fs42.statSync(dayPath).isDirectory()) continue;
23291
+ if (!fs43.statSync(dayPath).isDirectory()) continue;
22742
23292
  } catch {
22743
23293
  continue;
22744
23294
  }
22745
- for (const file of fs42.readdirSync(dayPath)) {
22746
- if (file.endsWith(".jsonl")) jsonlFiles.push(path43.join(dayPath, file));
23295
+ for (const file of fs43.readdirSync(dayPath)) {
23296
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path44.join(dayPath, file));
22747
23297
  }
22748
23298
  }
22749
23299
  }
@@ -22755,7 +23305,7 @@ function buildCodexSessions(days, allAuditEntries) {
22755
23305
  for (const filePath of jsonlFiles) {
22756
23306
  let lines;
22757
23307
  try {
22758
- lines = fs42.readFileSync(filePath, "utf-8").split("\n");
23308
+ lines = fs43.readFileSync(filePath, "utf-8").split("\n");
22759
23309
  } catch {
22760
23310
  continue;
22761
23311
  }
@@ -22833,10 +23383,10 @@ function buildCodexSessions(days, allAuditEntries) {
22833
23383
  return summaries;
22834
23384
  }
22835
23385
  function buildSessions(days, historyPath) {
22836
- const hPath = historyPath ?? path43.join(os37.homedir(), ".claude", "history.jsonl");
23386
+ const hPath = historyPath ?? path44.join(os38.homedir(), ".claude", "history.jsonl");
22837
23387
  let historyRaw;
22838
23388
  try {
22839
- historyRaw = fs42.readFileSync(hPath, "utf-8");
23389
+ historyRaw = fs43.readFileSync(hPath, "utf-8");
22840
23390
  } catch {
22841
23391
  return [];
22842
23392
  }
@@ -22861,7 +23411,7 @@ function buildSessions(days, historyPath) {
22861
23411
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
22862
23412
  let sessionLines = [];
22863
23413
  try {
22864
- sessionLines = fs42.readFileSync(jsonlFile, "utf-8").split("\n");
23414
+ sessionLines = fs43.readFileSync(jsonlFile, "utf-8").split("\n");
22865
23415
  } catch {
22866
23416
  }
22867
23417
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -23129,8 +23679,8 @@ function registerSessionsCommand(program2) {
23129
23679
  console.log("");
23130
23680
  console.log(chalk24.cyan.bold("\u{1F4CB} node9 sessions") + chalk24.dim(" \u2014 what your AI agent did"));
23131
23681
  console.log("");
23132
- const historyPath = path43.join(os37.homedir(), ".claude", "history.jsonl");
23133
- if (!fs42.existsSync(historyPath)) {
23682
+ const historyPath = path44.join(os38.homedir(), ".claude", "history.jsonl");
23683
+ if (!fs43.existsSync(historyPath)) {
23134
23684
  console.log(chalk24.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
23135
23685
  console.log(chalk24.gray(" Install Claude Code, run a few sessions, then try again.\n"));
23136
23686
  return;
@@ -23167,12 +23717,12 @@ function registerSessionsCommand(program2) {
23167
23717
 
23168
23718
  // src/cli/commands/skill-pin.ts
23169
23719
  import chalk25 from "chalk";
23170
- import fs43 from "fs";
23171
- import os38 from "os";
23172
- import path44 from "path";
23720
+ import fs44 from "fs";
23721
+ import os39 from "os";
23722
+ import path45 from "path";
23173
23723
  function wipeSkillSessions() {
23174
23724
  try {
23175
- fs43.rmSync(path44.join(os38.homedir(), ".node9", "skill-sessions"), {
23725
+ fs44.rmSync(path45.join(os39.homedir(), ".node9", "skill-sessions"), {
23176
23726
  recursive: true,
23177
23727
  force: true
23178
23728
  });
@@ -23254,15 +23804,15 @@ function registerSkillPinCommand(program2) {
23254
23804
  }
23255
23805
 
23256
23806
  // src/cli/commands/decisions.ts
23257
- import fs44 from "fs";
23258
- import os39 from "os";
23259
- import path45 from "path";
23807
+ import fs45 from "fs";
23808
+ import os40 from "os";
23809
+ import path46 from "path";
23260
23810
  import chalk26 from "chalk";
23261
- var DECISIONS_FILE2 = path45.join(os39.homedir(), ".node9", "decisions.json");
23811
+ var DECISIONS_FILE2 = path46.join(os40.homedir(), ".node9", "decisions.json");
23262
23812
  function readDecisions() {
23263
23813
  try {
23264
- if (!fs44.existsSync(DECISIONS_FILE2)) return {};
23265
- const raw = fs44.readFileSync(DECISIONS_FILE2, "utf-8");
23814
+ if (!fs45.existsSync(DECISIONS_FILE2)) return {};
23815
+ const raw = fs45.readFileSync(DECISIONS_FILE2, "utf-8");
23266
23816
  const parsed = JSON.parse(raw);
23267
23817
  const out = {};
23268
23818
  for (const [k, v] of Object.entries(parsed)) {
@@ -23274,11 +23824,11 @@ function readDecisions() {
23274
23824
  }
23275
23825
  }
23276
23826
  function writeDecisions(d) {
23277
- const dir = path45.dirname(DECISIONS_FILE2);
23278
- if (!fs44.existsSync(dir)) fs44.mkdirSync(dir, { recursive: true });
23827
+ const dir = path46.dirname(DECISIONS_FILE2);
23828
+ if (!fs45.existsSync(dir)) fs45.mkdirSync(dir, { recursive: true });
23279
23829
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
23280
- fs44.writeFileSync(tmp, JSON.stringify(d, null, 2));
23281
- fs44.renameSync(tmp, DECISIONS_FILE2);
23830
+ fs45.writeFileSync(tmp, JSON.stringify(d, null, 2));
23831
+ fs45.renameSync(tmp, DECISIONS_FILE2);
23282
23832
  }
23283
23833
  function registerDecisionsCommand(program2) {
23284
23834
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -23335,18 +23885,18 @@ Persistent decisions (${entries.length})
23335
23885
 
23336
23886
  // src/cli/commands/dlp.ts
23337
23887
  import chalk27 from "chalk";
23338
- import fs45 from "fs";
23339
- import path46 from "path";
23340
- import os40 from "os";
23341
- var AUDIT_LOG = path46.join(os40.homedir(), ".node9", "audit.log");
23342
- var RESOLVED_FILE = path46.join(os40.homedir(), ".node9", "dlp-resolved.json");
23888
+ import fs46 from "fs";
23889
+ import path47 from "path";
23890
+ import os41 from "os";
23891
+ var AUDIT_LOG = path47.join(os41.homedir(), ".node9", "audit.log");
23892
+ var RESOLVED_FILE = path47.join(os41.homedir(), ".node9", "dlp-resolved.json");
23343
23893
  var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
23344
23894
  function stripAnsi(s) {
23345
23895
  return s.replace(ANSI_RE, "");
23346
23896
  }
23347
23897
  function loadResolved() {
23348
23898
  try {
23349
- const raw = JSON.parse(fs45.readFileSync(RESOLVED_FILE, "utf-8"));
23899
+ const raw = JSON.parse(fs46.readFileSync(RESOLVED_FILE, "utf-8"));
23350
23900
  return new Set(raw);
23351
23901
  } catch {
23352
23902
  return /* @__PURE__ */ new Set();
@@ -23354,13 +23904,13 @@ function loadResolved() {
23354
23904
  }
23355
23905
  function saveResolved(resolved) {
23356
23906
  try {
23357
- fs45.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
23907
+ fs46.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
23358
23908
  } catch {
23359
23909
  }
23360
23910
  }
23361
23911
  function loadDlpFindings() {
23362
- if (!fs45.existsSync(AUDIT_LOG)) return [];
23363
- return fs45.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
23912
+ if (!fs46.existsSync(AUDIT_LOG)) return [];
23913
+ return fs46.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
23364
23914
  if (!line.trim()) return [];
23365
23915
  try {
23366
23916
  const e = JSON.parse(line);
@@ -23370,7 +23920,7 @@ function loadDlpFindings() {
23370
23920
  }
23371
23921
  });
23372
23922
  }
23373
- function entryKey(e) {
23923
+ function entryKey2(e) {
23374
23924
  return `${e.ts}:${e.dlpPattern}:${e.dlpSample}`;
23375
23925
  }
23376
23926
  function fmtDate3(ts) {
@@ -23393,7 +23943,7 @@ function registerDlpCommand(program2) {
23393
23943
  return;
23394
23944
  }
23395
23945
  const resolved = loadResolved();
23396
- for (const e of findings) resolved.add(entryKey(e));
23946
+ for (const e of findings) resolved.add(entryKey2(e));
23397
23947
  saveResolved(resolved);
23398
23948
  console.log(
23399
23949
  chalk27.green(
@@ -23406,7 +23956,7 @@ function registerDlpCommand(program2) {
23406
23956
  cmd.action(() => {
23407
23957
  const findings = loadDlpFindings();
23408
23958
  const resolved = loadResolved();
23409
- const open = findings.filter((e) => !resolved.has(entryKey(e)));
23959
+ const open = findings.filter((e) => !resolved.has(entryKey2(e)));
23410
23960
  const resolvedCount = findings.length - open.length;
23411
23961
  console.log("");
23412
23962
  console.log(
@@ -23459,14 +24009,14 @@ function registerDlpCommand(program2) {
23459
24009
  // src/cli/commands/mask.ts
23460
24010
  init_dlp();
23461
24011
  import chalk28 from "chalk";
23462
- import fs46 from "fs";
23463
- import path47 from "path";
23464
- import os41 from "os";
24012
+ import fs47 from "fs";
24013
+ import path48 from "path";
24014
+ import os42 from "os";
23465
24015
  function findJsonlFiles(dir) {
23466
24016
  const results = [];
23467
- if (!fs46.existsSync(dir)) return results;
23468
- for (const entry of fs46.readdirSync(dir, { withFileTypes: true })) {
23469
- const full = path47.join(dir, entry.name);
24017
+ if (!fs47.existsSync(dir)) return results;
24018
+ for (const entry of fs47.readdirSync(dir, { withFileTypes: true })) {
24019
+ const full = path48.join(dir, entry.name);
23470
24020
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
23471
24021
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
23472
24022
  }
@@ -23509,7 +24059,7 @@ function redactJson(obj) {
23509
24059
  function processFile(filePath, dryRun) {
23510
24060
  let raw;
23511
24061
  try {
23512
- raw = fs46.readFileSync(filePath, "utf-8");
24062
+ raw = fs47.readFileSync(filePath, "utf-8");
23513
24063
  } catch {
23514
24064
  return { redactedLines: 0, patterns: [] };
23515
24065
  }
@@ -23541,14 +24091,14 @@ function processFile(filePath, dryRun) {
23541
24091
  }
23542
24092
  }
23543
24093
  if (!dryRun && redactedLines > 0) {
23544
- fs46.writeFileSync(filePath, newLines.join("\n"), "utf-8");
24094
+ fs47.writeFileSync(filePath, newLines.join("\n"), "utf-8");
23545
24095
  }
23546
24096
  return { redactedLines, patterns };
23547
24097
  }
23548
24098
  function processJsonFile(filePath, dryRun) {
23549
24099
  let raw;
23550
24100
  try {
23551
- raw = fs46.readFileSync(filePath, "utf-8");
24101
+ raw = fs47.readFileSync(filePath, "utf-8");
23552
24102
  } catch {
23553
24103
  return { redactedLines: 0, patterns: [] };
23554
24104
  }
@@ -23561,15 +24111,15 @@ function processJsonFile(filePath, dryRun) {
23561
24111
  const { value, modified, found } = redactJson(parsed);
23562
24112
  if (!modified) return { redactedLines: 0, patterns: [] };
23563
24113
  if (!dryRun) {
23564
- fs46.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
24114
+ fs47.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
23565
24115
  }
23566
24116
  return { redactedLines: 1, patterns: found };
23567
24117
  }
23568
24118
  function findJsonFiles(dir) {
23569
24119
  const results = [];
23570
- if (!fs46.existsSync(dir)) return results;
23571
- for (const entry of fs46.readdirSync(dir, { withFileTypes: true })) {
23572
- const full = path47.join(dir, entry.name);
24120
+ if (!fs47.existsSync(dir)) return results;
24121
+ for (const entry of fs47.readdirSync(dir, { withFileTypes: true })) {
24122
+ const full = path48.join(dir, entry.name);
23573
24123
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
23574
24124
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
23575
24125
  }
@@ -23578,9 +24128,9 @@ function findJsonFiles(dir) {
23578
24128
  function registerMaskCommand(program2) {
23579
24129
  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) => {
23580
24130
  const dryRun = !!options.dryRun;
23581
- const home = os41.homedir();
23582
- const claudeDir = path47.join(home, ".claude", "projects");
23583
- const geminiDir = path47.join(home, ".gemini", "tmp");
24131
+ const home = os42.homedir();
24132
+ const claudeDir = path48.join(home, ".claude", "projects");
24133
+ const geminiDir = path48.join(home, ".gemini", "tmp");
23584
24134
  const allFiles = [
23585
24135
  ...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
23586
24136
  ...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
@@ -23588,7 +24138,7 @@ function registerMaskCommand(program2) {
23588
24138
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
23589
24139
  const filtered = cutoff ? allFiles.filter((f) => {
23590
24140
  try {
23591
- return fs46.statSync(f.path).mtime >= cutoff;
24141
+ return fs47.statSync(f.path).mtime >= cutoff;
23592
24142
  } catch {
23593
24143
  return false;
23594
24144
  }
@@ -23644,20 +24194,20 @@ function registerMaskCommand(program2) {
23644
24194
  // src/cli.ts
23645
24195
  init_blast();
23646
24196
  var { version } = JSON.parse(
23647
- fs49.readFileSync(path50.join(__dirname, "../package.json"), "utf-8")
24197
+ fs50.readFileSync(path51.join(__dirname, "../package.json"), "utf-8")
23648
24198
  );
23649
24199
  var program = new Command();
23650
24200
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
23651
24201
  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) => {
23652
24202
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
23653
- const credPath = path50.join(os44.homedir(), ".node9", "credentials.json");
23654
- if (!fs49.existsSync(path50.dirname(credPath)))
23655
- fs49.mkdirSync(path50.dirname(credPath), { recursive: true });
24203
+ const credPath = path51.join(os45.homedir(), ".node9", "credentials.json");
24204
+ if (!fs50.existsSync(path51.dirname(credPath)))
24205
+ fs50.mkdirSync(path51.dirname(credPath), { recursive: true });
23656
24206
  const profileName = options.profile || "default";
23657
24207
  let existingCreds = {};
23658
24208
  try {
23659
- if (fs49.existsSync(credPath)) {
23660
- const raw = JSON.parse(fs49.readFileSync(credPath, "utf-8"));
24209
+ if (fs50.existsSync(credPath)) {
24210
+ const raw = JSON.parse(fs50.readFileSync(credPath, "utf-8"));
23661
24211
  if (raw.apiKey) {
23662
24212
  existingCreds = {
23663
24213
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -23669,14 +24219,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
23669
24219
  } catch {
23670
24220
  }
23671
24221
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
23672
- fs49.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
24222
+ fs50.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
23673
24223
  let effectiveCloud = null;
23674
24224
  if (profileName === "default") {
23675
- const configPath = path50.join(os44.homedir(), ".node9", "config.json");
24225
+ const configPath = path51.join(os45.homedir(), ".node9", "config.json");
23676
24226
  let config = {};
23677
24227
  try {
23678
- if (fs49.existsSync(configPath))
23679
- config = JSON.parse(fs49.readFileSync(configPath, "utf-8"));
24228
+ if (fs50.existsSync(configPath))
24229
+ config = JSON.parse(fs50.readFileSync(configPath, "utf-8"));
23680
24230
  } catch {
23681
24231
  }
23682
24232
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -23691,9 +24241,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
23691
24241
  approvers.cloud = false;
23692
24242
  }
23693
24243
  s.approvers = approvers;
23694
- if (!fs49.existsSync(path50.dirname(configPath)))
23695
- fs49.mkdirSync(path50.dirname(configPath), { recursive: true });
23696
- fs49.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
24244
+ if (!fs50.existsSync(path51.dirname(configPath)))
24245
+ fs50.mkdirSync(path51.dirname(configPath), { recursive: true });
24246
+ fs50.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
23697
24247
  effectiveCloud = approvers.cloud === true;
23698
24248
  }
23699
24249
  if (options.profile && profileName !== "default") {
@@ -23852,15 +24402,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
23852
24402
  }
23853
24403
  }
23854
24404
  if (options.purge) {
23855
- const node9Dir = path50.join(os44.homedir(), ".node9");
23856
- if (fs49.existsSync(node9Dir)) {
24405
+ const node9Dir = path51.join(os45.homedir(), ".node9");
24406
+ if (fs50.existsSync(node9Dir)) {
23857
24407
  const confirmed = await confirm2({
23858
24408
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
23859
24409
  default: false
23860
24410
  });
23861
24411
  if (confirmed) {
23862
- fs49.rmSync(node9Dir, { recursive: true });
23863
- if (fs49.existsSync(node9Dir)) {
24412
+ fs50.rmSync(node9Dir, { recursive: true });
24413
+ if (fs50.existsSync(node9Dir)) {
23864
24414
  console.error(
23865
24415
  chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
23866
24416
  );
@@ -23975,7 +24525,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
23975
24525
  });
23976
24526
  program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
23977
24527
  try {
23978
- const dashboardPath = path50.join(__dirname, "dashboard.mjs");
24528
+ const dashboardPath = path51.join(__dirname, "dashboard.mjs");
23979
24529
  const dynamicImport = new Function("id", "return import(id)");
23980
24530
  const mod = await dynamicImport(`file://${dashboardPath}`);
23981
24531
  await mod.startMonitor();
@@ -24013,14 +24563,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
24013
24563
  Run "node9 addto claude" to register it as the statusLine.`
24014
24564
  ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
24015
24565
  if (subcommand === "debug") {
24016
- const flagFile = path50.join(os44.homedir(), ".node9", "hud-debug");
24566
+ const flagFile = path51.join(os45.homedir(), ".node9", "hud-debug");
24017
24567
  if (state === "on") {
24018
- fs49.mkdirSync(path50.dirname(flagFile), { recursive: true });
24019
- fs49.writeFileSync(flagFile, "");
24568
+ fs50.mkdirSync(path51.dirname(flagFile), { recursive: true });
24569
+ fs50.writeFileSync(flagFile, "");
24020
24570
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
24021
24571
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
24022
24572
  } else if (state === "off") {
24023
- if (fs49.existsSync(flagFile)) fs49.unlinkSync(flagFile);
24573
+ if (fs50.existsSync(flagFile)) fs50.unlinkSync(flagFile);
24024
24574
  console.log("HUD debug logging disabled.");
24025
24575
  } else {
24026
24576
  console.error("Usage: node9 hud debug on|off");
@@ -24137,9 +24687,9 @@ if (process.argv[2] !== "daemon") {
24137
24687
  const isCheckHook = process.argv[2] === "check";
24138
24688
  if (isCheckHook) {
24139
24689
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
24140
- const logPath = path50.join(os44.homedir(), ".node9", "hook-debug.log");
24690
+ const logPath = path51.join(os45.homedir(), ".node9", "hook-debug.log");
24141
24691
  const msg = reason instanceof Error ? reason.message : String(reason);
24142
- fs49.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
24692
+ fs50.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
24143
24693
  `);
24144
24694
  }
24145
24695
  process.exit(0);