@node9/proxy 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -6281,10 +6281,167 @@ var init_core = __esm({
6281
6281
  }
6282
6282
  });
6283
6283
 
6284
- // src/setup.ts
6284
+ // src/mcp-pin.ts
6285
6285
  import fs12 from "fs";
6286
6286
  import path14 from "path";
6287
6287
  import os11 from "os";
6288
+ import crypto3 from "crypto";
6289
+ function getHomePinsFilePath() {
6290
+ return path14.join(os11.homedir(), ".node9", "mcp-pins.json");
6291
+ }
6292
+ function getPinsFilePath() {
6293
+ return getHomePinsFilePath();
6294
+ }
6295
+ function findPinsFilePath(cwd) {
6296
+ const homeDir2 = os11.homedir();
6297
+ const homePath = getHomePinsFilePath();
6298
+ let current = path14.resolve(cwd ?? process.cwd());
6299
+ while (true) {
6300
+ if (current === homeDir2) break;
6301
+ const candidate = path14.join(current, ".node9", "mcp-pins.json");
6302
+ if (fs12.existsSync(candidate)) {
6303
+ return { path: candidate, source: "repo" };
6304
+ }
6305
+ const next = path14.dirname(current);
6306
+ if (next === current) break;
6307
+ current = next;
6308
+ }
6309
+ return { path: homePath, source: "home" };
6310
+ }
6311
+ function hashToolDefinitions(tools) {
6312
+ const sorted = [...tools].sort((a, b) => {
6313
+ const nameA = a.name ?? "";
6314
+ const nameB = b.name ?? "";
6315
+ return nameA.localeCompare(nameB);
6316
+ });
6317
+ const canonical = JSON.stringify(sorted);
6318
+ return crypto3.createHash("sha256").update(canonical).digest("hex");
6319
+ }
6320
+ function getServerKey(upstreamCommand) {
6321
+ return crypto3.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
6322
+ }
6323
+ function readPinsFile(filePath) {
6324
+ try {
6325
+ const raw = fs12.readFileSync(filePath, "utf-8");
6326
+ if (!raw.trim()) {
6327
+ return { ok: false, reason: "corrupt", detail: "empty file" };
6328
+ }
6329
+ const parsed = JSON.parse(raw);
6330
+ if (!parsed.servers || typeof parsed.servers !== "object" || Array.isArray(parsed.servers)) {
6331
+ return { ok: false, reason: "corrupt", detail: "invalid structure: missing servers object" };
6332
+ }
6333
+ return { ok: true, pins: { servers: parsed.servers } };
6334
+ } catch (err2) {
6335
+ if (err2.code === "ENOENT") {
6336
+ return { ok: false, reason: "missing" };
6337
+ }
6338
+ return { ok: false, reason: "corrupt", detail: String(err2) };
6339
+ }
6340
+ }
6341
+ function readMcpPinsSafe() {
6342
+ return readPinsFile(getHomePinsFilePath());
6343
+ }
6344
+ function readMcpPins() {
6345
+ const result = readMcpPinsSafe();
6346
+ if (result.ok) return result.pins;
6347
+ if (result.reason === "missing") return { servers: {} };
6348
+ throw new Error(`[node9] MCP pin file is corrupt: ${result.detail}`);
6349
+ }
6350
+ function writePinsFile(filePath, data) {
6351
+ fs12.mkdirSync(path14.dirname(filePath), { recursive: true });
6352
+ const tmp = `${filePath}.${crypto3.randomBytes(6).toString("hex")}.tmp`;
6353
+ const isHome = filePath === getHomePinsFilePath();
6354
+ fs12.writeFileSync(tmp, JSON.stringify(data, null, 2), isHome ? { mode: 384 } : {});
6355
+ fs12.renameSync(tmp, filePath);
6356
+ }
6357
+ function writeMcpPins(data) {
6358
+ writePinsFile(getHomePinsFilePath(), data);
6359
+ }
6360
+ function seedMcpPinsIfMissing() {
6361
+ const filePath = getPinsFilePath();
6362
+ if (fs12.existsSync(filePath)) return;
6363
+ writeMcpPins({ servers: {} });
6364
+ }
6365
+ function checkPin(serverKey, currentHash, cwd) {
6366
+ const found = findPinsFilePath(cwd);
6367
+ let repoEntry;
6368
+ if (found.source === "repo") {
6369
+ const repoResult = readPinsFile(found.path);
6370
+ if (!repoResult.ok) {
6371
+ return "corrupt";
6372
+ }
6373
+ repoEntry = repoResult.pins.servers[serverKey];
6374
+ }
6375
+ if (repoEntry) {
6376
+ return repoEntry.toolsHash === currentHash ? "match" : "mismatch";
6377
+ }
6378
+ const homeResult = readPinsFile(getHomePinsFilePath());
6379
+ if (!homeResult.ok) {
6380
+ if (homeResult.reason === "missing") return "new";
6381
+ return "corrupt";
6382
+ }
6383
+ const homeEntry = homeResult.pins.servers[serverKey];
6384
+ if (!homeEntry) return "new";
6385
+ return homeEntry.toolsHash === currentHash ? "match" : "mismatch";
6386
+ }
6387
+ function updatePin(serverKey, label, toolsHash, toolNames) {
6388
+ const pins = readMcpPins();
6389
+ pins.servers[serverKey] = {
6390
+ label,
6391
+ toolsHash,
6392
+ toolNames,
6393
+ toolCount: toolNames.length,
6394
+ pinnedAt: (/* @__PURE__ */ new Date()).toISOString()
6395
+ };
6396
+ writeMcpPins(pins);
6397
+ }
6398
+ function removePin(serverKey) {
6399
+ const pins = readMcpPins();
6400
+ delete pins.servers[serverKey];
6401
+ writeMcpPins(pins);
6402
+ }
6403
+ function clearAllPins() {
6404
+ writeMcpPins({ servers: {} });
6405
+ }
6406
+ function promotePin(serverKey, cwd) {
6407
+ const homePins = readMcpPins();
6408
+ const homeEntry = homePins.servers[serverKey];
6409
+ if (!homeEntry) {
6410
+ throw new Error(
6411
+ `[node9] Server "${serverKey}" is not pinned in ~/.node9/mcp-pins.json. Run \`node9 mcp pin list\` to see what's pinned.`
6412
+ );
6413
+ }
6414
+ const found = findPinsFilePath(cwd);
6415
+ let repoPath;
6416
+ let repoPins;
6417
+ let created = false;
6418
+ if (found.source === "repo") {
6419
+ repoPath = found.path;
6420
+ const result = readPinsFile(repoPath);
6421
+ if (!result.ok) {
6422
+ const detail = result.reason === "corrupt" ? result.detail : "missing";
6423
+ throw new Error(`[node9] Repo pin file at ${repoPath} is unreadable: ${detail}`);
6424
+ }
6425
+ repoPins = result.pins;
6426
+ } else {
6427
+ repoPath = path14.join(cwd ?? process.cwd(), ".node9", "mcp-pins.json");
6428
+ repoPins = { servers: {} };
6429
+ created = true;
6430
+ }
6431
+ repoPins.servers[serverKey] = { ...homeEntry };
6432
+ writePinsFile(repoPath, repoPins);
6433
+ return { repoPath, created };
6434
+ }
6435
+ var init_mcp_pin = __esm({
6436
+ "src/mcp-pin.ts"() {
6437
+ "use strict";
6438
+ }
6439
+ });
6440
+
6441
+ // src/setup.ts
6442
+ import fs13 from "fs";
6443
+ import path15 from "path";
6444
+ import os12 from "os";
6288
6445
  import chalk from "chalk";
6289
6446
  import { confirm } from "@inquirer/prompts";
6290
6447
  import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
@@ -6312,32 +6469,32 @@ function isStaleHookCommand(command) {
6312
6469
  const tokens = command.split(/\s+/);
6313
6470
  for (const tok of tokens) {
6314
6471
  if (!tok.startsWith("/")) continue;
6315
- if (!fs12.existsSync(tok)) return true;
6472
+ if (!fs13.existsSync(tok)) return true;
6316
6473
  }
6317
6474
  return false;
6318
6475
  }
