@node9/proxy 1.31.0 → 1.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -122,6 +122,9 @@ function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashAr
122
122
  const agentToolNameField = meta?.agentToolName ? { agentToolName: meta.agentToolName } : {};
123
123
  const dlpFields = meta?.dlpPattern ? { dlpPattern: meta.dlpPattern, dlpSample: meta.dlpSample } : {};
124
124
  const cloudLinkField = meta?.cloudRequestId ? { cloudRequestId: meta.cloudRequestId } : {};
125
+ const workingDirField = meta?.workingDir ? { workingDir: meta.workingDir } : {};
126
+ const shell = process.env.SHELL ? path.basename(process.env.SHELL) : void 0;
127
+ const shellTypeField = shell ? { shellType: shell } : {};
125
128
  appendToLog(LOCAL_AUDIT_LOG, {
126
129
  // eid first: the outbox shipper dedups on it, and a fixed leading field
127
130
  // makes the JSONL easy to eyeball.
@@ -135,11 +138,14 @@ function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashAr
135
138
  ...ruleNameField,
136
139
  ...dlpFields,
137
140
  ...cloudLinkField,
141
+ ...workingDirField,
142
+ ...shellTypeField,
138
143
  ...testRun,
139
144
  agent: meta?.agent,
140
145
  mcpServer: meta?.mcpServer,
141
146
  sessionId: meta?.sessionId,
142
- hostname: os.hostname()
147
+ hostname: os.hostname(),
148
+ platform: os.platform()
143
149
  });
144
150
  }
145
151
  function appendConfigAudit(entry) {
@@ -179,8 +185,8 @@ function sanitizeConfig(raw) {
179
185
  }
180
186
  }
181
187
  const lines = result.error.issues.map((issue) => {
182
- const path52 = issue.path.length > 0 ? issue.path.join(".") : "root";
183
- return ` \u2022 ${path52}: ${issue.message}`;
188
+ const path54 = issue.path.length > 0 ? issue.path.join(".") : "root";
189
+ return ` \u2022 ${path54}: ${issue.message}`;
184
190
  });
