@node9/proxy 1.30.0 → 1.31.0

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