6319
6476
  function readJson(filePath) {
6320
6477
  try {
6321
- if (fs12.existsSync(filePath)) {
6322
- return JSON.parse(fs12.readFileSync(filePath, "utf-8"));
6478
+ if (fs13.existsSync(filePath)) {
6479
+ return JSON.parse(fs13.readFileSync(filePath, "utf-8"));
6323
6480
  }
6324
6481
  } catch {
6325
6482
  }
6326
6483
  return null;
6327
6484
  }
6328
6485
  function writeJson(filePath, data) {
6329
- const dir = path14.dirname(filePath);
6330
- if (!fs12.existsSync(dir)) fs12.mkdirSync(dir, { recursive: true });
6331
- fs12.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
6486
+ const dir = path15.dirname(filePath);
6487
+ if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
6488
+ fs13.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
6332
6489
  }
6333
6490
  function isNode9Hook(cmd) {
6334
6491
  if (!cmd) return false;
6335
6492
  return /(?:^|[\s/\\])node9 (?:check|log)/.test(cmd) || /(?:^|[\s/\\])cli\.js (?:check|log)/.test(cmd);
6336
6493
  }
6337
6494
  function teardownClaude() {
6338
- const homeDir2 = os11.homedir();
6339
- const hooksPath = path14.join(homeDir2, ".claude", "settings.json");
6340
- const mcpPath = path14.join(homeDir2, ".claude", ".mcp.json");
6495
+ const homeDir2 = os12.homedir();
6496
+ const hooksPath = path15.join(homeDir2, ".claude", "settings.json");
6497
+ const mcpPath = path15.join(homeDir2, ".claude", ".mcp.json");
6341
6498
  let changed = false;
6342
6499
  const settings = readJson(hooksPath);
6343
6500
  if (settings?.hooks) {
@@ -6385,8 +6542,8 @@ function teardownClaude() {
6385
6542
  }
6386
6543
  }
6387
6544
  function teardownGemini() {
6388
- const homeDir2 = os11.homedir();
6389
- const settingsPath = path14.join(homeDir2, ".gemini", "settings.json");
6545
+ const homeDir2 = os12.homedir();
6546
+ const settingsPath = path15.join(homeDir2, ".gemini", "settings.json");
6390
6547
  const settings = readJson(settingsPath);
6391
6548
  if (!settings) {
6392
6549
  console.log(chalk.blue(" \u2139\uFE0F ~/.gemini/settings.json not found \u2014 nothing to remove"));
@@ -6429,8 +6586,8 @@ function teardownGemini() {
6429
6586
  }
6430
6587
  }
6431
6588
  function teardownCursor() {
6432
- const homeDir2 = os11.homedir();
6433
- const mcpPath = path14.join(homeDir2, ".cursor", "mcp.json");
6589
+ const homeDir2 = os12.homedir();
6590
+ const mcpPath = path15.join(homeDir2, ".cursor", "mcp.json");
6434
6591
  const mcpConfig = readJson(mcpPath);
6435
6592
  if (!mcpConfig?.mcpServers) {
6436
6593
  console.log(chalk.blue(" \u2139\uFE0F ~/.cursor/mcp.json not found \u2014 nothing to remove"));
@@ -6461,9 +6618,10 @@ function teardownCursor() {
6461
6618
  }
6462
6619
  }
6463
6620
  async function setupClaude() {
6464
- const homeDir2 = os11.homedir();
6465
- const mcpPath = path14.join(homeDir2, ".claude", ".mcp.json");
6466
- const hooksPath = path14.join(homeDir2, ".claude", "settings.json");
6621
+ seedMcpPinsIfMissing();
6622
+ const homeDir2 = os12.homedir();
6623
+ const mcpPath = path15.join(homeDir2, ".claude", ".mcp.json");
6624
+ const hooksPath = path15.join(homeDir2, ".claude", "settings.json");
6467
6625
  const claudeConfig = readJson(mcpPath) ?? {};
6468
6626
  const settings = readJson(hooksPath) ?? {};
6469
6627
  const servers = claudeConfig.mcpServers ?? {};
@@ -6613,8 +6771,9 @@ async function setupClaude() {
6613
6771
  }
6614
6772
  }
6615
6773
  async function setupGemini() {
6616
- const homeDir2 = os11.homedir();
6617
- const settingsPath = path14.join(homeDir2, ".gemini", "settings.json");
6774
+ seedMcpPinsIfMissing();
6775
+ const homeDir2 = os12.homedir();
6776
+ const settingsPath = path15.join(homeDir2, ".gemini", "settings.json");
6618
6777
  const settings = readJson(settingsPath) ?? {};
6619
6778
  const servers = settings.mcpServers ?? {};
6620
6779
  let hooksChanged = false;
@@ -6709,9 +6868,9 @@ async function setupGemini() {
6709
6868
  printDaemonTip();
6710
6869
  }
6711
6870
  }
6712
- function claudeDesktopConfigPath(homeDir2 = os11.homedir()) {
6871
+ function claudeDesktopConfigPath(homeDir2 = os12.homedir()) {
6713
6872
  if (process.platform === "darwin") {
6714
- return path14.join(
6873
+ return path15.join(
6715
6874
  homeDir2,
6716
6875
  "Library",
6717
6876
  "Application Support",
@@ -6720,18 +6879,18 @@ function claudeDesktopConfigPath(homeDir2 = os11.homedir()) {
6720
6879
  );
6721
6880
  }
6722
6881
  if (process.platform === "linux") {
6723
- return path14.join(homeDir2, ".config", "Claude", "claude_desktop_config.json");
6882
+ return path15.join(homeDir2, ".config", "Claude", "claude_desktop_config.json");
6724
6883
  }
6725
6884
  if (process.platform === "win32") {
6726
- const appData = process.env.APPDATA ?? path14.join(homeDir2, "AppData", "Roaming");
6727
- return path14.join(appData, "Claude", "claude_desktop_config.json");
6885
+ const appData = process.env.APPDATA ?? path15.join(homeDir2, "AppData", "Roaming");
6886
+ return path15.join(appData, "Claude", "claude_desktop_config.json");
6728
6887
  }
6729
6888
  return null;
6730
6889
  }
6731
- function detectAgents(homeDir2 = os11.homedir()) {
6890
+ function detectAgents(homeDir2 = os12.homedir()) {
6732
6891
  const exists = (p) => {
6733
6892
  try {
6734
- return fs12.existsSync(p);
6893
+ return fs13.existsSync(p);
6735
6894
  } catch (err2) {
6736
6895
  const code = err2.code;
6737
6896
  if (code !== "ENOENT") {
@@ -6743,18 +6902,19 @@ function detectAgents(homeDir2 = os11.homedir()) {
6743
6902
  };
6744
6903
  const desktopPath = claudeDesktopConfigPath(homeDir2);
6745
6904
  return {
6746
- claude: exists(path14.join(homeDir2, ".claude")) || exists(path14.join(homeDir2, ".claude.json")),
6747
- gemini: exists(path14.join(homeDir2, ".gemini")),
6748
- cursor: exists(path14.join(homeDir2, ".cursor")),
6749
- codex: exists(path14.join(homeDir2, ".codex")),
6750
- windsurf: exists(path14.join(homeDir2, ".codeium", "windsurf")),
6751
- vscode: exists(path14.join(homeDir2, ".vscode")),
6752
- claudeDesktop: desktopPath !== null && exists(path14.dirname(desktopPath))
6905
+ claude: exists(path15.join(homeDir2, ".claude")) || exists(path15.join(homeDir2, ".claude.json")),
6906
+ gemini: exists(path15.join(homeDir2, ".gemini")),
6907
+ cursor: exists(path15.join(homeDir2, ".cursor")),
6908
+ codex: exists(path15.join(homeDir2, ".codex")),
6909
+ windsurf: exists(path15.join(homeDir2, ".codeium", "windsurf")),
6910
+ vscode: exists(path15.join(homeDir2, ".vscode")),
6911
+ claudeDesktop: desktopPath !== null && exists(path15.dirname(desktopPath))
6753
6912
  };
6754
6913
  }
6755
6914
  async function setupCursor() {
6756
- const homeDir2 = os11.homedir();
6757
- const mcpPath = path14.join(homeDir2, ".cursor", "mcp.json");
6915
+ seedMcpPinsIfMissing();
6916
+ const homeDir2 = os12.homedir();
6917
+ const mcpPath = path15.join(homeDir2, ".cursor", "mcp.json");
6758
6918
  const mcpConfig = readJson(mcpPath) ?? {};
6759
6919
  const servers = mcpConfig.mcpServers ?? {};
6760
6920
  let anythingChanged = false;
@@ -6820,22 +6980,23 @@ async function setupCursor() {
6820
6980
  }
6821
6981
  function readToml(filePath) {
6822
6982
  try {
6823
- if (fs12.existsSync(filePath)) {
6824
- return parseToml(fs12.readFileSync(filePath, "utf-8"));
6983
+ if (fs13.existsSync(filePath)) {
6984
+ return parseToml(fs13.readFileSync(filePath, "utf-8"));
6825
6985
  }
6826
6986
  } catch {
6827
6987
  }
6828
6988
  return null;
6829
6989
  }
6830
6990
  function writeToml(filePath, data) {
6831
- const dir = path14.dirname(filePath);
6832
- if (!fs12.existsSync(dir)) fs12.mkdirSync(dir, { recursive: true });
6833
- fs12.writeFileSync(filePath, stringifyToml(data));
6991
+ const dir = path15.dirname(filePath);
6992
+ if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
6993
+ fs13.writeFileSync(filePath, stringifyToml(data));
6834
6994
  }
6835
6995
  async function setupCodex() {
6836
- const homeDir2 = os11.homedir();
6837
- const configPath = path14.join(homeDir2, ".codex", "config.toml");
6838
- const hooksPath = path14.join(homeDir2, ".codex", "hooks.json");
6996
+ seedMcpPinsIfMissing();
6997
+ const homeDir2 = os12.homedir();
6998
+ const configPath = path15.join(homeDir2, ".codex", "config.toml");
6999
+ const hooksPath = path15.join(homeDir2, ".codex", "hooks.json");
6839
7000
  const config = readToml(configPath) ?? {};
6840
7001
  const servers = config.mcp_servers ?? {};
6841
7002
  let anythingChanged = false;
@@ -6985,9 +7146,9 @@ async function setupCodex() {
6985
7146
  }
6986
7147
  }
6987
7148
  function teardownCodex() {
6988
- const homeDir2 = os11.homedir();
6989
- const configPath = path14.join(homeDir2, ".codex", "config.toml");
6990
- const hooksPath = path14.join(homeDir2, ".codex", "hooks.json");
7149
+ const homeDir2 = os12.homedir();
7150
+ const configPath = path15.join(homeDir2, ".codex", "config.toml");
7151
+ const hooksPath = path15.join(homeDir2, ".codex", "hooks.json");
6991
7152
  const hooksFile = readJson(hooksPath);
6992
7153
  if (hooksFile?.hooks) {
6993
7154
  let hooksChanged = false;
@@ -7034,8 +7195,8 @@ function teardownCodex() {
7034
7195
  }
7035
7196
  }
7036
7197
  function setupHud() {
7037
- const homeDir2 = os11.homedir();
7038
- const hooksPath = path14.join(homeDir2, ".claude", "settings.json");
7198
+ const homeDir2 = os12.homedir();
7199
+ const hooksPath = path15.join(homeDir2, ".claude", "settings.json");
7039
7200
  const settings = readJson(hooksPath) ?? {};
7040
7201
  const hudCommand = fullPathCommand("hud");
7041
7202
  const statusLineObj = { type: "command", command: hudCommand };
@@ -7061,8 +7222,8 @@ function setupHud() {
7061
7222
  console.log(chalk.gray(" Restart Claude Code to activate."));
7062
7223
  }
7063
7224
  function teardownHud() {
7064
- const homeDir2 = os11.homedir();
7065
- const hooksPath = path14.join(homeDir2, ".claude", "settings.json");
7225
+ const homeDir2 = os12.homedir();
7226
+ const hooksPath = path15.join(homeDir2, ".claude", "settings.json");
7066
7227
  const settings = readJson(hooksPath);
7067
7228
  if (!settings) {
7068
7229
  console.log(chalk.blue(" \u2139\uFE0F ~/.claude/settings.json not found \u2014 nothing to remove"));
@@ -7080,8 +7241,9 @@ function teardownHud() {
7080
7241
  console.log(chalk.gray(" Restart Claude Code for changes to take effect."));
7081
7242
  }
7082
7243
  async function setupWindsurf() {
7083
- const homeDir2 = os11.homedir();
7084
- const mcpPath = path14.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7244
+ seedMcpPinsIfMissing();
7245
+ const homeDir2 = os12.homedir();
7246
+ const mcpPath = path15.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7085
7247
  const mcpConfig = readJson(mcpPath) ?? {};
7086
7248
  const servers = mcpConfig.mcpServers ?? {};
7087
7249
  let anythingChanged = false;
@@ -7141,8 +7303,8 @@ async function setupWindsurf() {
7141
7303
  }
7142
7304
  }
7143
7305
  function teardownWindsurf() {
7144
- const homeDir2 = os11.homedir();
7145
- const mcpPath = path14.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7306
+ const homeDir2 = os12.homedir();
7307
+ const mcpPath = path15.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7146
7308
  const mcpConfig = readJson(mcpPath);
7147
7309
  if (!mcpConfig?.mcpServers) {
7148
7310
  console.log(
@@ -7183,8 +7345,9 @@ function hasNode9McpServerVSCode(servers) {
7183
7345
  return !!entry && entry.command === "node9" && Array.isArray(entry.args) && entry.args[0] === "mcp-server";
7184
7346
  }
7185
7347
  async function setupVSCode() {
7186
- const homeDir2 = os11.homedir();
7187
- const mcpPath = path14.join(homeDir2, ".vscode", "mcp.json");
7348
+ seedMcpPinsIfMissing();
7349
+ const homeDir2 = os12.homedir();
7350
+ const mcpPath = path15.join(homeDir2, ".vscode", "mcp.json");
7188
7351
  const mcpConfig = readJson(mcpPath) ?? {};
7189
7352
  const servers = mcpConfig.servers ?? {};
7190
7353
  let anythingChanged = false;
@@ -7245,8 +7408,8 @@ async function setupVSCode() {
7245
7408
  }
7246
7409
  }
7247
7410
  function teardownVSCode() {
7248
- const homeDir2 = os11.homedir();
7249
- const mcpPath = path14.join(homeDir2, ".vscode", "mcp.json");
7411
+ const homeDir2 = os12.homedir();
7412
+ const mcpPath = path15.join(homeDir2, ".vscode", "mcp.json");
7250
7413
  const mcpConfig = readJson(mcpPath);
7251
7414
  if (!mcpConfig?.servers) {
7252
7415
  console.log(chalk.blue(" \u2139\uFE0F ~/.vscode/mcp.json not found \u2014 nothing to remove"));
@@ -7279,6 +7442,7 @@ function teardownVSCode() {
7279
7442
  }
7280
7443
  }
7281
7444
  async function setupClaudeDesktop() {
7445
+ seedMcpPinsIfMissing();
7282
7446
  const configPath = claudeDesktopConfigPath();
7283
7447
  if (!configPath) {
7284
7448
  console.log(chalk.yellow(" \u26A0\uFE0F Claude Desktop is not supported on this platform."));
@@ -7377,32 +7541,32 @@ function teardownClaudeDesktop() {
7377
7541
  console.log(chalk.blue(" \u2139\uFE0F No Node9-wrapped MCP servers found in Claude Desktop config"));
7378
7542
  }
7379
7543
  }
7380
- function getAgentsStatus(homeDir2 = os11.homedir()) {
7544
+ function getAgentsStatus(homeDir2 = os12.homedir()) {
7381
7545
  const detected = detectAgents(homeDir2);
7382
7546
  const claudeWired = (() => {
7383
- const settings = readJson(path14.join(homeDir2, ".claude", "settings.json"));
7547
+ const settings = readJson(path15.join(homeDir2, ".claude", "settings.json"));
7384
7548
  return !!settings?.hooks?.PreToolUse?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
7385
7549
  })();
7386
7550
  const geminiWired = (() => {
7387
- const settings = readJson(path14.join(homeDir2, ".gemini", "settings.json"));
7551
+ const settings = readJson(path15.join(homeDir2, ".gemini", "settings.json"));
7388
7552
  return !!settings?.hooks?.BeforeTool?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
7389
7553
  })();
7390
7554
  const cursorWired = (() => {
7391
- const cfg = readJson(path14.join(homeDir2, ".cursor", "mcp.json"));
7555
+ const cfg = readJson(path15.join(homeDir2, ".cursor", "mcp.json"));
7392
7556
  return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
7393
7557
  })();
7394
7558
  const codexWired = (() => {
7395
- const cfg = readToml(path14.join(homeDir2, ".codex", "config.toml"));
7559
+ const cfg = readToml(path15.join(homeDir2, ".codex", "config.toml"));
7396
7560
  return !!(cfg?.mcp_servers && hasNode9McpServer(cfg.mcp_servers));
7397
7561
  })();
7398
7562
  const windsurfWired = (() => {
7399
7563
  const cfg = readJson(
7400
- path14.join(homeDir2, ".codeium", "windsurf", "mcp_config.json")
7564
+ path15.join(homeDir2, ".codeium", "windsurf", "mcp_config.json")
7401
7565
  );
7402
7566
  return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
7403
7567
  })();
7404
7568
  const vscodeWired = (() => {
7405
- const cfg = readJson(path14.join(homeDir2, ".vscode", "mcp.json"));
7569
+ const cfg = readJson(path15.join(homeDir2, ".vscode", "mcp.json"));
7406
7570
  return !!(cfg?.servers && hasNode9McpServerVSCode(cfg.servers));
7407
7571
  })();
7408
7572
  return [
@@ -7466,6 +7630,7 @@ var NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS;
7466
7630
  var init_setup = __esm({
7467
7631
  "src/setup.ts"() {
7468
7632
  "use strict";
7633
+ init_mcp_pin();
7469
7634
  NODE9_MCP_SERVER_ENTRY = { command: "node9", args: ["mcp-server"] };
7470
7635
  CODEX_PRE_TOOL_MATCHERS = ["^Bash$", "^apply_patch$", "^mcp__.*"];
7471
7636
  }
@@ -7659,85 +7824,85 @@ var init_scan_summary = __esm({
7659
7824
 
7660
7825
  // src/cli/commands/blast.ts
7661
7826
  import chalk2 from "chalk";
7662
- import fs13 from "fs";
7663
- import path15 from "path";
7664
- import os12 from "os";
7827
+ import fs14 from "fs";
7828
+ import path16 from "path";
7829
+ import os13 from "os";
7665
7830
  function buildSensitivePaths(home, cwd) {
7666
7831
  return [
7667
7832
  {
7668
- full: path15.join(home, ".ssh", "id_rsa"),
7833
+ full: path16.join(home, ".ssh", "id_rsa"),
7669
7834
  label: "~/.ssh/id_rsa",
7670
7835
  description: "RSA private key \u2014 grants SSH access to your servers",
7671
7836
  score: 20
7672
7837
  },
7673
7838
  {
7674
- full: path15.join(home, ".ssh", "id_ed25519"),
7839
+ full: path16.join(home, ".ssh", "id_ed25519"),
7675
7840
  label: "~/.ssh/id_ed25519",
7676
7841
  description: "Ed25519 private key \u2014 grants SSH access to your servers",
7677
7842
  score: 20
7678
7843
  },
7679
7844
  {
7680
- full: path15.join(home, ".ssh", "id_ecdsa"),
7845
+ full: path16.join(home, ".ssh", "id_ecdsa"),
7681
7846
  label: "~/.ssh/id_ecdsa",
7682
7847
  description: "ECDSA private key \u2014 grants SSH access to your servers",
7683
7848
  score: 20
7684
7849
  },
7685
7850
  {
7686
- full: path15.join(home, ".aws", "credentials"),
7851
+ full: path16.join(home, ".aws", "credentials"),
7687
7852
  label: "~/.aws/credentials",
7688
7853
  description: "AWS access keys \u2014 full cloud account access",
7689
7854
  score: 20
7690
7855
  },
7691
7856
  {
7692
- full: path15.join(home, ".aws", "config"),
7857
+ full: path16.join(home, ".aws", "config"),
7693
7858
  label: "~/.aws/config",
7694
7859
  description: "AWS configuration \u2014 account and region settings",
7695
7860
  score: 5
7696
7861
  },
7697
7862
  {
7698
- full: path15.join(home, ".config", "gcloud", "credentials.db"),
7863
+ full: path16.join(home, ".config", "gcloud", "credentials.db"),
7699
7864
  label: "~/.config/gcloud/credentials.db",
7700
7865
  description: "Google Cloud credentials",
7701
7866
  score: 15
7702
7867
  },
7703
7868
  {
7704
- full: path15.join(home, ".docker", "config.json"),
7869
+ full: path16.join(home, ".docker", "config.json"),
7705
7870
  label: "~/.docker/config.json",
7706
7871
  description: "Docker registry auth tokens",
7707
7872
  score: 10
7708
7873
  },
7709
7874
  {
7710
- full: path15.join(home, ".netrc"),
7875
+ full: path16.join(home, ".netrc"),
7711
7876
  label: "~/.netrc",
7712
7877
  description: "FTP/HTTP credentials in plain text",
7713
7878
  score: 15
7714
7879
  },
7715
7880
  {
7716
- full: path15.join(home, ".npmrc"),
7881
+ full: path16.join(home, ".npmrc"),
7717
7882
  label: "~/.npmrc",
7718
7883
  description: "npm auth token \u2014 can publish packages as you",
7719
7884
  score: 10
7720
7885
  },
7721
7886
  {
7722
- full: path15.join(home, ".node9", "credentials.json"),
7887
+ full: path16.join(home, ".node9", "credentials.json"),
7723
7888
  label: "~/.node9/credentials.json",
7724
7889
  description: "Node9 cloud API key",
7725
7890
  score: 10
7726
7891
  },
7727
7892
  {
7728
- full: path15.join(cwd, ".env"),
7893
+ full: path16.join(cwd, ".env"),
7729
7894
  label: ".env (current folder)",
7730
7895
  description: "App secrets \u2014 database passwords, API keys",
7731
7896
  score: 20
7732
7897
  },
7733
7898
  {
7734
- full: path15.join(cwd, ".env.local"),
7899
+ full: path16.join(cwd, ".env.local"),
7735
7900
  label: ".env.local (current folder)",
7736
7901
  description: "Local overrides \u2014 often contains real credentials",
7737
7902
  score: 15
7738
7903
  },
7739
7904
  {
7740
- full: path15.join(cwd, ".env.production"),
7905
+ full: path16.join(cwd, ".env.production"),
7741
7906
  label: ".env.production (current folder)",
7742
7907
  description: "Production secrets",
7743
7908
  score: 20
@@ -7746,7 +7911,7 @@ function buildSensitivePaths(home, cwd) {
7746
7911
  }
7747
7912
  function isReadable(filePath) {
7748
7913
  try {
7749
- fs13.accessSync(filePath, fs13.constants.R_OK);
7914
+ fs14.accessSync(filePath, fs14.constants.R_OK);
7750
7915
  return true;
7751
7916
  } catch {
7752
7917
  return false;
@@ -7759,13 +7924,13 @@ function scoreLabel(score) {
7759
7924
  return chalk2.red.bold(`${score}/100 Critical`);
7760
7925
  }
7761
7926
  function runBlast() {
7762
- const home = os12.homedir();
7927
+ const home = os13.homedir();
7763
7928
  const cwd = process.cwd();
7764
7929
  const paths = buildSensitivePaths(home, cwd);
7765
7930
  let scoreDeduction = 0;
7766
7931
  const reachable = [];
7767
7932
  for (const p of paths) {
7768
- if (fs13.existsSync(p.full) && isReadable(p.full)) {
7933
+ if (fs14.existsSync(p.full) && isReadable(p.full)) {
7769
7934
  reachable.push(p);
7770
7935
  scoreDeduction += p.score;
7771
7936
  }
@@ -7783,7 +7948,7 @@ function runBlast() {
7783
7948
  }
7784
7949
  function registerBlastCommand(program2) {
7785
7950
  program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
7786
- const home = os12.homedir();
7951
+ const home = os13.homedir();
7787
7952
  const cwd = process.cwd();
7788
7953
  const { reachable, envFindings, score } = runBlast();
7789
7954
  console.log("");
@@ -7959,17 +8124,17 @@ var init_scan_json = __esm({
7959
8124
  });
7960
8125
 
7961
8126
  // src/cli/render/scan-history.ts
7962
- import fs14 from "fs";
7963
- import path16 from "path";
7964
- import os13 from "os";
8127
+ import fs15 from "fs";
8128
+ import path17 from "path";
8129
+ import os14 from "os";
7965
8130
  function defaultHistoryPath() {
7966
- return path16.join(os13.homedir(), ".node9", "scan-history.json");
8131
+ return path17.join(os14.homedir(), ".node9", "scan-history.json");
7967
8132
  }
7968
8133
  function readPreviousScan(opts = {}) {
7969
8134
  const filePath = opts.path ?? defaultHistoryPath();
7970
8135
  try {
7971
- if (!fs14.existsSync(filePath)) return null;
7972
- const raw = fs14.readFileSync(filePath, "utf8");
8136
+ if (!fs15.existsSync(filePath)) return null;
8137
+ const raw = fs15.readFileSync(filePath, "utf8");
7973
8138
  const parsed = JSON.parse(raw);
7974
8139
  if (!Array.isArray(parsed) || parsed.length === 0) return null;
7975
8140
  const last = parsed[parsed.length - 1];
@@ -7983,11 +8148,11 @@ function appendScanHistory(record, opts = {}) {
7983
8148
  const filePath = opts.path ?? defaultHistoryPath();
7984
8149
  const cap = opts.cap ?? SCAN_HISTORY_CAP;
7985
8150
  try {
7986
- fs14.mkdirSync(path16.dirname(filePath), { recursive: true });
8151
+ fs15.mkdirSync(path17.dirname(filePath), { recursive: true });
7987
8152
  let history = [];
7988
- if (fs14.existsSync(filePath)) {
8153
+ if (fs15.existsSync(filePath)) {
7989
8154
  try {
7990
- const parsed = JSON.parse(fs14.readFileSync(filePath, "utf8"));
8155
+ const parsed = JSON.parse(fs15.readFileSync(filePath, "utf8"));
7991
8156
  if (Array.isArray(parsed)) {
7992
8157
  history = parsed.filter(isValidRecord);
7993
8158
  }
@@ -7998,7 +8163,7 @@ function appendScanHistory(record, opts = {}) {
7998
8163
  if (history.length > cap) {
7999
8164
  history = history.slice(history.length - cap);
8000
8165
  }
8001
- fs14.writeFileSync(filePath, JSON.stringify(history, null, 2));
8166
+ fs15.writeFileSync(filePath, JSON.stringify(history, null, 2));
8002
8167
  } catch (err2) {
8003
8168
  process.stderr.write(
8004
8169
  `[node9] Warning: could not write scan-history.json: ${err2.message}
@@ -8029,15 +8194,15 @@ var init_scan_history = __esm({
8029
8194
  });
8030
8195
 
8031
8196
  // src/pricing/litellm.ts
8032
- import fs15 from "fs";
8033
- import path17 from "path";
8034
- import os14 from "os";
8197
+ import fs16 from "fs";
8198
+ import path18 from "path";
8199
+ import os15 from "os";
8035
8200
  function normalizeModel(raw) {
8036
8201
  return raw.replace(/-\d{8}$/, "").toLowerCase();
8037
8202
  }
8038
8203
  function readCache() {
8039
8204
  try {
8040
- const raw = JSON.parse(fs15.readFileSync(CACHE_FILE(), "utf-8"));
8205
+ const raw = JSON.parse(fs16.readFileSync(CACHE_FILE(), "utf-8"));
8041
8206
  if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
8042
8207
  return null;
8043
8208
  }
@@ -8051,18 +8216,18 @@ function readCache() {
8051
8216
  function writeCache(prices) {
8052
8217
  try {
8053
8218
  const target = CACHE_FILE();
8054
- const dir = path17.dirname(target);
8055
- if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
8219
+ const dir = path18.dirname(target);
8220
+ if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
8056
8221
  const tmp = target + ".tmp";
8057
8222
  const body = {
8058
8223
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
8059
8224
  prices
8060
8225
  };
8061
- fs15.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
8062
- fs15.renameSync(tmp, target);
8226
+ fs16.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
8227
+ fs16.renameSync(tmp, target);
8063
8228
  } catch (err2) {
8064
8229
  try {
8065
- fs15.appendFileSync(
8230
+ fs16.appendFileSync(
8066
8231
  HOOK_DEBUG_LOG,
8067
8232
  `[pricing] cache write failed: ${err2.message}
8068
8233
  `
@@ -8185,7 +8350,7 @@ var init_litellm = __esm({
8185
8350
  "gemini-2.0-flash": [75e-9, 3e-7, 0, 0],
8186
8351
  "gemini-1.5-pro": [125e-8, 5e-6, 0, 0]
8187
8352
  };
8188
- CACHE_FILE = () => path17.join(os14.homedir(), ".node9", "model-pricing.json");
8353
+ CACHE_FILE = () => path18.join(os15.homedir(), ".node9", "model-pricing.json");
8189
8354
  TTL_MS = 24 * 60 * 60 * 1e3;
8190
8355
  memCache = null;
8191
8356
  memCacheAt = 0;
@@ -8194,17 +8359,17 @@ var init_litellm = __esm({
8194
8359
  });
8195
8360
 
8196
8361
  // src/costSync.ts
8197
- import fs16 from "fs";
8198
- import path18 from "path";
8199
- import os15 from "os";
8362
+ import fs17 from "fs";
8363
+ import path19 from "path";
8364
+ import os16 from "os";
8200
8365
  function decodeProjectDirName(dirName) {
8201
8366
  return dirName.replace(/-/g, "/");
8202
8367
  }
8203
8368
  function parseJSONLFile(filePath, fallbackWorkingDir) {
8204
- const runId = path18.basename(filePath, ".jsonl");
8369
+ const runId = path19.basename(filePath, ".jsonl");
8205
8370
  let content;
8206
8371
  try {
8207
- content = fs16.readFileSync(filePath, "utf8");
8372
+ content = fs17.readFileSync(filePath, "utf8");
8208
8373
  } catch {
8209
8374
  return /* @__PURE__ */ new Map();
8210
8375
  }
@@ -8260,34 +8425,34 @@ function parseJSONLFile(filePath, fallbackWorkingDir) {
8260
8425
  return daily;
8261
8426
  }
8262
8427
  function collectEntries(sinceMs) {
8263
- const projectsDir = path18.join(os15.homedir(), ".claude", "projects");
8264
- if (!fs16.existsSync(projectsDir)) return [];
8428
+ const projectsDir = path19.join(os16.homedir(), ".claude", "projects");
8429
+ if (!fs17.existsSync(projectsDir)) return [];
8265
8430
  const combined = /* @__PURE__ */ new Map();
8266
8431
  let dirs;
8267
8432
  try {
8268
- dirs = fs16.readdirSync(projectsDir);
8433
+ dirs = fs17.readdirSync(projectsDir);
8269
8434
  } catch {
8270
8435
  return [];
8271
8436
  }
8272
8437
  for (const dir of dirs) {
8273
- const dirPath = path18.join(projectsDir, dir);
8438
+ const dirPath = path19.join(projectsDir, dir);
8274
8439
  try {
8275
- if (!fs16.statSync(dirPath).isDirectory()) continue;
8440
+ if (!fs17.statSync(dirPath).isDirectory()) continue;
8276
8441
  } catch {
8277
8442
  continue;
8278
8443
  }
8279
8444
  let files;
8280
8445
  try {
8281
- files = fs16.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8446
+ files = fs17.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8282
8447
  } catch {
8283
8448
  continue;
8284
8449
  }
8285
8450
  const fallbackWorkingDir = decodeProjectDirName(dir);
8286
8451
  for (const file of files) {
8287
- const filePath = path18.join(dirPath, file);
8452
+ const filePath = path19.join(dirPath, file);
8288
8453
  if (sinceMs !== void 0) {
8289
8454
  try {
8290
- if (fs16.statSync(filePath).mtimeMs < sinceMs) continue;
8455
+ if (fs17.statSync(filePath).mtimeMs < sinceMs) continue;
8291
8456
  } catch {
8292
8457
  continue;
8293
8458
  }
@@ -8317,10 +8482,10 @@ async function syncCost() {
8317
8482
  if (entries.length === 0) return;
8318
8483
  let username = "unknown";
8319
8484
  try {
8320
- username = os15.userInfo().username;
8485
+ username = os16.userInfo().username;
8321
8486
  } catch {
8322
8487
  }
8323
- const machineId = `${os15.hostname()}:${username}`;
8488
+ const machineId = `${os16.hostname()}:${username}`;
8324
8489
  try {
8325
8490
  const res = await fetch(`${creds.apiUrl}/cost-sync`, {
8326
8491
  method: "POST",
@@ -8329,11 +8494,11 @@ async function syncCost() {
8329
8494
  signal: AbortSignal.timeout(15e3)
8330
8495
  });
8331
8496
  if (!res.ok) {
8332
- fs16.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
8497
+ fs17.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
8333
8498
  `);
8334
8499
  }
8335
8500
  } catch (err2) {
8336
- fs16.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
8501
+ fs17.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
8337
8502
  `);
8338
8503
  }
8339
8504
  }
@@ -8369,9 +8534,9 @@ __export(scan_watermark_exports, {
8369
8534
  tickForensicBroadcast: () => tickForensicBroadcast,
8370
8535
  tickScanWatcher: () => tickScanWatcher
8371
8536
  });
8372
- import fs17 from "fs";
8373
- import os16 from "os";
8374
- import path19 from "path";
8537
+ import fs18 from "fs";
8538
+ import os17 from "os";
8539
+ import path20 from "path";
8375
8540
  import readline from "readline";
8376
8541
  function freshWatermark() {
8377
8542
  return {
@@ -8384,7 +8549,7 @@ function freshWatermark() {
8384
8549
  function loadWatermark() {
8385
8550
  let raw;
8386
8551
  try {
8387
- raw = fs17.readFileSync(WATERMARK_FILE(), "utf-8");
8552
+ raw = fs18.readFileSync(WATERMARK_FILE(), "utf-8");
8388
8553
  } catch {
8389
8554
  return { status: "fresh", wm: freshWatermark() };
8390
8555
  }
@@ -8436,28 +8601,28 @@ function loadWatermark() {
8436
8601
  function saveWatermark(wm) {
8437
8602
  if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
8438
8603
  const target = WATERMARK_FILE();
8439
- const dir = path19.dirname(target);
8440
- if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
8604
+ const dir = path20.dirname(target);
8605
+ if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
8441
8606
  const tmp = target + ".tmp";
8442
- fs17.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
8443
- fs17.renameSync(tmp, target);
8607
+ fs18.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
8608
+ fs18.renameSync(tmp, target);
8444
8609
  }
8445
8610
  function listJsonlFiles() {
8446
8611
  const root = PROJECTS_DIR();
8447
- if (!fs17.existsSync(root)) return [];
8612
+ if (!fs18.existsSync(root)) return [];
8448
8613
  const out = [];
8449
- for (const entry of fs17.readdirSync(root, { withFileTypes: true })) {
8614
+ for (const entry of fs18.readdirSync(root, { withFileTypes: true })) {
8450
8615
  if (!entry.isDirectory()) continue;
8451
- const projectDir = path19.join(root, entry.name);
8616
+ const projectDir = path20.join(root, entry.name);
8452
8617
  let inner;
8453
8618
  try {
8454
- inner = fs17.readdirSync(projectDir, { withFileTypes: true });
8619
+ inner = fs18.readdirSync(projectDir, { withFileTypes: true });
8455
8620
  } catch {
8456
8621
  continue;
8457
8622
  }
8458
8623
  for (const file of inner) {
8459
8624
  if (file.isFile() && file.name.endsWith(".jsonl")) {
8460
- out.push(path19.join(projectDir, file.name));
8625
+ out.push(path20.join(projectDir, file.name));
8461
8626
  }
8462
8627
  }
8463
8628
  }
@@ -8465,7 +8630,7 @@ function listJsonlFiles() {
8465
8630
  }
8466
8631
  function fileSize(p) {
8467
8632
  try {
8468
- return fs17.statSync(p).size;
8633
+ return fs18.statSync(p).size;
8469
8634
  } catch {
8470
8635
  return 0;
8471
8636
  }
@@ -8473,7 +8638,7 @@ function fileSize(p) {
8473
8638
  async function scanDelta(filePath, fromByte, onLine) {
8474
8639
  const size = fileSize(filePath);
8475
8640
  if (size <= fromByte) return fromByte;
8476
- const stream = fs17.createReadStream(filePath, {
8641
+ const stream = fs18.createReadStream(filePath, {
8477
8642
  start: fromByte,
8478
8643
  end: size - 1,
8479
8644
  highWaterMark: 64 * 1024
@@ -8585,7 +8750,7 @@ async function tickForensicBroadcast(offsets) {
8585
8750
  continue;
8586
8751
  }
8587
8752
  if (size <= offset) continue;
8588
- const sessionId = path19.basename(file, ".jsonl");
8753
+ const sessionId = path20.basename(file, ".jsonl");
8589
8754
  const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
8590
8755
  out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
8591
8756
  });
@@ -8644,7 +8809,7 @@ function emptyTick(uploadAs) {
8644
8809
  function readRawWatermarkPreservingOffsets() {
8645
8810
  let raw;
8646
8811
  try {
8647
- raw = fs17.readFileSync(WATERMARK_FILE(), "utf-8");
8812
+ raw = fs18.readFileSync(WATERMARK_FILE(), "utf-8");
8648
8813
  } catch {
8649
8814
  return null;
8650
8815
  }
@@ -8678,13 +8843,13 @@ async function runActualTick(wm) {
8678
8843
  if (!known) {
8679
8844
  let mtimeMs = 0;
8680
8845
  try {
8681
- mtimeMs = fs17.statSync(filePath).mtime.getTime();
8846
+ mtimeMs = fs18.statSync(filePath).mtime.getTime();
8682
8847
  } catch {
8683
8848
  continue;
8684
8849
  }
8685
8850
  if (mtimeMs >= watermarkCreatedAt) {
8686
8851
  filesNew++;
8687
- const sessionId2 = path19.basename(filePath, ".jsonl");
8852
+ const sessionId2 = path20.basename(filePath, ".jsonl");
8688
8853
  const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
8689
8854
  totalToolCalls++;
8690
8855
  toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
@@ -8702,7 +8867,7 @@ async function runActualTick(wm) {
8702
8867
  filesSkipped++;
8703
8868
  continue;
8704
8869
  }
8705
- const sessionId = path19.basename(filePath, ".jsonl");
8870
+ const sessionId = path20.basename(filePath, ".jsonl");
8706
8871
  const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
8707
8872
  totalToolCalls++;
8708
8873
  toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
@@ -8730,8 +8895,8 @@ var init_scan_watermark = __esm({
8730
8895
  "use strict";
8731
8896
  init_dlp();
8732
8897
  init_dist();
8733
- PROJECTS_DIR = () => path19.join(os16.homedir(), ".claude", "projects");
8734
- WATERMARK_FILE = () => path19.join(os16.homedir(), ".node9", "scan-watermark.json");
8898
+ PROJECTS_DIR = () => path20.join(os17.homedir(), ".claude", "projects");
8899
+ WATERMARK_FILE = () => path20.join(os17.homedir(), ".node9", "scan-watermark.json");
8735
8900
  MAX_LINE_BYTES = 2 * 1024 * 1024;
8736
8901
  WATERMARK_SCHEMA_VERSION = 2;
8737
8902
  LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
@@ -8746,10 +8911,10 @@ __export(scan_upload_history_exports, {
8746
8911
  parseSinceCutoff: () => parseSinceCutoff,
8747
8912
  runUploadHistory: () => runUploadHistory
8748
8913
  });
8749
- import fs18 from "fs";
8914
+ import fs19 from "fs";
8750
8915
  import https from "https";
8751
- import os17 from "os";
8752
- import path20 from "path";
8916
+ import os18 from "os";
8917
+ import path21 from "path";
8753
8918
  import chalk4 from "chalk";
8754
8919
  function emptySignals2() {
8755
8920
  return {
@@ -8784,40 +8949,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
8784
8949
  return now.getTime() - 90 * 864e5;
8785
8950
  }
8786
8951
  function* iterateJsonlFiles(cutoffMs) {
8787
- const projectsDir = path20.join(os17.homedir(), ".claude", "projects");
8952
+ const projectsDir = path21.join(os18.homedir(), ".claude", "projects");
8788
8953
  let dirs;
8789
8954
  try {
8790
- dirs = fs18.readdirSync(projectsDir);
8955
+ dirs = fs19.readdirSync(projectsDir);
8791
8956
  } catch {
8792
8957
  return;
8793
8958
  }
8794
8959
  for (const dir of dirs) {
8795
- const dirPath = path20.join(projectsDir, dir);
8960
+ const dirPath = path21.join(projectsDir, dir);
8796
8961
  let stats;
8797
8962
  try {
8798
- stats = fs18.statSync(dirPath);
8963
+ stats = fs19.statSync(dirPath);
8799
8964
  } catch {
8800
8965
  continue;
8801
8966
  }
8802
8967
  if (!stats.isDirectory()) continue;
8803
8968
  let files;
8804
8969
  try {
8805
- files = fs18.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8970
+ files = fs19.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8806
8971
  } catch {
8807
8972
  continue;
8808
8973
  }
8809
8974
  for (const file of files) {
8810
- const filePath = path20.join(dirPath, file);
8975
+ const filePath = path21.join(dirPath, file);
8811
8976
  let mtime = 0;
8812
8977
  try {
8813
- mtime = fs18.statSync(filePath).mtimeMs;
8978
+ mtime = fs19.statSync(filePath).mtimeMs;
8814
8979
  } catch {
8815
8980
  continue;
8816
8981
  }
8817
8982
  if (mtime < cutoffMs) continue;
8818
8983
  yield {
8819
8984
  filePath,
8820
- sessionId: path20.basename(file, ".jsonl"),
8985
+ sessionId: path21.basename(file, ".jsonl"),
8821
8986
  projectDir: dir
8822
8987
  };
8823
8988
  }
@@ -8870,7 +9035,7 @@ async function runUploadHistory(opts) {
8870
9035
  filesScanned++;
8871
9036
  let content;
8872
9037
  try {
8873
- content = fs18.readFileSync(filePath, "utf8");
9038
+ content = fs19.readFileSync(filePath, "utf8");
8874
9039
  } catch {
8875
9040
  continue;
8876
9041
  }
@@ -8956,10 +9121,10 @@ async function runUploadHistory(opts) {
8956
9121
  const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
8957
9122
  let username = "unknown";
8958
9123
  try {
8959
- username = os17.userInfo().username;
9124
+ username = os18.userInfo().username;
8960
9125
  } catch {
8961
9126
  }
8962
- const machineId = `${os17.hostname()}:${username}`;
9127
+ const machineId = `${os18.hostname()}:${username}`;
8963
9128
  await postJson(costUrl, creds.apiKey, {
8964
9129
  machineId,
8965
9130
  entries: dailyEntries
@@ -9033,9 +9198,9 @@ var init_scan_upload_history = __esm({
9033
9198
 
9034
9199
  // src/cli/commands/scan.ts
9035
9200
  import chalk5 from "chalk";
9036
- import fs19 from "fs";
9037
- import path21 from "path";
9038
- import os18 from "os";
9201
+ import fs20 from "fs";
9202
+ import path22 from "path";
9203
+ import os19 from "os";
9039
9204
  import stringWidth2 from "string-width";
9040
9205
  function claudeModelPrice(model) {
9041
9206
  const base = model.replace(/@.*$/, "").replace(/-\d{8}$/, "");
@@ -9262,14 +9427,14 @@ function buildRuleSources() {
9262
9427
  }
9263
9428
  function countScanFiles() {
9264
9429
  let total = 0;
9265
- const claudeDir = path21.join(os18.homedir(), ".claude", "projects");
9266
- if (fs19.existsSync(claudeDir)) {
9430
+ const claudeDir = path22.join(os19.homedir(), ".claude", "projects");
9431
+ if (fs20.existsSync(claudeDir)) {
9267
9432
  try {
9268
- for (const proj of fs19.readdirSync(claudeDir)) {
9269
- const p = path21.join(claudeDir, proj);
9433
+ for (const proj of fs20.readdirSync(claudeDir)) {
9434
+ const p = path22.join(claudeDir, proj);
9270
9435
  try {
9271
- if (!fs19.statSync(p).isDirectory()) continue;
9272
- total += fs19.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
9436
+ if (!fs20.statSync(p).isDirectory()) continue;
9437
+ total += fs20.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
9273
9438
  } catch {
9274
9439
  continue;
9275
9440
  }
@@ -9277,17 +9442,17 @@ function countScanFiles() {
9277
9442
  } catch {
9278
9443
  }
9279
9444
  }
9280
- const geminiDir = path21.join(os18.homedir(), ".gemini", "tmp");
9281
- if (fs19.existsSync(geminiDir)) {
9445
+ const geminiDir = path22.join(os19.homedir(), ".gemini", "tmp");
9446
+ if (fs20.existsSync(geminiDir)) {
9282
9447
  try {
9283
- for (const slug of fs19.readdirSync(geminiDir)) {
9284
- const p = path21.join(geminiDir, slug);
9448
+ for (const slug of fs20.readdirSync(geminiDir)) {
9449
+ const p = path22.join(geminiDir, slug);
9285
9450
  try {
9286
- if (!fs19.statSync(p).isDirectory()) continue;
9287
- const chatsDir = path21.join(p, "chats");
9288
- if (fs19.existsSync(chatsDir)) {
9451
+ if (!fs20.statSync(p).isDirectory()) continue;
9452
+ const chatsDir = path22.join(p, "chats");
9453
+ if (fs20.existsSync(chatsDir)) {
9289
9454
  try {
9290
- total += fs19.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
9455
+ total += fs20.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
9291
9456
  } catch {
9292
9457
  }
9293
9458
  }
@@ -9298,22 +9463,22 @@ function countScanFiles() {
9298
9463
  } catch {
9299
9464
  }
9300
9465
  }
9301
- const codexDir = path21.join(os18.homedir(), ".codex", "sessions");
9302
- if (fs19.existsSync(codexDir)) {
9466
+ const codexDir = path22.join(os19.homedir(), ".codex", "sessions");
9467
+ if (fs20.existsSync(codexDir)) {
9303
9468
  try {
9304
- for (const year of fs19.readdirSync(codexDir)) {
9305
- const yp = path21.join(codexDir, year);
9469
+ for (const year of fs20.readdirSync(codexDir)) {
9470
+ const yp = path22.join(codexDir, year);
9306
9471
  try {
9307
- if (!fs19.statSync(yp).isDirectory()) continue;
9308
- for (const month of fs19.readdirSync(yp)) {
9309
- const mp = path21.join(yp, month);
9472
+ if (!fs20.statSync(yp).isDirectory()) continue;
9473
+ for (const month of fs20.readdirSync(yp)) {
9474
+ const mp = path22.join(yp, month);
9310
9475
  try {
9311
- if (!fs19.statSync(mp).isDirectory()) continue;
9312
- for (const day of fs19.readdirSync(mp)) {
9313
- const dp = path21.join(mp, day);
9476
+ if (!fs20.statSync(mp).isDirectory()) continue;
9477
+ for (const day of fs20.readdirSync(mp)) {
9478
+ const dp = path22.join(mp, day);
9314
9479
  try {
9315
- if (!fs19.statSync(dp).isDirectory()) continue;
9316
- total += fs19.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
9480
+ if (!fs20.statSync(dp).isDirectory()) continue;
9481
+ total += fs20.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
9317
9482
  } catch {
9318
9483
  continue;
9319
9484
  }
@@ -9349,7 +9514,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9349
9514
  const sessionId = file.replace(/\.jsonl$/, "");
9350
9515
  let raw;
9351
9516
  try {
9352
- raw = fs19.readFileSync(path21.join(projPath, file), "utf-8");
9517
+ raw = fs20.readFileSync(path22.join(projPath, file), "utf-8");
9353
9518
  } catch {
9354
9519
  return;
9355
9520
  }
@@ -9401,7 +9566,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9401
9566
  if (block.type !== "tool_result") continue;
9402
9567
  const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
9403
9568
  if (filePath) {
9404
- const ext = path21.extname(filePath).toLowerCase();
9569
+ const ext = path22.extname(filePath).toLowerCase();
9405
9570
  if (CODE_EXTENSIONS.has(ext)) continue;
9406
9571
  }
9407
9572
  const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
@@ -9458,7 +9623,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9458
9623
  const rawCmd = String(input.command ?? "").trimStart();
9459
9624
  if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
9460
9625
  const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
9461
- const inputFileExt = inputFilePath ? path21.extname(inputFilePath).toLowerCase() : "";
9626
+ const inputFileExt = inputFilePath ? path22.extname(inputFilePath).toLowerCase() : "";
9462
9627
  if (CODE_EXTENSIONS.has(inputFileExt)) continue;
9463
9628
  const dlpMatch = scanArgs(input);
9464
9629
  if (dlpMatch) {
@@ -9555,19 +9720,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9555
9720
  }
9556
9721
  }
9557
9722
  function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
9558
- const projPath = path21.join(projectsDir, proj);
9723
+ const projPath = path22.join(projectsDir, proj);
9559
9724
  try {
9560
- if (!fs19.statSync(projPath).isDirectory()) return;
9725
+ if (!fs20.statSync(projPath).isDirectory()) return;
9561
9726
  } catch {
9562
9727
  return;
9563
9728
  }
9564
- const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(os18.homedir(), "~")).slice(
9729
+ const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(os19.homedir(), "~")).slice(
9565
9730
  0,
9566
9731
  40
9567
9732
  );
9568
9733
  let files;
9569
9734
  try {
9570
- files = fs19.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
9735
+ files = fs20.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
9571
9736
  } catch {
9572
9737
  return;
9573
9738
  }
@@ -9601,12 +9766,12 @@ function emptyClaudeScan() {
9601
9766
  };
9602
9767
  }
9603
9768
  function scanClaudeHistory(startDate, onProgress, onLine) {
9604
- const projectsDir = path21.join(os18.homedir(), ".claude", "projects");
9769
+ const projectsDir = path22.join(os19.homedir(), ".claude", "projects");
9605
9770
  const result = emptyClaudeScan();
9606
- if (!fs19.existsSync(projectsDir)) return result;
9771
+ if (!fs20.existsSync(projectsDir)) return result;
9607
9772
  let projDirs;
9608
9773
  try {
9609
- projDirs = fs19.readdirSync(projectsDir);
9774
+ projDirs = fs20.readdirSync(projectsDir);
9610
9775
  } catch {
9611
9776
  return result;
9612
9777
  }
@@ -9627,7 +9792,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
9627
9792
  return result;
9628
9793
  }
9629
9794
  function scanGeminiHistory(startDate, onProgress, onLine) {
9630
- const tmpDir = path21.join(os18.homedir(), ".gemini", "tmp");
9795
+ const tmpDir = path22.join(os19.homedir(), ".gemini", "tmp");
9631
9796
  const result = {
9632
9797
  filesScanned: 0,
9633
9798
  sessions: 0,
@@ -9642,33 +9807,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
9642
9807
  sessionsWithEarlySecrets: 0
9643
9808
  };
9644
9809
  const dedup = emptyScanDedup();
9645
- if (!fs19.existsSync(tmpDir)) return result;
9810
+ if (!fs20.existsSync(tmpDir)) return result;
9646
9811
  let slugDirs;
9647
9812
  try {
9648
- slugDirs = fs19.readdirSync(tmpDir);
9813
+ slugDirs = fs20.readdirSync(tmpDir);
9649
9814
  } catch {
9650
9815
  return result;
9651
9816
  }
9652
9817
  const ruleSources = buildRuleSources();
9653
9818
  for (const slug of slugDirs) {
9654
- const slugPath = path21.join(tmpDir, slug);
9819
+ const slugPath = path22.join(tmpDir, slug);
9655
9820
  try {
9656
- if (!fs19.statSync(slugPath).isDirectory()) continue;
9821
+ if (!fs20.statSync(slugPath).isDirectory()) continue;
9657
9822
  } catch {
9658
9823
  continue;
9659
9824
  }
9660
9825
  let projLabel = stripTerminalEscapes(slug).slice(0, 40);
9661
9826
  try {
9662
9827
  projLabel = stripTerminalEscapes(
9663
- fs19.readFileSync(path21.join(slugPath, ".project_root"), "utf-8").trim()
9664
- ).replace(os18.homedir(), "~").slice(0, 40);
9828
+ fs20.readFileSync(path22.join(slugPath, ".project_root"), "utf-8").trim()
9829
+ ).replace(os19.homedir(), "~").slice(0, 40);
9665
9830
  } catch {
9666
9831
  }
9667
- const chatsDir = path21.join(slugPath, "chats");
9668
- if (!fs19.existsSync(chatsDir)) continue;
9832
+ const chatsDir = path22.join(slugPath, "chats");
9833
+ if (!fs20.existsSync(chatsDir)) continue;
9669
9834
  let chatFiles;
9670
9835
  try {
9671
- chatFiles = fs19.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
9836
+ chatFiles = fs20.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
9672
9837
  } catch {
9673
9838
  continue;
9674
9839
  }
@@ -9678,7 +9843,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
9678
9843
  const sessionId = chatFile.replace(/\.json$/, "");
9679
9844
  let raw;
9680
9845
  try {
9681
- raw = fs19.readFileSync(path21.join(chatsDir, chatFile), "utf-8");
9846
+ raw = fs20.readFileSync(path22.join(chatsDir, chatFile), "utf-8");
9682
9847
  } catch {
9683
9848
  continue;
9684
9849
  }
@@ -9840,7 +10005,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
9840
10005
  return result;
9841
10006
  }
9842
10007
  function scanCodexHistory(startDate, onProgress, onLine) {
9843
- const sessionsBase = path21.join(os18.homedir(), ".codex", "sessions");
10008
+ const sessionsBase = path22.join(os19.homedir(), ".codex", "sessions");
9844
10009
  const result = {
9845
10010
  filesScanned: 0,
9846
10011
  sessions: 0,
@@ -9855,32 +10020,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
9855
10020
  sessionsWithEarlySecrets: 0
9856
10021
  };
9857
10022
  const dedup = emptyScanDedup();
9858
- if (!fs19.existsSync(sessionsBase)) return result;
10023
+ if (!fs20.existsSync(sessionsBase)) return result;
9859
10024
  const jsonlFiles = [];
9860
10025
  try {
9861
- for (const year of fs19.readdirSync(sessionsBase)) {
9862
- const yearPath = path21.join(sessionsBase, year);
10026
+ for (const year of fs20.readdirSync(sessionsBase)) {
10027
+ const yearPath = path22.join(sessionsBase, year);
9863
10028
  try {
9864
- if (!fs19.statSync(yearPath).isDirectory()) continue;
10029
+ if (!fs20.statSync(yearPath).isDirectory()) continue;
9865
10030
  } catch {
9866
10031
  continue;
9867
10032
  }
9868
- for (const month of fs19.readdirSync(yearPath)) {
9869
- const monthPath = path21.join(yearPath, month);
10033
+ for (const month of fs20.readdirSync(yearPath)) {
10034
+ const monthPath = path22.join(yearPath, month);
9870
10035
  try {
9871
- if (!fs19.statSync(monthPath).isDirectory()) continue;
10036
+ if (!fs20.statSync(monthPath).isDirectory()) continue;
9872
10037
  } catch {
9873
10038
  continue;
9874
10039
  }
9875
- for (const day of fs19.readdirSync(monthPath)) {
9876
- const dayPath = path21.join(monthPath, day);
10040
+ for (const day of fs20.readdirSync(monthPath)) {
10041
+ const dayPath = path22.join(monthPath, day);
9877
10042
  try {
9878
- if (!fs19.statSync(dayPath).isDirectory()) continue;
10043
+ if (!fs20.statSync(dayPath).isDirectory()) continue;
9879
10044
  } catch {
9880
10045
  continue;
9881
10046
  }
9882
- for (const file of fs19.readdirSync(dayPath)) {
9883
- if (file.endsWith(".jsonl")) jsonlFiles.push(path21.join(dayPath, file));
10047
+ for (const file of fs20.readdirSync(dayPath)) {
10048
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path22.join(dayPath, file));
9884
10049
  }
9885
10050
  }
9886
10051
  }
@@ -9894,7 +10059,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
9894
10059
  onProgress?.(result.filesScanned);
9895
10060
  let lines;
9896
10061
  try {
9897
- lines = fs19.readFileSync(filePath, "utf-8").split("\n");
10062
+ lines = fs20.readFileSync(filePath, "utf-8").split("\n");
9898
10063
  } catch {
9899
10064
  continue;
9900
10065
  }
@@ -9920,7 +10085,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
9920
10085
  sessionId = String(payload["id"] ?? filePath);
9921
10086
  startTime = String(payload["timestamp"] ?? "");
9922
10087
  const cwd = String(payload["cwd"] ?? "");
9923
- projLabel = stripTerminalEscapes(cwd.replace(os18.homedir(), "~")).slice(0, 40);
10088
+ projLabel = stripTerminalEscapes(cwd.replace(os19.homedir(), "~")).slice(0, 40);
9924
10089
  continue;
9925
10090
  }
9926
10091
  if (entry.type === "event_msg" && payload["type"] === "token_count") {
@@ -10073,17 +10238,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
10073
10238
  return result;
10074
10239
  }
10075
10240
  function scanShellConfig() {
10076
- const home = os18.homedir();
10241
+ const home = os19.homedir();
10077
10242
  const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
10078
- (f) => path21.join(home, f)
10243
+ (f) => path22.join(home, f)
10079
10244
  );
10080
10245
  const findings = [];
10081
10246
  const seen = /* @__PURE__ */ new Set();
10082
10247
  for (const filePath of configFiles) {
10083
- if (!fs19.existsSync(filePath)) continue;
10248
+ if (!fs20.existsSync(filePath)) continue;
10084
10249
  let lines;
10085
10250
  try {
10086
- lines = fs19.readFileSync(filePath, "utf-8").split("\n");
10251
+ lines = fs20.readFileSync(filePath, "utf-8").split("\n");
10087
10252
  } catch {
10088
10253
  continue;
10089
10254
  }
@@ -10797,7 +10962,8 @@ function registerScanCommand(program2) {
10797
10962
  " node9 is still worth running \u2014 it monitors every tool call in real time.\n"
10798
10963
  )
10799
10964
  );
10800
- } else {
10965
+ }
10966
+ {
10801
10967
  const totalRisky = totalFindings + scan.dlpFindings.length;
10802
10968
  const score = classifyScore(blast.score);
10803
10969
  const severityDisplay = score.band === "critical" ? chalk5.red.bold(score.label) : score.color(score.label);
@@ -10863,7 +11029,7 @@ function registerScanCommand(program2) {
10863
11029
  if (!drillDown) {
10864
11030
  const useInk2 = !options.classic;
10865
11031
  if (useInk2) {
10866
- const scanInkPath = path21.join(__dirname, "scan-ink.mjs");
11032
+ const scanInkPath = path22.join(__dirname, "scan-ink.mjs");
10867
11033
  const dynamicImport = new Function("id", "return import(id)");
10868
11034
  const mod = await dynamicImport(`file://${scanInkPath}`);
10869
11035
  const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
@@ -11281,8 +11447,8 @@ var init_suggestion_tracker = __esm({
11281
11447
  });
11282
11448
 
11283
11449
  // src/daemon/taint-store.ts
11284
- import fs20 from "fs";
11285
- import path22 from "path";
11450
+ import fs21 from "fs";
11451
+ import path23 from "path";
11286
11452
  var DEFAULT_TTL_MS, TaintStore;
11287
11453
  var init_taint_store = __esm({
11288
11454
  "src/daemon/taint-store.ts"() {
@@ -11351,9 +11517,9 @@ var init_taint_store = __esm({
11351
11517
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
11352
11518
  _resolve(filePath) {
11353
11519
  try {
11354
- return fs20.realpathSync.native(path22.resolve(filePath));
11520
+ return fs21.realpathSync.native(path23.resolve(filePath));
11355
11521
  } catch {
11356
- return path22.resolve(filePath);
11522
+ return path23.resolve(filePath);
11357
11523
  }
11358
11524
  }
11359
11525
  };
@@ -11470,14 +11636,14 @@ var init_session_history = __esm({
11470
11636
 
11471
11637
  // src/daemon/state.ts
11472
11638
  import net2 from "net";
11473
- import fs21 from "fs";
11474
- import path23 from "path";
11475
- import os19 from "os";
11639
+ import fs22 from "fs";
11640
+ import path24 from "path";
11641
+ import os20 from "os";
11476
11642
  import { randomUUID as randomUUID3 } from "crypto";
11477
11643
  function loadInsightCounts() {
11478
11644
  try {
11479
- if (!fs21.existsSync(INSIGHT_COUNTS_FILE)) return;
11480
- const data = JSON.parse(fs21.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
11645
+ if (!fs22.existsSync(INSIGHT_COUNTS_FILE)) return;
11646
+ const data = JSON.parse(fs22.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
11481
11647
  for (const [tool, count] of Object.entries(data)) {
11482
11648
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
11483
11649
  }
@@ -11516,23 +11682,23 @@ function markRejectionHandlerRegistered() {
11516
11682
  daemonRejectionHandlerRegistered = true;
11517
11683
  }
11518
11684
  function atomicWriteSync2(filePath, data, options) {
11519
- const dir = path23.dirname(filePath);
11520
- if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
11685
+ const dir = path24.dirname(filePath);
11686
+ if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
11521
11687
  const tmpPath = `${filePath}.${randomUUID3()}.tmp`;
11522
11688
  try {
11523
- fs21.writeFileSync(tmpPath, data, options);
11689
+ fs22.writeFileSync(tmpPath, data, options);
11524
11690
  } catch (err2) {
11525
11691
  try {
11526
- fs21.unlinkSync(tmpPath);
11692
+ fs22.unlinkSync(tmpPath);
11527
11693
  } catch {
11528
11694
  }
11529
11695
  throw err2;
11530
11696
  }
11531
11697
  try {
11532
- fs21.renameSync(tmpPath, filePath);
11698
+ fs22.renameSync(tmpPath, filePath);
11533
11699
  } catch (err2) {
11534
11700
  try {
11535
- fs21.unlinkSync(tmpPath);
11701
+ fs22.unlinkSync(tmpPath);
11536
11702
  } catch {
11537
11703
  }
11538
11704
  throw err2;
@@ -11556,16 +11722,16 @@ function appendAuditLog(data) {
11556
11722
  decision: data.decision,
11557
11723
  source: "daemon"
11558
11724
  };
11559
- const dir = path23.dirname(AUDIT_LOG_FILE);
11560
- if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
11561
- fs21.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
11725
+ const dir = path24.dirname(AUDIT_LOG_FILE);
11726
+ if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
11727
+ fs22.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
11562
11728
  } catch {
11563
11729
  }
11564
11730
  }
11565
11731
  function getAuditHistory(limit = 20) {
11566
11732
  try {
11567
- if (!fs21.existsSync(AUDIT_LOG_FILE)) return [];
11568
- const lines = fs21.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
11733
+ if (!fs22.existsSync(AUDIT_LOG_FILE)) return [];
11734
+ const lines = fs22.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
11569
11735
  if (lines.length === 1 && lines[0] === "") return [];
11570
11736
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
11571
11737
  } catch {
@@ -11574,7 +11740,7 @@ function getAuditHistory(limit = 20) {
11574
11740
  }
11575
11741
  function getOrgName() {
11576
11742
  try {
11577
- if (fs21.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11743
+ if (fs22.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11578
11744
  } catch {
11579
11745
  }
11580
11746
  return null;
@@ -11582,8 +11748,8 @@ function getOrgName() {
11582
11748
  function writeGlobalSetting(key, value) {
11583
11749
  let config = {};
11584
11750
  try {
11585
- if (fs21.existsSync(GLOBAL_CONFIG_FILE)) {
11586
- config = JSON.parse(fs21.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11751
+ if (fs22.existsSync(GLOBAL_CONFIG_FILE)) {
11752
+ config = JSON.parse(fs22.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11587
11753
  }
11588
11754
  } catch {
11589
11755
  }
@@ -11595,8 +11761,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11595
11761
  try {
11596
11762
  let trust = { entries: [] };
11597
11763
  try {
11598
- if (fs21.existsSync(TRUST_FILE2))
11599
- trust = JSON.parse(fs21.readFileSync(TRUST_FILE2, "utf-8"));
11764
+ if (fs22.existsSync(TRUST_FILE2))
11765
+ trust = JSON.parse(fs22.readFileSync(TRUST_FILE2, "utf-8"));
11600
11766
  } catch {
11601
11767
  }
11602
11768
  trust.entries = trust.entries.filter(
@@ -11613,8 +11779,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11613
11779
  }
11614
11780
  function readPersistentDecisions() {
11615
11781
  try {
11616
- if (fs21.existsSync(DECISIONS_FILE)) {
11617
- return JSON.parse(fs21.readFileSync(DECISIONS_FILE, "utf-8"));
11782
+ if (fs22.existsSync(DECISIONS_FILE)) {
11783
+ return JSON.parse(fs22.readFileSync(DECISIONS_FILE, "utf-8"));
11618
11784
  }
11619
11785
  } catch {
11620
11786
  }
@@ -11642,7 +11808,7 @@ function estimateToolCost(tool, args) {
11642
11808
  const filePath = a.file_path ?? a.path;
11643
11809
  if (filePath) {
11644
11810
  try {
11645
- const bytes = fs21.statSync(filePath).size;
11811
+ const bytes = fs22.statSync(filePath).size;
11646
11812
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
11647
11813
  } catch {
11648
11814
  }
@@ -11713,7 +11879,7 @@ function abandonPending() {
11713
11879
  });
11714
11880
  if (autoStarted) {
11715
11881
  try {
11716
- fs21.unlinkSync(DAEMON_PID_FILE);
11882
+ fs22.unlinkSync(DAEMON_PID_FILE);
11717
11883
  } catch {
11718
11884
  }
11719
11885
  setTimeout(() => {
@@ -11724,8 +11890,8 @@ function abandonPending() {
11724
11890
  }
11725
11891
  function logActivitySocket(msg) {
11726
11892
  try {
11727
- fs21.appendFileSync(
11728
- path23.join(homeDir, ".node9", "hook-debug.log"),
11893
+ fs22.appendFileSync(
11894
+ path24.join(homeDir, ".node9", "hook-debug.log"),
11729
11895
  `[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
11730
11896
  `
11731
11897
  );
@@ -11747,13 +11913,13 @@ function shouldRebind(now = Date.now()) {
11747
11913
  function startActivitySocket() {
11748
11914
  bindActivitySocket();
11749
11915
  activityHealthInterval = setInterval(() => {
11750
- if (!fs21.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11916
+ if (!fs22.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11751
11917
  }, ACTIVITY_HEALTH_PROBE_MS);
11752
11918
  activityHealthInterval.unref();
11753
11919
  process.on("exit", () => {
11754
11920
  if (activityHealthInterval) clearInterval(activityHealthInterval);
11755
11921
  try {
11756
- fs21.unlinkSync(ACTIVITY_SOCKET_PATH2);
11922
+ fs22.unlinkSync(ACTIVITY_SOCKET_PATH2);
11757
11923
  } catch {
11758
11924
  }
11759
11925
  });
@@ -11781,7 +11947,7 @@ function attemptRebind(reason) {
11781
11947
  }
11782
11948
  function bindActivitySocket() {
11783
11949
  try {
11784
- fs21.unlinkSync(ACTIVITY_SOCKET_PATH2);
11950
+ fs22.unlinkSync(ACTIVITY_SOCKET_PATH2);
11785
11951
  } catch {
11786
11952
  }
11787
11953
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
@@ -11894,14 +12060,14 @@ var init_state2 = __esm({
11894
12060
  init_taint_store();
11895
12061
  init_session_counters();
11896
12062
  init_session_history();
11897
- homeDir = os19.homedir();
11898
- DAEMON_PID_FILE = path23.join(homeDir, ".node9", "daemon.pid");
11899
- DECISIONS_FILE = path23.join(homeDir, ".node9", "decisions.json");
11900
- AUDIT_LOG_FILE = path23.join(homeDir, ".node9", "audit.log");
11901
- TRUST_FILE2 = path23.join(homeDir, ".node9", "trust.json");
11902
- GLOBAL_CONFIG_FILE = path23.join(homeDir, ".node9", "config.json");
11903
- CREDENTIALS_FILE = path23.join(homeDir, ".node9", "credentials.json");
11904
- INSIGHT_COUNTS_FILE = path23.join(homeDir, ".node9", "insight-counts.json");
12063
+ homeDir = os20.homedir();
12064
+ DAEMON_PID_FILE = path24.join(homeDir, ".node9", "daemon.pid");
12065
+ DECISIONS_FILE = path24.join(homeDir, ".node9", "decisions.json");
12066
+ AUDIT_LOG_FILE = path24.join(homeDir, ".node9", "audit.log");
12067
+ TRUST_FILE2 = path24.join(homeDir, ".node9", "trust.json");
12068
+ GLOBAL_CONFIG_FILE = path24.join(homeDir, ".node9", "config.json");
12069
+ CREDENTIALS_FILE = path24.join(homeDir, ".node9", "credentials.json");
12070
+ INSIGHT_COUNTS_FILE = path24.join(homeDir, ".node9", "insight-counts.json");
11905
12071
  pending = /* @__PURE__ */ new Map();
11906
12072
  sseClients = /* @__PURE__ */ new Set();
11907
12073
  suggestionTracker = new SuggestionTracker(3);
@@ -11918,7 +12084,7 @@ var init_state2 = __esm({
11918
12084
  "2h": 2 * 60 * 6e4
11919
12085
  };
11920
12086
  autoStarted = process.env.NODE9_AUTO_STARTED === "1";
11921
- ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path23.join(os19.tmpdir(), "node9-activity.sock");
12087
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path24.join(os20.tmpdir(), "node9-activity.sock");
11922
12088
  ACTIVITY_RING_SIZE = 100;
11923
12089
  activityRing = [];
11924
12090
  LARGE_RESPONSE_RING_SIZE = 20;
@@ -11957,10 +12123,10 @@ var init_state2 = __esm({
11957
12123
  });
11958
12124
 
11959
12125
  // src/daemon/sync.ts
11960
- import fs22 from "fs";
12126
+ import fs23 from "fs";
11961
12127
  import https2 from "https";
11962
- import os20 from "os";
11963
- import path24 from "path";
12128
+ import os21 from "os";
12129
+ import path25 from "path";
11964
12130
  function emptySignals3() {
11965
12131
  return {
11966
12132
  dlpFindings: 0,
@@ -12000,8 +12166,8 @@ function readCredentials() {
12000
12166
  };
12001
12167
  }
12002
12168
  try {
12003
- const credPath = path24.join(os20.homedir(), ".node9", "credentials.json");
12004
- const creds = JSON.parse(fs22.readFileSync(credPath, "utf-8"));
12169
+ const credPath = path25.join(os21.homedir(), ".node9", "credentials.json");
12170
+ const creds = JSON.parse(fs23.readFileSync(credPath, "utf-8"));
12005
12171
  const profileName = process.env.NODE9_PROFILE ?? "default";
12006
12172
  const profile = creds[profileName];
12007
12173
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -12027,7 +12193,7 @@ function readCredentials() {
12027
12193
  }
12028
12194
  function readCachedEtag() {
12029
12195
  try {
12030
- const raw = JSON.parse(fs22.readFileSync(rulesCacheFile(), "utf-8"));
12196
+ const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
12031
12197
  return typeof raw.etag === "string" ? raw.etag : void 0;
12032
12198
  } catch {
12033
12199
  return void 0;
@@ -12088,9 +12254,9 @@ function extractRules(body) {
12088
12254
  return [];
12089
12255
  }
12090
12256
  function writeCache2(cache) {
12091
- const dir = path24.dirname(rulesCacheFile());
12092
- if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
12093
- fs22.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
12257
+ const dir = path25.dirname(rulesCacheFile());
12258
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
12259
+ fs23.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
12094
12260
  }
12095
12261
  async function syncOnce() {
12096
12262
  const creds = readCredentials();
@@ -12247,7 +12413,7 @@ async function runCloudSync() {
12247
12413
  }
12248
12414
  function getCloudSyncStatus() {
12249
12415
  try {
12250
- const raw = JSON.parse(fs22.readFileSync(rulesCacheFile(), "utf-8"));
12416
+ const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
12251
12417
  if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
12252
12418
  return {
12253
12419
  cached: true,
@@ -12264,7 +12430,7 @@ function getCloudSyncStatus() {
12264
12430
  }
12265
12431
  function getCloudRules() {
12266
12432
  try {
12267
- const raw = JSON.parse(fs22.readFileSync(rulesCacheFile(), "utf-8"));
12433
+ const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
12268
12434
  return Array.isArray(raw.rules) ? raw.rules : null;
12269
12435
  } catch {
12270
12436
  return null;
@@ -12320,7 +12486,7 @@ var init_sync = __esm({
12320
12486
  loop: "loops",
12321
12487
  "long-output-redacted": "longOutputRedactions"
12322
12488
  };
12323
- rulesCacheFile = () => path24.join(os20.homedir(), ".node9", "rules-cache.json");
12489
+ rulesCacheFile = () => path25.join(os21.homedir(), ".node9", "rules-cache.json");
12324
12490
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
12325
12491
  DEFAULT_INTERVAL_HOURS = 5;
12326
12492
  MIN_INTERVAL_HOURS = 1;
@@ -12331,73 +12497,73 @@ var init_sync = __esm({
12331
12497
  });
12332
12498
 
12333
12499
  // src/daemon/dlp-scanner.ts
12334
- import fs23 from "fs";
12335
- import path25 from "path";
12336
- import os21 from "os";
12500
+ import fs24 from "fs";
12501
+ import path26 from "path";
12502
+ import os22 from "os";
12337
12503
  function loadIndex() {
12338
12504
  try {
12339
- return JSON.parse(fs23.readFileSync(INDEX_FILE, "utf-8"));
12505
+ return JSON.parse(fs24.readFileSync(INDEX_FILE, "utf-8"));
12340
12506
  } catch {
12341
12507
  return {};
12342
12508
  }
12343
12509
  }
12344
12510
  function saveIndex(index) {
12345
12511
  try {
12346
- fs23.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12512
+ fs24.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12347
12513
  } catch {
12348
12514
  }
12349
12515
  }
12350
12516
  function appendAuditEntry(entry) {
12351
12517
  try {
12352
- fs23.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12518
+ fs24.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12353
12519
  } catch {
12354
12520
  }
12355
12521
  }
12356
12522
  function runDlpScan() {
12357
- if (!fs23.existsSync(PROJECTS_DIR2)) return;
12523
+ if (!fs24.existsSync(PROJECTS_DIR2)) return;
12358
12524
  const index = loadIndex();
12359
12525
  let updated = false;
12360
12526
  let projDirs;
12361
12527
  try {
12362
- projDirs = fs23.readdirSync(PROJECTS_DIR2);
12528
+ projDirs = fs24.readdirSync(PROJECTS_DIR2);
12363
12529
  } catch {
12364
12530
  return;
12365
12531
  }
12366
12532
  for (const proj of projDirs) {
12367
- const projPath = path25.join(PROJECTS_DIR2, proj);
12533
+ const projPath = path26.join(PROJECTS_DIR2, proj);
12368
12534
  try {
12369
- if (!fs23.lstatSync(projPath).isDirectory()) continue;
12370
- const real = fs23.realpathSync(projPath);
12371
- if (!real.startsWith(PROJECTS_DIR2 + path25.sep) && real !== PROJECTS_DIR2) continue;
12535
+ if (!fs24.lstatSync(projPath).isDirectory()) continue;
12536
+ const real = fs24.realpathSync(projPath);
12537
+ if (!real.startsWith(PROJECTS_DIR2 + path26.sep) && real !== PROJECTS_DIR2) continue;
12372
12538
  } catch {
12373
12539
  continue;
12374
12540
  }
12375
12541
  let files;
12376
12542
  try {
12377
- files = fs23.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12543
+ files = fs24.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12378
12544
  } catch {
12379
12545
  continue;
12380
12546
  }
12381
12547
  for (const file of files) {
12382
- const filePath = path25.join(projPath, file);
12548
+ const filePath = path26.join(projPath, file);
12383
12549
  const lastOffset = index[filePath] ?? 0;
12384
12550
  let size;
12385
12551
  try {
12386
- size = fs23.statSync(filePath).size;
12552
+ size = fs24.statSync(filePath).size;
12387
12553
  } catch {
12388
12554
  continue;
12389
12555
  }
12390
12556
  if (size <= lastOffset) continue;
12391
12557
  let fd;
12392
12558
  try {
12393
- fd = fs23.openSync(filePath, "r");
12559
+ fd = fs24.openSync(filePath, "r");
12394
12560
  } catch {
12395
12561
  continue;
12396
12562
  }
12397
12563
  try {
12398
12564
  const chunkSize = size - lastOffset;
12399
12565
  const buf = Buffer.alloc(chunkSize);
12400
- fs23.readSync(fd, buf, 0, chunkSize, lastOffset);
12566
+ fs24.readSync(fd, buf, 0, chunkSize, lastOffset);
12401
12567
  const chunk = buf.toString("utf-8");
12402
12568
  for (const line of chunk.split("\n")) {
12403
12569
  if (!line.trim()) continue;
@@ -12417,7 +12583,7 @@ function runDlpScan() {
12417
12583
  if (typeof text !== "string") continue;
12418
12584
  const match = scanText(text);
12419
12585
  if (!match) continue;
12420
- const projLabel = decodeURIComponent(proj).replace(os21.homedir(), "~").slice(0, 40);
12586
+ const projLabel = decodeURIComponent(proj).replace(os22.homedir(), "~").slice(0, 40);
12421
12587
  const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
12422
12588
  appendAuditEntry({
12423
12589
  ts,
@@ -12442,7 +12608,7 @@ Run: node9 report --period 30d`
12442
12608
  updated = true;
12443
12609
  } finally {
12444
12610
  try {
12445
- fs23.closeSync(fd);
12611
+ fs24.closeSync(fd);
12446
12612
  } catch {
12447
12613
  }
12448
12614
  }
@@ -12475,23 +12641,23 @@ var init_dlp_scanner = __esm({
12475
12641
  init_dlp();
12476
12642
  init_native();
12477
12643
  init_state2();
12478
- INDEX_FILE = path25.join(os21.homedir(), ".node9", "dlp-index.json");
12479
- PROJECTS_DIR2 = path25.join(os21.homedir(), ".claude", "projects");
12644
+ INDEX_FILE = path26.join(os22.homedir(), ".node9", "dlp-index.json");
12645
+ PROJECTS_DIR2 = path26.join(os22.homedir(), ".claude", "projects");
12480
12646
  }
12481
12647
  });
12482
12648
 
12483
12649
  // src/daemon/mcp-tools.ts
12484
- import fs24 from "fs";
12485
- import path26 from "path";
12486
- import os22 from "os";
12650
+ import fs25 from "fs";
12651
+ import path27 from "path";
12652
+ import os23 from "os";
12487
12653
  function getMcpToolsFile() {
12488
- return path26.join(os22.homedir(), ".node9", "mcp-tools.json");
12654
+ return path27.join(os23.homedir(), ".node9", "mcp-tools.json");
12489
12655
  }
12490
12656
  function readMcpToolsConfig() {
12491
12657
  try {
12492
12658
  const file = getMcpToolsFile();
12493
- if (!fs24.existsSync(file)) return {};
12494
- const raw = fs24.readFileSync(file, "utf-8");
12659
+ if (!fs25.existsSync(file)) return {};
12660
+ const raw = fs25.readFileSync(file, "utf-8");
12495
12661
  return JSON.parse(raw);
12496
12662
  } catch {
12497
12663
  return {};
@@ -12500,11 +12666,11 @@ function readMcpToolsConfig() {
12500
12666
  function writeMcpToolsConfig(config) {
12501
12667
  try {
12502
12668
  const file = getMcpToolsFile();
12503
- const dir = path26.dirname(file);
12504
- if (!fs24.existsSync(dir)) fs24.mkdirSync(dir, { recursive: true });
12505
- const tmpPath = `${file}.${os22.hostname()}.${process.pid}.tmp`;
12506
- fs24.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
12507
- fs24.renameSync(tmpPath, file);
12669
+ const dir = path27.dirname(file);
12670
+ if (!fs25.existsSync(dir)) fs25.mkdirSync(dir, { recursive: true });
12671
+ const tmpPath = `${file}.${os23.hostname()}.${process.pid}.tmp`;
12672
+ fs25.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
12673
+ fs25.renameSync(tmpPath, file);
12508
12674
  } catch (e) {
12509
12675
  console.error("Failed to write mcp-tools.json", e);
12510
12676
  }
@@ -12551,9 +12717,9 @@ var init_mcp_tools = __esm({
12551
12717
 
12552
12718
  // src/daemon/server.ts
12553
12719
  import http from "http";
12554
- import fs25 from "fs";
12555
- import path27 from "path";
12556
- import os23 from "os";
12720
+ import fs26 from "fs";
12721
+ import path28 from "path";
12722
+ import os24 from "os";
12557
12723
  import { randomUUID as randomUUID4 } from "crypto";
12558
12724
  import { spawnSync } from "child_process";
12559
12725
  import chalk6 from "chalk";
@@ -12574,7 +12740,7 @@ function startDaemon() {
12574
12740
  idleTimer = setTimeout(() => {
12575
12741
  if (autoStarted) {
12576
12742
  try {
12577
- fs25.unlinkSync(DAEMON_PID_FILE);
12743
+ fs26.unlinkSync(DAEMON_PID_FILE);
12578
12744
  } catch {
12579
12745
  }
12580
12746
  }
@@ -12719,7 +12885,7 @@ data: ${JSON.stringify(item.data)}
12719
12885
  mcpServer: entry.mcpServer
12720
12886
  });
12721
12887
  }
12722
- const projectCwd = typeof cwd === "string" && path27.isAbsolute(cwd) ? cwd : void 0;
12888
+ const projectCwd = typeof cwd === "string" && path28.isAbsolute(cwd) ? cwd : void 0;
12723
12889
  const projectConfig = getConfig(projectCwd);
12724
12890
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
12725
12891
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -13011,8 +13177,8 @@ data: ${JSON.stringify(item.data)}
13011
13177
  if (!validToken(req)) return res.writeHead(403).end();
13012
13178
  const periodParam = reqUrl.searchParams.get("period") || "7d";
13013
13179
  const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
13014
- const logPath = path27.join(os23.homedir(), ".node9", "audit.log");
13015
- if (!fs25.existsSync(logPath)) {
13180
+ const logPath = path28.join(os24.homedir(), ".node9", "audit.log");
13181
+ if (!fs26.existsSync(logPath)) {
13016
13182
  res.writeHead(200, { "Content-Type": "application/json" });
13017
13183
  return res.end(
13018
13184
  JSON.stringify({
@@ -13025,7 +13191,7 @@ data: ${JSON.stringify(item.data)}
13025
13191
  );
13026
13192
  }
13027
13193
  try {
13028
- const raw = fs25.readFileSync(logPath, "utf-8");
13194
+ const raw = fs26.readFileSync(logPath, "utf-8");
13029
13195
  const allEntries = raw.split("\n").flatMap((line) => {
13030
13196
  if (!line.trim()) return [];
13031
13197
  try {
@@ -13348,14 +13514,14 @@ data: ${JSON.stringify(item.data)}
13348
13514
  server.on("error", (e) => {
13349
13515
  if (e.code === "EADDRINUSE") {
13350
13516
  try {
13351
- if (fs25.existsSync(DAEMON_PID_FILE)) {
13352
- const { pid } = JSON.parse(fs25.readFileSync(DAEMON_PID_FILE, "utf-8"));
13517
+ if (fs26.existsSync(DAEMON_PID_FILE)) {
13518
+ const { pid } = JSON.parse(fs26.readFileSync(DAEMON_PID_FILE, "utf-8"));
13353
13519
  process.kill(pid, 0);
13354
13520
  return process.exit(0);
13355
13521
  }
13356
13522
  } catch {
13357
13523
  try {
13358
- fs25.unlinkSync(DAEMON_PID_FILE);
13524
+ fs26.unlinkSync(DAEMON_PID_FILE);
13359
13525
  } catch {
13360
13526
  }
13361
13527
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -13443,15 +13609,15 @@ var init_server = __esm({
13443
13609
  });
13444
13610
 
13445
13611
  // src/daemon/service.ts
13446
- import fs26 from "fs";
13447
- import path28 from "path";
13448
- import os24 from "os";
13612
+ import fs27 from "fs";
13613
+ import path29 from "path";
13614
+ import os25 from "os";
13449
13615
  import { spawnSync as spawnSync2, execFileSync } from "child_process";
13450
13616
  function resolveNode9Binary() {
13451
13617
  try {
13452
13618
  const script = process.argv[1];
13453
- if (typeof script === "string" && path28.isAbsolute(script) && fs26.existsSync(script)) {
13454
- return fs26.realpathSync(script);
13619
+ if (typeof script === "string" && path29.isAbsolute(script) && fs27.existsSync(script)) {
13620
+ return fs27.realpathSync(script);
13455
13621
  }
13456
13622
  } catch {
13457
13623
  }
@@ -13469,11 +13635,11 @@ function xmlEscape(s) {
13469
13635
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13470
13636
  }
13471
13637
  function launchdPlist(binaryPath) {
13472
- const logDir = path28.join(os24.homedir(), ".node9");
13638
+ const logDir = path29.join(os25.homedir(), ".node9");
13473
13639
  const nodePath = xmlEscape(process.execPath);
13474
13640
  const scriptPath = xmlEscape(binaryPath);
13475
- const outLog = xmlEscape(path28.join(logDir, "daemon.log"));
13476
- const errLog = xmlEscape(path28.join(logDir, "daemon-error.log"));
13641
+ const outLog = xmlEscape(path29.join(logDir, "daemon.log"));
13642
+ const errLog = xmlEscape(path29.join(logDir, "daemon-error.log"));
13477
13643
  return `<?xml version="1.0" encoding="UTF-8"?>
13478
13644
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
13479
13645
  <plist version="1.0">
@@ -13506,9 +13672,9 @@ function launchdPlist(binaryPath) {
13506
13672
  `;
13507
13673
  }
13508
13674
  function installLaunchd(binaryPath) {
13509
- const dir = path28.dirname(LAUNCHD_PLIST);
13510
- if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
13511
- fs26.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
13675
+ const dir = path29.dirname(LAUNCHD_PLIST);
13676
+ if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
13677
+ fs27.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
13512
13678
  spawnSync2("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
13513
13679
  const r = spawnSync2("launchctl", ["load", "-w", LAUNCHD_PLIST], {
13514
13680
  encoding: "utf8",
@@ -13519,13 +13685,13 @@ function installLaunchd(binaryPath) {
13519
13685
  }
13520
13686
  }
13521
13687
  function uninstallLaunchd() {
13522
- if (fs26.existsSync(LAUNCHD_PLIST)) {
13688
+ if (fs27.existsSync(LAUNCHD_PLIST)) {
13523
13689
  spawnSync2("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
13524
- fs26.unlinkSync(LAUNCHD_PLIST);
13690
+ fs27.unlinkSync(LAUNCHD_PLIST);
13525
13691
  }
13526
13692
  }
13527
13693
  function isLaunchdInstalled() {
13528
- return fs26.existsSync(LAUNCHD_PLIST);
13694
+ return fs27.existsSync(LAUNCHD_PLIST);
13529
13695
  }
13530
13696
  function systemdUnit(binaryPath) {
13531
13697
  return `[Unit]
@@ -13544,12 +13710,12 @@ WantedBy=default.target
13544
13710
  `;
13545
13711
  }
13546
13712
  function installSystemd(binaryPath) {
13547
- if (!fs26.existsSync(SYSTEMD_UNIT_DIR)) {
13548
- fs26.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13713
+ if (!fs27.existsSync(SYSTEMD_UNIT_DIR)) {
13714
+ fs27.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13549
13715
  }
13550
- fs26.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13716
+ fs27.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13551
13717
  try {
13552
- execFileSync("loginctl", ["enable-linger", os24.userInfo().username], { timeout: 3e3 });
13718
+ execFileSync("loginctl", ["enable-linger", os25.userInfo().username], { timeout: 3e3 });
13553
13719
  } catch {
13554
13720
  }
13555
13721
  const reload = spawnSync2("systemctl", ["--user", "daemon-reload"], {
@@ -13569,23 +13735,23 @@ function installSystemd(binaryPath) {
13569
13735
  }
13570
13736
  }
13571
13737
  function uninstallSystemd() {
13572
- if (fs26.existsSync(SYSTEMD_UNIT)) {
13738
+ if (fs27.existsSync(SYSTEMD_UNIT)) {
13573
13739
  spawnSync2("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
13574
13740
  encoding: "utf8",
13575
13741
  timeout: 5e3
13576
13742
  });
13577
13743
  spawnSync2("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
13578
- fs26.unlinkSync(SYSTEMD_UNIT);
13744
+ fs27.unlinkSync(SYSTEMD_UNIT);
13579
13745
  }
13580
13746
  }
13581
13747
  function isSystemdInstalled() {
13582
- return fs26.existsSync(SYSTEMD_UNIT);
13748
+ return fs27.existsSync(SYSTEMD_UNIT);
13583
13749
  }
13584
13750
  function stopRunningDaemon() {
13585
- const pidFile = path28.join(os24.homedir(), ".node9", "daemon.pid");
13586
- if (!fs26.existsSync(pidFile)) return;
13751
+ const pidFile = path29.join(os25.homedir(), ".node9", "daemon.pid");
13752
+ if (!fs27.existsSync(pidFile)) return;
13587
13753
  try {
13588
- const data = JSON.parse(fs26.readFileSync(pidFile, "utf-8"));
13754
+ const data = JSON.parse(fs27.readFileSync(pidFile, "utf-8"));
13589
13755
  const pid = data.pid;
13590
13756
  const MAX_PID2 = 4194304;
13591
13757
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -13605,7 +13771,7 @@ function stopRunningDaemon() {
13605
13771
  }
13606
13772
  }
13607
13773
  try {
13608
- fs26.unlinkSync(pidFile);
13774
+ fs27.unlinkSync(pidFile);
13609
13775
  } catch {
13610
13776
  }
13611
13777
  } catch {
@@ -13680,19 +13846,19 @@ var init_service = __esm({
13680
13846
  "src/daemon/service.ts"() {
13681
13847
  "use strict";
13682
13848
  LAUNCHD_LABEL = "ai.node9.daemon";
13683
- LAUNCHD_PLIST = path28.join(os24.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
13684
- SYSTEMD_UNIT_DIR = path28.join(os24.homedir(), ".config", "systemd", "user");
13685
- SYSTEMD_UNIT = path28.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
13849
+ LAUNCHD_PLIST = path29.join(os25.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
13850
+ SYSTEMD_UNIT_DIR = path29.join(os25.homedir(), ".config", "systemd", "user");
13851
+ SYSTEMD_UNIT = path29.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
13686
13852
  }
13687
13853
  });
13688
13854
 
13689
13855
  // src/daemon/index.ts
13690
- import fs27 from "fs";
13856
+ import fs28 from "fs";
13691
13857
  import chalk7 from "chalk";
13692
13858
  function stopDaemon() {
13693
- if (!fs27.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
13859
+ if (!fs28.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
13694
13860
  try {
13695
- const data = JSON.parse(fs27.readFileSync(DAEMON_PID_FILE, "utf-8"));
13861
+ const data = JSON.parse(fs28.readFileSync(DAEMON_PID_FILE, "utf-8"));
13696
13862
  const pid = data.pid;
13697
13863
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
13698
13864
  console.log(chalk7.gray("Cleaned up invalid PID file."));
@@ -13704,7 +13870,7 @@ function stopDaemon() {
13704
13870
  console.log(chalk7.gray("Cleaned up stale PID file."));
13705
13871
  } finally {
13706
13872
  try {
13707
- fs27.unlinkSync(DAEMON_PID_FILE);
13873
+ fs28.unlinkSync(DAEMON_PID_FILE);
13708
13874
  } catch {
13709
13875
  }
13710
13876
  }
@@ -13713,9 +13879,9 @@ function daemonStatus() {
13713
13879
  const serviceInstalled = isDaemonServiceInstalled();
13714
13880
  const serviceLabel = serviceInstalled ? chalk7.green("installed (starts on login)") : chalk7.yellow("not installed \u2014 run: node9 daemon install");
13715
13881
  let processStatus;
13716
- if (fs27.existsSync(DAEMON_PID_FILE)) {
13882
+ if (fs28.existsSync(DAEMON_PID_FILE)) {
13717
13883
  try {
13718
- const data = JSON.parse(fs27.readFileSync(DAEMON_PID_FILE, "utf-8"));
13884
+ const data = JSON.parse(fs28.readFileSync(DAEMON_PID_FILE, "utf-8"));
13719
13885
  const pid = data.pid;
13720
13886
  const port = data.port;
13721
13887
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -13760,7 +13926,7 @@ __export(tail_exports, {
13760
13926
  });
13761
13927
  import http2 from "http";
13762
13928
  import chalk29 from "chalk";
13763
- import fs45 from "fs";
13929
+ import fs46 from "fs";
13764
13930
  import os41 from "os";
13765
13931
  import path47 from "path";
13766
13932
  import readline6 from "readline";
@@ -13787,19 +13953,19 @@ function getModelContextLimit(model) {
13787
13953
  }
13788
13954
  function readSessionUsage() {
13789
13955
  const projectsDir = path47.join(os41.homedir(), ".claude", "projects");
13790
- if (!fs45.existsSync(projectsDir)) return null;
13956
+ if (!fs46.existsSync(projectsDir)) return null;
13791
13957
  let latestFile = null;
13792
13958
  let latestMtime = 0;
13793
13959
  try {
13794
- for (const dir of fs45.readdirSync(projectsDir)) {
13960
+ for (const dir of fs46.readdirSync(projectsDir)) {
13795
13961
  const dirPath = path47.join(projectsDir, dir);
13796
13962
  try {
13797
- if (!fs45.statSync(dirPath).isDirectory()) continue;
13798
- for (const file of fs45.readdirSync(dirPath)) {
13963
+ if (!fs46.statSync(dirPath).isDirectory()) continue;
13964
+ for (const file of fs46.readdirSync(dirPath)) {
13799
13965
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
13800
13966
  const filePath = path47.join(dirPath, file);
13801
13967
  try {
13802
- const mtime = fs45.statSync(filePath).mtimeMs;
13968
+ const mtime = fs46.statSync(filePath).mtimeMs;
13803
13969
  if (mtime > latestMtime) {
13804
13970
  latestMtime = mtime;
13805
13971
  latestFile = filePath;
@@ -13814,7 +13980,7 @@ function readSessionUsage() {
13814
13980
  }
13815
13981
  if (!latestFile) return null;
13816
13982
  try {
13817
- const lines = fs45.readFileSync(latestFile, "utf-8").split("\n");
13983
+ const lines = fs46.readFileSync(latestFile, "utf-8").split("\n");
13818
13984
  let lastModel = "";
13819
13985
  let lastInput = 0;
13820
13986
  let lastOutput = 0;
@@ -13914,9 +14080,9 @@ function renderPending(activity) {
13914
14080
  }
13915
14081
  async function ensureDaemon() {
13916
14082
  let pidPort = null;
13917
- if (fs45.existsSync(PID_FILE)) {
14083
+ if (fs46.existsSync(PID_FILE)) {
13918
14084
  try {
13919
- const { port } = JSON.parse(fs45.readFileSync(PID_FILE, "utf-8"));
14085
+ const { port } = JSON.parse(fs46.readFileSync(PID_FILE, "utf-8"));
13920
14086
  pidPort = port;
13921
14087
  } catch {
13922
14088
  console.error(chalk29.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -14074,7 +14240,7 @@ function buildRecoveryCardLines(req) {
14074
14240
  function readApproversFromDisk() {
14075
14241
  const configPath = path47.join(os41.homedir(), ".node9", "config.json");
14076
14242
  try {
14077
- const raw = JSON.parse(fs45.readFileSync(configPath, "utf-8"));
14243
+ const raw = JSON.parse(fs46.readFileSync(configPath, "utf-8"));
14078
14244
  const settings = raw.settings ?? {};
14079
14245
  return settings.approvers ?? {};
14080
14246
  } catch {
@@ -14092,13 +14258,13 @@ function approverStatusLine() {
14092
14258
  function toggleApprover(channel) {
14093
14259
  const configPath = path47.join(os41.homedir(), ".node9", "config.json");
14094
14260
  try {
14095
- const raw = JSON.parse(fs45.readFileSync(configPath, "utf-8"));
14261
+ const raw = JSON.parse(fs46.readFileSync(configPath, "utf-8"));
14096
14262
  const settings = raw.settings ?? {};
14097
14263
  const approvers = settings.approvers ?? {};
14098
14264
  approvers[channel] = approvers[channel] === false;
14099
14265
  settings.approvers = approvers;
14100
14266
  raw.settings = settings;
14101
- fs45.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14267
+ fs46.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14102
14268
  } catch (err2) {
14103
14269
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
14104
14270
  `);
@@ -14270,7 +14436,7 @@ async function startTail(options = {}) {
14270
14436
  }
14271
14437
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
14272
14438
  try {
14273
- fs45.appendFileSync(
14439
+ fs46.appendFileSync(
14274
14440
  path47.join(os41.homedir(), ".node9", "hook-debug.log"),
14275
14441
  `[tail] POST /decision failed: ${String(err2)}
14276
14442
  `
@@ -14337,7 +14503,7 @@ async function startTail(options = {}) {
14337
14503
  }
14338
14504
  const auditLog = path47.join(os41.homedir(), ".node9", "audit.log");
14339
14505
  try {
14340
- const unackedDlp = fs45.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14506
+ const unackedDlp = fs46.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14341
14507
  if (unackedDlp > 0) {
14342
14508
  console.log("");
14343
14509
  console.log(
@@ -14377,7 +14543,7 @@ async function startTail(options = {}) {
14377
14543
  if (stallWarned) return;
14378
14544
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
14379
14545
  try {
14380
- const auditMtime = fs45.statSync(auditLog).mtimeMs;
14546
+ const auditMtime = fs46.statSync(auditLog).mtimeMs;
14381
14547
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
14382
14548
  console.log("");
14383
14549
  console.log(
@@ -14616,7 +14782,7 @@ __export(hud_exports, {
14616
14782
  main: () => main,
14617
14783
  renderEnvironmentLine: () => renderEnvironmentLine
14618
14784
  });
14619
- import fs46 from "fs";
14785
+ import fs47 from "fs";
14620
14786
  import path48 from "path";
14621
14787
  import os42 from "os";
14622
14788
  import http3 from "http";
@@ -14694,9 +14860,9 @@ function formatTimeLeft(resetsAt) {
14694
14860
  return ` (${m}m left)`;
14695
14861
  }
14696
14862
  function safeReadJson(filePath) {
14697
- if (!fs46.existsSync(filePath)) return null;
14863
+ if (!fs47.existsSync(filePath)) return null;
14698
14864
  try {
14699
- return JSON.parse(fs46.readFileSync(filePath, "utf-8"));
14865
+ return JSON.parse(fs47.readFileSync(filePath, "utf-8"));
14700
14866
  } catch {
14701
14867
  return null;
14702
14868
  }
@@ -14717,10 +14883,10 @@ function countHooksInFile(filePath) {
14717
14883
  return Object.keys(cfg.hooks).length;
14718
14884
  }
14719
14885
  function countRulesInDir(rulesDir) {
14720
- if (!fs46.existsSync(rulesDir)) return 0;
14886
+ if (!fs47.existsSync(rulesDir)) return 0;
14721
14887
  let count = 0;
14722
14888
  try {
14723
- for (const entry of fs46.readdirSync(rulesDir, { withFileTypes: true })) {
14889
+ for (const entry of fs47.readdirSync(rulesDir, { withFileTypes: true })) {
14724
14890
  if (entry.isDirectory()) {
14725
14891
  count += countRulesInDir(path48.join(rulesDir, entry.name));
14726
14892
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -14746,7 +14912,7 @@ function countConfigs(cwd) {
14746
14912
  let hooksCount = 0;
14747
14913
  const userMcpServers = /* @__PURE__ */ new Set();
14748
14914
  const projectMcpServers = /* @__PURE__ */ new Set();
14749
- if (fs46.existsSync(path48.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14915
+ if (fs47.existsSync(path48.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14750
14916
  rulesCount += countRulesInDir(path48.join(claudeDir, "rules"));
14751
14917
  const userSettings = path48.join(claudeDir, "settings.json");
14752
14918
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
@@ -14757,18 +14923,18 @@ function countConfigs(cwd) {
14757
14923
  userMcpServers.delete(name);
14758
14924
  }
14759
14925
  if (cwd) {
14760
- if (fs46.existsSync(path48.join(cwd, "CLAUDE.md"))) claudeMdCount++;
14761
- if (fs46.existsSync(path48.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
14926
+ if (fs47.existsSync(path48.join(cwd, "CLAUDE.md"))) claudeMdCount++;
14927
+ if (fs47.existsSync(path48.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
14762
14928
  const projectClaudeDir = path48.join(cwd, ".claude");
14763
14929
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
14764
14930
  if (!overlapsUserScope) {
14765
- if (fs46.existsSync(path48.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14931
+ if (fs47.existsSync(path48.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14766
14932
  rulesCount += countRulesInDir(path48.join(projectClaudeDir, "rules"));
14767
14933
  const projSettings = path48.join(projectClaudeDir, "settings.json");
14768
14934
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
14769
14935
  hooksCount += countHooksInFile(projSettings);
14770
14936
  }
14771
- if (fs46.existsSync(path48.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14937
+ if (fs47.existsSync(path48.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14772
14938
  const localSettings = path48.join(projectClaudeDir, "settings.local.json");
14773
14939
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
14774
14940
  hooksCount += countHooksInFile(localSettings);
@@ -14806,11 +14972,11 @@ function readActiveShieldsHud() {
14806
14972
  }
14807
14973
  try {
14808
14974
  const shieldsPath = path48.join(os42.homedir(), ".node9", "shields.json");
14809
- if (!fs46.existsSync(shieldsPath)) {
14975
+ if (!fs47.existsSync(shieldsPath)) {
14810
14976
  shieldsCache = { value: [], ts: now };
14811
14977
  return [];
14812
14978
  }
14813
- const parsed = JSON.parse(fs46.readFileSync(shieldsPath, "utf-8"));
14979
+ const parsed = JSON.parse(fs47.readFileSync(shieldsPath, "utf-8"));
14814
14980
  if (!Array.isArray(parsed.active)) {
14815
14981
  shieldsCache = { value: [], ts: now };
14816
14982
  return [];
@@ -14912,17 +15078,17 @@ function renderContextLine(stdin) {
14912
15078
  async function main() {
14913
15079
  try {
14914
15080
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
14915
- if (fs46.existsSync(path48.join(os42.homedir(), ".node9", "hud-debug"))) {
15081
+ if (fs47.existsSync(path48.join(os42.homedir(), ".node9", "hud-debug"))) {
14916
15082
  try {
14917
15083
  const logPath = path48.join(os42.homedir(), ".node9", "hud-debug.log");
14918
15084
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
14919
15085
  let size = 0;
14920
15086
  try {
14921
- size = fs46.statSync(logPath).size;
15087
+ size = fs47.statSync(logPath).size;
14922
15088
  } catch {
14923
15089
  }
14924
15090
  if (size < MAX_LOG_SIZE) {
14925
- fs46.appendFileSync(
15091
+ fs47.appendFileSync(
14926
15092
  logPath,
14927
15093
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
14928
15094
  );
@@ -14946,8 +15112,8 @@ async function main() {
14946
15112
  path48.join(cwd, "node9.config.json"),
14947
15113
  path48.join(os42.homedir(), ".node9", "config.json")
14948
15114
  ]) {
14949
- if (!fs46.existsSync(configPath)) continue;
14950
- const cfg = JSON.parse(fs46.readFileSync(configPath, "utf-8"));
15115
+ if (!fs47.existsSync(configPath)) continue;
15116
+ const cfg = JSON.parse(fs47.readFileSync(configPath, "utf-8"));
14951
15117
  const hud = cfg.settings?.hud;
14952
15118
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
14953
15119
  }
@@ -14994,7 +15160,7 @@ init_setup();
14994
15160
  init_daemon2();
14995
15161
  import { Command } from "commander";
14996
15162
  import chalk30 from "chalk";
14997
- import fs47 from "fs";
15163
+ import fs48 from "fs";
14998
15164
  import path49 from "path";
14999
15165
  import os43 from "os";
15000
15166
  import { confirm as confirm2 } from "@inquirer/prompts";
@@ -15179,17 +15345,17 @@ async function runProxy(targetCommand) {
15179
15345
  // src/cli/daemon-starter.ts
15180
15346
  init_daemon();
15181
15347
  import { spawn as spawn3 } from "child_process";
15182
- import path29 from "path";
15183
- import fs28 from "fs";
15348
+ import path30 from "path";
15349
+ import fs29 from "fs";
15184
15350
  function isTestingMode() {
15185
15351
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
15186
15352
  }
15187
15353
  async function autoStartDaemonAndWait() {
15188
15354
  if (isTestingMode()) return false;
15189
- if (!path29.isAbsolute(process.argv[1])) return false;
15355
+ if (!path30.isAbsolute(process.argv[1])) return false;
15190
15356
  let resolvedArgv1;
15191
15357
  try {
15192
- resolvedArgv1 = fs28.realpathSync(process.argv[1]);
15358
+ resolvedArgv1 = fs29.realpathSync(process.argv[1]);
15193
15359
  } catch {
15194
15360
  return false;
15195
15361
  }
@@ -15220,19 +15386,19 @@ init_daemon();
15220
15386
  init_config();
15221
15387
  init_policy();
15222
15388
  import chalk9 from "chalk";
15223
- import fs31 from "fs";
15389
+ import fs32 from "fs";
15224
15390
  import { spawn as spawn5 } from "child_process";
15225
- import path32 from "path";
15226
- import os27 from "os";
15391
+ import path33 from "path";
15392
+ import os28 from "os";
15227
15393
 
15228
15394
  // src/undo.ts
15229
15395
  import { spawnSync as spawnSync3, spawn as spawn4 } from "child_process";
15230
- import crypto3 from "crypto";
15231
- import fs29 from "fs";
15396
+ import crypto4 from "crypto";
15397
+ import fs30 from "fs";
15232
15398
  import net3 from "net";
15233
- import path30 from "path";
15234
- import os25 from "os";
15235
- var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path30.join(os25.tmpdir(), "node9-activity.sock");
15399
+ import path31 from "path";
15400
+ import os26 from "os";
15401
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path31.join(os26.tmpdir(), "node9-activity.sock");
15236
15402
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15237
15403
  try {
15238
15404
  const payload = JSON.stringify({
@@ -15252,22 +15418,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15252
15418
  } catch {
15253
15419
  }
15254
15420
  }
15255
- var SNAPSHOT_STACK_PATH = path30.join(os25.homedir(), ".node9", "snapshots.json");
15256
- var UNDO_LATEST_PATH = path30.join(os25.homedir(), ".node9", "undo_latest.txt");
15421
+ var SNAPSHOT_STACK_PATH = path31.join(os26.homedir(), ".node9", "snapshots.json");
15422
+ var UNDO_LATEST_PATH = path31.join(os26.homedir(), ".node9", "undo_latest.txt");
15257
15423
  var MAX_SNAPSHOTS = 10;
15258
15424
  var GIT_TIMEOUT = 15e3;
15259
15425
  function readStack() {
15260
15426
  try {
15261
- if (fs29.existsSync(SNAPSHOT_STACK_PATH))
15262
- return JSON.parse(fs29.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15427
+ if (fs30.existsSync(SNAPSHOT_STACK_PATH))
15428
+ return JSON.parse(fs30.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15263
15429
  } catch {
15264
15430
  }
15265
15431
  return [];
15266
15432
  }
15267
15433
  function writeStack(stack) {
15268
- const dir = path30.dirname(SNAPSHOT_STACK_PATH);
15269
- if (!fs29.existsSync(dir)) fs29.mkdirSync(dir, { recursive: true });
15270
- fs29.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
15434
+ const dir = path31.dirname(SNAPSHOT_STACK_PATH);
15435
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
15436
+ fs30.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
15271
15437
  }
15272
15438
  function extractFilePath(args) {
15273
15439
  if (!args || typeof args !== "object") return null;
@@ -15287,12 +15453,12 @@ function buildArgsSummary(tool, args) {
15287
15453
  return "";
15288
15454
  }
15289
15455
  function findProjectRoot(filePath) {
15290
- let dir = path30.dirname(filePath);
15456
+ let dir = path31.dirname(filePath);
15291
15457
  while (true) {
15292
- if (fs29.existsSync(path30.join(dir, ".git")) || fs29.existsSync(path30.join(dir, "package.json"))) {
15458
+ if (fs30.existsSync(path31.join(dir, ".git")) || fs30.existsSync(path31.join(dir, "package.json"))) {
15293
15459
  return dir;
15294
15460
  }
15295
- const parent = path30.dirname(dir);
15461
+ const parent = path31.dirname(dir);
15296
15462
  if (parent === dir) return process.cwd();
15297
15463
  dir = parent;
15298
15464
  }
@@ -15300,7 +15466,7 @@ function findProjectRoot(filePath) {
15300
15466
  function normalizeCwdForHash(cwd) {
15301
15467
  let normalized;
15302
15468
  try {
15303
- normalized = fs29.realpathSync(cwd);
15469
+ normalized = fs30.realpathSync(cwd);
15304
15470
  } catch {
15305
15471
  normalized = cwd;
15306
15472
  }
@@ -15309,17 +15475,17 @@ function normalizeCwdForHash(cwd) {
15309
15475
  return normalized;
15310
15476
  }
15311
15477
  function getShadowRepoDir(cwd) {
15312
- const hash = crypto3.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
15313
- return path30.join(os25.homedir(), ".node9", "snapshots", hash);
15478
+ const hash = crypto4.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
15479
+ return path31.join(os26.homedir(), ".node9", "snapshots", hash);
15314
15480
  }
15315
15481
  function cleanOrphanedIndexFiles(shadowDir) {
15316
15482
  try {
15317
15483
  const cutoff = Date.now() - 6e4;
15318
- for (const f of fs29.readdirSync(shadowDir)) {
15484
+ for (const f of fs30.readdirSync(shadowDir)) {
15319
15485
  if (f.startsWith("index_")) {
15320
- const fp = path30.join(shadowDir, f);
15486
+ const fp = path31.join(shadowDir, f);
15321
15487
  try {
15322
- if (fs29.statSync(fp).mtimeMs < cutoff) fs29.unlinkSync(fp);
15488
+ if (fs30.statSync(fp).mtimeMs < cutoff) fs30.unlinkSync(fp);
15323
15489
  } catch {
15324
15490
  }
15325
15491
  }
@@ -15331,7 +15497,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
15331
15497
  const hardcoded = [".git", ".node9"];
15332
15498
  const lines = [...hardcoded, ...ignorePaths].join("\n");
15333
15499
  try {
15334
- fs29.writeFileSync(path30.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15500
+ fs30.writeFileSync(path31.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15335
15501
  } catch {
15336
15502
  }
15337
15503
  }
@@ -15344,25 +15510,25 @@ function ensureShadowRepo(shadowDir, cwd) {
15344
15510
  timeout: 3e3
15345
15511
  });
15346
15512
  if (check.status === 0) {
15347
- const ptPath = path30.join(shadowDir, "project-path.txt");
15513
+ const ptPath = path31.join(shadowDir, "project-path.txt");
15348
15514
  try {
15349
- const stored = fs29.readFileSync(ptPath, "utf8").trim();
15515
+ const stored = fs30.readFileSync(ptPath, "utf8").trim();
15350
15516
  if (stored === normalizedCwd) return true;
15351
15517
  if (process.env.NODE9_DEBUG === "1")
15352
15518
  console.error(
15353
15519
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
15354
15520
  );
15355
- fs29.rmSync(shadowDir, { recursive: true, force: true });
15521
+ fs30.rmSync(shadowDir, { recursive: true, force: true });
15356
15522
  } catch {
15357
15523
  try {
15358
- fs29.writeFileSync(ptPath, normalizedCwd, "utf8");
15524
+ fs30.writeFileSync(ptPath, normalizedCwd, "utf8");
15359
15525
  } catch {
15360
15526
  }
15361
15527
  return true;
15362
15528
  }
15363
15529
  }
15364
15530
  try {
15365
- fs29.mkdirSync(shadowDir, { recursive: true });
15531
+ fs30.mkdirSync(shadowDir, { recursive: true });
15366
15532
  } catch {
15367
15533
  }
15368
15534
  const init = spawnSync3("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -15371,7 +15537,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15371
15537
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
15372
15538
  return false;
15373
15539
  }
15374
- const configFile = path30.join(shadowDir, "config");
15540
+ const configFile = path31.join(shadowDir, "config");
15375
15541
  spawnSync3("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
15376
15542
  timeout: 3e3
15377
15543
  });
@@ -15379,7 +15545,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15379
15545
  timeout: 3e3
15380
15546
  });
15381
15547
  try {
15382
- fs29.writeFileSync(path30.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15548
+ fs30.writeFileSync(path31.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15383
15549
  } catch {
15384
15550
  }
15385
15551
  return true;
@@ -15402,12 +15568,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15402
15568
  let indexFile = null;
15403
15569
  try {
15404
15570
  const rawFilePath = extractFilePath(args);
15405
- const absFilePath = rawFilePath && path30.isAbsolute(rawFilePath) ? rawFilePath : null;
15571
+ const absFilePath = rawFilePath && path31.isAbsolute(rawFilePath) ? rawFilePath : null;
15406
15572
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
15407
15573
  const shadowDir = getShadowRepoDir(cwd);
15408
15574
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
15409
15575
  writeShadowExcludes(shadowDir, ignorePaths);
15410
- indexFile = path30.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15576
+ indexFile = path31.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15411
15577
  const shadowEnv = {
15412
15578
  ...process.env,
15413
15579
  GIT_DIR: shadowDir,
@@ -15479,7 +15645,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15479
15645
  writeStack(stack);
15480
15646
  const entry = stack[stack.length - 1];
15481
15647
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
15482
- fs29.writeFileSync(UNDO_LATEST_PATH, commitHash);
15648
+ fs30.writeFileSync(UNDO_LATEST_PATH, commitHash);
15483
15649
  if (shouldGc) {
15484
15650
  spawn4("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
15485
15651
  }
@@ -15490,7 +15656,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15490
15656
  } finally {
15491
15657
  if (indexFile) {
15492
15658
  try {
15493
- fs29.unlinkSync(indexFile);
15659
+ fs30.unlinkSync(indexFile);
15494
15660
  } catch {
15495
15661
  }
15496
15662
  }
@@ -15566,9 +15732,9 @@ function applyUndo(hash, cwd) {
15566
15732
  timeout: GIT_TIMEOUT
15567
15733
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
15568
15734
  for (const file of [...tracked, ...untracked]) {
15569
- const fullPath = path30.join(dir, file);
15570
- if (!snapshotFiles.has(file) && fs29.existsSync(fullPath)) {
15571
- fs29.unlinkSync(fullPath);
15735
+ const fullPath = path31.join(dir, file);
15736
+ if (!snapshotFiles.has(file) && fs30.existsSync(fullPath)) {
15737
+ fs30.unlinkSync(fullPath);
15572
15738
  }
15573
15739
  }
15574
15740
  return true;
@@ -15578,17 +15744,17 @@ function applyUndo(hash, cwd) {
15578
15744
  }
15579
15745
 
15580
15746
  // src/skill-pin.ts
15581
- import fs30 from "fs";
15582
- import path31 from "path";
15583
- import os26 from "os";
15584
- import crypto4 from "crypto";
15585
- function getPinsFilePath() {
15586
- return path31.join(os26.homedir(), ".node9", "skill-pins.json");
15747
+ import fs31 from "fs";
15748
+ import path32 from "path";
15749
+ import os27 from "os";
15750
+ import crypto5 from "crypto";
15751
+ function getPinsFilePath2() {
15752
+ return path32.join(os27.homedir(), ".node9", "skill-pins.json");
15587
15753
  }
15588
15754
  var MAX_FILES = 5e3;
15589
15755
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
15590
15756
  function sha256Bytes(buf) {
15591
- return crypto4.createHash("sha256").update(buf).digest("hex");
15757
+ return crypto5.createHash("sha256").update(buf).digest("hex");
15592
15758
  }
15593
15759
  function walkDir(root) {
15594
15760
  const out = [];
@@ -15597,18 +15763,18 @@ function walkDir(root) {
15597
15763
  if (out.length >= MAX_FILES) return;
15598
15764
  let entries;
15599
15765
  try {
15600
- entries = fs30.readdirSync(dir, { withFileTypes: true });
15766
+ entries = fs31.readdirSync(dir, { withFileTypes: true });
15601
15767
  } catch {
15602
15768
  return;
15603
15769
  }
15604
15770
  entries.sort((a, b) => a.name.localeCompare(b.name));
15605
15771
  for (const entry of entries) {
15606
15772
  if (out.length >= MAX_FILES) return;
15607
- const full = path31.join(dir, entry.name);
15608
- const rel = relDir ? path31.posix.join(relDir, entry.name) : entry.name;
15773
+ const full = path32.join(dir, entry.name);
15774
+ const rel = relDir ? path32.posix.join(relDir, entry.name) : entry.name;
15609
15775
  let lst;
15610
15776
  try {
15611
- lst = fs30.lstatSync(full);
15777
+ lst = fs31.lstatSync(full);
15612
15778
  } catch {
15613
15779
  continue;
15614
15780
  }
@@ -15620,7 +15786,7 @@ function walkDir(root) {
15620
15786
  if (!lst.isFile()) continue;
15621
15787
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
15622
15788
  try {
15623
- const buf = fs30.readFileSync(full);
15789
+ const buf = fs31.readFileSync(full);
15624
15790
  totalBytes += buf.length;
15625
15791
  out.push({ rel, hash: sha256Bytes(buf) });
15626
15792
  } catch {
@@ -15634,32 +15800,32 @@ function walkDir(root) {
15634
15800
  function hashSkillRoot(absPath) {
15635
15801
  let lst;
15636
15802
  try {
15637
- lst = fs30.lstatSync(absPath);
15803
+ lst = fs31.lstatSync(absPath);
15638
15804
  } catch {
15639
15805
  return { exists: false, contentHash: "", fileCount: 0 };
15640
15806
  }
15641
15807
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
15642
15808
  if (lst.isFile()) {
15643
15809
  try {
15644
- return { exists: true, contentHash: sha256Bytes(fs30.readFileSync(absPath)), fileCount: 1 };
15810
+ return { exists: true, contentHash: sha256Bytes(fs31.readFileSync(absPath)), fileCount: 1 };
15645
15811
  } catch {
15646
15812
  return { exists: false, contentHash: "", fileCount: 0 };
15647
15813
  }
15648
15814
  }
15649
15815
  if (lst.isDirectory()) {
15650
15816
  const entries = walkDir(absPath);
15651
- const contentHash = crypto4.createHash("sha256").update(entries.join("\n")).digest("hex");
15817
+ const contentHash = crypto5.createHash("sha256").update(entries.join("\n")).digest("hex");
15652
15818
  return { exists: true, contentHash, fileCount: entries.length };
15653
15819
  }
15654
15820
  return { exists: false, contentHash: "", fileCount: 0 };
15655
15821
  }
15656
15822
  function getRootKey(absPath) {
15657
- return crypto4.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15823
+ return crypto5.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15658
15824
  }
15659
15825
  function readSkillPinsSafe() {
15660
- const filePath = getPinsFilePath();
15826
+ const filePath = getPinsFilePath2();
15661
15827
  try {
15662
- const raw = fs30.readFileSync(filePath, "utf-8");
15828
+ const raw = fs31.readFileSync(filePath, "utf-8");
15663
15829
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
15664
15830
  const parsed = JSON.parse(raw);
15665
15831
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -15678,18 +15844,18 @@ function readSkillPins() {
15678
15844
  throw new Error(`[node9] skill pin file is corrupt: ${result.detail}`);
15679
15845
  }
15680
15846
  function writeSkillPins(data) {
15681
- const filePath = getPinsFilePath();
15682
- fs30.mkdirSync(path31.dirname(filePath), { recursive: true });
15683
- const tmp = `${filePath}.${crypto4.randomBytes(6).toString("hex")}.tmp`;
15684
- fs30.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15685
- fs30.renameSync(tmp, filePath);
15847
+ const filePath = getPinsFilePath2();
15848
+ fs31.mkdirSync(path32.dirname(filePath), { recursive: true });
15849
+ const tmp = `${filePath}.${crypto5.randomBytes(6).toString("hex")}.tmp`;
15850
+ fs31.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15851
+ fs31.renameSync(tmp, filePath);
15686
15852
  }
15687
- function removePin(rootKey) {
15853
+ function removePin2(rootKey) {
15688
15854
  const pins = readSkillPins();
15689
15855
  delete pins.roots[rootKey];
15690
15856
  writeSkillPins(pins);
15691
15857
  }
15692
- function clearAllPins() {
15858
+ function clearAllPins2() {
15693
15859
  writeSkillPins({ roots: {} });
15694
15860
  }
15695
15861
  function verifyAndPinRoots(roots) {
@@ -15726,36 +15892,36 @@ function verifyAndPinRoots(roots) {
15726
15892
  return { kind: "verified" };
15727
15893
  }
15728
15894
  function defaultSkillRoots(_cwd) {
15729
- const marketplaces = path31.join(os26.homedir(), ".claude", "plugins", "marketplaces");
15895
+ const marketplaces = path32.join(os27.homedir(), ".claude", "plugins", "marketplaces");
15730
15896
  const roots = [];
15731
15897
  let registries;
15732
15898
  try {
15733
- registries = fs30.readdirSync(marketplaces, { withFileTypes: true });
15899
+ registries = fs31.readdirSync(marketplaces, { withFileTypes: true });
15734
15900
  } catch {
15735
15901
  return [];
15736
15902
  }
15737
15903
  for (const registry of registries) {
15738
15904
  if (!registry.isDirectory()) continue;
15739
- const pluginsDir = path31.join(marketplaces, registry.name, "plugins");
15905
+ const pluginsDir = path32.join(marketplaces, registry.name, "plugins");
15740
15906
  let plugins;
15741
15907
  try {
15742
- plugins = fs30.readdirSync(pluginsDir, { withFileTypes: true });
15908
+ plugins = fs31.readdirSync(pluginsDir, { withFileTypes: true });
15743
15909
  } catch {
15744
15910
  continue;
15745
15911
  }
15746
15912
  for (const plugin of plugins) {
15747
15913
  if (!plugin.isDirectory()) continue;
15748
- roots.push(path31.join(pluginsDir, plugin.name));
15914
+ roots.push(path32.join(pluginsDir, plugin.name));
15749
15915
  }
15750
15916
  }
15751
15917
  return roots;
15752
15918
  }
15753
15919
  function resolveUserSkillRoot(entry, cwd) {
15754
15920
  if (!entry) return null;
15755
- if (entry.startsWith("~/") || entry === "~") return path31.join(os26.homedir(), entry.slice(1));
15756
- if (path31.isAbsolute(entry)) return entry;
15757
- if (!cwd || !path31.isAbsolute(cwd)) return null;
15758
- return path31.join(cwd, entry);
15921
+ if (entry.startsWith("~/") || entry === "~") return path32.join(os27.homedir(), entry.slice(1));
15922
+ if (path32.isAbsolute(entry)) return entry;
15923
+ if (!cwd || !path32.isAbsolute(cwd)) return null;
15924
+ return path32.join(cwd, entry);
15759
15925
  }
15760
15926
 
15761
15927
  // src/cli/commands/check.ts
@@ -15802,9 +15968,9 @@ function registerCheckCommand(program2) {
15802
15968
  } catch (err2) {
15803
15969
  const tempConfig = getConfig();
15804
15970
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
15805
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
15971
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
15806
15972
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
15807
- fs31.appendFileSync(
15973
+ fs32.appendFileSync(
15808
15974
  logPath,
15809
15975
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
15810
15976
  RAW: ${raw}
@@ -15817,14 +15983,14 @@ RAW: ${raw}
15817
15983
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
15818
15984
  if (process.env.NODE9_DEBUG === "1") {
15819
15985
  try {
15820
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
15821
- if (!fs31.existsSync(path32.dirname(logPath)))
15822
- fs31.mkdirSync(path32.dirname(logPath), { recursive: true });
15986
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
15987
+ if (!fs32.existsSync(path33.dirname(logPath)))
15988
+ fs32.mkdirSync(path33.dirname(logPath), { recursive: true });
15823
15989
  const sanitized = JSON.stringify({
15824
15990
  ...payload,
15825
15991
  prompt: `<redacted, ${prompt.length} bytes>`
15826
15992
  });
15827
- fs31.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
15993
+ fs32.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
15828
15994
  `);
15829
15995
  } catch {
15830
15996
  }
@@ -15844,8 +16010,8 @@ RAW: ${raw}
15844
16010
  );
15845
16011
  const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
15846
16012
  try {
15847
- const ttyFd = fs31.openSync("/dev/tty", "w");
15848
- fs31.writeSync(
16013
+ const ttyFd = fs32.openSync("/dev/tty", "w");
16014
+ fs32.writeSync(
15849
16015
  ttyFd,
15850
16016
  chalk9.bgRed.white.bold(`
15851
16017
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -15855,7 +16021,7 @@ RAW: ${raw}
15855
16021
 
15856
16022
  `)
15857
16023
  );
15858
- fs31.closeSync(ttyFd);
16024
+ fs32.closeSync(ttyFd);
15859
16025
  } catch {
15860
16026
  }
15861
16027
  const isCodex = agent2 === "Codex";
@@ -15873,16 +16039,16 @@ RAW: ${raw}
15873
16039
  );
15874
16040
  process.exit(2);
15875
16041
  }
15876
- const safeCwdForConfig = typeof payload.cwd === "string" && path32.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16042
+ const safeCwdForConfig = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15877
16043
  const config = getConfig(safeCwdForConfig);
15878
16044
  if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
15879
16045
  try {
15880
16046
  const scriptPath = process.argv[1];
15881
- if (typeof scriptPath !== "string" || !path32.isAbsolute(scriptPath))
16047
+ if (typeof scriptPath !== "string" || !path33.isAbsolute(scriptPath))
15882
16048
  throw new Error("node9: argv[1] is not an absolute path");
15883
- const resolvedScript = fs31.realpathSync(scriptPath);
15884
- const packageDist = fs31.realpathSync(path32.resolve(__dirname, "../.."));
15885
- if (!resolvedScript.startsWith(packageDist + path32.sep) && resolvedScript !== packageDist)
16049
+ const resolvedScript = fs32.realpathSync(scriptPath);
16050
+ const packageDist = fs32.realpathSync(path33.resolve(__dirname, "../.."));
16051
+ if (!resolvedScript.startsWith(packageDist + path33.sep) && resolvedScript !== packageDist)
15886
16052
  throw new Error(
15887
16053
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
15888
16054
  );
@@ -15904,10 +16070,10 @@ RAW: ${raw}
15904
16070
  });
15905
16071
  d.unref();
15906
16072
  } catch (spawnErr) {
15907
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
16073
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
15908
16074
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
15909
16075
  try {
15910
- fs31.appendFileSync(
16076
+ fs32.appendFileSync(
15911
16077
  logPath,
15912
16078
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
15913
16079
  `
@@ -15917,10 +16083,10 @@ RAW: ${raw}
15917
16083
  }
15918
16084
  }
15919
16085
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
15920
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
15921
- if (!fs31.existsSync(path32.dirname(logPath)))
15922
- fs31.mkdirSync(path32.dirname(logPath), { recursive: true });
15923
- fs31.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
16086
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16087
+ if (!fs32.existsSync(path33.dirname(logPath)))
16088
+ fs32.mkdirSync(path33.dirname(logPath), { recursive: true });
16089
+ fs32.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
15924
16090
  `);
15925
16091
  }
15926
16092
  const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
@@ -15933,8 +16099,8 @@ RAW: ${raw}
15933
16099
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
15934
16100
  let ttyFd = null;
15935
16101
  try {
15936
- ttyFd = fs31.openSync("/dev/tty", "w");
15937
- const writeTty = (line) => fs31.writeSync(ttyFd, line + "\n");
16102
+ ttyFd = fs32.openSync("/dev/tty", "w");
16103
+ const writeTty = (line) => fs32.writeSync(ttyFd, line + "\n");
15938
16104
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
15939
16105
  writeTty(chalk9.bgRed.white.bold(`
15940
16106
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -15953,7 +16119,7 @@ RAW: ${raw}
15953
16119
  } finally {
15954
16120
  if (ttyFd !== null)
15955
16121
  try {
15956
- fs31.closeSync(ttyFd);
16122
+ fs32.closeSync(ttyFd);
15957
16123
  } catch {
15958
16124
  }
15959
16125
  }
@@ -15989,17 +16155,17 @@ RAW: ${raw}
15989
16155
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
15990
16156
  if (skillPinCfg.enabled && safeSessionId) {
15991
16157
  try {
15992
- const sessionsDir = path32.join(os27.homedir(), ".node9", "skill-sessions");
15993
- const flagPath = path32.join(sessionsDir, `${safeSessionId}.json`);
16158
+ const sessionsDir = path33.join(os28.homedir(), ".node9", "skill-sessions");
16159
+ const flagPath = path33.join(sessionsDir, `${safeSessionId}.json`);
15994
16160
  let flag = null;
15995
16161
  try {
15996
- flag = JSON.parse(fs31.readFileSync(flagPath, "utf-8"));
16162
+ flag = JSON.parse(fs32.readFileSync(flagPath, "utf-8"));
15997
16163
  } catch {
15998
16164
  }
15999
16165
  const writeFlag = (data2) => {
16000
16166
  try {
16001
- fs31.mkdirSync(sessionsDir, { recursive: true });
16002
- fs31.writeFileSync(
16167
+ fs32.mkdirSync(sessionsDir, { recursive: true });
16168
+ fs32.writeFileSync(
16003
16169
  flagPath,
16004
16170
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
16005
16171
  { mode: 384 }
@@ -16010,8 +16176,8 @@ RAW: ${raw}
16010
16176
  const sendSkillWarn = (detail, recoveryCmd) => {
16011
16177
  let ttyFd = null;
16012
16178
  try {
16013
- ttyFd = fs31.openSync("/dev/tty", "w");
16014
- const w = (line) => fs31.writeSync(ttyFd, line + "\n");
16179
+ ttyFd = fs32.openSync("/dev/tty", "w");
16180
+ const w = (line) => fs32.writeSync(ttyFd, line + "\n");
16015
16181
  w(chalk9.yellow(`
16016
16182
  \u26A0\uFE0F Node9: installed skill drift detected`));
16017
16183
  w(chalk9.gray(` ${detail}`));
@@ -16026,7 +16192,7 @@ RAW: ${raw}
16026
16192
  } finally {
16027
16193
  if (ttyFd !== null)
16028
16194
  try {
16029
- fs31.closeSync(ttyFd);
16195
+ fs32.closeSync(ttyFd);
16030
16196
  } catch {
16031
16197
  }
16032
16198
  }
@@ -16042,7 +16208,7 @@ RAW: ${raw}
16042
16208
  return;
16043
16209
  }
16044
16210
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
16045
- const absoluteCwd = typeof payload.cwd === "string" && path32.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16211
+ const absoluteCwd = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16046
16212
  const extraRoots = skillPinCfg.roots;
16047
16213
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
16048
16214
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -16083,10 +16249,10 @@ RAW: ${raw}
16083
16249
  }
16084
16250
  try {
16085
16251
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
16086
- for (const name of fs31.readdirSync(sessionsDir)) {
16087
- const p = path32.join(sessionsDir, name);
16252
+ for (const name of fs32.readdirSync(sessionsDir)) {
16253
+ const p = path33.join(sessionsDir, name);
16088
16254
  try {
16089
- if (fs31.statSync(p).mtimeMs < cutoff) fs31.unlinkSync(p);
16255
+ if (fs32.statSync(p).mtimeMs < cutoff) fs32.unlinkSync(p);
16090
16256
  } catch {
16091
16257
  }
16092
16258
  }
@@ -16096,9 +16262,9 @@ RAW: ${raw}
16096
16262
  } catch (err2) {
16097
16263
  if (process.env.NODE9_DEBUG === "1") {
16098
16264
  try {
16099
- const dbg = path32.join(os27.homedir(), ".node9", "hook-debug.log");
16265
+ const dbg = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16100
16266
  const msg = err2 instanceof Error ? err2.message : String(err2);
16101
- fs31.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16267
+ fs32.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16102
16268
  `);
16103
16269
  } catch {
16104
16270
  }
@@ -16108,7 +16274,7 @@ RAW: ${raw}
16108
16274
  if (shouldSnapshot(toolName, toolInput, config)) {
16109
16275
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
16110
16276
  }
16111
- const safeCwdForAuth = typeof payload.cwd === "string" && path32.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16277
+ const safeCwdForAuth = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16112
16278
  const result = await authorizeHeadless(toolName, toolInput, meta, {
16113
16279
  cwd: safeCwdForAuth
16114
16280
  });
@@ -16120,12 +16286,12 @@ RAW: ${raw}
16120
16286
  }
16121
16287
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
16122
16288
  try {
16123
- const tty = fs31.openSync("/dev/tty", "w");
16124
- fs31.writeSync(
16289
+ const tty = fs32.openSync("/dev/tty", "w");
16290
+ fs32.writeSync(
16125
16291
  tty,
16126
16292
  chalk9.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
16127
16293
  );
16128
- fs31.closeSync(tty);
16294
+ fs32.closeSync(tty);
16129
16295
  } catch {
16130
16296
  }
16131
16297
  const daemonReady = await autoStartDaemonAndWait();
@@ -16152,9 +16318,9 @@ RAW: ${raw}
16152
16318
  });
16153
16319
  } catch (err2) {
16154
16320
  if (process.env.NODE9_DEBUG === "1") {
16155
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
16321
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16156
16322
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
16157
- fs31.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16323
+ fs32.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16158
16324
  `);
16159
16325
  }
16160
16326
  process.exit(0);
@@ -16190,9 +16356,9 @@ RAW: ${raw}
16190
16356
  // src/cli/commands/log.ts
16191
16357
  init_audit();
16192
16358
  init_config();
16193
- import fs32 from "fs";
16194
- import path33 from "path";
16195
- import os28 from "os";
16359
+ import fs33 from "fs";
16360
+ import path34 from "path";
16361
+ import os29 from "os";
16196
16362
  init_daemon();
16197
16363
 
16198
16364
  // src/utils/cp-mv-parser.ts
@@ -16268,10 +16434,10 @@ function registerLogCommand(program2) {
16268
16434
  };
16269
16435
  if (agent) entry.agent = agent;
16270
16436
  if (payload.session_id) entry.sessionId = payload.session_id;
16271
- const logPath = path33.join(os28.homedir(), ".node9", "audit.log");
16272
- if (!fs32.existsSync(path33.dirname(logPath)))
16273
- fs32.mkdirSync(path33.dirname(logPath), { recursive: true });
16274
- fs32.appendFileSync(logPath, JSON.stringify(entry) + "\n");
16437
+ const logPath = path34.join(os29.homedir(), ".node9", "audit.log");
16438
+ if (!fs33.existsSync(path34.dirname(logPath)))
16439
+ fs33.mkdirSync(path34.dirname(logPath), { recursive: true });
16440
+ fs33.appendFileSync(logPath, JSON.stringify(entry) + "\n");
16275
16441
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
16276
16442
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
16277
16443
  if (command) {
@@ -16304,7 +16470,7 @@ function registerLogCommand(program2) {
16304
16470
  }
16305
16471
  }
16306
16472
  }
16307
- const safeCwd = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16473
+ const safeCwd = typeof payload.cwd === "string" && path34.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16308
16474
  const config = getConfig(safeCwd);
16309
16475
  if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
16310
16476
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
@@ -16325,9 +16491,9 @@ function registerLogCommand(program2) {
16325
16491
  const msg = err2 instanceof Error ? err2.message : String(err2);
16326
16492
  process.stderr.write(`[Node9] audit log error: ${msg}
16327
16493
  `);
16328
- const debugPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16494
+ const debugPath = path34.join(os29.homedir(), ".node9", "hook-debug.log");
16329
16495
  try {
16330
- fs32.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16496
+ fs33.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16331
16497
  `);
16332
16498
  } catch {
16333
16499
  }
@@ -16728,13 +16894,13 @@ function registerConfigShowCommand(program2) {
16728
16894
  // src/cli/commands/doctor.ts
16729
16895
  init_daemon();
16730
16896
  import chalk11 from "chalk";
16731
- import fs33 from "fs";
16732
- import path34 from "path";
16733
- import os29 from "os";
16897
+ import fs34 from "fs";
16898
+ import path35 from "path";
16899
+ import os30 from "os";
16734
16900
  import { execSync } from "child_process";
16735
16901
  function registerDoctorCommand(program2, version2) {
16736
16902
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
16737
- const homeDir2 = os29.homedir();
16903
+ const homeDir2 = os30.homedir();
16738
16904
  let failures = 0;
16739
16905
  function pass(msg) {
16740
16906
  console.log(chalk11.green(" \u2705 ") + msg);
@@ -16783,10 +16949,10 @@ function registerDoctorCommand(program2, version2) {
16783
16949
  );
16784
16950
  }
16785
16951
  section("Configuration");
16786
- const globalConfigPath = path34.join(homeDir2, ".node9", "config.json");
16787
- if (fs33.existsSync(globalConfigPath)) {
16952
+ const globalConfigPath = path35.join(homeDir2, ".node9", "config.json");
16953
+ if (fs34.existsSync(globalConfigPath)) {
16788
16954
  try {
16789
- JSON.parse(fs33.readFileSync(globalConfigPath, "utf-8"));
16955
+ JSON.parse(fs34.readFileSync(globalConfigPath, "utf-8"));
16790
16956
  pass("~/.node9/config.json found and valid");
16791
16957
  } catch {
16792
16958
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -16794,10 +16960,10 @@ function registerDoctorCommand(program2, version2) {
16794
16960
  } else {
16795
16961
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
16796
16962
  }
16797
- const projectConfigPath = path34.join(process.cwd(), "node9.config.json");
16798
- if (fs33.existsSync(projectConfigPath)) {
16963
+ const projectConfigPath = path35.join(process.cwd(), "node9.config.json");
16964
+ if (fs34.existsSync(projectConfigPath)) {
16799
16965
  try {
16800
- JSON.parse(fs33.readFileSync(projectConfigPath, "utf-8"));
16966
+ JSON.parse(fs34.readFileSync(projectConfigPath, "utf-8"));
16801
16967
  pass("node9.config.json found and valid (project)");
16802
16968
  } catch {
16803
16969
  fail(
@@ -16806,8 +16972,8 @@ function registerDoctorCommand(program2, version2) {
16806
16972
  );
16807
16973
  }
16808
16974
  }
16809
- const credsPath = path34.join(homeDir2, ".node9", "credentials.json");
16810
- if (fs33.existsSync(credsPath)) {
16975
+ const credsPath = path35.join(homeDir2, ".node9", "credentials.json");
16976
+ if (fs34.existsSync(credsPath)) {
16811
16977
  pass("Cloud credentials found (~/.node9/credentials.json)");
16812
16978
  } else {
16813
16979
  warn(
@@ -16816,10 +16982,10 @@ function registerDoctorCommand(program2, version2) {
16816
16982
  );
16817
16983
  }
16818
16984
  section("Agent Hooks");
16819
- const claudeSettingsPath = path34.join(homeDir2, ".claude", "settings.json");
16820
- if (fs33.existsSync(claudeSettingsPath)) {
16985
+ const claudeSettingsPath = path35.join(homeDir2, ".claude", "settings.json");
16986
+ if (fs34.existsSync(claudeSettingsPath)) {
16821
16987
  try {
16822
- const cs = JSON.parse(fs33.readFileSync(claudeSettingsPath, "utf-8"));
16988
+ const cs = JSON.parse(fs34.readFileSync(claudeSettingsPath, "utf-8"));
16823
16989
  const hasHook = cs.hooks?.PreToolUse?.some(
16824
16990
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16825
16991
  );
@@ -16835,10 +17001,10 @@ function registerDoctorCommand(program2, version2) {
16835
17001
  } else {
16836
17002
  warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
16837
17003
  }
16838
- const geminiSettingsPath = path34.join(homeDir2, ".gemini", "settings.json");
16839
- if (fs33.existsSync(geminiSettingsPath)) {
17004
+ const geminiSettingsPath = path35.join(homeDir2, ".gemini", "settings.json");
17005
+ if (fs34.existsSync(geminiSettingsPath)) {
16840
17006
  try {
16841
- const gs = JSON.parse(fs33.readFileSync(geminiSettingsPath, "utf-8"));
17007
+ const gs = JSON.parse(fs34.readFileSync(geminiSettingsPath, "utf-8"));
16842
17008
  const hasHook = gs.hooks?.BeforeTool?.some(
16843
17009
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16844
17010
  );
@@ -16854,10 +17020,10 @@ function registerDoctorCommand(program2, version2) {
16854
17020
  } else {
16855
17021
  warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
16856
17022
  }
16857
- const cursorHooksPath = path34.join(homeDir2, ".cursor", "hooks.json");
16858
- if (fs33.existsSync(cursorHooksPath)) {
17023
+ const cursorHooksPath = path35.join(homeDir2, ".cursor", "hooks.json");
17024
+ if (fs34.existsSync(cursorHooksPath)) {
16859
17025
  try {
16860
- const cur = JSON.parse(fs33.readFileSync(cursorHooksPath, "utf-8"));
17026
+ const cur = JSON.parse(fs34.readFileSync(cursorHooksPath, "utf-8"));
16861
17027
  const hasHook = cur.hooks?.preToolUse?.some(
16862
17028
  (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
16863
17029
  );
@@ -16897,9 +17063,9 @@ function registerDoctorCommand(program2, version2) {
16897
17063
 
16898
17064
  // src/cli/commands/audit.ts
16899
17065
  import chalk12 from "chalk";
16900
- import fs34 from "fs";
16901
- import path35 from "path";
16902
- import os30 from "os";
17066
+ import fs35 from "fs";
17067
+ import path36 from "path";
17068
+ import os31 from "os";
16903
17069
  function formatRelativeTime(timestamp) {
16904
17070
  const diff = Date.now() - new Date(timestamp).getTime();
16905
17071
  const sec = Math.floor(diff / 1e3);
@@ -16912,14 +17078,14 @@ function formatRelativeTime(timestamp) {
16912
17078
  }
16913
17079
  function registerAuditCommand(program2) {
16914
17080
  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) => {
16915
- const logPath = path35.join(os30.homedir(), ".node9", "audit.log");
16916
- if (!fs34.existsSync(logPath)) {
17081
+ const logPath = path36.join(os31.homedir(), ".node9", "audit.log");
17082
+ if (!fs35.existsSync(logPath)) {
16917
17083
  console.log(
16918
17084
  chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
16919
17085
  );
16920
17086
  return;
16921
17087
  }
16922
- const raw = fs34.readFileSync(logPath, "utf-8");
17088
+ const raw = fs35.readFileSync(logPath, "utf-8");
16923
17089
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
16924
17090
  let entries = lines.flatMap((line) => {
16925
17091
  try {
@@ -16977,9 +17143,9 @@ import chalk13 from "chalk";
16977
17143
  // src/cli/aggregate/report-audit.ts
16978
17144
  init_costSync();
16979
17145
  init_litellm();
16980
- import fs35 from "fs";
16981
- import os31 from "os";
16982
- import path36 from "path";
17146
+ import fs36 from "fs";
17147
+ import os32 from "os";
17148
+ import path37 from "path";
16983
17149
  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;
16984
17150
  function buildTestTimestamps(allEntries) {
16985
17151
  const testTs = /* @__PURE__ */ new Set();
@@ -17059,8 +17225,8 @@ function getDateRange(period, now) {
17059
17225
  }
17060
17226
  }
17061
17227
  function parseAuditLog(logPath) {
17062
- if (!fs35.existsSync(logPath)) return [];
17063
- const raw = fs35.readFileSync(logPath, "utf-8");
17228
+ if (!fs36.existsSync(logPath)) return [];
17229
+ const raw = fs36.readFileSync(logPath, "utf-8");
17064
17230
  return raw.split("\n").flatMap((line) => {
17065
17231
  if (!line.trim()) return [];
17066
17232
  try {
@@ -17120,25 +17286,25 @@ function freezeClaudeCost(acc) {
17120
17286
  };
17121
17287
  }
17122
17288
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17123
- const projPath = path36.join(projectsDir, proj);
17289
+ const projPath = path37.join(projectsDir, proj);
17124
17290
  let files;
17125
17291
  try {
17126
- const stat = fs35.statSync(projPath);
17292
+ const stat = fs36.statSync(projPath);
17127
17293
  if (!stat.isDirectory()) return;
17128
- files = fs35.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17294
+ files = fs36.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17129
17295
  } catch {
17130
17296
  return;
17131
17297
  }
17132
17298
  const startMs = start.getTime();
17133
17299
  for (const file of files) {
17134
- const filePath = path36.join(projPath, file);
17300
+ const filePath = path37.join(projPath, file);
17135
17301
  try {
17136
- if (fs35.statSync(filePath).mtimeMs < startMs) continue;
17302
+ if (fs36.statSync(filePath).mtimeMs < startMs) continue;
17137
17303
  } catch {
17138
17304
  continue;
17139
17305
  }
17140
17306
  try {
17141
- const raw = fs35.readFileSync(filePath, "utf-8");
17307
+ const raw = fs36.readFileSync(filePath, "utf-8");
17142
17308
  for (const line of raw.split("\n")) {
17143
17309
  if (!line.trim()) continue;
17144
17310
  let entry;
@@ -17188,10 +17354,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17188
17354
  }
17189
17355
  function loadClaudeCost(start, end, projectsDir) {
17190
17356
  const acc = emptyClaudeCostAccumulator();
17191
- if (!fs35.existsSync(projectsDir)) return freezeClaudeCost(acc);
17357
+ if (!fs36.existsSync(projectsDir)) return freezeClaudeCost(acc);
17192
17358
  let dirs;
17193
17359
  try {
17194
- dirs = fs35.readdirSync(projectsDir);
17360
+ dirs = fs36.readdirSync(projectsDir);
17195
17361
  } catch {
17196
17362
  return freezeClaudeCost(acc);
17197
17363
  }
@@ -17203,7 +17369,7 @@ function loadClaudeCost(start, end, projectsDir) {
17203
17369
  function processCodexCostFile(filePath, start, end, acc) {
17204
17370
  let lines;
17205
17371
  try {
17206
- lines = fs35.readFileSync(filePath, "utf-8").split("\n");
17372
+ lines = fs36.readFileSync(filePath, "utf-8").split("\n");
17207
17373
  } catch {
17208
17374
  return;
17209
17375
  }
@@ -17248,31 +17414,31 @@ function processCodexCostFile(filePath, start, end, acc) {
17248
17414
  }
17249
17415
  function listCodexSessionFiles(sessionsBase) {
17250
17416
  const jsonlFiles = [];
17251
- if (!fs35.existsSync(sessionsBase)) return jsonlFiles;
17417
+ if (!fs36.existsSync(sessionsBase)) return jsonlFiles;
17252
17418
  try {
17253
- for (const year of fs35.readdirSync(sessionsBase)) {
17254
- const yearPath = path36.join(sessionsBase, year);
17419
+ for (const year of fs36.readdirSync(sessionsBase)) {
17420
+ const yearPath = path37.join(sessionsBase, year);
17255
17421
  try {
17256
- if (!fs35.statSync(yearPath).isDirectory()) continue;
17422
+ if (!fs36.statSync(yearPath).isDirectory()) continue;
17257
17423
  } catch {
17258
17424
  continue;
17259
17425
  }
17260
- for (const month of fs35.readdirSync(yearPath)) {
17261
- const monthPath = path36.join(yearPath, month);
17426
+ for (const month of fs36.readdirSync(yearPath)) {
17427
+ const monthPath = path37.join(yearPath, month);
17262
17428
  try {
17263
- if (!fs35.statSync(monthPath).isDirectory()) continue;
17429
+ if (!fs36.statSync(monthPath).isDirectory()) continue;
17264
17430
  } catch {
17265
17431
  continue;
17266
17432
  }
17267
- for (const day of fs35.readdirSync(monthPath)) {
17268
- const dayPath = path36.join(monthPath, day);
17433
+ for (const day of fs36.readdirSync(monthPath)) {
17434
+ const dayPath = path37.join(monthPath, day);
17269
17435
  try {
17270
- if (!fs35.statSync(dayPath).isDirectory()) continue;
17436
+ if (!fs36.statSync(dayPath).isDirectory()) continue;
17271
17437
  } catch {
17272
17438
  continue;
17273
17439
  }
17274
- for (const file of fs35.readdirSync(dayPath)) {
17275
- if (file.endsWith(".jsonl")) jsonlFiles.push(path36.join(dayPath, file));
17440
+ for (const file of fs36.readdirSync(dayPath)) {
17441
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path37.join(dayPath, file));
17276
17442
  }
17277
17443
  }
17278
17444
  }
@@ -17325,13 +17491,13 @@ function freezeGeminiCost(acc) {
17325
17491
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
17326
17492
  const startMs = start.getTime();
17327
17493
  try {
17328
- if (fs35.statSync(filePath).mtimeMs < startMs) return;
17494
+ if (fs36.statSync(filePath).mtimeMs < startMs) return;
17329
17495
  } catch {
17330
17496
  return;
17331
17497
  }
17332
17498
  let raw;
17333
17499
  try {
17334
- raw = fs35.readFileSync(filePath, "utf-8");
17500
+ raw = fs36.readFileSync(filePath, "utf-8");
17335
17501
  } catch {
17336
17502
  return;
17337
17503
  }
@@ -17380,30 +17546,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
17380
17546
  const out = [];
17381
17547
  let dirs;
17382
17548
  try {
17383
- if (!fs35.statSync(geminiTmpDir).isDirectory()) return out;
17384
- dirs = fs35.readdirSync(geminiTmpDir);
17549
+ if (!fs36.statSync(geminiTmpDir).isDirectory()) return out;
17550
+ dirs = fs36.readdirSync(geminiTmpDir);
17385
17551
  } catch {
17386
17552
  return out;
17387
17553
  }
17388
17554
  for (const proj of dirs) {
17389
- const chatsDir = path36.join(geminiTmpDir, proj, "chats");
17555
+ const chatsDir = path37.join(geminiTmpDir, proj, "chats");
17390
17556
  let files;
17391
17557
  try {
17392
- if (!fs35.statSync(chatsDir).isDirectory()) continue;
17393
- files = fs35.readdirSync(chatsDir);
17558
+ if (!fs36.statSync(chatsDir).isDirectory()) continue;
17559
+ files = fs36.readdirSync(chatsDir);
17394
17560
  } catch {
17395
17561
  continue;
17396
17562
  }
17397
17563
  for (const f of files) {
17398
17564
  if (!f.endsWith(".jsonl")) continue;
17399
- out.push({ projectKey: proj, file: path36.join(chatsDir, f) });
17565
+ out.push({ projectKey: proj, file: path37.join(chatsDir, f) });
17400
17566
  }
17401
17567
  }
17402
17568
  return out;
17403
17569
  }
17404
17570
  function loadGeminiCost(start, end, geminiTmpDir) {
17405
17571
  const acc = emptyGeminiAccumulator();
17406
- if (!fs35.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17572
+ if (!fs36.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17407
17573
  for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
17408
17574
  processGeminiCostFile(file, projectKey, start, end, acc);
17409
17575
  }
@@ -17411,11 +17577,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
17411
17577
  }
17412
17578
  function aggregateReportFromAudit(period, opts = {}) {
17413
17579
  const now = opts.now ?? /* @__PURE__ */ new Date();
17414
- const auditLogPath = opts.auditLogPath ?? path36.join(os31.homedir(), ".node9", "audit.log");
17415
- const claudeProjectsDir = opts.claudeProjectsDir ?? path36.join(os31.homedir(), ".claude", "projects");
17416
- const codexSessionsDir = opts.codexSessionsDir ?? path36.join(os31.homedir(), ".codex", "sessions");
17417
- const geminiTmpDir = opts.geminiTmpDir ?? path36.join(os31.homedir(), ".gemini", "tmp");
17418
- const hasAuditFile = fs35.existsSync(auditLogPath);
17580
+ const auditLogPath = opts.auditLogPath ?? path37.join(os32.homedir(), ".node9", "audit.log");
17581
+ const claudeProjectsDir = opts.claudeProjectsDir ?? path37.join(os32.homedir(), ".claude", "projects");
17582
+ const codexSessionsDir = opts.codexSessionsDir ?? path37.join(os32.homedir(), ".codex", "sessions");
17583
+ const geminiTmpDir = opts.geminiTmpDir ?? path37.join(os32.homedir(), ".gemini", "tmp");
17584
+ const hasAuditFile = fs36.existsSync(auditLogPath);
17419
17585
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
17420
17586
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
17421
17587
  const { start, end } = getDateRange(period, now);
@@ -18113,12 +18279,12 @@ function registerDaemonCommand(program2) {
18113
18279
  init_core();
18114
18280
  init_daemon();
18115
18281
  import chalk15 from "chalk";
18116
- import fs36 from "fs";
18117
- import path37 from "path";
18118
- import os32 from "os";
18282
+ import fs37 from "fs";
18283
+ import path38 from "path";
18284
+ import os33 from "os";
18119
18285
  function readJson2(filePath) {
18120
18286
  try {
18121
- if (fs36.existsSync(filePath)) return JSON.parse(fs36.readFileSync(filePath, "utf-8"));
18287
+ if (fs37.existsSync(filePath)) return JSON.parse(fs37.readFileSync(filePath, "utf-8"));
18122
18288
  } catch {
18123
18289
  }
18124
18290
  return null;
@@ -18183,28 +18349,28 @@ function registerStatusCommand(program2) {
18183
18349
  console.log("");
18184
18350
  const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
18185
18351
  console.log(` Mode: ${modeLabel}`);
18186
- const projectConfig = path37.join(process.cwd(), "node9.config.json");
18187
- const globalConfig = path37.join(os32.homedir(), ".node9", "config.json");
18352
+ const projectConfig = path38.join(process.cwd(), "node9.config.json");
18353
+ const globalConfig = path38.join(os33.homedir(), ".node9", "config.json");
18188
18354
  console.log(
18189
- ` Local: ${fs36.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
18355
+ ` Local: ${fs37.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
18190
18356
  );
18191
18357
  console.log(
18192
- ` Global: ${fs36.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
18358
+ ` Global: ${fs37.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
18193
18359
  );
18194
18360
  if (mergedConfig.policy.sandboxPaths.length > 0) {
18195
18361
  console.log(
18196
18362
  ` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
18197
18363
  );
18198
18364
  }
18199
- const homeDir2 = os32.homedir();
18365
+ const homeDir2 = os33.homedir();
18200
18366
  const claudeSettings = readJson2(
18201
- path37.join(homeDir2, ".claude", "settings.json")
18367
+ path38.join(homeDir2, ".claude", "settings.json")
18202
18368
  );
18203
- const claudeConfig = readJson2(path37.join(homeDir2, ".claude.json"));
18369
+ const claudeConfig = readJson2(path38.join(homeDir2, ".claude.json"));
18204
18370
  const geminiSettings = readJson2(
18205
- path37.join(homeDir2, ".gemini", "settings.json")
18371
+ path38.join(homeDir2, ".gemini", "settings.json")
18206
18372
  );
18207
- const cursorConfig = readJson2(path37.join(homeDir2, ".cursor", "mcp.json"));
18373
+ const cursorConfig = readJson2(path38.join(homeDir2, ".cursor", "mcp.json"));
18208
18374
  const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
18209
18375
  if (agentFound) {
18210
18376
  console.log("");
@@ -18267,9 +18433,9 @@ init_setup();
18267
18433
  init_shields();
18268
18434
  init_service();
18269
18435
  import chalk16 from "chalk";
18270
- import fs37 from "fs";
18271
- import path38 from "path";
18272
- import os33 from "os";
18436
+ import fs38 from "fs";
18437
+ import path39 from "path";
18438
+ import os34 from "os";
18273
18439
  import https4 from "https";
18274
18440
  var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
18275
18441
  function fireTelemetryPing(agents) {
@@ -18345,15 +18511,15 @@ function registerInitCommand(program2) {
18345
18511
  }
18346
18512
  console.log("");
18347
18513
  }
18348
- const configPath = path38.join(os33.homedir(), ".node9", "config.json");
18349
- if (fs37.existsSync(configPath) && !options.force) {
18514
+ const configPath = path39.join(os34.homedir(), ".node9", "config.json");
18515
+ if (fs38.existsSync(configPath) && !options.force) {
18350
18516
  try {
18351
- const existing = JSON.parse(fs37.readFileSync(configPath, "utf-8"));
18517
+ const existing = JSON.parse(fs38.readFileSync(configPath, "utf-8"));
18352
18518
  const settings = existing.settings ?? {};
18353
18519
  if (settings.mode !== chosenMode) {
18354
18520
  settings.mode = chosenMode;
18355
18521
  existing.settings = settings;
18356
- fs37.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18522
+ fs38.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18357
18523
  console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
18358
18524
  } else {
18359
18525
  console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -18366,9 +18532,9 @@ function registerInitCommand(program2) {
18366
18532
  ...DEFAULT_CONFIG,
18367
18533
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
18368
18534
  };
18369
- const dir = path38.dirname(configPath);
18370
- if (!fs37.existsSync(dir)) fs37.mkdirSync(dir, { recursive: true });
18371
- fs37.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
18535
+ const dir = path39.dirname(configPath);
18536
+ if (!fs38.existsSync(dir)) fs38.mkdirSync(dir, { recursive: true });
18537
+ fs38.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
18372
18538
  console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
18373
18539
  console.log(chalk16.gray(` Mode: ${chosenMode}`));
18374
18540
  }
@@ -18466,7 +18632,7 @@ function registerInitCommand(program2) {
18466
18632
  }
18467
18633
 
18468
18634
  // src/cli/commands/undo.ts
18469
- import path39 from "path";
18635
+ import path40 from "path";
18470
18636
  import chalk18 from "chalk";
18471
18637
 
18472
18638
  // src/tui/undo-navigator.ts
@@ -18625,7 +18791,7 @@ function findMatchingCwd(startDir, history) {
18625
18791
  let dir = startDir;
18626
18792
  while (true) {
18627
18793
  if (cwds.has(dir)) return dir;
18628
- const parent = path39.dirname(dir);
18794
+ const parent = path40.dirname(dir);
18629
18795
  if (parent === dir) return null;
18630
18796
  dir = parent;
18631
18797
  }
@@ -18758,90 +18924,7 @@ import chalk19 from "chalk";
18758
18924
  import { spawn as spawn7 } from "child_process";
18759
18925
  import { execa as execa2 } from "execa";
18760
18926
  init_provenance();
18761
-
18762
- // src/mcp-pin.ts
18763
- import fs38 from "fs";
18764
- import path40 from "path";
18765
- import os34 from "os";
18766
- import crypto5 from "crypto";
18767
- function getPinsFilePath2() {
18768
- return path40.join(os34.homedir(), ".node9", "mcp-pins.json");
18769
- }
18770
- function hashToolDefinitions(tools) {
18771
- const sorted = [...tools].sort((a, b) => {
18772
- const nameA = a.name ?? "";
18773
- const nameB = b.name ?? "";
18774
- return nameA.localeCompare(nameB);
18775
- });
18776
- const canonical = JSON.stringify(sorted);
18777
- return crypto5.createHash("sha256").update(canonical).digest("hex");
18778
- }
18779
- function getServerKey(upstreamCommand) {
18780
- return crypto5.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
18781
- }
18782
- function readMcpPinsSafe() {
18783
- const filePath = getPinsFilePath2();
18784
- try {
18785
- const raw = fs38.readFileSync(filePath, "utf-8");
18786
- if (!raw.trim()) {
18787
- return { ok: false, reason: "corrupt", detail: "empty file" };
18788
- }
18789
- const parsed = JSON.parse(raw);
18790
- if (!parsed.servers || typeof parsed.servers !== "object" || Array.isArray(parsed.servers)) {
18791
- return { ok: false, reason: "corrupt", detail: "invalid structure: missing servers object" };
18792
- }
18793
- return { ok: true, pins: { servers: parsed.servers } };
18794
- } catch (err2) {
18795
- if (err2.code === "ENOENT") {
18796
- return { ok: false, reason: "missing" };
18797
- }
18798
- return { ok: false, reason: "corrupt", detail: String(err2) };
18799
- }
18800
- }
18801
- function readMcpPins() {
18802
- const result = readMcpPinsSafe();
18803
- if (result.ok) return result.pins;
18804
- if (result.reason === "missing") return { servers: {} };
18805
- throw new Error(`[node9] MCP pin file is corrupt: ${result.detail}`);
18806
- }
18807
- function writeMcpPins(data) {
18808
- const filePath = getPinsFilePath2();
18809
- fs38.mkdirSync(path40.dirname(filePath), { recursive: true });
18810
- const tmp = `${filePath}.${crypto5.randomBytes(6).toString("hex")}.tmp`;
18811
- fs38.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
18812
- fs38.renameSync(tmp, filePath);
18813
- }
18814
- function checkPin(serverKey, currentHash) {
18815
- const result = readMcpPinsSafe();
18816
- if (!result.ok) {
18817
- if (result.reason === "missing") return "new";
18818
- return "corrupt";
18819
- }
18820
- const entry = result.pins.servers[serverKey];
18821
- if (!entry) return "new";
18822
- return entry.toolsHash === currentHash ? "match" : "mismatch";
18823
- }
18824
- function updatePin(serverKey, label, toolsHash, toolNames) {
18825
- const pins = readMcpPins();
18826
- pins.servers[serverKey] = {
18827
- label,
18828
- toolsHash,
18829
- toolNames,
18830
- toolCount: toolNames.length,
18831
- pinnedAt: (/* @__PURE__ */ new Date()).toISOString()
18832
- };
18833
- writeMcpPins(pins);
18834
- }
18835
- function removePin2(serverKey) {
18836
- const pins = readMcpPins();
18837
- delete pins.servers[serverKey];
18838
- writeMcpPins(pins);
18839
- }
18840
- function clearAllPins2() {
18841
- writeMcpPins({ servers: {} });
18842
- }
18843
-
18844
- // src/mcp-gateway/index.ts
18927
+ init_mcp_pin();
18845
18928
  init_mcp_tools();
18846
18929
  init_daemon();
18847
18930
  function sanitize4(value) {
@@ -18903,6 +18986,7 @@ function tokenize4(cmd) {
18903
18986
  return tokens;
18904
18987
  }
18905
18988
  async function runMcpGateway(upstreamCommand) {
18989
+ const gatewayCwd = process.cwd();
18906
18990
  const commandParts = tokenize4(upstreamCommand);
18907
18991
  const cmd = commandParts[0];
18908
18992
  const cmdArgs = commandParts.slice(1);
@@ -19125,7 +19209,7 @@ async function runMcpGateway(upstreamCommand) {
19125
19209
  if (parsed.result && Array.isArray(parsed.result.tools)) {
19126
19210
  const tools = parsed.result.tools || [];
19127
19211
  const currentHash = hashToolDefinitions(tools);
19128
- const pinStatus = checkPin(serverKey, currentHash);
19212
+ const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
19129
19213
  const token = getInternalToken();
19130
19214
  if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
19131
19215
  const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
@@ -20009,27 +20093,46 @@ function registerTrustCommand(program2) {
20009
20093
  }
20010
20094
 
20011
20095
  // src/cli/commands/mcp-pin.ts
20096
+ init_mcp_pin();
20012
20097
  import chalk21 from "chalk";
20098
+ import fs40 from "fs";
20013
20099
  function registerMcpPinCommand(program2) {
20014
20100
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
20015
20101
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
20016
20102
  pinSubCmd.command("list").description("Show all pinned MCP servers and their tool definition hashes").action(() => {
20017
- const result = readMcpPinsSafe();
20018
- if (!result.ok) {
20019
- if (result.reason === "missing") {
20020
- console.log(chalk21.gray("\nNo MCP servers are pinned yet."));
20021
- console.log(
20022
- chalk21.gray("Pins are created automatically when the MCP gateway first connects.\n")
20023
- );
20024
- return;
20103
+ const found = findPinsFilePath(process.cwd());
20104
+ const homeResult = readMcpPinsSafe();
20105
+ let repoEntries = {};
20106
+ let repoCorrupt = false;
20107
+ if (found.source === "repo") {
20108
+ try {
20109
+ const raw = fs40.readFileSync(found.path, "utf-8");
20110
+ const parsed = JSON.parse(raw);
20111
+ repoEntries = parsed.servers ?? {};
20112
+ } catch {
20113
+ repoCorrupt = true;
20025
20114
  }
20115
+ }
20116
+ if (repoCorrupt) {
20026
20117
  console.error(chalk21.red(`
20027
- \u274C Pin file is corrupt: ${result.detail}`));
20118
+ \u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
20119
+ process.exit(1);
20120
+ }
20121
+ if (!homeResult.ok && homeResult.reason === "corrupt") {
20122
+ console.error(chalk21.red(`
20123
+ \u274C Home pin file is corrupt: ${homeResult.detail}`));
20028
20124
  console.error(chalk21.yellow(" Run: node9 mcp pin reset\n"));
20029
20125
  process.exit(1);
20030
20126
  }
20031
- const entries = Object.entries(result.pins.servers);
20032
- if (entries.length === 0) {
20127
+ const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
20128
+ const merged = /* @__PURE__ */ new Map();
20129
+ for (const [key, entry] of Object.entries(homeEntries)) {
20130
+ merged.set(key, { entry, source: "home" });
20131
+ }
20132
+ for (const [key, entry] of Object.entries(repoEntries)) {
20133
+ merged.set(key, { entry, source: "repo" });
20134
+ }
20135
+ if (merged.size === 0) {
20033
20136
  console.log(chalk21.gray("\nNo MCP servers are pinned yet."));
20034
20137
  console.log(
20035
20138
  chalk21.gray("Pins are created automatically when the MCP gateway first connects.\n")
@@ -20037,13 +20140,47 @@ function registerMcpPinCommand(program2) {
20037
20140
  return;
20038
20141
  }
20039
20142
  console.log(chalk21.bold("\n\u{1F512} Pinned MCP Servers\n"));
20040
- for (const [key, entry] of entries) {
20041
- console.log(` ${chalk21.cyan(key)} ${chalk21.gray(entry.label)}`);
20143
+ const showSource = found.source === "repo";
20144
+ for (const [key, { entry, source }] of merged) {
20145
+ const tag = showSource ? ` ${chalk21.yellow(`[${source}]`)}` : "";
20146
+ console.log(` ${chalk21.cyan(key)}${tag} ${chalk21.gray(entry.label)}`);
20042
20147
  console.log(` Tools (${entry.toolCount}): ${chalk21.white(entry.toolNames.join(", "))}`);
20043
20148
  console.log(` Hash: ${chalk21.gray(entry.toolsHash.slice(0, 16))}...`);
20044
20149
  console.log(` Pinned: ${chalk21.gray(entry.pinnedAt)}`);
20045
20150
  console.log("");
20046
20151
  }
20152
+ if (showSource) {
20153
+ console.log(chalk21.gray(` [repo] entries come from ${found.path}`));
20154
+ console.log(chalk21.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
20155
+ }
20156
+ });
20157
+ pinSubCmd.command("promote <serverKey>").description(
20158
+ "Copy a pin from ~/.node9/mcp-pins.json into <repo>/.node9/mcp-pins.json so teammates share the same vetted baseline"
20159
+ ).action((serverKey) => {
20160
+ try {
20161
+ const { repoPath, created } = promotePin(serverKey, process.cwd());
20162
+ if (created) {
20163
+ console.log(
20164
+ chalk21.green(
20165
+ `
20166
+ \u2705 Created ${repoPath} with the promoted pin for ${chalk21.cyan(serverKey)}.`
20167
+ )
20168
+ );
20169
+ } else {
20170
+ console.log(chalk21.green(`
20171
+ \u2705 Promoted ${chalk21.cyan(serverKey)} into ${repoPath}.`));
20172
+ }
20173
+ console.log(chalk21.gray(" Review the change and commit it:"));
20174
+ console.log(chalk21.cyan(` git add ${repoPath}`));
20175
+ console.log(chalk21.cyan(` git commit -m "pin ${serverKey} (node9)"`));
20176
+ console.log("");
20177
+ } catch (err2) {
20178
+ const msg = err2 instanceof Error ? err2.message : String(err2);
20179
+ console.error(chalk21.red(`
20180
+ \u274C ${msg}
20181
+ `));
20182
+ process.exit(1);
20183
+ }
20047
20184
  });
20048
20185
  pinSubCmd.command("update <serverKey>").description(
20049
20186
  "Remove a pin so the next gateway connection re-pins with current tool definitions"
@@ -20065,7 +20202,7 @@ function registerMcpPinCommand(program2) {
20065
20202
  process.exit(1);
20066
20203
  }
20067
20204
  const label = pins.servers[serverKey].label;
20068
- removePin2(serverKey);
20205
+ removePin(serverKey);
20069
20206
  console.log(chalk21.green(`
20070
20207
  \u{1F513} Pin removed for ${chalk21.cyan(serverKey)}`));
20071
20208
  console.log(chalk21.gray(` Server: ${label}`));
@@ -20078,7 +20215,7 @@ function registerMcpPinCommand(program2) {
20078
20215
  return;
20079
20216
  }
20080
20217
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
20081
- clearAllPins2();
20218
+ clearAllPins();
20082
20219
  console.log(chalk21.green(`
20083
20220
  \u{1F513} Cleared ${count} MCP pin(s).`));
20084
20221
  console.log(chalk21.gray(" Next connection to each server will re-pin.\n"));
@@ -20261,7 +20398,7 @@ init_scan();
20261
20398
 
20262
20399
  // src/cli/commands/sessions.ts
20263
20400
  import chalk24 from "chalk";
20264
- import fs40 from "fs";
20401
+ import fs41 from "fs";
20265
20402
  import path42 from "path";
20266
20403
  import os36 from "os";
20267
20404
  var CLAUDE_PRICING3 = {
@@ -20379,7 +20516,7 @@ function loadAuditEntries(auditPath) {
20379
20516
  const aPath = auditPath ?? path42.join(os36.homedir(), ".node9", "audit.log");
20380
20517
  let raw;
20381
20518
  try {
20382
- raw = fs40.readFileSync(aPath, "utf-8");
20519
+ raw = fs41.readFileSync(aPath, "utf-8");
20383
20520
  } catch {
20384
20521
  return [];
20385
20522
  }
@@ -20416,7 +20553,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
20416
20553
  }
20417
20554
  function buildGeminiSessions(days, allAuditEntries) {
20418
20555
  const tmpDir = path42.join(os36.homedir(), ".gemini", "tmp");
20419
- if (!fs40.existsSync(tmpDir)) return [];
20556
+ if (!fs41.existsSync(tmpDir)) return [];
20420
20557
  const cutoff = days !== null ? (() => {
20421
20558
  const d = /* @__PURE__ */ new Date();
20422
20559
  d.setDate(d.getDate() - days);
@@ -20425,7 +20562,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20425
20562
  })() : null;
20426
20563
  let slugDirs;
20427
20564
  try {
20428
- slugDirs = fs40.readdirSync(tmpDir);
20565
+ slugDirs = fs41.readdirSync(tmpDir);
20429
20566
  } catch {
20430
20567
  return [];
20431
20568
  }
@@ -20433,27 +20570,27 @@ function buildGeminiSessions(days, allAuditEntries) {
20433
20570
  for (const slug of slugDirs) {
20434
20571
  const slugPath = path42.join(tmpDir, slug);
20435
20572
  try {
20436
- if (!fs40.statSync(slugPath).isDirectory()) continue;
20573
+ if (!fs41.statSync(slugPath).isDirectory()) continue;
20437
20574
  } catch {
20438
20575
  continue;
20439
20576
  }
20440
20577
  let projectRoot = path42.join(os36.homedir(), slug);
20441
20578
  try {
20442
- projectRoot = fs40.readFileSync(path42.join(slugPath, ".project_root"), "utf-8").trim();
20579
+ projectRoot = fs41.readFileSync(path42.join(slugPath, ".project_root"), "utf-8").trim();
20443
20580
  } catch {
20444
20581
  }
20445
20582
  const chatsDir = path42.join(slugPath, "chats");
20446
- if (!fs40.existsSync(chatsDir)) continue;
20583
+ if (!fs41.existsSync(chatsDir)) continue;
20447
20584
  let chatFiles;
20448
20585
  try {
20449
- chatFiles = fs40.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20586
+ chatFiles = fs41.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20450
20587
  } catch {
20451
20588
  continue;
20452
20589
  }
20453
20590
  for (const chatFile of chatFiles) {
20454
20591
  let raw;
20455
20592
  try {
20456
- raw = fs40.readFileSync(path42.join(chatsDir, chatFile), "utf-8");
20593
+ raw = fs41.readFileSync(path42.join(chatsDir, chatFile), "utf-8");
20457
20594
  } catch {
20458
20595
  continue;
20459
20596
  }
@@ -20534,7 +20671,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20534
20671
  }
20535
20672
  function buildCodexSessions(days, allAuditEntries) {
20536
20673
  const sessionsBase = path42.join(os36.homedir(), ".codex", "sessions");
20537
- if (!fs40.existsSync(sessionsBase)) return [];
20674
+ if (!fs41.existsSync(sessionsBase)) return [];
20538
20675
  const cutoff = days !== null ? (() => {
20539
20676
  const d = /* @__PURE__ */ new Date();
20540
20677
  d.setDate(d.getDate() - days);
@@ -20543,28 +20680,28 @@ function buildCodexSessions(days, allAuditEntries) {
20543
20680
  })() : null;
20544
20681
  const jsonlFiles = [];
20545
20682
  try {
20546
- for (const year of fs40.readdirSync(sessionsBase)) {
20683
+ for (const year of fs41.readdirSync(sessionsBase)) {
20547
20684
  const yearPath = path42.join(sessionsBase, year);
20548
20685
  try {
20549
- if (!fs40.statSync(yearPath).isDirectory()) continue;
20686
+ if (!fs41.statSync(yearPath).isDirectory()) continue;
20550
20687
  } catch {
20551
20688
  continue;
20552
20689
  }
20553
- for (const month of fs40.readdirSync(yearPath)) {
20690
+ for (const month of fs41.readdirSync(yearPath)) {
20554
20691
  const monthPath = path42.join(yearPath, month);
20555
20692
  try {
20556
- if (!fs40.statSync(monthPath).isDirectory()) continue;
20693
+ if (!fs41.statSync(monthPath).isDirectory()) continue;
20557
20694
  } catch {
20558
20695
  continue;
20559
20696
  }
20560
- for (const day of fs40.readdirSync(monthPath)) {
20697
+ for (const day of fs41.readdirSync(monthPath)) {
20561
20698
  const dayPath = path42.join(monthPath, day);
20562
20699
  try {
20563
- if (!fs40.statSync(dayPath).isDirectory()) continue;
20700
+ if (!fs41.statSync(dayPath).isDirectory()) continue;
20564
20701
  } catch {
20565
20702
  continue;
20566
20703
  }
20567
- for (const file of fs40.readdirSync(dayPath)) {
20704
+ for (const file of fs41.readdirSync(dayPath)) {
20568
20705
  if (file.endsWith(".jsonl")) jsonlFiles.push(path42.join(dayPath, file));
20569
20706
  }
20570
20707
  }
@@ -20577,7 +20714,7 @@ function buildCodexSessions(days, allAuditEntries) {
20577
20714
  for (const filePath of jsonlFiles) {
20578
20715
  let lines;
20579
20716
  try {
20580
- lines = fs40.readFileSync(filePath, "utf-8").split("\n");
20717
+ lines = fs41.readFileSync(filePath, "utf-8").split("\n");
20581
20718
  } catch {
20582
20719
  continue;
20583
20720
  }
@@ -20658,7 +20795,7 @@ function buildSessions(days, historyPath) {
20658
20795
  const hPath = historyPath ?? path42.join(os36.homedir(), ".claude", "history.jsonl");
20659
20796
  let historyRaw;
20660
20797
  try {
20661
- historyRaw = fs40.readFileSync(hPath, "utf-8");
20798
+ historyRaw = fs41.readFileSync(hPath, "utf-8");
20662
20799
  } catch {
20663
20800
  return [];
20664
20801
  }
@@ -20683,7 +20820,7 @@ function buildSessions(days, historyPath) {
20683
20820
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
20684
20821
  let sessionLines = [];
20685
20822
  try {
20686
- sessionLines = fs40.readFileSync(jsonlFile, "utf-8").split("\n");
20823
+ sessionLines = fs41.readFileSync(jsonlFile, "utf-8").split("\n");
20687
20824
  } catch {
20688
20825
  }
20689
20826
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -20950,7 +21087,7 @@ function registerSessionsCommand(program2) {
20950
21087
  console.log(chalk24.cyan.bold("\u{1F4CB} node9 sessions") + chalk24.dim(" \u2014 what your AI agent did"));
20951
21088
  console.log("");
20952
21089
  const historyPath = path42.join(os36.homedir(), ".claude", "history.jsonl");
20953
- if (!fs40.existsSync(historyPath)) {
21090
+ if (!fs41.existsSync(historyPath)) {
20954
21091
  console.log(chalk24.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
20955
21092
  console.log(chalk24.gray(" Install Claude Code, run a few sessions, then try again.\n"));
20956
21093
  return;
@@ -20987,12 +21124,12 @@ function registerSessionsCommand(program2) {
20987
21124
 
20988
21125
  // src/cli/commands/skill-pin.ts
20989
21126
  import chalk25 from "chalk";
20990
- import fs41 from "fs";
21127
+ import fs42 from "fs";
20991
21128
  import os37 from "os";
20992
21129
  import path43 from "path";
20993
21130
  function wipeSkillSessions() {
20994
21131
  try {
20995
- fs41.rmSync(path43.join(os37.homedir(), ".node9", "skill-sessions"), {
21132
+ fs42.rmSync(path43.join(os37.homedir(), ".node9", "skill-sessions"), {
20996
21133
  recursive: true,
20997
21134
  force: true
20998
21135
  });
@@ -21050,7 +21187,7 @@ function registerSkillPinCommand(program2) {
21050
21187
  process.exit(1);
21051
21188
  }
21052
21189
  const rootPath = pins.roots[rootKey].rootPath;
21053
- removePin(rootKey);
21190
+ removePin2(rootKey);
21054
21191
  wipeSkillSessions();
21055
21192
  console.log(chalk25.green(`
21056
21193
  \u{1F513} Pin removed for ${chalk25.cyan(rootKey)}`));
@@ -21065,7 +21202,7 @@ function registerSkillPinCommand(program2) {
21065
21202
  return;
21066
21203
  }
21067
21204
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
21068
- clearAllPins();
21205
+ clearAllPins2();
21069
21206
  wipeSkillSessions();
21070
21207
  console.log(chalk25.green(`
21071
21208
  \u{1F513} Cleared ${count} skill pin(s).`));
@@ -21074,15 +21211,15 @@ function registerSkillPinCommand(program2) {
21074
21211
  }
21075
21212
 
21076
21213
  // src/cli/commands/decisions.ts
21077
- import fs42 from "fs";
21214
+ import fs43 from "fs";
21078
21215
  import os38 from "os";
21079
21216
  import path44 from "path";
21080
21217
  import chalk26 from "chalk";
21081
21218
  var DECISIONS_FILE2 = path44.join(os38.homedir(), ".node9", "decisions.json");
21082
21219
  function readDecisions() {
21083
21220
  try {
21084
- if (!fs42.existsSync(DECISIONS_FILE2)) return {};
21085
- const raw = fs42.readFileSync(DECISIONS_FILE2, "utf-8");
21221
+ if (!fs43.existsSync(DECISIONS_FILE2)) return {};
21222
+ const raw = fs43.readFileSync(DECISIONS_FILE2, "utf-8");
21086
21223
  const parsed = JSON.parse(raw);
21087
21224
  const out = {};
21088
21225
  for (const [k, v] of Object.entries(parsed)) {
@@ -21095,10 +21232,10 @@ function readDecisions() {
21095
21232
  }
21096
21233
  function writeDecisions(d) {
21097
21234
  const dir = path44.dirname(DECISIONS_FILE2);
21098
- if (!fs42.existsSync(dir)) fs42.mkdirSync(dir, { recursive: true });
21235
+ if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
21099
21236
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
21100
- fs42.writeFileSync(tmp, JSON.stringify(d, null, 2));
21101
- fs42.renameSync(tmp, DECISIONS_FILE2);
21237
+ fs43.writeFileSync(tmp, JSON.stringify(d, null, 2));
21238
+ fs43.renameSync(tmp, DECISIONS_FILE2);
21102
21239
  }
21103
21240
  function registerDecisionsCommand(program2) {
21104
21241
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -21155,7 +21292,7 @@ Persistent decisions (${entries.length})
21155
21292
 
21156
21293
  // src/cli/commands/dlp.ts
21157
21294
  import chalk27 from "chalk";
21158
- import fs43 from "fs";
21295
+ import fs44 from "fs";
21159
21296
  import path45 from "path";
21160
21297
  import os39 from "os";
21161
21298
  var AUDIT_LOG = path45.join(os39.homedir(), ".node9", "audit.log");
@@ -21166,7 +21303,7 @@ function stripAnsi(s) {
21166
21303
  }
21167
21304
  function loadResolved() {
21168
21305
  try {
21169
- const raw = JSON.parse(fs43.readFileSync(RESOLVED_FILE, "utf-8"));
21306
+ const raw = JSON.parse(fs44.readFileSync(RESOLVED_FILE, "utf-8"));
21170
21307
  return new Set(raw);
21171
21308
  } catch {
21172
21309
  return /* @__PURE__ */ new Set();
@@ -21174,13 +21311,13 @@ function loadResolved() {
21174
21311
  }
21175
21312
  function saveResolved(resolved) {
21176
21313
  try {
21177
- fs43.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21314
+ fs44.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21178
21315
  } catch {
21179
21316
  }
21180
21317
  }
21181
21318
  function loadDlpFindings() {
21182
- if (!fs43.existsSync(AUDIT_LOG)) return [];
21183
- return fs43.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
21319
+ if (!fs44.existsSync(AUDIT_LOG)) return [];
21320
+ return fs44.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
21184
21321
  if (!line.trim()) return [];
21185
21322
  try {
21186
21323
  const e = JSON.parse(line);
@@ -21279,13 +21416,13 @@ function registerDlpCommand(program2) {
21279
21416
  // src/cli/commands/mask.ts
21280
21417
  init_dlp();
21281
21418
  import chalk28 from "chalk";
21282
- import fs44 from "fs";
21419
+ import fs45 from "fs";
21283
21420
  import path46 from "path";
21284
21421
  import os40 from "os";
21285
21422
  function findJsonlFiles(dir) {
21286
21423
  const results = [];
21287
- if (!fs44.existsSync(dir)) return results;
21288
- for (const entry of fs44.readdirSync(dir, { withFileTypes: true })) {
21424
+ if (!fs45.existsSync(dir)) return results;
21425
+ for (const entry of fs45.readdirSync(dir, { withFileTypes: true })) {
21289
21426
  const full = path46.join(dir, entry.name);
21290
21427
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
21291
21428
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
@@ -21329,7 +21466,7 @@ function redactJson(obj) {
21329
21466
  function processFile(filePath, dryRun) {
21330
21467
  let raw;
21331
21468
  try {
21332
- raw = fs44.readFileSync(filePath, "utf-8");
21469
+ raw = fs45.readFileSync(filePath, "utf-8");
21333
21470
  } catch {
21334
21471
  return { redactedLines: 0, patterns: [] };
21335
21472
  }
@@ -21361,14 +21498,14 @@ function processFile(filePath, dryRun) {
21361
21498
  }
21362
21499
  }
21363
21500
  if (!dryRun && redactedLines > 0) {
21364
- fs44.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21501
+ fs45.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21365
21502
  }
21366
21503
  return { redactedLines, patterns };
21367
21504
  }
21368
21505
  function processJsonFile(filePath, dryRun) {
21369
21506
  let raw;
21370
21507
  try {
21371
- raw = fs44.readFileSync(filePath, "utf-8");
21508
+ raw = fs45.readFileSync(filePath, "utf-8");
21372
21509
  } catch {
21373
21510
  return { redactedLines: 0, patterns: [] };
21374
21511
  }
@@ -21381,14 +21518,14 @@ function processJsonFile(filePath, dryRun) {
21381
21518
  const { value, modified, found } = redactJson(parsed);
21382
21519
  if (!modified) return { redactedLines: 0, patterns: [] };
21383
21520
  if (!dryRun) {
21384
- fs44.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21521
+ fs45.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21385
21522
  }
21386
21523
  return { redactedLines: 1, patterns: found };
21387
21524
  }
21388
21525
  function findJsonFiles(dir) {
21389
21526
  const results = [];
21390
- if (!fs44.existsSync(dir)) return results;
21391
- for (const entry of fs44.readdirSync(dir, { withFileTypes: true })) {
21527
+ if (!fs45.existsSync(dir)) return results;
21528
+ for (const entry of fs45.readdirSync(dir, { withFileTypes: true })) {
21392
21529
  const full = path46.join(dir, entry.name);
21393
21530
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
21394
21531
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
@@ -21408,7 +21545,7 @@ function registerMaskCommand(program2) {
21408
21545
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
21409
21546
  const filtered = cutoff ? allFiles.filter((f) => {
21410
21547
  try {
21411
- return fs44.statSync(f.path).mtime >= cutoff;
21548
+ return fs45.statSync(f.path).mtime >= cutoff;
21412
21549
  } catch {
21413
21550
  return false;
21414
21551
  }
@@ -21464,20 +21601,20 @@ function registerMaskCommand(program2) {
21464
21601
  // src/cli.ts
21465
21602
  init_blast();
21466
21603
  var { version } = JSON.parse(
21467
- fs47.readFileSync(path49.join(__dirname, "../package.json"), "utf-8")
21604
+ fs48.readFileSync(path49.join(__dirname, "../package.json"), "utf-8")
21468
21605
  );
21469
21606
  var program = new Command();
21470
21607
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
21471
21608
  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) => {
21472
21609
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
21473
21610
  const credPath = path49.join(os43.homedir(), ".node9", "credentials.json");
21474
- if (!fs47.existsSync(path49.dirname(credPath)))
21475
- fs47.mkdirSync(path49.dirname(credPath), { recursive: true });
21611
+ if (!fs48.existsSync(path49.dirname(credPath)))
21612
+ fs48.mkdirSync(path49.dirname(credPath), { recursive: true });
21476
21613
  const profileName = options.profile || "default";
21477
21614
  let existingCreds = {};
21478
21615
  try {
21479
- if (fs47.existsSync(credPath)) {
21480
- const raw = JSON.parse(fs47.readFileSync(credPath, "utf-8"));
21616
+ if (fs48.existsSync(credPath)) {
21617
+ const raw = JSON.parse(fs48.readFileSync(credPath, "utf-8"));
21481
21618
  if (raw.apiKey) {
21482
21619
  existingCreds = {
21483
21620
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -21489,13 +21626,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21489
21626
  } catch {
21490
21627
  }
21491
21628
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
21492
- fs47.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21629
+ fs48.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21493
21630
  if (profileName === "default") {
21494
21631
  const configPath = path49.join(os43.homedir(), ".node9", "config.json");
21495
21632
  let config = {};
21496
21633
  try {
21497
- if (fs47.existsSync(configPath))
21498
- config = JSON.parse(fs47.readFileSync(configPath, "utf-8"));
21634
+ if (fs48.existsSync(configPath))
21635
+ config = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
21499
21636
  } catch {
21500
21637
  }
21501
21638
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -21510,9 +21647,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21510
21647
  approvers.cloud = false;
21511
21648
  }
21512
21649
  s.approvers = approvers;
21513
- if (!fs47.existsSync(path49.dirname(configPath)))
21514
- fs47.mkdirSync(path49.dirname(configPath), { recursive: true });
21515
- fs47.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
21650
+ if (!fs48.existsSync(path49.dirname(configPath)))
21651
+ fs48.mkdirSync(path49.dirname(configPath), { recursive: true });
21652
+ fs48.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
21516
21653
  }
21517
21654
  if (options.profile && profileName !== "default") {
21518
21655
  console.log(chalk30.green(`\u2705 Profile "${profileName}" saved`));
@@ -21650,14 +21787,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
21650
21787
  }
21651
21788
  if (options.purge) {
21652
21789
  const node9Dir = path49.join(os43.homedir(), ".node9");
21653
- if (fs47.existsSync(node9Dir)) {
21790
+ if (fs48.existsSync(node9Dir)) {
21654
21791
  const confirmed = await confirm2({
21655
21792
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
21656
21793
  default: false
21657
21794
  });
21658
21795
  if (confirmed) {
21659
- fs47.rmSync(node9Dir, { recursive: true });
21660
- if (fs47.existsSync(node9Dir)) {
21796
+ fs48.rmSync(node9Dir, { recursive: true });
21797
+ if (fs48.existsSync(node9Dir)) {
21661
21798
  console.error(
21662
21799
  chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
21663
21800
  );
@@ -21812,12 +21949,12 @@ Run "node9 addto claude" to register it as the statusLine.`
21812
21949
  if (subcommand === "debug") {
21813
21950
  const flagFile = path49.join(os43.homedir(), ".node9", "hud-debug");
21814
21951
  if (state === "on") {
21815
- fs47.mkdirSync(path49.dirname(flagFile), { recursive: true });
21816
- fs47.writeFileSync(flagFile, "");
21952
+ fs48.mkdirSync(path49.dirname(flagFile), { recursive: true });
21953
+ fs48.writeFileSync(flagFile, "");
21817
21954
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
21818
21955
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
21819
21956
  } else if (state === "off") {
21820
- if (fs47.existsSync(flagFile)) fs47.unlinkSync(flagFile);
21957
+ if (fs48.existsSync(flagFile)) fs48.unlinkSync(flagFile);
21821
21958
  console.log("HUD debug logging disabled.");
21822
21959
  } else {
21823
21960
  console.error("Usage: node9 hud debug on|off");
@@ -21933,7 +22070,7 @@ if (process.argv[2] !== "daemon") {
21933
22070
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
21934
22071
  const logPath = path49.join(os43.homedir(), ".node9", "hook-debug.log");
21935
22072
  const msg = reason instanceof Error ? reason.message : String(reason);
21936
- fs47.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
22073
+ fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
21937
22074
  `);
21938
22075
  }
21939
22076
  process.exit(0);