@node9/proxy 1.11.13 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -168,8 +168,8 @@ function sanitizeConfig(raw) {
168
168
  }
169
169
  }
170
170
  const lines = result.error.issues.map((issue) => {
171
- const path44 = issue.path.length > 0 ? issue.path.join(".") : "root";
172
- return ` \u2022 ${path44}: ${issue.message}`;
171
+ const path45 = issue.path.length > 0 ? issue.path.join(".") : "root";
172
+ return ` \u2022 ${path45}: ${issue.message}`;
173
173
  });
174
174
  return {
175
175
  sanitized,
@@ -2083,9 +2083,9 @@ function matchesPattern(text, patterns) {
2083
2083
  const withoutDotSlash = text.replace(/^\.\//, "");
2084
2084
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
2085
2085
  }
2086
- function getNestedValue(obj, path44) {
2086
+ function getNestedValue(obj, path45) {
2087
2087
  if (!obj || typeof obj !== "object") return null;
2088
- return path44.split(".").reduce((prev, curr) => prev?.[curr], obj);
2088
+ return path45.split(".").reduce((prev, curr) => prev?.[curr], obj);
2089
2089
  }
2090
2090
  function normalizeCommandForPolicy(command) {
2091
2091
  try {
@@ -2344,7 +2344,12 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
2344
2344
  pathTokens = analyzed.paths;
2345
2345
  const INLINE_EXEC_PATTERN = /^(python3?|bash|sh|zsh|perl|ruby|node|php|lua)\s+(-c|-e|-eval)\s/i;
2346
2346
  if (INLINE_EXEC_PATTERN.test(shellCommand.trim())) {
2347
- return { decision: "review", blockedByLabel: "Node9 Standard (Inline Execution)", tier: 3 };
2347
+ return {
2348
+ decision: "review",
2349
+ blockedByLabel: "Node9 Standard (Inline Execution)",
2350
+ ruleDescription: "The AI is running code directly from the command line. Review the full script below before allowing it to execute.",
2351
+ tier: 3
2352
+ };
2348
2353
  }
2349
2354
  const evalVerdict = detectDangerousShellExec(shellCommand);
2350
2355
  if (evalVerdict === "block") {
@@ -2352,6 +2357,7 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
2352
2357
  decision: "block",
2353
2358
  blockedByLabel: "Node9: Eval Remote Execution",
2354
2359
  reason: "eval of remote download (curl/wget) is a near-certain supply-chain attack",
2360
+ ruleDescription: "The AI is downloading a script from the internet and running it immediately without inspection. This is a common way malware gets installed.",
2355
2361
  tier: 3
2356
2362
  };
2357
2363
  }
@@ -2360,6 +2366,7 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
2360
2366
  decision: "review",
2361
2367
  blockedByLabel: "Node9: Eval Dynamic Content",
2362
2368
  reason: "eval of dynamic content (variable or subshell expansion) requires approval",
2369
+ ruleDescription: "The AI is running a command that includes a variable or subshell expansion. The actual command executed at runtime may differ from what is shown here.",
2363
2370
  tier: 3
2364
2371
  };
2365
2372
  }
@@ -2489,6 +2496,7 @@ async function evaluatePolicy(toolName, args, agent, cwd) {
2489
2496
  blockedByLabel: `Project/Global Config \u2014 dangerous word: "${matchedDangerousWord}"`,
2490
2497
  matchedWord: matchedDangerousWord,
2491
2498
  matchedField,
2499
+ ruleDescription: `This command contains a flagged keyword ("${matchedDangerousWord}") from your node9 config. Review it before allowing.`,
2492
2500
  tier: 6
2493
2501
  };
2494
2502
  }
@@ -2641,7 +2649,8 @@ async function explainPolicy(toolName, args) {
2641
2649
  waterfall,
2642
2650
  steps,
2643
2651
  decision: "review",
2644
- blockedByLabel: "Node9 Standard (Inline Execution)"
2652
+ blockedByLabel: "Node9 Standard (Inline Execution)",
2653
+ ruleDescription: "The AI is running code directly from the command line. Review the full script below before allowing it to execute."
2645
2654
  };
2646
2655
  }