185
191
  return {
186
192
  sanitized,
@@ -532,6 +538,8 @@ function normalizeCommandForPolicyImpl(command) {
532
538
  if (f === PARSE_FAIL) return command;
533
539
  try {
534
540
  const strips = [];
541
+ const rewrites = [];
542
+ const msgSpans = /* @__PURE__ */ new Set();
535
543
  syntax.Walk(f, (node) => {
536
544
  if (!node) return false;
537
545
  const n = node;
@@ -547,25 +555,46 @@ function normalizeCommandForPolicyImpl(command) {
547
555
  if (nextParts.length !== 1) continue;
548
556
  const quotedNode = nextParts[0];
549
557
  const nt = syntax.NodeType(quotedNode);
558
+ const markStrip = () => {
559
+ const s = next.Pos().Offset();
560
+ const e = next.End().Offset();
561
+ strips.push([s, e]);
562
+ msgSpans.add(`${s}:${e}`);
563
+ };
550
564
  if (nt === "SglQuoted") {
551
- strips.push([next.Pos().Offset(), next.End().Offset()]);
565
+ markStrip();
552
566
  } else if (nt === "DblQuoted") {
553
567
  const innerParts = quotedNode.Parts || [];
554
568
  const allLit = innerParts.length === 0 || innerParts.every((p) => syntax.NodeType(p) === "Lit");
555
569
  if (allLit) {
556
- strips.push([next.Pos().Offset(), next.End().Offset()]);
570
+ markStrip();
557
571
  } else if (innerParts.every((p) => isCatHeredocOrLit(p))) {
558
- strips.push([next.Pos().Offset(), next.End().Offset()]);
572
+ markStrip();
559
573
  }
560
574
  }
561
575
  }
576
+ for (const arg of args) {
577
+ const s = arg.Pos().Offset();
578
+ const e = arg.End().Offset();
579
+ if (msgSpans.has(`${s}:${e}`)) continue;
580
+ const resolved = resolveWordLiteral(arg);
581
+ if (resolved === null) continue;
582
+ const source = command.slice(s, e);
583
+ if (resolved === source) continue;
584
+ if (resolved === "" || /\s/.test(resolved)) continue;
585
+ rewrites.push([s, e, resolved]);
586
+ }
562
587
  return true;
563
588
  });
564
- if (strips.length === 0) return command;
565
- strips.sort((a, b) => b[0] - a[0]);
589
+ const edits = [
590
+ ...strips.map(([s, e]) => [s, e, '""']),
591
+ ...rewrites
592
+ ];
593
+ if (edits.length === 0) return command;
594
+ edits.sort((a, b) => b[0] - a[0]);
566
595
  let result = command;
567
- for (const [start, end] of strips) {
568
- result = result.slice(0, start) + '""' + result.slice(end);
596
+ for (const [s, e, rep] of edits) {
597
+ result = result.slice(0, s) + rep + result.slice(e);
569
598
  }
570
599
  return result;
571
600
  } catch {
@@ -627,6 +656,17 @@ function detectDangerousShellExec(command) {
627
656
  function isBashTool(toolName) {
628
657
  return BASH_TOOL_NAMES.has(toolName.toLowerCase());
629
658
  }
659
+ function analyzeSqlDestructive(command) {
660
+ if (!SQL_DDL_RE.test(command)) return null;
661
+ const { actions } = analyzeShellCommand(command);
662
+ if (!actions.some((a) => SQL_DB_CLIS.has(a))) return null;
663
+ return {
664
+ ruleName: "review-drop-truncate-shell",
665
+ verdict: "review",
666
+ reason: "SQL DDL destructive statement inside a shell command",
667
+ description: "The AI wants to drop or truncate a database table via the shell. This permanently deletes the table structure or all its data."
668
+ };
669
+ }
630
670
  function isProtectedHomePath(rawPath) {
631
671
  let p = rawPath.replace(/^\$HOME[\\/]?|^\$\{HOME\}[\\/]?/, "~/");
632
672
  let underHome = false;
@@ -788,19 +828,20 @@ function extractShellDestinations(command) {
788
828
  return out;
789
829
  }
790
830
  function analyzeFsOperation(command) {
791
- if (!FS_OP_PRESCREEN_RE.test(command)) return null;
792
- if (fsOpCache.has(command)) {
793
- const hit = fsOpCache.get(command) ?? null;
794
- fsOpCache.delete(command);
795
- fsOpCache.set(command, hit);
831
+ const normalized = normalizeCommandForPolicy(command);
832
+ if (!FS_OP_PRESCREEN_RE.test(normalized)) return null;
833
+ if (fsOpCache.has(normalized)) {
834
+ const hit = fsOpCache.get(normalized) ?? null;
835
+ fsOpCache.delete(normalized);
836
+ fsOpCache.set(normalized, hit);
796
837
  return hit;
797
838
  }
798
- const computed = analyzeFsOperationImpl(command);
839
+ const computed = analyzeFsOperationImpl(normalized);
799
840
  if (fsOpCache.size >= FS_OP_CACHE_MAX) {
800
841
  const oldest = fsOpCache.keys().next().value;
801
842
  if (oldest !== void 0) fsOpCache.delete(oldest);
802
843
  }
803
- fsOpCache.set(command, computed);
844
+ fsOpCache.set(normalized, computed);
804
845
  return computed;
805
846
  }
806
847
  function analyzeFsOperationImpl(command) {
@@ -1199,9 +1240,9 @@ function matchesPattern(text, patterns) {
1199
1240
  const withoutDotSlash = text.replace(/^\.\//, "");
1200
1241
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1201
1242
  }
1202
- function getNestedValue(obj, path52) {
1243
+ function getNestedValue(obj, path54) {
1203
1244
  if (!obj || typeof obj !== "object") return null;
1204
- const segments = path52.split(".");
1245
+ const segments = path54.split(".");
1205
1246
  for (const seg of segments) {
1206
1247
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1207
1248
  }
@@ -1341,6 +1382,17 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
1341
1382
  ruleDescription: fsVerdict.reason
1342
1383
  };
1343
1384
  }
1385
+ const sqlVerdict = analyzeSqlDestructive(bashCommand);
1386
+ if (sqlVerdict) {
1387
+ return {
1388
+ decision: sqlVerdict.verdict,
1389
+ blockedByLabel: `Node9 (AST): ${sqlVerdict.ruleName}`,
1390
+ reason: sqlVerdict.reason,
1391
+ tier: 2,
1392
+ ruleName: sqlVerdict.ruleName,
1393
+ ruleDescription: sqlVerdict.description
1394
+ };
1395
+ }
1344
1396
  }
1345
1397
  if (config.policy.smartRules.length > 0) {
1346
1398
  const matchedRule = config.policy.smartRules.find(
@@ -1921,7 +1973,7 @@ function extractCanonicalFindings(call, ctx) {
1921
1973
  })
1922
1974
  );
1923
1975
  }
1924
- if (DESTRUCTIVE_OP_RE.test(command)) {
1976
+ if (command !== null && DESTRUCTIVE_OP_RE.test(normalizeCommandForPolicy(command))) {
1925
1977
  out.push(
1926
1978
  makeFinding({
1927
1979
  type: "destructive-op",
@@ -2073,7 +2125,7 @@ function* stringValues(obj, depth = 0) {
2073
2125
  }
2074
2126
  for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
2075
2127
  }
2076
- var ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, COST_PER_LOOP_ITER_USD, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, TERMINAL_ESCAPE_RE;
2128
+ var ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, 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;
2077
2129
  var init_dist = __esm({
2078
2130
  "packages/policy-engine/dist/index.mjs"() {
2079
2131
  "use strict";
@@ -2685,8 +2737,24 @@ var init_dist = __esm({
2685
2737
  "shield:project-jail:block-read-ssh",
2686
2738
  "shield:project-jail:block-read-aws",
2687
2739
  "shield:project-jail:block-read-env",
2688
- "shield:project-jail:review-read-credentials"
2740
+ "shield:project-jail:review-read-credentials",
2741
+ // SQL-DDL is now owned by the AST detector (analyzeSqlDestructive) so the
2742
+ // raw-regex smart rule is suppressed for bash — its cond1 read a grep
2743
+ // alternation's `|` as a shell pipe (`grep "…|mysql…"` → false positive).
2744
+ "review-drop-truncate-shell"
2689
2745
  ]);
2746
+ SQL_DB_CLIS = /* @__PURE__ */ new Set([
2747
+ "psql",
2748
+ "mysql",
2749
+ "mariadb",
2750
+ "sqlite3",
2751
+ "sqlplus",
2752
+ "cockroach",
2753
+ "clickhouse-client",
2754
+ "mongo",
2755
+ "mongosh"
2756
+ ]);
2757
+ SQL_DDL_RE = /\b(DROP|TRUNCATE)\s+(TABLE|DATABASE|SCHEMA|INDEX)\b/i;
2690
2758
  NET_BINARIES = /* @__PURE__ */ new Set(["curl", "wget", "scp", "ssh", "nc", "ncat", "netcat"]);
2691
2759
  VALUE_FLAGS = {
2692
2760
  curl: /* @__PURE__ */ new Set([
@@ -3725,7 +3793,7 @@ var init_dist = __esm({
3725
3793
  REALTIME_PII_PATTERNS = ["SSN", "Credit Card"];
3726
3794
  MAX_PII_SCAN_BYTES = 1e5;
3727
3795
  LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
3728
- CANONICAL_EXTRACTOR_VERSION = "canonical-v4";
3796
+ CANONICAL_EXTRACTOR_VERSION = "canonical-v6";
3729
3797
  DEDUPE_PREVIEW_LEN = 120;
3730
3798
  TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
3731
3799
  /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
@@ -6055,7 +6123,8 @@ async function authorizeHeadless(toolName, args, meta, options) {
6055
6123
  }
6056
6124
  return _authorizeHeadlessCore(toolName, args, meta, options);
6057
6125
  }
6058
- async function _authorizeHeadlessCore(toolName, args, meta, options) {
6126
+ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
6127
+ const meta = options?.cwd && !metaArg?.workingDir ? { ...metaArg, workingDir: options.cwd } : metaArg;
6059
6128
  if (process.env.NODE9_PAUSED === "1") return { approved: true, checkedBy: "paused" };
6060
6129
  const pauseState = checkPause();
6061
6130
  if (pauseState.paused) return { approved: true, checkedBy: "paused" };
@@ -7216,7 +7285,7 @@ function writeJson(filePath, data) {
7216
7285
  }
7217
7286
  function isNode9Hook(cmd) {
7218
7287
  if (!cmd) return false;
7219
- return /(?:^|[\s/\\"])node9 (?:check|log)/.test(cmd) || /(?:^|[\s/\\"])cli\.js" (?:check|log)/.test(cmd) || /(?:^|[\s/\\])cli\.js (?:check|log)/.test(cmd);
7288
+ return /(?:^|[\s/\\"])node9"? (?:check|log)/.test(cmd) || /(?:^|[\s/\\])cli\.js"? (?:check|log)/.test(cmd);
7220
7289
  }
7221
7290
  function teardownClaude() {
7222
7291
  const homeDir2 = os12.homedir();
@@ -10003,83 +10072,132 @@ var init_litellm = __esm({
10003
10072
  import fs17 from "fs";
10004
10073
  import os16 from "os";
10005
10074
  import path19 from "path";
10006
- function codexLogPath() {
10007
- return path19.join(os16.homedir(), ".codex", "log", "codex-tui.log");
10008
- }
10009
- function parseCodexUsageLine(line) {
10010
- if (!line.includes("token_usage")) return null;
10011
- const date = line.match(RE_DATE)?.[1];
10012
- if (!date) return null;
10013
- const model = line.match(RE_MODEL)?.[1];
10014
- if (!model) return null;
10015
- const num3 = (re) => {
10016
- const m = line.match(re);
10017
- return m ? Number(m[1]) : 0;
10018
- };
10019
- const totalInput = num3(RE_INPUT);
10020
- const cached = num3(RE_CACHED);
10021
- const nonCached = num3(RE_NON_CACHED);
10022
- const output = num3(RE_OUTPUT);
10023
- const inputTokens = nonCached || Math.max(0, totalInput - cached);
10024
- if (inputTokens === 0 && output === 0 && cached === 0) return null;
10025
- const runId = line.match(RE_THREAD)?.[1] ?? "";
10026
- const norm = normalizeModel(model);
10027
- const p = pricingFor(model);
10028
- const costUSD = p ? inputTokens * p[0] + output * p[1] + cached * p[3] : 0;
10075
+ function codexSessionsDir() {
10076
+ return path19.join(os16.homedir(), ".codex", "sessions");
10077
+ }
10078
+ function codexPriceFor(model) {
10079
+ return pricingFor(model) ?? CODEX_FALLBACK;
10080
+ }
10081
+ function listCodexSessionFiles(base) {
10082
+ const out = [];
10083
+ for (const y of safeReaddir(base)) {
10084
+ const yp = path19.join(base, y);
10085
+ if (!isDir(yp)) continue;
10086
+ for (const m of safeReaddir(yp)) {
10087
+ const mp = path19.join(yp, m);
10088
+ if (!isDir(mp)) continue;
10089
+ for (const d of safeReaddir(mp)) {
10090
+ const dp = path19.join(mp, d);
10091
+ if (!isDir(dp)) continue;
10092
+ for (const f of safeReaddir(dp)) {
10093
+ if (f.endsWith(".jsonl")) out.push(path19.join(dp, f));
10094
+ }
10095
+ }
10096
+ }
10097
+ }
10098
+ return out;
10099
+ }
10100
+ function safeReaddir(dir) {
10101
+ try {
10102
+ return fs17.readdirSync(dir);
10103
+ } catch {
10104
+ return [];
10105
+ }
10106
+ }
10107
+ function isDir(p) {
10108
+ try {
10109
+ return fs17.statSync(p).isDirectory();
10110
+ } catch {
10111
+ return false;
10112
+ }
10113
+ }
10114
+ function parseCodexSession(lines) {
10115
+ let sessionStart2 = "";
10116
+ let runId = "";
10117
+ let cwd = "";
10118
+ let model = "";
10119
+ let input = 0;
10120
+ let cached = 0;
10121
+ let output = 0;
10122
+ let sawUsage = false;
10123
+ for (const raw of lines) {
10124
+ if (!raw.trim()) continue;
10125
+ let entry;
10126
+ try {
10127
+ entry = JSON.parse(raw);
10128
+ } catch {
10129
+ continue;
10130
+ }
10131
+ const p = entry.payload ?? {};
10132
+ if (entry.type === "session_meta") {
10133
+ if (!sessionStart2 && typeof p["timestamp"] === "string") sessionStart2 = p["timestamp"];
10134
+ if (!runId && typeof p["id"] === "string") runId = p["id"];
10135
+ if (!cwd && typeof p["cwd"] === "string") cwd = p["cwd"];
10136
+ continue;
10137
+ }
10138
+ if (entry.type === "turn_context") {
10139
+ if (typeof p["model"] === "string") model = p["model"];
10140
+ if (!cwd && typeof p["cwd"] === "string") cwd = p["cwd"];
10141
+ continue;
10142
+ }
10143
+ if (entry.type === "event_msg" && p["type"] === "token_count") {
10144
+ const info = p["info"] ?? {};
10145
+ const usage = info["total_token_usage"] ?? {};
10146
+ if (typeof usage["input_tokens"] === "number") input = usage["input_tokens"];
10147
+ if (typeof usage["cached_input_tokens"] === "number") cached = usage["cached_input_tokens"];
10148
+ if (typeof usage["output_tokens"] === "number") output = usage["output_tokens"];
10149
+ sawUsage = true;
10150
+ }
10151
+ }
10152
+ if (!sessionStart2 || !sawUsage) return null;
10153
+ const nonCached = Math.max(0, input - cached);
10154
+ if (nonCached === 0 && output === 0 && cached === 0) return null;
10155
+ const norm = normalizeModel(model || "gpt-5");
10156
+ const [pin, pout, , pcr] = codexPriceFor(model || "gpt-5");
10157
+ const costUSD = nonCached * pin + output * pout + cached * pcr;
10029
10158
  return {
10030
- date,
10159
+ date: sessionStart2.slice(0, 10),
10031
10160
  model: norm,
10032
- workingDir: "",
10033
- // Codex span carries no cwd — attribution is by runId (thread)
10161
+ workingDir: cwd,
10034
10162
  runId,
10035
10163
  costUSD,
10036
- inputTokens,
10164
+ inputTokens: nonCached,
10037
10165
  outputTokens: output,
10038
10166
  cacheReadTokens: cached,
10039
10167
  cacheWriteTokens: 0
10040
10168
  };
10041
10169
  }
10042
- var RE_INPUT, RE_CACHED, RE_NON_CACHED, RE_OUTPUT, RE_MODEL, RE_THREAD, RE_DATE, codexSource;
10170
+ var CODEX_FALLBACK, codexSource;
10043
10171
  var init_cost_codex = __esm({
10044
10172
  "src/cost-codex.ts"() {
10045
10173
  "use strict";
10046
10174
  init_litellm();
10047
- RE_INPUT = /token_usage\.input_tokens=(\d+)/;
10048
- RE_CACHED = /token_usage\.cached_input_tokens=(\d+)/;
10049
- RE_NON_CACHED = /token_usage\.non_cached_input_tokens=(\d+)/;
10050
- RE_OUTPUT = /token_usage\.output_tokens=(\d+)/;
10051
- RE_MODEL = /\bmodel=([^\s}]+)/;
10052
- RE_THREAD = /\bthread\.id=([0-9a-fA-F-]+)/;
10053
- RE_DATE = /^(\d{4}-\d{2}-\d{2})T/;
10175
+ CODEX_FALLBACK = [5e-6, 15e-6, 0, 25e-7];
10054
10176
  codexSource = {
10055
10177
  id: "codex",
10056
10178
  available() {
10057
10179
  try {
10058
- return fs17.existsSync(codexLogPath());
10180
+ return fs17.existsSync(codexSessionsDir());
10059
10181
  } catch {
10060
10182
  return false;
10061
10183
  }
10062
10184
  },
10063
10185
  collect(sinceMs) {
10064
- const file = codexLogPath();
10065
- let content;
10066
- try {
10067
- if (sinceMs !== void 0 && fs17.statSync(file).mtimeMs < sinceMs) return [];
10068
- content = fs17.readFileSync(file, "utf8");
10069
- } catch {
10070
- return [];
10071
- }
10186
+ const base = codexSessionsDir();
10072
10187
  const combined = /* @__PURE__ */ new Map();
10073
- for (const line of content.split("\n")) {
10074
- if (!line.includes("token_usage")) continue;
10075
- if (sinceMs !== void 0) {
10076
- const tsFull = line.match(/^(\S+)\s/)?.[1];
10077
- if (tsFull) {
10078
- const t = Date.parse(tsFull);
10079
- if (!Number.isNaN(t) && t < sinceMs) continue;
10080
- }
10188
+ for (const file of listCodexSessionFiles(base)) {
10189
+ try {
10190
+ if (sinceMs !== void 0 && fs17.statSync(file).mtimeMs < sinceMs) continue;
10191
+ } catch {
10192
+ continue;
10081
10193
  }
10082
- const e = parseCodexUsageLine(line);
10194
+ let content;
10195
+ try {
10196
+ content = fs17.readFileSync(file, "utf8");
10197
+ } catch {
10198
+ continue;
10199
+ }
10200
+ const e = parseCodexSession(content.split("\n"));
10083
10201
  if (!e) continue;
10084
10202
  const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
10085
10203
  const prev = combined.get(key);
@@ -10099,18 +10217,289 @@ var init_cost_codex = __esm({
10099
10217
  }
10100
10218
  });
10101
10219
 
10102
- // src/costSync.ts
10220
+ // src/cost-gemini.ts
10103
10221
  import fs18 from "fs";
10104
- import path20 from "path";
10105
10222
  import os17 from "os";
10223
+ import path20 from "path";
10224
+ function geminiTmpDir() {
10225
+ return path20.join(os17.homedir(), ".gemini", "tmp");
10226
+ }
10227
+ function geminiPriceFor(model) {
10228
+ let tuple = pricingFor(model);
10229
+ if (!tuple && /^gemini-/i.test(model)) {
10230
+ for (const proxy of GEMINI_FALLBACK_MODELS) {
10231
+ tuple = pricingFor(proxy);
10232
+ if (tuple) break;
10233
+ }
10234
+ }
10235
+ if (!tuple) return null;
10236
+ return { input: tuple[0], output: tuple[1], cacheRead: tuple[3] || tuple[0] };
10237
+ }
10238
+ function safeReaddir2(dir) {
10239
+ try {
10240
+ return fs18.readdirSync(dir);
10241
+ } catch {
10242
+ return [];
10243
+ }
10244
+ }
10245
+ function isDir2(p) {
10246
+ try {
10247
+ return fs18.statSync(p).isDirectory();
10248
+ } catch {
10249
+ return false;
10250
+ }
10251
+ }
10252
+ function listGeminiSessionFiles(base) {
10253
+ const out = [];
10254
+ for (const project of safeReaddir2(base)) {
10255
+ const chats = path20.join(base, project, "chats");
10256
+ if (!isDir2(chats)) continue;
10257
+ for (const f of safeReaddir2(chats)) {
10258
+ if (f.startsWith("session-") && f.endsWith(".jsonl")) {
10259
+ out.push({ file: path20.join(chats, f), project });
10260
+ }
10261
+ }
10262
+ }
10263
+ return out;
10264
+ }
10265
+ function parseGeminiSession(lines, project) {
10266
+ const seenIds = /* @__PURE__ */ new Set();
10267
+ const byKey = /* @__PURE__ */ new Map();
10268
+ let runId = "";
10269
+ for (const raw of lines) {
10270
+ if (!raw.trim()) continue;
10271
+ let obj;
10272
+ try {
10273
+ obj = JSON.parse(raw);
10274
+ } catch {
10275
+ continue;
10276
+ }
10277
+ if (typeof obj.sessionId === "string" && !runId) runId = obj.sessionId;
10278
+ if (!obj.tokens || !obj.model || !obj.timestamp) continue;
10279
+ if (obj.id) {
10280
+ if (seenIds.has(obj.id)) continue;
10281
+ seenIds.add(obj.id);
10282
+ }
10283
+ const price = geminiPriceFor(obj.model);
10284
+ if (!price) continue;
10285
+ const inp = obj.tokens.input ?? 0;
10286
+ const out = obj.tokens.output ?? 0;
10287
+ const cached = Math.min(obj.tokens.cached ?? 0, inp);
10288
+ const fresh = Math.max(0, inp - cached);
10289
+ const cost = fresh * price.input + cached * price.cacheRead + out * price.output;
10290
+ const date = obj.timestamp.slice(0, 10);
10291
+ const model = normalizeModel(obj.model);
10292
+ const key = `${date}::${model}`;
10293
+ const prev = byKey.get(key);
10294
+ if (prev) {
10295
+ prev.costUSD += cost;
10296
+ prev.inputTokens += fresh;
10297
+ prev.outputTokens += out;
10298
+ prev.cacheReadTokens += cached;
10299
+ } else {
10300
+ byKey.set(key, {
10301
+ date,
10302
+ model,
10303
+ workingDir: project,
10304
+ runId,
10305
+ costUSD: cost,
10306
+ inputTokens: fresh,
10307
+ outputTokens: out,
10308
+ cacheReadTokens: cached,
10309
+ cacheWriteTokens: 0
10310
+ });
10311
+ }
10312
+ }
10313
+ if (runId) for (const e of byKey.values()) e.runId = runId;
10314
+ return [...byKey.values()];
10315
+ }
10316
+ var GEMINI_FALLBACK_MODELS, geminiSource;
10317
+ var init_cost_gemini = __esm({
10318
+ "src/cost-gemini.ts"() {
10319
+ "use strict";
10320
+ init_litellm();
10321
+ GEMINI_FALLBACK_MODELS = ["gemini-2.5-flash", "gemini-2.0-flash"];
10322
+ geminiSource = {
10323
+ id: "gemini",
10324
+ available() {
10325
+ try {
10326
+ return fs18.existsSync(geminiTmpDir());
10327
+ } catch {
10328
+ return false;
10329
+ }
10330
+ },
10331
+ collect(sinceMs) {
10332
+ const combined = /* @__PURE__ */ new Map();
10333
+ for (const { file, project } of listGeminiSessionFiles(geminiTmpDir())) {
10334
+ try {
10335
+ if (sinceMs !== void 0 && fs18.statSync(file).mtimeMs < sinceMs) continue;
10336
+ } catch {
10337
+ continue;
10338
+ }
10339
+ let content;
10340
+ try {
10341
+ content = fs18.readFileSync(file, "utf8");
10342
+ } catch {
10343
+ continue;
10344
+ }
10345
+ for (const e of parseGeminiSession(content.split("\n"), project)) {
10346
+ const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
10347
+ const prev = combined.get(key);
10348
+ if (prev) {
10349
+ prev.costUSD += e.costUSD;
10350
+ prev.inputTokens += e.inputTokens;
10351
+ prev.outputTokens += e.outputTokens;
10352
+ prev.cacheReadTokens += e.cacheReadTokens;
10353
+ prev.cacheWriteTokens += e.cacheWriteTokens;
10354
+ } else {
10355
+ combined.set(key, { ...e });
10356
+ }
10357
+ }
10358
+ }
10359
+ return [...combined.values()];
10360
+ }
10361
+ };
10362
+ }
10363
+ });
10364
+
10365
+ // src/cost-copilot.ts
10366
+ import fs19 from "fs";
10367
+ import os18 from "os";
10368
+ import path21 from "path";
10369
+ function copilotSessionsDir() {
10370
+ return path21.join(os18.homedir(), ".copilot", "session-state");
10371
+ }
10372
+ function safeReaddir3(dir) {
10373
+ try {
10374
+ return fs19.readdirSync(dir);
10375
+ } catch {
10376
+ return [];
10377
+ }
10378
+ }
10379
+ function priceTokens(model, u) {
10380
+ const tuple = pricingFor(model);
10381
+ if (!tuple || !u) return 0;
10382
+ const [pin, pout, pcw, pcr] = tuple;
10383
+ return (u.inputTokens ?? 0) * pin + (u.outputTokens ?? 0) * pout + (u.cacheWriteTokens ?? 0) * pcw + (u.cacheReadTokens ?? 0) * pcr;
10384
+ }
10385
+ function parseCopilotSession(lines) {
10386
+ let sessionId = "";
10387
+ let cwd = "";
10388
+ let startDate = "";
10389
+ let shutdownDate = "";
10390
+ let modelMetrics = null;
10391
+ for (const raw of lines) {
10392
+ if (!raw.trim()) continue;
10393
+ let o;
10394
+ try {
10395
+ o = JSON.parse(raw);
10396
+ } catch {
10397
+ continue;
10398
+ }
10399
+ const d = o.data ?? {};
10400
+ if (o.type === "session.start") {
10401
+ if (typeof d["sessionId"] === "string") sessionId = d["sessionId"];
10402
+ if (typeof d["startTime"] === "string") startDate = d["startTime"];
10403
+ const ctx = d["context"] ?? {};
10404
+ if (typeof ctx["cwd"] === "string") cwd = ctx["cwd"];
10405
+ } else if (o.type === "session.shutdown") {
10406
+ if (d["modelMetrics"] && typeof d["modelMetrics"] === "object") {
10407
+ modelMetrics = d["modelMetrics"];
10408
+ }
10409
+ if (typeof o.timestamp === "string") shutdownDate = o.timestamp;
10410
+ }
10411
+ }
10412
+ if (!modelMetrics) return [];
10413
+ const date = (startDate || shutdownDate).slice(0, 10);
10414
+ if (!date) return [];
10415
+ const rows = [];
10416
+ for (const [rawModel, m] of Object.entries(modelMetrics)) {
10417
+ const u = m.usage ?? {};
10418
+ const inputTokens = u.inputTokens ?? 0;
10419
+ const outputTokens = u.outputTokens ?? 0;
10420
+ const cacheReadTokens = u.cacheReadTokens ?? 0;
10421
+ const cacheWriteTokens = u.cacheWriteTokens ?? 0;
10422
+ if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0) {
10423
+ continue;
10424
+ }
10425
+ const model = normalizeModel(rawModel);
10426
+ const costUSD = typeof m.requests?.cost === "number" && m.requests.cost > 0 ? m.requests.cost : priceTokens(rawModel, u);
10427
+ rows.push({
10428
+ date,
10429
+ model,
10430
+ workingDir: cwd,
10431
+ runId: sessionId,
10432
+ costUSD,
10433
+ inputTokens,
10434
+ outputTokens,
10435
+ cacheReadTokens,
10436
+ cacheWriteTokens
10437
+ });
10438
+ }
10439
+ return rows;
10440
+ }
10441
+ var copilotSource;
10442
+ var init_cost_copilot = __esm({
10443
+ "src/cost-copilot.ts"() {
10444
+ "use strict";
10445
+ init_litellm();
10446
+ copilotSource = {
10447
+ id: "copilot",
10448
+ available() {
10449
+ try {
10450
+ return fs19.existsSync(copilotSessionsDir());
10451
+ } catch {
10452
+ return false;
10453
+ }
10454
+ },
10455
+ collect(sinceMs) {
10456
+ const base = copilotSessionsDir();
10457
+ const combined = /* @__PURE__ */ new Map();
10458
+ for (const sid of safeReaddir3(base)) {
10459
+ const file = path21.join(base, sid, "events.jsonl");
10460
+ try {
10461
+ if (sinceMs !== void 0 && fs19.statSync(file).mtimeMs < sinceMs) continue;
10462
+ } catch {
10463
+ continue;
10464
+ }
10465
+ let content;
10466
+ try {
10467
+ content = fs19.readFileSync(file, "utf8");
10468
+ } catch {
10469
+ continue;
10470
+ }
10471
+ for (const e of parseCopilotSession(content.split("\n"))) {
10472
+ const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
10473
+ const prev = combined.get(key);
10474
+ if (prev) {
10475
+ prev.costUSD += e.costUSD;
10476
+ prev.inputTokens += e.inputTokens;
10477
+ prev.outputTokens += e.outputTokens;
10478
+ prev.cacheReadTokens += e.cacheReadTokens;
10479
+ prev.cacheWriteTokens += e.cacheWriteTokens;
10480
+ } else {
10481
+ combined.set(key, { ...e });
10482
+ }
10483
+ }
10484
+ }
10485
+ return [...combined.values()];
10486
+ }
10487
+ };
10488
+ }
10489
+ });
10490
+
10491
+ // src/costSync.ts
10492
+ import fs20 from "fs";
10493
+ import path22 from "path";
10494
+ import os19 from "os";
10106
10495
  function decodeProjectDirName(dirName) {
10107
10496
  return dirName.replace(/-/g, "/");
10108
10497
  }
10109
10498
  function parseJSONLFile(filePath, fallbackWorkingDir) {
10110
- const runId = path20.basename(filePath, ".jsonl");
10499
+ const runId = path22.basename(filePath, ".jsonl");
10111
10500
  let content;
10112
10501
  try {
10113
- content = fs18.readFileSync(filePath, "utf8");
10502
+ content = fs20.readFileSync(filePath, "utf8");
10114
10503
  } catch {
10115
10504
  return /* @__PURE__ */ new Map();
10116
10505
  }
@@ -10194,6 +10583,45 @@ function collectEntries(sinceMs) {
10194
10583
  }
10195
10584
  return [...combined.values()];
10196
10585
  }
10586
+ function chunk(arr, size) {
10587
+ if (size <= 0) return arr.length ? [arr] : [];
10588
+ const out = [];
10589
+ for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
10590
+ return out;
10591
+ }
10592
+ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
10593
+ for (const batch of chunk(entries, COST_BATCH_SIZE)) {
10594
+ try {
10595
+ const res = await fetch(`${apiUrl}/cost-sync`, {
10596
+ method: "POST",
10597
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
10598
+ body: JSON.stringify({ machineId, entries: batch }),
10599
+ signal: AbortSignal.timeout(15e3)
10600
+ });
10601
+ if (!res.ok) {
10602
+ fs20.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
10603
+ `);
10604
+ } else {
10605
+ let stored;
10606
+ try {
10607
+ const respBody = typeof res.json === "function" ? await res.json() : null;
10608
+ stored = respBody?.stored;
10609
+ } catch {
10610
+ }
10611
+ if (typeof stored === "number" && stored < batch.length) {
10612
+ fs20.appendFileSync(
10613
+ HOOK_DEBUG_LOG,
10614
+ `[cost-sync] dropped ${batch.length - stored} of ${batch.length} rows
10615
+ `
10616
+ );
10617
+ }
10618
+ }
10619
+ } catch (err2) {
10620
+ fs20.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
10621
+ `);
10622
+ }
10623
+ }
10624
+ }
10197
10625
  async function syncCost() {
10198
10626
  const creds = getCredentials();
10199
10627
  if (!creds?.apiKey || !creds?.apiUrl) return;
@@ -10202,25 +10630,11 @@ async function syncCost() {
10202
10630
  if (entries.length === 0) return;
10203
10631
  let username = "unknown";
10204
10632
  try {
10205
- username = os17.userInfo().username;
10633
+ username = os19.userInfo().username;
10206
10634
  } catch {
10207
10635
  }
10208
- const machineId = `${os17.hostname()}:${username}`;
10209
- try {
10210
- const res = await fetch(`${creds.apiUrl}/cost-sync`, {
10211
- method: "POST",
10212
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
10213
- body: JSON.stringify({ machineId, entries }),
10214
- signal: AbortSignal.timeout(15e3)
10215
- });
10216
- if (!res.ok) {
10217
- fs18.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
10218
- `);
10219
- }
10220
- } catch (err2) {
10221
- fs18.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
10222
- `);
10223
- }
10636
+ const machineId = `${os19.hostname()}:${username}`;
10637
+ await postCostBatches(creds.apiUrl, creds.apiKey, machineId, entries);
10224
10638
  }
10225
10639
  function startCostSync() {
10226
10640
  syncCost().catch(() => {
@@ -10231,7 +10645,7 @@ function startCostSync() {
10231
10645
  }, SYNC_INTERVAL_MS);
10232
10646
  timer.unref();
10233
10647
  }
10234
- var SYNC_INTERVAL_MS, claudeSource, COST_SOURCES;
10648
+ var SYNC_INTERVAL_MS, claudeSource, COST_SOURCES, COST_BATCH_SIZE;
10235
10649
  var init_costSync = __esm({
10236
10650
  "src/costSync.ts"() {
10237
10651
  "use strict";
@@ -10239,41 +10653,43 @@ var init_costSync = __esm({
10239
10653
  init_audit();
10240
10654
  init_litellm();
10241
10655
  init_cost_codex();
10656
+ init_cost_gemini();
10657
+ init_cost_copilot();
10242
10658
  SYNC_INTERVAL_MS = 10 * 60 * 1e3;
10243
10659
  claudeSource = {
10244
10660
  id: "claude",
10245
10661
  available() {
10246
- return fs18.existsSync(path20.join(os17.homedir(), ".claude", "projects"));
10662
+ return fs20.existsSync(path22.join(os19.homedir(), ".claude", "projects"));
10247
10663
  },
10248
10664
  collect(sinceMs) {
10249
- const projectsDir = path20.join(os17.homedir(), ".claude", "projects");
10250
- if (!fs18.existsSync(projectsDir)) return [];
10665
+ const projectsDir = path22.join(os19.homedir(), ".claude", "projects");
10666
+ if (!fs20.existsSync(projectsDir)) return [];
10251
10667
  const combined = /* @__PURE__ */ new Map();
10252
10668
  let dirs;
10253
10669
  try {
10254
- dirs = fs18.readdirSync(projectsDir);
10670
+ dirs = fs20.readdirSync(projectsDir);
10255
10671
  } catch {
10256
10672
  return [];
10257
10673
  }
10258
10674
  for (const dir of dirs) {
10259
- const dirPath = path20.join(projectsDir, dir);
10675
+ const dirPath = path22.join(projectsDir, dir);
10260
10676
  try {
10261
- if (!fs18.statSync(dirPath).isDirectory()) continue;
10677
+ if (!fs20.statSync(dirPath).isDirectory()) continue;
10262
10678
  } catch {
10263
10679
  continue;
10264
10680
  }
10265
10681
  let files;
10266
10682
  try {
10267
- files = fs18.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10683
+ files = fs20.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10268
10684
  } catch {
10269
10685
  continue;
10270
10686
  }
10271
10687
  const fallbackWorkingDir = decodeProjectDirName(dir);
10272
10688
  for (const file of files) {
10273
- const filePath = path20.join(dirPath, file);
10689
+ const filePath = path22.join(dirPath, file);
10274
10690
  if (sinceMs !== void 0) {
10275
10691
  try {
10276
- if (fs18.statSync(filePath).mtimeMs < sinceMs) continue;
10692
+ if (fs20.statSync(filePath).mtimeMs < sinceMs) continue;
10277
10693
  } catch {
10278
10694
  continue;
10279
10695
  }
@@ -10296,7 +10712,8 @@ var init_costSync = __esm({
10296
10712
  return [...combined.values()];
10297
10713
  }
10298
10714
  };
10299
- COST_SOURCES = [claudeSource, codexSource];
10715
+ COST_SOURCES = [claudeSource, codexSource, geminiSource, copilotSource];
10716
+ COST_BATCH_SIZE = 200;
10300
10717
  }
10301
10718
  });
10302
10719
 
@@ -10312,9 +10729,9 @@ __export(scan_watermark_exports, {
10312
10729
  tickForensicBroadcast: () => tickForensicBroadcast,
10313
10730
  tickScanWatcher: () => tickScanWatcher
10314
10731
  });
10315
- import fs19 from "fs";
10316
- import os18 from "os";
10317
- import path21 from "path";
10732
+ import fs21 from "fs";
10733
+ import os20 from "os";
10734
+ import path23 from "path";
10318
10735
  import readline from "readline";
10319
10736
  function freshWatermark() {
10320
10737
  return {
@@ -10327,7 +10744,7 @@ function freshWatermark() {
10327
10744
  function loadWatermark() {
10328
10745
  let raw;
10329
10746
  try {
10330
- raw = fs19.readFileSync(WATERMARK_FILE(), "utf-8");
10747
+ raw = fs21.readFileSync(WATERMARK_FILE(), "utf-8");
10331
10748
  } catch {
10332
10749
  return { status: "fresh", wm: freshWatermark() };
10333
10750
  }
@@ -10379,28 +10796,28 @@ function loadWatermark() {
10379
10796
  function saveWatermark(wm) {
10380
10797
  if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
10381
10798
  const target = WATERMARK_FILE();
10382
- const dir = path21.dirname(target);
10383
- if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
10799
+ const dir = path23.dirname(target);
10800
+ if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
10384
10801
  const tmp = target + ".tmp";
10385
- fs19.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
10386
- fs19.renameSync(tmp, target);
10802
+ fs21.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
10803
+ fs21.renameSync(tmp, target);
10387
10804
  }
10388
10805
  function listJsonlFiles() {
10389
10806
  const root = PROJECTS_DIR();
10390
- if (!fs19.existsSync(root)) return [];
10807
+ if (!fs21.existsSync(root)) return [];
10391
10808
  const out = [];
10392
- for (const entry of fs19.readdirSync(root, { withFileTypes: true })) {
10809
+ for (const entry of fs21.readdirSync(root, { withFileTypes: true })) {
10393
10810
  if (!entry.isDirectory()) continue;
10394
- const projectDir = path21.join(root, entry.name);
10811
+ const projectDir = path23.join(root, entry.name);
10395
10812
  let inner;
10396
10813
  try {
10397
- inner = fs19.readdirSync(projectDir, { withFileTypes: true });
10814
+ inner = fs21.readdirSync(projectDir, { withFileTypes: true });
10398
10815
  } catch {
10399
10816
  continue;
10400
10817
  }
10401
10818
  for (const file of inner) {
10402
10819
  if (file.isFile() && file.name.endsWith(".jsonl")) {
10403
- out.push(path21.join(projectDir, file.name));
10820
+ out.push(path23.join(projectDir, file.name));
10404
10821
  }
10405
10822
  }
10406
10823
  }
@@ -10408,7 +10825,7 @@ function listJsonlFiles() {
10408
10825
  }
10409
10826
  function fileSize(p) {
10410
10827
  try {
10411
- return fs19.statSync(p).size;
10828
+ return fs21.statSync(p).size;
10412
10829
  } catch {
10413
10830
  return 0;
10414
10831
  }
@@ -10416,7 +10833,7 @@ function fileSize(p) {
10416
10833
  async function scanDelta(filePath, fromByte, onLine) {
10417
10834
  const size = fileSize(filePath);
10418
10835
  if (size <= fromByte) return fromByte;
10419
- const stream = fs19.createReadStream(filePath, {
10836
+ const stream = fs21.createReadStream(filePath, {
10420
10837
  start: fromByte,
10421
10838
  end: size - 1,
10422
10839
  highWaterMark: 64 * 1024
@@ -10528,7 +10945,7 @@ async function tickForensicBroadcast(offsets) {
10528
10945
  continue;
10529
10946
  }
10530
10947
  if (size <= offset) continue;
10531
- const sessionId = path21.basename(file, ".jsonl");
10948
+ const sessionId = path23.basename(file, ".jsonl");
10532
10949
  const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
10533
10950
  out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
10534
10951
  });
@@ -10587,7 +11004,7 @@ function emptyTick(uploadAs) {
10587
11004
  function readRawWatermarkPreservingOffsets() {
10588
11005
  let raw;
10589
11006
  try {
10590
- raw = fs19.readFileSync(WATERMARK_FILE(), "utf-8");
11007
+ raw = fs21.readFileSync(WATERMARK_FILE(), "utf-8");
10591
11008
  } catch {
10592
11009
  return null;
10593
11010
  }
@@ -10621,13 +11038,13 @@ async function runActualTick(wm) {
10621
11038
  if (!known) {
10622
11039
  let mtimeMs = 0;
10623
11040
  try {
10624
- mtimeMs = fs19.statSync(filePath).mtime.getTime();
11041
+ mtimeMs = fs21.statSync(filePath).mtime.getTime();
10625
11042
  } catch {
10626
11043
  continue;
10627
11044
  }
10628
11045
  if (mtimeMs >= watermarkCreatedAt) {
10629
11046
  filesNew++;
10630
- const sessionId2 = path21.basename(filePath, ".jsonl");
11047
+ const sessionId2 = path23.basename(filePath, ".jsonl");
10631
11048
  const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
10632
11049
  totalToolCalls++;
10633
11050
  toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
@@ -10645,7 +11062,7 @@ async function runActualTick(wm) {
10645
11062
  filesSkipped++;
10646
11063
  continue;
10647
11064
  }
10648
- const sessionId = path21.basename(filePath, ".jsonl");
11065
+ const sessionId = path23.basename(filePath, ".jsonl");
10649
11066
  const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
10650
11067
  totalToolCalls++;
10651
11068
  toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
@@ -10673,8 +11090,8 @@ var init_scan_watermark = __esm({
10673
11090
  "use strict";
10674
11091
  init_dlp();
10675
11092
  init_dist();
10676
- PROJECTS_DIR = () => path21.join(os18.homedir(), ".claude", "projects");
10677
- WATERMARK_FILE = () => path21.join(os18.homedir(), ".node9", "scan-watermark.json");
11093
+ PROJECTS_DIR = () => path23.join(os20.homedir(), ".claude", "projects");
11094
+ WATERMARK_FILE = () => path23.join(os20.homedir(), ".node9", "scan-watermark.json");
10678
11095
  MAX_LINE_BYTES = 2 * 1024 * 1024;
10679
11096
  WATERMARK_SCHEMA_VERSION = 2;
10680
11097
  LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
@@ -10690,10 +11107,10 @@ __export(scan_upload_history_exports, {
10690
11107
  parseSinceCutoff: () => parseSinceCutoff,
10691
11108
  runUploadHistory: () => runUploadHistory
10692
11109
  });
10693
- import fs20 from "fs";
11110
+ import fs22 from "fs";
10694
11111
  import https from "https";
10695
- import os19 from "os";
10696
- import path22 from "path";
11112
+ import os21 from "os";
11113
+ import path24 from "path";
10697
11114
  import chalk4 from "chalk";
10698
11115
  function emptySignals2() {
10699
11116
  return {
@@ -10728,40 +11145,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
10728
11145
  return now.getTime() - 90 * 864e5;
10729
11146
  }
10730
11147
  function* iterateJsonlFiles(cutoffMs) {
10731
- const projectsDir = path22.join(os19.homedir(), ".claude", "projects");
11148
+ const projectsDir = path24.join(os21.homedir(), ".claude", "projects");
10732
11149
  let dirs;
10733
11150
  try {
10734
- dirs = fs20.readdirSync(projectsDir);
11151
+ dirs = fs22.readdirSync(projectsDir);
10735
11152
  } catch {
10736
11153
  return;
10737
11154
  }
10738
11155
  for (const dir of dirs) {
10739
- const dirPath = path22.join(projectsDir, dir);
11156
+ const dirPath = path24.join(projectsDir, dir);
10740
11157
  let stats;
10741
11158
  try {
10742
- stats = fs20.statSync(dirPath);
11159
+ stats = fs22.statSync(dirPath);
10743
11160
  } catch {
10744
11161
  continue;
10745
11162
  }
10746
11163
  if (!stats.isDirectory()) continue;
10747
11164
  let files;
10748
11165
  try {
10749
- files = fs20.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
11166
+ files = fs22.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10750
11167
  } catch {
10751
11168
  continue;
10752
11169
  }
10753
11170
  for (const file of files) {
10754
- const filePath = path22.join(dirPath, file);
11171
+ const filePath = path24.join(dirPath, file);
10755
11172
  let mtime = 0;
10756
11173
  try {
10757
- mtime = fs20.statSync(filePath).mtimeMs;
11174
+ mtime = fs22.statSync(filePath).mtimeMs;
10758
11175
  } catch {
10759
11176
  continue;
10760
11177
  }
10761
11178
  if (mtime < cutoffMs) continue;
10762
11179
  yield {
10763
11180
  filePath,
10764
- sessionId: path22.basename(file, ".jsonl"),
11181
+ sessionId: path24.basename(file, ".jsonl"),
10765
11182
  projectDir: dir
10766
11183
  };
10767
11184
  }
@@ -10815,7 +11232,9 @@ async function runUploadHistory(opts) {
10815
11232
  let filesScanned = 0;
10816
11233
  let linesParsed = 0;
10817
11234
  let linesSkipped = 0;
10818
- const dailyEntries = [];
11235
+ const dailyEntries = collectEntries(cutoffMs).filter(
11236
+ (e) => cutoffMs === 0 || Date.parse(e.date + "T00:00:00Z") >= cutoffMs
11237
+ );
10819
11238
  const liveLoopCfg = getConfig().policy.loopDetection;
10820
11239
  const loopCfg = {
10821
11240
  enabled: liveLoopCfg.enabled,
@@ -10827,7 +11246,7 @@ async function runUploadHistory(opts) {
10827
11246
  filesScanned++;
10828
11247
  let content;
10829
11248
  try {
10830
- content = fs20.readFileSync(filePath, "utf8");
11249
+ content = fs22.readFileSync(filePath, "utf8");
10831
11250
  } catch {
10832
11251
  continue;
10833
11252
  }
@@ -10877,14 +11296,6 @@ async function runUploadHistory(opts) {
10877
11296
  if (sf) findings.push(sf);
10878
11297
  }
10879
11298
  }
10880
- const fallbackWorkingDir = decodeProjectDirName(projectDir);
10881
- const dailyMap = parseJSONLFile(filePath, fallbackWorkingDir);
10882
- for (const entry of dailyMap.values()) {
10883
- if (cutoffMs > 0 && Date.parse(entry.date + "T00:00:00Z") < cutoffMs) {
10884
- continue;
10885
- }
10886
- dailyEntries.push(entry);
10887
- }
10888
11299
  }
10889
11300
  if (filesScanned === 0) {
10890
11301
  console.log(chalk4.yellow(" No JSONL files found in window. Nothing to upload."));
@@ -10909,10 +11320,10 @@ async function runUploadHistory(opts) {
10909
11320
  const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
10910
11321
  let username = "unknown";
10911
11322
  try {
10912
- username = os19.userInfo().username;
11323
+ username = os21.userInfo().username;
10913
11324
  } catch {
10914
11325
  }
10915
- const machineId = `${os19.hostname()}:${username}`;
11326
+ const machineId = `${os21.hostname()}:${username}`;
10916
11327
  await postJson(costUrl, creds.apiKey, {
10917
11328
  machineId,
10918
11329
  entries: dailyEntries
@@ -10986,9 +11397,9 @@ var init_scan_upload_history = __esm({
10986
11397
 
10987
11398
  // src/cli/commands/scan.ts
10988
11399
  import chalk5 from "chalk";
10989
- import fs21 from "fs";
10990
- import path23 from "path";
10991
- import os20 from "os";
11400
+ import fs23 from "fs";
11401
+ import path25 from "path";
11402
+ import os22 from "os";
10992
11403
  import stringWidth2 from "string-width";
10993
11404
  function claudeModelPrice(model) {
10994
11405
  const base = model.replace(/@.*$/, "").replace(/-\d{8}$/, "");
@@ -11215,14 +11626,14 @@ function buildRuleSources() {
11215
11626
  }
11216
11627
  function countScanFiles() {
11217
11628
  let total = 0;
11218
- const claudeDir = path23.join(os20.homedir(), ".claude", "projects");
11219
- if (fs21.existsSync(claudeDir)) {
11629
+ const claudeDir = path25.join(os22.homedir(), ".claude", "projects");
11630
+ if (fs23.existsSync(claudeDir)) {
11220
11631
  try {
11221
- for (const proj of fs21.readdirSync(claudeDir)) {
11222
- const p = path23.join(claudeDir, proj);
11632
+ for (const proj of fs23.readdirSync(claudeDir)) {
11633
+ const p = path25.join(claudeDir, proj);
11223
11634
  try {
11224
- if (!fs21.statSync(p).isDirectory()) continue;
11225
- total += fs21.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
11635
+ if (!fs23.statSync(p).isDirectory()) continue;
11636
+ total += fs23.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
11226
11637
  } catch {
11227
11638
  continue;
11228
11639
  }
@@ -11230,17 +11641,17 @@ function countScanFiles() {
11230
11641
  } catch {
11231
11642
  }
11232
11643
  }
11233
- const geminiDir = path23.join(os20.homedir(), ".gemini", "tmp");
11234
- if (fs21.existsSync(geminiDir)) {
11644
+ const geminiDir = path25.join(os22.homedir(), ".gemini", "tmp");
11645
+ if (fs23.existsSync(geminiDir)) {
11235
11646
  try {
11236
- for (const slug of fs21.readdirSync(geminiDir)) {
11237
- const p = path23.join(geminiDir, slug);
11647
+ for (const slug of fs23.readdirSync(geminiDir)) {
11648
+ const p = path25.join(geminiDir, slug);
11238
11649
  try {
11239
- if (!fs21.statSync(p).isDirectory()) continue;
11240
- const chatsDir = path23.join(p, "chats");
11241
- if (fs21.existsSync(chatsDir)) {
11650
+ if (!fs23.statSync(p).isDirectory()) continue;
11651
+ const chatsDir = path25.join(p, "chats");
11652
+ if (fs23.existsSync(chatsDir)) {
11242
11653
  try {
11243
- total += fs21.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
11654
+ total += fs23.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
11244
11655
  } catch {
11245
11656
  }
11246
11657
  }
@@ -11252,15 +11663,15 @@ function countScanFiles() {
11252
11663
  }
11253
11664
  }
11254
11665
  for (const surface of ["antigravity-cli", "antigravity-ide"]) {
11255
- const brainDir = path23.join(os20.homedir(), ".gemini", surface, "brain");
11256
- if (!fs21.existsSync(brainDir)) continue;
11666
+ const brainDir = path25.join(os22.homedir(), ".gemini", surface, "brain");
11667
+ if (!fs23.existsSync(brainDir)) continue;
11257
11668
  try {
11258
- for (const conv of fs21.readdirSync(brainDir)) {
11259
- const convPath = path23.join(brainDir, conv);
11669
+ for (const conv of fs23.readdirSync(brainDir)) {
11670
+ const convPath = path25.join(brainDir, conv);
11260
11671
  try {
11261
- if (!fs21.statSync(convPath).isDirectory()) continue;
11262
- const logsDir = path23.join(convPath, ".system_generated", "logs");
11263
- if (fs21.existsSync(path23.join(logsDir, "transcript_full.jsonl")) || fs21.existsSync(path23.join(logsDir, "transcript.jsonl"))) {
11672
+ if (!fs23.statSync(convPath).isDirectory()) continue;
11673
+ const logsDir = path25.join(convPath, ".system_generated", "logs");
11674
+ if (fs23.existsSync(path25.join(logsDir, "transcript_full.jsonl")) || fs23.existsSync(path25.join(logsDir, "transcript.jsonl"))) {
11264
11675
  total += 1;
11265
11676
  }
11266
11677
  } catch {
@@ -11270,31 +11681,31 @@ function countScanFiles() {
11270
11681
  } catch {
11271
11682
  }
11272
11683
  }
11273
- const copilotDir = path23.join(os20.homedir(), ".copilot", "session-state");
11274
- if (fs21.existsSync(copilotDir)) {
11684
+ const copilotDir = path25.join(os22.homedir(), ".copilot", "session-state");
11685
+ if (fs23.existsSync(copilotDir)) {
11275
11686
  try {
11276
- for (const sid of fs21.readdirSync(copilotDir)) {
11277
- if (fs21.existsSync(path23.join(copilotDir, sid, "events.jsonl"))) total += 1;
11687
+ for (const sid of fs23.readdirSync(copilotDir)) {
11688
+ if (fs23.existsSync(path25.join(copilotDir, sid, "events.jsonl"))) total += 1;
11278
11689
  }
11279
11690
  } catch {
11280
11691
  }
11281
11692
  }
11282
- const codexDir = path23.join(os20.homedir(), ".codex", "sessions");
11283
- if (fs21.existsSync(codexDir)) {
11693
+ const codexDir = path25.join(os22.homedir(), ".codex", "sessions");
11694
+ if (fs23.existsSync(codexDir)) {
11284
11695
  try {
11285
- for (const year of fs21.readdirSync(codexDir)) {
11286
- const yp = path23.join(codexDir, year);
11696
+ for (const year of fs23.readdirSync(codexDir)) {
11697
+ const yp = path25.join(codexDir, year);
11287
11698
  try {
11288
- if (!fs21.statSync(yp).isDirectory()) continue;
11289
- for (const month of fs21.readdirSync(yp)) {
11290
- const mp = path23.join(yp, month);
11699
+ if (!fs23.statSync(yp).isDirectory()) continue;
11700
+ for (const month of fs23.readdirSync(yp)) {
11701
+ const mp = path25.join(yp, month);
11291
11702
  try {
11292
- if (!fs21.statSync(mp).isDirectory()) continue;
11293
- for (const day of fs21.readdirSync(mp)) {
11294
- const dp = path23.join(mp, day);
11703
+ if (!fs23.statSync(mp).isDirectory()) continue;
11704
+ for (const day of fs23.readdirSync(mp)) {
11705
+ const dp = path25.join(mp, day);
11295
11706
  try {
11296
- if (!fs21.statSync(dp).isDirectory()) continue;
11297
- total += fs21.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
11707
+ if (!fs23.statSync(dp).isDirectory()) continue;
11708
+ total += fs23.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
11298
11709
  } catch {
11299
11710
  continue;
11300
11711
  }
@@ -11330,7 +11741,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
11330
11741
  const sessionId = file.replace(/\.jsonl$/, "");
11331
11742
  let raw;
11332
11743
  try {
11333
- raw = fs21.readFileSync(path23.join(projPath, file), "utf-8");
11744
+ raw = fs23.readFileSync(path25.join(projPath, file), "utf-8");
11334
11745
  } catch {
11335
11746
  return;
11336
11747
  }
@@ -11382,7 +11793,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
11382
11793
  if (block.type !== "tool_result") continue;
11383
11794
  const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
11384
11795
  if (filePath) {
11385
- const ext = path23.extname(filePath).toLowerCase();
11796
+ const ext = path25.extname(filePath).toLowerCase();
11386
11797
  if (CODE_EXTENSIONS.has(ext)) continue;
11387
11798
  }
11388
11799
  const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
@@ -11439,7 +11850,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
11439
11850
  const rawCmd = String(input.command ?? "").trimStart();
11440
11851
  if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
11441
11852
  const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
11442
- const inputFileExt = inputFilePath ? path23.extname(inputFilePath).toLowerCase() : "";
11853
+ const inputFileExt = inputFilePath ? path25.extname(inputFilePath).toLowerCase() : "";
11443
11854
  if (CODE_EXTENSIONS.has(inputFileExt)) continue;
11444
11855
  const dlpMatch = scanArgs(input);
11445
11856
  if (dlpMatch) {
@@ -11536,19 +11947,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
11536
11947
  }
11537
11948
  }
11538
11949
  function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
11539
- const projPath = path23.join(projectsDir, proj);
11950
+ const projPath = path25.join(projectsDir, proj);
11540
11951
  try {
11541
- if (!fs21.statSync(projPath).isDirectory()) return;
11952
+ if (!fs23.statSync(projPath).isDirectory()) return;
11542
11953
  } catch {
11543
11954
  return;
11544
11955
  }
11545
- const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(os20.homedir(), "~")).slice(
11956
+ const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(os22.homedir(), "~")).slice(
11546
11957
  0,
11547
11958
  40
11548
11959
  );
11549
11960
  let files;
11550
11961
  try {
11551
- files = fs21.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
11962
+ files = fs23.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
11552
11963
  } catch {
11553
11964
  return;
11554
11965
  }
@@ -11582,12 +11993,12 @@ function emptyClaudeScan() {
11582
11993
  };
11583
11994
  }
11584
11995
  function scanClaudeHistory(startDate, onProgress, onLine) {
11585
- const projectsDir = path23.join(os20.homedir(), ".claude", "projects");
11996
+ const projectsDir = path25.join(os22.homedir(), ".claude", "projects");
11586
11997
  const result = emptyClaudeScan();
11587
- if (!fs21.existsSync(projectsDir)) return result;
11998
+ if (!fs23.existsSync(projectsDir)) return result;
11588
11999
  let projDirs;
11589
12000
  try {
11590
- projDirs = fs21.readdirSync(projectsDir);
12001
+ projDirs = fs23.readdirSync(projectsDir);
11591
12002
  } catch {
11592
12003
  return result;
11593
12004
  }
@@ -11608,7 +12019,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
11608
12019
  return result;
11609
12020
  }
11610
12021
  function scanGeminiHistory(startDate, onProgress, onLine) {
11611
- const tmpDir = path23.join(os20.homedir(), ".gemini", "tmp");
12022
+ const tmpDir = path25.join(os22.homedir(), ".gemini", "tmp");
11612
12023
  const result = {
11613
12024
  filesScanned: 0,
11614
12025
  sessions: 0,
@@ -11623,33 +12034,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
11623
12034
  sessionsWithEarlySecrets: 0
11624
12035
  };
11625
12036
  const dedup = emptyScanDedup();
11626
- if (!fs21.existsSync(tmpDir)) return result;
12037
+ if (!fs23.existsSync(tmpDir)) return result;
11627
12038
  let slugDirs;
11628
12039
  try {
11629
- slugDirs = fs21.readdirSync(tmpDir);
12040
+ slugDirs = fs23.readdirSync(tmpDir);
11630
12041
  } catch {
11631
12042
  return result;
11632
12043
  }
11633
12044
  const ruleSources = buildRuleSources();
11634
12045
  for (const slug of slugDirs) {
11635
- const slugPath = path23.join(tmpDir, slug);
12046
+ const slugPath = path25.join(tmpDir, slug);
11636
12047
  try {
11637
- if (!fs21.statSync(slugPath).isDirectory()) continue;
12048
+ if (!fs23.statSync(slugPath).isDirectory()) continue;
11638
12049
  } catch {
11639
12050
  continue;
11640
12051
  }
11641
12052
  let projLabel = stripTerminalEscapes(slug).slice(0, 40);
11642
12053
  try {
11643
12054
  projLabel = stripTerminalEscapes(
11644
- fs21.readFileSync(path23.join(slugPath, ".project_root"), "utf-8").trim()
11645
- ).replace(os20.homedir(), "~").slice(0, 40);
12055
+ fs23.readFileSync(path25.join(slugPath, ".project_root"), "utf-8").trim()
12056
+ ).replace(os22.homedir(), "~").slice(0, 40);
11646
12057
  } catch {
11647
12058
  }
11648
- const chatsDir = path23.join(slugPath, "chats");
11649
- if (!fs21.existsSync(chatsDir)) continue;
12059
+ const chatsDir = path25.join(slugPath, "chats");
12060
+ if (!fs23.existsSync(chatsDir)) continue;
11650
12061
  let chatFiles;
11651
12062
  try {
11652
- chatFiles = fs21.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
12063
+ chatFiles = fs23.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
11653
12064
  } catch {
11654
12065
  continue;
11655
12066
  }
@@ -11659,7 +12070,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
11659
12070
  const sessionId = chatFile.replace(/\.json$/, "");
11660
12071
  let raw;
11661
12072
  try {
11662
- raw = fs21.readFileSync(path23.join(chatsDir, chatFile), "utf-8");
12073
+ raw = fs23.readFileSync(path25.join(chatsDir, chatFile), "utf-8");
11663
12074
  } catch {
11664
12075
  continue;
11665
12076
  }
@@ -11821,13 +12232,13 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
11821
12232
  return result;
11822
12233
  }
11823
12234
  function antigravityBrainDirs() {
11824
- return ["antigravity-cli", "antigravity-ide"].map((surface) => path23.join(os20.homedir(), ".gemini", surface, "brain")).filter((p) => fs21.existsSync(p));
12235
+ return ["antigravity-cli", "antigravity-ide"].map((surface) => path25.join(os22.homedir(), ".gemini", surface, "brain")).filter((p) => fs23.existsSync(p));
11825
12236
  }
11826
12237
  function antigravityTranscriptPath(convPath) {
11827
- const logsDir = path23.join(convPath, ".system_generated", "logs");
12238
+ const logsDir = path25.join(convPath, ".system_generated", "logs");
11828
12239
  for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
11829
- const p = path23.join(logsDir, name);
11830
- if (fs21.existsSync(p)) return p;
12240
+ const p = path25.join(logsDir, name);
12241
+ if (fs23.existsSync(p)) return p;
11831
12242
  }
11832
12243
  return null;
11833
12244
  }
@@ -11853,14 +12264,14 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
11853
12264
  for (const brainDir of brainDirs) {
11854
12265
  let convDirs;
11855
12266
  try {
11856
- convDirs = fs21.readdirSync(brainDir);
12267
+ convDirs = fs23.readdirSync(brainDir);
11857
12268
  } catch {
11858
12269
  continue;
11859
12270
  }
11860
12271
  for (const conv of convDirs) {
11861
- const convPath = path23.join(brainDir, conv);
12272
+ const convPath = path25.join(brainDir, conv);
11862
12273
  try {
11863
- if (!fs21.statSync(convPath).isDirectory()) continue;
12274
+ if (!fs23.statSync(convPath).isDirectory()) continue;
11864
12275
  } catch {
11865
12276
  continue;
11866
12277
  }
@@ -11870,7 +12281,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
11870
12281
  onProgress?.(result.filesScanned);
11871
12282
  let raw;
11872
12283
  try {
11873
- raw = fs21.readFileSync(transcriptFile, "utf-8");
12284
+ raw = fs23.readFileSync(transcriptFile, "utf-8");
11874
12285
  } catch {
11875
12286
  continue;
11876
12287
  }
@@ -11927,7 +12338,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
11927
12338
  result.bashCalls++;
11928
12339
  const cwd = String(input.cwd ?? "");
11929
12340
  if (cwd && projLabel === conv.slice(0, 8)) {
11930
- projLabel = stripTerminalEscapes(cwd).replace(os20.homedir(), "~").slice(0, 40);
12341
+ projLabel = stripTerminalEscapes(cwd).replace(os22.homedir(), "~").slice(0, 40);
11931
12342
  }
11932
12343
  }
11933
12344
  const rawCmd = String(input.command ?? "").trimStart();
@@ -12027,7 +12438,7 @@ function scanAntigravityHistory(startDate, onProgress, onLine) {
12027
12438
  return result;
12028
12439
  }
12029
12440
  function scanCopilotHistory(startDate, onProgress, onLine) {
12030
- const sessionDir = path23.join(os20.homedir(), ".copilot", "session-state");
12441
+ const sessionDir = path25.join(os22.homedir(), ".copilot", "session-state");
12031
12442
  const result = {
12032
12443
  filesScanned: 0,
12033
12444
  sessions: 0,
@@ -12043,22 +12454,22 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
12043
12454
  sessionsWithEarlySecrets: 0
12044
12455
  };
12045
12456
  const dedup = emptyScanDedup();
12046
- if (!fs21.existsSync(sessionDir)) return result;
12457
+ if (!fs23.existsSync(sessionDir)) return result;
12047
12458
  let sessionIds;
12048
12459
  try {
12049
- sessionIds = fs21.readdirSync(sessionDir);
12460
+ sessionIds = fs23.readdirSync(sessionDir);
12050
12461
  } catch {
12051
12462
  return result;
12052
12463
  }
12053
12464
  const ruleSources = buildRuleSources();
12054
12465
  for (const sessionId of sessionIds) {
12055
- const eventsPath = path23.join(sessionDir, sessionId, "events.jsonl");
12056
- if (!fs21.existsSync(eventsPath)) continue;
12466
+ const eventsPath = path25.join(sessionDir, sessionId, "events.jsonl");
12467
+ if (!fs23.existsSync(eventsPath)) continue;
12057
12468
  result.filesScanned++;
12058
12469
  onProgress?.(result.filesScanned);
12059
12470
  let raw;
12060
12471
  try {
12061
- raw = fs21.readFileSync(eventsPath, "utf-8");
12472
+ raw = fs23.readFileSync(eventsPath, "utf-8");
12062
12473
  } catch {
12063
12474
  continue;
12064
12475
  }
@@ -12078,7 +12489,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
12078
12489
  if (ev.type === "session.start") {
12079
12490
  const cwd = ev.data?.context?.cwd;
12080
12491
  if (typeof cwd === "string" && cwd) {
12081
- projLabel = stripTerminalEscapes(cwd).replace(os20.homedir(), "~").slice(0, 40);
12492
+ projLabel = stripTerminalEscapes(cwd).replace(os22.homedir(), "~").slice(0, 40);
12082
12493
  }
12083
12494
  continue;
12084
12495
  }
@@ -12210,7 +12621,7 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
12210
12621
  return result;
12211
12622
  }
12212
12623
  function scanCodexHistory(startDate, onProgress, onLine) {
12213
- const sessionsBase = path23.join(os20.homedir(), ".codex", "sessions");
12624
+ const sessionsBase = path25.join(os22.homedir(), ".codex", "sessions");
12214
12625
  const result = {
12215
12626
  filesScanned: 0,
12216
12627
  sessions: 0,
@@ -12225,32 +12636,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
12225
12636
  sessionsWithEarlySecrets: 0
12226
12637
  };
12227
12638
  const dedup = emptyScanDedup();
12228
- if (!fs21.existsSync(sessionsBase)) return result;
12639
+ if (!fs23.existsSync(sessionsBase)) return result;
12229
12640
  const jsonlFiles = [];
12230
12641
  try {
12231
- for (const year of fs21.readdirSync(sessionsBase)) {
12232
- const yearPath = path23.join(sessionsBase, year);
12642
+ for (const year of fs23.readdirSync(sessionsBase)) {
12643
+ const yearPath = path25.join(sessionsBase, year);
12233
12644
  try {
12234
- if (!fs21.statSync(yearPath).isDirectory()) continue;
12645
+ if (!fs23.statSync(yearPath).isDirectory()) continue;
12235
12646
  } catch {
12236
12647
  continue;
12237
12648
  }
12238
- for (const month of fs21.readdirSync(yearPath)) {
12239
- const monthPath = path23.join(yearPath, month);
12649
+ for (const month of fs23.readdirSync(yearPath)) {
12650
+ const monthPath = path25.join(yearPath, month);
12240
12651
  try {
12241
- if (!fs21.statSync(monthPath).isDirectory()) continue;
12652
+ if (!fs23.statSync(monthPath).isDirectory()) continue;
12242
12653
  } catch {
12243
12654
  continue;
12244
12655
  }
12245
- for (const day of fs21.readdirSync(monthPath)) {
12246
- const dayPath = path23.join(monthPath, day);
12656
+ for (const day of fs23.readdirSync(monthPath)) {
12657
+ const dayPath = path25.join(monthPath, day);
12247
12658
  try {
12248
- if (!fs21.statSync(dayPath).isDirectory()) continue;
12659
+ if (!fs23.statSync(dayPath).isDirectory()) continue;
12249
12660
  } catch {
12250
12661
  continue;
12251
12662
  }
12252
- for (const file of fs21.readdirSync(dayPath)) {
12253
- if (file.endsWith(".jsonl")) jsonlFiles.push(path23.join(dayPath, file));
12663
+ for (const file of fs23.readdirSync(dayPath)) {
12664
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path25.join(dayPath, file));
12254
12665
  }
12255
12666
  }
12256
12667
  }
@@ -12264,7 +12675,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
12264
12675
  onProgress?.(result.filesScanned);
12265
12676
  let lines;
12266
12677
  try {
12267
- lines = fs21.readFileSync(filePath, "utf-8").split("\n");
12678
+ lines = fs23.readFileSync(filePath, "utf-8").split("\n");
12268
12679
  } catch {
12269
12680
  continue;
12270
12681
  }
@@ -12290,7 +12701,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
12290
12701
  sessionId = String(payload["id"] ?? filePath);
12291
12702
  startTime = String(payload["timestamp"] ?? "");
12292
12703
  const cwd = String(payload["cwd"] ?? "");
12293
- projLabel = stripTerminalEscapes(cwd.replace(os20.homedir(), "~")).slice(0, 40);
12704
+ projLabel = stripTerminalEscapes(cwd.replace(os22.homedir(), "~")).slice(0, 40);
12294
12705
  continue;
12295
12706
  }
12296
12707
  if (entry.type === "event_msg" && payload["type"] === "token_count") {
@@ -12443,17 +12854,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
12443
12854
  return result;
12444
12855
  }
12445
12856
  function scanShellConfig() {
12446
- const home = os20.homedir();
12857
+ const home = os22.homedir();
12447
12858
  const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
12448
- (f) => path23.join(home, f)
12859
+ (f) => path25.join(home, f)
12449
12860
  );
12450
12861
  const findings = [];
12451
12862
  const seen = /* @__PURE__ */ new Set();
12452
12863
  for (const filePath of configFiles) {
12453
- if (!fs21.existsSync(filePath)) continue;
12864
+ if (!fs23.existsSync(filePath)) continue;
12454
12865
  let lines;
12455
12866
  try {
12456
- lines = fs21.readFileSync(filePath, "utf-8").split("\n");
12867
+ lines = fs23.readFileSync(filePath, "utf-8").split("\n");
12457
12868
  } catch {
12458
12869
  continue;
12459
12870
  }
@@ -13259,7 +13670,7 @@ function registerScanCommand(program2) {
13259
13670
  if (!drillDown) {
13260
13671
  const useInk2 = !options.classic;
13261
13672
  if (useInk2) {
13262
- const scanInkPath = path23.join(__dirname, "scan-ink.mjs");
13673
+ const scanInkPath = path25.join(__dirname, "scan-ink.mjs");
13263
13674
  const dynamicImport = new Function("id", "return import(id)");
13264
13675
  const mod = await dynamicImport(`file://${scanInkPath}`);
13265
13676
  const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
@@ -13680,8 +14091,8 @@ var init_suggestion_tracker = __esm({
13680
14091
  });
13681
14092
 
13682
14093
  // src/daemon/taint-store.ts
13683
- import fs22 from "fs";
13684
- import path24 from "path";
14094
+ import fs24 from "fs";
14095
+ import path26 from "path";
13685
14096
  var DEFAULT_TTL_MS, TaintStore;
13686
14097
  var init_taint_store = __esm({
13687
14098
  "src/daemon/taint-store.ts"() {
@@ -13750,9 +14161,9 @@ var init_taint_store = __esm({
13750
14161
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
13751
14162
  _resolve(filePath) {
13752
14163
  try {
13753
- return fs22.realpathSync.native(path24.resolve(filePath));
14164
+ return fs24.realpathSync.native(path26.resolve(filePath));
13754
14165
  } catch {
13755
- return path24.resolve(filePath);
14166
+ return path26.resolve(filePath);
13756
14167
  }
13757
14168
  }
13758
14169
  };
@@ -13869,14 +14280,14 @@ var init_session_history = __esm({
13869
14280
 
13870
14281
  // src/daemon/state.ts
13871
14282
  import net2 from "net";
13872
- import fs23 from "fs";
13873
- import path25 from "path";
13874
- import os21 from "os";
14283
+ import fs25 from "fs";
14284
+ import path27 from "path";
14285
+ import os23 from "os";
13875
14286
  import { randomUUID as randomUUID3 } from "crypto";
13876
14287
  function loadInsightCounts() {
13877
14288
  try {
13878
- if (!fs23.existsSync(INSIGHT_COUNTS_FILE)) return;
13879
- const data = JSON.parse(fs23.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
14289
+ if (!fs25.existsSync(INSIGHT_COUNTS_FILE)) return;
14290
+ const data = JSON.parse(fs25.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
13880
14291
  for (const [tool, count] of Object.entries(data)) {
13881
14292
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
13882
14293
  }
@@ -13915,23 +14326,23 @@ function markRejectionHandlerRegistered() {
13915
14326
  daemonRejectionHandlerRegistered = true;
13916
14327
  }
13917
14328
  function atomicWriteSync2(filePath, data, options) {
13918
- const dir = path25.dirname(filePath);
13919
- if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
14329
+ const dir = path27.dirname(filePath);
14330
+ if (!fs25.existsSync(dir)) fs25.mkdirSync(dir, { recursive: true });
13920
14331
  const tmpPath = `${filePath}.${randomUUID3()}.tmp`;
13921
14332
  try {
13922
- fs23.writeFileSync(tmpPath, data, options);
14333
+ fs25.writeFileSync(tmpPath, data, options);
13923
14334
  } catch (err2) {
13924
14335
  try {
13925
- fs23.unlinkSync(tmpPath);
14336
+ fs25.unlinkSync(tmpPath);
13926
14337
  } catch {
13927
14338
  }
13928
14339
  throw err2;
13929
14340
  }
13930
14341
  try {
13931
- fs23.renameSync(tmpPath, filePath);
14342
+ fs25.renameSync(tmpPath, filePath);
13932
14343
  } catch (err2) {
13933
14344
  try {
13934
- fs23.unlinkSync(tmpPath);
14345
+ fs25.unlinkSync(tmpPath);
13935
14346
  } catch {
13936
14347
  }
13937
14348
  throw err2;
@@ -13955,16 +14366,16 @@ function appendAuditLog(data) {
13955
14366
  decision: data.decision,
13956
14367
  source: "daemon"
13957
14368
  };
13958
- const dir = path25.dirname(AUDIT_LOG_FILE);
13959
- if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
13960
- fs23.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
14369
+ const dir = path27.dirname(AUDIT_LOG_FILE);
14370
+ if (!fs25.existsSync(dir)) fs25.mkdirSync(dir, { recursive: true });
14371
+ fs25.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
13961
14372
  } catch {
13962
14373
  }
13963
14374
  }
13964
14375
  function getAuditHistory(limit = 20) {
13965
14376
  try {
13966
- if (!fs23.existsSync(AUDIT_LOG_FILE)) return [];
13967
- const lines = fs23.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
14377
+ if (!fs25.existsSync(AUDIT_LOG_FILE)) return [];
14378
+ const lines = fs25.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
13968
14379
  if (lines.length === 1 && lines[0] === "") return [];
13969
14380
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
13970
14381
  } catch {
@@ -13973,7 +14384,7 @@ function getAuditHistory(limit = 20) {
13973
14384
  }
13974
14385
  function getOrgName() {
13975
14386
  try {
13976
- if (fs23.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
14387
+ if (fs25.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
13977
14388
  } catch {
13978
14389
  }
13979
14390
  return null;
@@ -13981,8 +14392,8 @@ function getOrgName() {
13981
14392
  function writeGlobalSetting(key, value) {
13982
14393
  let config = {};
13983
14394
  try {
13984
- if (fs23.existsSync(GLOBAL_CONFIG_FILE)) {
13985
- config = JSON.parse(fs23.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
14395
+ if (fs25.existsSync(GLOBAL_CONFIG_FILE)) {
14396
+ config = JSON.parse(fs25.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
13986
14397
  }
13987
14398
  } catch {
13988
14399
  }
@@ -13994,8 +14405,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
13994
14405
  try {
13995
14406
  let trust = { entries: [] };
13996
14407
  try {
13997
- if (fs23.existsSync(TRUST_FILE2))
13998
- trust = JSON.parse(fs23.readFileSync(TRUST_FILE2, "utf-8"));
14408
+ if (fs25.existsSync(TRUST_FILE2))
14409
+ trust = JSON.parse(fs25.readFileSync(TRUST_FILE2, "utf-8"));
13999
14410
  } catch {
14000
14411
  }
14001
14412
  trust.entries = trust.entries.filter(
@@ -14012,8 +14423,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
14012
14423
  }
14013
14424
  function readPersistentDecisions() {
14014
14425
  try {
14015
- if (fs23.existsSync(DECISIONS_FILE)) {
14016
- return JSON.parse(fs23.readFileSync(DECISIONS_FILE, "utf-8"));
14426
+ if (fs25.existsSync(DECISIONS_FILE)) {
14427
+ return JSON.parse(fs25.readFileSync(DECISIONS_FILE, "utf-8"));
14017
14428
  }
14018
14429
  } catch {
14019
14430
  }
@@ -14030,7 +14441,7 @@ function writePersistentDecision(toolName, decision) {
14030
14441
  function readBody(req) {
14031
14442
  return new Promise((resolve) => {
14032
14443
  let body = "";
14033
- req.on("data", (chunk) => body += chunk);
14444
+ req.on("data", (chunk2) => body += chunk2);
14034
14445
  req.on("end", () => resolve(body));
14035
14446
  });
14036
14447
  }
@@ -14041,7 +14452,7 @@ function estimateToolCost(tool, args) {
14041
14452
  const filePath = a.file_path ?? a.path;
14042
14453
  if (filePath) {
14043
14454
  try {
14044
- const bytes = fs23.statSync(filePath).size;
14455
+ const bytes = fs25.statSync(filePath).size;
14045
14456
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
14046
14457
  } catch {
14047
14458
  }
@@ -14112,7 +14523,7 @@ function abandonPending() {
14112
14523
  });
14113
14524
  if (autoStarted) {
14114
14525
  try {
14115
- fs23.unlinkSync(DAEMON_PID_FILE);
14526
+ fs25.unlinkSync(DAEMON_PID_FILE);
14116
14527
  } catch {
14117
14528
  }
14118
14529
  setTimeout(() => {
@@ -14123,8 +14534,8 @@ function abandonPending() {
14123
14534
  }
14124
14535
  function logActivitySocket(msg) {
14125
14536
  try {
14126
- fs23.appendFileSync(
14127
- path25.join(homeDir, ".node9", "hook-debug.log"),
14537
+ fs25.appendFileSync(
14538
+ path27.join(homeDir, ".node9", "hook-debug.log"),
14128
14539
  `[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
14129
14540
  `
14130
14541
  );
@@ -14146,13 +14557,13 @@ function shouldRebind(now = Date.now()) {
14146
14557
  function startActivitySocket() {
14147
14558
  bindActivitySocket();
14148
14559
  activityHealthInterval = setInterval(() => {
14149
- if (!fs23.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
14560
+ if (!fs25.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
14150
14561
  }, ACTIVITY_HEALTH_PROBE_MS);
14151
14562
  activityHealthInterval.unref();
14152
14563
  process.on("exit", () => {
14153
14564
  if (activityHealthInterval) clearInterval(activityHealthInterval);
14154
14565
  try {
14155
- fs23.unlinkSync(ACTIVITY_SOCKET_PATH2);
14566
+ fs25.unlinkSync(ACTIVITY_SOCKET_PATH2);
14156
14567
  } catch {
14157
14568
  }
14158
14569
  });
@@ -14180,20 +14591,20 @@ function attemptRebind(reason) {
14180
14591
  }
14181
14592
  function bindActivitySocket() {
14182
14593
  try {
14183
- fs23.unlinkSync(ACTIVITY_SOCKET_PATH2);
14594
+ fs25.unlinkSync(ACTIVITY_SOCKET_PATH2);
14184
14595
  } catch {
14185
14596
  }
14186
14597
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
14187
14598
  const unixServer = net2.createServer((socket) => {
14188
14599
  const chunks = [];
14189
14600
  let bytesReceived = 0;
14190
- socket.on("data", (chunk) => {
14191
- bytesReceived += chunk.length;
14601
+ socket.on("data", (chunk2) => {
14602
+ bytesReceived += chunk2.length;
14192
14603
  if (bytesReceived > ACTIVITY_MAX_BYTES) {
14193
14604
  socket.destroy();
14194
14605
  return;
14195
14606
  }
14196
- chunks.push(chunk);
14607
+ chunks.push(chunk2);
14197
14608
  });
14198
14609
  socket.on("end", () => {
14199
14610
  try {
@@ -14293,14 +14704,14 @@ var init_state2 = __esm({
14293
14704
  init_taint_store();
14294
14705
  init_session_counters();
14295
14706
  init_session_history();
14296
- homeDir = os21.homedir();
14297
- DAEMON_PID_FILE = path25.join(homeDir, ".node9", "daemon.pid");
14298
- DECISIONS_FILE = path25.join(homeDir, ".node9", "decisions.json");
14299
- AUDIT_LOG_FILE = path25.join(homeDir, ".node9", "audit.log");
14300
- TRUST_FILE2 = path25.join(homeDir, ".node9", "trust.json");
14301
- GLOBAL_CONFIG_FILE = path25.join(homeDir, ".node9", "config.json");
14302
- CREDENTIALS_FILE = path25.join(homeDir, ".node9", "credentials.json");
14303
- INSIGHT_COUNTS_FILE = path25.join(homeDir, ".node9", "insight-counts.json");
14707
+ homeDir = os23.homedir();
14708
+ DAEMON_PID_FILE = path27.join(homeDir, ".node9", "daemon.pid");
14709
+ DECISIONS_FILE = path27.join(homeDir, ".node9", "decisions.json");
14710
+ AUDIT_LOG_FILE = path27.join(homeDir, ".node9", "audit.log");
14711
+ TRUST_FILE2 = path27.join(homeDir, ".node9", "trust.json");
14712
+ GLOBAL_CONFIG_FILE = path27.join(homeDir, ".node9", "config.json");
14713
+ CREDENTIALS_FILE = path27.join(homeDir, ".node9", "credentials.json");
14714
+ INSIGHT_COUNTS_FILE = path27.join(homeDir, ".node9", "insight-counts.json");
14304
14715
  pending = /* @__PURE__ */ new Map();
14305
14716
  sseClients = /* @__PURE__ */ new Set();
14306
14717
  suggestionTracker = new SuggestionTracker(3);
@@ -14317,7 +14728,7 @@ var init_state2 = __esm({
14317
14728
  "2h": 2 * 60 * 6e4
14318
14729
  };
14319
14730
  autoStarted = process.env.NODE9_AUTO_STARTED === "1";
14320
- ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path25.join(os21.tmpdir(), "node9-activity.sock");
14731
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path27.join(os23.tmpdir(), "node9-activity.sock");
14321
14732
  ACTIVITY_RING_SIZE = 100;
14322
14733
  activityRing = [];
14323
14734
  LARGE_RESPONSE_RING_SIZE = 20;
@@ -14356,10 +14767,10 @@ var init_state2 = __esm({
14356
14767
  });
14357
14768
 
14358
14769
  // src/daemon/sync.ts
14359
- import fs24 from "fs";
14770
+ import fs26 from "fs";
14360
14771
  import https2 from "https";
14361
- import os22 from "os";
14362
- import path26 from "path";
14772
+ import os24 from "os";
14773
+ import path28 from "path";
14363
14774
  function emptySignals3() {
14364
14775
  return {
14365
14776
  dlpFindings: 0,
@@ -14399,8 +14810,8 @@ function readCredentials() {
14399
14810
  };
14400
14811
  }
14401
14812
  try {
14402
- const credPath = path26.join(os22.homedir(), ".node9", "credentials.json");
14403
- const creds = JSON.parse(fs24.readFileSync(credPath, "utf-8"));
14813
+ const credPath = path28.join(os24.homedir(), ".node9", "credentials.json");
14814
+ const creds = JSON.parse(fs26.readFileSync(credPath, "utf-8"));
14404
14815
  const profileName = process.env.NODE9_PROFILE ?? "default";
14405
14816
  const profile = creds[profileName];
14406
14817
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -14426,7 +14837,7 @@ function readCredentials() {
14426
14837
  }
14427
14838
  function readCachedEtag() {
14428
14839
  try {
14429
- const raw = JSON.parse(fs24.readFileSync(rulesCacheFile(), "utf-8"));
14840
+ const raw = JSON.parse(fs26.readFileSync(rulesCacheFile(), "utf-8"));
14430
14841
  return typeof raw.etag === "string" ? raw.etag : void 0;
14431
14842
  } catch {
14432
14843
  return void 0;
@@ -14456,7 +14867,7 @@ function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
14456
14867
  return;
14457
14868
  }
14458
14869
  const chunks = [];
14459
- res.on("data", (chunk) => chunks.push(chunk));
14870
+ res.on("data", (chunk2) => chunks.push(chunk2));
14460
14871
  res.on("end", () => {
14461
14872
  if (res.statusCode !== 200) {
14462
14873
  reject(new Error(`API returned ${res.statusCode ?? "unknown"}`));
@@ -14487,9 +14898,9 @@ function extractRules(body) {
14487
14898
  return [];
14488
14899
  }
14489
14900
  function writeCache2(cache) {
14490
- const dir = path26.dirname(rulesCacheFile());
14491
- if (!fs24.existsSync(dir)) fs24.mkdirSync(dir, { recursive: true });
14492
- fs24.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
14901
+ const dir = path28.dirname(rulesCacheFile());
14902
+ if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
14903
+ fs26.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
14493
14904
  }
14494
14905
  async function syncOnce() {
14495
14906
  const creds = readCredentials();
@@ -14646,7 +15057,7 @@ async function runCloudSync() {
14646
15057
  }
14647
15058
  function getCloudSyncStatus() {
14648
15059
  try {
14649
- const raw = JSON.parse(fs24.readFileSync(rulesCacheFile(), "utf-8"));
15060
+ const raw = JSON.parse(fs26.readFileSync(rulesCacheFile(), "utf-8"));
14650
15061
  if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
14651
15062
  return {
14652
15063
  cached: true,
@@ -14663,7 +15074,7 @@ function getCloudSyncStatus() {
14663
15074
  }
14664
15075
  function getCloudRules() {
14665
15076
  try {
14666
- const raw = JSON.parse(fs24.readFileSync(rulesCacheFile(), "utf-8"));
15077
+ const raw = JSON.parse(fs26.readFileSync(rulesCacheFile(), "utf-8"));
14667
15078
  return Array.isArray(raw.rules) ? raw.rules : null;
14668
15079
  } catch {
14669
15080
  return null;
@@ -14719,7 +15130,7 @@ var init_sync = __esm({
14719
15130
  loop: "loops",
14720
15131
  "long-output-redacted": "longOutputRedactions"
14721
15132
  };
14722
- rulesCacheFile = () => path26.join(os22.homedir(), ".node9", "rules-cache.json");
15133
+ rulesCacheFile = () => path28.join(os24.homedir(), ".node9", "rules-cache.json");
14723
15134
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
14724
15135
  DEFAULT_INTERVAL_HOURS = 5;
14725
15136
  MIN_INTERVAL_HOURS = 1;
@@ -14742,26 +15153,26 @@ __export(audit_shipper_exports, {
14742
15153
  startAuditShipper: () => startAuditShipper,
14743
15154
  writeWatermark: () => writeWatermark
14744
15155
  });
14745
- import fs25 from "fs";
14746
- import path27 from "path";
14747
- import os23 from "os";
15156
+ import fs27 from "fs";
15157
+ import path29 from "path";
15158
+ import os25 from "os";
14748
15159
  import crypto5 from "crypto";
14749
15160
  function fileSignature(filePath) {
14750
- const fd = fs25.openSync(filePath, "r");
15161
+ const fd = fs27.openSync(filePath, "r");
14751
15162
  try {
14752
15163
  const buf = Buffer.alloc(512);
14753
- const read = fs25.readSync(fd, buf, 0, 512, 0);
15164
+ const read = fs27.readSync(fd, buf, 0, 512, 0);
14754
15165
  const slice = buf.subarray(0, read);
14755
15166
  const nl = slice.indexOf(10);
14756
15167
  const firstLine = nl === -1 ? slice : slice.subarray(0, nl);
14757
15168
  return crypto5.createHash("sha256").update(firstLine).digest("hex").slice(0, 16);
14758
15169
  } finally {
14759
- fs25.closeSync(fd);
15170
+ fs27.closeSync(fd);
14760
15171
  }
14761
15172
  }
14762
15173
  function readWatermark(watermarkPath) {
14763
15174
  try {
14764
- const raw = JSON.parse(fs25.readFileSync(watermarkPath, "utf-8"));
15175
+ const raw = JSON.parse(fs27.readFileSync(watermarkPath, "utf-8"));
14765
15176
  if (typeof raw.fileSig === "string" && typeof raw.offset === "number" && raw.offset >= 0)
14766
15177
  return raw;
14767
15178
  } catch {
@@ -14770,13 +15181,13 @@ function readWatermark(watermarkPath) {
14770
15181
  }
14771
15182
  function writeWatermark(watermarkPath, wm) {
14772
15183
  const tmp = `${watermarkPath}.tmp`;
14773
- fs25.writeFileSync(tmp, JSON.stringify(wm));
14774
- fs25.renameSync(tmp, watermarkPath);
15184
+ fs27.writeFileSync(tmp, JSON.stringify(wm));
15185
+ fs27.renameSync(tmp, watermarkPath);
14775
15186
  }
14776
- function buildWireRows(chunk) {
14777
- const lastNl = chunk.lastIndexOf(10);
15187
+ function buildWireRows(chunk2) {
15188
+ const lastNl = chunk2.lastIndexOf(10);
14778
15189
  if (lastNl === -1) return { rows: [], consumed: 0 };
14779
- const complete = chunk.subarray(0, lastNl + 1);
15190
+ const complete = chunk2.subarray(0, lastNl + 1);
14780
15191
  const rows = [];
14781
15192
  for (const line of complete.toString("utf-8").split("\n")) {
14782
15193
  if (!line.trim()) continue;
@@ -14810,7 +15221,10 @@ function buildWireRows(chunk) {
14810
15221
  ...typeof parsed.sessionId === "string" ? { sessionId: parsed.sessionId } : {},
14811
15222
  ...typeof parsed.dlpPattern === "string" ? { dlpPattern: parsed.dlpPattern } : {},
14812
15223
  ...typeof parsed.dlpSample === "string" ? { dlpSample: parsed.dlpSample } : {},
14813
- ...cloudRequestId ? { cloudRequestId } : {}
15224
+ ...cloudRequestId ? { cloudRequestId } : {},
15225
+ ...typeof parsed.workingDir === "string" ? { workingDir: parsed.workingDir } : {},
15226
+ ...typeof parsed.platform === "string" ? { platform: parsed.platform } : {},
15227
+ ...typeof parsed.shellType === "string" ? { shellType: parsed.shellType } : {}
14814
15228
  });
14815
15229
  }
14816
15230
  return { rows, consumed: lastNl + 1 };
@@ -14839,11 +15253,11 @@ async function shipOnce(deps = {}) {
14839
15253
  if (!creds?.apiKey) return { status: "no-creds", shipped: 0 };
14840
15254
  const endpoint = buildBatchEndpoint(creds.apiUrl);
14841
15255
  if (!endpoint) return { status: "no-creds", shipped: 0 };
14842
- if (!fs25.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
15256
+ if (!fs27.existsSync(auditLogPath)) return { status: "idle", shipped: 0 };
14843
15257
  let shipped = 0;
14844
15258
  try {
14845
15259
  for (let chunkN = 0; chunkN < MAX_CHUNKS_PER_TICK; chunkN++) {
14846
- const size = fs25.statSync(auditLogPath).size;
15260
+ const size = fs27.statSync(auditLogPath).size;
14847
15261
  if (size === 0) break;
14848
15262
  const sig = fileSignature(auditLogPath);
14849
15263
  const wm = readWatermark(watermarkPath);
@@ -14851,12 +15265,12 @@ async function shipOnce(deps = {}) {
14851
15265
  if (offset >= size) break;
14852
15266
  const toRead = Math.min(size - offset, MAX_CHUNK_BYTES);
14853
15267
  const buf = Buffer.alloc(toRead);
14854
- const fd = fs25.openSync(auditLogPath, "r");
15268
+ const fd = fs27.openSync(auditLogPath, "r");
14855
15269
  let read;
14856
15270
  try {
14857
- read = fs25.readSync(fd, buf, 0, toRead, offset);
15271
+ read = fs27.readSync(fd, buf, 0, toRead, offset);
14858
15272
  } finally {
14859
- fs25.closeSync(fd);
15273
+ fs27.closeSync(fd);
14860
15274
  }
14861
15275
  const { rows, consumed } = buildWireRows(buf.subarray(0, read));
14862
15276
  if (consumed === 0) break;
@@ -14903,8 +15317,8 @@ async function shipOnce(deps = {}) {
14903
15317
  }
14904
15318
  function shipLagBytes(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHIP_WATERMARK) {
14905
15319
  try {
14906
- if (!fs25.existsSync(auditLogPath)) return 0;
14907
- const size = fs25.statSync(auditLogPath).size;
15320
+ if (!fs27.existsSync(auditLogPath)) return 0;
15321
+ const size = fs27.statSync(auditLogPath).size;
14908
15322
  const wm = readWatermark(watermarkPath);
14909
15323
  if (!wm) return size;
14910
15324
  if (wm.fileSig !== fileSignature(auditLogPath)) return size;
@@ -14935,7 +15349,7 @@ var init_audit_shipper = __esm({
14935
15349
  init_config();
14936
15350
  init_sync();
14937
15351
  init_cloud();
14938
- AUDIT_SHIP_WATERMARK = path27.join(os23.homedir(), ".node9", "audit-ship.json");
15352
+ AUDIT_SHIP_WATERMARK = path29.join(os25.homedir(), ".node9", "audit-ship.json");
14939
15353
  DEFAULT_INTERVAL_MS = 2e4;
14940
15354
  MAX_BATCH = 500;
14941
15355
  MAX_CHUNK_BYTES = 4 * 1024 * 1024;
@@ -14947,75 +15361,75 @@ var init_audit_shipper = __esm({
14947
15361
  });
14948
15362
 
14949
15363
  // src/daemon/dlp-scanner.ts
14950
- import fs26 from "fs";
14951
- import path28 from "path";
14952
- import os24 from "os";
15364
+ import fs28 from "fs";
15365
+ import path30 from "path";
15366
+ import os26 from "os";
14953
15367
  function loadIndex() {
14954
15368
  try {
14955
- return JSON.parse(fs26.readFileSync(INDEX_FILE, "utf-8"));
15369
+ return JSON.parse(fs28.readFileSync(INDEX_FILE, "utf-8"));
14956
15370
  } catch {
14957
15371
  return {};
14958
15372
  }
14959
15373
  }
14960
15374
  function saveIndex(index) {
14961
15375
  try {
14962
- fs26.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
15376
+ fs28.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
14963
15377
  } catch {
14964
15378
  }
14965
15379
  }
14966
15380
  function appendAuditEntry(entry) {
14967
15381
  try {
14968
- fs26.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
15382
+ fs28.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
14969
15383
  } catch {
14970
15384
  }
14971
15385
  }
14972
15386
  function runDlpScan() {
14973
- if (!fs26.existsSync(PROJECTS_DIR2)) return;
15387
+ if (!fs28.existsSync(PROJECTS_DIR2)) return;
14974
15388
  const index = loadIndex();
14975
15389
  let updated = false;
14976
15390
  let projDirs;
14977
15391
  try {
14978
- projDirs = fs26.readdirSync(PROJECTS_DIR2);
15392
+ projDirs = fs28.readdirSync(PROJECTS_DIR2);
14979
15393
  } catch {
14980
15394
  return;
14981
15395
  }
14982
15396
  for (const proj of projDirs) {
14983
- const projPath = path28.join(PROJECTS_DIR2, proj);
15397
+ const projPath = path30.join(PROJECTS_DIR2, proj);
14984
15398
  try {
14985
- if (!fs26.lstatSync(projPath).isDirectory()) continue;
14986
- const real = fs26.realpathSync(projPath);
14987
- if (!real.startsWith(PROJECTS_DIR2 + path28.sep) && real !== PROJECTS_DIR2) continue;
15399
+ if (!fs28.lstatSync(projPath).isDirectory()) continue;
15400
+ const real = fs28.realpathSync(projPath);
15401
+ if (!real.startsWith(PROJECTS_DIR2 + path30.sep) && real !== PROJECTS_DIR2) continue;
14988
15402
  } catch {
14989
15403
  continue;
14990
15404
  }
14991
15405
  let files;
14992
15406
  try {
14993
- files = fs26.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
15407
+ files = fs28.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
14994
15408
  } catch {
14995
15409
  continue;
14996
15410
  }
14997
15411
  for (const file of files) {
14998
- const filePath = path28.join(projPath, file);
15412
+ const filePath = path30.join(projPath, file);
14999
15413
  const lastOffset = index[filePath] ?? 0;
15000
15414
  let size;
15001
15415
  try {
15002
- size = fs26.statSync(filePath).size;
15416
+ size = fs28.statSync(filePath).size;
15003
15417
  } catch {
15004
15418
  continue;
15005
15419
  }
15006
15420
  if (size <= lastOffset) continue;
15007
15421
  let fd;
15008
15422
  try {
15009
- fd = fs26.openSync(filePath, "r");
15423
+ fd = fs28.openSync(filePath, "r");
15010
15424
  } catch {
15011
15425
  continue;
15012
15426
  }
15013
15427
  try {
15014
15428
  const chunkSize = size - lastOffset;
15015
15429
  const buf = Buffer.alloc(chunkSize);
15016
- fs26.readSync(fd, buf, 0, chunkSize, lastOffset);
15017
- const chunk = buf.toString("utf-8");
15018
- for (const line of chunk.split("\n")) {
15430
+ fs28.readSync(fd, buf, 0, chunkSize, lastOffset);
15431
+ const chunk2 = buf.toString("utf-8");
15432
+ for (const line of chunk2.split("\n")) {
15019
15433
  if (!line.trim()) continue;
15020
15434
  let entry;
15021
15435
  try {
@@ -15033,7 +15447,7 @@ function runDlpScan() {
15033
15447
  if (typeof text !== "string") continue;
15034
15448
  const match = scanText(text);
15035
15449
  if (!match) continue;
15036
- const projLabel = decodeURIComponent(proj).replace(os24.homedir(), "~").slice(0, 40);
15450
+ const projLabel = decodeURIComponent(proj).replace(os26.homedir(), "~").slice(0, 40);
15037
15451
  const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
15038
15452
  appendAuditEntry({
15039
15453
  ts,
@@ -15058,7 +15472,7 @@ Run: node9 report --period 30d`
15058
15472
  updated = true;
15059
15473
  } finally {
15060
15474
  try {
15061
- fs26.closeSync(fd);
15475
+ fs28.closeSync(fd);
15062
15476
  } catch {
15063
15477
  }
15064
15478
  }
@@ -15091,23 +15505,23 @@ var init_dlp_scanner = __esm({
15091
15505
  init_dlp();
15092
15506
  init_native();
15093
15507
  init_state2();
15094
- INDEX_FILE = path28.join(os24.homedir(), ".node9", "dlp-index.json");
15095
- PROJECTS_DIR2 = path28.join(os24.homedir(), ".claude", "projects");
15508
+ INDEX_FILE = path30.join(os26.homedir(), ".node9", "dlp-index.json");
15509
+ PROJECTS_DIR2 = path30.join(os26.homedir(), ".claude", "projects");
15096
15510
  }
15097
15511
  });
15098
15512
 
15099
15513
  // src/daemon/mcp-tools.ts
15100
- import fs27 from "fs";
15101
- import path29 from "path";
15102
- import os25 from "os";
15514
+ import fs29 from "fs";
15515
+ import path31 from "path";
15516
+ import os27 from "os";
15103
15517
  function getMcpToolsFile() {
15104
- return path29.join(os25.homedir(), ".node9", "mcp-tools.json");
15518
+ return path31.join(os27.homedir(), ".node9", "mcp-tools.json");
15105
15519
  }
15106
15520
  function readMcpToolsConfig() {
15107
15521
  try {
15108
15522
  const file = getMcpToolsFile();
15109
- if (!fs27.existsSync(file)) return {};
15110
- const raw = fs27.readFileSync(file, "utf-8");
15523
+ if (!fs29.existsSync(file)) return {};
15524
+ const raw = fs29.readFileSync(file, "utf-8");
15111
15525
  return JSON.parse(raw);
15112
15526
  } catch {
15113
15527
  return {};
@@ -15116,11 +15530,11 @@ function readMcpToolsConfig() {
15116
15530
  function writeMcpToolsConfig(config) {
15117
15531
  try {
15118
15532
  const file = getMcpToolsFile();
15119
- const dir = path29.dirname(file);
15120
- if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
15121
- const tmpPath = `${file}.${os25.hostname()}.${process.pid}.tmp`;
15122
- fs27.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
15123
- fs27.renameSync(tmpPath, file);
15533
+ const dir = path31.dirname(file);
15534
+ if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
15535
+ const tmpPath = `${file}.${os27.hostname()}.${process.pid}.tmp`;
15536
+ fs29.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
15537
+ fs29.renameSync(tmpPath, file);
15124
15538
  } catch (e) {
15125
15539
  console.error("Failed to write mcp-tools.json", e);
15126
15540
  }
@@ -15167,9 +15581,9 @@ var init_mcp_tools = __esm({
15167
15581
 
15168
15582
  // src/daemon/server.ts
15169
15583
  import http from "http";
15170
- import fs28 from "fs";
15171
- import path30 from "path";
15172
- import os26 from "os";
15584
+ import fs30 from "fs";
15585
+ import path32 from "path";
15586
+ import os28 from "os";
15173
15587
  import { randomUUID as randomUUID4 } from "crypto";
15174
15588
  import { spawnSync } from "child_process";
15175
15589
  import chalk6 from "chalk";
@@ -15191,7 +15605,7 @@ function startDaemon() {
15191
15605
  idleTimer = setTimeout(() => {
15192
15606
  if (autoStarted) {
15193
15607
  try {
15194
- fs28.unlinkSync(DAEMON_PID_FILE);
15608
+ fs30.unlinkSync(DAEMON_PID_FILE);
15195
15609
  } catch {
15196
15610
  }
15197
15611
  }
@@ -15336,7 +15750,7 @@ data: ${JSON.stringify(item.data)}
15336
15750
  mcpServer: entry.mcpServer
15337
15751
  });
15338
15752
  }
15339
- const projectCwd = typeof cwd === "string" && path30.isAbsolute(cwd) ? cwd : void 0;
15753
+ const projectCwd = typeof cwd === "string" && path32.isAbsolute(cwd) ? cwd : void 0;
15340
15754
  const projectConfig = getConfig(projectCwd);
15341
15755
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
15342
15756
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -15628,8 +16042,8 @@ data: ${JSON.stringify(item.data)}
15628
16042
  if (!validToken(req)) return res.writeHead(403).end();
15629
16043
  const periodParam = reqUrl.searchParams.get("period") || "7d";
15630
16044
  const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
15631
- const logPath = path30.join(os26.homedir(), ".node9", "audit.log");
15632
- if (!fs28.existsSync(logPath)) {
16045
+ const logPath = path32.join(os28.homedir(), ".node9", "audit.log");
16046
+ if (!fs30.existsSync(logPath)) {
15633
16047
  res.writeHead(200, { "Content-Type": "application/json" });
15634
16048
  return res.end(
15635
16049
  JSON.stringify({
@@ -15642,7 +16056,7 @@ data: ${JSON.stringify(item.data)}
15642
16056
  );
15643
16057
  }
15644
16058
  try {
15645
- const raw = fs28.readFileSync(logPath, "utf-8");
16059
+ const raw = fs30.readFileSync(logPath, "utf-8");
15646
16060
  const allEntries = raw.split("\n").flatMap((line) => {
15647
16061
  if (!line.trim()) return [];
15648
16062
  try {
@@ -15965,14 +16379,14 @@ data: ${JSON.stringify(item.data)}
15965
16379
  server.on("error", (e) => {
15966
16380
  if (e.code === "EADDRINUSE") {
15967
16381
  try {
15968
- if (fs28.existsSync(DAEMON_PID_FILE)) {
15969
- const { pid } = JSON.parse(fs28.readFileSync(DAEMON_PID_FILE, "utf-8"));
16382
+ if (fs30.existsSync(DAEMON_PID_FILE)) {
16383
+ const { pid } = JSON.parse(fs30.readFileSync(DAEMON_PID_FILE, "utf-8"));
15970
16384
  process.kill(pid, 0);
15971
16385
  return process.exit(0);
15972
16386
  }
15973
16387
  } catch {
15974
16388
  try {
15975
- fs28.unlinkSync(DAEMON_PID_FILE);
16389
+ fs30.unlinkSync(DAEMON_PID_FILE);
15976
16390
  } catch {
15977
16391
  }
15978
16392
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -16061,15 +16475,15 @@ var init_server = __esm({
16061
16475
  });
16062
16476
 
16063
16477
  // src/daemon/service.ts
16064
- import fs29 from "fs";
16065
- import path31 from "path";
16066
- import os27 from "os";
16478
+ import fs31 from "fs";
16479
+ import path33 from "path";
16480
+ import os29 from "os";
16067
16481
  import { spawnSync as spawnSync2, execFileSync } from "child_process";
16068
16482
  function resolveNode9Binary() {
16069
16483
  try {
16070
16484
  const script = process.argv[1];
16071
- if (typeof script === "string" && path31.isAbsolute(script) && fs29.existsSync(script)) {
16072
- return fs29.realpathSync(script);
16485
+ if (typeof script === "string" && path33.isAbsolute(script) && fs31.existsSync(script)) {
16486
+ return fs31.realpathSync(script);
16073
16487
  }
16074
16488
  } catch {
16075
16489
  }
@@ -16087,11 +16501,11 @@ function xmlEscape(s) {
16087
16501
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
16088
16502
  }
16089
16503
  function launchdPlist(binaryPath) {
16090
- const logDir = path31.join(os27.homedir(), ".node9");
16504
+ const logDir = path33.join(os29.homedir(), ".node9");
16091
16505
  const nodePath = xmlEscape(process.execPath);
16092
16506
  const scriptPath = xmlEscape(binaryPath);
16093
- const outLog = xmlEscape(path31.join(logDir, "daemon.log"));
16094
- const errLog = xmlEscape(path31.join(logDir, "daemon-error.log"));
16507
+ const outLog = xmlEscape(path33.join(logDir, "daemon.log"));
16508
+ const errLog = xmlEscape(path33.join(logDir, "daemon-error.log"));
16095
16509
  return `<?xml version="1.0" encoding="UTF-8"?>
16096
16510
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
16097
16511
  <plist version="1.0">
@@ -16124,9 +16538,9 @@ function launchdPlist(binaryPath) {
16124
16538
  `;
16125
16539
  }
16126
16540
  function installLaunchd(binaryPath) {
16127
- const dir = path31.dirname(LAUNCHD_PLIST);
16128
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
16129
- fs29.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
16541
+ const dir = path33.dirname(LAUNCHD_PLIST);
16542
+ if (!fs31.existsSync(dir)) fs31.mkdirSync(dir, { recursive: true });
16543
+ fs31.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
16130
16544
  spawnSync2("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
16131
16545
  const r = spawnSync2("launchctl", ["load", "-w", LAUNCHD_PLIST], {
16132
16546
  encoding: "utf8",
@@ -16137,13 +16551,13 @@ function installLaunchd(binaryPath) {
16137
16551
  }
16138
16552
  }
16139
16553
  function uninstallLaunchd() {
16140
- if (fs29.existsSync(LAUNCHD_PLIST)) {
16554
+ if (fs31.existsSync(LAUNCHD_PLIST)) {
16141
16555
  spawnSync2("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
16142
- fs29.unlinkSync(LAUNCHD_PLIST);
16556
+ fs31.unlinkSync(LAUNCHD_PLIST);
16143
16557
  }
16144
16558
  }
16145
16559
  function isLaunchdInstalled() {
16146
- return fs29.existsSync(LAUNCHD_PLIST);
16560
+ return fs31.existsSync(LAUNCHD_PLIST);
16147
16561
  }
16148
16562
  function systemdUnit(binaryPath) {
16149
16563
  return `[Unit]
@@ -16162,12 +16576,12 @@ WantedBy=default.target
16162
16576
  `;
16163
16577
  }
16164
16578
  function installSystemd(binaryPath) {
16165
- if (!fs29.existsSync(SYSTEMD_UNIT_DIR)) {
16166
- fs29.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
16579
+ if (!fs31.existsSync(SYSTEMD_UNIT_DIR)) {
16580
+ fs31.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
16167
16581
  }
16168
- fs29.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
16582
+ fs31.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
16169
16583
  try {
16170
- execFileSync("loginctl", ["enable-linger", os27.userInfo().username], { timeout: 3e3 });
16584
+ execFileSync("loginctl", ["enable-linger", os29.userInfo().username], { timeout: 3e3 });
16171
16585
  } catch {
16172
16586
  }
16173
16587
  const reload = spawnSync2("systemctl", ["--user", "daemon-reload"], {
@@ -16187,23 +16601,23 @@ function installSystemd(binaryPath) {
16187
16601
  }
16188
16602
  }
16189
16603
  function uninstallSystemd() {
16190
- if (fs29.existsSync(SYSTEMD_UNIT)) {
16604
+ if (fs31.existsSync(SYSTEMD_UNIT)) {
16191
16605
  spawnSync2("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
16192
16606
  encoding: "utf8",
16193
16607
  timeout: 5e3
16194
16608
  });
16195
16609
  spawnSync2("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
16196
- fs29.unlinkSync(SYSTEMD_UNIT);
16610
+ fs31.unlinkSync(SYSTEMD_UNIT);
16197
16611
  }
16198
16612
  }
16199
16613
  function isSystemdInstalled() {
16200
- return fs29.existsSync(SYSTEMD_UNIT);
16614
+ return fs31.existsSync(SYSTEMD_UNIT);
16201
16615
  }
16202
16616
  function stopRunningDaemon() {
16203
- const pidFile = path31.join(os27.homedir(), ".node9", "daemon.pid");
16204
- if (!fs29.existsSync(pidFile)) return;
16617
+ const pidFile = path33.join(os29.homedir(), ".node9", "daemon.pid");
16618
+ if (!fs31.existsSync(pidFile)) return;
16205
16619
  try {
16206
- const data = JSON.parse(fs29.readFileSync(pidFile, "utf-8"));
16620
+ const data = JSON.parse(fs31.readFileSync(pidFile, "utf-8"));
16207
16621
  const pid = data.pid;
16208
16622
  const MAX_PID2 = 4194304;
16209
16623
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -16223,7 +16637,7 @@ function stopRunningDaemon() {
16223
16637
  }
16224
16638
  }
16225
16639
  try {
16226
- fs29.unlinkSync(pidFile);
16640
+ fs31.unlinkSync(pidFile);
16227
16641
  } catch {
16228
16642
  }
16229
16643
  } catch {
@@ -16298,19 +16712,19 @@ var init_service = __esm({
16298
16712
  "src/daemon/service.ts"() {
16299
16713
  "use strict";
16300
16714
  LAUNCHD_LABEL = "ai.node9.daemon";
16301
- LAUNCHD_PLIST = path31.join(os27.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
16302
- SYSTEMD_UNIT_DIR = path31.join(os27.homedir(), ".config", "systemd", "user");
16303
- SYSTEMD_UNIT = path31.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
16715
+ LAUNCHD_PLIST = path33.join(os29.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
16716
+ SYSTEMD_UNIT_DIR = path33.join(os29.homedir(), ".config", "systemd", "user");
16717
+ SYSTEMD_UNIT = path33.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
16304
16718
  }
16305
16719
  });
16306
16720
 
16307
16721
  // src/daemon/index.ts
16308
- import fs30 from "fs";
16722
+ import fs32 from "fs";
16309
16723
  import chalk7 from "chalk";
16310
16724
  function stopDaemon() {
16311
- if (!fs30.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
16725
+ if (!fs32.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
16312
16726
  try {
16313
- const data = JSON.parse(fs30.readFileSync(DAEMON_PID_FILE, "utf-8"));
16727
+ const data = JSON.parse(fs32.readFileSync(DAEMON_PID_FILE, "utf-8"));
16314
16728
  const pid = data.pid;
16315
16729
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
16316
16730
  console.log(chalk7.gray("Cleaned up invalid PID file."));
@@ -16322,7 +16736,7 @@ function stopDaemon() {
16322
16736
  console.log(chalk7.gray("Cleaned up stale PID file."));
16323
16737
  } finally {
16324
16738
  try {
16325
- fs30.unlinkSync(DAEMON_PID_FILE);
16739
+ fs32.unlinkSync(DAEMON_PID_FILE);
16326
16740
  } catch {
16327
16741
  }
16328
16742
  }
@@ -16331,9 +16745,9 @@ function daemonStatus() {
16331
16745
  const serviceInstalled = isDaemonServiceInstalled();
16332
16746
  const serviceLabel = serviceInstalled ? chalk7.green("installed (starts on login)") : chalk7.yellow("not installed \u2014 run: node9 daemon install");
16333
16747
  let processStatus;
16334
- if (fs30.existsSync(DAEMON_PID_FILE)) {
16748
+ if (fs32.existsSync(DAEMON_PID_FILE)) {
16335
16749
  try {
16336
- const data = JSON.parse(fs30.readFileSync(DAEMON_PID_FILE, "utf-8"));
16750
+ const data = JSON.parse(fs32.readFileSync(DAEMON_PID_FILE, "utf-8"));
16337
16751
  const pid = data.pid;
16338
16752
  const port = data.port;
16339
16753
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -16378,9 +16792,9 @@ __export(tail_exports, {
16378
16792
  });
16379
16793
  import http2 from "http";
16380
16794
  import chalk29 from "chalk";
16381
- import fs48 from "fs";
16382
- import os43 from "os";
16383
- import path49 from "path";
16795
+ import fs50 from "fs";
16796
+ import os45 from "os";
16797
+ import path51 from "path";
16384
16798
  import readline6 from "readline";
16385
16799
  import { spawn as spawn8 } from "child_process";
16386
16800
  function shortenPathSummary(s) {
@@ -16404,20 +16818,20 @@ function getModelContextLimit(model) {
16404
16818
  return 2e5;
16405
16819
  }
16406
16820
  function readSessionUsage() {
16407
- const projectsDir = path49.join(os43.homedir(), ".claude", "projects");
16408
- if (!fs48.existsSync(projectsDir)) return null;
16821
+ const projectsDir = path51.join(os45.homedir(), ".claude", "projects");
16822
+ if (!fs50.existsSync(projectsDir)) return null;
16409
16823
  let latestFile = null;
16410
16824
  let latestMtime = 0;
16411
16825
  try {
16412
- for (const dir of fs48.readdirSync(projectsDir)) {
16413
- const dirPath = path49.join(projectsDir, dir);
16826
+ for (const dir of fs50.readdirSync(projectsDir)) {
16827
+ const dirPath = path51.join(projectsDir, dir);
16414
16828
  try {
16415
- if (!fs48.statSync(dirPath).isDirectory()) continue;
16416
- for (const file of fs48.readdirSync(dirPath)) {
16829
+ if (!fs50.statSync(dirPath).isDirectory()) continue;
16830
+ for (const file of fs50.readdirSync(dirPath)) {
16417
16831
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
16418
- const filePath = path49.join(dirPath, file);
16832
+ const filePath = path51.join(dirPath, file);
16419
16833
  try {
16420
- const mtime = fs48.statSync(filePath).mtimeMs;
16834
+ const mtime = fs50.statSync(filePath).mtimeMs;
16421
16835
  if (mtime > latestMtime) {
16422
16836
  latestMtime = mtime;
16423
16837
  latestFile = filePath;
@@ -16432,7 +16846,7 @@ function readSessionUsage() {
16432
16846
  }
16433
16847
  if (!latestFile) return null;
16434
16848
  try {
16435
- const lines = fs48.readFileSync(latestFile, "utf-8").split("\n");
16849
+ const lines = fs50.readFileSync(latestFile, "utf-8").split("\n");
16436
16850
  let lastModel = "";
16437
16851
  let lastInput = 0;
16438
16852
  let lastOutput = 0;
@@ -16493,7 +16907,7 @@ function formatBase(activity) {
16493
16907
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
16494
16908
  const icon = getIcon(activity.tool);
16495
16909
  const toolName = activity.tool.slice(0, 16).padEnd(16);
16496
- const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os43.homedir(), "~");
16910
+ const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os45.homedir(), "~");
16497
16911
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
16498
16912
  return `${chalk29.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk29.white.bold(toolName)} ${chalk29.dim(argsPreview)}`;
16499
16913
  }
@@ -16532,9 +16946,9 @@ function renderPending(activity) {
16532
16946
  }
16533
16947
  async function ensureDaemon() {
16534
16948
  let pidPort = null;
16535
- if (fs48.existsSync(PID_FILE)) {
16949
+ if (fs50.existsSync(PID_FILE)) {
16536
16950
  try {
16537
- const { port } = JSON.parse(fs48.readFileSync(PID_FILE, "utf-8"));
16951
+ const { port } = JSON.parse(fs50.readFileSync(PID_FILE, "utf-8"));
16538
16952
  pidPort = port;
16539
16953
  } catch {
16540
16954
  console.error(chalk29.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -16690,9 +17104,9 @@ function buildRecoveryCardLines(req) {
16690
17104
  ];
16691
17105
  }
16692
17106
  function readApproversFromDisk() {
16693
- const configPath = path49.join(os43.homedir(), ".node9", "config.json");
17107
+ const configPath = path51.join(os45.homedir(), ".node9", "config.json");
16694
17108
  try {
16695
- const raw = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
17109
+ const raw = JSON.parse(fs50.readFileSync(configPath, "utf-8"));
16696
17110
  const settings = raw.settings ?? {};
16697
17111
  return settings.approvers ?? {};
16698
17112
  } catch {
@@ -16708,15 +17122,15 @@ function approverStatusLine() {
16708
17122
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
16709
17123
  }
16710
17124
  function toggleApprover(channel) {
16711
- const configPath = path49.join(os43.homedir(), ".node9", "config.json");
17125
+ const configPath = path51.join(os45.homedir(), ".node9", "config.json");
16712
17126
  try {
16713
- const raw = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
17127
+ const raw = JSON.parse(fs50.readFileSync(configPath, "utf-8"));
16714
17128
  const settings = raw.settings ?? {};
16715
17129
  const approvers = settings.approvers ?? {};
16716
17130
  approvers[channel] = approvers[channel] === false;
16717
17131
  settings.approvers = approvers;
16718
17132
  raw.settings = settings;
16719
- fs48.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
17133
+ fs50.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
16720
17134
  } catch (err2) {
16721
17135
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
16722
17136
  `);
@@ -16888,8 +17302,8 @@ async function startTail(options = {}) {
16888
17302
  }
16889
17303
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
16890
17304
  try {
16891
- fs48.appendFileSync(
16892
- path49.join(os43.homedir(), ".node9", "hook-debug.log"),
17305
+ fs50.appendFileSync(
17306
+ path51.join(os45.homedir(), ".node9", "hook-debug.log"),
16893
17307
  `[tail] POST /decision failed: ${String(err2)}
16894
17308
  `
16895
17309
  );
@@ -16953,9 +17367,9 @@ async function startTail(options = {}) {
16953
17367
  };
16954
17368
  process.stdin.on("keypress", onKeypress);
16955
17369
  }
16956
- const auditLog = path49.join(os43.homedir(), ".node9", "audit.log");
17370
+ const auditLog = path51.join(os45.homedir(), ".node9", "audit.log");
16957
17371
  try {
16958
- const unackedDlp = fs48.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
17372
+ const unackedDlp = fs50.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
16959
17373
  if (unackedDlp > 0) {
16960
17374
  console.log("");
16961
17375
  console.log(
@@ -16995,7 +17409,7 @@ async function startTail(options = {}) {
16995
17409
  if (stallWarned) return;
16996
17410
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
16997
17411
  try {
16998
- const auditMtime = fs48.statSync(auditLog).mtimeMs;
17412
+ const auditMtime = fs50.statSync(auditLog).mtimeMs;
16999
17413
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
17000
17414
  console.log("");
17001
17415
  console.log(
@@ -17186,7 +17600,7 @@ var init_tail = __esm({
17186
17600
  "use strict";
17187
17601
  init_daemon2();
17188
17602
  init_daemon();
17189
- PID_FILE = path49.join(os43.homedir(), ".node9", "daemon.pid");
17603
+ PID_FILE = path51.join(os45.homedir(), ".node9", "daemon.pid");
17190
17604
  ICONS = {
17191
17605
  bash: "\u{1F4BB}",
17192
17606
  shell: "\u{1F4BB}",
@@ -17234,14 +17648,14 @@ __export(hud_exports, {
17234
17648
  main: () => main,
17235
17649
  renderEnvironmentLine: () => renderEnvironmentLine
17236
17650
  });
17237
- import fs49 from "fs";
17238
- import path50 from "path";
17239
- import os44 from "os";
17651
+ import fs51 from "fs";
17652
+ import path52 from "path";
17653
+ import os46 from "os";
17240
17654
  import http3 from "http";
17241
17655
  async function readStdin() {
17242
17656
  const chunks = [];
17243
- for await (const chunk of process.stdin) {
17244
- chunks.push(chunk);
17657
+ for await (const chunk2 of process.stdin) {
17658
+ chunks.push(chunk2);
17245
17659
  }
17246
17660
  const raw = Buffer.concat(chunks).toString("utf-8").trim();
17247
17661
  if (!raw) return {};
@@ -17312,9 +17726,9 @@ function formatTimeLeft(resetsAt) {
17312
17726
  return ` (${m}m left)`;
17313
17727
  }
17314
17728
  function safeReadJson(filePath) {
17315
- if (!fs49.existsSync(filePath)) return null;
17729
+ if (!fs51.existsSync(filePath)) return null;
17316
17730
  try {
17317
- return JSON.parse(fs49.readFileSync(filePath, "utf-8"));
17731
+ return JSON.parse(fs51.readFileSync(filePath, "utf-8"));
17318
17732
  } catch {
17319
17733
  return null;
17320
17734
  }
@@ -17335,12 +17749,12 @@ function countHooksInFile(filePath) {
17335
17749
  return Object.keys(cfg.hooks).length;
17336
17750
  }
17337
17751
  function countRulesInDir(rulesDir) {
17338
- if (!fs49.existsSync(rulesDir)) return 0;
17752
+ if (!fs51.existsSync(rulesDir)) return 0;
17339
17753
  let count = 0;
17340
17754
  try {
17341
- for (const entry of fs49.readdirSync(rulesDir, { withFileTypes: true })) {
17755
+ for (const entry of fs51.readdirSync(rulesDir, { withFileTypes: true })) {
17342
17756
  if (entry.isDirectory()) {
17343
- count += countRulesInDir(path50.join(rulesDir, entry.name));
17757
+ count += countRulesInDir(path52.join(rulesDir, entry.name));
17344
17758
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
17345
17759
  count++;
17346
17760
  }
@@ -17351,46 +17765,46 @@ function countRulesInDir(rulesDir) {
17351
17765
  }
17352
17766
  function isSamePath(a, b) {
17353
17767
  try {
17354
- return path50.resolve(a) === path50.resolve(b);
17768
+ return path52.resolve(a) === path52.resolve(b);
17355
17769
  } catch {
17356
17770
  return false;
17357
17771
  }
17358
17772
  }
17359
17773
  function countConfigs(cwd) {
17360
- const homeDir2 = os44.homedir();
17361
- const claudeDir = path50.join(homeDir2, ".claude");
17774
+ const homeDir2 = os46.homedir();
17775
+ const claudeDir = path52.join(homeDir2, ".claude");
17362
17776
  let claudeMdCount = 0;
17363
17777
  let rulesCount = 0;
17364
17778
  let hooksCount = 0;
17365
17779
  const userMcpServers = /* @__PURE__ */ new Set();
17366
17780
  const projectMcpServers = /* @__PURE__ */ new Set();
17367
- if (fs49.existsSync(path50.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
17368
- rulesCount += countRulesInDir(path50.join(claudeDir, "rules"));
17369
- const userSettings = path50.join(claudeDir, "settings.json");
17781
+ if (fs51.existsSync(path52.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
17782
+ rulesCount += countRulesInDir(path52.join(claudeDir, "rules"));
17783
+ const userSettings = path52.join(claudeDir, "settings.json");
17370
17784
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
17371
17785
  hooksCount += countHooksInFile(userSettings);
17372
- const userClaudeJson = path50.join(homeDir2, ".claude.json");
17786
+ const userClaudeJson = path52.join(homeDir2, ".claude.json");
17373
17787
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
17374
17788
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
17375
17789
  userMcpServers.delete(name);
17376
17790
  }
17377
17791
  if (cwd) {
17378
- if (fs49.existsSync(path50.join(cwd, "CLAUDE.md"))) claudeMdCount++;
17379
- if (fs49.existsSync(path50.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
17380
- const projectClaudeDir = path50.join(cwd, ".claude");
17792
+ if (fs51.existsSync(path52.join(cwd, "CLAUDE.md"))) claudeMdCount++;
17793
+ if (fs51.existsSync(path52.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
17794
+ const projectClaudeDir = path52.join(cwd, ".claude");
17381
17795
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
17382
17796
  if (!overlapsUserScope) {
17383
- if (fs49.existsSync(path50.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
17384
- rulesCount += countRulesInDir(path50.join(projectClaudeDir, "rules"));
17385
- const projSettings = path50.join(projectClaudeDir, "settings.json");
17797
+ if (fs51.existsSync(path52.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
17798
+ rulesCount += countRulesInDir(path52.join(projectClaudeDir, "rules"));
17799
+ const projSettings = path52.join(projectClaudeDir, "settings.json");
17386
17800
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
17387
17801
  hooksCount += countHooksInFile(projSettings);
17388
17802
  }
17389
- if (fs49.existsSync(path50.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
17390
- const localSettings = path50.join(projectClaudeDir, "settings.local.json");
17803
+ if (fs51.existsSync(path52.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
17804
+ const localSettings = path52.join(projectClaudeDir, "settings.local.json");
17391
17805
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
17392
17806
  hooksCount += countHooksInFile(localSettings);
17393
- const mcpJsonServers = getMcpServerNames(path50.join(cwd, ".mcp.json"));
17807
+ const mcpJsonServers = getMcpServerNames(path52.join(cwd, ".mcp.json"));
17394
17808
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
17395
17809
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
17396
17810
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -17423,12 +17837,12 @@ function readActiveShieldsHud() {
17423
17837
  return shieldsCache.value;
17424
17838
  }
17425
17839
  try {
17426
- const shieldsPath = path50.join(os44.homedir(), ".node9", "shields.json");
17427
- if (!fs49.existsSync(shieldsPath)) {
17840
+ const shieldsPath = path52.join(os46.homedir(), ".node9", "shields.json");
17841
+ if (!fs51.existsSync(shieldsPath)) {
17428
17842
  shieldsCache = { value: [], ts: now };
17429
17843
  return [];
17430
17844
  }
17431
- const parsed = JSON.parse(fs49.readFileSync(shieldsPath, "utf-8"));
17845
+ const parsed = JSON.parse(fs51.readFileSync(shieldsPath, "utf-8"));
17432
17846
  if (!Array.isArray(parsed.active)) {
17433
17847
  shieldsCache = { value: [], ts: now };
17434
17848
  return [];
@@ -17530,17 +17944,17 @@ function renderContextLine(stdin) {
17530
17944
  async function main() {
17531
17945
  try {
17532
17946
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
17533
- if (fs49.existsSync(path50.join(os44.homedir(), ".node9", "hud-debug"))) {
17947
+ if (fs51.existsSync(path52.join(os46.homedir(), ".node9", "hud-debug"))) {
17534
17948
  try {
17535
- const logPath = path50.join(os44.homedir(), ".node9", "hud-debug.log");
17949
+ const logPath = path52.join(os46.homedir(), ".node9", "hud-debug.log");
17536
17950
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
17537
17951
  let size = 0;
17538
17952
  try {
17539
- size = fs49.statSync(logPath).size;
17953
+ size = fs51.statSync(logPath).size;
17540
17954
  } catch {
17541
17955
  }
17542
17956
  if (size < MAX_LOG_SIZE) {
17543
- fs49.appendFileSync(
17957
+ fs51.appendFileSync(
17544
17958
  logPath,
17545
17959
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
17546
17960
  );
@@ -17561,11 +17975,11 @@ async function main() {
17561
17975
  try {
17562
17976
  const cwd = stdin.cwd ?? process.cwd();
17563
17977
  for (const configPath of [
17564
- path50.join(cwd, "node9.config.json"),
17565
- path50.join(os44.homedir(), ".node9", "config.json")
17978
+ path52.join(cwd, "node9.config.json"),
17979
+ path52.join(os46.homedir(), ".node9", "config.json")
17566
17980
  ]) {
17567
- if (!fs49.existsSync(configPath)) continue;
17568
- const cfg = JSON.parse(fs49.readFileSync(configPath, "utf-8"));
17981
+ if (!fs51.existsSync(configPath)) continue;
17982
+ const cfg = JSON.parse(fs51.readFileSync(configPath, "utf-8"));
17569
17983
  const hud = cfg.settings?.hud;
17570
17984
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
17571
17985
  }
@@ -17612,9 +18026,9 @@ init_setup();
17612
18026
  init_daemon2();
17613
18027
  import { Command } from "commander";
17614
18028
  import chalk30 from "chalk";
17615
- import fs50 from "fs";
17616
- import path51 from "path";
17617
- import os45 from "os";
18029
+ import fs52 from "fs";
18030
+ import path53 from "path";
18031
+ import os47 from "os";
17618
18032
  import { confirm as confirm2 } from "@inquirer/prompts";
17619
18033
 
17620
18034
  // src/utils/duration.ts
@@ -17797,17 +18211,17 @@ async function runProxy(targetCommand) {
17797
18211
  // src/cli/daemon-starter.ts
17798
18212
  init_daemon();
17799
18213
  import { spawn as spawn3 } from "child_process";
17800
- import path32 from "path";
17801
- import fs31 from "fs";
18214
+ import path34 from "path";
18215
+ import fs33 from "fs";
17802
18216
  function isTestingMode() {
17803
18217
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
17804
18218
  }
17805
18219
  async function autoStartDaemonAndWait() {
17806
18220
  if (isTestingMode()) return false;
17807
- if (!path32.isAbsolute(process.argv[1])) return false;
18221
+ if (!path34.isAbsolute(process.argv[1])) return false;
17808
18222
  let resolvedArgv1;
17809
18223
  try {
17810
- resolvedArgv1 = fs31.realpathSync(process.argv[1]);
18224
+ resolvedArgv1 = fs33.realpathSync(process.argv[1]);
17811
18225
  } catch {
17812
18226
  return false;
17813
18227
  }
@@ -17838,19 +18252,19 @@ init_daemon();
17838
18252
  init_config();
17839
18253
  init_policy();
17840
18254
  import chalk9 from "chalk";
17841
- import fs34 from "fs";
18255
+ import fs36 from "fs";
17842
18256
  import { spawn as spawn5 } from "child_process";
17843
- import path35 from "path";
17844
- import os30 from "os";
18257
+ import path37 from "path";
18258
+ import os32 from "os";
17845
18259
 
17846
18260
  // src/undo.ts
17847
18261
  import { spawnSync as spawnSync3, spawn as spawn4 } from "child_process";
17848
18262
  import crypto6 from "crypto";
17849
- import fs32 from "fs";
18263
+ import fs34 from "fs";
17850
18264
  import net3 from "net";
17851
- import path33 from "path";
17852
- import os28 from "os";
17853
- var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path33.join(os28.tmpdir(), "node9-activity.sock");
18265
+ import path35 from "path";
18266
+ import os30 from "os";
18267
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path35.join(os30.tmpdir(), "node9-activity.sock");
17854
18268
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
17855
18269
  try {
17856
18270
  const payload = JSON.stringify({
@@ -17870,22 +18284,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
17870
18284
  } catch {
17871
18285
  }
17872
18286
  }
17873
- var SNAPSHOT_STACK_PATH = path33.join(os28.homedir(), ".node9", "snapshots.json");
17874
- var UNDO_LATEST_PATH = path33.join(os28.homedir(), ".node9", "undo_latest.txt");
18287
+ var SNAPSHOT_STACK_PATH = path35.join(os30.homedir(), ".node9", "snapshots.json");
18288
+ var UNDO_LATEST_PATH = path35.join(os30.homedir(), ".node9", "undo_latest.txt");
17875
18289
  var MAX_SNAPSHOTS = 10;
17876
18290
  var GIT_TIMEOUT = 15e3;
17877
18291
  function readStack() {
17878
18292
  try {
17879
- if (fs32.existsSync(SNAPSHOT_STACK_PATH))
17880
- return JSON.parse(fs32.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
18293
+ if (fs34.existsSync(SNAPSHOT_STACK_PATH))
18294
+ return JSON.parse(fs34.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
17881
18295
  } catch {
17882
18296
  }
17883
18297
  return [];
17884
18298
  }
17885
18299
  function writeStack(stack) {
17886
- const dir = path33.dirname(SNAPSHOT_STACK_PATH);
17887
- if (!fs32.existsSync(dir)) fs32.mkdirSync(dir, { recursive: true });
17888
- fs32.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
18300
+ const dir = path35.dirname(SNAPSHOT_STACK_PATH);
18301
+ if (!fs34.existsSync(dir)) fs34.mkdirSync(dir, { recursive: true });
18302
+ fs34.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
17889
18303
  }
17890
18304
  function extractFilePath(args) {
17891
18305
  if (!args || typeof args !== "object") return null;
@@ -17905,12 +18319,12 @@ function buildArgsSummary(tool, args) {
17905
18319
  return "";
17906
18320
  }
17907
18321
  function findProjectRoot(filePath) {
17908
- let dir = path33.dirname(filePath);
18322
+ let dir = path35.dirname(filePath);
17909
18323
  while (true) {
17910
- if (fs32.existsSync(path33.join(dir, ".git")) || fs32.existsSync(path33.join(dir, "package.json"))) {
18324
+ if (fs34.existsSync(path35.join(dir, ".git")) || fs34.existsSync(path35.join(dir, "package.json"))) {
17911
18325
  return dir;
17912
18326
  }
17913
- const parent = path33.dirname(dir);
18327
+ const parent = path35.dirname(dir);
17914
18328
  if (parent === dir) return process.cwd();
17915
18329
  dir = parent;
17916
18330
  }
@@ -17918,7 +18332,7 @@ function findProjectRoot(filePath) {
17918
18332
  function normalizeCwdForHash(cwd) {
17919
18333
  let normalized;
17920
18334
  try {
17921
- normalized = fs32.realpathSync(cwd);
18335
+ normalized = fs34.realpathSync(cwd);
17922
18336
  } catch {
17923
18337
  normalized = cwd;
17924
18338
  }
@@ -17928,16 +18342,16 @@ function normalizeCwdForHash(cwd) {
17928
18342
  }
17929
18343
  function getShadowRepoDir(cwd) {
17930
18344
  const hash = crypto6.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
17931
- return path33.join(os28.homedir(), ".node9", "snapshots", hash);
18345
+ return path35.join(os30.homedir(), ".node9", "snapshots", hash);
17932
18346
  }
17933
18347
  function cleanOrphanedIndexFiles(shadowDir) {
17934
18348
  try {
17935
18349
  const cutoff = Date.now() - 6e4;
17936
- for (const f of fs32.readdirSync(shadowDir)) {
18350
+ for (const f of fs34.readdirSync(shadowDir)) {
17937
18351
  if (f.startsWith("index_")) {
17938
- const fp = path33.join(shadowDir, f);
18352
+ const fp = path35.join(shadowDir, f);
17939
18353
  try {
17940
- if (fs32.statSync(fp).mtimeMs < cutoff) fs32.unlinkSync(fp);
18354
+ if (fs34.statSync(fp).mtimeMs < cutoff) fs34.unlinkSync(fp);
17941
18355
  } catch {
17942
18356
  }
17943
18357
  }
@@ -17949,7 +18363,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
17949
18363
  const hardcoded = [".git", ".node9"];
17950
18364
  const lines = [...hardcoded, ...ignorePaths].join("\n");
17951
18365
  try {
17952
- fs32.writeFileSync(path33.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
18366
+ fs34.writeFileSync(path35.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
17953
18367
  } catch {
17954
18368
  }
17955
18369
  }
@@ -17962,25 +18376,25 @@ function ensureShadowRepo(shadowDir, cwd) {
17962
18376
  timeout: 3e3
17963
18377
  });
17964
18378
  if (check.status === 0) {
17965
- const ptPath = path33.join(shadowDir, "project-path.txt");
18379
+ const ptPath = path35.join(shadowDir, "project-path.txt");
17966
18380
  try {
17967
- const stored = fs32.readFileSync(ptPath, "utf8").trim();
18381
+ const stored = fs34.readFileSync(ptPath, "utf8").trim();
17968
18382
  if (stored === normalizedCwd) return true;
17969
18383
  if (process.env.NODE9_DEBUG === "1")
17970
18384
  console.error(
17971
18385
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
17972
18386
  );
17973
- fs32.rmSync(shadowDir, { recursive: true, force: true });
18387
+ fs34.rmSync(shadowDir, { recursive: true, force: true });
17974
18388
  } catch {
17975
18389
  try {
17976
- fs32.writeFileSync(ptPath, normalizedCwd, "utf8");
18390
+ fs34.writeFileSync(ptPath, normalizedCwd, "utf8");
17977
18391
  } catch {
17978
18392
  }
17979
18393
  return true;
17980
18394
  }
17981
18395
  }
17982
18396
  try {
17983
- fs32.mkdirSync(shadowDir, { recursive: true });
18397
+ fs34.mkdirSync(shadowDir, { recursive: true });
17984
18398
  } catch {
17985
18399
  }
17986
18400
  const init = spawnSync3("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -17989,7 +18403,7 @@ function ensureShadowRepo(shadowDir, cwd) {
17989
18403
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
17990
18404
  return false;
17991
18405
  }
17992
- const configFile = path33.join(shadowDir, "config");
18406
+ const configFile = path35.join(shadowDir, "config");
17993
18407
  spawnSync3("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
17994
18408
  timeout: 3e3
17995
18409
  });
@@ -17997,7 +18411,7 @@ function ensureShadowRepo(shadowDir, cwd) {
17997
18411
  timeout: 3e3
17998
18412
  });
17999
18413
  try {
18000
- fs32.writeFileSync(path33.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
18414
+ fs34.writeFileSync(path35.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
18001
18415
  } catch {
18002
18416
  }
18003
18417
  return true;
@@ -18020,12 +18434,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
18020
18434
  let indexFile = null;
18021
18435
  try {
18022
18436
  const rawFilePath = extractFilePath(args);
18023
- const absFilePath = rawFilePath && path33.isAbsolute(rawFilePath) ? rawFilePath : null;
18437
+ const absFilePath = rawFilePath && path35.isAbsolute(rawFilePath) ? rawFilePath : null;
18024
18438
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
18025
18439
  const shadowDir = getShadowRepoDir(cwd);
18026
18440
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
18027
18441
  writeShadowExcludes(shadowDir, ignorePaths);
18028
- indexFile = path33.join(shadowDir, `index_${process.pid}_${Date.now()}`);
18442
+ indexFile = path35.join(shadowDir, `index_${process.pid}_${Date.now()}`);
18029
18443
  const shadowEnv = {
18030
18444
  ...process.env,
18031
18445
  GIT_DIR: shadowDir,
@@ -18097,7 +18511,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
18097
18511
  writeStack(stack);
18098
18512
  const entry = stack[stack.length - 1];
18099
18513
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
18100
- fs32.writeFileSync(UNDO_LATEST_PATH, commitHash);
18514
+ fs34.writeFileSync(UNDO_LATEST_PATH, commitHash);
18101
18515
  if (shouldGc) {
18102
18516
  spawn4("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
18103
18517
  }
@@ -18108,7 +18522,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
18108
18522
  } finally {
18109
18523
  if (indexFile) {
18110
18524
  try {
18111
- fs32.unlinkSync(indexFile);
18525
+ fs34.unlinkSync(indexFile);
18112
18526
  } catch {
18113
18527
  }
18114
18528
  }
@@ -18184,9 +18598,9 @@ function applyUndo(hash, cwd) {
18184
18598
  timeout: GIT_TIMEOUT
18185
18599
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
18186
18600
  for (const file of [...tracked, ...untracked]) {
18187
- const fullPath = path33.join(dir, file);
18188
- if (!snapshotFiles.has(file) && fs32.existsSync(fullPath)) {
18189
- fs32.unlinkSync(fullPath);
18601
+ const fullPath = path35.join(dir, file);
18602
+ if (!snapshotFiles.has(file) && fs34.existsSync(fullPath)) {
18603
+ fs34.unlinkSync(fullPath);
18190
18604
  }
18191
18605
  }
18192
18606
  return true;
@@ -18196,12 +18610,12 @@ function applyUndo(hash, cwd) {
18196
18610
  }
18197
18611
 
18198
18612
  // src/skill-pin.ts
18199
- import fs33 from "fs";
18200
- import path34 from "path";
18201
- import os29 from "os";
18613
+ import fs35 from "fs";
18614
+ import path36 from "path";
18615
+ import os31 from "os";
18202
18616
  import crypto7 from "crypto";
18203
18617
  function getPinsFilePath2() {
18204
- return path34.join(os29.homedir(), ".node9", "skill-pins.json");
18618
+ return path36.join(os31.homedir(), ".node9", "skill-pins.json");
18205
18619
  }
18206
18620
  var MAX_FILES = 5e3;
18207
18621
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
@@ -18215,18 +18629,18 @@ function walkDir(root) {
18215
18629
  if (out.length >= MAX_FILES) return;
18216
18630
  let entries;
18217
18631
  try {
18218
- entries = fs33.readdirSync(dir, { withFileTypes: true });
18632
+ entries = fs35.readdirSync(dir, { withFileTypes: true });
18219
18633
  } catch {
18220
18634
  return;
18221
18635
  }
18222
18636
  entries.sort((a, b) => a.name.localeCompare(b.name));
18223
18637
  for (const entry of entries) {
18224
18638
  if (out.length >= MAX_FILES) return;
18225
- const full = path34.join(dir, entry.name);
18226
- const rel = relDir ? path34.posix.join(relDir, entry.name) : entry.name;
18639
+ const full = path36.join(dir, entry.name);
18640
+ const rel = relDir ? path36.posix.join(relDir, entry.name) : entry.name;
18227
18641
  let lst;
18228
18642
  try {
18229
- lst = fs33.lstatSync(full);
18643
+ lst = fs35.lstatSync(full);
18230
18644
  } catch {
18231
18645
  continue;
18232
18646
  }
@@ -18238,7 +18652,7 @@ function walkDir(root) {
18238
18652
  if (!lst.isFile()) continue;
18239
18653
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
18240
18654
  try {
18241
- const buf = fs33.readFileSync(full);
18655
+ const buf = fs35.readFileSync(full);
18242
18656
  totalBytes += buf.length;
18243
18657
  out.push({ rel, hash: sha256Bytes(buf) });
18244
18658
  } catch {
@@ -18252,14 +18666,14 @@ function walkDir(root) {
18252
18666
  function hashSkillRoot(absPath) {
18253
18667
  let lst;
18254
18668
  try {
18255
- lst = fs33.lstatSync(absPath);
18669
+ lst = fs35.lstatSync(absPath);
18256
18670
  } catch {
18257
18671
  return { exists: false, contentHash: "", fileCount: 0 };
18258
18672
  }
18259
18673
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
18260
18674
  if (lst.isFile()) {
18261
18675
  try {
18262
- return { exists: true, contentHash: sha256Bytes(fs33.readFileSync(absPath)), fileCount: 1 };
18676
+ return { exists: true, contentHash: sha256Bytes(fs35.readFileSync(absPath)), fileCount: 1 };
18263
18677
  } catch {
18264
18678
  return { exists: false, contentHash: "", fileCount: 0 };
18265
18679
  }
@@ -18277,7 +18691,7 @@ function getRootKey(absPath) {
18277
18691
  function readSkillPinsSafe() {
18278
18692
  const filePath = getPinsFilePath2();
18279
18693
  try {
18280
- const raw = fs33.readFileSync(filePath, "utf-8");
18694
+ const raw = fs35.readFileSync(filePath, "utf-8");
18281
18695
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
18282
18696
  const parsed = JSON.parse(raw);
18283
18697
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -18297,10 +18711,10 @@ function readSkillPins() {
18297
18711
  }
18298
18712
  function writeSkillPins(data) {
18299
18713
  const filePath = getPinsFilePath2();
18300
- fs33.mkdirSync(path34.dirname(filePath), { recursive: true });
18714
+ fs35.mkdirSync(path36.dirname(filePath), { recursive: true });
18301
18715
  const tmp = `${filePath}.${crypto7.randomBytes(6).toString("hex")}.tmp`;
18302
- fs33.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
18303
- fs33.renameSync(tmp, filePath);
18716
+ fs35.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
18717
+ fs35.renameSync(tmp, filePath);
18304
18718
  }
18305
18719
  function removePin2(rootKey) {
18306
18720
  const pins = readSkillPins();
@@ -18344,36 +18758,36 @@ function verifyAndPinRoots(roots) {
18344
18758
  return { kind: "verified" };
18345
18759
  }
18346
18760
  function defaultSkillRoots(_cwd) {
18347
- const marketplaces = path34.join(os29.homedir(), ".claude", "plugins", "marketplaces");
18761
+ const marketplaces = path36.join(os31.homedir(), ".claude", "plugins", "marketplaces");
18348
18762
  const roots = [];
18349
18763
  let registries;
18350
18764
  try {
18351
- registries = fs33.readdirSync(marketplaces, { withFileTypes: true });
18765
+ registries = fs35.readdirSync(marketplaces, { withFileTypes: true });
18352
18766
  } catch {
18353
18767
  return [];
18354
18768
  }
18355
18769
  for (const registry of registries) {
18356
18770
  if (!registry.isDirectory()) continue;
18357
- const pluginsDir = path34.join(marketplaces, registry.name, "plugins");
18771
+ const pluginsDir = path36.join(marketplaces, registry.name, "plugins");
18358
18772
  let plugins;
18359
18773
  try {
18360
- plugins = fs33.readdirSync(pluginsDir, { withFileTypes: true });
18774
+ plugins = fs35.readdirSync(pluginsDir, { withFileTypes: true });
18361
18775
  } catch {
18362
18776
  continue;
18363
18777
  }
18364
18778
  for (const plugin of plugins) {
18365
18779
  if (!plugin.isDirectory()) continue;
18366
- roots.push(path34.join(pluginsDir, plugin.name));
18780
+ roots.push(path36.join(pluginsDir, plugin.name));
18367
18781
  }
18368
18782
  }
18369
18783
  return roots;
18370
18784
  }
18371
18785
  function resolveUserSkillRoot(entry, cwd) {
18372
18786
  if (!entry) return null;
18373
- if (entry.startsWith("~/") || entry === "~") return path34.join(os29.homedir(), entry.slice(1));
18374
- if (path34.isAbsolute(entry)) return entry;
18375
- if (!cwd || !path34.isAbsolute(cwd)) return null;
18376
- return path34.join(cwd, entry);
18787
+ if (entry.startsWith("~/") || entry === "~") return path36.join(os31.homedir(), entry.slice(1));
18788
+ if (path36.isAbsolute(entry)) return entry;
18789
+ if (!cwd || !path36.isAbsolute(cwd)) return null;
18790
+ return path36.join(cwd, entry);
18377
18791
  }
18378
18792
 
18379
18793
  // src/cli/commands/check.ts
@@ -18442,9 +18856,9 @@ function registerCheckCommand(program2) {
18442
18856
  } catch (err2) {
18443
18857
  const tempConfig = getConfig();
18444
18858
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
18445
- const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18859
+ const logPath = path37.join(os32.homedir(), ".node9", "hook-debug.log");
18446
18860
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
18447
- fs34.appendFileSync(
18861
+ fs36.appendFileSync(
18448
18862
  logPath,
18449
18863
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
18450
18864
  RAW: ${raw}
@@ -18457,14 +18871,14 @@ RAW: ${raw}
18457
18871
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
18458
18872
  if (process.env.NODE9_DEBUG === "1") {
18459
18873
  try {
18460
- const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18461
- if (!fs34.existsSync(path35.dirname(logPath)))
18462
- fs34.mkdirSync(path35.dirname(logPath), { recursive: true });
18874
+ const logPath = path37.join(os32.homedir(), ".node9", "hook-debug.log");
18875
+ if (!fs36.existsSync(path37.dirname(logPath)))
18876
+ fs36.mkdirSync(path37.dirname(logPath), { recursive: true });
18463
18877
  const sanitized = JSON.stringify({
18464
18878
  ...payload,
18465
18879
  prompt: `<redacted, ${prompt.length} bytes>`
18466
18880
  });
18467
- fs34.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
18881
+ fs36.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
18468
18882
  `);
18469
18883
  } catch {
18470
18884
  }
@@ -18484,8 +18898,8 @@ RAW: ${raw}
18484
18898
  );
18485
18899
  const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
18486
18900
  try {
18487
- const ttyFd = fs34.openSync("/dev/tty", "w");
18488
- fs34.writeSync(
18901
+ const ttyFd = fs36.openSync("/dev/tty", "w");
18902
+ fs36.writeSync(
18489
18903
  ttyFd,
18490
18904
  chalk9.bgRed.white.bold(`
18491
18905
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -18495,7 +18909,7 @@ RAW: ${raw}
18495
18909
 
18496
18910
  `)
18497
18911
  );
18498
- fs34.closeSync(ttyFd);
18912
+ fs36.closeSync(ttyFd);
18499
18913
  } catch {
18500
18914
  }
18501
18915
  const isCodex = agent2 === "Codex";
@@ -18514,16 +18928,16 @@ RAW: ${raw}
18514
18928
  process.exit(2);
18515
18929
  }
18516
18930
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
18517
- const safeCwdForConfig = typeof payloadCwd === "string" && path35.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18931
+ const safeCwdForConfig = typeof payloadCwd === "string" && path37.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18518
18932
  const config = getConfig(safeCwdForConfig);
18519
18933
  if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
18520
18934
  try {
18521
18935
  const scriptPath = process.argv[1];
18522
- if (typeof scriptPath !== "string" || !path35.isAbsolute(scriptPath))
18936
+ if (typeof scriptPath !== "string" || !path37.isAbsolute(scriptPath))
18523
18937
  throw new Error("node9: argv[1] is not an absolute path");
18524
- const resolvedScript = fs34.realpathSync(scriptPath);
18525
- const packageDist = fs34.realpathSync(path35.resolve(__dirname, "../.."));
18526
- if (!resolvedScript.startsWith(packageDist + path35.sep) && resolvedScript !== packageDist)
18938
+ const resolvedScript = fs36.realpathSync(scriptPath);
18939
+ const packageDist = fs36.realpathSync(path37.resolve(__dirname, "../.."));
18940
+ if (!resolvedScript.startsWith(packageDist + path37.sep) && resolvedScript !== packageDist)
18527
18941
  throw new Error(
18528
18942
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
18529
18943
  );
@@ -18545,10 +18959,10 @@ RAW: ${raw}
18545
18959
  });
18546
18960
  d.unref();
18547
18961
  } catch (spawnErr) {
18548
- const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18962
+ const logPath = path37.join(os32.homedir(), ".node9", "hook-debug.log");
18549
18963
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
18550
18964
  try {
18551
- fs34.appendFileSync(
18965
+ fs36.appendFileSync(
18552
18966
  logPath,
18553
18967
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
18554
18968
  `
@@ -18558,10 +18972,10 @@ RAW: ${raw}
18558
18972
  }
18559
18973
  }
18560
18974
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
18561
- const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
18562
- if (!fs34.existsSync(path35.dirname(logPath)))
18563
- fs34.mkdirSync(path35.dirname(logPath), { recursive: true });
18564
- fs34.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
18975
+ const logPath = path37.join(os32.homedir(), ".node9", "hook-debug.log");
18976
+ if (!fs36.existsSync(path37.dirname(logPath)))
18977
+ fs36.mkdirSync(path37.dirname(logPath), { recursive: true });
18978
+ fs36.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
18565
18979
  `);
18566
18980
  }
18567
18981
  const rawToolName = sanitize2(extractToolName(payload));
@@ -18575,8 +18989,8 @@ RAW: ${raw}
18575
18989
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
18576
18990
  let ttyFd = null;
18577
18991
  try {
18578
- ttyFd = fs34.openSync("/dev/tty", "w");
18579
- const writeTty = (line) => fs34.writeSync(ttyFd, line + "\n");
18992
+ ttyFd = fs36.openSync("/dev/tty", "w");
18993
+ const writeTty = (line) => fs36.writeSync(ttyFd, line + "\n");
18580
18994
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
18581
18995
  writeTty(chalk9.bgRed.white.bold(`
18582
18996
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -18595,7 +19009,7 @@ RAW: ${raw}
18595
19009
  } finally {
18596
19010
  if (ttyFd !== null)
18597
19011
  try {
18598
- fs34.closeSync(ttyFd);
19012
+ fs36.closeSync(ttyFd);
18599
19013
  } catch {
18600
19014
  }
18601
19015
  }
@@ -18646,17 +19060,17 @@ RAW: ${raw}
18646
19060
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
18647
19061
  if (skillPinCfg.enabled && safeSessionId) {
18648
19062
  try {
18649
- const sessionsDir = path35.join(os30.homedir(), ".node9", "skill-sessions");
18650
- const flagPath = path35.join(sessionsDir, `${safeSessionId}.json`);
19063
+ const sessionsDir = path37.join(os32.homedir(), ".node9", "skill-sessions");
19064
+ const flagPath = path37.join(sessionsDir, `${safeSessionId}.json`);
18651
19065
  let flag = null;
18652
19066
  try {
18653
- flag = JSON.parse(fs34.readFileSync(flagPath, "utf-8"));
19067
+ flag = JSON.parse(fs36.readFileSync(flagPath, "utf-8"));
18654
19068
  } catch {
18655
19069
  }
18656
19070
  const writeFlag = (data2) => {
18657
19071
  try {
18658
- fs34.mkdirSync(sessionsDir, { recursive: true });
18659
- fs34.writeFileSync(
19072
+ fs36.mkdirSync(sessionsDir, { recursive: true });
19073
+ fs36.writeFileSync(
18660
19074
  flagPath,
18661
19075
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
18662
19076
  { mode: 384 }
@@ -18667,8 +19081,8 @@ RAW: ${raw}
18667
19081
  const sendSkillWarn = (detail, recoveryCmd) => {
18668
19082
  let ttyFd = null;
18669
19083
  try {
18670
- ttyFd = fs34.openSync("/dev/tty", "w");
18671
- const w = (line) => fs34.writeSync(ttyFd, line + "\n");
19084
+ ttyFd = fs36.openSync("/dev/tty", "w");
19085
+ const w = (line) => fs36.writeSync(ttyFd, line + "\n");
18672
19086
  w(chalk9.yellow(`
18673
19087
  \u26A0\uFE0F Node9: installed skill drift detected`));
18674
19088
  w(chalk9.gray(` ${detail}`));
@@ -18683,7 +19097,7 @@ RAW: ${raw}
18683
19097
  } finally {
18684
19098
  if (ttyFd !== null)
18685
19099
  try {
18686
- fs34.closeSync(ttyFd);
19100
+ fs36.closeSync(ttyFd);
18687
19101
  } catch {
18688
19102
  }
18689
19103
  }
@@ -18699,7 +19113,7 @@ RAW: ${raw}
18699
19113
  return;
18700
19114
  }
18701
19115
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
18702
- const absoluteCwd = typeof payloadCwd === "string" && path35.isAbsolute(payloadCwd) ? payloadCwd : void 0;
19116
+ const absoluteCwd = typeof payloadCwd === "string" && path37.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18703
19117
  const extraRoots = skillPinCfg.roots;
18704
19118
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
18705
19119
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -18740,10 +19154,10 @@ RAW: ${raw}
18740
19154
  }
18741
19155
  try {
18742
19156
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
18743
- for (const name of fs34.readdirSync(sessionsDir)) {
18744
- const p = path35.join(sessionsDir, name);
19157
+ for (const name of fs36.readdirSync(sessionsDir)) {
19158
+ const p = path37.join(sessionsDir, name);
18745
19159
  try {
18746
- if (fs34.statSync(p).mtimeMs < cutoff) fs34.unlinkSync(p);
19160
+ if (fs36.statSync(p).mtimeMs < cutoff) fs36.unlinkSync(p);
18747
19161
  } catch {
18748
19162
  }
18749
19163
  }
@@ -18753,9 +19167,9 @@ RAW: ${raw}
18753
19167
  } catch (err2) {
18754
19168
  if (process.env.NODE9_DEBUG === "1") {
18755
19169
  try {
18756
- const dbg = path35.join(os30.homedir(), ".node9", "hook-debug.log");
19170
+ const dbg = path37.join(os32.homedir(), ".node9", "hook-debug.log");
18757
19171
  const msg = err2 instanceof Error ? err2.message : String(err2);
18758
- fs34.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
19172
+ fs36.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
18759
19173
  `);
18760
19174
  } catch {
18761
19175
  }
@@ -18765,7 +19179,7 @@ RAW: ${raw}
18765
19179
  if (shouldSnapshot(toolName, toolInput, config)) {
18766
19180
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
18767
19181
  }
18768
- const safeCwdForAuth = typeof payloadCwd === "string" && path35.isAbsolute(payloadCwd) ? payloadCwd : void 0;
19182
+ const safeCwdForAuth = typeof payloadCwd === "string" && path37.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18769
19183
  const result = await authorizeHeadless(toolName, toolInput, meta, {
18770
19184
  cwd: safeCwdForAuth
18771
19185
  });
@@ -18777,12 +19191,12 @@ RAW: ${raw}
18777
19191
  }
18778
19192
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
18779
19193
  try {
18780
- const tty = fs34.openSync("/dev/tty", "w");
18781
- fs34.writeSync(
19194
+ const tty = fs36.openSync("/dev/tty", "w");
19195
+ fs36.writeSync(
18782
19196
  tty,
18783
19197
  chalk9.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
18784
19198
  );
18785
- fs34.closeSync(tty);
19199
+ fs36.closeSync(tty);
18786
19200
  } catch {
18787
19201
  }
18788
19202
  const daemonReady = await autoStartDaemonAndWait();
@@ -18809,9 +19223,9 @@ RAW: ${raw}
18809
19223
  });
18810
19224
  } catch (err2) {
18811
19225
  if (process.env.NODE9_DEBUG === "1") {
18812
- const logPath = path35.join(os30.homedir(), ".node9", "hook-debug.log");
19226
+ const logPath = path37.join(os32.homedir(), ".node9", "hook-debug.log");
18813
19227
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
18814
- fs34.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
19228
+ fs36.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
18815
19229
  `);
18816
19230
  }
18817
19231
  process.exit(0);
@@ -18831,8 +19245,8 @@ RAW: ${raw}
18831
19245
  await processPayload(raw);
18832
19246
  };
18833
19247
  process.stdin.setEncoding("utf-8");
18834
- process.stdin.on("data", (chunk) => {
18835
- raw += chunk;
19248
+ process.stdin.on("data", (chunk2) => {
19249
+ raw += chunk2;
18836
19250
  if (inactivityTimer) clearTimeout(inactivityTimer);
18837
19251
  inactivityTimer = setTimeout(() => void done(), 2e3);
18838
19252
  });
@@ -18847,9 +19261,9 @@ RAW: ${raw}
18847
19261
  // src/cli/commands/log.ts
18848
19262
  init_audit();
18849
19263
  init_config();
18850
- import fs35 from "fs";
18851
- import path36 from "path";
18852
- import os31 from "os";
19264
+ import fs37 from "fs";
19265
+ import path38 from "path";
19266
+ import os33 from "os";
18853
19267
  init_daemon();
18854
19268
 
18855
19269
  // src/utils/cp-mv-parser.ts
@@ -18942,10 +19356,10 @@ function registerLogCommand(program2) {
18942
19356
  if (rawToolName !== tool) entry.agentToolName = rawToolName;
18943
19357
  const payloadSessionId = payload.session_id ?? payload.conversationId;
18944
19358
  if (payloadSessionId) entry.sessionId = payloadSessionId;
18945
- const logPath = path36.join(os31.homedir(), ".node9", "audit.log");
18946
- if (!fs35.existsSync(path36.dirname(logPath)))
18947
- fs35.mkdirSync(path36.dirname(logPath), { recursive: true });
18948
- fs35.appendFileSync(logPath, JSON.stringify(entry) + "\n");
19359
+ const logPath = path38.join(os33.homedir(), ".node9", "audit.log");
19360
+ if (!fs37.existsSync(path38.dirname(logPath)))
19361
+ fs37.mkdirSync(path38.dirname(logPath), { recursive: true });
19362
+ fs37.appendFileSync(logPath, JSON.stringify(entry) + "\n");
18949
19363
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
18950
19364
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
18951
19365
  if (command) {
@@ -18979,7 +19393,7 @@ function registerLogCommand(program2) {
18979
19393
  }
18980
19394
  }
18981
19395
  const payloadCwd = typeof payload.cwd === "string" ? payload.cwd : Array.isArray(payload.workspacePaths) && typeof payload.workspacePaths[0] === "string" ? payload.workspacePaths[0] : void 0;
18982
- const safeCwd = typeof payloadCwd === "string" && path36.isAbsolute(payloadCwd) ? payloadCwd : void 0;
19396
+ const safeCwd = typeof payloadCwd === "string" && path38.isAbsolute(payloadCwd) ? payloadCwd : void 0;
18983
19397
  const config = getConfig(safeCwd);
18984
19398
  if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
18985
19399
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
@@ -19000,9 +19414,9 @@ function registerLogCommand(program2) {
19000
19414
  const msg = err2 instanceof Error ? err2.message : String(err2);
19001
19415
  process.stderr.write(`[Node9] audit log error: ${msg}
19002
19416
  `);
19003
- const debugPath = path36.join(os31.homedir(), ".node9", "hook-debug.log");
19417
+ const debugPath = path38.join(os33.homedir(), ".node9", "hook-debug.log");
19004
19418
  try {
19005
- fs35.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
19419
+ fs37.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
19006
19420
  `);
19007
19421
  } catch {
19008
19422
  }
@@ -19014,7 +19428,7 @@ function registerLogCommand(program2) {
19014
19428
  } else {
19015
19429
  let raw = "";
19016
19430
  process.stdin.setEncoding("utf-8");
19017
- process.stdin.on("data", (chunk) => raw += chunk);
19431
+ process.stdin.on("data", (chunk2) => raw += chunk2);
19018
19432
  process.stdin.on("end", () => {
19019
19433
  void logPayload(raw);
19020
19434
  });
@@ -19042,7 +19456,7 @@ function httpsFetch(url) {
19042
19456
  return;
19043
19457
  }
19044
19458
  const chunks = [];
19045
- res.on("data", (chunk) => chunks.push(chunk));
19459
+ res.on("data", (chunk2) => chunks.push(chunk2));
19046
19460
  res.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
19047
19461
  res.on("error", reject);
19048
19462
  }).on("error", reject);
@@ -19404,13 +19818,13 @@ function registerConfigShowCommand(program2) {
19404
19818
  init_daemon();
19405
19819
  init_config();
19406
19820
  import chalk11 from "chalk";
19407
- import fs36 from "fs";
19408
- import path37 from "path";
19409
- import os32 from "os";
19821
+ import fs38 from "fs";
19822
+ import path39 from "path";
19823
+ import os34 from "os";
19410
19824
  import { execSync } from "child_process";
19411
19825
  function registerDoctorCommand(program2, version2) {
19412
19826
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
19413
- const homeDir2 = os32.homedir();
19827
+ const homeDir2 = os34.homedir();
19414
19828
  let failures = 0;
19415
19829
  function pass(msg) {
19416
19830
  console.log(chalk11.green(" \u2705 ") + msg);
@@ -19459,10 +19873,10 @@ function registerDoctorCommand(program2, version2) {
19459
19873
  );
19460
19874
  }
19461
19875
  section("Configuration");
19462
- const globalConfigPath = path37.join(homeDir2, ".node9", "config.json");
19463
- if (fs36.existsSync(globalConfigPath)) {
19876
+ const globalConfigPath = path39.join(homeDir2, ".node9", "config.json");
19877
+ if (fs38.existsSync(globalConfigPath)) {
19464
19878
  try {
19465
- JSON.parse(fs36.readFileSync(globalConfigPath, "utf-8"));
19879
+ JSON.parse(fs38.readFileSync(globalConfigPath, "utf-8"));
19466
19880
  pass("~/.node9/config.json found and valid");
19467
19881
  } catch {
19468
19882
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -19470,10 +19884,10 @@ function registerDoctorCommand(program2, version2) {
19470
19884
  } else {
19471
19885
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
19472
19886
  }
19473
- const projectConfigPath = path37.join(process.cwd(), "node9.config.json");
19474
- if (fs36.existsSync(projectConfigPath)) {
19887
+ const projectConfigPath = path39.join(process.cwd(), "node9.config.json");
19888
+ if (fs38.existsSync(projectConfigPath)) {
19475
19889
  try {
19476
- JSON.parse(fs36.readFileSync(projectConfigPath, "utf-8"));
19890
+ JSON.parse(fs38.readFileSync(projectConfigPath, "utf-8"));
19477
19891
  pass("node9.config.json found and valid (project)");
19478
19892
  } catch {
19479
19893
  fail(
@@ -19482,8 +19896,8 @@ function registerDoctorCommand(program2, version2) {
19482
19896
  );
19483
19897
  }
19484
19898
  }
19485
- const credsPath = path37.join(homeDir2, ".node9", "credentials.json");
19486
- if (fs36.existsSync(credsPath)) {
19899
+ const credsPath = path39.join(homeDir2, ".node9", "credentials.json");
19900
+ if (fs38.existsSync(credsPath)) {
19487
19901
  pass("Cloud credentials found (~/.node9/credentials.json)");
19488
19902
  } else {
19489
19903
  warn(
@@ -19492,10 +19906,10 @@ function registerDoctorCommand(program2, version2) {
19492
19906
  );
19493
19907
  }
19494
19908
  section("Agent Hooks");
19495
- const claudeSettingsPath = path37.join(homeDir2, ".claude", "settings.json");
19496
- if (fs36.existsSync(claudeSettingsPath)) {
19909
+ const claudeSettingsPath = path39.join(homeDir2, ".claude", "settings.json");
19910
+ if (fs38.existsSync(claudeSettingsPath)) {
19497
19911
  try {
19498
- const cs = JSON.parse(fs36.readFileSync(claudeSettingsPath, "utf-8"));
19912
+ const cs = JSON.parse(fs38.readFileSync(claudeSettingsPath, "utf-8"));
19499
19913
  const hasHook = cs.hooks?.PreToolUse?.some(
19500
19914
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
19501
19915
  );
@@ -19511,10 +19925,10 @@ function registerDoctorCommand(program2, version2) {
19511
19925
  } else {
19512
19926
  warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
19513
19927
  }
19514
- const geminiSettingsPath = path37.join(homeDir2, ".gemini", "settings.json");
19515
- if (fs36.existsSync(geminiSettingsPath)) {
19928
+ const geminiSettingsPath = path39.join(homeDir2, ".gemini", "settings.json");
19929
+ if (fs38.existsSync(geminiSettingsPath)) {
19516
19930
  try {
19517
- const gs = JSON.parse(fs36.readFileSync(geminiSettingsPath, "utf-8"));
19931
+ const gs = JSON.parse(fs38.readFileSync(geminiSettingsPath, "utf-8"));
19518
19932
  const hasHook = gs.hooks?.BeforeTool?.some(
19519
19933
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
19520
19934
  );
@@ -19530,10 +19944,10 @@ function registerDoctorCommand(program2, version2) {
19530
19944
  } else {
19531
19945
  warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
19532
19946
  }
19533
- const cursorHooksPath = path37.join(homeDir2, ".cursor", "hooks.json");
19534
- if (fs36.existsSync(cursorHooksPath)) {
19947
+ const cursorHooksPath = path39.join(homeDir2, ".cursor", "hooks.json");
19948
+ if (fs38.existsSync(cursorHooksPath)) {
19535
19949
  try {
19536
- const cur = JSON.parse(fs36.readFileSync(cursorHooksPath, "utf-8"));
19950
+ const cur = JSON.parse(fs38.readFileSync(cursorHooksPath, "utf-8"));
19537
19951
  const hasHook = cur.hooks?.preToolUse?.some(
19538
19952
  (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
19539
19953
  );
@@ -19564,7 +19978,7 @@ function registerDoctorCommand(program2, version2) {
19564
19978
  try {
19565
19979
  const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
19566
19980
  const cfg = getConfig();
19567
- const creds = fs36.existsSync(path37.join(os32.homedir(), ".node9", "credentials.json"));
19981
+ const creds = fs38.existsSync(path39.join(os34.homedir(), ".node9", "credentials.json"));
19568
19982
  if (!creds) {
19569
19983
  warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
19570
19984
  } else if (!cfg.settings.approvers.cloud) {
@@ -19614,9 +20028,9 @@ function registerDoctorCommand(program2, version2) {
19614
20028
 
19615
20029
  // src/cli/commands/audit.ts
19616
20030
  import chalk12 from "chalk";
19617
- import fs37 from "fs";
19618
- import path38 from "path";
19619
- import os33 from "os";
20031
+ import fs39 from "fs";
20032
+ import path40 from "path";
20033
+ import os35 from "os";
19620
20034
  function formatRelativeTime(timestamp) {
19621
20035
  const diff = Date.now() - new Date(timestamp).getTime();
19622
20036
  const sec = Math.floor(diff / 1e3);
@@ -19629,14 +20043,14 @@ function formatRelativeTime(timestamp) {
19629
20043
  }
19630
20044
  function registerAuditCommand(program2) {
19631
20045
  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) => {
19632
- const logPath = path38.join(os33.homedir(), ".node9", "audit.log");
19633
- if (!fs37.existsSync(logPath)) {
20046
+ const logPath = path40.join(os35.homedir(), ".node9", "audit.log");
20047
+ if (!fs39.existsSync(logPath)) {
19634
20048
  console.log(
19635
20049
  chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
19636
20050
  );
19637
20051
  return;
19638
20052
  }
19639
- const raw = fs37.readFileSync(logPath, "utf-8");
20053
+ const raw = fs39.readFileSync(logPath, "utf-8");
19640
20054
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
19641
20055
  let entries = lines.flatMap((line) => {
19642
20056
  try {
@@ -19694,9 +20108,9 @@ import chalk13 from "chalk";
19694
20108
  // src/cli/aggregate/report-audit.ts
19695
20109
  init_costSync();
19696
20110
  init_litellm();
19697
- import fs38 from "fs";
19698
- import os34 from "os";
19699
- import path39 from "path";
20111
+ import fs40 from "fs";
20112
+ import os36 from "os";
20113
+ import path41 from "path";
19700
20114
  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;
19701
20115
  function buildTestTimestamps(allEntries) {
19702
20116
  const testTs = /* @__PURE__ */ new Set();
@@ -19776,8 +20190,8 @@ function getDateRange(period, now) {
19776
20190
  }
19777
20191
  }
19778
20192
  function parseAuditLog(logPath) {
19779
- if (!fs38.existsSync(logPath)) return [];
19780
- const raw = fs38.readFileSync(logPath, "utf-8");
20193
+ if (!fs40.existsSync(logPath)) return [];
20194
+ const raw = fs40.readFileSync(logPath, "utf-8");
19781
20195
  return raw.split("\n").flatMap((line) => {
19782
20196
  if (!line.trim()) return [];
19783
20197
  try {
@@ -19837,25 +20251,25 @@ function freezeClaudeCost(acc) {
19837
20251
  };
19838
20252
  }
19839
20253
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
19840
- const projPath = path39.join(projectsDir, proj);
20254
+ const projPath = path41.join(projectsDir, proj);
19841
20255
  let files;
19842
20256
  try {
19843
- const stat = fs38.statSync(projPath);
20257
+ const stat = fs40.statSync(projPath);
19844
20258
  if (!stat.isDirectory()) return;
19845
- files = fs38.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
20259
+ files = fs40.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
19846
20260
  } catch {
19847
20261
  return;
19848
20262
  }
19849
20263
  const startMs = start.getTime();
19850
20264
  for (const file of files) {
19851
- const filePath = path39.join(projPath, file);
20265
+ const filePath = path41.join(projPath, file);
19852
20266
  try {
19853
- if (fs38.statSync(filePath).mtimeMs < startMs) continue;
20267
+ if (fs40.statSync(filePath).mtimeMs < startMs) continue;
19854
20268
  } catch {
19855
20269
  continue;
19856
20270
  }
19857
20271
  try {
19858
- const raw = fs38.readFileSync(filePath, "utf-8");
20272
+ const raw = fs40.readFileSync(filePath, "utf-8");
19859
20273
  for (const line of raw.split("\n")) {
19860
20274
  if (!line.trim()) continue;
19861
20275
  let entry;
@@ -19905,10 +20319,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
19905
20319
  }
19906
20320
  function loadClaudeCost(start, end, projectsDir) {
19907
20321
  const acc = emptyClaudeCostAccumulator();
19908
- if (!fs38.existsSync(projectsDir)) return freezeClaudeCost(acc);
20322
+ if (!fs40.existsSync(projectsDir)) return freezeClaudeCost(acc);
19909
20323
  let dirs;
19910
20324
  try {
19911
- dirs = fs38.readdirSync(projectsDir);
20325
+ dirs = fs40.readdirSync(projectsDir);
19912
20326
  } catch {
19913
20327
  return freezeClaudeCost(acc);
19914
20328
  }
@@ -19920,7 +20334,7 @@ function loadClaudeCost(start, end, projectsDir) {
19920
20334
  function processCodexCostFile(filePath, start, end, acc) {
19921
20335
  let lines;
19922
20336
  try {
19923
- lines = fs38.readFileSync(filePath, "utf-8").split("\n");
20337
+ lines = fs40.readFileSync(filePath, "utf-8").split("\n");
19924
20338
  } catch {
19925
20339
  return;
19926
20340
  }
@@ -19963,33 +20377,33 @@ function processCodexCostFile(filePath, start, end, acc) {
19963
20377
  const dateKey = sessionStart2.slice(0, 10);
19964
20378
  acc.byDay.set(dateKey, (acc.byDay.get(dateKey) ?? 0) + cost);
19965
20379
  }
19966
- function listCodexSessionFiles(sessionsBase) {
20380
+ function listCodexSessionFiles2(sessionsBase) {
19967
20381
  const jsonlFiles = [];
19968
- if (!fs38.existsSync(sessionsBase)) return jsonlFiles;
20382
+ if (!fs40.existsSync(sessionsBase)) return jsonlFiles;
19969
20383
  try {
19970
- for (const year of fs38.readdirSync(sessionsBase)) {
19971
- const yearPath = path39.join(sessionsBase, year);
20384
+ for (const year of fs40.readdirSync(sessionsBase)) {
20385
+ const yearPath = path41.join(sessionsBase, year);
19972
20386
  try {
19973
- if (!fs38.statSync(yearPath).isDirectory()) continue;
20387
+ if (!fs40.statSync(yearPath).isDirectory()) continue;
19974
20388
  } catch {
19975
20389
  continue;
19976
20390
  }
19977
- for (const month of fs38.readdirSync(yearPath)) {
19978
- const monthPath = path39.join(yearPath, month);
20391
+ for (const month of fs40.readdirSync(yearPath)) {
20392
+ const monthPath = path41.join(yearPath, month);
19979
20393
  try {
19980
- if (!fs38.statSync(monthPath).isDirectory()) continue;
20394
+ if (!fs40.statSync(monthPath).isDirectory()) continue;
19981
20395
  } catch {
19982
20396
  continue;
19983
20397
  }
19984
- for (const day of fs38.readdirSync(monthPath)) {
19985
- const dayPath = path39.join(monthPath, day);
20398
+ for (const day of fs40.readdirSync(monthPath)) {
20399
+ const dayPath = path41.join(monthPath, day);
19986
20400
  try {
19987
- if (!fs38.statSync(dayPath).isDirectory()) continue;
20401
+ if (!fs40.statSync(dayPath).isDirectory()) continue;
19988
20402
  } catch {
19989
20403
  continue;
19990
20404
  }
19991
- for (const file of fs38.readdirSync(dayPath)) {
19992
- if (file.endsWith(".jsonl")) jsonlFiles.push(path39.join(dayPath, file));
20405
+ for (const file of fs40.readdirSync(dayPath)) {
20406
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path41.join(dayPath, file));
19993
20407
  }
19994
20408
  }
19995
20409
  }
@@ -20001,17 +20415,17 @@ function listCodexSessionFiles(sessionsBase) {
20001
20415
  }
20002
20416
  function loadCodexCost(start, end, sessionsBase) {
20003
20417
  const acc = { total: 0, toolCalls: 0, byDay: /* @__PURE__ */ new Map() };
20004
- const files = listCodexSessionFiles(sessionsBase);
20418
+ const files = listCodexSessionFiles2(sessionsBase);
20005
20419
  for (const filePath of files) {
20006
20420
  processCodexCostFile(filePath, start, end, acc);
20007
20421
  }
20008
20422
  return { total: acc.total, byDay: acc.byDay, toolCalls: acc.toolCalls };
20009
20423
  }
20010
- var GEMINI_FALLBACK_MODELS = ["gemini-2.5-flash", "gemini-2.0-flash"];
20011
- function geminiPriceFor(model) {
20424
+ var GEMINI_FALLBACK_MODELS2 = ["gemini-2.5-flash", "gemini-2.0-flash"];
20425
+ function geminiPriceFor2(model) {
20012
20426
  let tuple = pricingFor(model);
20013
20427
  if (!tuple && /^gemini-/i.test(model)) {
20014
- for (const proxy of GEMINI_FALLBACK_MODELS) {
20428
+ for (const proxy of GEMINI_FALLBACK_MODELS2) {
20015
20429
  tuple = pricingFor(proxy);
20016
20430
  if (tuple) break;
20017
20431
  }
@@ -20042,13 +20456,13 @@ function freezeGeminiCost(acc) {
20042
20456
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
20043
20457
  const startMs = start.getTime();
20044
20458
  try {
20045
- if (fs38.statSync(filePath).mtimeMs < startMs) return;
20459
+ if (fs40.statSync(filePath).mtimeMs < startMs) return;
20046
20460
  } catch {
20047
20461
  return;
20048
20462
  }
20049
20463
  let raw;
20050
20464
  try {
20051
- raw = fs38.readFileSync(filePath, "utf-8");
20465
+ raw = fs40.readFileSync(filePath, "utf-8");
20052
20466
  } catch {
20053
20467
  return;
20054
20468
  }
@@ -20069,7 +20483,7 @@ function processGeminiCostFile(filePath, projectKey, start, end, acc) {
20069
20483
  }
20070
20484
  const ts = new Date(entry.timestamp);
20071
20485
  if (ts < start || ts > end) continue;
20072
- const price = geminiPriceFor(entry.model);
20486
+ const price = geminiPriceFor2(entry.model);
20073
20487
  if (!price) continue;
20074
20488
  const inp = entry.tokens.input ?? 0;
20075
20489
  const out = entry.tokens.output ?? 0;
@@ -20093,46 +20507,46 @@ function processGeminiCostFile(filePath, projectKey, start, end, acc) {
20093
20507
  acc.byProject.set(projectKey, rollup);
20094
20508
  }
20095
20509
  }
20096
- function listGeminiSessionFiles(geminiTmpDir) {
20510
+ function listGeminiSessionFiles2(geminiTmpDir2) {
20097
20511
  const out = [];
20098
20512
  let dirs;
20099
20513
  try {
20100
- if (!fs38.statSync(geminiTmpDir).isDirectory()) return out;
20101
- dirs = fs38.readdirSync(geminiTmpDir);
20514
+ if (!fs40.statSync(geminiTmpDir2).isDirectory()) return out;
20515
+ dirs = fs40.readdirSync(geminiTmpDir2);
20102
20516
  } catch {
20103
20517
  return out;
20104
20518
  }
20105
20519
  for (const proj of dirs) {
20106
- const chatsDir = path39.join(geminiTmpDir, proj, "chats");
20520
+ const chatsDir = path41.join(geminiTmpDir2, proj, "chats");
20107
20521
  let files;
20108
20522
  try {
20109
- if (!fs38.statSync(chatsDir).isDirectory()) continue;
20110
- files = fs38.readdirSync(chatsDir);
20523
+ if (!fs40.statSync(chatsDir).isDirectory()) continue;
20524
+ files = fs40.readdirSync(chatsDir);
20111
20525
  } catch {
20112
20526
  continue;
20113
20527
  }
20114
20528
  for (const f of files) {
20115
20529
  if (!f.endsWith(".jsonl")) continue;
20116
- out.push({ projectKey: proj, file: path39.join(chatsDir, f) });
20530
+ out.push({ projectKey: proj, file: path41.join(chatsDir, f) });
20117
20531
  }
20118
20532
  }
20119
20533
  return out;
20120
20534
  }
20121
- function loadGeminiCost(start, end, geminiTmpDir) {
20535
+ function loadGeminiCost(start, end, geminiTmpDir2) {
20122
20536
  const acc = emptyGeminiAccumulator();
20123
- if (!fs38.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
20124
- for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
20537
+ if (!fs40.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
20538
+ for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
20125
20539
  processGeminiCostFile(file, projectKey, start, end, acc);
20126
20540
  }
20127
20541
  return freezeGeminiCost(acc);
20128
20542
  }
20129
20543
  function aggregateReportFromAudit(period, opts = {}) {
20130
20544
  const now = opts.now ?? /* @__PURE__ */ new Date();
20131
- const auditLogPath = opts.auditLogPath ?? path39.join(os34.homedir(), ".node9", "audit.log");
20132
- const claudeProjectsDir = opts.claudeProjectsDir ?? path39.join(os34.homedir(), ".claude", "projects");
20133
- const codexSessionsDir = opts.codexSessionsDir ?? path39.join(os34.homedir(), ".codex", "sessions");
20134
- const geminiTmpDir = opts.geminiTmpDir ?? path39.join(os34.homedir(), ".gemini", "tmp");
20135
- const hasAuditFile = fs38.existsSync(auditLogPath);
20545
+ const auditLogPath = opts.auditLogPath ?? path41.join(os36.homedir(), ".node9", "audit.log");
20546
+ const claudeProjectsDir = opts.claudeProjectsDir ?? path41.join(os36.homedir(), ".claude", "projects");
20547
+ const codexSessionsDir2 = opts.codexSessionsDir ?? path41.join(os36.homedir(), ".codex", "sessions");
20548
+ const geminiTmpDir2 = opts.geminiTmpDir ?? path41.join(os36.homedir(), ".gemini", "tmp");
20549
+ const hasAuditFile = fs40.existsSync(auditLogPath);
20136
20550
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
20137
20551
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
20138
20552
  const { start, end } = getDateRange(period, now);
@@ -20149,8 +20563,8 @@ function aggregateReportFromAudit(period, opts = {}) {
20149
20563
  };
20150
20564
  });
20151
20565
  const claudeCost = opts.preloadedClaudeCost ?? loadClaudeCost(start, end, claudeProjectsDir);
20152
- const codexCost = opts.preloadedCodexCost ?? loadCodexCost(start, end, codexSessionsDir);
20153
- const geminiCost = opts.preloadedGeminiCost ?? loadGeminiCost(start, end, geminiTmpDir);
20566
+ const codexCost = opts.preloadedCodexCost ?? loadCodexCost(start, end, codexSessionsDir2);
20567
+ const geminiCost = opts.preloadedGeminiCost ?? loadGeminiCost(start, end, geminiTmpDir2);
20154
20568
  for (const [day, c] of codexCost.byDay) {
20155
20569
  claudeCost.byDay.set(day, (claudeCost.byDay.get(day) ?? 0) + c);
20156
20570
  }
@@ -20829,20 +21243,47 @@ function registerDaemonCommand(program2) {
20829
21243
  // src/cli/commands/status.ts
20830
21244
  init_core();
20831
21245
  init_daemon();
21246
+ init_setup();
20832
21247
  import chalk15 from "chalk";
20833
- import fs39 from "fs";
20834
- import path40 from "path";
20835
- import os35 from "os";
21248
+ import fs41 from "fs";
21249
+ import path42 from "path";
21250
+ import os37 from "os";
21251
+ import * as yaml2 from "yaml";
21252
+ function readHermesHooks(configPath) {
21253
+ if (!fs41.existsSync(configPath)) return null;
21254
+ let raw;
21255
+ try {
21256
+ raw = fs41.readFileSync(configPath, "utf-8");
21257
+ } catch {
21258
+ return null;
21259
+ }
21260
+ try {
21261
+ const cfg = yaml2.parse(raw);
21262
+ const has = (event) => (cfg?.hooks?.[event] ?? []).some(
21263
+ (e) => typeof e?.command === "string" && isNode9Hook(e.command)
21264
+ );
21265
+ return { pre: has("pre_tool_call"), post: has("post_tool_call") };
21266
+ } catch {
21267
+ console.error(
21268
+ chalk15.yellow(
21269
+ ` \u26A0\uFE0F Hermes config.yaml at ${configPath} is not valid YAML \u2014 showing as unwired.`
21270
+ )
21271
+ );
21272
+ return { pre: false, post: false };
21273
+ }
21274
+ }
20836
21275
  function readJson2(filePath) {
20837
21276
  try {
20838
- if (fs39.existsSync(filePath)) return JSON.parse(fs39.readFileSync(filePath, "utf-8"));
21277
+ if (fs41.existsSync(filePath)) return JSON.parse(fs41.readFileSync(filePath, "utf-8"));
20839
21278
  } catch {
20840
21279
  }
20841
21280
  return null;
20842
21281
  }
20843
- function isNode9Hook2(cmd) {
20844
- if (!cmd) return false;
20845
- return /(?:^|[\s/\\])node9 (?:check|log)/.test(cmd) || /(?:^|[\s/\\])cli\.js (?:check|log)/.test(cmd);
21282
+ function matchersHaveNode9Hook(matchers) {
21283
+ return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
21284
+ }
21285
+ function flatHaveNode9Hook(entries) {
21286
+ return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
20846
21287
  }
20847
21288
  function wrappedMcpServers(servers) {
20848
21289
  if (!servers) return [];
@@ -20857,6 +21298,7 @@ function printAgentSection(label, hookPairs, wrapped) {
20857
21298
  console.log(chalk15.red(` \u2717 ${name}`) + chalk15.gray(" (not wired)"));
20858
21299
  }
20859
21300
  }
21301
+ if (wrapped === null) return;
20860
21302
  if (wrapped.length > 0) {
20861
21303
  console.log(chalk15.cyan(` MCP proxied:`));
20862
21304
  for (const entry of wrapped) {
@@ -20900,40 +21342,51 @@ function registerStatusCommand(program2) {
20900
21342
  console.log("");
20901
21343
  const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
20902
21344
  console.log(` Mode: ${modeLabel}`);
20903
- const projectConfig = path40.join(process.cwd(), "node9.config.json");
20904
- const globalConfig = path40.join(os35.homedir(), ".node9", "config.json");
21345
+ const projectConfig = path42.join(process.cwd(), "node9.config.json");
21346
+ const globalConfig = path42.join(os37.homedir(), ".node9", "config.json");
20905
21347
  console.log(
20906
- ` Local: ${fs39.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
21348
+ ` Local: ${fs41.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
20907
21349
  );
20908
21350
  console.log(
20909
- ` Global: ${fs39.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
21351
+ ` Global: ${fs41.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
20910
21352
  );
20911
21353
  if (mergedConfig.policy.sandboxPaths.length > 0) {
20912
21354
  console.log(
20913
21355
  ` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
20914
21356
  );
20915
21357
  }
20916
- const homeDir2 = os35.homedir();
21358
+ const homeDir2 = os37.homedir();
20917
21359
  const claudeSettings = readJson2(
20918
- path40.join(homeDir2, ".claude", "settings.json")
21360
+ path42.join(homeDir2, ".claude", "settings.json")
20919
21361
  );
20920
- const claudeConfig = readJson2(path40.join(homeDir2, ".claude.json"));
21362
+ const claudeConfig = readJson2(path42.join(homeDir2, ".claude.json"));
20921
21363
  const geminiSettings = readJson2(
20922
- path40.join(homeDir2, ".gemini", "settings.json")
21364
+ path42.join(homeDir2, ".gemini", "settings.json")
21365
+ );
21366
+ const cursorConfig = readJson2(path42.join(homeDir2, ".cursor", "mcp.json"));
21367
+ const antigravityHooks = readJson2(
21368
+ path42.join(homeDir2, ".gemini", "config", "hooks.json")
20923
21369
  );
20924
- const cursorConfig = readJson2(path40.join(homeDir2, ".cursor", "mcp.json"));
20925
- const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
21370
+ const antigravityMcp = readJson2(
21371
+ path42.join(homeDir2, ".gemini", "config", "mcp_config.json")
21372
+ );
21373
+ const antigravityPresent = antigravityHooks !== null || fs41.existsSync(path42.join(homeDir2, ".gemini", "antigravity-cli")) || fs41.existsSync(path42.join(homeDir2, ".gemini", "antigravity-ide"));
21374
+ const copilotHooks = readJson2(
21375
+ path42.join(homeDir2, ".copilot", "hooks", "node9.json")
21376
+ );
21377
+ const copilotMcp = readJson2(
21378
+ path42.join(homeDir2, ".copilot", "mcp-config.json")
21379
+ );
21380
+ const copilotPresent = fs41.existsSync(path42.join(homeDir2, ".copilot"));
21381
+ const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
21382
+ const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
20926
21383
  if (agentFound) {
20927
21384
  console.log("");
20928
21385
  console.log(chalk15.bold(" Agent Wiring:"));
20929
21386
  console.log("");
20930
21387
  if (claudeSettings || claudeConfig) {
20931
- const preHook = claudeSettings?.hooks?.PreToolUse?.some(
20932
- (m) => m.hooks.some((h) => isNode9Hook2(h.command))
20933
- ) ?? false;
20934
- const postHook = claudeSettings?.hooks?.PostToolUse?.some(
20935
- (m) => m.hooks.some((h) => isNode9Hook2(h.command))
20936
- ) ?? false;
21388
+ const preHook = matchersHaveNode9Hook(claudeSettings?.hooks?.PreToolUse);
21389
+ const postHook = matchersHaveNode9Hook(claudeSettings?.hooks?.PostToolUse);
20937
21390
  printAgentSection(
20938
21391
  "Claude Code",
20939
21392
  [
@@ -20945,12 +21398,8 @@ function registerStatusCommand(program2) {
20945
21398
  console.log("");
20946
21399
  }
20947
21400
  if (geminiSettings) {
20948
- const beforeHook = geminiSettings.hooks?.BeforeTool?.some(
20949
- (m) => m.hooks.some((h) => isNode9Hook2(h.command))
20950
- ) ?? false;
20951
- const afterHook = geminiSettings.hooks?.AfterTool?.some(
20952
- (m) => m.hooks.some((h) => isNode9Hook2(h.command))
20953
- ) ?? false;
21401
+ const beforeHook = matchersHaveNode9Hook(geminiSettings.hooks?.BeforeTool);
21402
+ const afterHook = matchersHaveNode9Hook(geminiSettings.hooks?.AfterTool);
20954
21403
  printAgentSection(
20955
21404
  "Gemini CLI",
20956
21405
  [
@@ -20961,10 +21410,50 @@ function registerStatusCommand(program2) {
20961
21410
  );
20962
21411
  console.log("");
20963
21412
  }
21413
+ if (antigravityPresent) {
21414
+ const preHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PreToolUse);
21415
+ const postHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PostToolUse);
21416
+ printAgentSection(
21417
+ "Antigravity",
21418
+ [
21419
+ { name: "PreToolUse (node9 check)", present: preHook },
21420
+ { name: "PostToolUse (node9 log)", present: postHook }
21421
+ ],
21422
+ wrappedMcpServers(antigravityMcp?.mcpServers)
21423
+ );
21424
+ console.log("");
21425
+ }
21426
+ if (copilotPresent) {
21427
+ const preHook = flatHaveNode9Hook(copilotHooks?.hooks?.PreToolUse);
21428
+ const postHook = flatHaveNode9Hook(copilotHooks?.hooks?.PostToolUse);
21429
+ const promptHook = flatHaveNode9Hook(copilotHooks?.hooks?.UserPromptSubmit);
21430
+ printAgentSection(
21431
+ "GitHub Copilot",
21432
+ [
21433
+ { name: "PreToolUse (node9 check)", present: preHook },
21434
+ { name: "PostToolUse (node9 log)", present: postHook },
21435
+ { name: "UserPromptSubmit (node9 check)", present: promptHook }
21436
+ ],
21437
+ wrappedMcpServers(copilotMcp?.mcpServers)
21438
+ );
21439
+ console.log("");
21440
+ }
20964
21441
  if (cursorConfig) {
20965
21442
  printAgentSection("Cursor", [], wrappedMcpServers(cursorConfig.mcpServers));
20966
21443
  console.log("");
20967
21444
  }
21445
+ if (hermesHooks) {
21446
+ printAgentSection(
21447
+ "Hermes Agent",
21448
+ [
21449
+ { name: "pre_tool_call (node9 check)", present: hermesHooks.pre },
21450
+ { name: "post_tool_call (node9 log)", present: hermesHooks.post }
21451
+ ],
21452
+ null
21453
+ // Hermes has no MCP surface
21454
+ );
21455
+ console.log("");
21456
+ }
20968
21457
  }
20969
21458
  const pauseState = checkPause();
20970
21459
  if (pauseState.paused) {
@@ -20984,9 +21473,9 @@ init_setup();
20984
21473
  init_shields();
20985
21474
  init_service();
20986
21475
  import chalk16 from "chalk";
20987
- import fs40 from "fs";
20988
- import path41 from "path";
20989
- import os36 from "os";
21476
+ import fs42 from "fs";
21477
+ import path43 from "path";
21478
+ import os38 from "os";
20990
21479
  import https4 from "https";
20991
21480
  var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
20992
21481
  function buildTelemetryPayload(agents, firstInstall) {
@@ -21072,16 +21561,16 @@ function registerInitCommand(program2) {
21072
21561
  }
21073
21562
  console.log("");
21074
21563
  }
21075
- const configPath = path41.join(os36.homedir(), ".node9", "config.json");
21076
- const isFirstInstall = !fs40.existsSync(configPath);
21077
- if (fs40.existsSync(configPath) && !options.force) {
21564
+ const configPath = path43.join(os38.homedir(), ".node9", "config.json");
21565
+ const isFirstInstall = !fs42.existsSync(configPath);
21566
+ if (fs42.existsSync(configPath) && !options.force) {
21078
21567
  try {
21079
- const existing = JSON.parse(fs40.readFileSync(configPath, "utf-8"));
21568
+ const existing = JSON.parse(fs42.readFileSync(configPath, "utf-8"));
21080
21569
  const settings = existing.settings ?? {};
21081
21570
  if (settings.mode !== chosenMode) {
21082
21571
  settings.mode = chosenMode;
21083
21572
  existing.settings = settings;
21084
- fs40.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
21573
+ fs42.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
21085
21574
  console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
21086
21575
  } else {
21087
21576
  console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -21094,9 +21583,9 @@ function registerInitCommand(program2) {
21094
21583
  ...DEFAULT_CONFIG,
21095
21584
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
21096
21585
  };
21097
- const dir = path41.dirname(configPath);
21098
- if (!fs40.existsSync(dir)) fs40.mkdirSync(dir, { recursive: true });
21099
- fs40.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
21586
+ const dir = path43.dirname(configPath);
21587
+ if (!fs42.existsSync(dir)) fs42.mkdirSync(dir, { recursive: true });
21588
+ fs42.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
21100
21589
  console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
21101
21590
  console.log(chalk16.gray(` Mode: ${chosenMode}`));
21102
21591
  }
@@ -21201,7 +21690,7 @@ function registerInitCommand(program2) {
21201
21690
  }
21202
21691
 
21203
21692
  // src/cli/commands/undo.ts
21204
- import path42 from "path";
21693
+ import path44 from "path";
21205
21694
  import chalk18 from "chalk";
21206
21695
 
21207
21696
  // src/tui/undo-navigator.ts
@@ -21360,7 +21849,7 @@ function findMatchingCwd(startDir, history) {
21360
21849
  let dir = startDir;
21361
21850
  while (true) {
21362
21851
  if (cwds.has(dir)) return dir;
21363
- const parent = path42.dirname(dir);
21852
+ const parent = path44.dirname(dir);
21364
21853
  if (parent === dir) return null;
21365
21854
  dir = parent;
21366
21855
  }
@@ -21936,9 +22425,9 @@ function registerMcpGatewayCommand(program2) {
21936
22425
 
21937
22426
  // src/mcp-server/index.ts
21938
22427
  import readline5 from "readline";
21939
- import fs41 from "fs";
21940
- import os37 from "os";
21941
- import path43 from "path";
22428
+ import fs43 from "fs";
22429
+ import os39 from "os";
22430
+ import path45 from "path";
21942
22431
  import { spawnSync as spawnSync4 } from "child_process";
21943
22432
  init_core();
21944
22433
  init_daemon();
@@ -22189,13 +22678,13 @@ function handleStatus() {
22189
22678
  lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
22190
22679
  lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
22191
22680
  lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
22192
- const projectConfig = path43.join(process.cwd(), "node9.config.json");
22193
- const globalConfig = path43.join(os37.homedir(), ".node9", "config.json");
22681
+ const projectConfig = path45.join(process.cwd(), "node9.config.json");
22682
+ const globalConfig = path45.join(os39.homedir(), ".node9", "config.json");
22194
22683
  lines.push(
22195
- `Project config (node9.config.json): ${fs41.existsSync(projectConfig) ? "present" : "not found"}`
22684
+ `Project config (node9.config.json): ${fs43.existsSync(projectConfig) ? "present" : "not found"}`
22196
22685
  );
22197
22686
  lines.push(
22198
- `Global config (~/.node9/config.json): ${fs41.existsSync(globalConfig) ? "present" : "not found"}`
22687
+ `Global config (~/.node9/config.json): ${fs43.existsSync(globalConfig) ? "present" : "not found"}`
22199
22688
  );
22200
22689
  return lines.join("\n");
22201
22690
  }
@@ -22269,21 +22758,21 @@ function handleShieldDisable(args) {
22269
22758
  writeActiveShields(active.filter((s) => s !== name));
22270
22759
  return `Shield "${name}" disabled.`;
22271
22760
  }
22272
- var GLOBAL_CONFIG_PATH = path43.join(os37.homedir(), ".node9", "config.json");
22761
+ var GLOBAL_CONFIG_PATH = path45.join(os39.homedir(), ".node9", "config.json");
22273
22762
  var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
22274
22763
  function readGlobalConfigRaw() {
22275
22764
  try {
22276
- if (fs41.existsSync(GLOBAL_CONFIG_PATH)) {
22277
- return JSON.parse(fs41.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
22765
+ if (fs43.existsSync(GLOBAL_CONFIG_PATH)) {
22766
+ return JSON.parse(fs43.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
22278
22767
  }
22279
22768
  } catch {
22280
22769
  }
22281
22770
  return {};
22282
22771
  }
22283
22772
  function writeGlobalConfigRaw(data) {
22284
- const dir = path43.dirname(GLOBAL_CONFIG_PATH);
22285
- if (!fs41.existsSync(dir)) fs41.mkdirSync(dir, { recursive: true });
22286
- fs41.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
22773
+ const dir = path45.dirname(GLOBAL_CONFIG_PATH);
22774
+ if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
22775
+ fs43.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
22287
22776
  }
22288
22777
  function handleApproverList() {
22289
22778
  const config = getConfig();
@@ -22327,9 +22816,9 @@ function handleApproverSet(args) {
22327
22816
  function handleAuditGet(args) {
22328
22817
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
22329
22818
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
22330
- const auditPath = path43.join(os37.homedir(), ".node9", "audit.log");
22331
- if (!fs41.existsSync(auditPath)) return "No audit log found.";
22332
- const rawLines = fs41.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
22819
+ const auditPath = path45.join(os39.homedir(), ".node9", "audit.log");
22820
+ if (!fs43.existsSync(auditPath)) return "No audit log found.";
22821
+ const rawLines = fs43.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
22333
22822
  const parsed = [];
22334
22823
  for (const line of rawLines) {
22335
22824
  try {
@@ -22664,7 +23153,7 @@ function registerTrustCommand(program2) {
22664
23153
  // src/cli/commands/mcp-pin.ts
22665
23154
  init_mcp_pin();
22666
23155
  import chalk21 from "chalk";
22667
- import fs42 from "fs";
23156
+ import fs44 from "fs";
22668
23157
  function registerMcpPinCommand(program2) {
22669
23158
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
22670
23159
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
@@ -22675,7 +23164,7 @@ function registerMcpPinCommand(program2) {
22675
23164
  let repoCorrupt = false;
22676
23165
  if (found.source === "repo") {
22677
23166
  try {
22678
- const raw = fs42.readFileSync(found.path, "utf-8");
23167
+ const raw = fs44.readFileSync(found.path, "utf-8");
22679
23168
  const parsed = JSON.parse(raw);
22680
23169
  repoEntries = parsed.servers ?? {};
22681
23170
  } catch {
@@ -22989,9 +23478,9 @@ init_scan();
22989
23478
  // src/cli/commands/sessions.ts
22990
23479
  init_scan_summary();
22991
23480
  import chalk24 from "chalk";
22992
- import fs43 from "fs";
22993
- import path44 from "path";
22994
- import os38 from "os";
23481
+ import fs45 from "fs";
23482
+ import path46 from "path";
23483
+ import os40 from "os";
22995
23484
  var CLAUDE_PRICING3 = {
22996
23485
  "claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
22997
23486
  "claude-opus-4-5": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
@@ -23032,10 +23521,10 @@ function encodeProjectPath(projectPath) {
23032
23521
  }
23033
23522
  function sessionJsonlPath(projectPath, sessionId) {
23034
23523
  const encoded = encodeProjectPath(projectPath);
23035
- return path44.join(os38.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
23524
+ return path46.join(os40.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
23036
23525
  }
23037
23526
  function projectLabel(projectPath) {
23038
- return projectPath.replace(os38.homedir(), "~");
23527
+ return projectPath.replace(os40.homedir(), "~");
23039
23528
  }
23040
23529
  function parseHistoryLines(lines) {
23041
23530
  const entries = [];
@@ -23104,10 +23593,10 @@ function parseSessionLines(lines) {
23104
23593
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
23105
23594
  }
23106
23595
  function loadAuditEntries(auditPath) {
23107
- const aPath = auditPath ?? path44.join(os38.homedir(), ".node9", "audit.log");
23596
+ const aPath = auditPath ?? path46.join(os40.homedir(), ".node9", "audit.log");
23108
23597
  let raw;
23109
23598
  try {
23110
- raw = fs43.readFileSync(aPath, "utf-8");
23599
+ raw = fs45.readFileSync(aPath, "utf-8");
23111
23600
  } catch {
23112
23601
  return [];
23113
23602
  }
@@ -23143,8 +23632,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
23143
23632
  return result;
23144
23633
  }
23145
23634
  function buildGeminiSessions(days, allAuditEntries) {
23146
- const tmpDir = path44.join(os38.homedir(), ".gemini", "tmp");
23147
- if (!fs43.existsSync(tmpDir)) return [];
23635
+ const tmpDir = path46.join(os40.homedir(), ".gemini", "tmp");
23636
+ if (!fs45.existsSync(tmpDir)) return [];
23148
23637
  const cutoff = days !== null ? (() => {
23149
23638
  const d = /* @__PURE__ */ new Date();
23150
23639
  d.setDate(d.getDate() - days);
@@ -23153,35 +23642,35 @@ function buildGeminiSessions(days, allAuditEntries) {
23153
23642
  })() : null;
23154
23643
  let slugDirs;
23155
23644
  try {
23156
- slugDirs = fs43.readdirSync(tmpDir);
23645
+ slugDirs = fs45.readdirSync(tmpDir);
23157
23646
  } catch {
23158
23647
  return [];
23159
23648
  }
23160
23649
  const summaries = [];
23161
23650
  for (const slug of slugDirs) {
23162
- const slugPath = path44.join(tmpDir, slug);
23651
+ const slugPath = path46.join(tmpDir, slug);
23163
23652
  try {
23164
- if (!fs43.statSync(slugPath).isDirectory()) continue;
23653
+ if (!fs45.statSync(slugPath).isDirectory()) continue;
23165
23654
  } catch {
23166
23655
  continue;
23167
23656
  }
23168
- let projectRoot = path44.join(os38.homedir(), slug);
23657
+ let projectRoot = path46.join(os40.homedir(), slug);
23169
23658
  try {
23170
- projectRoot = fs43.readFileSync(path44.join(slugPath, ".project_root"), "utf-8").trim();
23659
+ projectRoot = fs45.readFileSync(path46.join(slugPath, ".project_root"), "utf-8").trim();
23171
23660
  } catch {
23172
23661
  }
23173
- const chatsDir = path44.join(slugPath, "chats");
23174
- if (!fs43.existsSync(chatsDir)) continue;
23662
+ const chatsDir = path46.join(slugPath, "chats");
23663
+ if (!fs45.existsSync(chatsDir)) continue;
23175
23664
  let chatFiles;
23176
23665
  try {
23177
- chatFiles = fs43.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
23666
+ chatFiles = fs45.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
23178
23667
  } catch {
23179
23668
  continue;
23180
23669
  }
23181
23670
  for (const chatFile of chatFiles) {
23182
23671
  let raw;
23183
23672
  try {
23184
- raw = fs43.readFileSync(path44.join(chatsDir, chatFile), "utf-8");
23673
+ raw = fs45.readFileSync(path46.join(chatsDir, chatFile), "utf-8");
23185
23674
  } catch {
23186
23675
  continue;
23187
23676
  }
@@ -23261,8 +23750,8 @@ function buildGeminiSessions(days, allAuditEntries) {
23261
23750
  return summaries;
23262
23751
  }
23263
23752
  function buildCodexSessions(days, allAuditEntries) {
23264
- const sessionsBase = path44.join(os38.homedir(), ".codex", "sessions");
23265
- if (!fs43.existsSync(sessionsBase)) return [];
23753
+ const sessionsBase = path46.join(os40.homedir(), ".codex", "sessions");
23754
+ if (!fs45.existsSync(sessionsBase)) return [];
23266
23755
  const cutoff = days !== null ? (() => {
23267
23756
  const d = /* @__PURE__ */ new Date();
23268
23757
  d.setDate(d.getDate() - days);
@@ -23271,29 +23760,29 @@ function buildCodexSessions(days, allAuditEntries) {
23271
23760
  })() : null;
23272
23761
  const jsonlFiles = [];
23273
23762
  try {
23274
- for (const year of fs43.readdirSync(sessionsBase)) {
23275
- const yearPath = path44.join(sessionsBase, year);
23763
+ for (const year of fs45.readdirSync(sessionsBase)) {
23764
+ const yearPath = path46.join(sessionsBase, year);
23276
23765
  try {
23277
- if (!fs43.statSync(yearPath).isDirectory()) continue;
23766
+ if (!fs45.statSync(yearPath).isDirectory()) continue;
23278
23767
  } catch {
23279
23768
  continue;
23280
23769
  }
23281
- for (const month of fs43.readdirSync(yearPath)) {
23282
- const monthPath = path44.join(yearPath, month);
23770
+ for (const month of fs45.readdirSync(yearPath)) {
23771
+ const monthPath = path46.join(yearPath, month);
23283
23772
  try {
23284
- if (!fs43.statSync(monthPath).isDirectory()) continue;
23773
+ if (!fs45.statSync(monthPath).isDirectory()) continue;
23285
23774
  } catch {
23286
23775
  continue;
23287
23776
  }
23288
- for (const day of fs43.readdirSync(monthPath)) {
23289
- const dayPath = path44.join(monthPath, day);
23777
+ for (const day of fs45.readdirSync(monthPath)) {
23778
+ const dayPath = path46.join(monthPath, day);
23290
23779
  try {
23291
- if (!fs43.statSync(dayPath).isDirectory()) continue;
23780
+ if (!fs45.statSync(dayPath).isDirectory()) continue;
23292
23781
  } catch {
23293
23782
  continue;
23294
23783
  }
23295
- for (const file of fs43.readdirSync(dayPath)) {
23296
- if (file.endsWith(".jsonl")) jsonlFiles.push(path44.join(dayPath, file));
23784
+ for (const file of fs45.readdirSync(dayPath)) {
23785
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path46.join(dayPath, file));
23297
23786
  }
23298
23787
  }
23299
23788
  }
@@ -23305,7 +23794,7 @@ function buildCodexSessions(days, allAuditEntries) {
23305
23794
  for (const filePath of jsonlFiles) {
23306
23795
  let lines;
23307
23796
  try {
23308
- lines = fs43.readFileSync(filePath, "utf-8").split("\n");
23797
+ lines = fs45.readFileSync(filePath, "utf-8").split("\n");
23309
23798
  } catch {
23310
23799
  continue;
23311
23800
  }
@@ -23383,10 +23872,10 @@ function buildCodexSessions(days, allAuditEntries) {
23383
23872
  return summaries;
23384
23873
  }
23385
23874
  function buildSessions(days, historyPath) {
23386
- const hPath = historyPath ?? path44.join(os38.homedir(), ".claude", "history.jsonl");
23875
+ const hPath = historyPath ?? path46.join(os40.homedir(), ".claude", "history.jsonl");
23387
23876
  let historyRaw;
23388
23877
  try {
23389
- historyRaw = fs43.readFileSync(hPath, "utf-8");
23878
+ historyRaw = fs45.readFileSync(hPath, "utf-8");
23390
23879
  } catch {
23391
23880
  return [];
23392
23881
  }
@@ -23411,7 +23900,7 @@ function buildSessions(days, historyPath) {
23411
23900
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
23412
23901
  let sessionLines = [];
23413
23902
  try {
23414
- sessionLines = fs43.readFileSync(jsonlFile, "utf-8").split("\n");
23903
+ sessionLines = fs45.readFileSync(jsonlFile, "utf-8").split("\n");
23415
23904
  } catch {
23416
23905
  }
23417
23906
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -23679,8 +24168,8 @@ function registerSessionsCommand(program2) {
23679
24168
  console.log("");
23680
24169
  console.log(chalk24.cyan.bold("\u{1F4CB} node9 sessions") + chalk24.dim(" \u2014 what your AI agent did"));
23681
24170
  console.log("");
23682
- const historyPath = path44.join(os38.homedir(), ".claude", "history.jsonl");
23683
- if (!fs43.existsSync(historyPath)) {
24171
+ const historyPath = path46.join(os40.homedir(), ".claude", "history.jsonl");
24172
+ if (!fs45.existsSync(historyPath)) {
23684
24173
  console.log(chalk24.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
23685
24174
  console.log(chalk24.gray(" Install Claude Code, run a few sessions, then try again.\n"));
23686
24175
  return;
@@ -23717,12 +24206,12 @@ function registerSessionsCommand(program2) {
23717
24206
 
23718
24207
  // src/cli/commands/skill-pin.ts
23719
24208
  import chalk25 from "chalk";
23720
- import fs44 from "fs";
23721
- import os39 from "os";
23722
- import path45 from "path";
24209
+ import fs46 from "fs";
24210
+ import os41 from "os";
24211
+ import path47 from "path";
23723
24212
  function wipeSkillSessions() {
23724
24213
  try {
23725
- fs44.rmSync(path45.join(os39.homedir(), ".node9", "skill-sessions"), {
24214
+ fs46.rmSync(path47.join(os41.homedir(), ".node9", "skill-sessions"), {
23726
24215
  recursive: true,
23727
24216
  force: true
23728
24217
  });
@@ -23804,15 +24293,15 @@ function registerSkillPinCommand(program2) {
23804
24293
  }
23805
24294
 
23806
24295
  // src/cli/commands/decisions.ts
23807
- import fs45 from "fs";
23808
- import os40 from "os";
23809
- import path46 from "path";
24296
+ import fs47 from "fs";
24297
+ import os42 from "os";
24298
+ import path48 from "path";
23810
24299
  import chalk26 from "chalk";
23811
- var DECISIONS_FILE2 = path46.join(os40.homedir(), ".node9", "decisions.json");
24300
+ var DECISIONS_FILE2 = path48.join(os42.homedir(), ".node9", "decisions.json");
23812
24301
  function readDecisions() {
23813
24302
  try {
23814
- if (!fs45.existsSync(DECISIONS_FILE2)) return {};
23815
- const raw = fs45.readFileSync(DECISIONS_FILE2, "utf-8");
24303
+ if (!fs47.existsSync(DECISIONS_FILE2)) return {};
24304
+ const raw = fs47.readFileSync(DECISIONS_FILE2, "utf-8");
23816
24305
  const parsed = JSON.parse(raw);
23817
24306
  const out = {};
23818
24307
  for (const [k, v] of Object.entries(parsed)) {
@@ -23824,11 +24313,11 @@ function readDecisions() {
23824
24313
  }
23825
24314
  }
23826
24315
  function writeDecisions(d) {
23827
- const dir = path46.dirname(DECISIONS_FILE2);
23828
- if (!fs45.existsSync(dir)) fs45.mkdirSync(dir, { recursive: true });
24316
+ const dir = path48.dirname(DECISIONS_FILE2);
24317
+ if (!fs47.existsSync(dir)) fs47.mkdirSync(dir, { recursive: true });
23829
24318
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
23830
- fs45.writeFileSync(tmp, JSON.stringify(d, null, 2));
23831
- fs45.renameSync(tmp, DECISIONS_FILE2);
24319
+ fs47.writeFileSync(tmp, JSON.stringify(d, null, 2));
24320
+ fs47.renameSync(tmp, DECISIONS_FILE2);
23832
24321
  }
23833
24322
  function registerDecisionsCommand(program2) {
23834
24323
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -23885,18 +24374,18 @@ Persistent decisions (${entries.length})
23885
24374
 
23886
24375
  // src/cli/commands/dlp.ts
23887
24376
  import chalk27 from "chalk";
23888
- import fs46 from "fs";
23889
- import path47 from "path";
23890
- import os41 from "os";
23891
- var AUDIT_LOG = path47.join(os41.homedir(), ".node9", "audit.log");
23892
- var RESOLVED_FILE = path47.join(os41.homedir(), ".node9", "dlp-resolved.json");
24377
+ import fs48 from "fs";
24378
+ import path49 from "path";
24379
+ import os43 from "os";
24380
+ var AUDIT_LOG = path49.join(os43.homedir(), ".node9", "audit.log");
24381
+ var RESOLVED_FILE = path49.join(os43.homedir(), ".node9", "dlp-resolved.json");
23893
24382
  var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
23894
24383
  function stripAnsi(s) {
23895
24384
  return s.replace(ANSI_RE, "");
23896
24385
  }
23897
24386
  function loadResolved() {
23898
24387
  try {
23899
- const raw = JSON.parse(fs46.readFileSync(RESOLVED_FILE, "utf-8"));
24388
+ const raw = JSON.parse(fs48.readFileSync(RESOLVED_FILE, "utf-8"));
23900
24389
  return new Set(raw);
23901
24390
  } catch {
23902
24391
  return /* @__PURE__ */ new Set();
@@ -23904,13 +24393,13 @@ function loadResolved() {
23904
24393
  }
23905
24394
  function saveResolved(resolved) {
23906
24395
  try {
23907
- fs46.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
24396
+ fs48.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
23908
24397
  } catch {
23909
24398
  }
23910
24399
  }
23911
24400
  function loadDlpFindings() {
23912
- if (!fs46.existsSync(AUDIT_LOG)) return [];
23913
- return fs46.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
24401
+ if (!fs48.existsSync(AUDIT_LOG)) return [];
24402
+ return fs48.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
23914
24403
  if (!line.trim()) return [];
23915
24404
  try {
23916
24405
  const e = JSON.parse(line);
@@ -24009,14 +24498,14 @@ function registerDlpCommand(program2) {
24009
24498
  // src/cli/commands/mask.ts
24010
24499
  init_dlp();
24011
24500
  import chalk28 from "chalk";
24012
- import fs47 from "fs";
24013
- import path48 from "path";
24014
- import os42 from "os";
24501
+ import fs49 from "fs";
24502
+ import path50 from "path";
24503
+ import os44 from "os";
24015
24504
  function findJsonlFiles(dir) {
24016
24505
  const results = [];
24017
- if (!fs47.existsSync(dir)) return results;
24018
- for (const entry of fs47.readdirSync(dir, { withFileTypes: true })) {
24019
- const full = path48.join(dir, entry.name);
24506
+ if (!fs49.existsSync(dir)) return results;
24507
+ for (const entry of fs49.readdirSync(dir, { withFileTypes: true })) {
24508
+ const full = path50.join(dir, entry.name);
24020
24509
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
24021
24510
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
24022
24511
  }
@@ -24059,7 +24548,7 @@ function redactJson(obj) {
24059
24548
  function processFile(filePath, dryRun) {
24060
24549
  let raw;
24061
24550
  try {
24062
- raw = fs47.readFileSync(filePath, "utf-8");
24551
+ raw = fs49.readFileSync(filePath, "utf-8");
24063
24552
  } catch {
24064
24553
  return { redactedLines: 0, patterns: [] };
24065
24554
  }
@@ -24091,14 +24580,14 @@ function processFile(filePath, dryRun) {
24091
24580
  }
24092
24581
  }
24093
24582
  if (!dryRun && redactedLines > 0) {
24094
- fs47.writeFileSync(filePath, newLines.join("\n"), "utf-8");
24583
+ fs49.writeFileSync(filePath, newLines.join("\n"), "utf-8");
24095
24584
  }
24096
24585
  return { redactedLines, patterns };
24097
24586
  }
24098
24587
  function processJsonFile(filePath, dryRun) {
24099
24588
  let raw;
24100
24589
  try {
24101
- raw = fs47.readFileSync(filePath, "utf-8");
24590
+ raw = fs49.readFileSync(filePath, "utf-8");
24102
24591
  } catch {
24103
24592
  return { redactedLines: 0, patterns: [] };
24104
24593
  }
@@ -24111,15 +24600,15 @@ function processJsonFile(filePath, dryRun) {
24111
24600
  const { value, modified, found } = redactJson(parsed);
24112
24601
  if (!modified) return { redactedLines: 0, patterns: [] };
24113
24602
  if (!dryRun) {
24114
- fs47.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
24603
+ fs49.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
24115
24604
  }
24116
24605
  return { redactedLines: 1, patterns: found };
24117
24606
  }
24118
24607
  function findJsonFiles(dir) {
24119
24608
  const results = [];
24120
- if (!fs47.existsSync(dir)) return results;
24121
- for (const entry of fs47.readdirSync(dir, { withFileTypes: true })) {
24122
- const full = path48.join(dir, entry.name);
24609
+ if (!fs49.existsSync(dir)) return results;
24610
+ for (const entry of fs49.readdirSync(dir, { withFileTypes: true })) {
24611
+ const full = path50.join(dir, entry.name);
24123
24612
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
24124
24613
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
24125
24614
  }
@@ -24128,9 +24617,9 @@ function findJsonFiles(dir) {
24128
24617
  function registerMaskCommand(program2) {
24129
24618
  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) => {
24130
24619
  const dryRun = !!options.dryRun;
24131
- const home = os42.homedir();
24132
- const claudeDir = path48.join(home, ".claude", "projects");
24133
- const geminiDir = path48.join(home, ".gemini", "tmp");
24620
+ const home = os44.homedir();
24621
+ const claudeDir = path50.join(home, ".claude", "projects");
24622
+ const geminiDir = path50.join(home, ".gemini", "tmp");
24134
24623
  const allFiles = [
24135
24624
  ...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
24136
24625
  ...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
@@ -24138,7 +24627,7 @@ function registerMaskCommand(program2) {
24138
24627
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
24139
24628
  const filtered = cutoff ? allFiles.filter((f) => {
24140
24629
  try {
24141
- return fs47.statSync(f.path).mtime >= cutoff;
24630
+ return fs49.statSync(f.path).mtime >= cutoff;
24142
24631
  } catch {
24143
24632
  return false;
24144
24633
  }
@@ -24194,20 +24683,20 @@ function registerMaskCommand(program2) {
24194
24683
  // src/cli.ts
24195
24684
  init_blast();
24196
24685
  var { version } = JSON.parse(
24197
- fs50.readFileSync(path51.join(__dirname, "../package.json"), "utf-8")
24686
+ fs52.readFileSync(path53.join(__dirname, "../package.json"), "utf-8")
24198
24687
  );
24199
24688
  var program = new Command();
24200
24689
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
24201
24690
  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) => {
24202
24691
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
24203
- const credPath = path51.join(os45.homedir(), ".node9", "credentials.json");
24204
- if (!fs50.existsSync(path51.dirname(credPath)))
24205
- fs50.mkdirSync(path51.dirname(credPath), { recursive: true });
24692
+ const credPath = path53.join(os47.homedir(), ".node9", "credentials.json");
24693
+ if (!fs52.existsSync(path53.dirname(credPath)))
24694
+ fs52.mkdirSync(path53.dirname(credPath), { recursive: true });
24206
24695
  const profileName = options.profile || "default";
24207
24696
  let existingCreds = {};
24208
24697
  try {
24209
- if (fs50.existsSync(credPath)) {
24210
- const raw = JSON.parse(fs50.readFileSync(credPath, "utf-8"));
24698
+ if (fs52.existsSync(credPath)) {
24699
+ const raw = JSON.parse(fs52.readFileSync(credPath, "utf-8"));
24211
24700
  if (raw.apiKey) {
24212
24701
  existingCreds = {
24213
24702
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -24219,14 +24708,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
24219
24708
  } catch {
24220
24709
  }
24221
24710
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
24222
- fs50.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
24711
+ fs52.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
24223
24712
  let effectiveCloud = null;
24224
24713
  if (profileName === "default") {
24225
- const configPath = path51.join(os45.homedir(), ".node9", "config.json");
24714
+ const configPath = path53.join(os47.homedir(), ".node9", "config.json");
24226
24715
  let config = {};
24227
24716
  try {
24228
- if (fs50.existsSync(configPath))
24229
- config = JSON.parse(fs50.readFileSync(configPath, "utf-8"));
24717
+ if (fs52.existsSync(configPath))
24718
+ config = JSON.parse(fs52.readFileSync(configPath, "utf-8"));
24230
24719
  } catch {
24231
24720
  }
24232
24721
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -24241,9 +24730,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
24241
24730
  approvers.cloud = false;
24242
24731
  }
24243
24732
  s.approvers = approvers;
24244
- if (!fs50.existsSync(path51.dirname(configPath)))
24245
- fs50.mkdirSync(path51.dirname(configPath), { recursive: true });
24246
- fs50.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
24733
+ if (!fs52.existsSync(path53.dirname(configPath)))
24734
+ fs52.mkdirSync(path53.dirname(configPath), { recursive: true });
24735
+ fs52.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
24247
24736
  effectiveCloud = approvers.cloud === true;
24248
24737
  }
24249
24738
  if (options.profile && profileName !== "default") {
@@ -24402,15 +24891,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
24402
24891
  }
24403
24892
  }
24404
24893
  if (options.purge) {
24405
- const node9Dir = path51.join(os45.homedir(), ".node9");
24406
- if (fs50.existsSync(node9Dir)) {
24894
+ const node9Dir = path53.join(os47.homedir(), ".node9");
24895
+ if (fs52.existsSync(node9Dir)) {
24407
24896
  const confirmed = await confirm2({
24408
24897
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
24409
24898
  default: false
24410
24899
  });
24411
24900
  if (confirmed) {
24412
- fs50.rmSync(node9Dir, { recursive: true });
24413
- if (fs50.existsSync(node9Dir)) {
24901
+ fs52.rmSync(node9Dir, { recursive: true });
24902
+ if (fs52.existsSync(node9Dir)) {
24414
24903
  console.error(
24415
24904
  chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
24416
24905
  );
@@ -24525,7 +25014,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
24525
25014
  });
24526
25015
  program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
24527
25016
  try {
24528
- const dashboardPath = path51.join(__dirname, "dashboard.mjs");
25017
+ const dashboardPath = path53.join(__dirname, "dashboard.mjs");
24529
25018
  const dynamicImport = new Function("id", "return import(id)");
24530
25019
  const mod = await dynamicImport(`file://${dashboardPath}`);
24531
25020
  await mod.startMonitor();
@@ -24563,14 +25052,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
24563
25052
  Run "node9 addto claude" to register it as the statusLine.`
24564
25053
  ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
24565
25054
  if (subcommand === "debug") {
24566
- const flagFile = path51.join(os45.homedir(), ".node9", "hud-debug");
25055
+ const flagFile = path53.join(os47.homedir(), ".node9", "hud-debug");
24567
25056
  if (state === "on") {
24568
- fs50.mkdirSync(path51.dirname(flagFile), { recursive: true });
24569
- fs50.writeFileSync(flagFile, "");
25057
+ fs52.mkdirSync(path53.dirname(flagFile), { recursive: true });
25058
+ fs52.writeFileSync(flagFile, "");
24570
25059
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
24571
25060
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
24572
25061
  } else if (state === "off") {
24573
- if (fs50.existsSync(flagFile)) fs50.unlinkSync(flagFile);
25062
+ if (fs52.existsSync(flagFile)) fs52.unlinkSync(flagFile);
24574
25063
  console.log("HUD debug logging disabled.");
24575
25064
  } else {
24576
25065
  console.error("Usage: node9 hud debug on|off");
@@ -24687,9 +25176,9 @@ if (process.argv[2] !== "daemon") {
24687
25176
  const isCheckHook = process.argv[2] === "check";
24688
25177
  if (isCheckHook) {
24689
25178
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
24690
- const logPath = path51.join(os45.homedir(), ".node9", "hook-debug.log");
25179
+ const logPath = path53.join(os47.homedir(), ".node9", "hook-debug.log");
24691
25180
  const msg = reason instanceof Error ? reason.message : String(reason);
24692
- fs50.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
25181
+ fs52.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
24693
25182
  `);
24694
25183
  }
24695
25184
  process.exit(0);