2647
2656
  steps.push({
@@ -2747,7 +2756,8 @@ async function explainPolicy(toolName, args) {
2747
2756
  steps,
2748
2757
  decision: "review",
2749
2758
  blockedByLabel: `Project/Global Config \u2014 dangerous word: "${matchedDangerousWord}"`,
2750
- matchedToken: matchedDangerousWord
2759
+ matchedToken: matchedDangerousWord,
2760
+ ruleDescription: `This command contains a flagged keyword ("${matchedDangerousWord}") from your node9 config. Review it before allowing.`
2751
2761
  };
2752
2762
  }
2753
2763
  steps.push({
@@ -5266,6 +5276,10 @@ var init_ui = __esm({
5266
5276
  border-color: rgba(83, 155, 245, 0.35);
5267
5277
  background: rgba(83, 155, 245, 0.04);
5268
5278
  }
5279
+ .pending-card.discovery-card {
5280
+ border-color: rgba(120, 100, 255, 0.45);
5281
+ background: rgba(100, 80, 255, 0.06);
5282
+ }
5269
5283
  .pending-card-header {
5270
5284
  display: flex;
5271
5285
  align-items: center;
@@ -7452,7 +7466,7 @@ var init_ui = __esm({
7452
7466
  });
7453
7467
 
7454
7468
  try {
7455
- await fetch('/mcp/approve', {
7469
+ const res = await fetch('/mcp/approve', {
7456
7470
  method: 'POST',
7457
7471
  headers: {
7458
7472
  'Content-Type': 'application/json',
@@ -7460,9 +7474,19 @@ var init_ui = __esm({
7460
7474
  },
7461
7475
  body: JSON.stringify({ id, serverKey, disabledTools }),
7462
7476
  });
7477
+ if (!res.ok) {
7478
+ showToast(
7479
+ '\u26A0\uFE0F',
7480
+ 'Approval failed',
7481
+ \`Server responded with \${res.status}\`,
7482
+ 'toast-block'
7483
+ );
7484
+ return;
7485
+ }
7463
7486
  closeMcpReview();
7464
7487
  refreshMcpTools();
7465
7488
  } catch (err) {
7489
+ showToast('\u26A0\uFE0F', 'Approval failed', 'Network error \u2014 check the daemon', 'toast-block');
7466
7490
  console.error('Failed to approve MCP server:', err);
7467
7491
  }
7468
7492
  }
@@ -8276,6 +8300,9 @@ var init_ui2 = __esm({
8276
8300
  });
8277
8301
 
8278
8302
  // src/cli/daemon-starter.ts
8303
+ function isTestingMode() {
8304
+ return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
8305
+ }
8279
8306
  function openBrowserLocal() {
8280
8307
  const url = `http://${DAEMON_HOST}:${DAEMON_PORT}/`;
8281
8308
  try {
@@ -8286,26 +8313,41 @@ function openBrowserLocal() {
8286
8313
  } catch {
8287
8314
  }
8288
8315
  }
8289
- async function autoStartDaemonAndWait() {
8290
- if (process.env.NODE9_TESTING === "1") return false;
8316
+ async function autoStartDaemonAndWait(openBrowser2 = true) {
8317
+ if (isTestingMode()) return false;
8318
+ if (!import_path16.default.isAbsolute(process.argv[1])) return false;
8319
+ let resolvedArgv1;
8291
8320
  try {
8292
- const child = (0, import_child_process3.spawn)(process.execPath, [process.argv[1], "daemon"], {
8321
+ resolvedArgv1 = import_fs13.default.realpathSync(process.argv[1]);
8322
+ } catch {
8323
+ return false;
8324
+ }
8325
+ if (!resolvedArgv1.endsWith(".js")) return false;
8326
+ try {
8327
+ const child = (0, import_child_process3.spawn)(process.execPath, [resolvedArgv1, "daemon"], {
8293
8328
  detached: true,
8294
8329
  stdio: "ignore",
8295
8330
  // NODE9_BROWSER_OPENED=1 tells the daemon we will open the browser ourselves
8296
8331
  // (openBrowserLocal below), so it must not open a duplicate tab on first approval.
8297
- env: { ...process.env, NODE9_AUTO_STARTED: "1", NODE9_BROWSER_OPENED: "1" }
8332
+ // Only set NODE9_BROWSER_OPENED when we actually intend to open it here.
8333
+ env: {
8334
+ ...process.env,
8335
+ NODE9_AUTO_STARTED: "1",
8336
+ ...openBrowser2 && { NODE9_BROWSER_OPENED: "1" }
8337
+ }
8298
8338
  });
8299
8339
  child.unref();
8300
8340
  for (let i = 0; i < 20; i++) {
8301
8341
  await new Promise((r) => setTimeout(r, 250));
8302
8342
  if (!isDaemonRunning()) continue;
8303
8343
  try {
8304
- const res = await fetch("http://127.0.0.1:7391/settings", {
8344
+ const res = await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/settings`, {
8305
8345
  signal: AbortSignal.timeout(500)
8306
8346
  });
8307
8347
  if (res.ok) {
8308
- openBrowserLocal();
8348
+ if (openBrowser2) {
8349
+ openBrowserLocal();
8350
+ }
8309
8351
  return true;
8310
8352
  }
8311
8353
  } catch {
@@ -8315,11 +8357,13 @@ async function autoStartDaemonAndWait() {
8315
8357
  }
8316
8358
  return false;
8317
8359
  }
8318
- var import_child_process3;
8360
+ var import_child_process3, import_path16, import_fs13;
8319
8361
  var init_daemon_starter = __esm({
8320
8362
  "src/cli/daemon-starter.ts"() {
8321
8363
  "use strict";
8322
8364
  import_child_process3 = require("child_process");
8365
+ import_path16 = __toESM(require("path"));
8366
+ import_fs13 = __toESM(require("fs"));
8323
8367
  init_daemon();
8324
8368
  }
8325
8369
  });
@@ -8612,14 +8656,14 @@ function buildRuleSources() {
8612
8656
  }
8613
8657
  function countScanFiles() {
8614
8658
  let total = 0;
8615
- const claudeDir = import_path16.default.join(import_os12.default.homedir(), ".claude", "projects");
8616
- if (import_fs13.default.existsSync(claudeDir)) {
8659
+ const claudeDir = import_path17.default.join(import_os12.default.homedir(), ".claude", "projects");
8660
+ if (import_fs14.default.existsSync(claudeDir)) {
8617
8661
  try {
8618
- for (const proj of import_fs13.default.readdirSync(claudeDir)) {
8619
- const p = import_path16.default.join(claudeDir, proj);
8662
+ for (const proj of import_fs14.default.readdirSync(claudeDir)) {
8663
+ const p = import_path17.default.join(claudeDir, proj);
8620
8664
  try {
8621
- if (!import_fs13.default.statSync(p).isDirectory()) continue;
8622
- total += import_fs13.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
8665
+ if (!import_fs14.default.statSync(p).isDirectory()) continue;
8666
+ total += import_fs14.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
8623
8667
  } catch {
8624
8668
  continue;
8625
8669
  }
@@ -8627,17 +8671,17 @@ function countScanFiles() {
8627
8671
  } catch {
8628
8672
  }
8629
8673
  }
8630
- const geminiDir = import_path16.default.join(import_os12.default.homedir(), ".gemini", "tmp");
8631
- if (import_fs13.default.existsSync(geminiDir)) {
8674
+ const geminiDir = import_path17.default.join(import_os12.default.homedir(), ".gemini", "tmp");
8675
+ if (import_fs14.default.existsSync(geminiDir)) {
8632
8676
  try {
8633
- for (const slug of import_fs13.default.readdirSync(geminiDir)) {
8634
- const p = import_path16.default.join(geminiDir, slug);
8677
+ for (const slug of import_fs14.default.readdirSync(geminiDir)) {
8678
+ const p = import_path17.default.join(geminiDir, slug);
8635
8679
  try {
8636
- if (!import_fs13.default.statSync(p).isDirectory()) continue;
8637
- const chatsDir = import_path16.default.join(p, "chats");
8638
- if (import_fs13.default.existsSync(chatsDir)) {
8680
+ if (!import_fs14.default.statSync(p).isDirectory()) continue;
8681
+ const chatsDir = import_path17.default.join(p, "chats");
8682
+ if (import_fs14.default.existsSync(chatsDir)) {
8639
8683
  try {
8640
- total += import_fs13.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
8684
+ total += import_fs14.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
8641
8685
  } catch {
8642
8686
  }
8643
8687
  }
@@ -8648,22 +8692,22 @@ function countScanFiles() {
8648
8692
  } catch {
8649
8693
  }
8650
8694
  }
8651
- const codexDir = import_path16.default.join(import_os12.default.homedir(), ".codex", "sessions");
8652
- if (import_fs13.default.existsSync(codexDir)) {
8695
+ const codexDir = import_path17.default.join(import_os12.default.homedir(), ".codex", "sessions");
8696
+ if (import_fs14.default.existsSync(codexDir)) {
8653
8697
  try {
8654
- for (const year of import_fs13.default.readdirSync(codexDir)) {
8655
- const yp = import_path16.default.join(codexDir, year);
8698
+ for (const year of import_fs14.default.readdirSync(codexDir)) {
8699
+ const yp = import_path17.default.join(codexDir, year);
8656
8700
  try {
8657
- if (!import_fs13.default.statSync(yp).isDirectory()) continue;
8658
- for (const month of import_fs13.default.readdirSync(yp)) {
8659
- const mp = import_path16.default.join(yp, month);
8701
+ if (!import_fs14.default.statSync(yp).isDirectory()) continue;
8702
+ for (const month of import_fs14.default.readdirSync(yp)) {
8703
+ const mp = import_path17.default.join(yp, month);
8660
8704
  try {
8661
- if (!import_fs13.default.statSync(mp).isDirectory()) continue;
8662
- for (const day of import_fs13.default.readdirSync(mp)) {
8663
- const dp = import_path16.default.join(mp, day);
8705
+ if (!import_fs14.default.statSync(mp).isDirectory()) continue;
8706
+ for (const day of import_fs14.default.readdirSync(mp)) {
8707
+ const dp = import_path17.default.join(mp, day);
8664
8708
  try {
8665
- if (!import_fs13.default.statSync(dp).isDirectory()) continue;
8666
- total += import_fs13.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
8709
+ if (!import_fs14.default.statSync(dp).isDirectory()) continue;
8710
+ total += import_fs14.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
8667
8711
  } catch {
8668
8712
  continue;
8669
8713
  }
@@ -8681,18 +8725,19 @@ function countScanFiles() {
8681
8725
  }
8682
8726
  return total;
8683
8727
  }
8684
- function renderProgressBar(done, total) {
8728
+ function renderProgressBar(done, total, lines) {
8685
8729
  const width = 28;
8686
8730
  const pct = total > 0 ? done / total : 0;
8687
8731
  const filled = Math.min(width, Math.round(pct * width));
8688
8732
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
8689
- const label = total > 0 ? `${done}/${total} files` : `${done} files`;
8733
+ const fileLabel = total > 0 ? `${done}/${total} files` : `${done} files`;
8734
+ const lineLabel = lines > 0 ? import_chalk2.default.dim(` ${lines.toLocaleString()} lines`) : "";
8690
8735
  process.stdout.write(
8691
- `\r ${import_chalk2.default.cyan("Scanning")} [${import_chalk2.default.cyan(bar)}] ${import_chalk2.default.dim(label)} `
8736
+ `\r ${import_chalk2.default.cyan("Scanning")} [${import_chalk2.default.cyan(bar)}] ${import_chalk2.default.dim(fileLabel)}${lineLabel} `
8692
8737
  );
8693
8738
  }
8694
- function scanClaudeHistory(startDate, onProgress) {
8695
- const projectsDir = import_path16.default.join(import_os12.default.homedir(), ".claude", "projects");
8739
+ function scanClaudeHistory(startDate, onProgress, onLine) {
8740
+ const projectsDir = import_path17.default.join(import_os12.default.homedir(), ".claude", "projects");
8696
8741
  const result = {
8697
8742
  filesScanned: 0,
8698
8743
  sessions: 0,
@@ -8705,25 +8750,25 @@ function scanClaudeHistory(startDate, onProgress) {
8705
8750
  firstDate: null,
8706
8751
  lastDate: null
8707
8752
  };
8708
- if (!import_fs13.default.existsSync(projectsDir)) return result;
8753
+ if (!import_fs14.default.existsSync(projectsDir)) return result;
8709
8754
  let projDirs;
8710
8755
  try {
8711
- projDirs = import_fs13.default.readdirSync(projectsDir);
8756
+ projDirs = import_fs14.default.readdirSync(projectsDir);
8712
8757
  } catch {
8713
8758
  return result;
8714
8759
  }
8715
8760
  const ruleSources = buildRuleSources();
8716
8761
  for (const proj of projDirs) {
8717
- const projPath = import_path16.default.join(projectsDir, proj);
8762
+ const projPath = import_path17.default.join(projectsDir, proj);
8718
8763
  try {
8719
- if (!import_fs13.default.statSync(projPath).isDirectory()) continue;
8764
+ if (!import_fs14.default.statSync(projPath).isDirectory()) continue;
8720
8765
  } catch {
8721
8766
  continue;
8722
8767
  }
8723
8768
  const projLabel = decodeURIComponent(proj).replace(import_os12.default.homedir(), "~").slice(0, 40);
8724
8769
  let files;
8725
8770
  try {
8726
- files = import_fs13.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
8771
+ files = import_fs14.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
8727
8772
  } catch {
8728
8773
  continue;
8729
8774
  }
@@ -8734,13 +8779,14 @@ function scanClaudeHistory(startDate, onProgress) {
8734
8779
  const sessionId = file.replace(/\.jsonl$/, "");
8735
8780
  let raw;
8736
8781
  try {
8737
- raw = import_fs13.default.readFileSync(import_path16.default.join(projPath, file), "utf-8");
8782
+ raw = import_fs14.default.readFileSync(import_path17.default.join(projPath, file), "utf-8");
8738
8783
  } catch {
8739
8784
  continue;
8740
8785
  }
8741
8786
  const sessionCalls = [];
8742
8787
  for (const line of raw.split("\n")) {
8743
8788
  if (!line.trim()) continue;
8789
+ onLine?.();
8744
8790
  let entry;
8745
8791
  try {
8746
8792
  entry = JSON.parse(line);
@@ -8886,8 +8932,8 @@ function scanClaudeHistory(startDate, onProgress) {
8886
8932
  }
8887
8933
  return result;
8888
8934
  }
8889
- function scanGeminiHistory(startDate, onProgress) {
8890
- const tmpDir = import_path16.default.join(import_os12.default.homedir(), ".gemini", "tmp");
8935
+ function scanGeminiHistory(startDate, onProgress, onLine) {
8936
+ const tmpDir = import_path17.default.join(import_os12.default.homedir(), ".gemini", "tmp");
8891
8937
  const result = {
8892
8938
  filesScanned: 0,
8893
8939
  sessions: 0,
@@ -8900,31 +8946,31 @@ function scanGeminiHistory(startDate, onProgress) {
8900
8946
  firstDate: null,
8901
8947
  lastDate: null
8902
8948
  };
8903
- if (!import_fs13.default.existsSync(tmpDir)) return result;
8949
+ if (!import_fs14.default.existsSync(tmpDir)) return result;
8904
8950
  let slugDirs;
8905
8951
  try {
8906
- slugDirs = import_fs13.default.readdirSync(tmpDir);
8952
+ slugDirs = import_fs14.default.readdirSync(tmpDir);
8907
8953
  } catch {
8908
8954
  return result;
8909
8955
  }
8910
8956
  const ruleSources = buildRuleSources();
8911
8957
  for (const slug of slugDirs) {
8912
- const slugPath = import_path16.default.join(tmpDir, slug);
8958
+ const slugPath = import_path17.default.join(tmpDir, slug);
8913
8959
  try {
8914
- if (!import_fs13.default.statSync(slugPath).isDirectory()) continue;
8960
+ if (!import_fs14.default.statSync(slugPath).isDirectory()) continue;
8915
8961
  } catch {
8916
8962
  continue;
8917
8963
  }
8918
8964
  let projLabel = slug;
8919
8965
  try {
8920
- projLabel = import_fs13.default.readFileSync(import_path16.default.join(slugPath, ".project_root"), "utf-8").trim().replace(import_os12.default.homedir(), "~").slice(0, 40);
8966
+ projLabel = import_fs14.default.readFileSync(import_path17.default.join(slugPath, ".project_root"), "utf-8").trim().replace(import_os12.default.homedir(), "~").slice(0, 40);
8921
8967
  } catch {
8922
8968
  }
8923
- const chatsDir = import_path16.default.join(slugPath, "chats");
8924
- if (!import_fs13.default.existsSync(chatsDir)) continue;
8969
+ const chatsDir = import_path17.default.join(slugPath, "chats");
8970
+ if (!import_fs14.default.existsSync(chatsDir)) continue;
8925
8971
  let chatFiles;
8926
8972
  try {
8927
- chatFiles = import_fs13.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
8973
+ chatFiles = import_fs14.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
8928
8974
  } catch {
8929
8975
  continue;
8930
8976
  }
@@ -8934,7 +8980,7 @@ function scanGeminiHistory(startDate, onProgress) {
8934
8980
  const sessionId = chatFile.replace(/\.json$/, "");
8935
8981
  let raw;
8936
8982
  try {
8937
- raw = import_fs13.default.readFileSync(import_path16.default.join(chatsDir, chatFile), "utf-8");
8983
+ raw = import_fs14.default.readFileSync(import_path17.default.join(chatsDir, chatFile), "utf-8");
8938
8984
  } catch {
8939
8985
  continue;
8940
8986
  }
@@ -8947,6 +8993,7 @@ function scanGeminiHistory(startDate, onProgress) {
8947
8993
  }
8948
8994
  result.sessions++;
8949
8995
  for (const msg of session.messages ?? []) {
8996
+ onLine?.();
8950
8997
  if (msg.type === "user") {
8951
8998
  const content = msg.content;
8952
8999
  const text = Array.isArray(content) ? content.map((c) => c.text ?? "").join("\n") : typeof content === "string" ? content : "";
@@ -9082,8 +9129,8 @@ function scanGeminiHistory(startDate, onProgress) {
9082
9129
  }
9083
9130
  return result;
9084
9131
  }
9085
- function scanCodexHistory(startDate, onProgress) {
9086
- const sessionsBase = import_path16.default.join(import_os12.default.homedir(), ".codex", "sessions");
9132
+ function scanCodexHistory(startDate, onProgress, onLine) {
9133
+ const sessionsBase = import_path17.default.join(import_os12.default.homedir(), ".codex", "sessions");
9087
9134
  const result = {
9088
9135
  filesScanned: 0,
9089
9136
  sessions: 0,
@@ -9096,32 +9143,32 @@ function scanCodexHistory(startDate, onProgress) {
9096
9143
  firstDate: null,
9097
9144
  lastDate: null
9098
9145
  };
9099
- if (!import_fs13.default.existsSync(sessionsBase)) return result;
9146
+ if (!import_fs14.default.existsSync(sessionsBase)) return result;
9100
9147
  const jsonlFiles = [];
9101
9148
  try {
9102
- for (const year of import_fs13.default.readdirSync(sessionsBase)) {
9103
- const yearPath = import_path16.default.join(sessionsBase, year);
9149
+ for (const year of import_fs14.default.readdirSync(sessionsBase)) {
9150
+ const yearPath = import_path17.default.join(sessionsBase, year);
9104
9151
  try {
9105
- if (!import_fs13.default.statSync(yearPath).isDirectory()) continue;
9152
+ if (!import_fs14.default.statSync(yearPath).isDirectory()) continue;
9106
9153
  } catch {
9107
9154
  continue;
9108
9155
  }
9109
- for (const month of import_fs13.default.readdirSync(yearPath)) {
9110
- const monthPath = import_path16.default.join(yearPath, month);
9156
+ for (const month of import_fs14.default.readdirSync(yearPath)) {
9157
+ const monthPath = import_path17.default.join(yearPath, month);
9111
9158
  try {
9112
- if (!import_fs13.default.statSync(monthPath).isDirectory()) continue;
9159
+ if (!import_fs14.default.statSync(monthPath).isDirectory()) continue;
9113
9160
  } catch {
9114
9161
  continue;
9115
9162
  }
9116
- for (const day of import_fs13.default.readdirSync(monthPath)) {
9117
- const dayPath = import_path16.default.join(monthPath, day);
9163
+ for (const day of import_fs14.default.readdirSync(monthPath)) {
9164
+ const dayPath = import_path17.default.join(monthPath, day);
9118
9165
  try {
9119
- if (!import_fs13.default.statSync(dayPath).isDirectory()) continue;
9166
+ if (!import_fs14.default.statSync(dayPath).isDirectory()) continue;
9120
9167
  } catch {
9121
9168
  continue;
9122
9169
  }
9123
- for (const file of import_fs13.default.readdirSync(dayPath)) {
9124
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path16.default.join(dayPath, file));
9170
+ for (const file of import_fs14.default.readdirSync(dayPath)) {
9171
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path17.default.join(dayPath, file));
9125
9172
  }
9126
9173
  }
9127
9174
  }
@@ -9135,7 +9182,7 @@ function scanCodexHistory(startDate, onProgress) {
9135
9182
  onProgress?.(result.filesScanned);
9136
9183
  let lines;
9137
9184
  try {
9138
- lines = import_fs13.default.readFileSync(filePath, "utf-8").split("\n");
9185
+ lines = import_fs14.default.readFileSync(filePath, "utf-8").split("\n");
9139
9186
  } catch {
9140
9187
  continue;
9141
9188
  }
@@ -9149,6 +9196,7 @@ function scanCodexHistory(startDate, onProgress) {
9149
9196
  let lastTotalOutput = 0;
9150
9197
  for (const line of lines) {
9151
9198
  if (!line.trim()) continue;
9199
+ onLine?.();
9152
9200
  let entry;
9153
9201
  try {
9154
9202
  entry = JSON.parse(line);
@@ -9353,17 +9401,17 @@ function printRuleGroup(rule, topN, drillDown, previewWidth) {
9353
9401
  }
9354
9402
  }
9355
9403
  function registerScanCommand(program2) {
9356
- program2.command("scan").description("Forecast: scan agent history and show what node9 would catch if installed").option("--all", "Scan all history (default: last 90 days)").option("--days <n>", "Scan last N days of history", "90").option("--top <n>", "Max findings to show per rule (default: 5)", "5").option("--drill-down", "Show all findings with full commands and session IDs").action(async (options) => {
9404
+ program2.command("scan").description("Forecast: scan agent history and show what node9 would catch if installed").option("--all", "Scan all history (default: last 30 days)").option("--days <n>", "Scan last N days of history", "30").option("--top <n>", "Max findings to show per rule (default: 5)", "5").option("--drill-down", "Show all findings with full commands and session IDs").action(async (options) => {
9357
9405
  const drillDown = options.drillDown ?? false;
9358
9406
  const topN = drillDown ? Infinity : Math.max(1, parseInt(options.top, 10) || 5);
9359
9407
  const previewWidth = 70;
9360
9408
  const startDate = options.all ? null : (() => {
9361
9409
  const d = /* @__PURE__ */ new Date();
9362
- d.setDate(d.getDate() - (parseInt(options.days, 10) || 90));
9410
+ d.setDate(d.getDate() - (parseInt(options.days, 10) || 30));
9363
9411
  d.setHours(0, 0, 0, 0);
9364
9412
  return d;
9365
9413
  })();
9366
- const isInstalled = import_fs13.default.existsSync(import_path16.default.join(import_os12.default.homedir(), ".node9", "audit.log"));
9414
+ const isInstalled = import_fs14.default.existsSync(import_path17.default.join(import_os12.default.homedir(), ".node9", "audit.log"));
9367
9415
  console.log("");
9368
9416
  if (!isInstalled) {
9369
9417
  console.log(
@@ -9380,19 +9428,32 @@ function registerScanCommand(program2) {
9380
9428
  console.log("");
9381
9429
  const totalFiles = countScanFiles();
9382
9430
  let filesScanned = 0;
9431
+ let linesScanned = 0;
9432
+ let lastRender = 0;
9383
9433
  const onProgress = (done) => {
9384
9434
  filesScanned = done;
9385
- renderProgressBar(filesScanned, totalFiles);
9435
+ renderProgressBar(filesScanned, totalFiles, linesScanned);
9436
+ lastRender = Date.now();
9386
9437
  };
9387
- renderProgressBar(0, totalFiles);
9388
- const claudeScan = scanClaudeHistory(startDate, onProgress);
9438
+ const onLine = () => {
9439
+ linesScanned++;
9440
+ const now = Date.now();
9441
+ if (now - lastRender >= 80) {
9442
+ lastRender = now;
9443
+ renderProgressBar(filesScanned, totalFiles, linesScanned);
9444
+ }
9445
+ };
9446
+ renderProgressBar(0, totalFiles, 0);
9447
+ const claudeScan = scanClaudeHistory(startDate, onProgress, onLine);
9389
9448
  const geminiScan = scanGeminiHistory(
9390
9449
  startDate,
9391
- (done) => onProgress(claudeScan.filesScanned + done)
9450
+ (done) => onProgress(claudeScan.filesScanned + done),
9451
+ onLine
9392
9452
  );
9393
9453
  const codexScan = scanCodexHistory(
9394
9454
  startDate,
9395
- (done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done)
9455
+ (done) => onProgress(claudeScan.filesScanned + geminiScan.filesScanned + done),
9456
+ onLine
9396
9457
  );
9397
9458
  const scan = mergeScans(mergeScans(claudeScan, geminiScan), codexScan);
9398
9459
  const summary = buildScanSummary([
@@ -9410,7 +9471,7 @@ function registerScanCommand(program2) {
9410
9471
  );
9411
9472
  return;
9412
9473
  }
9413
- const rangeLabel = options.all ? import_chalk2.default.dim("all time") : import_chalk2.default.dim(`last ${options.days ?? 90} days`);
9474
+ const rangeLabel = options.all ? import_chalk2.default.dim("all time") : import_chalk2.default.dim(`last ${options.days ?? 30} days`);
9414
9475
  const dateRange = scan.firstDate && scan.lastDate ? import_chalk2.default.dim(` ${fmtTs(scan.firstDate)} \u2013 ${fmtTs(scan.lastDate)}`) : "";
9415
9476
  const breakdownParts = [];
9416
9477
  if (claudeScan.sessions > 0)
@@ -9588,39 +9649,43 @@ function registerScanCommand(program2) {
9588
9649
  console.log(" " + import_chalk2.default.dim("\u2192 ") + import_chalk2.default.underline("https://node9.ai"));
9589
9650
  }
9590
9651
  console.log("");
9591
- if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
9592
- const internalToken = getInternalToken();
9593
- if (internalToken) {
9594
- try {
9595
- const summary2 = buildScanSummary([
9596
- { id: "claude", label: "Claude", icon: "\u{1F916}", scan: claudeScan },
9597
- { id: "gemini", label: "Gemini", icon: "\u264A", scan: geminiScan },
9598
- { id: "codex", label: "Codex", icon: "\u{1F52E}", scan: codexScan }
9599
- ]);
9600
- const payload = { status: "complete", summary: summary2 };
9601
- await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/scan/push`, {
9602
- method: "POST",
9603
- headers: { "Content-Type": "application/json", "x-node9-internal": internalToken },
9604
- body: JSON.stringify(payload),
9605
- signal: AbortSignal.timeout(3e3)
9606
- });
9607
- const url = `http://${DAEMON_HOST}:${DAEMON_PORT}/`;
9608
- console.log(" " + import_chalk2.default.cyan("\u{1F310} View in browser:") + " " + import_chalk2.default.underline(url));
9609
- console.log("");
9610
- openBrowserLocal();
9611
- } catch {
9652
+ const url = `http://${DAEMON_HOST}:${DAEMON_PORT}/`;
9653
+ if (!isTestingMode()) {
9654
+ if (isDaemonRunning()) {
9655
+ const internalToken = getInternalToken();
9656
+ if (internalToken) {
9657
+ try {
9658
+ const summary2 = buildScanSummary([
9659
+ { id: "claude", label: "Claude", icon: "\u{1F916}", scan: claudeScan },
9660
+ { id: "gemini", label: "Gemini", icon: "\u264A", scan: geminiScan },
9661
+ { id: "codex", label: "Codex", icon: "\u{1F52E}", scan: codexScan }
9662
+ ]);
9663
+ await fetch(`http://${DAEMON_HOST}:${DAEMON_PORT}/scan/push`, {
9664
+ method: "POST",
9665
+ headers: { "Content-Type": "application/json", "x-node9-internal": internalToken },
9666
+ body: JSON.stringify({ status: "complete", summary: summary2 }),
9667
+ signal: AbortSignal.timeout(3e3)
9668
+ });
9669
+ openBrowserLocal();
9670
+ } catch {
9671
+ }
9612
9672
  }
9613
9673
  }
9674
+ console.log(" " + import_chalk2.default.cyan("\u{1F310} View in browser:") + " " + import_chalk2.default.underline(url));
9675
+ if (!isDaemonRunning()) {
9676
+ console.log(" " + import_chalk2.default.dim(" run node9 daemon --background to activate"));
9677
+ }
9678
+ console.log("");
9614
9679
  }
9615
9680
  });
9616
9681
  }
9617
- var import_chalk2, import_fs13, import_path16, import_os12, CLAUDE_PRICING, GEMINI_PRICING, LOOP_TOOLS, LOOP_THRESHOLD, DEFAULT_RULE_NAMES;
9682
+ var import_chalk2, import_fs14, import_path17, import_os12, CLAUDE_PRICING, GEMINI_PRICING, LOOP_TOOLS, LOOP_THRESHOLD, DEFAULT_RULE_NAMES;
9618
9683
  var init_scan = __esm({
9619
9684
  "src/cli/commands/scan.ts"() {
9620
9685
  "use strict";
9621
9686
  import_chalk2 = __toESM(require("chalk"));
9622
- import_fs13 = __toESM(require("fs"));
9623
- import_path16 = __toESM(require("path"));
9687
+ import_fs14 = __toESM(require("fs"));
9688
+ import_path17 = __toESM(require("path"));
9624
9689
  import_os12 = __toESM(require("os"));
9625
9690
  init_shields();
9626
9691
  init_config();
@@ -9757,12 +9822,12 @@ var init_suggestion_tracker = __esm({
9757
9822
  });
9758
9823
 
9759
9824
  // src/daemon/taint-store.ts
9760
- var import_fs14, import_path17, DEFAULT_TTL_MS, TaintStore;
9825
+ var import_fs15, import_path18, DEFAULT_TTL_MS, TaintStore;
9761
9826
  var init_taint_store = __esm({
9762
9827
  "src/daemon/taint-store.ts"() {
9763
9828
  "use strict";
9764
- import_fs14 = __toESM(require("fs"));
9765
- import_path17 = __toESM(require("path"));
9829
+ import_fs15 = __toESM(require("fs"));
9830
+ import_path18 = __toESM(require("path"));
9766
9831
  DEFAULT_TTL_MS = 60 * 60 * 1e3;
9767
9832
  TaintStore = class {
9768
9833
  records = /* @__PURE__ */ new Map();
@@ -9827,9 +9892,9 @@ var init_taint_store = __esm({
9827
9892
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
9828
9893
  _resolve(filePath) {
9829
9894
  try {
9830
- return import_fs14.default.realpathSync.native(import_path17.default.resolve(filePath));
9895
+ return import_fs15.default.realpathSync.native(import_path18.default.resolve(filePath));
9831
9896
  } catch {
9832
- return import_path17.default.resolve(filePath);
9897
+ return import_path18.default.resolve(filePath);
9833
9898
  }
9834
9899
  }
9835
9900
  };
@@ -9947,8 +10012,8 @@ var init_session_history = __esm({
9947
10012
  // src/daemon/state.ts
9948
10013
  function loadInsightCounts() {
9949
10014
  try {
9950
- if (!import_fs15.default.existsSync(INSIGHT_COUNTS_FILE)) return;
9951
- const data = JSON.parse(import_fs15.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
10015
+ if (!import_fs16.default.existsSync(INSIGHT_COUNTS_FILE)) return;
10016
+ const data = JSON.parse(import_fs16.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
9952
10017
  for (const [tool, count] of Object.entries(data)) {
9953
10018
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
9954
10019
  }
@@ -9991,23 +10056,23 @@ function setCachedScanResult(result) {
9991
10056
  cachedScanTs = Date.now();
9992
10057
  }
9993
10058
  function atomicWriteSync2(filePath, data, options) {
9994
- const dir = import_path18.default.dirname(filePath);
9995
- if (!import_fs15.default.existsSync(dir)) import_fs15.default.mkdirSync(dir, { recursive: true });
10059
+ const dir = import_path19.default.dirname(filePath);
10060
+ if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
9996
10061
  const tmpPath = `${filePath}.${(0, import_crypto6.randomUUID)()}.tmp`;
9997
10062
  try {
9998
- import_fs15.default.writeFileSync(tmpPath, data, options);
10063
+ import_fs16.default.writeFileSync(tmpPath, data, options);
9999
10064
  } catch (err2) {
10000
10065
  try {
10001
- import_fs15.default.unlinkSync(tmpPath);
10066
+ import_fs16.default.unlinkSync(tmpPath);
10002
10067
  } catch {
10003
10068
  }
10004
10069
  throw err2;
10005
10070
  }
10006
10071
  try {
10007
- import_fs15.default.renameSync(tmpPath, filePath);
10072
+ import_fs16.default.renameSync(tmpPath, filePath);
10008
10073
  } catch (err2) {
10009
10074
  try {
10010
- import_fs15.default.unlinkSync(tmpPath);
10075
+ import_fs16.default.unlinkSync(tmpPath);
10011
10076
  } catch {
10012
10077
  }
10013
10078
  throw err2;
@@ -10031,16 +10096,16 @@ function appendAuditLog(data) {
10031
10096
  decision: data.decision,
10032
10097
  source: "daemon"
10033
10098
  };
10034
- const dir = import_path18.default.dirname(AUDIT_LOG_FILE);
10035
- if (!import_fs15.default.existsSync(dir)) import_fs15.default.mkdirSync(dir, { recursive: true });
10036
- import_fs15.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
10099
+ const dir = import_path19.default.dirname(AUDIT_LOG_FILE);
10100
+ if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
10101
+ import_fs16.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
10037
10102
  } catch {
10038
10103
  }
10039
10104
  }
10040
10105
  function getAuditHistory(limit = 20) {
10041
10106
  try {
10042
- if (!import_fs15.default.existsSync(AUDIT_LOG_FILE)) return [];
10043
- const lines = import_fs15.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
10107
+ if (!import_fs16.default.existsSync(AUDIT_LOG_FILE)) return [];
10108
+ const lines = import_fs16.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
10044
10109
  if (lines.length === 1 && lines[0] === "") return [];
10045
10110
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
10046
10111
  } catch {
@@ -10049,19 +10114,19 @@ function getAuditHistory(limit = 20) {
10049
10114
  }
10050
10115
  function getOrgName() {
10051
10116
  try {
10052
- if (import_fs15.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
10117
+ if (import_fs16.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
10053
10118
  } catch {
10054
10119
  }
10055
10120
  return null;
10056
10121
  }
10057
10122
  function hasStoredSlackKey() {
10058
- return import_fs15.default.existsSync(CREDENTIALS_FILE);
10123
+ return import_fs16.default.existsSync(CREDENTIALS_FILE);
10059
10124
  }
10060
10125
  function writeGlobalSetting(key, value) {
10061
10126
  let config = {};
10062
10127
  try {
10063
- if (import_fs15.default.existsSync(GLOBAL_CONFIG_FILE)) {
10064
- config = JSON.parse(import_fs15.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
10128
+ if (import_fs16.default.existsSync(GLOBAL_CONFIG_FILE)) {
10129
+ config = JSON.parse(import_fs16.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
10065
10130
  }
10066
10131
  } catch {
10067
10132
  }
@@ -10073,8 +10138,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
10073
10138
  try {
10074
10139
  let trust = { entries: [] };
10075
10140
  try {
10076
- if (import_fs15.default.existsSync(TRUST_FILE2))
10077
- trust = JSON.parse(import_fs15.default.readFileSync(TRUST_FILE2, "utf-8"));
10141
+ if (import_fs16.default.existsSync(TRUST_FILE2))
10142
+ trust = JSON.parse(import_fs16.default.readFileSync(TRUST_FILE2, "utf-8"));
10078
10143
  } catch {
10079
10144
  }
10080
10145
  trust.entries = trust.entries.filter(
@@ -10091,8 +10156,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
10091
10156
  }
10092
10157
  function readPersistentDecisions() {
10093
10158
  try {
10094
- if (import_fs15.default.existsSync(DECISIONS_FILE)) {
10095
- return JSON.parse(import_fs15.default.readFileSync(DECISIONS_FILE, "utf-8"));
10159
+ if (import_fs16.default.existsSync(DECISIONS_FILE)) {
10160
+ return JSON.parse(import_fs16.default.readFileSync(DECISIONS_FILE, "utf-8"));
10096
10161
  }
10097
10162
  } catch {
10098
10163
  }
@@ -10129,7 +10194,7 @@ function estimateToolCost(tool, args) {
10129
10194
  const filePath = a.file_path ?? a.path;
10130
10195
  if (filePath) {
10131
10196
  try {
10132
- const bytes = import_fs15.default.statSync(filePath).size;
10197
+ const bytes = import_fs16.default.statSync(filePath).size;
10133
10198
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
10134
10199
  } catch {
10135
10200
  }
@@ -10187,7 +10252,7 @@ function abandonPending() {
10187
10252
  });
10188
10253
  if (autoStarted) {
10189
10254
  try {
10190
- import_fs15.default.unlinkSync(DAEMON_PID_FILE);
10255
+ import_fs16.default.unlinkSync(DAEMON_PID_FILE);
10191
10256
  } catch {
10192
10257
  }
10193
10258
  setTimeout(() => {
@@ -10198,7 +10263,7 @@ function abandonPending() {
10198
10263
  }
10199
10264
  function startActivitySocket() {
10200
10265
  try {
10201
- import_fs15.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
10266
+ import_fs16.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
10202
10267
  } catch {
10203
10268
  }
10204
10269
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
@@ -10280,18 +10345,18 @@ function startActivitySocket() {
10280
10345
  unixServer.listen(ACTIVITY_SOCKET_PATH2);
10281
10346
  process.on("exit", () => {
10282
10347
  try {
10283
- import_fs15.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
10348
+ import_fs16.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
10284
10349
  } catch {
10285
10350
  }
10286
10351
  });
10287
10352
  }
10288
- var import_net2, import_fs15, import_path18, import_os13, import_child_process4, import_crypto6, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, suggestions, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, WRITE_TOOL_NAMES;
10353
+ var import_net2, import_fs16, import_path19, import_os13, import_child_process4, import_crypto6, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, suggestions, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, WRITE_TOOL_NAMES;
10289
10354
  var init_state2 = __esm({
10290
10355
  "src/daemon/state.ts"() {
10291
10356
  "use strict";
10292
10357
  import_net2 = __toESM(require("net"));
10293
- import_fs15 = __toESM(require("fs"));
10294
- import_path18 = __toESM(require("path"));
10358
+ import_fs16 = __toESM(require("fs"));
10359
+ import_path19 = __toESM(require("path"));
10295
10360
  import_os13 = __toESM(require("os"));
10296
10361
  import_child_process4 = require("child_process");
10297
10362
  import_crypto6 = require("crypto");
@@ -10301,13 +10366,13 @@ var init_state2 = __esm({
10301
10366
  init_session_counters();
10302
10367
  init_session_history();
10303
10368
  homeDir = import_os13.default.homedir();
10304
- DAEMON_PID_FILE = import_path18.default.join(homeDir, ".node9", "daemon.pid");
10305
- DECISIONS_FILE = import_path18.default.join(homeDir, ".node9", "decisions.json");
10306
- AUDIT_LOG_FILE = import_path18.default.join(homeDir, ".node9", "audit.log");
10307
- TRUST_FILE2 = import_path18.default.join(homeDir, ".node9", "trust.json");
10308
- GLOBAL_CONFIG_FILE = import_path18.default.join(homeDir, ".node9", "config.json");
10309
- CREDENTIALS_FILE = import_path18.default.join(homeDir, ".node9", "credentials.json");
10310
- INSIGHT_COUNTS_FILE = import_path18.default.join(homeDir, ".node9", "insight-counts.json");
10369
+ DAEMON_PID_FILE = import_path19.default.join(homeDir, ".node9", "daemon.pid");
10370
+ DECISIONS_FILE = import_path19.default.join(homeDir, ".node9", "decisions.json");
10371
+ AUDIT_LOG_FILE = import_path19.default.join(homeDir, ".node9", "audit.log");
10372
+ TRUST_FILE2 = import_path19.default.join(homeDir, ".node9", "trust.json");
10373
+ GLOBAL_CONFIG_FILE = import_path19.default.join(homeDir, ".node9", "config.json");
10374
+ CREDENTIALS_FILE = import_path19.default.join(homeDir, ".node9", "credentials.json");
10375
+ INSIGHT_COUNTS_FILE = import_path19.default.join(homeDir, ".node9", "insight-counts.json");
10311
10376
  pending = /* @__PURE__ */ new Map();
10312
10377
  sseClients = /* @__PURE__ */ new Set();
10313
10378
  suggestionTracker = new SuggestionTracker(3);
@@ -10325,7 +10390,7 @@ var init_state2 = __esm({
10325
10390
  "2h": 2 * 60 * 6e4
10326
10391
  };
10327
10392
  autoStarted = process.env.NODE9_AUTO_STARTED === "1";
10328
- ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path18.default.join(import_os13.default.tmpdir(), "node9-activity.sock");
10393
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path19.default.join(import_os13.default.tmpdir(), "node9-activity.sock");
10329
10394
  ACTIVITY_RING_SIZE = 100;
10330
10395
  activityRing = [];
10331
10396
  LARGE_RESPONSE_RING_SIZE = 20;
@@ -10355,8 +10420,8 @@ var init_state2 = __esm({
10355
10420
  function patchConfig(configPath, patch) {
10356
10421
  let config = {};
10357
10422
  try {
10358
- if (import_fs16.default.existsSync(configPath)) {
10359
- config = JSON.parse(import_fs16.default.readFileSync(configPath, "utf8"));
10423
+ if (import_fs17.default.existsSync(configPath)) {
10424
+ config = JSON.parse(import_fs17.default.readFileSync(configPath, "utf8"));
10360
10425
  }
10361
10426
  } catch {
10362
10427
  throw new Error(`Cannot read config at ${configPath} \u2014 file may be corrupted`);
@@ -10375,36 +10440,36 @@ function patchConfig(configPath, patch) {
10375
10440
  ignored.push(patch.toolName);
10376
10441
  }
10377
10442
  }
10378
- const dir = import_path19.default.dirname(configPath);
10379
- import_fs16.default.mkdirSync(dir, { recursive: true });
10443
+ const dir = import_path20.default.dirname(configPath);
10444
+ import_fs17.default.mkdirSync(dir, { recursive: true });
10380
10445
  const tmp = configPath + ".node9-tmp";
10381
10446
  try {
10382
- import_fs16.default.writeFileSync(tmp, JSON.stringify(config, null, 2), { mode: 384 });
10447
+ import_fs17.default.writeFileSync(tmp, JSON.stringify(config, null, 2), { mode: 384 });
10383
10448
  } catch (err2) {
10384
10449
  try {
10385
- import_fs16.default.unlinkSync(tmp);
10450
+ import_fs17.default.unlinkSync(tmp);
10386
10451
  } catch {
10387
10452
  }
10388
10453
  throw err2;
10389
10454
  }
10390
10455
  try {
10391
- import_fs16.default.renameSync(tmp, configPath);
10456
+ import_fs17.default.renameSync(tmp, configPath);
10392
10457
  } catch (err2) {
10393
10458
  try {
10394
- import_fs16.default.unlinkSync(tmp);
10459
+ import_fs17.default.unlinkSync(tmp);
10395
10460
  } catch {
10396
10461
  }
10397
10462
  throw err2;
10398
10463
  }
10399
10464
  }
10400
- var import_fs16, import_path19, import_os14, GLOBAL_CONFIG_PATH;
10465
+ var import_fs17, import_path20, import_os14, GLOBAL_CONFIG_PATH;
10401
10466
  var init_patch = __esm({
10402
10467
  "src/config/patch.ts"() {
10403
10468
  "use strict";
10404
- import_fs16 = __toESM(require("fs"));
10405
- import_path19 = __toESM(require("path"));
10469
+ import_fs17 = __toESM(require("fs"));
10470
+ import_path20 = __toESM(require("path"));
10406
10471
  import_os14 = __toESM(require("os"));
10407
- GLOBAL_CONFIG_PATH = import_path19.default.join(import_os14.default.homedir(), ".node9", "config.json");
10472
+ GLOBAL_CONFIG_PATH = import_path20.default.join(import_os14.default.homedir(), ".node9", "config.json");
10408
10473
  }
10409
10474
  });
10410
10475
 
@@ -10424,7 +10489,7 @@ function pricingFor(model) {
10424
10489
  function parseJSONLFile(filePath) {
10425
10490
  let content;
10426
10491
  try {
10427
- content = import_fs17.default.readFileSync(filePath, "utf8");
10492
+ content = import_fs18.default.readFileSync(filePath, "utf8");
10428
10493
  } catch {
10429
10494
  return /* @__PURE__ */ new Map();
10430
10495
  }
@@ -10476,30 +10541,30 @@ function parseJSONLFile(filePath) {
10476
10541
  return daily;
10477
10542
  }
10478
10543
  function collectEntries() {
10479
- const projectsDir = import_path20.default.join(import_os15.default.homedir(), ".claude", "projects");
10480
- if (!import_fs17.default.existsSync(projectsDir)) return [];
10544
+ const projectsDir = import_path21.default.join(import_os15.default.homedir(), ".claude", "projects");
10545
+ if (!import_fs18.default.existsSync(projectsDir)) return [];
10481
10546
  const combined = /* @__PURE__ */ new Map();
10482
10547
  let dirs;
10483
10548
  try {
10484
- dirs = import_fs17.default.readdirSync(projectsDir);
10549
+ dirs = import_fs18.default.readdirSync(projectsDir);
10485
10550
  } catch {
10486
10551
  return [];
10487
10552
  }
10488
10553
  for (const dir of dirs) {
10489
- const dirPath = import_path20.default.join(projectsDir, dir);
10554
+ const dirPath = import_path21.default.join(projectsDir, dir);
10490
10555
  try {
10491
- if (!import_fs17.default.statSync(dirPath).isDirectory()) continue;
10556
+ if (!import_fs18.default.statSync(dirPath).isDirectory()) continue;
10492
10557
  } catch {
10493
10558
  continue;
10494
10559
  }
10495
10560
  let files;
10496
10561
  try {
10497
- files = import_fs17.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10562
+ files = import_fs18.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
10498
10563
  } catch {
10499
10564
  continue;
10500
10565
  }
10501
10566
  for (const file of files) {
10502
- const entries = parseJSONLFile(import_path20.default.join(dirPath, file));
10567
+ const entries = parseJSONLFile(import_path21.default.join(dirPath, file));
10503
10568
  for (const [key, e] of entries) {
10504
10569
  const prev = combined.get(key);
10505
10570
  if (prev) {
@@ -10535,11 +10600,11 @@ async function syncCost() {
10535
10600
  signal: AbortSignal.timeout(15e3)
10536
10601
  });
10537
10602
  if (!res.ok) {
10538
- import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
10603
+ import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
10539
10604
  `);
10540
10605
  }
10541
10606
  } catch (err2) {
10542
- import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
10607
+ import_fs18.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
10543
10608
  `);
10544
10609
  }
10545
10610
  }
@@ -10552,12 +10617,12 @@ function startCostSync() {
10552
10617
  }, SYNC_INTERVAL_MS);
10553
10618
  timer.unref();
10554
10619
  }
10555
- var import_fs17, import_path20, import_os15, SYNC_INTERVAL_MS, PRICING;
10620
+ var import_fs18, import_path21, import_os15, SYNC_INTERVAL_MS, PRICING;
10556
10621
  var init_costSync = __esm({
10557
10622
  "src/costSync.ts"() {
10558
10623
  "use strict";
10559
- import_fs17 = __toESM(require("fs"));
10560
- import_path20 = __toESM(require("path"));
10624
+ import_fs18 = __toESM(require("fs"));
10625
+ import_path21 = __toESM(require("path"));
10561
10626
  import_os15 = __toESM(require("os"));
10562
10627
  init_config();
10563
10628
  init_audit();
@@ -10583,8 +10648,8 @@ function readCredentials() {
10583
10648
  };
10584
10649
  }
10585
10650
  try {
10586
- const credPath = import_path21.default.join(import_os16.default.homedir(), ".node9", "credentials.json");
10587
- const creds = JSON.parse(import_fs18.default.readFileSync(credPath, "utf-8"));
10651
+ const credPath = import_path22.default.join(import_os16.default.homedir(), ".node9", "credentials.json");
10652
+ const creds = JSON.parse(import_fs19.default.readFileSync(credPath, "utf-8"));
10588
10653
  const profileName = process.env.NODE9_PROFILE ?? "default";
10589
10654
  const profile = creds[profileName];
10590
10655
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -10646,9 +10711,9 @@ async function syncOnce() {
10646
10711
  try {
10647
10712
  const rules = await fetchCloudRules(creds.apiKey, creds.apiUrl);
10648
10713
  const cache = { fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), rules };
10649
- const dir = import_path21.default.dirname(rulesCacheFile());
10650
- if (!import_fs18.default.existsSync(dir)) import_fs18.default.mkdirSync(dir, { recursive: true });
10651
- import_fs18.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
10714
+ const dir = import_path22.default.dirname(rulesCacheFile());
10715
+ if (!import_fs19.default.existsSync(dir)) import_fs19.default.mkdirSync(dir, { recursive: true });
10716
+ import_fs19.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
10652
10717
  } catch {
10653
10718
  }
10654
10719
  }
@@ -10660,9 +10725,9 @@ async function runCloudSync() {
10660
10725
  try {
10661
10726
  const rules = await fetchCloudRules(creds.apiKey, creds.apiUrl);
10662
10727
  const cache = { fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), rules };
10663
- const dir = import_path21.default.dirname(rulesCacheFile());
10664
- if (!import_fs18.default.existsSync(dir)) import_fs18.default.mkdirSync(dir, { recursive: true });
10665
- import_fs18.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
10728
+ const dir = import_path22.default.dirname(rulesCacheFile());
10729
+ if (!import_fs19.default.existsSync(dir)) import_fs19.default.mkdirSync(dir, { recursive: true });
10730
+ import_fs19.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
10666
10731
  return { ok: true, rules: rules.length, fetchedAt: cache.fetchedAt };
10667
10732
  } catch (err2) {
10668
10733
  return { ok: false, reason: err2 instanceof Error ? err2.message : String(err2) };
@@ -10670,7 +10735,7 @@ async function runCloudSync() {
10670
10735
  }
10671
10736
  function getCloudSyncStatus() {
10672
10737
  try {
10673
- const raw = JSON.parse(import_fs18.default.readFileSync(rulesCacheFile(), "utf-8"));
10738
+ const raw = JSON.parse(import_fs19.default.readFileSync(rulesCacheFile(), "utf-8"));
10674
10739
  if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
10675
10740
  return { cached: true, rules: raw.rules.length, fetchedAt: raw.fetchedAt };
10676
10741
  } catch {
@@ -10679,7 +10744,7 @@ function getCloudSyncStatus() {
10679
10744
  }
10680
10745
  function getCloudRules() {
10681
10746
  try {
10682
- const raw = JSON.parse(import_fs18.default.readFileSync(rulesCacheFile(), "utf-8"));
10747
+ const raw = JSON.parse(import_fs19.default.readFileSync(rulesCacheFile(), "utf-8"));
10683
10748
  return Array.isArray(raw.rules) ? raw.rules : null;
10684
10749
  } catch {
10685
10750
  return null;
@@ -10694,16 +10759,16 @@ function startCloudSync() {
10694
10759
  const recurring = setInterval(() => void syncOnce(), intervalMs);
10695
10760
  recurring.unref();
10696
10761
  }
10697
- var import_fs18, import_https, import_os16, import_path21, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS;
10762
+ var import_fs19, import_https, import_os16, import_path22, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS;
10698
10763
  var init_sync = __esm({
10699
10764
  "src/daemon/sync.ts"() {
10700
10765
  "use strict";
10701
- import_fs18 = __toESM(require("fs"));
10766
+ import_fs19 = __toESM(require("fs"));
10702
10767
  import_https = __toESM(require("https"));
10703
10768
  import_os16 = __toESM(require("os"));
10704
- import_path21 = __toESM(require("path"));
10769
+ import_path22 = __toESM(require("path"));
10705
10770
  init_config();
10706
- rulesCacheFile = () => import_path21.default.join(import_os16.default.homedir(), ".node9", "rules-cache.json");
10771
+ rulesCacheFile = () => import_path22.default.join(import_os16.default.homedir(), ".node9", "rules-cache.json");
10707
10772
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/policy";
10708
10773
  DEFAULT_INTERVAL_HOURS = 5;
10709
10774
  MIN_INTERVAL_HOURS = 1;
@@ -10713,68 +10778,68 @@ var init_sync = __esm({
10713
10778
  // src/daemon/dlp-scanner.ts
10714
10779
  function loadIndex() {
10715
10780
  try {
10716
- return JSON.parse(import_fs19.default.readFileSync(INDEX_FILE, "utf-8"));
10781
+ return JSON.parse(import_fs20.default.readFileSync(INDEX_FILE, "utf-8"));
10717
10782
  } catch {
10718
10783
  return {};
10719
10784
  }
10720
10785
  }
10721
10786
  function saveIndex(index) {
10722
10787
  try {
10723
- import_fs19.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
10788
+ import_fs20.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
10724
10789
  } catch {
10725
10790
  }
10726
10791
  }
10727
10792
  function appendAuditEntry(entry) {
10728
10793
  try {
10729
- import_fs19.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
10794
+ import_fs20.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
10730
10795
  } catch {
10731
10796
  }
10732
10797
  }
10733
10798
  function runDlpScan() {
10734
- if (!import_fs19.default.existsSync(PROJECTS_DIR)) return;
10799
+ if (!import_fs20.default.existsSync(PROJECTS_DIR)) return;
10735
10800
  const index = loadIndex();
10736
10801
  let updated = false;
10737
10802
  let projDirs;
10738
10803
  try {
10739
- projDirs = import_fs19.default.readdirSync(PROJECTS_DIR);
10804
+ projDirs = import_fs20.default.readdirSync(PROJECTS_DIR);
10740
10805
  } catch {
10741
10806
  return;
10742
10807
  }
10743
10808
  for (const proj of projDirs) {
10744
- const projPath = import_path22.default.join(PROJECTS_DIR, proj);
10809
+ const projPath = import_path23.default.join(PROJECTS_DIR, proj);
10745
10810
  try {
10746
- if (!import_fs19.default.lstatSync(projPath).isDirectory()) continue;
10747
- const real = import_fs19.default.realpathSync(projPath);
10748
- if (!real.startsWith(PROJECTS_DIR + import_path22.default.sep) && real !== PROJECTS_DIR) continue;
10811
+ if (!import_fs20.default.lstatSync(projPath).isDirectory()) continue;
10812
+ const real = import_fs20.default.realpathSync(projPath);
10813
+ if (!real.startsWith(PROJECTS_DIR + import_path23.default.sep) && real !== PROJECTS_DIR) continue;
10749
10814
  } catch {
10750
10815
  continue;
10751
10816
  }
10752
10817
  let files;
10753
10818
  try {
10754
- files = import_fs19.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
10819
+ files = import_fs20.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
10755
10820
  } catch {
10756
10821
  continue;
10757
10822
  }
10758
10823
  for (const file of files) {
10759
- const filePath = import_path22.default.join(projPath, file);
10824
+ const filePath = import_path23.default.join(projPath, file);
10760
10825
  const lastOffset = index[filePath] ?? 0;
10761
10826
  let size;
10762
10827
  try {
10763
- size = import_fs19.default.statSync(filePath).size;
10828
+ size = import_fs20.default.statSync(filePath).size;
10764
10829
  } catch {
10765
10830
  continue;
10766
10831
  }
10767
10832
  if (size <= lastOffset) continue;
10768
10833
  let fd;
10769
10834
  try {
10770
- fd = import_fs19.default.openSync(filePath, "r");
10835
+ fd = import_fs20.default.openSync(filePath, "r");
10771
10836
  } catch {
10772
10837
  continue;
10773
10838
  }
10774
10839
  try {
10775
10840
  const chunkSize = size - lastOffset;
10776
10841
  const buf = Buffer.alloc(chunkSize);
10777
- import_fs19.default.readSync(fd, buf, 0, chunkSize, lastOffset);
10842
+ import_fs20.default.readSync(fd, buf, 0, chunkSize, lastOffset);
10778
10843
  const chunk = buf.toString("utf-8");
10779
10844
  for (const line of chunk.split("\n")) {
10780
10845
  if (!line.trim()) continue;
@@ -10819,7 +10884,7 @@ Run: node9 report --period 30d`
10819
10884
  updated = true;
10820
10885
  } finally {
10821
10886
  try {
10822
- import_fs19.default.closeSync(fd);
10887
+ import_fs20.default.closeSync(fd);
10823
10888
  } catch {
10824
10889
  }
10825
10890
  }
@@ -10845,30 +10910,30 @@ function startDlpScanner() {
10845
10910
  );
10846
10911
  timer.unref();
10847
10912
  }
10848
- var import_fs19, import_path22, import_os17, INDEX_FILE, PROJECTS_DIR;
10913
+ var import_fs20, import_path23, import_os17, INDEX_FILE, PROJECTS_DIR;
10849
10914
  var init_dlp_scanner = __esm({
10850
10915
  "src/daemon/dlp-scanner.ts"() {
10851
10916
  "use strict";
10852
- import_fs19 = __toESM(require("fs"));
10853
- import_path22 = __toESM(require("path"));
10917
+ import_fs20 = __toESM(require("fs"));
10918
+ import_path23 = __toESM(require("path"));
10854
10919
  import_os17 = __toESM(require("os"));
10855
10920
  init_dlp();
10856
10921
  init_native();
10857
10922
  init_state2();
10858
- INDEX_FILE = import_path22.default.join(import_os17.default.homedir(), ".node9", "dlp-index.json");
10859
- PROJECTS_DIR = import_path22.default.join(import_os17.default.homedir(), ".claude", "projects");
10923
+ INDEX_FILE = import_path23.default.join(import_os17.default.homedir(), ".node9", "dlp-index.json");
10924
+ PROJECTS_DIR = import_path23.default.join(import_os17.default.homedir(), ".claude", "projects");
10860
10925
  }
10861
10926
  });
10862
10927
 
10863
10928
  // src/daemon/mcp-tools.ts
10864
10929
  function getMcpToolsFile() {
10865
- return import_path23.default.join(import_os18.default.homedir(), ".node9", "mcp-tools.json");
10930
+ return import_path24.default.join(import_os18.default.homedir(), ".node9", "mcp-tools.json");
10866
10931
  }
10867
10932
  function readMcpToolsConfig() {
10868
10933
  try {
10869
10934
  const file = getMcpToolsFile();
10870
- if (!import_fs20.default.existsSync(file)) return {};
10871
- const raw = import_fs20.default.readFileSync(file, "utf-8");
10935
+ if (!import_fs21.default.existsSync(file)) return {};
10936
+ const raw = import_fs21.default.readFileSync(file, "utf-8");
10872
10937
  return JSON.parse(raw);
10873
10938
  } catch {
10874
10939
  return {};
@@ -10877,11 +10942,11 @@ function readMcpToolsConfig() {
10877
10942
  function writeMcpToolsConfig(config) {
10878
10943
  try {
10879
10944
  const file = getMcpToolsFile();
10880
- const dir = import_path23.default.dirname(file);
10881
- if (!import_fs20.default.existsSync(dir)) import_fs20.default.mkdirSync(dir, { recursive: true });
10945
+ const dir = import_path24.default.dirname(file);
10946
+ if (!import_fs21.default.existsSync(dir)) import_fs21.default.mkdirSync(dir, { recursive: true });
10882
10947
  const tmpPath = `${file}.${import_os18.default.hostname()}.${process.pid}.tmp`;
10883
- import_fs20.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
10884
- import_fs20.default.renameSync(tmpPath, file);
10948
+ import_fs21.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
10949
+ import_fs21.default.renameSync(tmpPath, file);
10885
10950
  } catch (e) {
10886
10951
  console.error("Failed to write mcp-tools.json", e);
10887
10952
  }
@@ -10920,12 +10985,12 @@ function approveServer(serverKey, disabledTools) {
10920
10985
  writeMcpToolsConfig(config);
10921
10986
  }
10922
10987
  }
10923
- var import_fs20, import_path23, import_os18;
10988
+ var import_fs21, import_path24, import_os18;
10924
10989
  var init_mcp_tools = __esm({
10925
10990
  "src/daemon/mcp-tools.ts"() {
10926
10991
  "use strict";
10927
- import_fs20 = __toESM(require("fs"));
10928
- import_path23 = __toESM(require("path"));
10992
+ import_fs21 = __toESM(require("fs"));
10993
+ import_path24 = __toESM(require("path"));
10929
10994
  import_os18 = __toESM(require("os"));
10930
10995
  }
10931
10996
  });
@@ -10950,7 +11015,7 @@ function startDaemon() {
10950
11015
  idleTimer = setTimeout(() => {
10951
11016
  if (autoStarted) {
10952
11017
  try {
10953
- import_fs21.default.unlinkSync(DAEMON_PID_FILE);
11018
+ import_fs22.default.unlinkSync(DAEMON_PID_FILE);
10954
11019
  } catch {
10955
11020
  }
10956
11021
  }
@@ -11121,7 +11186,7 @@ data: ${JSON.stringify(item.data)}
11121
11186
  status: "pending"
11122
11187
  });
11123
11188
  }
11124
- const projectCwd = typeof cwd === "string" && import_path24.default.isAbsolute(cwd) ? cwd : void 0;
11189
+ const projectCwd = typeof cwd === "string" && import_path25.default.isAbsolute(cwd) ? cwd : void 0;
11125
11190
  const projectConfig = getConfig(projectCwd);
11126
11191
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
11127
11192
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -11485,8 +11550,8 @@ data: ${JSON.stringify(item.data)}
11485
11550
  if (!validToken(req)) return res.writeHead(403).end();
11486
11551
  const periodParam = reqUrl.searchParams.get("period") || "7d";
11487
11552
  const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
11488
- const logPath = import_path24.default.join(import_os19.default.homedir(), ".node9", "audit.log");
11489
- if (!import_fs21.default.existsSync(logPath)) {
11553
+ const logPath = import_path25.default.join(import_os19.default.homedir(), ".node9", "audit.log");
11554
+ if (!import_fs22.default.existsSync(logPath)) {
11490
11555
  res.writeHead(200, { "Content-Type": "application/json" });
11491
11556
  return res.end(
11492
11557
  JSON.stringify({
@@ -11499,7 +11564,7 @@ data: ${JSON.stringify(item.data)}
11499
11564
  );
11500
11565
  }
11501
11566
  try {
11502
- const raw = import_fs21.default.readFileSync(logPath, "utf-8");
11567
+ const raw = import_fs22.default.readFileSync(logPath, "utf-8");
11503
11568
  const allEntries = raw.split("\n").flatMap((line) => {
11504
11569
  if (!line.trim()) return [];
11505
11570
  try {
@@ -11603,7 +11668,7 @@ data: ${JSON.stringify(item.data)}
11603
11668
  }
11604
11669
  try {
11605
11670
  const d = /* @__PURE__ */ new Date();
11606
- d.setDate(d.getDate() - 90);
11671
+ d.setDate(d.getDate() - 30);
11607
11672
  d.setHours(0, 0, 0, 0);
11608
11673
  const EMPTY_SCAN = {
11609
11674
  filesScanned: 0,
@@ -11679,8 +11744,8 @@ data: ${JSON.stringify(item.data)}
11679
11744
  const body = await readBody(req);
11680
11745
  const data = body ? JSON.parse(body) : {};
11681
11746
  const configPath = data.configPath ?? GLOBAL_CONFIG_PATH;
11682
- const node9Dir = import_path24.default.dirname(GLOBAL_CONFIG_PATH);
11683
- if (!import_path24.default.resolve(configPath).startsWith(node9Dir + import_path24.default.sep)) {
11747
+ const node9Dir = import_path25.default.dirname(GLOBAL_CONFIG_PATH);
11748
+ if (!import_path25.default.resolve(configPath).startsWith(node9Dir + import_path25.default.sep)) {
11684
11749
  res.writeHead(400, { "Content-Type": "application/json" });
11685
11750
  return res.end(
11686
11751
  JSON.stringify({ error: "configPath must be within the node9 config directory" })
@@ -11794,11 +11859,16 @@ data: ${JSON.stringify(item.data)}
11794
11859
  if (!validToken(req)) return res.writeHead(403).end();
11795
11860
  try {
11796
11861
  const { serverKey, disabledTools } = JSON.parse(await readBody(req));
11797
- if (typeof serverKey !== "string" || !Array.isArray(disabledTools)) {
11862
+ if (typeof serverKey !== "string" || serverKey.length < 1 || serverKey.length > 256 || !/^[\w.-]+$/.test(serverKey) || !Array.isArray(disabledTools)) {
11798
11863
  res.writeHead(400).end();
11799
11864
  return;
11800
11865
  }
11801
11866
  approveServer(serverKey, disabledTools);
11867
+ appendAuditLog({
11868
+ toolName: `mcp-server:${serverKey}`,
11869
+ args: { disabledTools },
11870
+ decision: "allow"
11871
+ });
11802
11872
  broadcast("mcp-tools-updated", { serverKey, disabledTools });
11803
11873
  res.writeHead(200).end();
11804
11874
  return;
@@ -11811,12 +11881,17 @@ data: ${JSON.stringify(item.data)}
11811
11881
  if (req.headers["x-node9-internal"] !== internalToken) return res.writeHead(403).end();
11812
11882
  try {
11813
11883
  const { serverKey, tools } = JSON.parse(await readBody(req));
11814
- if (typeof serverKey !== "string" || !Array.isArray(tools)) {
11884
+ if (typeof serverKey !== "string" || serverKey.length < 1 || serverKey.length > 256 || !/^[\w.-]+$/.test(serverKey) || !Array.isArray(tools)) {
11815
11885
  res.writeHead(400).end();
11816
11886
  return;
11817
11887
  }
11818
11888
  const status = updateServerDiscovery(serverKey, tools);
11819
11889
  if (status === "new" || status === "drift") {
11890
+ appendAuditLog({
11891
+ toolName: `mcp-server:${serverKey}`,
11892
+ args: { toolCount: tools.length, status },
11893
+ decision: "mcp-discovered"
11894
+ });
11820
11895
  const id = (0, import_crypto7.randomUUID)();
11821
11896
  const entry = {
11822
11897
  id,
@@ -11885,6 +11960,11 @@ data: ${JSON.stringify(item.data)}
11885
11960
  }
11886
11961
  clearTimeout(entry.timer);
11887
11962
  approveServer(serverKey, disabledTools);
11963
+ appendAuditLog({
11964
+ toolName: `mcp-server:${serverKey}`,
11965
+ args: { disabledTools },
11966
+ decision: "allow"
11967
+ });
11888
11968
  pending.delete(id);
11889
11969
  broadcast("remove", { id, decision: "allow" });
11890
11970
  res.writeHead(200).end();
@@ -11907,14 +11987,14 @@ data: ${JSON.stringify(item.data)}
11907
11987
  server.on("error", (e) => {
11908
11988
  if (e.code === "EADDRINUSE") {
11909
11989
  try {
11910
- if (import_fs21.default.existsSync(DAEMON_PID_FILE)) {
11911
- const { pid } = JSON.parse(import_fs21.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
11990
+ if (import_fs22.default.existsSync(DAEMON_PID_FILE)) {
11991
+ const { pid } = JSON.parse(import_fs22.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
11912
11992
  process.kill(pid, 0);
11913
11993
  return process.exit(0);
11914
11994
  }
11915
11995
  } catch {
11916
11996
  try {
11917
- import_fs21.default.unlinkSync(DAEMON_PID_FILE);
11997
+ import_fs22.default.unlinkSync(DAEMON_PID_FILE);
11918
11998
  } catch {
11919
11999
  }
11920
12000
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -11973,13 +12053,13 @@ data: ${JSON.stringify(item.data)}
11973
12053
  }
11974
12054
  startActivitySocket();
11975
12055
  }
11976
- var import_http, import_fs21, import_path24, import_os19, import_crypto7, import_child_process5, import_chalk3;
12056
+ var import_http, import_fs22, import_path25, import_os19, import_crypto7, import_child_process5, import_chalk3;
11977
12057
  var init_server = __esm({
11978
12058
  "src/daemon/server.ts"() {
11979
12059
  "use strict";
11980
12060
  import_http = __toESM(require("http"));
11981
- import_fs21 = __toESM(require("fs"));
11982
- import_path24 = __toESM(require("path"));
12061
+ import_fs22 = __toESM(require("fs"));
12062
+ import_path25 = __toESM(require("path"));
11983
12063
  import_os19 = __toESM(require("os"));
11984
12064
  import_crypto7 = require("crypto");
11985
12065
  import_child_process5 = require("child_process");
@@ -12004,8 +12084,8 @@ var init_server = __esm({
12004
12084
  function resolveNode9Binary() {
12005
12085
  try {
12006
12086
  const script = process.argv[1];
12007
- if (typeof script === "string" && import_path25.default.isAbsolute(script) && import_fs22.default.existsSync(script)) {
12008
- return import_fs22.default.realpathSync(script);
12087
+ if (typeof script === "string" && import_path26.default.isAbsolute(script) && import_fs23.default.existsSync(script)) {
12088
+ return import_fs23.default.realpathSync(script);
12009
12089
  }
12010
12090
  } catch {
12011
12091
  }
@@ -12023,11 +12103,11 @@ function xmlEscape(s) {
12023
12103
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
12024
12104
  }
12025
12105
  function launchdPlist(binaryPath) {
12026
- const logDir = import_path25.default.join(import_os20.default.homedir(), ".node9");
12106
+ const logDir = import_path26.default.join(import_os20.default.homedir(), ".node9");
12027
12107
  const nodePath = xmlEscape(process.execPath);
12028
12108
  const scriptPath = xmlEscape(binaryPath);
12029
- const outLog = xmlEscape(import_path25.default.join(logDir, "daemon.log"));
12030
- const errLog = xmlEscape(import_path25.default.join(logDir, "daemon-error.log"));
12109
+ const outLog = xmlEscape(import_path26.default.join(logDir, "daemon.log"));
12110
+ const errLog = xmlEscape(import_path26.default.join(logDir, "daemon-error.log"));
12031
12111
  return `<?xml version="1.0" encoding="UTF-8"?>
12032
12112
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
12033
12113
  <plist version="1.0">
@@ -12062,9 +12142,9 @@ function launchdPlist(binaryPath) {
12062
12142
  `;
12063
12143
  }
12064
12144
  function installLaunchd(binaryPath) {
12065
- const dir = import_path25.default.dirname(LAUNCHD_PLIST);
12066
- if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
12067
- import_fs22.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
12145
+ const dir = import_path26.default.dirname(LAUNCHD_PLIST);
12146
+ if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
12147
+ import_fs23.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
12068
12148
  (0, import_child_process6.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
12069
12149
  const r = (0, import_child_process6.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
12070
12150
  encoding: "utf8",
@@ -12075,13 +12155,13 @@ function installLaunchd(binaryPath) {
12075
12155
  }
12076
12156
  }
12077
12157
  function uninstallLaunchd() {
12078
- if (import_fs22.default.existsSync(LAUNCHD_PLIST)) {
12158
+ if (import_fs23.default.existsSync(LAUNCHD_PLIST)) {
12079
12159
  (0, import_child_process6.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
12080
- import_fs22.default.unlinkSync(LAUNCHD_PLIST);
12160
+ import_fs23.default.unlinkSync(LAUNCHD_PLIST);
12081
12161
  }
12082
12162
  }
12083
12163
  function isLaunchdInstalled() {
12084
- return import_fs22.default.existsSync(LAUNCHD_PLIST);
12164
+ return import_fs23.default.existsSync(LAUNCHD_PLIST);
12085
12165
  }
12086
12166
  function systemdUnit(binaryPath) {
12087
12167
  return `[Unit]
@@ -12101,10 +12181,10 @@ WantedBy=default.target
12101
12181
  `;
12102
12182
  }
12103
12183
  function installSystemd(binaryPath) {
12104
- if (!import_fs22.default.existsSync(SYSTEMD_UNIT_DIR)) {
12105
- import_fs22.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
12184
+ if (!import_fs23.default.existsSync(SYSTEMD_UNIT_DIR)) {
12185
+ import_fs23.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
12106
12186
  }
12107
- import_fs22.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
12187
+ import_fs23.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
12108
12188
  try {
12109
12189
  (0, import_child_process6.execFileSync)("loginctl", ["enable-linger", import_os20.default.userInfo().username], { timeout: 3e3 });
12110
12190
  } catch {
@@ -12126,23 +12206,23 @@ function installSystemd(binaryPath) {
12126
12206
  }
12127
12207
  }
12128
12208
  function uninstallSystemd() {
12129
- if (import_fs22.default.existsSync(SYSTEMD_UNIT)) {
12209
+ if (import_fs23.default.existsSync(SYSTEMD_UNIT)) {
12130
12210
  (0, import_child_process6.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
12131
12211
  encoding: "utf8",
12132
12212
  timeout: 5e3
12133
12213
  });
12134
12214
  (0, import_child_process6.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
12135
- import_fs22.default.unlinkSync(SYSTEMD_UNIT);
12215
+ import_fs23.default.unlinkSync(SYSTEMD_UNIT);
12136
12216
  }
12137
12217
  }
12138
12218
  function isSystemdInstalled() {
12139
- return import_fs22.default.existsSync(SYSTEMD_UNIT);
12219
+ return import_fs23.default.existsSync(SYSTEMD_UNIT);
12140
12220
  }
12141
12221
  function stopRunningDaemon() {
12142
- const pidFile = import_path25.default.join(import_os20.default.homedir(), ".node9", "daemon.pid");
12143
- if (!import_fs22.default.existsSync(pidFile)) return;
12222
+ const pidFile = import_path26.default.join(import_os20.default.homedir(), ".node9", "daemon.pid");
12223
+ if (!import_fs23.default.existsSync(pidFile)) return;
12144
12224
  try {
12145
- const data = JSON.parse(import_fs22.default.readFileSync(pidFile, "utf-8"));
12225
+ const data = JSON.parse(import_fs23.default.readFileSync(pidFile, "utf-8"));
12146
12226
  const pid = data.pid;
12147
12227
  const MAX_PID2 = 4194304;
12148
12228
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -12162,7 +12242,7 @@ function stopRunningDaemon() {
12162
12242
  }
12163
12243
  }
12164
12244
  try {
12165
- import_fs22.default.unlinkSync(pidFile);
12245
+ import_fs23.default.unlinkSync(pidFile);
12166
12246
  } catch {
12167
12247
  }
12168
12248
  } catch {
@@ -12232,26 +12312,26 @@ function isDaemonServiceInstalled() {
12232
12312
  if (process.platform === "linux") return isSystemdInstalled();
12233
12313
  return false;
12234
12314
  }
12235
- var import_fs22, import_path25, import_os20, import_child_process6, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
12315
+ var import_fs23, import_path26, import_os20, import_child_process6, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
12236
12316
  var init_service = __esm({
12237
12317
  "src/daemon/service.ts"() {
12238
12318
  "use strict";
12239
- import_fs22 = __toESM(require("fs"));
12240
- import_path25 = __toESM(require("path"));
12319
+ import_fs23 = __toESM(require("fs"));
12320
+ import_path26 = __toESM(require("path"));
12241
12321
  import_os20 = __toESM(require("os"));
12242
12322
  import_child_process6 = require("child_process");
12243
12323
  LAUNCHD_LABEL = "ai.node9.daemon";
12244
- LAUNCHD_PLIST = import_path25.default.join(import_os20.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
12245
- SYSTEMD_UNIT_DIR = import_path25.default.join(import_os20.default.homedir(), ".config", "systemd", "user");
12246
- SYSTEMD_UNIT = import_path25.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
12324
+ LAUNCHD_PLIST = import_path26.default.join(import_os20.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
12325
+ SYSTEMD_UNIT_DIR = import_path26.default.join(import_os20.default.homedir(), ".config", "systemd", "user");
12326
+ SYSTEMD_UNIT = import_path26.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
12247
12327
  }
12248
12328
  });
12249
12329
 
12250
12330
  // src/daemon/index.ts
12251
12331
  function stopDaemon() {
12252
- if (!import_fs23.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk4.default.yellow("Not running."));
12332
+ if (!import_fs24.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk4.default.yellow("Not running."));
12253
12333
  try {
12254
- const data = JSON.parse(import_fs23.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
12334
+ const data = JSON.parse(import_fs24.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
12255
12335
  const pid = data.pid;
12256
12336
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
12257
12337
  console.log(import_chalk4.default.gray("Cleaned up invalid PID file."));
@@ -12263,7 +12343,7 @@ function stopDaemon() {
12263
12343
  console.log(import_chalk4.default.gray("Cleaned up stale PID file."));
12264
12344
  } finally {
12265
12345
  try {
12266
- import_fs23.default.unlinkSync(DAEMON_PID_FILE);
12346
+ import_fs24.default.unlinkSync(DAEMON_PID_FILE);
12267
12347
  } catch {
12268
12348
  }
12269
12349
  }
@@ -12272,9 +12352,9 @@ function daemonStatus() {
12272
12352
  const serviceInstalled = isDaemonServiceInstalled();
12273
12353
  const serviceLabel = serviceInstalled ? import_chalk4.default.green("installed (starts on login)") : import_chalk4.default.yellow("not installed \u2014 run: node9 daemon install");
12274
12354
  let processStatus;
12275
- if (import_fs23.default.existsSync(DAEMON_PID_FILE)) {
12355
+ if (import_fs24.default.existsSync(DAEMON_PID_FILE)) {
12276
12356
  try {
12277
- const data = JSON.parse(import_fs23.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
12357
+ const data = JSON.parse(import_fs24.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
12278
12358
  const pid = data.pid;
12279
12359
  const port = data.port;
12280
12360
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -12304,11 +12384,11 @@ function daemonStatus() {
12304
12384
  console.log(` Service : ${serviceLabel}
12305
12385
  `);
12306
12386
  }
12307
- var import_fs23, import_chalk4, import_child_process7, MAX_PID;
12387
+ var import_fs24, import_chalk4, import_child_process7, MAX_PID;
12308
12388
  var init_daemon2 = __esm({
12309
12389
  "src/daemon/index.ts"() {
12310
12390
  "use strict";
12311
- import_fs23 = __toESM(require("fs"));
12391
+ import_fs24 = __toESM(require("fs"));
12312
12392
  import_chalk4 = __toESM(require("chalk"));
12313
12393
  import_child_process7 = require("child_process");
12314
12394
  init_server();
@@ -12340,20 +12420,20 @@ function getModelContextLimit(model) {
12340
12420
  return 2e5;
12341
12421
  }
12342
12422
  function readSessionUsage() {
12343
- const projectsDir = import_path41.default.join(import_os35.default.homedir(), ".claude", "projects");
12344
- if (!import_fs38.default.existsSync(projectsDir)) return null;
12423
+ const projectsDir = import_path42.default.join(import_os35.default.homedir(), ".claude", "projects");
12424
+ if (!import_fs39.default.existsSync(projectsDir)) return null;
12345
12425
  let latestFile = null;
12346
12426
  let latestMtime = 0;
12347
12427
  try {
12348
- for (const dir of import_fs38.default.readdirSync(projectsDir)) {
12349
- const dirPath = import_path41.default.join(projectsDir, dir);
12428
+ for (const dir of import_fs39.default.readdirSync(projectsDir)) {
12429
+ const dirPath = import_path42.default.join(projectsDir, dir);
12350
12430
  try {
12351
- if (!import_fs38.default.statSync(dirPath).isDirectory()) continue;
12352
- for (const file of import_fs38.default.readdirSync(dirPath)) {
12431
+ if (!import_fs39.default.statSync(dirPath).isDirectory()) continue;
12432
+ for (const file of import_fs39.default.readdirSync(dirPath)) {
12353
12433
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
12354
- const filePath = import_path41.default.join(dirPath, file);
12434
+ const filePath = import_path42.default.join(dirPath, file);
12355
12435
  try {
12356
- const mtime = import_fs38.default.statSync(filePath).mtimeMs;
12436
+ const mtime = import_fs39.default.statSync(filePath).mtimeMs;
12357
12437
  if (mtime > latestMtime) {
12358
12438
  latestMtime = mtime;
12359
12439
  latestFile = filePath;
@@ -12368,7 +12448,7 @@ function readSessionUsage() {
12368
12448
  }
12369
12449
  if (!latestFile) return null;
12370
12450
  try {
12371
- const lines = import_fs38.default.readFileSync(latestFile, "utf-8").split("\n");
12451
+ const lines = import_fs39.default.readFileSync(latestFile, "utf-8").split("\n");
12372
12452
  let lastModel = "";
12373
12453
  let lastInput = 0;
12374
12454
  let lastOutput = 0;
@@ -12457,9 +12537,9 @@ function renderPending(activity) {
12457
12537
  }
12458
12538
  async function ensureDaemon() {
12459
12539
  let pidPort = null;
12460
- if (import_fs38.default.existsSync(PID_FILE)) {
12540
+ if (import_fs39.default.existsSync(PID_FILE)) {
12461
12541
  try {
12462
- const { port } = JSON.parse(import_fs38.default.readFileSync(PID_FILE, "utf-8"));
12542
+ const { port } = JSON.parse(import_fs39.default.readFileSync(PID_FILE, "utf-8"));
12463
12543
  pidPort = port;
12464
12544
  } catch {
12465
12545
  console.error(import_chalk25.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -12612,9 +12692,9 @@ function buildRecoveryCardLines(req) {
12612
12692
  ];
12613
12693
  }
12614
12694
  function readApproversFromDisk() {
12615
- const configPath = import_path41.default.join(import_os35.default.homedir(), ".node9", "config.json");
12695
+ const configPath = import_path42.default.join(import_os35.default.homedir(), ".node9", "config.json");
12616
12696
  try {
12617
- const raw = JSON.parse(import_fs38.default.readFileSync(configPath, "utf-8"));
12697
+ const raw = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
12618
12698
  const settings = raw.settings ?? {};
12619
12699
  return settings.approvers ?? {};
12620
12700
  } catch {
@@ -12630,15 +12710,15 @@ function approverStatusLine() {
12630
12710
  return `${fmt("native", "native")} ${fmt("browser", "browser")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
12631
12711
  }
12632
12712
  function toggleApprover(channel) {
12633
- const configPath = import_path41.default.join(import_os35.default.homedir(), ".node9", "config.json");
12713
+ const configPath = import_path42.default.join(import_os35.default.homedir(), ".node9", "config.json");
12634
12714
  try {
12635
- const raw = JSON.parse(import_fs38.default.readFileSync(configPath, "utf-8"));
12715
+ const raw = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
12636
12716
  const settings = raw.settings ?? {};
12637
12717
  const approvers = settings.approvers ?? {};
12638
12718
  approvers[channel] = approvers[channel] === false;
12639
12719
  settings.approvers = approvers;
12640
12720
  raw.settings = settings;
12641
- import_fs38.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
12721
+ import_fs39.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
12642
12722
  } catch (err2) {
12643
12723
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
12644
12724
  `);
@@ -12808,8 +12888,8 @@ async function startTail(options = {}) {
12808
12888
  }
12809
12889
  postDecisionHttp(req2.id, httpDecision, csrfToken, port, httpOpts).catch((err2) => {
12810
12890
  try {
12811
- import_fs38.default.appendFileSync(
12812
- import_path41.default.join(import_os35.default.homedir(), ".node9", "hook-debug.log"),
12891
+ import_fs39.default.appendFileSync(
12892
+ import_path42.default.join(import_os35.default.homedir(), ".node9", "hook-debug.log"),
12813
12893
  `[tail] POST /decision failed: ${String(err2)}
12814
12894
  `
12815
12895
  );
@@ -12890,9 +12970,9 @@ async function startTail(options = {}) {
12890
12970
  }
12891
12971
  } catch {
12892
12972
  }
12893
- const auditLog = import_path41.default.join(import_os35.default.homedir(), ".node9", "audit.log");
12973
+ const auditLog = import_path42.default.join(import_os35.default.homedir(), ".node9", "audit.log");
12894
12974
  try {
12895
- const unackedDlp = import_fs38.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
12975
+ const unackedDlp = import_fs39.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
12896
12976
  if (unackedDlp > 0) {
12897
12977
  console.log("");
12898
12978
  console.log(
@@ -13077,21 +13157,21 @@ async function startTail(options = {}) {
13077
13157
  process.exit(1);
13078
13158
  });
13079
13159
  }
13080
- var import_http2, import_chalk25, import_fs38, import_os35, import_path41, import_readline5, import_child_process16, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
13160
+ var import_http2, import_chalk25, import_fs39, import_os35, import_path42, import_readline5, import_child_process16, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
13081
13161
  var init_tail = __esm({
13082
13162
  "src/tui/tail.ts"() {
13083
13163
  "use strict";
13084
13164
  import_http2 = __toESM(require("http"));
13085
13165
  import_chalk25 = __toESM(require("chalk"));
13086
- import_fs38 = __toESM(require("fs"));
13166
+ import_fs39 = __toESM(require("fs"));
13087
13167
  import_os35 = __toESM(require("os"));
13088
- import_path41 = __toESM(require("path"));
13168
+ import_path42 = __toESM(require("path"));
13089
13169
  import_readline5 = __toESM(require("readline"));
13090
13170
  import_child_process16 = require("child_process");
13091
13171
  init_daemon2();
13092
13172
  init_daemon();
13093
13173
  init_core();
13094
- PID_FILE = import_path41.default.join(import_os35.default.homedir(), ".node9", "daemon.pid");
13174
+ PID_FILE = import_path42.default.join(import_os35.default.homedir(), ".node9", "daemon.pid");
13095
13175
  ICONS = {
13096
13176
  bash: "\u{1F4BB}",
13097
13177
  shell: "\u{1F4BB}",
@@ -13213,9 +13293,9 @@ function formatTimeLeft(resetsAt) {
13213
13293
  return ` (${m}m left)`;
13214
13294
  }
13215
13295
  function safeReadJson(filePath) {
13216
- if (!import_fs39.default.existsSync(filePath)) return null;
13296
+ if (!import_fs40.default.existsSync(filePath)) return null;
13217
13297
  try {
13218
- return JSON.parse(import_fs39.default.readFileSync(filePath, "utf-8"));
13298
+ return JSON.parse(import_fs40.default.readFileSync(filePath, "utf-8"));
13219
13299
  } catch {
13220
13300
  return null;
13221
13301
  }
@@ -13236,12 +13316,12 @@ function countHooksInFile(filePath) {
13236
13316
  return Object.keys(cfg.hooks).length;
13237
13317
  }
13238
13318
  function countRulesInDir(rulesDir) {
13239
- if (!import_fs39.default.existsSync(rulesDir)) return 0;
13319
+ if (!import_fs40.default.existsSync(rulesDir)) return 0;
13240
13320
  let count = 0;
13241
13321
  try {
13242
- for (const entry of import_fs39.default.readdirSync(rulesDir, { withFileTypes: true })) {
13322
+ for (const entry of import_fs40.default.readdirSync(rulesDir, { withFileTypes: true })) {
13243
13323
  if (entry.isDirectory()) {
13244
- count += countRulesInDir(import_path42.default.join(rulesDir, entry.name));
13324
+ count += countRulesInDir(import_path43.default.join(rulesDir, entry.name));
13245
13325
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
13246
13326
  count++;
13247
13327
  }
@@ -13252,46 +13332,46 @@ function countRulesInDir(rulesDir) {
13252
13332
  }
13253
13333
  function isSamePath(a, b) {
13254
13334
  try {
13255
- return import_path42.default.resolve(a) === import_path42.default.resolve(b);
13335
+ return import_path43.default.resolve(a) === import_path43.default.resolve(b);
13256
13336
  } catch {
13257
13337
  return false;
13258
13338
  }
13259
13339
  }
13260
13340
  function countConfigs(cwd) {
13261
13341
  const homeDir2 = import_os36.default.homedir();
13262
- const claudeDir = import_path42.default.join(homeDir2, ".claude");
13342
+ const claudeDir = import_path43.default.join(homeDir2, ".claude");
13263
13343
  let claudeMdCount = 0;
13264
13344
  let rulesCount = 0;
13265
13345
  let hooksCount = 0;
13266
13346
  const userMcpServers = /* @__PURE__ */ new Set();
13267
13347
  const projectMcpServers = /* @__PURE__ */ new Set();
13268
- if (import_fs39.default.existsSync(import_path42.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
13269
- rulesCount += countRulesInDir(import_path42.default.join(claudeDir, "rules"));
13270
- const userSettings = import_path42.default.join(claudeDir, "settings.json");
13348
+ if (import_fs40.default.existsSync(import_path43.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
13349
+ rulesCount += countRulesInDir(import_path43.default.join(claudeDir, "rules"));
13350
+ const userSettings = import_path43.default.join(claudeDir, "settings.json");
13271
13351
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
13272
13352
  hooksCount += countHooksInFile(userSettings);
13273
- const userClaudeJson = import_path42.default.join(homeDir2, ".claude.json");
13353
+ const userClaudeJson = import_path43.default.join(homeDir2, ".claude.json");
13274
13354
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
13275
13355
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
13276
13356
  userMcpServers.delete(name);
13277
13357
  }
13278
13358
  if (cwd) {
13279
- if (import_fs39.default.existsSync(import_path42.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
13280
- if (import_fs39.default.existsSync(import_path42.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
13281
- const projectClaudeDir = import_path42.default.join(cwd, ".claude");
13359
+ if (import_fs40.default.existsSync(import_path43.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
13360
+ if (import_fs40.default.existsSync(import_path43.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
13361
+ const projectClaudeDir = import_path43.default.join(cwd, ".claude");
13282
13362
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
13283
13363
  if (!overlapsUserScope) {
13284
- if (import_fs39.default.existsSync(import_path42.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
13285
- rulesCount += countRulesInDir(import_path42.default.join(projectClaudeDir, "rules"));
13286
- const projSettings = import_path42.default.join(projectClaudeDir, "settings.json");
13364
+ if (import_fs40.default.existsSync(import_path43.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
13365
+ rulesCount += countRulesInDir(import_path43.default.join(projectClaudeDir, "rules"));
13366
+ const projSettings = import_path43.default.join(projectClaudeDir, "settings.json");
13287
13367
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
13288
13368
  hooksCount += countHooksInFile(projSettings);
13289
13369
  }
13290
- if (import_fs39.default.existsSync(import_path42.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
13291
- const localSettings = import_path42.default.join(projectClaudeDir, "settings.local.json");
13370
+ if (import_fs40.default.existsSync(import_path43.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
13371
+ const localSettings = import_path43.default.join(projectClaudeDir, "settings.local.json");
13292
13372
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
13293
13373
  hooksCount += countHooksInFile(localSettings);
13294
- const mcpJsonServers = getMcpServerNames(import_path42.default.join(cwd, ".mcp.json"));
13374
+ const mcpJsonServers = getMcpServerNames(import_path43.default.join(cwd, ".mcp.json"));
13295
13375
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
13296
13376
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
13297
13377
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -13324,12 +13404,12 @@ function readActiveShieldsHud() {
13324
13404
  return shieldsCache.value;
13325
13405
  }
13326
13406
  try {
13327
- const shieldsPath = import_path42.default.join(import_os36.default.homedir(), ".node9", "shields.json");
13328
- if (!import_fs39.default.existsSync(shieldsPath)) {
13407
+ const shieldsPath = import_path43.default.join(import_os36.default.homedir(), ".node9", "shields.json");
13408
+ if (!import_fs40.default.existsSync(shieldsPath)) {
13329
13409
  shieldsCache = { value: [], ts: now };
13330
13410
  return [];
13331
13411
  }
13332
- const parsed = JSON.parse(import_fs39.default.readFileSync(shieldsPath, "utf-8"));
13412
+ const parsed = JSON.parse(import_fs40.default.readFileSync(shieldsPath, "utf-8"));
13333
13413
  if (!Array.isArray(parsed.active)) {
13334
13414
  shieldsCache = { value: [], ts: now };
13335
13415
  return [];
@@ -13431,17 +13511,17 @@ function renderContextLine(stdin) {
13431
13511
  async function main() {
13432
13512
  try {
13433
13513
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
13434
- if (import_fs39.default.existsSync(import_path42.default.join(import_os36.default.homedir(), ".node9", "hud-debug"))) {
13514
+ if (import_fs40.default.existsSync(import_path43.default.join(import_os36.default.homedir(), ".node9", "hud-debug"))) {
13435
13515
  try {
13436
- const logPath = import_path42.default.join(import_os36.default.homedir(), ".node9", "hud-debug.log");
13516
+ const logPath = import_path43.default.join(import_os36.default.homedir(), ".node9", "hud-debug.log");
13437
13517
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
13438
13518
  let size = 0;
13439
13519
  try {
13440
- size = import_fs39.default.statSync(logPath).size;
13520
+ size = import_fs40.default.statSync(logPath).size;
13441
13521
  } catch {
13442
13522
  }
13443
13523
  if (size < MAX_LOG_SIZE) {
13444
- import_fs39.default.appendFileSync(
13524
+ import_fs40.default.appendFileSync(
13445
13525
  logPath,
13446
13526
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
13447
13527
  );
@@ -13462,11 +13542,11 @@ async function main() {
13462
13542
  try {
13463
13543
  const cwd = stdin.cwd ?? process.cwd();
13464
13544
  for (const configPath of [
13465
- import_path42.default.join(cwd, "node9.config.json"),
13466
- import_path42.default.join(import_os36.default.homedir(), ".node9", "config.json")
13545
+ import_path43.default.join(cwd, "node9.config.json"),
13546
+ import_path43.default.join(import_os36.default.homedir(), ".node9", "config.json")
13467
13547
  ]) {
13468
- if (!import_fs39.default.existsSync(configPath)) continue;
13469
- const cfg = JSON.parse(import_fs39.default.readFileSync(configPath, "utf-8"));
13548
+ if (!import_fs40.default.existsSync(configPath)) continue;
13549
+ const cfg = JSON.parse(import_fs40.default.readFileSync(configPath, "utf-8"));
13470
13550
  const hud = cfg.settings?.hud;
13471
13551
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
13472
13552
  }
@@ -13484,12 +13564,12 @@ async function main() {
13484
13564
  renderOffline();
13485
13565
  }
13486
13566
  }
13487
- var import_fs39, import_path42, import_os36, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
13567
+ var import_fs40, import_path43, import_os36, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
13488
13568
  var init_hud = __esm({
13489
13569
  "src/cli/hud.ts"() {
13490
13570
  "use strict";
13491
- import_fs39 = __toESM(require("fs"));
13492
- import_path42 = __toESM(require("path"));
13571
+ import_fs40 = __toESM(require("fs"));
13572
+ import_path43 = __toESM(require("path"));
13493
13573
  import_os36 = __toESM(require("os"));
13494
13574
  import_http3 = __toESM(require("http"));
13495
13575
  init_daemon();
@@ -14538,8 +14618,8 @@ function getAgentsStatus(homeDir2 = import_os11.default.homedir()) {
14538
14618
  // src/cli.ts
14539
14619
  init_daemon2();
14540
14620
  var import_chalk26 = __toESM(require("chalk"));
14541
- var import_fs40 = __toESM(require("fs"));
14542
- var import_path43 = __toESM(require("path"));
14621
+ var import_fs41 = __toESM(require("fs"));
14622
+ var import_path44 = __toESM(require("path"));
14543
14623
  var import_os37 = __toESM(require("os"));
14544
14624
  var import_prompts2 = require("@inquirer/prompts");
14545
14625
 
@@ -14725,9 +14805,9 @@ init_daemon_starter();
14725
14805
 
14726
14806
  // src/cli/commands/check.ts
14727
14807
  var import_chalk6 = __toESM(require("chalk"));
14728
- var import_fs26 = __toESM(require("fs"));
14808
+ var import_fs27 = __toESM(require("fs"));
14729
14809
  var import_child_process10 = require("child_process");
14730
- var import_path28 = __toESM(require("path"));
14810
+ var import_path29 = __toESM(require("path"));
14731
14811
  var import_os23 = __toESM(require("os"));
14732
14812
  init_orchestrator();
14733
14813
  init_daemon();
@@ -14737,11 +14817,11 @@ init_policy();
14737
14817
  // src/undo.ts
14738
14818
  var import_child_process9 = require("child_process");
14739
14819
  var import_crypto8 = __toESM(require("crypto"));
14740
- var import_fs24 = __toESM(require("fs"));
14820
+ var import_fs25 = __toESM(require("fs"));
14741
14821
  var import_net3 = __toESM(require("net"));
14742
- var import_path26 = __toESM(require("path"));
14822
+ var import_path27 = __toESM(require("path"));
14743
14823
  var import_os21 = __toESM(require("os"));
14744
- var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path26.default.join(import_os21.default.tmpdir(), "node9-activity.sock");
14824
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path27.default.join(import_os21.default.tmpdir(), "node9-activity.sock");
14745
14825
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
14746
14826
  try {
14747
14827
  const payload = JSON.stringify({
@@ -14761,22 +14841,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
14761
14841
  } catch {
14762
14842
  }
14763
14843
  }
14764
- var SNAPSHOT_STACK_PATH = import_path26.default.join(import_os21.default.homedir(), ".node9", "snapshots.json");
14765
- var UNDO_LATEST_PATH = import_path26.default.join(import_os21.default.homedir(), ".node9", "undo_latest.txt");
14844
+ var SNAPSHOT_STACK_PATH = import_path27.default.join(import_os21.default.homedir(), ".node9", "snapshots.json");
14845
+ var UNDO_LATEST_PATH = import_path27.default.join(import_os21.default.homedir(), ".node9", "undo_latest.txt");
14766
14846
  var MAX_SNAPSHOTS = 10;
14767
14847
  var GIT_TIMEOUT = 15e3;
14768
14848
  function readStack() {
14769
14849
  try {
14770
- if (import_fs24.default.existsSync(SNAPSHOT_STACK_PATH))
14771
- return JSON.parse(import_fs24.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
14850
+ if (import_fs25.default.existsSync(SNAPSHOT_STACK_PATH))
14851
+ return JSON.parse(import_fs25.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
14772
14852
  } catch {
14773
14853
  }
14774
14854
  return [];
14775
14855
  }
14776
14856
  function writeStack(stack) {
14777
- const dir = import_path26.default.dirname(SNAPSHOT_STACK_PATH);
14778
- if (!import_fs24.default.existsSync(dir)) import_fs24.default.mkdirSync(dir, { recursive: true });
14779
- import_fs24.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
14857
+ const dir = import_path27.default.dirname(SNAPSHOT_STACK_PATH);
14858
+ if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
14859
+ import_fs25.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
14780
14860
  }
14781
14861
  function extractFilePath(args) {
14782
14862
  if (!args || typeof args !== "object") return null;
@@ -14796,12 +14876,12 @@ function buildArgsSummary(tool, args) {
14796
14876
  return "";
14797
14877
  }
14798
14878
  function findProjectRoot(filePath) {
14799
- let dir = import_path26.default.dirname(filePath);
14879
+ let dir = import_path27.default.dirname(filePath);
14800
14880
  while (true) {
14801
- if (import_fs24.default.existsSync(import_path26.default.join(dir, ".git")) || import_fs24.default.existsSync(import_path26.default.join(dir, "package.json"))) {
14881
+ if (import_fs25.default.existsSync(import_path27.default.join(dir, ".git")) || import_fs25.default.existsSync(import_path27.default.join(dir, "package.json"))) {
14802
14882
  return dir;
14803
14883
  }
14804
- const parent = import_path26.default.dirname(dir);
14884
+ const parent = import_path27.default.dirname(dir);
14805
14885
  if (parent === dir) return process.cwd();
14806
14886
  dir = parent;
14807
14887
  }
@@ -14809,7 +14889,7 @@ function findProjectRoot(filePath) {
14809
14889
  function normalizeCwdForHash(cwd) {
14810
14890
  let normalized;
14811
14891
  try {
14812
- normalized = import_fs24.default.realpathSync(cwd);
14892
+ normalized = import_fs25.default.realpathSync(cwd);
14813
14893
  } catch {
14814
14894
  normalized = cwd;
14815
14895
  }
@@ -14819,16 +14899,16 @@ function normalizeCwdForHash(cwd) {
14819
14899
  }
14820
14900
  function getShadowRepoDir(cwd) {
14821
14901
  const hash = import_crypto8.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
14822
- return import_path26.default.join(import_os21.default.homedir(), ".node9", "snapshots", hash);
14902
+ return import_path27.default.join(import_os21.default.homedir(), ".node9", "snapshots", hash);
14823
14903
  }
14824
14904
  function cleanOrphanedIndexFiles(shadowDir) {
14825
14905
  try {
14826
14906
  const cutoff = Date.now() - 6e4;
14827
- for (const f of import_fs24.default.readdirSync(shadowDir)) {
14907
+ for (const f of import_fs25.default.readdirSync(shadowDir)) {
14828
14908
  if (f.startsWith("index_")) {
14829
- const fp = import_path26.default.join(shadowDir, f);
14909
+ const fp = import_path27.default.join(shadowDir, f);
14830
14910
  try {
14831
- if (import_fs24.default.statSync(fp).mtimeMs < cutoff) import_fs24.default.unlinkSync(fp);
14911
+ if (import_fs25.default.statSync(fp).mtimeMs < cutoff) import_fs25.default.unlinkSync(fp);
14832
14912
  } catch {
14833
14913
  }
14834
14914
  }
@@ -14840,7 +14920,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
14840
14920
  const hardcoded = [".git", ".node9"];
14841
14921
  const lines = [...hardcoded, ...ignorePaths].join("\n");
14842
14922
  try {
14843
- import_fs24.default.writeFileSync(import_path26.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
14923
+ import_fs25.default.writeFileSync(import_path27.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
14844
14924
  } catch {
14845
14925
  }
14846
14926
  }
@@ -14853,25 +14933,25 @@ function ensureShadowRepo(shadowDir, cwd) {
14853
14933
  timeout: 3e3
14854
14934
  });
14855
14935
  if (check.status === 0) {
14856
- const ptPath = import_path26.default.join(shadowDir, "project-path.txt");
14936
+ const ptPath = import_path27.default.join(shadowDir, "project-path.txt");
14857
14937
  try {
14858
- const stored = import_fs24.default.readFileSync(ptPath, "utf8").trim();
14938
+ const stored = import_fs25.default.readFileSync(ptPath, "utf8").trim();
14859
14939
  if (stored === normalizedCwd) return true;
14860
14940
  if (process.env.NODE9_DEBUG === "1")
14861
14941
  console.error(
14862
14942
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
14863
14943
  );
14864
- import_fs24.default.rmSync(shadowDir, { recursive: true, force: true });
14944
+ import_fs25.default.rmSync(shadowDir, { recursive: true, force: true });
14865
14945
  } catch {
14866
14946
  try {
14867
- import_fs24.default.writeFileSync(ptPath, normalizedCwd, "utf8");
14947
+ import_fs25.default.writeFileSync(ptPath, normalizedCwd, "utf8");
14868
14948
  } catch {
14869
14949
  }
14870
14950
  return true;
14871
14951
  }
14872
14952
  }
14873
14953
  try {
14874
- import_fs24.default.mkdirSync(shadowDir, { recursive: true });
14954
+ import_fs25.default.mkdirSync(shadowDir, { recursive: true });
14875
14955
  } catch {
14876
14956
  }
14877
14957
  const init = (0, import_child_process9.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -14880,7 +14960,7 @@ function ensureShadowRepo(shadowDir, cwd) {
14880
14960
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
14881
14961
  return false;
14882
14962
  }
14883
- const configFile = import_path26.default.join(shadowDir, "config");
14963
+ const configFile = import_path27.default.join(shadowDir, "config");
14884
14964
  (0, import_child_process9.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
14885
14965
  timeout: 3e3
14886
14966
  });
@@ -14888,7 +14968,7 @@ function ensureShadowRepo(shadowDir, cwd) {
14888
14968
  timeout: 3e3
14889
14969
  });
14890
14970
  try {
14891
- import_fs24.default.writeFileSync(import_path26.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
14971
+ import_fs25.default.writeFileSync(import_path27.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
14892
14972
  } catch {
14893
14973
  }
14894
14974
  return true;
@@ -14908,12 +14988,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
14908
14988
  let indexFile = null;
14909
14989
  try {
14910
14990
  const rawFilePath = extractFilePath(args);
14911
- const absFilePath = rawFilePath && import_path26.default.isAbsolute(rawFilePath) ? rawFilePath : null;
14991
+ const absFilePath = rawFilePath && import_path27.default.isAbsolute(rawFilePath) ? rawFilePath : null;
14912
14992
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
14913
14993
  const shadowDir = getShadowRepoDir(cwd);
14914
14994
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
14915
14995
  writeShadowExcludes(shadowDir, ignorePaths);
14916
- indexFile = import_path26.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
14996
+ indexFile = import_path27.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
14917
14997
  const shadowEnv = {
14918
14998
  ...process.env,
14919
14999
  GIT_DIR: shadowDir,
@@ -14985,7 +15065,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
14985
15065
  writeStack(stack);
14986
15066
  const entry = stack[stack.length - 1];
14987
15067
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
14988
- import_fs24.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
15068
+ import_fs25.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
14989
15069
  if (shouldGc) {
14990
15070
  (0, import_child_process9.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
14991
15071
  }
@@ -14996,7 +15076,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
14996
15076
  } finally {
14997
15077
  if (indexFile) {
14998
15078
  try {
14999
- import_fs24.default.unlinkSync(indexFile);
15079
+ import_fs25.default.unlinkSync(indexFile);
15000
15080
  } catch {
15001
15081
  }
15002
15082
  }
@@ -15072,9 +15152,9 @@ function applyUndo(hash, cwd) {
15072
15152
  timeout: GIT_TIMEOUT
15073
15153
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
15074
15154
  for (const file of [...tracked, ...untracked]) {
15075
- const fullPath = import_path26.default.join(dir, file);
15076
- if (!snapshotFiles.has(file) && import_fs24.default.existsSync(fullPath)) {
15077
- import_fs24.default.unlinkSync(fullPath);
15155
+ const fullPath = import_path27.default.join(dir, file);
15156
+ if (!snapshotFiles.has(file) && import_fs25.default.existsSync(fullPath)) {
15157
+ import_fs25.default.unlinkSync(fullPath);
15078
15158
  }
15079
15159
  }
15080
15160
  return true;
@@ -15087,12 +15167,12 @@ function applyUndo(hash, cwd) {
15087
15167
  init_daemon_starter();
15088
15168
 
15089
15169
  // src/skill-pin.ts
15090
- var import_fs25 = __toESM(require("fs"));
15091
- var import_path27 = __toESM(require("path"));
15170
+ var import_fs26 = __toESM(require("fs"));
15171
+ var import_path28 = __toESM(require("path"));
15092
15172
  var import_os22 = __toESM(require("os"));
15093
15173
  var import_crypto9 = __toESM(require("crypto"));
15094
15174
  function getPinsFilePath() {
15095
- return import_path27.default.join(import_os22.default.homedir(), ".node9", "skill-pins.json");
15175
+ return import_path28.default.join(import_os22.default.homedir(), ".node9", "skill-pins.json");
15096
15176
  }
15097
15177
  var MAX_FILES = 5e3;
15098
15178
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
@@ -15106,18 +15186,18 @@ function walkDir(root) {
15106
15186
  if (out.length >= MAX_FILES) return;
15107
15187
  let entries;
15108
15188
  try {
15109
- entries = import_fs25.default.readdirSync(dir, { withFileTypes: true });
15189
+ entries = import_fs26.default.readdirSync(dir, { withFileTypes: true });
15110
15190
  } catch {
15111
15191
  return;
15112
15192
  }
15113
15193
  entries.sort((a, b) => a.name.localeCompare(b.name));
15114
15194
  for (const entry of entries) {
15115
15195
  if (out.length >= MAX_FILES) return;
15116
- const full = import_path27.default.join(dir, entry.name);
15117
- const rel = relDir ? import_path27.default.posix.join(relDir, entry.name) : entry.name;
15196
+ const full = import_path28.default.join(dir, entry.name);
15197
+ const rel = relDir ? import_path28.default.posix.join(relDir, entry.name) : entry.name;
15118
15198
  let lst;
15119
15199
  try {
15120
- lst = import_fs25.default.lstatSync(full);
15200
+ lst = import_fs26.default.lstatSync(full);
15121
15201
  } catch {
15122
15202
  continue;
15123
15203
  }
@@ -15129,7 +15209,7 @@ function walkDir(root) {
15129
15209
  if (!lst.isFile()) continue;
15130
15210
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
15131
15211
  try {
15132
- const buf = import_fs25.default.readFileSync(full);
15212
+ const buf = import_fs26.default.readFileSync(full);
15133
15213
  totalBytes += buf.length;
15134
15214
  out.push({ rel, hash: sha256Bytes(buf) });
15135
15215
  } catch {
@@ -15143,14 +15223,14 @@ function walkDir(root) {
15143
15223
  function hashSkillRoot(absPath) {
15144
15224
  let lst;
15145
15225
  try {
15146
- lst = import_fs25.default.lstatSync(absPath);
15226
+ lst = import_fs26.default.lstatSync(absPath);
15147
15227
  } catch {
15148
15228
  return { exists: false, contentHash: "", fileCount: 0 };
15149
15229
  }
15150
15230
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
15151
15231
  if (lst.isFile()) {
15152
15232
  try {
15153
- return { exists: true, contentHash: sha256Bytes(import_fs25.default.readFileSync(absPath)), fileCount: 1 };
15233
+ return { exists: true, contentHash: sha256Bytes(import_fs26.default.readFileSync(absPath)), fileCount: 1 };
15154
15234
  } catch {
15155
15235
  return { exists: false, contentHash: "", fileCount: 0 };
15156
15236
  }
@@ -15168,7 +15248,7 @@ function getRootKey(absPath) {
15168
15248
  function readSkillPinsSafe() {
15169
15249
  const filePath = getPinsFilePath();
15170
15250
  try {
15171
- const raw = import_fs25.default.readFileSync(filePath, "utf-8");
15251
+ const raw = import_fs26.default.readFileSync(filePath, "utf-8");
15172
15252
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
15173
15253
  const parsed = JSON.parse(raw);
15174
15254
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -15188,10 +15268,10 @@ function readSkillPins() {
15188
15268
  }
15189
15269
  function writeSkillPins(data) {
15190
15270
  const filePath = getPinsFilePath();
15191
- import_fs25.default.mkdirSync(import_path27.default.dirname(filePath), { recursive: true });
15271
+ import_fs26.default.mkdirSync(import_path28.default.dirname(filePath), { recursive: true });
15192
15272
  const tmp = `${filePath}.${import_crypto9.default.randomBytes(6).toString("hex")}.tmp`;
15193
- import_fs25.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15194
- import_fs25.default.renameSync(tmp, filePath);
15273
+ import_fs26.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15274
+ import_fs26.default.renameSync(tmp, filePath);
15195
15275
  }
15196
15276
  function removePin(rootKey) {
15197
15277
  const pins = readSkillPins();
@@ -15235,36 +15315,36 @@ function verifyAndPinRoots(roots) {
15235
15315
  return { kind: "verified" };
15236
15316
  }
15237
15317
  function defaultSkillRoots(_cwd) {
15238
- const marketplaces = import_path27.default.join(import_os22.default.homedir(), ".claude", "plugins", "marketplaces");
15318
+ const marketplaces = import_path28.default.join(import_os22.default.homedir(), ".claude", "plugins", "marketplaces");
15239
15319
  const roots = [];
15240
15320
  let registries;
15241
15321
  try {
15242
- registries = import_fs25.default.readdirSync(marketplaces, { withFileTypes: true });
15322
+ registries = import_fs26.default.readdirSync(marketplaces, { withFileTypes: true });
15243
15323
  } catch {
15244
15324
  return [];
15245
15325
  }
15246
15326
  for (const registry of registries) {
15247
15327
  if (!registry.isDirectory()) continue;
15248
- const pluginsDir = import_path27.default.join(marketplaces, registry.name, "plugins");
15328
+ const pluginsDir = import_path28.default.join(marketplaces, registry.name, "plugins");
15249
15329
  let plugins;
15250
15330
  try {
15251
- plugins = import_fs25.default.readdirSync(pluginsDir, { withFileTypes: true });
15331
+ plugins = import_fs26.default.readdirSync(pluginsDir, { withFileTypes: true });
15252
15332
  } catch {
15253
15333
  continue;
15254
15334
  }
15255
15335
  for (const plugin of plugins) {
15256
15336
  if (!plugin.isDirectory()) continue;
15257
- roots.push(import_path27.default.join(pluginsDir, plugin.name));
15337
+ roots.push(import_path28.default.join(pluginsDir, plugin.name));
15258
15338
  }
15259
15339
  }
15260
15340
  return roots;
15261
15341
  }
15262
15342
  function resolveUserSkillRoot(entry, cwd) {
15263
15343
  if (!entry) return null;
15264
- if (entry.startsWith("~/") || entry === "~") return import_path27.default.join(import_os22.default.homedir(), entry.slice(1));
15265
- if (import_path27.default.isAbsolute(entry)) return entry;
15266
- if (!cwd || !import_path27.default.isAbsolute(cwd)) return null;
15267
- return import_path27.default.join(cwd, entry);
15344
+ if (entry.startsWith("~/") || entry === "~") return import_path28.default.join(import_os22.default.homedir(), entry.slice(1));
15345
+ if (import_path28.default.isAbsolute(entry)) return entry;
15346
+ if (!cwd || !import_path28.default.isAbsolute(cwd)) return null;
15347
+ return import_path28.default.join(cwd, entry);
15268
15348
  }
15269
15349
 
15270
15350
  // src/cli/commands/check.ts
@@ -15282,9 +15362,9 @@ function registerCheckCommand(program2) {
15282
15362
  } catch (err2) {
15283
15363
  const tempConfig = getConfig();
15284
15364
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
15285
- const logPath = import_path28.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15365
+ const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15286
15366
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
15287
- import_fs26.default.appendFileSync(
15367
+ import_fs27.default.appendFileSync(
15288
15368
  logPath,
15289
15369
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
15290
15370
  RAW: ${raw}
@@ -15297,11 +15377,11 @@ RAW: ${raw}
15297
15377
  if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
15298
15378
  try {
15299
15379
  const scriptPath = process.argv[1];
15300
- if (typeof scriptPath !== "string" || !import_path28.default.isAbsolute(scriptPath))
15380
+ if (typeof scriptPath !== "string" || !import_path29.default.isAbsolute(scriptPath))
15301
15381
  throw new Error("node9: argv[1] is not an absolute path");
15302
- const resolvedScript = import_fs26.default.realpathSync(scriptPath);
15303
- const packageDist = import_fs26.default.realpathSync(import_path28.default.resolve(__dirname, "../.."));
15304
- if (!resolvedScript.startsWith(packageDist + import_path28.default.sep) && resolvedScript !== packageDist)
15382
+ const resolvedScript = import_fs27.default.realpathSync(scriptPath);
15383
+ const packageDist = import_fs27.default.realpathSync(import_path29.default.resolve(__dirname, "../.."));
15384
+ if (!resolvedScript.startsWith(packageDist + import_path29.default.sep) && resolvedScript !== packageDist)
15305
15385
  throw new Error(
15306
15386
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
15307
15387
  );
@@ -15323,10 +15403,10 @@ RAW: ${raw}
15323
15403
  });
15324
15404
  d.unref();
15325
15405
  } catch (spawnErr) {
15326
- const logPath = import_path28.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15406
+ const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15327
15407
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
15328
15408
  try {
15329
- import_fs26.default.appendFileSync(
15409
+ import_fs27.default.appendFileSync(
15330
15410
  logPath,
15331
15411
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
15332
15412
  `
@@ -15336,10 +15416,10 @@ RAW: ${raw}
15336
15416
  }
15337
15417
  }
15338
15418
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
15339
- const logPath = import_path28.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15340
- if (!import_fs26.default.existsSync(import_path28.default.dirname(logPath)))
15341
- import_fs26.default.mkdirSync(import_path28.default.dirname(logPath), { recursive: true });
15342
- import_fs26.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
15419
+ const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15420
+ if (!import_fs27.default.existsSync(import_path29.default.dirname(logPath)))
15421
+ import_fs27.default.mkdirSync(import_path29.default.dirname(logPath), { recursive: true });
15422
+ import_fs27.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
15343
15423
  `);
15344
15424
  }
15345
15425
  const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
@@ -15352,8 +15432,8 @@ RAW: ${raw}
15352
15432
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
15353
15433
  let ttyFd = null;
15354
15434
  try {
15355
- ttyFd = import_fs26.default.openSync("/dev/tty", "w");
15356
- const writeTty = (line) => import_fs26.default.writeSync(ttyFd, line + "\n");
15435
+ ttyFd = import_fs27.default.openSync("/dev/tty", "w");
15436
+ const writeTty = (line) => import_fs27.default.writeSync(ttyFd, line + "\n");
15357
15437
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
15358
15438
  writeTty(import_chalk6.default.bgRed.white.bold(`
15359
15439
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -15372,7 +15452,7 @@ RAW: ${raw}
15372
15452
  } finally {
15373
15453
  if (ttyFd !== null)
15374
15454
  try {
15375
- import_fs26.default.closeSync(ttyFd);
15455
+ import_fs27.default.closeSync(ttyFd);
15376
15456
  } catch {
15377
15457
  }
15378
15458
  }
@@ -15406,17 +15486,17 @@ RAW: ${raw}
15406
15486
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
15407
15487
  if (skillPinCfg.enabled && safeSessionId) {
15408
15488
  try {
15409
- const sessionsDir = import_path28.default.join(import_os23.default.homedir(), ".node9", "skill-sessions");
15410
- const flagPath = import_path28.default.join(sessionsDir, `${safeSessionId}.json`);
15489
+ const sessionsDir = import_path29.default.join(import_os23.default.homedir(), ".node9", "skill-sessions");
15490
+ const flagPath = import_path29.default.join(sessionsDir, `${safeSessionId}.json`);
15411
15491
  let flag = null;
15412
15492
  try {
15413
- flag = JSON.parse(import_fs26.default.readFileSync(flagPath, "utf-8"));
15493
+ flag = JSON.parse(import_fs27.default.readFileSync(flagPath, "utf-8"));
15414
15494
  } catch {
15415
15495
  }
15416
15496
  const writeFlag = (data2) => {
15417
15497
  try {
15418
- import_fs26.default.mkdirSync(sessionsDir, { recursive: true });
15419
- import_fs26.default.writeFileSync(
15498
+ import_fs27.default.mkdirSync(sessionsDir, { recursive: true });
15499
+ import_fs27.default.writeFileSync(
15420
15500
  flagPath,
15421
15501
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
15422
15502
  { mode: 384 }
@@ -15427,8 +15507,8 @@ RAW: ${raw}
15427
15507
  const sendSkillWarn = (detail, recoveryCmd) => {
15428
15508
  let ttyFd = null;
15429
15509
  try {
15430
- ttyFd = import_fs26.default.openSync("/dev/tty", "w");
15431
- const w = (line) => import_fs26.default.writeSync(ttyFd, line + "\n");
15510
+ ttyFd = import_fs27.default.openSync("/dev/tty", "w");
15511
+ const w = (line) => import_fs27.default.writeSync(ttyFd, line + "\n");
15432
15512
  w(import_chalk6.default.yellow(`
15433
15513
  \u26A0\uFE0F Node9: installed skill drift detected`));
15434
15514
  w(import_chalk6.default.gray(` ${detail}`));
@@ -15443,7 +15523,7 @@ RAW: ${raw}
15443
15523
  } finally {
15444
15524
  if (ttyFd !== null)
15445
15525
  try {
15446
- import_fs26.default.closeSync(ttyFd);
15526
+ import_fs27.default.closeSync(ttyFd);
15447
15527
  } catch {
15448
15528
  }
15449
15529
  }
@@ -15459,7 +15539,7 @@ RAW: ${raw}
15459
15539
  return;
15460
15540
  }
15461
15541
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
15462
- const absoluteCwd = typeof payload.cwd === "string" && import_path28.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15542
+ const absoluteCwd = typeof payload.cwd === "string" && import_path29.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15463
15543
  const extraRoots = skillPinCfg.roots;
15464
15544
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
15465
15545
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -15500,10 +15580,10 @@ RAW: ${raw}
15500
15580
  }
15501
15581
  try {
15502
15582
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
15503
- for (const name of import_fs26.default.readdirSync(sessionsDir)) {
15504
- const p = import_path28.default.join(sessionsDir, name);
15583
+ for (const name of import_fs27.default.readdirSync(sessionsDir)) {
15584
+ const p = import_path29.default.join(sessionsDir, name);
15505
15585
  try {
15506
- if (import_fs26.default.statSync(p).mtimeMs < cutoff) import_fs26.default.unlinkSync(p);
15586
+ if (import_fs27.default.statSync(p).mtimeMs < cutoff) import_fs27.default.unlinkSync(p);
15507
15587
  } catch {
15508
15588
  }
15509
15589
  }
@@ -15513,9 +15593,9 @@ RAW: ${raw}
15513
15593
  } catch (err2) {
15514
15594
  if (process.env.NODE9_DEBUG === "1") {
15515
15595
  try {
15516
- const dbg = import_path28.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15596
+ const dbg = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15517
15597
  const msg = err2 instanceof Error ? err2.message : String(err2);
15518
- import_fs26.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
15598
+ import_fs27.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
15519
15599
  `);
15520
15600
  } catch {
15521
15601
  }
@@ -15525,7 +15605,7 @@ RAW: ${raw}
15525
15605
  if (shouldSnapshot(toolName, toolInput, config)) {
15526
15606
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
15527
15607
  }
15528
- const safeCwdForAuth = typeof payload.cwd === "string" && import_path28.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15608
+ const safeCwdForAuth = typeof payload.cwd === "string" && import_path29.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15529
15609
  const result = await authorizeHeadless(toolName, toolInput, meta, {
15530
15610
  cwd: safeCwdForAuth
15531
15611
  });
@@ -15537,12 +15617,12 @@ RAW: ${raw}
15537
15617
  }
15538
15618
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
15539
15619
  try {
15540
- const tty = import_fs26.default.openSync("/dev/tty", "w");
15541
- import_fs26.default.writeSync(
15620
+ const tty = import_fs27.default.openSync("/dev/tty", "w");
15621
+ import_fs27.default.writeSync(
15542
15622
  tty,
15543
15623
  import_chalk6.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
15544
15624
  );
15545
- import_fs26.default.closeSync(tty);
15625
+ import_fs27.default.closeSync(tty);
15546
15626
  } catch {
15547
15627
  }
15548
15628
  const daemonReady = await autoStartDaemonAndWait();
@@ -15569,9 +15649,9 @@ RAW: ${raw}
15569
15649
  });
15570
15650
  } catch (err2) {
15571
15651
  if (process.env.NODE9_DEBUG === "1") {
15572
- const logPath = import_path28.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15652
+ const logPath = import_path29.default.join(import_os23.default.homedir(), ".node9", "hook-debug.log");
15573
15653
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
15574
- import_fs26.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
15654
+ import_fs27.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
15575
15655
  `);
15576
15656
  }
15577
15657
  process.exit(0);
@@ -15605,8 +15685,8 @@ RAW: ${raw}
15605
15685
  }
15606
15686
 
15607
15687
  // src/cli/commands/log.ts
15608
- var import_fs27 = __toESM(require("fs"));
15609
- var import_path29 = __toESM(require("path"));
15688
+ var import_fs28 = __toESM(require("fs"));
15689
+ var import_path30 = __toESM(require("path"));
15610
15690
  var import_os24 = __toESM(require("os"));
15611
15691
  init_audit();
15612
15692
  init_config();
@@ -15682,10 +15762,10 @@ function registerLogCommand(program2) {
15682
15762
  decision: "allowed",
15683
15763
  source: "post-hook"
15684
15764
  };
15685
- const logPath = import_path29.default.join(import_os24.default.homedir(), ".node9", "audit.log");
15686
- if (!import_fs27.default.existsSync(import_path29.default.dirname(logPath)))
15687
- import_fs27.default.mkdirSync(import_path29.default.dirname(logPath), { recursive: true });
15688
- import_fs27.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
15765
+ const logPath = import_path30.default.join(import_os24.default.homedir(), ".node9", "audit.log");
15766
+ if (!import_fs28.default.existsSync(import_path30.default.dirname(logPath)))
15767
+ import_fs28.default.mkdirSync(import_path30.default.dirname(logPath), { recursive: true });
15768
+ import_fs28.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
15689
15769
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
15690
15770
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
15691
15771
  if (command) {
@@ -15718,7 +15798,7 @@ function registerLogCommand(program2) {
15718
15798
  }
15719
15799
  }
15720
15800
  }
15721
- const safeCwd = typeof payload.cwd === "string" && import_path29.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15801
+ const safeCwd = typeof payload.cwd === "string" && import_path30.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15722
15802
  const config = getConfig(safeCwd);
15723
15803
  if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
15724
15804
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
@@ -15739,9 +15819,9 @@ function registerLogCommand(program2) {
15739
15819
  const msg = err2 instanceof Error ? err2.message : String(err2);
15740
15820
  process.stderr.write(`[Node9] audit log error: ${msg}
15741
15821
  `);
15742
- const debugPath = import_path29.default.join(import_os24.default.homedir(), ".node9", "hook-debug.log");
15822
+ const debugPath = import_path30.default.join(import_os24.default.homedir(), ".node9", "hook-debug.log");
15743
15823
  try {
15744
- import_fs27.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
15824
+ import_fs28.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
15745
15825
  `);
15746
15826
  } catch {
15747
15827
  }
@@ -16141,8 +16221,8 @@ function registerConfigShowCommand(program2) {
16141
16221
 
16142
16222
  // src/cli/commands/doctor.ts
16143
16223
  var import_chalk8 = __toESM(require("chalk"));
16144
- var import_fs28 = __toESM(require("fs"));
16145
- var import_path30 = __toESM(require("path"));
16224
+ var import_fs29 = __toESM(require("fs"));
16225
+ var import_path31 = __toESM(require("path"));
16146
16226
  var import_os25 = __toESM(require("os"));
16147
16227
  var import_child_process11 = require("child_process");
16148
16228
  init_daemon();
@@ -16197,10 +16277,10 @@ function registerDoctorCommand(program2, version2) {
16197
16277
  );
16198
16278
  }
16199
16279
  section("Configuration");
16200
- const globalConfigPath = import_path30.default.join(homeDir2, ".node9", "config.json");
16201
- if (import_fs28.default.existsSync(globalConfigPath)) {
16280
+ const globalConfigPath = import_path31.default.join(homeDir2, ".node9", "config.json");
16281
+ if (import_fs29.default.existsSync(globalConfigPath)) {
16202
16282
  try {
16203
- JSON.parse(import_fs28.default.readFileSync(globalConfigPath, "utf-8"));
16283
+ JSON.parse(import_fs29.default.readFileSync(globalConfigPath, "utf-8"));
16204
16284
  pass("~/.node9/config.json found and valid");
16205
16285
  } catch {
16206
16286
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -16208,10 +16288,10 @@ function registerDoctorCommand(program2, version2) {
16208
16288
  } else {
16209
16289
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
16210
16290
  }
16211
- const projectConfigPath = import_path30.default.join(process.cwd(), "node9.config.json");
16212
- if (import_fs28.default.existsSync(projectConfigPath)) {
16291
+ const projectConfigPath = import_path31.default.join(process.cwd(), "node9.config.json");
16292
+ if (import_fs29.default.existsSync(projectConfigPath)) {
16213
16293
  try {
16214
- JSON.parse(import_fs28.default.readFileSync(projectConfigPath, "utf-8"));
16294
+ JSON.parse(import_fs29.default.readFileSync(projectConfigPath, "utf-8"));
16215
16295
  pass("node9.config.json found and valid (project)");
16216
16296
  } catch {
16217
16297
  fail(
@@ -16220,8 +16300,8 @@ function registerDoctorCommand(program2, version2) {
16220
16300
  );
16221
16301
  }
16222
16302
  }
16223
- const credsPath = import_path30.default.join(homeDir2, ".node9", "credentials.json");
16224
- if (import_fs28.default.existsSync(credsPath)) {
16303
+ const credsPath = import_path31.default.join(homeDir2, ".node9", "credentials.json");
16304
+ if (import_fs29.default.existsSync(credsPath)) {
16225
16305
  pass("Cloud credentials found (~/.node9/credentials.json)");
16226
16306
  } else {
16227
16307
  warn(
@@ -16230,10 +16310,10 @@ function registerDoctorCommand(program2, version2) {
16230
16310
  );
16231
16311
  }
16232
16312
  section("Agent Hooks");
16233
- const claudeSettingsPath = import_path30.default.join(homeDir2, ".claude", "settings.json");
16234
- if (import_fs28.default.existsSync(claudeSettingsPath)) {
16313
+ const claudeSettingsPath = import_path31.default.join(homeDir2, ".claude", "settings.json");
16314
+ if (import_fs29.default.existsSync(claudeSettingsPath)) {
16235
16315
  try {
16236
- const cs = JSON.parse(import_fs28.default.readFileSync(claudeSettingsPath, "utf-8"));
16316
+ const cs = JSON.parse(import_fs29.default.readFileSync(claudeSettingsPath, "utf-8"));
16237
16317
  const hasHook = cs.hooks?.PreToolUse?.some(
16238
16318
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16239
16319
  );
@@ -16249,10 +16329,10 @@ function registerDoctorCommand(program2, version2) {
16249
16329
  } else {
16250
16330
  warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
16251
16331
  }
16252
- const geminiSettingsPath = import_path30.default.join(homeDir2, ".gemini", "settings.json");
16253
- if (import_fs28.default.existsSync(geminiSettingsPath)) {
16332
+ const geminiSettingsPath = import_path31.default.join(homeDir2, ".gemini", "settings.json");
16333
+ if (import_fs29.default.existsSync(geminiSettingsPath)) {
16254
16334
  try {
16255
- const gs = JSON.parse(import_fs28.default.readFileSync(geminiSettingsPath, "utf-8"));
16335
+ const gs = JSON.parse(import_fs29.default.readFileSync(geminiSettingsPath, "utf-8"));
16256
16336
  const hasHook = gs.hooks?.BeforeTool?.some(
16257
16337
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16258
16338
  );
@@ -16268,10 +16348,10 @@ function registerDoctorCommand(program2, version2) {
16268
16348
  } else {
16269
16349
  warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
16270
16350
  }
16271
- const cursorHooksPath = import_path30.default.join(homeDir2, ".cursor", "hooks.json");
16272
- if (import_fs28.default.existsSync(cursorHooksPath)) {
16351
+ const cursorHooksPath = import_path31.default.join(homeDir2, ".cursor", "hooks.json");
16352
+ if (import_fs29.default.existsSync(cursorHooksPath)) {
16273
16353
  try {
16274
- const cur = JSON.parse(import_fs28.default.readFileSync(cursorHooksPath, "utf-8"));
16354
+ const cur = JSON.parse(import_fs29.default.readFileSync(cursorHooksPath, "utf-8"));
16275
16355
  const hasHook = cur.hooks?.preToolUse?.some(
16276
16356
  (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
16277
16357
  );
@@ -16309,8 +16389,8 @@ function registerDoctorCommand(program2, version2) {
16309
16389
 
16310
16390
  // src/cli/commands/audit.ts
16311
16391
  var import_chalk9 = __toESM(require("chalk"));
16312
- var import_fs29 = __toESM(require("fs"));
16313
- var import_path31 = __toESM(require("path"));
16392
+ var import_fs30 = __toESM(require("fs"));
16393
+ var import_path32 = __toESM(require("path"));
16314
16394
  var import_os26 = __toESM(require("os"));
16315
16395
  function formatRelativeTime(timestamp) {
16316
16396
  const diff = Date.now() - new Date(timestamp).getTime();
@@ -16324,14 +16404,14 @@ function formatRelativeTime(timestamp) {
16324
16404
  }
16325
16405
  function registerAuditCommand(program2) {
16326
16406
  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) => {
16327
- const logPath = import_path31.default.join(import_os26.default.homedir(), ".node9", "audit.log");
16328
- if (!import_fs29.default.existsSync(logPath)) {
16407
+ const logPath = import_path32.default.join(import_os26.default.homedir(), ".node9", "audit.log");
16408
+ if (!import_fs30.default.existsSync(logPath)) {
16329
16409
  console.log(
16330
16410
  import_chalk9.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
16331
16411
  );
16332
16412
  return;
16333
16413
  }
16334
- const raw = import_fs29.default.readFileSync(logPath, "utf-8");
16414
+ const raw = import_fs30.default.readFileSync(logPath, "utf-8");
16335
16415
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
16336
16416
  let entries = lines.flatMap((line) => {
16337
16417
  try {
@@ -16385,8 +16465,8 @@ function registerAuditCommand(program2) {
16385
16465
 
16386
16466
  // src/cli/commands/report.ts
16387
16467
  var import_chalk10 = __toESM(require("chalk"));
16388
- var import_fs30 = __toESM(require("fs"));
16389
- var import_path32 = __toESM(require("path"));
16468
+ var import_fs31 = __toESM(require("fs"));
16469
+ var import_path33 = __toESM(require("path"));
16390
16470
  var import_os27 = __toESM(require("os"));
16391
16471
  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;
16392
16472
  function buildTestTimestamps(allEntries) {
@@ -16434,8 +16514,8 @@ function getDateRange(period) {
16434
16514
  }
16435
16515
  }
16436
16516
  function parseAuditLog(logPath) {
16437
- if (!import_fs30.default.existsSync(logPath)) return [];
16438
- const raw = import_fs30.default.readFileSync(logPath, "utf-8");
16517
+ if (!import_fs31.default.existsSync(logPath)) return [];
16518
+ const raw = import_fs31.default.readFileSync(logPath, "utf-8");
16439
16519
  return raw.split("\n").flatMap((line) => {
16440
16520
  if (!line.trim()) return [];
16441
16521
  try {
@@ -16514,11 +16594,11 @@ function loadClaudeCost(start, end) {
16514
16594
  cacheWriteTokens: 0,
16515
16595
  cacheReadTokens: 0
16516
16596
  };
16517
- const projectsDir = import_path32.default.join(import_os27.default.homedir(), ".claude", "projects");
16518
- if (!import_fs30.default.existsSync(projectsDir)) return empty;
16597
+ const projectsDir = import_path33.default.join(import_os27.default.homedir(), ".claude", "projects");
16598
+ if (!import_fs31.default.existsSync(projectsDir)) return empty;
16519
16599
  let dirs;
16520
16600
  try {
16521
- dirs = import_fs30.default.readdirSync(projectsDir);
16601
+ dirs = import_fs31.default.readdirSync(projectsDir);
16522
16602
  } catch {
16523
16603
  return empty;
16524
16604
  }
@@ -16530,18 +16610,18 @@ function loadClaudeCost(start, end) {
16530
16610
  const byDay = /* @__PURE__ */ new Map();
16531
16611
  const byModel = /* @__PURE__ */ new Map();
16532
16612
  for (const proj of dirs) {
16533
- const projPath = import_path32.default.join(projectsDir, proj);
16613
+ const projPath = import_path33.default.join(projectsDir, proj);
16534
16614
  let files;
16535
16615
  try {
16536
- const stat = import_fs30.default.statSync(projPath);
16616
+ const stat = import_fs31.default.statSync(projPath);
16537
16617
  if (!stat.isDirectory()) continue;
16538
- files = import_fs30.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
16618
+ files = import_fs31.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
16539
16619
  } catch {
16540
16620
  continue;
16541
16621
  }
16542
16622
  for (const file of files) {
16543
16623
  try {
16544
- const raw = import_fs30.default.readFileSync(import_path32.default.join(projPath, file), "utf-8");
16624
+ const raw = import_fs31.default.readFileSync(import_path33.default.join(projPath, file), "utf-8");
16545
16625
  for (const line of raw.split("\n")) {
16546
16626
  if (!line.trim()) continue;
16547
16627
  let entry;
@@ -16582,36 +16662,36 @@ function loadClaudeCost(start, end) {
16582
16662
  return { total, byDay, byModel, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens };
16583
16663
  }
16584
16664
  function loadCodexCost(start, end) {
16585
- const sessionsBase = import_path32.default.join(import_os27.default.homedir(), ".codex", "sessions");
16665
+ const sessionsBase = import_path33.default.join(import_os27.default.homedir(), ".codex", "sessions");
16586
16666
  const byDay = /* @__PURE__ */ new Map();
16587
16667
  let total = 0;
16588
16668
  let toolCalls = 0;
16589
- if (!import_fs30.default.existsSync(sessionsBase)) return { total, byDay, toolCalls };
16669
+ if (!import_fs31.default.existsSync(sessionsBase)) return { total, byDay, toolCalls };
16590
16670
  const jsonlFiles = [];
16591
16671
  try {
16592
- for (const year of import_fs30.default.readdirSync(sessionsBase)) {
16593
- const yearPath = import_path32.default.join(sessionsBase, year);
16672
+ for (const year of import_fs31.default.readdirSync(sessionsBase)) {
16673
+ const yearPath = import_path33.default.join(sessionsBase, year);
16594
16674
  try {
16595
- if (!import_fs30.default.statSync(yearPath).isDirectory()) continue;
16675
+ if (!import_fs31.default.statSync(yearPath).isDirectory()) continue;
16596
16676
  } catch {
16597
16677
  continue;
16598
16678
  }
16599
- for (const month of import_fs30.default.readdirSync(yearPath)) {
16600
- const monthPath = import_path32.default.join(yearPath, month);
16679
+ for (const month of import_fs31.default.readdirSync(yearPath)) {
16680
+ const monthPath = import_path33.default.join(yearPath, month);
16601
16681
  try {
16602
- if (!import_fs30.default.statSync(monthPath).isDirectory()) continue;
16682
+ if (!import_fs31.default.statSync(monthPath).isDirectory()) continue;
16603
16683
  } catch {
16604
16684
  continue;
16605
16685
  }
16606
- for (const day of import_fs30.default.readdirSync(monthPath)) {
16607
- const dayPath = import_path32.default.join(monthPath, day);
16686
+ for (const day of import_fs31.default.readdirSync(monthPath)) {
16687
+ const dayPath = import_path33.default.join(monthPath, day);
16608
16688
  try {
16609
- if (!import_fs30.default.statSync(dayPath).isDirectory()) continue;
16689
+ if (!import_fs31.default.statSync(dayPath).isDirectory()) continue;
16610
16690
  } catch {
16611
16691
  continue;
16612
16692
  }
16613
- for (const file of import_fs30.default.readdirSync(dayPath)) {
16614
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path32.default.join(dayPath, file));
16693
+ for (const file of import_fs31.default.readdirSync(dayPath)) {
16694
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path33.default.join(dayPath, file));
16615
16695
  }
16616
16696
  }
16617
16697
  }
@@ -16622,7 +16702,7 @@ function loadCodexCost(start, end) {
16622
16702
  for (const filePath of jsonlFiles) {
16623
16703
  let lines;
16624
16704
  try {
16625
- lines = import_fs30.default.readFileSync(filePath, "utf-8").split("\n");
16705
+ lines = import_fs31.default.readFileSync(filePath, "utf-8").split("\n");
16626
16706
  } catch {
16627
16707
  continue;
16628
16708
  }
@@ -16672,7 +16752,7 @@ function registerReportCommand(program2) {
16672
16752
  const period = ["today", "7d", "30d", "month"].includes(
16673
16753
  options.period
16674
16754
  ) ? options.period : "7d";
16675
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "audit.log");
16755
+ const logPath = import_path33.default.join(import_os27.default.homedir(), ".node9", "audit.log");
16676
16756
  const allEntries = parseAuditLog(logPath);
16677
16757
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
16678
16758
  if (unackedDlp.length > 0) {
@@ -17177,14 +17257,14 @@ function registerDaemonCommand(program2) {
17177
17257
 
17178
17258
  // src/cli/commands/status.ts
17179
17259
  var import_chalk12 = __toESM(require("chalk"));
17180
- var import_fs31 = __toESM(require("fs"));
17181
- var import_path33 = __toESM(require("path"));
17260
+ var import_fs32 = __toESM(require("fs"));
17261
+ var import_path34 = __toESM(require("path"));
17182
17262
  var import_os28 = __toESM(require("os"));
17183
17263
  init_core();
17184
17264
  init_daemon();
17185
17265
  function readJson2(filePath) {
17186
17266
  try {
17187
- if (import_fs31.default.existsSync(filePath)) return JSON.parse(import_fs31.default.readFileSync(filePath, "utf-8"));
17267
+ if (import_fs32.default.existsSync(filePath)) return JSON.parse(import_fs32.default.readFileSync(filePath, "utf-8"));
17188
17268
  } catch {
17189
17269
  }
17190
17270
  return null;
@@ -17249,13 +17329,13 @@ function registerStatusCommand(program2) {
17249
17329
  console.log("");
17250
17330
  const modeLabel = settings.mode === "audit" ? import_chalk12.default.blue("audit") : settings.mode === "strict" ? import_chalk12.default.red("strict") : import_chalk12.default.white("standard");
17251
17331
  console.log(` Mode: ${modeLabel}`);
17252
- const projectConfig = import_path33.default.join(process.cwd(), "node9.config.json");
17253
- const globalConfig = import_path33.default.join(import_os28.default.homedir(), ".node9", "config.json");
17332
+ const projectConfig = import_path34.default.join(process.cwd(), "node9.config.json");
17333
+ const globalConfig = import_path34.default.join(import_os28.default.homedir(), ".node9", "config.json");
17254
17334
  console.log(
17255
- ` Local: ${import_fs31.default.existsSync(projectConfig) ? import_chalk12.default.green("Active (node9.config.json)") : import_chalk12.default.gray("Not present")}`
17335
+ ` Local: ${import_fs32.default.existsSync(projectConfig) ? import_chalk12.default.green("Active (node9.config.json)") : import_chalk12.default.gray("Not present")}`
17256
17336
  );
17257
17337
  console.log(
17258
- ` Global: ${import_fs31.default.existsSync(globalConfig) ? import_chalk12.default.green("Active (~/.node9/config.json)") : import_chalk12.default.gray("Not present")}`
17338
+ ` Global: ${import_fs32.default.existsSync(globalConfig) ? import_chalk12.default.green("Active (~/.node9/config.json)") : import_chalk12.default.gray("Not present")}`
17259
17339
  );
17260
17340
  if (mergedConfig.policy.sandboxPaths.length > 0) {
17261
17341
  console.log(
@@ -17264,13 +17344,13 @@ function registerStatusCommand(program2) {
17264
17344
  }
17265
17345
  const homeDir2 = import_os28.default.homedir();
17266
17346
  const claudeSettings = readJson2(
17267
- import_path33.default.join(homeDir2, ".claude", "settings.json")
17347
+ import_path34.default.join(homeDir2, ".claude", "settings.json")
17268
17348
  );
17269
- const claudeConfig = readJson2(import_path33.default.join(homeDir2, ".claude.json"));
17349
+ const claudeConfig = readJson2(import_path34.default.join(homeDir2, ".claude.json"));
17270
17350
  const geminiSettings = readJson2(
17271
- import_path33.default.join(homeDir2, ".gemini", "settings.json")
17351
+ import_path34.default.join(homeDir2, ".gemini", "settings.json")
17272
17352
  );
17273
- const cursorConfig = readJson2(import_path33.default.join(homeDir2, ".cursor", "mcp.json"));
17353
+ const cursorConfig = readJson2(import_path34.default.join(homeDir2, ".cursor", "mcp.json"));
17274
17354
  const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
17275
17355
  if (agentFound) {
17276
17356
  console.log("");
@@ -17329,8 +17409,8 @@ function registerStatusCommand(program2) {
17329
17409
 
17330
17410
  // src/cli/commands/init.ts
17331
17411
  var import_chalk13 = __toESM(require("chalk"));
17332
- var import_fs32 = __toESM(require("fs"));
17333
- var import_path34 = __toESM(require("path"));
17412
+ var import_fs33 = __toESM(require("fs"));
17413
+ var import_path35 = __toESM(require("path"));
17334
17414
  var import_os29 = __toESM(require("os"));
17335
17415
  var import_https3 = __toESM(require("https"));
17336
17416
  init_core();
@@ -17392,15 +17472,15 @@ function registerInitCommand(program2) {
17392
17472
  }
17393
17473
  console.log("");
17394
17474
  }
17395
- const configPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "config.json");
17396
- if (import_fs32.default.existsSync(configPath) && !options.force) {
17475
+ const configPath = import_path35.default.join(import_os29.default.homedir(), ".node9", "config.json");
17476
+ if (import_fs33.default.existsSync(configPath) && !options.force) {
17397
17477
  try {
17398
- const existing = JSON.parse(import_fs32.default.readFileSync(configPath, "utf-8"));
17478
+ const existing = JSON.parse(import_fs33.default.readFileSync(configPath, "utf-8"));
17399
17479
  const settings = existing.settings ?? {};
17400
17480
  if (settings.mode !== chosenMode) {
17401
17481
  settings.mode = chosenMode;
17402
17482
  existing.settings = settings;
17403
- import_fs32.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
17483
+ import_fs33.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
17404
17484
  console.log(import_chalk13.default.green(`\u2705 Mode updated: ${chosenMode}`));
17405
17485
  } else {
17406
17486
  console.log(import_chalk13.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -17413,9 +17493,9 @@ function registerInitCommand(program2) {
17413
17493
  ...DEFAULT_CONFIG,
17414
17494
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
17415
17495
  };
17416
- const dir = import_path34.default.dirname(configPath);
17417
- if (!import_fs32.default.existsSync(dir)) import_fs32.default.mkdirSync(dir, { recursive: true });
17418
- import_fs32.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
17496
+ const dir = import_path35.default.dirname(configPath);
17497
+ if (!import_fs33.default.existsSync(dir)) import_fs33.default.mkdirSync(dir, { recursive: true });
17498
+ import_fs33.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
17419
17499
  console.log(import_chalk13.default.green(`\u2705 Config created: ${configPath}`));
17420
17500
  console.log(import_chalk13.default.gray(` Mode: ${chosenMode}`));
17421
17501
  }
@@ -17500,7 +17580,7 @@ function registerInitCommand(program2) {
17500
17580
  }
17501
17581
 
17502
17582
  // src/cli/commands/undo.ts
17503
- var import_path35 = __toESM(require("path"));
17583
+ var import_path36 = __toESM(require("path"));
17504
17584
  var import_chalk15 = __toESM(require("chalk"));
17505
17585
 
17506
17586
  // src/tui/undo-navigator.ts
@@ -17659,7 +17739,7 @@ function findMatchingCwd(startDir, history) {
17659
17739
  let dir = startDir;
17660
17740
  while (true) {
17661
17741
  if (cwds.has(dir)) return dir;
17662
- const parent = import_path35.default.dirname(dir);
17742
+ const parent = import_path36.default.dirname(dir);
17663
17743
  if (parent === dir) return null;
17664
17744
  dir = parent;
17665
17745
  }
@@ -17855,12 +17935,12 @@ init_orchestrator();
17855
17935
  init_provenance();
17856
17936
 
17857
17937
  // src/mcp-pin.ts
17858
- var import_fs33 = __toESM(require("fs"));
17859
- var import_path36 = __toESM(require("path"));
17938
+ var import_fs34 = __toESM(require("fs"));
17939
+ var import_path37 = __toESM(require("path"));
17860
17940
  var import_os30 = __toESM(require("os"));
17861
17941
  var import_crypto10 = __toESM(require("crypto"));
17862
17942
  function getPinsFilePath2() {
17863
- return import_path36.default.join(import_os30.default.homedir(), ".node9", "mcp-pins.json");
17943
+ return import_path37.default.join(import_os30.default.homedir(), ".node9", "mcp-pins.json");
17864
17944
  }
17865
17945
  function hashToolDefinitions(tools) {
17866
17946
  const sorted = [...tools].sort((a, b) => {
@@ -17877,7 +17957,7 @@ function getServerKey(upstreamCommand) {
17877
17957
  function readMcpPinsSafe() {
17878
17958
  const filePath = getPinsFilePath2();
17879
17959
  try {
17880
- const raw = import_fs33.default.readFileSync(filePath, "utf-8");
17960
+ const raw = import_fs34.default.readFileSync(filePath, "utf-8");
17881
17961
  if (!raw.trim()) {
17882
17962
  return { ok: false, reason: "corrupt", detail: "empty file" };
17883
17963
  }
@@ -17901,10 +17981,10 @@ function readMcpPins() {
17901
17981
  }
17902
17982
  function writeMcpPins(data) {
17903
17983
  const filePath = getPinsFilePath2();
17904
- import_fs33.default.mkdirSync(import_path36.default.dirname(filePath), { recursive: true });
17984
+ import_fs34.default.mkdirSync(import_path37.default.dirname(filePath), { recursive: true });
17905
17985
  const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
17906
- import_fs33.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
17907
- import_fs33.default.renameSync(tmp, filePath);
17986
+ import_fs34.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
17987
+ import_fs34.default.renameSync(tmp, filePath);
17908
17988
  }
17909
17989
  function checkPin(serverKey, currentHash) {
17910
17990
  const result = readMcpPinsSafe();
@@ -18352,9 +18432,9 @@ function registerMcpGatewayCommand(program2) {
18352
18432
 
18353
18433
  // src/mcp-server/index.ts
18354
18434
  var import_readline4 = __toESM(require("readline"));
18355
- var import_fs34 = __toESM(require("fs"));
18435
+ var import_fs35 = __toESM(require("fs"));
18356
18436
  var import_os31 = __toESM(require("os"));
18357
- var import_path37 = __toESM(require("path"));
18437
+ var import_path38 = __toESM(require("path"));
18358
18438
  var import_child_process15 = require("child_process");
18359
18439
  init_core();
18360
18440
  init_daemon();
@@ -18605,13 +18685,13 @@ function handleStatus() {
18605
18685
  lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
18606
18686
  lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
18607
18687
  lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
18608
- const projectConfig = import_path37.default.join(process.cwd(), "node9.config.json");
18609
- const globalConfig = import_path37.default.join(import_os31.default.homedir(), ".node9", "config.json");
18688
+ const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
18689
+ const globalConfig = import_path38.default.join(import_os31.default.homedir(), ".node9", "config.json");
18610
18690
  lines.push(
18611
- `Project config (node9.config.json): ${import_fs34.default.existsSync(projectConfig) ? "present" : "not found"}`
18691
+ `Project config (node9.config.json): ${import_fs35.default.existsSync(projectConfig) ? "present" : "not found"}`
18612
18692
  );
18613
18693
  lines.push(
18614
- `Global config (~/.node9/config.json): ${import_fs34.default.existsSync(globalConfig) ? "present" : "not found"}`
18694
+ `Global config (~/.node9/config.json): ${import_fs35.default.existsSync(globalConfig) ? "present" : "not found"}`
18615
18695
  );
18616
18696
  return lines.join("\n");
18617
18697
  }
@@ -18685,21 +18765,21 @@ function handleShieldDisable(args) {
18685
18765
  writeActiveShields(active.filter((s) => s !== name));
18686
18766
  return `Shield "${name}" disabled.`;
18687
18767
  }
18688
- var GLOBAL_CONFIG_PATH2 = import_path37.default.join(import_os31.default.homedir(), ".node9", "config.json");
18768
+ var GLOBAL_CONFIG_PATH2 = import_path38.default.join(import_os31.default.homedir(), ".node9", "config.json");
18689
18769
  var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
18690
18770
  function readGlobalConfigRaw() {
18691
18771
  try {
18692
- if (import_fs34.default.existsSync(GLOBAL_CONFIG_PATH2)) {
18693
- return JSON.parse(import_fs34.default.readFileSync(GLOBAL_CONFIG_PATH2, "utf-8"));
18772
+ if (import_fs35.default.existsSync(GLOBAL_CONFIG_PATH2)) {
18773
+ return JSON.parse(import_fs35.default.readFileSync(GLOBAL_CONFIG_PATH2, "utf-8"));
18694
18774
  }
18695
18775
  } catch {
18696
18776
  }
18697
18777
  return {};
18698
18778
  }
18699
18779
  function writeGlobalConfigRaw(data) {
18700
- const dir = import_path37.default.dirname(GLOBAL_CONFIG_PATH2);
18701
- if (!import_fs34.default.existsSync(dir)) import_fs34.default.mkdirSync(dir, { recursive: true });
18702
- import_fs34.default.writeFileSync(GLOBAL_CONFIG_PATH2, JSON.stringify(data, null, 2) + "\n");
18780
+ const dir = import_path38.default.dirname(GLOBAL_CONFIG_PATH2);
18781
+ if (!import_fs35.default.existsSync(dir)) import_fs35.default.mkdirSync(dir, { recursive: true });
18782
+ import_fs35.default.writeFileSync(GLOBAL_CONFIG_PATH2, JSON.stringify(data, null, 2) + "\n");
18703
18783
  }
18704
18784
  function handleApproverList() {
18705
18785
  const config = getConfig();
@@ -18743,9 +18823,9 @@ function handleApproverSet(args) {
18743
18823
  function handleAuditGet(args) {
18744
18824
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
18745
18825
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
18746
- const auditPath = import_path37.default.join(import_os31.default.homedir(), ".node9", "audit.log");
18747
- if (!import_fs34.default.existsSync(auditPath)) return "No audit log found.";
18748
- const rawLines = import_fs34.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
18826
+ const auditPath = import_path38.default.join(import_os31.default.homedir(), ".node9", "audit.log");
18827
+ if (!import_fs35.default.existsSync(auditPath)) return "No audit log found.";
18828
+ const rawLines = import_fs35.default.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
18749
18829
  const parsed = [];
18750
18830
  for (const line of rawLines) {
18751
18831
  try {
@@ -19299,8 +19379,8 @@ init_scan();
19299
19379
 
19300
19380
  // src/cli/commands/sessions.ts
19301
19381
  var import_chalk22 = __toESM(require("chalk"));
19302
- var import_fs35 = __toESM(require("fs"));
19303
- var import_path38 = __toESM(require("path"));
19382
+ var import_fs36 = __toESM(require("fs"));
19383
+ var import_path39 = __toESM(require("path"));
19304
19384
  var import_os32 = __toESM(require("os"));
19305
19385
  var CLAUDE_PRICING3 = {
19306
19386
  "claude-opus-4-6": { i: 5e-6, o: 25e-6, cw: 625e-8, cr: 5e-7 },
@@ -19342,7 +19422,7 @@ function encodeProjectPath(projectPath) {
19342
19422
  }
19343
19423
  function sessionJsonlPath(projectPath, sessionId) {
19344
19424
  const encoded = encodeProjectPath(projectPath);
19345
- return import_path38.default.join(import_os32.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
19425
+ return import_path39.default.join(import_os32.default.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
19346
19426
  }
19347
19427
  function projectLabel(projectPath) {
19348
19428
  return projectPath.replace(import_os32.default.homedir(), "~");
@@ -19414,10 +19494,10 @@ function parseSessionLines(lines) {
19414
19494
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
19415
19495
  }
19416
19496
  function loadAuditEntries(auditPath) {
19417
- const aPath = auditPath ?? import_path38.default.join(import_os32.default.homedir(), ".node9", "audit.log");
19497
+ const aPath = auditPath ?? import_path39.default.join(import_os32.default.homedir(), ".node9", "audit.log");
19418
19498
  let raw;
19419
19499
  try {
19420
- raw = import_fs35.default.readFileSync(aPath, "utf-8");
19500
+ raw = import_fs36.default.readFileSync(aPath, "utf-8");
19421
19501
  } catch {
19422
19502
  return [];
19423
19503
  }
@@ -19453,8 +19533,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
19453
19533
  return result;
19454
19534
  }
19455
19535
  function buildGeminiSessions(days, allAuditEntries) {
19456
- const tmpDir = import_path38.default.join(import_os32.default.homedir(), ".gemini", "tmp");
19457
- if (!import_fs35.default.existsSync(tmpDir)) return [];
19536
+ const tmpDir = import_path39.default.join(import_os32.default.homedir(), ".gemini", "tmp");
19537
+ if (!import_fs36.default.existsSync(tmpDir)) return [];
19458
19538
  const cutoff = days !== null ? (() => {
19459
19539
  const d = /* @__PURE__ */ new Date();
19460
19540
  d.setDate(d.getDate() - days);
@@ -19463,35 +19543,35 @@ function buildGeminiSessions(days, allAuditEntries) {
19463
19543
  })() : null;
19464
19544
  let slugDirs;
19465
19545
  try {
19466
- slugDirs = import_fs35.default.readdirSync(tmpDir);
19546
+ slugDirs = import_fs36.default.readdirSync(tmpDir);
19467
19547
  } catch {
19468
19548
  return [];
19469
19549
  }
19470
19550
  const summaries = [];
19471
19551
  for (const slug of slugDirs) {
19472
- const slugPath = import_path38.default.join(tmpDir, slug);
19552
+ const slugPath = import_path39.default.join(tmpDir, slug);
19473
19553
  try {
19474
- if (!import_fs35.default.statSync(slugPath).isDirectory()) continue;
19554
+ if (!import_fs36.default.statSync(slugPath).isDirectory()) continue;
19475
19555
  } catch {
19476
19556
  continue;
19477
19557
  }
19478
- let projectRoot = import_path38.default.join(import_os32.default.homedir(), slug);
19558
+ let projectRoot = import_path39.default.join(import_os32.default.homedir(), slug);
19479
19559
  try {
19480
- projectRoot = import_fs35.default.readFileSync(import_path38.default.join(slugPath, ".project_root"), "utf-8").trim();
19560
+ projectRoot = import_fs36.default.readFileSync(import_path39.default.join(slugPath, ".project_root"), "utf-8").trim();
19481
19561
  } catch {
19482
19562
  }
19483
- const chatsDir = import_path38.default.join(slugPath, "chats");
19484
- if (!import_fs35.default.existsSync(chatsDir)) continue;
19563
+ const chatsDir = import_path39.default.join(slugPath, "chats");
19564
+ if (!import_fs36.default.existsSync(chatsDir)) continue;
19485
19565
  let chatFiles;
19486
19566
  try {
19487
- chatFiles = import_fs35.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
19567
+ chatFiles = import_fs36.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
19488
19568
  } catch {
19489
19569
  continue;
19490
19570
  }
19491
19571
  for (const chatFile of chatFiles) {
19492
19572
  let raw;
19493
19573
  try {
19494
- raw = import_fs35.default.readFileSync(import_path38.default.join(chatsDir, chatFile), "utf-8");
19574
+ raw = import_fs36.default.readFileSync(import_path39.default.join(chatsDir, chatFile), "utf-8");
19495
19575
  } catch {
19496
19576
  continue;
19497
19577
  }
@@ -19571,8 +19651,8 @@ function buildGeminiSessions(days, allAuditEntries) {
19571
19651
  return summaries;
19572
19652
  }
19573
19653
  function buildCodexSessions(days, allAuditEntries) {
19574
- const sessionsBase = import_path38.default.join(import_os32.default.homedir(), ".codex", "sessions");
19575
- if (!import_fs35.default.existsSync(sessionsBase)) return [];
19654
+ const sessionsBase = import_path39.default.join(import_os32.default.homedir(), ".codex", "sessions");
19655
+ if (!import_fs36.default.existsSync(sessionsBase)) return [];
19576
19656
  const cutoff = days !== null ? (() => {
19577
19657
  const d = /* @__PURE__ */ new Date();
19578
19658
  d.setDate(d.getDate() - days);
@@ -19581,29 +19661,29 @@ function buildCodexSessions(days, allAuditEntries) {
19581
19661
  })() : null;
19582
19662
  const jsonlFiles = [];
19583
19663
  try {
19584
- for (const year of import_fs35.default.readdirSync(sessionsBase)) {
19585
- const yearPath = import_path38.default.join(sessionsBase, year);
19664
+ for (const year of import_fs36.default.readdirSync(sessionsBase)) {
19665
+ const yearPath = import_path39.default.join(sessionsBase, year);
19586
19666
  try {
19587
- if (!import_fs35.default.statSync(yearPath).isDirectory()) continue;
19667
+ if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
19588
19668
  } catch {
19589
19669
  continue;
19590
19670
  }
19591
- for (const month of import_fs35.default.readdirSync(yearPath)) {
19592
- const monthPath = import_path38.default.join(yearPath, month);
19671
+ for (const month of import_fs36.default.readdirSync(yearPath)) {
19672
+ const monthPath = import_path39.default.join(yearPath, month);
19593
19673
  try {
19594
- if (!import_fs35.default.statSync(monthPath).isDirectory()) continue;
19674
+ if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
19595
19675
  } catch {
19596
19676
  continue;
19597
19677
  }
19598
- for (const day of import_fs35.default.readdirSync(monthPath)) {
19599
- const dayPath = import_path38.default.join(monthPath, day);
19678
+ for (const day of import_fs36.default.readdirSync(monthPath)) {
19679
+ const dayPath = import_path39.default.join(monthPath, day);
19600
19680
  try {
19601
- if (!import_fs35.default.statSync(dayPath).isDirectory()) continue;
19681
+ if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
19602
19682
  } catch {
19603
19683
  continue;
19604
19684
  }
19605
- for (const file of import_fs35.default.readdirSync(dayPath)) {
19606
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path38.default.join(dayPath, file));
19685
+ for (const file of import_fs36.default.readdirSync(dayPath)) {
19686
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path39.default.join(dayPath, file));
19607
19687
  }
19608
19688
  }
19609
19689
  }
@@ -19615,7 +19695,7 @@ function buildCodexSessions(days, allAuditEntries) {
19615
19695
  for (const filePath of jsonlFiles) {
19616
19696
  let lines;
19617
19697
  try {
19618
- lines = import_fs35.default.readFileSync(filePath, "utf-8").split("\n");
19698
+ lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
19619
19699
  } catch {
19620
19700
  continue;
19621
19701
  }
@@ -19693,10 +19773,10 @@ function buildCodexSessions(days, allAuditEntries) {
19693
19773
  return summaries;
19694
19774
  }
19695
19775
  function buildSessions(days, historyPath) {
19696
- const hPath = historyPath ?? import_path38.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
19776
+ const hPath = historyPath ?? import_path39.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
19697
19777
  let historyRaw;
19698
19778
  try {
19699
- historyRaw = import_fs35.default.readFileSync(hPath, "utf-8");
19779
+ historyRaw = import_fs36.default.readFileSync(hPath, "utf-8");
19700
19780
  } catch {
19701
19781
  return [];
19702
19782
  }
@@ -19721,7 +19801,7 @@ function buildSessions(days, historyPath) {
19721
19801
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
19722
19802
  let sessionLines = [];
19723
19803
  try {
19724
- sessionLines = import_fs35.default.readFileSync(jsonlFile, "utf-8").split("\n");
19804
+ sessionLines = import_fs36.default.readFileSync(jsonlFile, "utf-8").split("\n");
19725
19805
  } catch {
19726
19806
  }
19727
19807
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -19987,8 +20067,8 @@ function registerSessionsCommand(program2) {
19987
20067
  console.log("");
19988
20068
  console.log(import_chalk22.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk22.default.dim(" \u2014 what your AI agent did"));
19989
20069
  console.log("");
19990
- const historyPath = import_path38.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
19991
- if (!import_fs35.default.existsSync(historyPath)) {
20070
+ const historyPath = import_path39.default.join(import_os32.default.homedir(), ".claude", "history.jsonl");
20071
+ if (!import_fs36.default.existsSync(historyPath)) {
19992
20072
  console.log(import_chalk22.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
19993
20073
  console.log(import_chalk22.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
19994
20074
  return;
@@ -20025,12 +20105,12 @@ function registerSessionsCommand(program2) {
20025
20105
 
20026
20106
  // src/cli/commands/skill-pin.ts
20027
20107
  var import_chalk23 = __toESM(require("chalk"));
20028
- var import_fs36 = __toESM(require("fs"));
20108
+ var import_fs37 = __toESM(require("fs"));
20029
20109
  var import_os33 = __toESM(require("os"));
20030
- var import_path39 = __toESM(require("path"));
20110
+ var import_path40 = __toESM(require("path"));
20031
20111
  function wipeSkillSessions() {
20032
20112
  try {
20033
- import_fs36.default.rmSync(import_path39.default.join(import_os33.default.homedir(), ".node9", "skill-sessions"), {
20113
+ import_fs37.default.rmSync(import_path40.default.join(import_os33.default.homedir(), ".node9", "skill-sessions"), {
20034
20114
  recursive: true,
20035
20115
  force: true
20036
20116
  });
@@ -20113,18 +20193,18 @@ function registerSkillPinCommand(program2) {
20113
20193
 
20114
20194
  // src/cli/commands/dlp.ts
20115
20195
  var import_chalk24 = __toESM(require("chalk"));
20116
- var import_fs37 = __toESM(require("fs"));
20117
- var import_path40 = __toESM(require("path"));
20196
+ var import_fs38 = __toESM(require("fs"));
20197
+ var import_path41 = __toESM(require("path"));
20118
20198
  var import_os34 = __toESM(require("os"));
20119
- var AUDIT_LOG = import_path40.default.join(import_os34.default.homedir(), ".node9", "audit.log");
20120
- var RESOLVED_FILE = import_path40.default.join(import_os34.default.homedir(), ".node9", "dlp-resolved.json");
20199
+ var AUDIT_LOG = import_path41.default.join(import_os34.default.homedir(), ".node9", "audit.log");
20200
+ var RESOLVED_FILE = import_path41.default.join(import_os34.default.homedir(), ".node9", "dlp-resolved.json");
20121
20201
  var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
20122
20202
  function stripAnsi(s) {
20123
20203
  return s.replace(ANSI_RE, "");
20124
20204
  }
20125
20205
  function loadResolved() {
20126
20206
  try {
20127
- const raw = JSON.parse(import_fs37.default.readFileSync(RESOLVED_FILE, "utf-8"));
20207
+ const raw = JSON.parse(import_fs38.default.readFileSync(RESOLVED_FILE, "utf-8"));
20128
20208
  return new Set(raw);
20129
20209
  } catch {
20130
20210
  return /* @__PURE__ */ new Set();
@@ -20132,13 +20212,13 @@ function loadResolved() {
20132
20212
  }
20133
20213
  function saveResolved(resolved) {
20134
20214
  try {
20135
- import_fs37.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
20215
+ import_fs38.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
20136
20216
  } catch {
20137
20217
  }
20138
20218
  }
20139
20219
  function loadDlpFindings() {
20140
- if (!import_fs37.default.existsSync(AUDIT_LOG)) return [];
20141
- return import_fs37.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
20220
+ if (!import_fs38.default.existsSync(AUDIT_LOG)) return [];
20221
+ return import_fs38.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
20142
20222
  if (!line.trim()) return [];
20143
20223
  try {
20144
20224
  const e = JSON.parse(line);
@@ -20236,20 +20316,20 @@ function registerDlpCommand(program2) {
20236
20316
 
20237
20317
  // src/cli.ts
20238
20318
  var { version } = JSON.parse(
20239
- import_fs40.default.readFileSync(import_path43.default.join(__dirname, "../package.json"), "utf-8")
20319
+ import_fs41.default.readFileSync(import_path44.default.join(__dirname, "../package.json"), "utf-8")
20240
20320
  );
20241
20321
  var program = new import_commander.Command();
20242
20322
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
20243
20323
  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) => {
20244
20324
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
20245
- const credPath = import_path43.default.join(import_os37.default.homedir(), ".node9", "credentials.json");
20246
- if (!import_fs40.default.existsSync(import_path43.default.dirname(credPath)))
20247
- import_fs40.default.mkdirSync(import_path43.default.dirname(credPath), { recursive: true });
20325
+ const credPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "credentials.json");
20326
+ if (!import_fs41.default.existsSync(import_path44.default.dirname(credPath)))
20327
+ import_fs41.default.mkdirSync(import_path44.default.dirname(credPath), { recursive: true });
20248
20328
  const profileName = options.profile || "default";
20249
20329
  let existingCreds = {};
20250
20330
  try {
20251
- if (import_fs40.default.existsSync(credPath)) {
20252
- const raw = JSON.parse(import_fs40.default.readFileSync(credPath, "utf-8"));
20331
+ if (import_fs41.default.existsSync(credPath)) {
20332
+ const raw = JSON.parse(import_fs41.default.readFileSync(credPath, "utf-8"));
20253
20333
  if (raw.apiKey) {
20254
20334
  existingCreds = {
20255
20335
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -20261,13 +20341,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
20261
20341
  } catch {
20262
20342
  }
20263
20343
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
20264
- import_fs40.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
20344
+ import_fs41.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
20265
20345
  if (profileName === "default") {
20266
- const configPath = import_path43.default.join(import_os37.default.homedir(), ".node9", "config.json");
20346
+ const configPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "config.json");
20267
20347
  let config = {};
20268
20348
  try {
20269
- if (import_fs40.default.existsSync(configPath))
20270
- config = JSON.parse(import_fs40.default.readFileSync(configPath, "utf-8"));
20349
+ if (import_fs41.default.existsSync(configPath))
20350
+ config = JSON.parse(import_fs41.default.readFileSync(configPath, "utf-8"));
20271
20351
  } catch {
20272
20352
  }
20273
20353
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -20282,9 +20362,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
20282
20362
  approvers.cloud = false;
20283
20363
  }
20284
20364
  s.approvers = approvers;
20285
- if (!import_fs40.default.existsSync(import_path43.default.dirname(configPath)))
20286
- import_fs40.default.mkdirSync(import_path43.default.dirname(configPath), { recursive: true });
20287
- import_fs40.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
20365
+ if (!import_fs41.default.existsSync(import_path44.default.dirname(configPath)))
20366
+ import_fs41.default.mkdirSync(import_path44.default.dirname(configPath), { recursive: true });
20367
+ import_fs41.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
20288
20368
  }
20289
20369
  if (options.profile && profileName !== "default") {
20290
20370
  console.log(import_chalk26.default.green(`\u2705 Profile "${profileName}" saved`));
@@ -20421,15 +20501,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
20421
20501
  }
20422
20502
  }
20423
20503
  if (options.purge) {
20424
- const node9Dir = import_path43.default.join(import_os37.default.homedir(), ".node9");
20425
- if (import_fs40.default.existsSync(node9Dir)) {
20504
+ const node9Dir = import_path44.default.join(import_os37.default.homedir(), ".node9");
20505
+ if (import_fs41.default.existsSync(node9Dir)) {
20426
20506
  const confirmed = await (0, import_prompts2.confirm)({
20427
20507
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
20428
20508
  default: false
20429
20509
  });
20430
20510
  if (confirmed) {
20431
- import_fs40.default.rmSync(node9Dir, { recursive: true });
20432
- if (import_fs40.default.existsSync(node9Dir)) {
20511
+ import_fs41.default.rmSync(node9Dir, { recursive: true });
20512
+ if (import_fs41.default.existsSync(node9Dir)) {
20433
20513
  console.error(
20434
20514
  import_chalk26.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
20435
20515
  );
@@ -20571,14 +20651,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
20571
20651
  Run "node9 addto claude" to register it as the statusLine.`
20572
20652
  ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
20573
20653
  if (subcommand === "debug") {
20574
- const flagFile = import_path43.default.join(import_os37.default.homedir(), ".node9", "hud-debug");
20654
+ const flagFile = import_path44.default.join(import_os37.default.homedir(), ".node9", "hud-debug");
20575
20655
  if (state === "on") {
20576
- import_fs40.default.mkdirSync(import_path43.default.dirname(flagFile), { recursive: true });
20577
- import_fs40.default.writeFileSync(flagFile, "");
20656
+ import_fs41.default.mkdirSync(import_path44.default.dirname(flagFile), { recursive: true });
20657
+ import_fs41.default.writeFileSync(flagFile, "");
20578
20658
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
20579
20659
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
20580
20660
  } else if (state === "off") {
20581
- if (import_fs40.default.existsSync(flagFile)) import_fs40.default.unlinkSync(flagFile);
20661
+ if (import_fs41.default.existsSync(flagFile)) import_fs41.default.unlinkSync(flagFile);
20582
20662
  console.log("HUD debug logging disabled.");
20583
20663
  } else {
20584
20664
  console.error("Usage: node9 hud debug on|off");
@@ -20690,9 +20770,9 @@ if (process.argv[2] !== "daemon") {
20690
20770
  const isCheckHook = process.argv[2] === "check";
20691
20771
  if (isCheckHook) {
20692
20772
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
20693
- const logPath = import_path43.default.join(import_os37.default.homedir(), ".node9", "hook-debug.log");
20773
+ const logPath = import_path44.default.join(import_os37.default.homedir(), ".node9", "hook-debug.log");
20694
20774
  const msg = reason instanceof Error ? reason.message : String(reason);
20695
- import_fs40.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
20775
+ import_fs41.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
20696
20776
  `);
20697
20777
  }
20698
20778
  process.exit(0);