@node9/proxy 1.22.0 → 1.23.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
  }
@@ -10863,7 +11028,7 @@ function registerScanCommand(program2) {
10863
11028
  if (!drillDown) {
10864
11029
  const useInk2 = !options.classic;
10865
11030
  if (useInk2) {
10866
- const scanInkPath = path21.join(__dirname, "scan-ink.mjs");
11031
+ const scanInkPath = path22.join(__dirname, "scan-ink.mjs");
10867
11032
  const dynamicImport = new Function("id", "return import(id)");
10868
11033
  const mod = await dynamicImport(`file://${scanInkPath}`);
10869
11034
  const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
@@ -11281,8 +11446,8 @@ var init_suggestion_tracker = __esm({
11281
11446
  });
11282
11447
 
11283
11448
  // src/daemon/taint-store.ts
11284
- import fs20 from "fs";
11285
- import path22 from "path";
11449
+ import fs21 from "fs";
11450
+ import path23 from "path";
11286
11451
  var DEFAULT_TTL_MS, TaintStore;
11287
11452
  var init_taint_store = __esm({
11288
11453
  "src/daemon/taint-store.ts"() {
@@ -11351,9 +11516,9 @@ var init_taint_store = __esm({
11351
11516
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
11352
11517
  _resolve(filePath) {
11353
11518
  try {
11354
- return fs20.realpathSync.native(path22.resolve(filePath));
11519
+ return fs21.realpathSync.native(path23.resolve(filePath));
11355
11520
  } catch {
11356
- return path22.resolve(filePath);
11521
+ return path23.resolve(filePath);
11357
11522
  }
11358
11523
  }
11359
11524
  };
@@ -11470,14 +11635,14 @@ var init_session_history = __esm({
11470
11635
 
11471
11636
  // src/daemon/state.ts
11472
11637
  import net2 from "net";
11473
- import fs21 from "fs";
11474
- import path23 from "path";
11475
- import os19 from "os";
11638
+ import fs22 from "fs";
11639
+ import path24 from "path";
11640
+ import os20 from "os";
11476
11641
  import { randomUUID as randomUUID3 } from "crypto";
11477
11642
  function loadInsightCounts() {
11478
11643
  try {
11479
- if (!fs21.existsSync(INSIGHT_COUNTS_FILE)) return;
11480
- const data = JSON.parse(fs21.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
11644
+ if (!fs22.existsSync(INSIGHT_COUNTS_FILE)) return;
11645
+ const data = JSON.parse(fs22.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
11481
11646
  for (const [tool, count] of Object.entries(data)) {
11482
11647
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
11483
11648
  }
@@ -11516,23 +11681,23 @@ function markRejectionHandlerRegistered() {
11516
11681
  daemonRejectionHandlerRegistered = true;
11517
11682
  }
11518
11683
  function atomicWriteSync2(filePath, data, options) {
11519
- const dir = path23.dirname(filePath);
11520
- if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
11684
+ const dir = path24.dirname(filePath);
11685
+ if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
11521
11686
  const tmpPath = `${filePath}.${randomUUID3()}.tmp`;
11522
11687
  try {
11523
- fs21.writeFileSync(tmpPath, data, options);
11688
+ fs22.writeFileSync(tmpPath, data, options);
11524
11689
  } catch (err2) {
11525
11690
  try {
11526
- fs21.unlinkSync(tmpPath);
11691
+ fs22.unlinkSync(tmpPath);
11527
11692
  } catch {
11528
11693
  }
11529
11694
  throw err2;
11530
11695
  }
11531
11696
  try {
11532
- fs21.renameSync(tmpPath, filePath);
11697
+ fs22.renameSync(tmpPath, filePath);
11533
11698
  } catch (err2) {
11534
11699
  try {
11535
- fs21.unlinkSync(tmpPath);
11700
+ fs22.unlinkSync(tmpPath);
11536
11701
  } catch {
11537
11702
  }
11538
11703
  throw err2;
@@ -11556,16 +11721,16 @@ function appendAuditLog(data) {
11556
11721
  decision: data.decision,
11557
11722
  source: "daemon"
11558
11723
  };
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");
11724
+ const dir = path24.dirname(AUDIT_LOG_FILE);
11725
+ if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
11726
+ fs22.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
11562
11727
  } catch {
11563
11728
  }
11564
11729
  }
11565
11730
  function getAuditHistory(limit = 20) {
11566
11731
  try {
11567
- if (!fs21.existsSync(AUDIT_LOG_FILE)) return [];
11568
- const lines = fs21.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
11732
+ if (!fs22.existsSync(AUDIT_LOG_FILE)) return [];
11733
+ const lines = fs22.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
11569
11734
  if (lines.length === 1 && lines[0] === "") return [];
11570
11735
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
11571
11736
  } catch {
@@ -11574,7 +11739,7 @@ function getAuditHistory(limit = 20) {
11574
11739
  }
11575
11740
  function getOrgName() {
11576
11741
  try {
11577
- if (fs21.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11742
+ if (fs22.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11578
11743
  } catch {
11579
11744
  }
11580
11745
  return null;
@@ -11582,8 +11747,8 @@ function getOrgName() {
11582
11747
  function writeGlobalSetting(key, value) {
11583
11748
  let config = {};
11584
11749
  try {
11585
- if (fs21.existsSync(GLOBAL_CONFIG_FILE)) {
11586
- config = JSON.parse(fs21.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11750
+ if (fs22.existsSync(GLOBAL_CONFIG_FILE)) {
11751
+ config = JSON.parse(fs22.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11587
11752
  }
11588
11753
  } catch {
11589
11754
  }
@@ -11595,8 +11760,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11595
11760
  try {
11596
11761
  let trust = { entries: [] };
11597
11762
  try {
11598
- if (fs21.existsSync(TRUST_FILE2))
11599
- trust = JSON.parse(fs21.readFileSync(TRUST_FILE2, "utf-8"));
11763
+ if (fs22.existsSync(TRUST_FILE2))
11764
+ trust = JSON.parse(fs22.readFileSync(TRUST_FILE2, "utf-8"));
11600
11765
  } catch {
11601
11766
  }
11602
11767
  trust.entries = trust.entries.filter(
@@ -11613,8 +11778,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11613
11778
  }
11614
11779
  function readPersistentDecisions() {
11615
11780
  try {
11616
- if (fs21.existsSync(DECISIONS_FILE)) {
11617
- return JSON.parse(fs21.readFileSync(DECISIONS_FILE, "utf-8"));
11781
+ if (fs22.existsSync(DECISIONS_FILE)) {
11782
+ return JSON.parse(fs22.readFileSync(DECISIONS_FILE, "utf-8"));
11618
11783
  }
11619
11784
  } catch {
11620
11785
  }
@@ -11642,7 +11807,7 @@ function estimateToolCost(tool, args) {
11642
11807
  const filePath = a.file_path ?? a.path;
11643
11808
  if (filePath) {
11644
11809
  try {
11645
- const bytes = fs21.statSync(filePath).size;
11810
+ const bytes = fs22.statSync(filePath).size;
11646
11811
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
11647
11812
  } catch {
11648
11813
  }
@@ -11713,7 +11878,7 @@ function abandonPending() {
11713
11878
  });
11714
11879
  if (autoStarted) {
11715
11880
  try {
11716
- fs21.unlinkSync(DAEMON_PID_FILE);
11881
+ fs22.unlinkSync(DAEMON_PID_FILE);
11717
11882
  } catch {
11718
11883
  }
11719
11884
  setTimeout(() => {
@@ -11724,8 +11889,8 @@ function abandonPending() {
11724
11889
  }
11725
11890
  function logActivitySocket(msg) {
11726
11891
  try {
11727
- fs21.appendFileSync(
11728
- path23.join(homeDir, ".node9", "hook-debug.log"),
11892
+ fs22.appendFileSync(
11893
+ path24.join(homeDir, ".node9", "hook-debug.log"),
11729
11894
  `[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
11730
11895
  `
11731
11896
  );
@@ -11747,13 +11912,13 @@ function shouldRebind(now = Date.now()) {
11747
11912
  function startActivitySocket() {
11748
11913
  bindActivitySocket();
11749
11914
  activityHealthInterval = setInterval(() => {
11750
- if (!fs21.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11915
+ if (!fs22.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11751
11916
  }, ACTIVITY_HEALTH_PROBE_MS);
11752
11917
  activityHealthInterval.unref();
11753
11918
  process.on("exit", () => {
11754
11919
  if (activityHealthInterval) clearInterval(activityHealthInterval);
11755
11920
  try {
11756
- fs21.unlinkSync(ACTIVITY_SOCKET_PATH2);
11921
+ fs22.unlinkSync(ACTIVITY_SOCKET_PATH2);
11757
11922
  } catch {
11758
11923
  }
11759
11924
  });
@@ -11781,7 +11946,7 @@ function attemptRebind(reason) {
11781
11946
  }
11782
11947
  function bindActivitySocket() {
11783
11948
  try {
11784
- fs21.unlinkSync(ACTIVITY_SOCKET_PATH2);
11949
+ fs22.unlinkSync(ACTIVITY_SOCKET_PATH2);
11785
11950
  } catch {
11786
11951
  }
11787
11952
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
@@ -11894,14 +12059,14 @@ var init_state2 = __esm({
11894
12059
  init_taint_store();
11895
12060
  init_session_counters();
11896
12061
  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");
12062
+ homeDir = os20.homedir();
12063
+ DAEMON_PID_FILE = path24.join(homeDir, ".node9", "daemon.pid");
12064
+ DECISIONS_FILE = path24.join(homeDir, ".node9", "decisions.json");
12065
+ AUDIT_LOG_FILE = path24.join(homeDir, ".node9", "audit.log");
12066
+ TRUST_FILE2 = path24.join(homeDir, ".node9", "trust.json");
12067
+ GLOBAL_CONFIG_FILE = path24.join(homeDir, ".node9", "config.json");
12068
+ CREDENTIALS_FILE = path24.join(homeDir, ".node9", "credentials.json");
12069
+ INSIGHT_COUNTS_FILE = path24.join(homeDir, ".node9", "insight-counts.json");
11905
12070
  pending = /* @__PURE__ */ new Map();
11906
12071
  sseClients = /* @__PURE__ */ new Set();
11907
12072
  suggestionTracker = new SuggestionTracker(3);
@@ -11918,7 +12083,7 @@ var init_state2 = __esm({
11918
12083
  "2h": 2 * 60 * 6e4
11919
12084
  };
11920
12085
  autoStarted = process.env.NODE9_AUTO_STARTED === "1";
11921
- ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path23.join(os19.tmpdir(), "node9-activity.sock");
12086
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path24.join(os20.tmpdir(), "node9-activity.sock");
11922
12087
  ACTIVITY_RING_SIZE = 100;
11923
12088
  activityRing = [];
11924
12089
  LARGE_RESPONSE_RING_SIZE = 20;
@@ -11957,10 +12122,10 @@ var init_state2 = __esm({
11957
12122
  });
11958
12123
 
11959
12124
  // src/daemon/sync.ts
11960
- import fs22 from "fs";
12125
+ import fs23 from "fs";
11961
12126
  import https2 from "https";
11962
- import os20 from "os";
11963
- import path24 from "path";
12127
+ import os21 from "os";
12128
+ import path25 from "path";
11964
12129
  function emptySignals3() {
11965
12130
  return {
11966
12131
  dlpFindings: 0,
@@ -12000,8 +12165,8 @@ function readCredentials() {
12000
12165
  };
12001
12166
  }
12002
12167
  try {
12003
- const credPath = path24.join(os20.homedir(), ".node9", "credentials.json");
12004
- const creds = JSON.parse(fs22.readFileSync(credPath, "utf-8"));
12168
+ const credPath = path25.join(os21.homedir(), ".node9", "credentials.json");
12169
+ const creds = JSON.parse(fs23.readFileSync(credPath, "utf-8"));
12005
12170
  const profileName = process.env.NODE9_PROFILE ?? "default";
12006
12171
  const profile = creds[profileName];
12007
12172
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -12027,7 +12192,7 @@ function readCredentials() {
12027
12192
  }
12028
12193
  function readCachedEtag() {
12029
12194
  try {
12030
- const raw = JSON.parse(fs22.readFileSync(rulesCacheFile(), "utf-8"));
12195
+ const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
12031
12196
  return typeof raw.etag === "string" ? raw.etag : void 0;
12032
12197
  } catch {
12033
12198
  return void 0;
@@ -12088,9 +12253,9 @@ function extractRules(body) {
12088
12253
  return [];
12089
12254
  }
12090
12255
  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");
12256
+ const dir = path25.dirname(rulesCacheFile());
12257
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
12258
+ fs23.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
12094
12259
  }
12095
12260
  async function syncOnce() {
12096
12261
  const creds = readCredentials();
@@ -12247,7 +12412,7 @@ async function runCloudSync() {
12247
12412
  }
12248
12413
  function getCloudSyncStatus() {
12249
12414
  try {
12250
- const raw = JSON.parse(fs22.readFileSync(rulesCacheFile(), "utf-8"));
12415
+ const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
12251
12416
  if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
12252
12417
  return {
12253
12418
  cached: true,
@@ -12264,7 +12429,7 @@ function getCloudSyncStatus() {
12264
12429
  }
12265
12430
  function getCloudRules() {
12266
12431
  try {
12267
- const raw = JSON.parse(fs22.readFileSync(rulesCacheFile(), "utf-8"));
12432
+ const raw = JSON.parse(fs23.readFileSync(rulesCacheFile(), "utf-8"));
12268
12433
  return Array.isArray(raw.rules) ? raw.rules : null;
12269
12434
  } catch {
12270
12435
  return null;
@@ -12320,7 +12485,7 @@ var init_sync = __esm({
12320
12485
  loop: "loops",
12321
12486
  "long-output-redacted": "longOutputRedactions"
12322
12487
  };
12323
- rulesCacheFile = () => path24.join(os20.homedir(), ".node9", "rules-cache.json");
12488
+ rulesCacheFile = () => path25.join(os21.homedir(), ".node9", "rules-cache.json");
12324
12489
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
12325
12490
  DEFAULT_INTERVAL_HOURS = 5;
12326
12491
  MIN_INTERVAL_HOURS = 1;
@@ -12331,73 +12496,73 @@ var init_sync = __esm({
12331
12496
  });
12332
12497
 
12333
12498
  // src/daemon/dlp-scanner.ts
12334
- import fs23 from "fs";
12335
- import path25 from "path";
12336
- import os21 from "os";
12499
+ import fs24 from "fs";
12500
+ import path26 from "path";
12501
+ import os22 from "os";
12337
12502
  function loadIndex() {
12338
12503
  try {
12339
- return JSON.parse(fs23.readFileSync(INDEX_FILE, "utf-8"));
12504
+ return JSON.parse(fs24.readFileSync(INDEX_FILE, "utf-8"));
12340
12505
  } catch {
12341
12506
  return {};
12342
12507
  }
12343
12508
  }
12344
12509
  function saveIndex(index) {
12345
12510
  try {
12346
- fs23.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12511
+ fs24.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12347
12512
  } catch {
12348
12513
  }
12349
12514
  }
12350
12515
  function appendAuditEntry(entry) {
12351
12516
  try {
12352
- fs23.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12517
+ fs24.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12353
12518
  } catch {
12354
12519
  }
12355
12520
  }
12356
12521
  function runDlpScan() {
12357
- if (!fs23.existsSync(PROJECTS_DIR2)) return;
12522
+ if (!fs24.existsSync(PROJECTS_DIR2)) return;
12358
12523
  const index = loadIndex();
12359
12524
  let updated = false;
12360
12525
  let projDirs;
12361
12526
  try {
12362
- projDirs = fs23.readdirSync(PROJECTS_DIR2);
12527
+ projDirs = fs24.readdirSync(PROJECTS_DIR2);
12363
12528
  } catch {
12364
12529
  return;
12365
12530
  }
12366
12531
  for (const proj of projDirs) {
12367
- const projPath = path25.join(PROJECTS_DIR2, proj);
12532
+ const projPath = path26.join(PROJECTS_DIR2, proj);
12368
12533
  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;
12534
+ if (!fs24.lstatSync(projPath).isDirectory()) continue;
12535
+ const real = fs24.realpathSync(projPath);
12536
+ if (!real.startsWith(PROJECTS_DIR2 + path26.sep) && real !== PROJECTS_DIR2) continue;
12372
12537
  } catch {
12373
12538
  continue;
12374
12539
  }
12375
12540
  let files;
12376
12541
  try {
12377
- files = fs23.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12542
+ files = fs24.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12378
12543
  } catch {
12379
12544
  continue;
12380
12545
  }
12381
12546
  for (const file of files) {
12382
- const filePath = path25.join(projPath, file);
12547
+ const filePath = path26.join(projPath, file);
12383
12548
  const lastOffset = index[filePath] ?? 0;
12384
12549
  let size;
12385
12550
  try {
12386
- size = fs23.statSync(filePath).size;
12551
+ size = fs24.statSync(filePath).size;
12387
12552
  } catch {
12388
12553
  continue;
12389
12554
  }
12390
12555
  if (size <= lastOffset) continue;
12391
12556
  let fd;
12392
12557
  try {
12393
- fd = fs23.openSync(filePath, "r");
12558
+ fd = fs24.openSync(filePath, "r");
12394
12559
  } catch {
12395
12560
  continue;
12396
12561
  }
12397
12562
  try {
12398
12563
  const chunkSize = size - lastOffset;
12399
12564
  const buf = Buffer.alloc(chunkSize);
12400
- fs23.readSync(fd, buf, 0, chunkSize, lastOffset);
12565
+ fs24.readSync(fd, buf, 0, chunkSize, lastOffset);
12401
12566
  const chunk = buf.toString("utf-8");
12402
12567
  for (const line of chunk.split("\n")) {
12403
12568
  if (!line.trim()) continue;
@@ -12417,7 +12582,7 @@ function runDlpScan() {
12417
12582
  if (typeof text !== "string") continue;
12418
12583
  const match = scanText(text);
12419
12584
  if (!match) continue;
12420
- const projLabel = decodeURIComponent(proj).replace(os21.homedir(), "~").slice(0, 40);
12585
+ const projLabel = decodeURIComponent(proj).replace(os22.homedir(), "~").slice(0, 40);
12421
12586
  const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
12422
12587
  appendAuditEntry({
12423
12588
  ts,
@@ -12442,7 +12607,7 @@ Run: node9 report --period 30d`
12442
12607
  updated = true;
12443
12608
  } finally {
12444
12609
  try {
12445
- fs23.closeSync(fd);
12610
+ fs24.closeSync(fd);
12446
12611
  } catch {
12447
12612
  }
12448
12613
  }
@@ -12475,23 +12640,23 @@ var init_dlp_scanner = __esm({
12475
12640
  init_dlp();
12476
12641
  init_native();
12477
12642
  init_state2();
12478
- INDEX_FILE = path25.join(os21.homedir(), ".node9", "dlp-index.json");
12479
- PROJECTS_DIR2 = path25.join(os21.homedir(), ".claude", "projects");
12643
+ INDEX_FILE = path26.join(os22.homedir(), ".node9", "dlp-index.json");
12644
+ PROJECTS_DIR2 = path26.join(os22.homedir(), ".claude", "projects");
12480
12645
  }
12481
12646
  });
12482
12647
 
12483
12648
  // src/daemon/mcp-tools.ts
12484
- import fs24 from "fs";
12485
- import path26 from "path";
12486
- import os22 from "os";
12649
+ import fs25 from "fs";
12650
+ import path27 from "path";
12651
+ import os23 from "os";
12487
12652
  function getMcpToolsFile() {
12488
- return path26.join(os22.homedir(), ".node9", "mcp-tools.json");
12653
+ return path27.join(os23.homedir(), ".node9", "mcp-tools.json");
12489
12654
  }
12490
12655
  function readMcpToolsConfig() {
12491
12656
  try {
12492
12657
  const file = getMcpToolsFile();
12493
- if (!fs24.existsSync(file)) return {};
12494
- const raw = fs24.readFileSync(file, "utf-8");
12658
+ if (!fs25.existsSync(file)) return {};
12659
+ const raw = fs25.readFileSync(file, "utf-8");
12495
12660
  return JSON.parse(raw);
12496
12661
  } catch {
12497
12662
  return {};
@@ -12500,11 +12665,11 @@ function readMcpToolsConfig() {
12500
12665
  function writeMcpToolsConfig(config) {
12501
12666
  try {
12502
12667
  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);
12668
+ const dir = path27.dirname(file);
12669
+ if (!fs25.existsSync(dir)) fs25.mkdirSync(dir, { recursive: true });
12670
+ const tmpPath = `${file}.${os23.hostname()}.${process.pid}.tmp`;
12671
+ fs25.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
12672
+ fs25.renameSync(tmpPath, file);
12508
12673
  } catch (e) {
12509
12674
  console.error("Failed to write mcp-tools.json", e);
12510
12675
  }
@@ -12551,9 +12716,9 @@ var init_mcp_tools = __esm({
12551
12716
 
12552
12717
  // src/daemon/server.ts
12553
12718
  import http from "http";
12554
- import fs25 from "fs";
12555
- import path27 from "path";
12556
- import os23 from "os";
12719
+ import fs26 from "fs";
12720
+ import path28 from "path";
12721
+ import os24 from "os";
12557
12722
  import { randomUUID as randomUUID4 } from "crypto";
12558
12723
  import { spawnSync } from "child_process";
12559
12724
  import chalk6 from "chalk";
@@ -12574,7 +12739,7 @@ function startDaemon() {
12574
12739
  idleTimer = setTimeout(() => {
12575
12740
  if (autoStarted) {
12576
12741
  try {
12577
- fs25.unlinkSync(DAEMON_PID_FILE);
12742
+ fs26.unlinkSync(DAEMON_PID_FILE);
12578
12743
  } catch {
12579
12744
  }
12580
12745
  }
@@ -12719,7 +12884,7 @@ data: ${JSON.stringify(item.data)}
12719
12884
  mcpServer: entry.mcpServer
12720
12885
  });
12721
12886
  }
12722
- const projectCwd = typeof cwd === "string" && path27.isAbsolute(cwd) ? cwd : void 0;
12887
+ const projectCwd = typeof cwd === "string" && path28.isAbsolute(cwd) ? cwd : void 0;
12723
12888
  const projectConfig = getConfig(projectCwd);
12724
12889
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
12725
12890
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -13011,8 +13176,8 @@ data: ${JSON.stringify(item.data)}
13011
13176
  if (!validToken(req)) return res.writeHead(403).end();
13012
13177
  const periodParam = reqUrl.searchParams.get("period") || "7d";
13013
13178
  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)) {
13179
+ const logPath = path28.join(os24.homedir(), ".node9", "audit.log");
13180
+ if (!fs26.existsSync(logPath)) {
13016
13181
  res.writeHead(200, { "Content-Type": "application/json" });
13017
13182
  return res.end(
13018
13183
  JSON.stringify({
@@ -13025,7 +13190,7 @@ data: ${JSON.stringify(item.data)}
13025
13190
  );
13026
13191
  }
13027
13192
  try {
13028
- const raw = fs25.readFileSync(logPath, "utf-8");
13193
+ const raw = fs26.readFileSync(logPath, "utf-8");
13029
13194
  const allEntries = raw.split("\n").flatMap((line) => {
13030
13195
  if (!line.trim()) return [];
13031
13196
  try {
@@ -13348,14 +13513,14 @@ data: ${JSON.stringify(item.data)}
13348
13513
  server.on("error", (e) => {
13349
13514
  if (e.code === "EADDRINUSE") {
13350
13515
  try {
13351
- if (fs25.existsSync(DAEMON_PID_FILE)) {
13352
- const { pid } = JSON.parse(fs25.readFileSync(DAEMON_PID_FILE, "utf-8"));
13516
+ if (fs26.existsSync(DAEMON_PID_FILE)) {
13517
+ const { pid } = JSON.parse(fs26.readFileSync(DAEMON_PID_FILE, "utf-8"));
13353
13518
  process.kill(pid, 0);
13354
13519
  return process.exit(0);
13355
13520
  }
13356
13521
  } catch {
13357
13522
  try {
13358
- fs25.unlinkSync(DAEMON_PID_FILE);
13523
+ fs26.unlinkSync(DAEMON_PID_FILE);
13359
13524
  } catch {
13360
13525
  }
13361
13526
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -13443,15 +13608,15 @@ var init_server = __esm({
13443
13608
  });
13444
13609
 
13445
13610
  // src/daemon/service.ts
13446
- import fs26 from "fs";
13447
- import path28 from "path";
13448
- import os24 from "os";
13611
+ import fs27 from "fs";
13612
+ import path29 from "path";
13613
+ import os25 from "os";
13449
13614
  import { spawnSync as spawnSync2, execFileSync } from "child_process";
13450
13615
  function resolveNode9Binary() {
13451
13616
  try {
13452
13617
  const script = process.argv[1];
13453
- if (typeof script === "string" && path28.isAbsolute(script) && fs26.existsSync(script)) {
13454
- return fs26.realpathSync(script);
13618
+ if (typeof script === "string" && path29.isAbsolute(script) && fs27.existsSync(script)) {
13619
+ return fs27.realpathSync(script);
13455
13620
  }
13456
13621
  } catch {
13457
13622
  }
@@ -13469,11 +13634,11 @@ function xmlEscape(s) {
13469
13634
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13470
13635
  }
13471
13636
  function launchdPlist(binaryPath) {
13472
- const logDir = path28.join(os24.homedir(), ".node9");
13637
+ const logDir = path29.join(os25.homedir(), ".node9");
13473
13638
  const nodePath = xmlEscape(process.execPath);
13474
13639
  const scriptPath = xmlEscape(binaryPath);
13475
- const outLog = xmlEscape(path28.join(logDir, "daemon.log"));
13476
- const errLog = xmlEscape(path28.join(logDir, "daemon-error.log"));
13640
+ const outLog = xmlEscape(path29.join(logDir, "daemon.log"));
13641
+ const errLog = xmlEscape(path29.join(logDir, "daemon-error.log"));
13477
13642
  return `<?xml version="1.0" encoding="UTF-8"?>
13478
13643
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
13479
13644
  <plist version="1.0">
@@ -13506,9 +13671,9 @@ function launchdPlist(binaryPath) {
13506
13671
  `;
13507
13672
  }
13508
13673
  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");
13674
+ const dir = path29.dirname(LAUNCHD_PLIST);
13675
+ if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
13676
+ fs27.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
13512
13677
  spawnSync2("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
13513
13678
  const r = spawnSync2("launchctl", ["load", "-w", LAUNCHD_PLIST], {
13514
13679
  encoding: "utf8",
@@ -13519,13 +13684,13 @@ function installLaunchd(binaryPath) {
13519
13684
  }
13520
13685
  }
13521
13686
  function uninstallLaunchd() {
13522
- if (fs26.existsSync(LAUNCHD_PLIST)) {
13687
+ if (fs27.existsSync(LAUNCHD_PLIST)) {
13523
13688
  spawnSync2("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
13524
- fs26.unlinkSync(LAUNCHD_PLIST);
13689
+ fs27.unlinkSync(LAUNCHD_PLIST);
13525
13690
  }
13526
13691
  }
13527
13692
  function isLaunchdInstalled() {
13528
- return fs26.existsSync(LAUNCHD_PLIST);
13693
+ return fs27.existsSync(LAUNCHD_PLIST);
13529
13694
  }
13530
13695
  function systemdUnit(binaryPath) {
13531
13696
  return `[Unit]
@@ -13544,12 +13709,12 @@ WantedBy=default.target
13544
13709
  `;
13545
13710
  }
13546
13711
  function installSystemd(binaryPath) {
13547
- if (!fs26.existsSync(SYSTEMD_UNIT_DIR)) {
13548
- fs26.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13712
+ if (!fs27.existsSync(SYSTEMD_UNIT_DIR)) {
13713
+ fs27.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13549
13714
  }
13550
- fs26.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13715
+ fs27.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13551
13716
  try {
13552
- execFileSync("loginctl", ["enable-linger", os24.userInfo().username], { timeout: 3e3 });
13717
+ execFileSync("loginctl", ["enable-linger", os25.userInfo().username], { timeout: 3e3 });
13553
13718
  } catch {
13554
13719
  }
13555
13720
  const reload = spawnSync2("systemctl", ["--user", "daemon-reload"], {
@@ -13569,23 +13734,23 @@ function installSystemd(binaryPath) {
13569
13734
  }
13570
13735
  }
13571
13736
  function uninstallSystemd() {
13572
- if (fs26.existsSync(SYSTEMD_UNIT)) {
13737
+ if (fs27.existsSync(SYSTEMD_UNIT)) {
13573
13738
  spawnSync2("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
13574
13739
  encoding: "utf8",
13575
13740
  timeout: 5e3
13576
13741
  });
13577
13742
  spawnSync2("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
13578
- fs26.unlinkSync(SYSTEMD_UNIT);
13743
+ fs27.unlinkSync(SYSTEMD_UNIT);
13579
13744
  }
13580
13745
  }
13581
13746
  function isSystemdInstalled() {
13582
- return fs26.existsSync(SYSTEMD_UNIT);
13747
+ return fs27.existsSync(SYSTEMD_UNIT);
13583
13748
  }
13584
13749
  function stopRunningDaemon() {
13585
- const pidFile = path28.join(os24.homedir(), ".node9", "daemon.pid");
13586
- if (!fs26.existsSync(pidFile)) return;
13750
+ const pidFile = path29.join(os25.homedir(), ".node9", "daemon.pid");
13751
+ if (!fs27.existsSync(pidFile)) return;
13587
13752
  try {
13588
- const data = JSON.parse(fs26.readFileSync(pidFile, "utf-8"));
13753
+ const data = JSON.parse(fs27.readFileSync(pidFile, "utf-8"));
13589
13754
  const pid = data.pid;
13590
13755
  const MAX_PID2 = 4194304;
13591
13756
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -13605,7 +13770,7 @@ function stopRunningDaemon() {
13605
13770
  }
13606
13771
  }
13607
13772
  try {
13608
- fs26.unlinkSync(pidFile);
13773
+ fs27.unlinkSync(pidFile);
13609
13774
  } catch {
13610
13775
  }
13611
13776
  } catch {
@@ -13680,19 +13845,19 @@ var init_service = __esm({
13680
13845
  "src/daemon/service.ts"() {
13681
13846
  "use strict";
13682
13847
  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");
13848
+ LAUNCHD_PLIST = path29.join(os25.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
13849
+ SYSTEMD_UNIT_DIR = path29.join(os25.homedir(), ".config", "systemd", "user");
13850
+ SYSTEMD_UNIT = path29.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
13686
13851
  }
13687
13852
  });
13688
13853
 
13689
13854
  // src/daemon/index.ts
13690
- import fs27 from "fs";
13855
+ import fs28 from "fs";
13691
13856
  import chalk7 from "chalk";
13692
13857
  function stopDaemon() {
13693
- if (!fs27.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
13858
+ if (!fs28.existsSync(DAEMON_PID_FILE)) return console.log(chalk7.yellow("Not running."));
13694
13859
  try {
13695
- const data = JSON.parse(fs27.readFileSync(DAEMON_PID_FILE, "utf-8"));
13860
+ const data = JSON.parse(fs28.readFileSync(DAEMON_PID_FILE, "utf-8"));
13696
13861
  const pid = data.pid;
13697
13862
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
13698
13863
  console.log(chalk7.gray("Cleaned up invalid PID file."));
@@ -13704,7 +13869,7 @@ function stopDaemon() {
13704
13869
  console.log(chalk7.gray("Cleaned up stale PID file."));
13705
13870
  } finally {
13706
13871
  try {
13707
- fs27.unlinkSync(DAEMON_PID_FILE);
13872
+ fs28.unlinkSync(DAEMON_PID_FILE);
13708
13873
  } catch {
13709
13874
  }
13710
13875
  }
@@ -13713,9 +13878,9 @@ function daemonStatus() {
13713
13878
  const serviceInstalled = isDaemonServiceInstalled();
13714
13879
  const serviceLabel = serviceInstalled ? chalk7.green("installed (starts on login)") : chalk7.yellow("not installed \u2014 run: node9 daemon install");
13715
13880
  let processStatus;
13716
- if (fs27.existsSync(DAEMON_PID_FILE)) {
13881
+ if (fs28.existsSync(DAEMON_PID_FILE)) {
13717
13882
  try {
13718
- const data = JSON.parse(fs27.readFileSync(DAEMON_PID_FILE, "utf-8"));
13883
+ const data = JSON.parse(fs28.readFileSync(DAEMON_PID_FILE, "utf-8"));
13719
13884
  const pid = data.pid;
13720
13885
  const port = data.port;
13721
13886
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -13760,7 +13925,7 @@ __export(tail_exports, {
13760
13925
  });
13761
13926
  import http2 from "http";
13762
13927
  import chalk29 from "chalk";
13763
- import fs45 from "fs";
13928
+ import fs46 from "fs";
13764
13929
  import os41 from "os";
13765
13930
  import path47 from "path";
13766
13931
  import readline6 from "readline";
@@ -13787,19 +13952,19 @@ function getModelContextLimit(model) {
13787
13952
  }
13788
13953
  function readSessionUsage() {
13789
13954
  const projectsDir = path47.join(os41.homedir(), ".claude", "projects");
13790
- if (!fs45.existsSync(projectsDir)) return null;
13955
+ if (!fs46.existsSync(projectsDir)) return null;
13791
13956
  let latestFile = null;
13792
13957
  let latestMtime = 0;
13793
13958
  try {
13794
- for (const dir of fs45.readdirSync(projectsDir)) {
13959
+ for (const dir of fs46.readdirSync(projectsDir)) {
13795
13960
  const dirPath = path47.join(projectsDir, dir);
13796
13961
  try {
13797
- if (!fs45.statSync(dirPath).isDirectory()) continue;
13798
- for (const file of fs45.readdirSync(dirPath)) {
13962
+ if (!fs46.statSync(dirPath).isDirectory()) continue;
13963
+ for (const file of fs46.readdirSync(dirPath)) {
13799
13964
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
13800
13965
  const filePath = path47.join(dirPath, file);
13801
13966
  try {
13802
- const mtime = fs45.statSync(filePath).mtimeMs;
13967
+ const mtime = fs46.statSync(filePath).mtimeMs;
13803
13968
  if (mtime > latestMtime) {
13804
13969
  latestMtime = mtime;
13805
13970
  latestFile = filePath;
@@ -13814,7 +13979,7 @@ function readSessionUsage() {
13814
13979
  }
13815
13980
  if (!latestFile) return null;
13816
13981
  try {
13817
- const lines = fs45.readFileSync(latestFile, "utf-8").split("\n");
13982
+ const lines = fs46.readFileSync(latestFile, "utf-8").split("\n");
13818
13983
  let lastModel = "";
13819
13984
  let lastInput = 0;
13820
13985
  let lastOutput = 0;
@@ -13914,9 +14079,9 @@ function renderPending(activity) {
13914
14079
  }
13915
14080
  async function ensureDaemon() {
13916
14081
  let pidPort = null;
13917
- if (fs45.existsSync(PID_FILE)) {
14082
+ if (fs46.existsSync(PID_FILE)) {
13918
14083
  try {
13919
- const { port } = JSON.parse(fs45.readFileSync(PID_FILE, "utf-8"));
14084
+ const { port } = JSON.parse(fs46.readFileSync(PID_FILE, "utf-8"));
13920
14085
  pidPort = port;
13921
14086
  } catch {
13922
14087
  console.error(chalk29.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -14074,7 +14239,7 @@ function buildRecoveryCardLines(req) {
14074
14239
  function readApproversFromDisk() {
14075
14240
  const configPath = path47.join(os41.homedir(), ".node9", "config.json");
14076
14241
  try {
14077
- const raw = JSON.parse(fs45.readFileSync(configPath, "utf-8"));
14242
+ const raw = JSON.parse(fs46.readFileSync(configPath, "utf-8"));
14078
14243
  const settings = raw.settings ?? {};
14079
14244
  return settings.approvers ?? {};
14080
14245
  } catch {
@@ -14092,13 +14257,13 @@ function approverStatusLine() {
14092
14257
  function toggleApprover(channel) {
14093
14258
  const configPath = path47.join(os41.homedir(), ".node9", "config.json");
14094
14259
  try {
14095
- const raw = JSON.parse(fs45.readFileSync(configPath, "utf-8"));
14260
+ const raw = JSON.parse(fs46.readFileSync(configPath, "utf-8"));
14096
14261
  const settings = raw.settings ?? {};
14097
14262
  const approvers = settings.approvers ?? {};
14098
14263
  approvers[channel] = approvers[channel] === false;
14099
14264
  settings.approvers = approvers;
14100
14265
  raw.settings = settings;
14101
- fs45.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14266
+ fs46.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14102
14267
  } catch (err2) {
14103
14268
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
14104
14269
  `);
@@ -14270,7 +14435,7 @@ async function startTail(options = {}) {
14270
14435
  }
14271
14436
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
14272
14437
  try {
14273
- fs45.appendFileSync(
14438
+ fs46.appendFileSync(
14274
14439
  path47.join(os41.homedir(), ".node9", "hook-debug.log"),
14275
14440
  `[tail] POST /decision failed: ${String(err2)}
14276
14441
  `
@@ -14337,7 +14502,7 @@ async function startTail(options = {}) {
14337
14502
  }
14338
14503
  const auditLog = path47.join(os41.homedir(), ".node9", "audit.log");
14339
14504
  try {
14340
- const unackedDlp = fs45.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14505
+ const unackedDlp = fs46.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14341
14506
  if (unackedDlp > 0) {
14342
14507
  console.log("");
14343
14508
  console.log(
@@ -14377,7 +14542,7 @@ async function startTail(options = {}) {
14377
14542
  if (stallWarned) return;
14378
14543
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
14379
14544
  try {
14380
- const auditMtime = fs45.statSync(auditLog).mtimeMs;
14545
+ const auditMtime = fs46.statSync(auditLog).mtimeMs;
14381
14546
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
14382
14547
  console.log("");
14383
14548
  console.log(
@@ -14616,7 +14781,7 @@ __export(hud_exports, {
14616
14781
  main: () => main,
14617
14782
  renderEnvironmentLine: () => renderEnvironmentLine
14618
14783
  });
14619
- import fs46 from "fs";
14784
+ import fs47 from "fs";
14620
14785
  import path48 from "path";
14621
14786
  import os42 from "os";
14622
14787
  import http3 from "http";
@@ -14694,9 +14859,9 @@ function formatTimeLeft(resetsAt) {
14694
14859
  return ` (${m}m left)`;
14695
14860
  }
14696
14861
  function safeReadJson(filePath) {
14697
- if (!fs46.existsSync(filePath)) return null;
14862
+ if (!fs47.existsSync(filePath)) return null;
14698
14863
  try {
14699
- return JSON.parse(fs46.readFileSync(filePath, "utf-8"));
14864
+ return JSON.parse(fs47.readFileSync(filePath, "utf-8"));
14700
14865
  } catch {
14701
14866
  return null;
14702
14867
  }
@@ -14717,10 +14882,10 @@ function countHooksInFile(filePath) {
14717
14882
  return Object.keys(cfg.hooks).length;
14718
14883
  }
14719
14884
  function countRulesInDir(rulesDir) {
14720
- if (!fs46.existsSync(rulesDir)) return 0;
14885
+ if (!fs47.existsSync(rulesDir)) return 0;
14721
14886
  let count = 0;
14722
14887
  try {
14723
- for (const entry of fs46.readdirSync(rulesDir, { withFileTypes: true })) {
14888
+ for (const entry of fs47.readdirSync(rulesDir, { withFileTypes: true })) {
14724
14889
  if (entry.isDirectory()) {
14725
14890
  count += countRulesInDir(path48.join(rulesDir, entry.name));
14726
14891
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -14746,7 +14911,7 @@ function countConfigs(cwd) {
14746
14911
  let hooksCount = 0;
14747
14912
  const userMcpServers = /* @__PURE__ */ new Set();
14748
14913
  const projectMcpServers = /* @__PURE__ */ new Set();
14749
- if (fs46.existsSync(path48.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14914
+ if (fs47.existsSync(path48.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14750
14915
  rulesCount += countRulesInDir(path48.join(claudeDir, "rules"));
14751
14916
  const userSettings = path48.join(claudeDir, "settings.json");
14752
14917
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
@@ -14757,18 +14922,18 @@ function countConfigs(cwd) {
14757
14922
  userMcpServers.delete(name);
14758
14923
  }
14759
14924
  if (cwd) {
14760
- if (fs46.existsSync(path48.join(cwd, "CLAUDE.md"))) claudeMdCount++;
14761
- if (fs46.existsSync(path48.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
14925
+ if (fs47.existsSync(path48.join(cwd, "CLAUDE.md"))) claudeMdCount++;
14926
+ if (fs47.existsSync(path48.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
14762
14927
  const projectClaudeDir = path48.join(cwd, ".claude");
14763
14928
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
14764
14929
  if (!overlapsUserScope) {
14765
- if (fs46.existsSync(path48.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14930
+ if (fs47.existsSync(path48.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14766
14931
  rulesCount += countRulesInDir(path48.join(projectClaudeDir, "rules"));
14767
14932
  const projSettings = path48.join(projectClaudeDir, "settings.json");
14768
14933
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
14769
14934
  hooksCount += countHooksInFile(projSettings);
14770
14935
  }
14771
- if (fs46.existsSync(path48.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14936
+ if (fs47.existsSync(path48.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14772
14937
  const localSettings = path48.join(projectClaudeDir, "settings.local.json");
14773
14938
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
14774
14939
  hooksCount += countHooksInFile(localSettings);
@@ -14806,11 +14971,11 @@ function readActiveShieldsHud() {
14806
14971
  }
14807
14972
  try {
14808
14973
  const shieldsPath = path48.join(os42.homedir(), ".node9", "shields.json");
14809
- if (!fs46.existsSync(shieldsPath)) {
14974
+ if (!fs47.existsSync(shieldsPath)) {
14810
14975
  shieldsCache = { value: [], ts: now };
14811
14976
  return [];
14812
14977
  }
14813
- const parsed = JSON.parse(fs46.readFileSync(shieldsPath, "utf-8"));
14978
+ const parsed = JSON.parse(fs47.readFileSync(shieldsPath, "utf-8"));
14814
14979
  if (!Array.isArray(parsed.active)) {
14815
14980
  shieldsCache = { value: [], ts: now };
14816
14981
  return [];
@@ -14912,17 +15077,17 @@ function renderContextLine(stdin) {
14912
15077
  async function main() {
14913
15078
  try {
14914
15079
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
14915
- if (fs46.existsSync(path48.join(os42.homedir(), ".node9", "hud-debug"))) {
15080
+ if (fs47.existsSync(path48.join(os42.homedir(), ".node9", "hud-debug"))) {
14916
15081
  try {
14917
15082
  const logPath = path48.join(os42.homedir(), ".node9", "hud-debug.log");
14918
15083
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
14919
15084
  let size = 0;
14920
15085
  try {
14921
- size = fs46.statSync(logPath).size;
15086
+ size = fs47.statSync(logPath).size;
14922
15087
  } catch {
14923
15088
  }
14924
15089
  if (size < MAX_LOG_SIZE) {
14925
- fs46.appendFileSync(
15090
+ fs47.appendFileSync(
14926
15091
  logPath,
14927
15092
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
14928
15093
  );
@@ -14946,8 +15111,8 @@ async function main() {
14946
15111
  path48.join(cwd, "node9.config.json"),
14947
15112
  path48.join(os42.homedir(), ".node9", "config.json")
14948
15113
  ]) {
14949
- if (!fs46.existsSync(configPath)) continue;
14950
- const cfg = JSON.parse(fs46.readFileSync(configPath, "utf-8"));
15114
+ if (!fs47.existsSync(configPath)) continue;
15115
+ const cfg = JSON.parse(fs47.readFileSync(configPath, "utf-8"));
14951
15116
  const hud = cfg.settings?.hud;
14952
15117
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
14953
15118
  }
@@ -14994,7 +15159,7 @@ init_setup();
14994
15159
  init_daemon2();
14995
15160
  import { Command } from "commander";
14996
15161
  import chalk30 from "chalk";
14997
- import fs47 from "fs";
15162
+ import fs48 from "fs";
14998
15163
  import path49 from "path";
14999
15164
  import os43 from "os";
15000
15165
  import { confirm as confirm2 } from "@inquirer/prompts";
@@ -15179,17 +15344,17 @@ async function runProxy(targetCommand) {
15179
15344
  // src/cli/daemon-starter.ts
15180
15345
  init_daemon();
15181
15346
  import { spawn as spawn3 } from "child_process";
15182
- import path29 from "path";
15183
- import fs28 from "fs";
15347
+ import path30 from "path";
15348
+ import fs29 from "fs";
15184
15349
  function isTestingMode() {
15185
15350
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
15186
15351
  }
15187
15352
  async function autoStartDaemonAndWait() {
15188
15353
  if (isTestingMode()) return false;
15189
- if (!path29.isAbsolute(process.argv[1])) return false;
15354
+ if (!path30.isAbsolute(process.argv[1])) return false;
15190
15355
  let resolvedArgv1;
15191
15356
  try {
15192
- resolvedArgv1 = fs28.realpathSync(process.argv[1]);
15357
+ resolvedArgv1 = fs29.realpathSync(process.argv[1]);
15193
15358
  } catch {
15194
15359
  return false;
15195
15360
  }
@@ -15220,19 +15385,19 @@ init_daemon();
15220
15385
  init_config();
15221
15386
  init_policy();
15222
15387
  import chalk9 from "chalk";
15223
- import fs31 from "fs";
15388
+ import fs32 from "fs";
15224
15389
  import { spawn as spawn5 } from "child_process";
15225
- import path32 from "path";
15226
- import os27 from "os";
15390
+ import path33 from "path";
15391
+ import os28 from "os";
15227
15392
 
15228
15393
  // src/undo.ts
15229
15394
  import { spawnSync as spawnSync3, spawn as spawn4 } from "child_process";
15230
- import crypto3 from "crypto";
15231
- import fs29 from "fs";
15395
+ import crypto4 from "crypto";
15396
+ import fs30 from "fs";
15232
15397
  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");
15398
+ import path31 from "path";
15399
+ import os26 from "os";
15400
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : path31.join(os26.tmpdir(), "node9-activity.sock");
15236
15401
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15237
15402
  try {
15238
15403
  const payload = JSON.stringify({
@@ -15252,22 +15417,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15252
15417
  } catch {
15253
15418
  }
15254
15419
  }
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");
15420
+ var SNAPSHOT_STACK_PATH = path31.join(os26.homedir(), ".node9", "snapshots.json");
15421
+ var UNDO_LATEST_PATH = path31.join(os26.homedir(), ".node9", "undo_latest.txt");
15257
15422
  var MAX_SNAPSHOTS = 10;
15258
15423
  var GIT_TIMEOUT = 15e3;
15259
15424
  function readStack() {
15260
15425
  try {
15261
- if (fs29.existsSync(SNAPSHOT_STACK_PATH))
15262
- return JSON.parse(fs29.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15426
+ if (fs30.existsSync(SNAPSHOT_STACK_PATH))
15427
+ return JSON.parse(fs30.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15263
15428
  } catch {
15264
15429
  }
15265
15430
  return [];
15266
15431
  }
15267
15432
  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));
15433
+ const dir = path31.dirname(SNAPSHOT_STACK_PATH);
15434
+ if (!fs30.existsSync(dir)) fs30.mkdirSync(dir, { recursive: true });
15435
+ fs30.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
15271
15436
  }
15272
15437
  function extractFilePath(args) {
15273
15438
  if (!args || typeof args !== "object") return null;
@@ -15287,12 +15452,12 @@ function buildArgsSummary(tool, args) {
15287
15452
  return "";
15288
15453
  }
15289
15454
  function findProjectRoot(filePath) {
15290
- let dir = path30.dirname(filePath);
15455
+ let dir = path31.dirname(filePath);
15291
15456
  while (true) {
15292
- if (fs29.existsSync(path30.join(dir, ".git")) || fs29.existsSync(path30.join(dir, "package.json"))) {
15457
+ if (fs30.existsSync(path31.join(dir, ".git")) || fs30.existsSync(path31.join(dir, "package.json"))) {
15293
15458
  return dir;
15294
15459
  }
15295
- const parent = path30.dirname(dir);
15460
+ const parent = path31.dirname(dir);
15296
15461
  if (parent === dir) return process.cwd();
15297
15462
  dir = parent;
15298
15463
  }
@@ -15300,7 +15465,7 @@ function findProjectRoot(filePath) {
15300
15465
  function normalizeCwdForHash(cwd) {
15301
15466
  let normalized;
15302
15467
  try {
15303
- normalized = fs29.realpathSync(cwd);
15468
+ normalized = fs30.realpathSync(cwd);
15304
15469
  } catch {
15305
15470
  normalized = cwd;
15306
15471
  }
@@ -15309,17 +15474,17 @@ function normalizeCwdForHash(cwd) {
15309
15474
  return normalized;
15310
15475
  }
15311
15476
  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);
15477
+ const hash = crypto4.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
15478
+ return path31.join(os26.homedir(), ".node9", "snapshots", hash);
15314
15479
  }
15315
15480
  function cleanOrphanedIndexFiles(shadowDir) {
15316
15481
  try {
15317
15482
  const cutoff = Date.now() - 6e4;
15318
- for (const f of fs29.readdirSync(shadowDir)) {
15483
+ for (const f of fs30.readdirSync(shadowDir)) {
15319
15484
  if (f.startsWith("index_")) {
15320
- const fp = path30.join(shadowDir, f);
15485
+ const fp = path31.join(shadowDir, f);
15321
15486
  try {
15322
- if (fs29.statSync(fp).mtimeMs < cutoff) fs29.unlinkSync(fp);
15487
+ if (fs30.statSync(fp).mtimeMs < cutoff) fs30.unlinkSync(fp);
15323
15488
  } catch {
15324
15489
  }
15325
15490
  }
@@ -15331,7 +15496,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
15331
15496
  const hardcoded = [".git", ".node9"];
15332
15497
  const lines = [...hardcoded, ...ignorePaths].join("\n");
15333
15498
  try {
15334
- fs29.writeFileSync(path30.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15499
+ fs30.writeFileSync(path31.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15335
15500
  } catch {
15336
15501
  }
15337
15502
  }
@@ -15344,25 +15509,25 @@ function ensureShadowRepo(shadowDir, cwd) {
15344
15509
  timeout: 3e3
15345
15510
  });
15346
15511
  if (check.status === 0) {
15347
- const ptPath = path30.join(shadowDir, "project-path.txt");
15512
+ const ptPath = path31.join(shadowDir, "project-path.txt");
15348
15513
  try {
15349
- const stored = fs29.readFileSync(ptPath, "utf8").trim();
15514
+ const stored = fs30.readFileSync(ptPath, "utf8").trim();
15350
15515
  if (stored === normalizedCwd) return true;
15351
15516
  if (process.env.NODE9_DEBUG === "1")
15352
15517
  console.error(
15353
15518
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
15354
15519
  );
15355
- fs29.rmSync(shadowDir, { recursive: true, force: true });
15520
+ fs30.rmSync(shadowDir, { recursive: true, force: true });
15356
15521
  } catch {
15357
15522
  try {
15358
- fs29.writeFileSync(ptPath, normalizedCwd, "utf8");
15523
+ fs30.writeFileSync(ptPath, normalizedCwd, "utf8");
15359
15524
  } catch {
15360
15525
  }
15361
15526
  return true;
15362
15527
  }
15363
15528
  }
15364
15529
  try {
15365
- fs29.mkdirSync(shadowDir, { recursive: true });
15530
+ fs30.mkdirSync(shadowDir, { recursive: true });
15366
15531
  } catch {
15367
15532
  }
15368
15533
  const init = spawnSync3("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -15371,7 +15536,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15371
15536
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
15372
15537
  return false;
15373
15538
  }
15374
- const configFile = path30.join(shadowDir, "config");
15539
+ const configFile = path31.join(shadowDir, "config");
15375
15540
  spawnSync3("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
15376
15541
  timeout: 3e3
15377
15542
  });
@@ -15379,7 +15544,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15379
15544
  timeout: 3e3
15380
15545
  });
15381
15546
  try {
15382
- fs29.writeFileSync(path30.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15547
+ fs30.writeFileSync(path31.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15383
15548
  } catch {
15384
15549
  }
15385
15550
  return true;
@@ -15402,12 +15567,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15402
15567
  let indexFile = null;
15403
15568
  try {
15404
15569
  const rawFilePath = extractFilePath(args);
15405
- const absFilePath = rawFilePath && path30.isAbsolute(rawFilePath) ? rawFilePath : null;
15570
+ const absFilePath = rawFilePath && path31.isAbsolute(rawFilePath) ? rawFilePath : null;
15406
15571
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
15407
15572
  const shadowDir = getShadowRepoDir(cwd);
15408
15573
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
15409
15574
  writeShadowExcludes(shadowDir, ignorePaths);
15410
- indexFile = path30.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15575
+ indexFile = path31.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15411
15576
  const shadowEnv = {
15412
15577
  ...process.env,
15413
15578
  GIT_DIR: shadowDir,
@@ -15479,7 +15644,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15479
15644
  writeStack(stack);
15480
15645
  const entry = stack[stack.length - 1];
15481
15646
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
15482
- fs29.writeFileSync(UNDO_LATEST_PATH, commitHash);
15647
+ fs30.writeFileSync(UNDO_LATEST_PATH, commitHash);
15483
15648
  if (shouldGc) {
15484
15649
  spawn4("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
15485
15650
  }
@@ -15490,7 +15655,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15490
15655
  } finally {
15491
15656
  if (indexFile) {
15492
15657
  try {
15493
- fs29.unlinkSync(indexFile);
15658
+ fs30.unlinkSync(indexFile);
15494
15659
  } catch {
15495
15660
  }
15496
15661
  }
@@ -15566,9 +15731,9 @@ function applyUndo(hash, cwd) {
15566
15731
  timeout: GIT_TIMEOUT
15567
15732
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
15568
15733
  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);
15734
+ const fullPath = path31.join(dir, file);
15735
+ if (!snapshotFiles.has(file) && fs30.existsSync(fullPath)) {
15736
+ fs30.unlinkSync(fullPath);
15572
15737
  }
15573
15738
  }
15574
15739
  return true;
@@ -15578,17 +15743,17 @@ function applyUndo(hash, cwd) {
15578
15743
  }
15579
15744
 
15580
15745
  // 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");
15746
+ import fs31 from "fs";
15747
+ import path32 from "path";
15748
+ import os27 from "os";
15749
+ import crypto5 from "crypto";
15750
+ function getPinsFilePath2() {
15751
+ return path32.join(os27.homedir(), ".node9", "skill-pins.json");
15587
15752
  }
15588
15753
  var MAX_FILES = 5e3;
15589
15754
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
15590
15755
  function sha256Bytes(buf) {
15591
- return crypto4.createHash("sha256").update(buf).digest("hex");
15756
+ return crypto5.createHash("sha256").update(buf).digest("hex");
15592
15757
  }
15593
15758
  function walkDir(root) {
15594
15759
  const out = [];
@@ -15597,18 +15762,18 @@ function walkDir(root) {
15597
15762
  if (out.length >= MAX_FILES) return;
15598
15763
  let entries;
15599
15764
  try {
15600
- entries = fs30.readdirSync(dir, { withFileTypes: true });
15765
+ entries = fs31.readdirSync(dir, { withFileTypes: true });
15601
15766
  } catch {
15602
15767
  return;
15603
15768
  }
15604
15769
  entries.sort((a, b) => a.name.localeCompare(b.name));
15605
15770
  for (const entry of entries) {
15606
15771
  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;
15772
+ const full = path32.join(dir, entry.name);
15773
+ const rel = relDir ? path32.posix.join(relDir, entry.name) : entry.name;
15609
15774
  let lst;
15610
15775
  try {
15611
- lst = fs30.lstatSync(full);
15776
+ lst = fs31.lstatSync(full);
15612
15777
  } catch {
15613
15778
  continue;
15614
15779
  }
@@ -15620,7 +15785,7 @@ function walkDir(root) {
15620
15785
  if (!lst.isFile()) continue;
15621
15786
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
15622
15787
  try {
15623
- const buf = fs30.readFileSync(full);
15788
+ const buf = fs31.readFileSync(full);
15624
15789
  totalBytes += buf.length;
15625
15790
  out.push({ rel, hash: sha256Bytes(buf) });
15626
15791
  } catch {
@@ -15634,32 +15799,32 @@ function walkDir(root) {
15634
15799
  function hashSkillRoot(absPath) {
15635
15800
  let lst;
15636
15801
  try {
15637
- lst = fs30.lstatSync(absPath);
15802
+ lst = fs31.lstatSync(absPath);
15638
15803
  } catch {
15639
15804
  return { exists: false, contentHash: "", fileCount: 0 };
15640
15805
  }
15641
15806
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
15642
15807
  if (lst.isFile()) {
15643
15808
  try {
15644
- return { exists: true, contentHash: sha256Bytes(fs30.readFileSync(absPath)), fileCount: 1 };
15809
+ return { exists: true, contentHash: sha256Bytes(fs31.readFileSync(absPath)), fileCount: 1 };
15645
15810
  } catch {
15646
15811
  return { exists: false, contentHash: "", fileCount: 0 };
15647
15812
  }
15648
15813
  }
15649
15814
  if (lst.isDirectory()) {
15650
15815
  const entries = walkDir(absPath);
15651
- const contentHash = crypto4.createHash("sha256").update(entries.join("\n")).digest("hex");
15816
+ const contentHash = crypto5.createHash("sha256").update(entries.join("\n")).digest("hex");
15652
15817
  return { exists: true, contentHash, fileCount: entries.length };
15653
15818
  }
15654
15819
  return { exists: false, contentHash: "", fileCount: 0 };
15655
15820
  }
15656
15821
  function getRootKey(absPath) {
15657
- return crypto4.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15822
+ return crypto5.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15658
15823
  }
15659
15824
  function readSkillPinsSafe() {
15660
- const filePath = getPinsFilePath();
15825
+ const filePath = getPinsFilePath2();
15661
15826
  try {
15662
- const raw = fs30.readFileSync(filePath, "utf-8");
15827
+ const raw = fs31.readFileSync(filePath, "utf-8");
15663
15828
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
15664
15829
  const parsed = JSON.parse(raw);
15665
15830
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -15678,18 +15843,18 @@ function readSkillPins() {
15678
15843
  throw new Error(`[node9] skill pin file is corrupt: ${result.detail}`);
15679
15844
  }
15680
15845
  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);
15846
+ const filePath = getPinsFilePath2();
15847
+ fs31.mkdirSync(path32.dirname(filePath), { recursive: true });
15848
+ const tmp = `${filePath}.${crypto5.randomBytes(6).toString("hex")}.tmp`;
15849
+ fs31.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15850
+ fs31.renameSync(tmp, filePath);
15686
15851
  }
15687
- function removePin(rootKey) {
15852
+ function removePin2(rootKey) {
15688
15853
  const pins = readSkillPins();
15689
15854
  delete pins.roots[rootKey];
15690
15855
  writeSkillPins(pins);
15691
15856
  }
15692
- function clearAllPins() {
15857
+ function clearAllPins2() {
15693
15858
  writeSkillPins({ roots: {} });
15694
15859
  }
15695
15860
  function verifyAndPinRoots(roots) {
@@ -15726,36 +15891,36 @@ function verifyAndPinRoots(roots) {
15726
15891
  return { kind: "verified" };
15727
15892
  }
15728
15893
  function defaultSkillRoots(_cwd) {
15729
- const marketplaces = path31.join(os26.homedir(), ".claude", "plugins", "marketplaces");
15894
+ const marketplaces = path32.join(os27.homedir(), ".claude", "plugins", "marketplaces");
15730
15895
  const roots = [];
15731
15896
  let registries;
15732
15897
  try {
15733
- registries = fs30.readdirSync(marketplaces, { withFileTypes: true });
15898
+ registries = fs31.readdirSync(marketplaces, { withFileTypes: true });
15734
15899
  } catch {
15735
15900
  return [];
15736
15901
  }
15737
15902
  for (const registry of registries) {
15738
15903
  if (!registry.isDirectory()) continue;
15739
- const pluginsDir = path31.join(marketplaces, registry.name, "plugins");
15904
+ const pluginsDir = path32.join(marketplaces, registry.name, "plugins");
15740
15905
  let plugins;
15741
15906
  try {
15742
- plugins = fs30.readdirSync(pluginsDir, { withFileTypes: true });
15907
+ plugins = fs31.readdirSync(pluginsDir, { withFileTypes: true });
15743
15908
  } catch {
15744
15909
  continue;
15745
15910
  }
15746
15911
  for (const plugin of plugins) {
15747
15912
  if (!plugin.isDirectory()) continue;
15748
- roots.push(path31.join(pluginsDir, plugin.name));
15913
+ roots.push(path32.join(pluginsDir, plugin.name));
15749
15914
  }
15750
15915
  }
15751
15916
  return roots;
15752
15917
  }
15753
15918
  function resolveUserSkillRoot(entry, cwd) {
15754
15919
  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);
15920
+ if (entry.startsWith("~/") || entry === "~") return path32.join(os27.homedir(), entry.slice(1));
15921
+ if (path32.isAbsolute(entry)) return entry;
15922
+ if (!cwd || !path32.isAbsolute(cwd)) return null;
15923
+ return path32.join(cwd, entry);
15759
15924
  }
15760
15925
 
15761
15926
  // src/cli/commands/check.ts
@@ -15802,9 +15967,9 @@ function registerCheckCommand(program2) {
15802
15967
  } catch (err2) {
15803
15968
  const tempConfig = getConfig();
15804
15969
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
15805
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
15970
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
15806
15971
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
15807
- fs31.appendFileSync(
15972
+ fs32.appendFileSync(
15808
15973
  logPath,
15809
15974
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
15810
15975
  RAW: ${raw}
@@ -15817,14 +15982,14 @@ RAW: ${raw}
15817
15982
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
15818
15983
  if (process.env.NODE9_DEBUG === "1") {
15819
15984
  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 });
15985
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
15986
+ if (!fs32.existsSync(path33.dirname(logPath)))
15987
+ fs32.mkdirSync(path33.dirname(logPath), { recursive: true });
15823
15988
  const sanitized = JSON.stringify({
15824
15989
  ...payload,
15825
15990
  prompt: `<redacted, ${prompt.length} bytes>`
15826
15991
  });
15827
- fs31.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
15992
+ fs32.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
15828
15993
  `);
15829
15994
  } catch {
15830
15995
  }
@@ -15844,8 +16009,8 @@ RAW: ${raw}
15844
16009
  );
15845
16010
  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
16011
  try {
15847
- const ttyFd = fs31.openSync("/dev/tty", "w");
15848
- fs31.writeSync(
16012
+ const ttyFd = fs32.openSync("/dev/tty", "w");
16013
+ fs32.writeSync(
15849
16014
  ttyFd,
15850
16015
  chalk9.bgRed.white.bold(`
15851
16016
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -15855,7 +16020,7 @@ RAW: ${raw}
15855
16020
 
15856
16021
  `)
15857
16022
  );
15858
- fs31.closeSync(ttyFd);
16023
+ fs32.closeSync(ttyFd);
15859
16024
  } catch {
15860
16025
  }
15861
16026
  const isCodex = agent2 === "Codex";
@@ -15873,16 +16038,16 @@ RAW: ${raw}
15873
16038
  );
15874
16039
  process.exit(2);
15875
16040
  }
15876
- const safeCwdForConfig = typeof payload.cwd === "string" && path32.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16041
+ const safeCwdForConfig = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15877
16042
  const config = getConfig(safeCwdForConfig);
15878
16043
  if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
15879
16044
  try {
15880
16045
  const scriptPath = process.argv[1];
15881
- if (typeof scriptPath !== "string" || !path32.isAbsolute(scriptPath))
16046
+ if (typeof scriptPath !== "string" || !path33.isAbsolute(scriptPath))
15882
16047
  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)
16048
+ const resolvedScript = fs32.realpathSync(scriptPath);
16049
+ const packageDist = fs32.realpathSync(path33.resolve(__dirname, "../.."));
16050
+ if (!resolvedScript.startsWith(packageDist + path33.sep) && resolvedScript !== packageDist)
15886
16051
  throw new Error(
15887
16052
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
15888
16053
  );
@@ -15904,10 +16069,10 @@ RAW: ${raw}
15904
16069
  });
15905
16070
  d.unref();
15906
16071
  } catch (spawnErr) {
15907
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
16072
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
15908
16073
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
15909
16074
  try {
15910
- fs31.appendFileSync(
16075
+ fs32.appendFileSync(
15911
16076
  logPath,
15912
16077
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
15913
16078
  `
@@ -15917,10 +16082,10 @@ RAW: ${raw}
15917
16082
  }
15918
16083
  }
15919
16084
  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}
16085
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16086
+ if (!fs32.existsSync(path33.dirname(logPath)))
16087
+ fs32.mkdirSync(path33.dirname(logPath), { recursive: true });
16088
+ fs32.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
15924
16089
  `);
15925
16090
  }
15926
16091
  const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
@@ -15933,8 +16098,8 @@ RAW: ${raw}
15933
16098
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
15934
16099
  let ttyFd = null;
15935
16100
  try {
15936
- ttyFd = fs31.openSync("/dev/tty", "w");
15937
- const writeTty = (line) => fs31.writeSync(ttyFd, line + "\n");
16101
+ ttyFd = fs32.openSync("/dev/tty", "w");
16102
+ const writeTty = (line) => fs32.writeSync(ttyFd, line + "\n");
15938
16103
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
15939
16104
  writeTty(chalk9.bgRed.white.bold(`
15940
16105
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -15953,7 +16118,7 @@ RAW: ${raw}
15953
16118
  } finally {
15954
16119
  if (ttyFd !== null)
15955
16120
  try {
15956
- fs31.closeSync(ttyFd);
16121
+ fs32.closeSync(ttyFd);
15957
16122
  } catch {
15958
16123
  }
15959
16124
  }
@@ -15989,17 +16154,17 @@ RAW: ${raw}
15989
16154
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
15990
16155
  if (skillPinCfg.enabled && safeSessionId) {
15991
16156
  try {
15992
- const sessionsDir = path32.join(os27.homedir(), ".node9", "skill-sessions");
15993
- const flagPath = path32.join(sessionsDir, `${safeSessionId}.json`);
16157
+ const sessionsDir = path33.join(os28.homedir(), ".node9", "skill-sessions");
16158
+ const flagPath = path33.join(sessionsDir, `${safeSessionId}.json`);
15994
16159
  let flag = null;
15995
16160
  try {
15996
- flag = JSON.parse(fs31.readFileSync(flagPath, "utf-8"));
16161
+ flag = JSON.parse(fs32.readFileSync(flagPath, "utf-8"));
15997
16162
  } catch {
15998
16163
  }
15999
16164
  const writeFlag = (data2) => {
16000
16165
  try {
16001
- fs31.mkdirSync(sessionsDir, { recursive: true });
16002
- fs31.writeFileSync(
16166
+ fs32.mkdirSync(sessionsDir, { recursive: true });
16167
+ fs32.writeFileSync(
16003
16168
  flagPath,
16004
16169
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
16005
16170
  { mode: 384 }
@@ -16010,8 +16175,8 @@ RAW: ${raw}
16010
16175
  const sendSkillWarn = (detail, recoveryCmd) => {
16011
16176
  let ttyFd = null;
16012
16177
  try {
16013
- ttyFd = fs31.openSync("/dev/tty", "w");
16014
- const w = (line) => fs31.writeSync(ttyFd, line + "\n");
16178
+ ttyFd = fs32.openSync("/dev/tty", "w");
16179
+ const w = (line) => fs32.writeSync(ttyFd, line + "\n");
16015
16180
  w(chalk9.yellow(`
16016
16181
  \u26A0\uFE0F Node9: installed skill drift detected`));
16017
16182
  w(chalk9.gray(` ${detail}`));
@@ -16026,7 +16191,7 @@ RAW: ${raw}
16026
16191
  } finally {
16027
16192
  if (ttyFd !== null)
16028
16193
  try {
16029
- fs31.closeSync(ttyFd);
16194
+ fs32.closeSync(ttyFd);
16030
16195
  } catch {
16031
16196
  }
16032
16197
  }
@@ -16042,7 +16207,7 @@ RAW: ${raw}
16042
16207
  return;
16043
16208
  }
16044
16209
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
16045
- const absoluteCwd = typeof payload.cwd === "string" && path32.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16210
+ const absoluteCwd = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16046
16211
  const extraRoots = skillPinCfg.roots;
16047
16212
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
16048
16213
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -16083,10 +16248,10 @@ RAW: ${raw}
16083
16248
  }
16084
16249
  try {
16085
16250
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
16086
- for (const name of fs31.readdirSync(sessionsDir)) {
16087
- const p = path32.join(sessionsDir, name);
16251
+ for (const name of fs32.readdirSync(sessionsDir)) {
16252
+ const p = path33.join(sessionsDir, name);
16088
16253
  try {
16089
- if (fs31.statSync(p).mtimeMs < cutoff) fs31.unlinkSync(p);
16254
+ if (fs32.statSync(p).mtimeMs < cutoff) fs32.unlinkSync(p);
16090
16255
  } catch {
16091
16256
  }
16092
16257
  }
@@ -16096,9 +16261,9 @@ RAW: ${raw}
16096
16261
  } catch (err2) {
16097
16262
  if (process.env.NODE9_DEBUG === "1") {
16098
16263
  try {
16099
- const dbg = path32.join(os27.homedir(), ".node9", "hook-debug.log");
16264
+ const dbg = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16100
16265
  const msg = err2 instanceof Error ? err2.message : String(err2);
16101
- fs31.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16266
+ fs32.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16102
16267
  `);
16103
16268
  } catch {
16104
16269
  }
@@ -16108,7 +16273,7 @@ RAW: ${raw}
16108
16273
  if (shouldSnapshot(toolName, toolInput, config)) {
16109
16274
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
16110
16275
  }
16111
- const safeCwdForAuth = typeof payload.cwd === "string" && path32.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16276
+ const safeCwdForAuth = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16112
16277
  const result = await authorizeHeadless(toolName, toolInput, meta, {
16113
16278
  cwd: safeCwdForAuth
16114
16279
  });
@@ -16120,12 +16285,12 @@ RAW: ${raw}
16120
16285
  }
16121
16286
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
16122
16287
  try {
16123
- const tty = fs31.openSync("/dev/tty", "w");
16124
- fs31.writeSync(
16288
+ const tty = fs32.openSync("/dev/tty", "w");
16289
+ fs32.writeSync(
16125
16290
  tty,
16126
16291
  chalk9.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
16127
16292
  );
16128
- fs31.closeSync(tty);
16293
+ fs32.closeSync(tty);
16129
16294
  } catch {
16130
16295
  }
16131
16296
  const daemonReady = await autoStartDaemonAndWait();
@@ -16152,9 +16317,9 @@ RAW: ${raw}
16152
16317
  });
16153
16318
  } catch (err2) {
16154
16319
  if (process.env.NODE9_DEBUG === "1") {
16155
- const logPath = path32.join(os27.homedir(), ".node9", "hook-debug.log");
16320
+ const logPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16156
16321
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
16157
- fs31.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16322
+ fs32.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16158
16323
  `);
16159
16324
  }
16160
16325
  process.exit(0);
@@ -16190,9 +16355,9 @@ RAW: ${raw}
16190
16355
  // src/cli/commands/log.ts
16191
16356
  init_audit();
16192
16357
  init_config();
16193
- import fs32 from "fs";
16194
- import path33 from "path";
16195
- import os28 from "os";
16358
+ import fs33 from "fs";
16359
+ import path34 from "path";
16360
+ import os29 from "os";
16196
16361
  init_daemon();
16197
16362
 
16198
16363
  // src/utils/cp-mv-parser.ts
@@ -16268,10 +16433,10 @@ function registerLogCommand(program2) {
16268
16433
  };
16269
16434
  if (agent) entry.agent = agent;
16270
16435
  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");
16436
+ const logPath = path34.join(os29.homedir(), ".node9", "audit.log");
16437
+ if (!fs33.existsSync(path34.dirname(logPath)))
16438
+ fs33.mkdirSync(path34.dirname(logPath), { recursive: true });
16439
+ fs33.appendFileSync(logPath, JSON.stringify(entry) + "\n");
16275
16440
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
16276
16441
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
16277
16442
  if (command) {
@@ -16304,7 +16469,7 @@ function registerLogCommand(program2) {
16304
16469
  }
16305
16470
  }
16306
16471
  }
16307
- const safeCwd = typeof payload.cwd === "string" && path33.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16472
+ const safeCwd = typeof payload.cwd === "string" && path34.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16308
16473
  const config = getConfig(safeCwd);
16309
16474
  if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
16310
16475
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
@@ -16325,9 +16490,9 @@ function registerLogCommand(program2) {
16325
16490
  const msg = err2 instanceof Error ? err2.message : String(err2);
16326
16491
  process.stderr.write(`[Node9] audit log error: ${msg}
16327
16492
  `);
16328
- const debugPath = path33.join(os28.homedir(), ".node9", "hook-debug.log");
16493
+ const debugPath = path34.join(os29.homedir(), ".node9", "hook-debug.log");
16329
16494
  try {
16330
- fs32.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16495
+ fs33.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16331
16496
  `);
16332
16497
  } catch {
16333
16498
  }
@@ -16728,13 +16893,13 @@ function registerConfigShowCommand(program2) {
16728
16893
  // src/cli/commands/doctor.ts
16729
16894
  init_daemon();
16730
16895
  import chalk11 from "chalk";
16731
- import fs33 from "fs";
16732
- import path34 from "path";
16733
- import os29 from "os";
16896
+ import fs34 from "fs";
16897
+ import path35 from "path";
16898
+ import os30 from "os";
16734
16899
  import { execSync } from "child_process";
16735
16900
  function registerDoctorCommand(program2, version2) {
16736
16901
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
16737
- const homeDir2 = os29.homedir();
16902
+ const homeDir2 = os30.homedir();
16738
16903
  let failures = 0;
16739
16904
  function pass(msg) {
16740
16905
  console.log(chalk11.green(" \u2705 ") + msg);
@@ -16783,10 +16948,10 @@ function registerDoctorCommand(program2, version2) {
16783
16948
  );
16784
16949
  }
16785
16950
  section("Configuration");
16786
- const globalConfigPath = path34.join(homeDir2, ".node9", "config.json");
16787
- if (fs33.existsSync(globalConfigPath)) {
16951
+ const globalConfigPath = path35.join(homeDir2, ".node9", "config.json");
16952
+ if (fs34.existsSync(globalConfigPath)) {
16788
16953
  try {
16789
- JSON.parse(fs33.readFileSync(globalConfigPath, "utf-8"));
16954
+ JSON.parse(fs34.readFileSync(globalConfigPath, "utf-8"));
16790
16955
  pass("~/.node9/config.json found and valid");
16791
16956
  } catch {
16792
16957
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -16794,10 +16959,10 @@ function registerDoctorCommand(program2, version2) {
16794
16959
  } else {
16795
16960
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
16796
16961
  }
16797
- const projectConfigPath = path34.join(process.cwd(), "node9.config.json");
16798
- if (fs33.existsSync(projectConfigPath)) {
16962
+ const projectConfigPath = path35.join(process.cwd(), "node9.config.json");
16963
+ if (fs34.existsSync(projectConfigPath)) {
16799
16964
  try {
16800
- JSON.parse(fs33.readFileSync(projectConfigPath, "utf-8"));
16965
+ JSON.parse(fs34.readFileSync(projectConfigPath, "utf-8"));
16801
16966
  pass("node9.config.json found and valid (project)");
16802
16967
  } catch {
16803
16968
  fail(
@@ -16806,8 +16971,8 @@ function registerDoctorCommand(program2, version2) {
16806
16971
  );
16807
16972
  }
16808
16973
  }
16809
- const credsPath = path34.join(homeDir2, ".node9", "credentials.json");
16810
- if (fs33.existsSync(credsPath)) {
16974
+ const credsPath = path35.join(homeDir2, ".node9", "credentials.json");
16975
+ if (fs34.existsSync(credsPath)) {
16811
16976
  pass("Cloud credentials found (~/.node9/credentials.json)");
16812
16977
  } else {
16813
16978
  warn(
@@ -16816,10 +16981,10 @@ function registerDoctorCommand(program2, version2) {
16816
16981
  );
16817
16982
  }
16818
16983
  section("Agent Hooks");
16819
- const claudeSettingsPath = path34.join(homeDir2, ".claude", "settings.json");
16820
- if (fs33.existsSync(claudeSettingsPath)) {
16984
+ const claudeSettingsPath = path35.join(homeDir2, ".claude", "settings.json");
16985
+ if (fs34.existsSync(claudeSettingsPath)) {
16821
16986
  try {
16822
- const cs = JSON.parse(fs33.readFileSync(claudeSettingsPath, "utf-8"));
16987
+ const cs = JSON.parse(fs34.readFileSync(claudeSettingsPath, "utf-8"));
16823
16988
  const hasHook = cs.hooks?.PreToolUse?.some(
16824
16989
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16825
16990
  );
@@ -16835,10 +17000,10 @@ function registerDoctorCommand(program2, version2) {
16835
17000
  } else {
16836
17001
  warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
16837
17002
  }
16838
- const geminiSettingsPath = path34.join(homeDir2, ".gemini", "settings.json");
16839
- if (fs33.existsSync(geminiSettingsPath)) {
17003
+ const geminiSettingsPath = path35.join(homeDir2, ".gemini", "settings.json");
17004
+ if (fs34.existsSync(geminiSettingsPath)) {
16840
17005
  try {
16841
- const gs = JSON.parse(fs33.readFileSync(geminiSettingsPath, "utf-8"));
17006
+ const gs = JSON.parse(fs34.readFileSync(geminiSettingsPath, "utf-8"));
16842
17007
  const hasHook = gs.hooks?.BeforeTool?.some(
16843
17008
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16844
17009
  );
@@ -16854,10 +17019,10 @@ function registerDoctorCommand(program2, version2) {
16854
17019
  } else {
16855
17020
  warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
16856
17021
  }
16857
- const cursorHooksPath = path34.join(homeDir2, ".cursor", "hooks.json");
16858
- if (fs33.existsSync(cursorHooksPath)) {
17022
+ const cursorHooksPath = path35.join(homeDir2, ".cursor", "hooks.json");
17023
+ if (fs34.existsSync(cursorHooksPath)) {
16859
17024
  try {
16860
- const cur = JSON.parse(fs33.readFileSync(cursorHooksPath, "utf-8"));
17025
+ const cur = JSON.parse(fs34.readFileSync(cursorHooksPath, "utf-8"));
16861
17026
  const hasHook = cur.hooks?.preToolUse?.some(
16862
17027
  (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
16863
17028
  );
@@ -16897,9 +17062,9 @@ function registerDoctorCommand(program2, version2) {
16897
17062
 
16898
17063
  // src/cli/commands/audit.ts
16899
17064
  import chalk12 from "chalk";
16900
- import fs34 from "fs";
16901
- import path35 from "path";
16902
- import os30 from "os";
17065
+ import fs35 from "fs";
17066
+ import path36 from "path";
17067
+ import os31 from "os";
16903
17068
  function formatRelativeTime(timestamp) {
16904
17069
  const diff = Date.now() - new Date(timestamp).getTime();
16905
17070
  const sec = Math.floor(diff / 1e3);
@@ -16912,14 +17077,14 @@ function formatRelativeTime(timestamp) {
16912
17077
  }
16913
17078
  function registerAuditCommand(program2) {
16914
17079
  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)) {
17080
+ const logPath = path36.join(os31.homedir(), ".node9", "audit.log");
17081
+ if (!fs35.existsSync(logPath)) {
16917
17082
  console.log(
16918
17083
  chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
16919
17084
  );
16920
17085
  return;
16921
17086
  }
16922
- const raw = fs34.readFileSync(logPath, "utf-8");
17087
+ const raw = fs35.readFileSync(logPath, "utf-8");
16923
17088
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
16924
17089
  let entries = lines.flatMap((line) => {
16925
17090
  try {
@@ -16977,9 +17142,9 @@ import chalk13 from "chalk";
16977
17142
  // src/cli/aggregate/report-audit.ts
16978
17143
  init_costSync();
16979
17144
  init_litellm();
16980
- import fs35 from "fs";
16981
- import os31 from "os";
16982
- import path36 from "path";
17145
+ import fs36 from "fs";
17146
+ import os32 from "os";
17147
+ import path37 from "path";
16983
17148
  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
17149
  function buildTestTimestamps(allEntries) {
16985
17150
  const testTs = /* @__PURE__ */ new Set();
@@ -17059,8 +17224,8 @@ function getDateRange(period, now) {
17059
17224
  }
17060
17225
  }
17061
17226
  function parseAuditLog(logPath) {
17062
- if (!fs35.existsSync(logPath)) return [];
17063
- const raw = fs35.readFileSync(logPath, "utf-8");
17227
+ if (!fs36.existsSync(logPath)) return [];
17228
+ const raw = fs36.readFileSync(logPath, "utf-8");
17064
17229
  return raw.split("\n").flatMap((line) => {
17065
17230
  if (!line.trim()) return [];
17066
17231
  try {
@@ -17120,25 +17285,25 @@ function freezeClaudeCost(acc) {
17120
17285
  };
17121
17286
  }
17122
17287
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17123
- const projPath = path36.join(projectsDir, proj);
17288
+ const projPath = path37.join(projectsDir, proj);
17124
17289
  let files;
17125
17290
  try {
17126
- const stat = fs35.statSync(projPath);
17291
+ const stat = fs36.statSync(projPath);
17127
17292
  if (!stat.isDirectory()) return;
17128
- files = fs35.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17293
+ files = fs36.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17129
17294
  } catch {
17130
17295
  return;
17131
17296
  }
17132
17297
  const startMs = start.getTime();
17133
17298
  for (const file of files) {
17134
- const filePath = path36.join(projPath, file);
17299
+ const filePath = path37.join(projPath, file);
17135
17300
  try {
17136
- if (fs35.statSync(filePath).mtimeMs < startMs) continue;
17301
+ if (fs36.statSync(filePath).mtimeMs < startMs) continue;
17137
17302
  } catch {
17138
17303
  continue;
17139
17304
  }
17140
17305
  try {
17141
- const raw = fs35.readFileSync(filePath, "utf-8");
17306
+ const raw = fs36.readFileSync(filePath, "utf-8");
17142
17307
  for (const line of raw.split("\n")) {
17143
17308
  if (!line.trim()) continue;
17144
17309
  let entry;
@@ -17188,10 +17353,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17188
17353
  }
17189
17354
  function loadClaudeCost(start, end, projectsDir) {
17190
17355
  const acc = emptyClaudeCostAccumulator();
17191
- if (!fs35.existsSync(projectsDir)) return freezeClaudeCost(acc);
17356
+ if (!fs36.existsSync(projectsDir)) return freezeClaudeCost(acc);
17192
17357
  let dirs;
17193
17358
  try {
17194
- dirs = fs35.readdirSync(projectsDir);
17359
+ dirs = fs36.readdirSync(projectsDir);
17195
17360
  } catch {
17196
17361
  return freezeClaudeCost(acc);
17197
17362
  }
@@ -17203,7 +17368,7 @@ function loadClaudeCost(start, end, projectsDir) {
17203
17368
  function processCodexCostFile(filePath, start, end, acc) {
17204
17369
  let lines;
17205
17370
  try {
17206
- lines = fs35.readFileSync(filePath, "utf-8").split("\n");
17371
+ lines = fs36.readFileSync(filePath, "utf-8").split("\n");
17207
17372
  } catch {
17208
17373
  return;
17209
17374
  }
@@ -17248,31 +17413,31 @@ function processCodexCostFile(filePath, start, end, acc) {
17248
17413
  }
17249
17414
  function listCodexSessionFiles(sessionsBase) {
17250
17415
  const jsonlFiles = [];
17251
- if (!fs35.existsSync(sessionsBase)) return jsonlFiles;
17416
+ if (!fs36.existsSync(sessionsBase)) return jsonlFiles;
17252
17417
  try {
17253
- for (const year of fs35.readdirSync(sessionsBase)) {
17254
- const yearPath = path36.join(sessionsBase, year);
17418
+ for (const year of fs36.readdirSync(sessionsBase)) {
17419
+ const yearPath = path37.join(sessionsBase, year);
17255
17420
  try {
17256
- if (!fs35.statSync(yearPath).isDirectory()) continue;
17421
+ if (!fs36.statSync(yearPath).isDirectory()) continue;
17257
17422
  } catch {
17258
17423
  continue;
17259
17424
  }
17260
- for (const month of fs35.readdirSync(yearPath)) {
17261
- const monthPath = path36.join(yearPath, month);
17425
+ for (const month of fs36.readdirSync(yearPath)) {
17426
+ const monthPath = path37.join(yearPath, month);
17262
17427
  try {
17263
- if (!fs35.statSync(monthPath).isDirectory()) continue;
17428
+ if (!fs36.statSync(monthPath).isDirectory()) continue;
17264
17429
  } catch {
17265
17430
  continue;
17266
17431
  }
17267
- for (const day of fs35.readdirSync(monthPath)) {
17268
- const dayPath = path36.join(monthPath, day);
17432
+ for (const day of fs36.readdirSync(monthPath)) {
17433
+ const dayPath = path37.join(monthPath, day);
17269
17434
  try {
17270
- if (!fs35.statSync(dayPath).isDirectory()) continue;
17435
+ if (!fs36.statSync(dayPath).isDirectory()) continue;
17271
17436
  } catch {
17272
17437
  continue;
17273
17438
  }
17274
- for (const file of fs35.readdirSync(dayPath)) {
17275
- if (file.endsWith(".jsonl")) jsonlFiles.push(path36.join(dayPath, file));
17439
+ for (const file of fs36.readdirSync(dayPath)) {
17440
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path37.join(dayPath, file));
17276
17441
  }
17277
17442
  }
17278
17443
  }
@@ -17325,13 +17490,13 @@ function freezeGeminiCost(acc) {
17325
17490
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
17326
17491
  const startMs = start.getTime();
17327
17492
  try {
17328
- if (fs35.statSync(filePath).mtimeMs < startMs) return;
17493
+ if (fs36.statSync(filePath).mtimeMs < startMs) return;
17329
17494
  } catch {
17330
17495
  return;
17331
17496
  }
17332
17497
  let raw;
17333
17498
  try {
17334
- raw = fs35.readFileSync(filePath, "utf-8");
17499
+ raw = fs36.readFileSync(filePath, "utf-8");
17335
17500
  } catch {
17336
17501
  return;
17337
17502
  }
@@ -17380,30 +17545,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
17380
17545
  const out = [];
17381
17546
  let dirs;
17382
17547
  try {
17383
- if (!fs35.statSync(geminiTmpDir).isDirectory()) return out;
17384
- dirs = fs35.readdirSync(geminiTmpDir);
17548
+ if (!fs36.statSync(geminiTmpDir).isDirectory()) return out;
17549
+ dirs = fs36.readdirSync(geminiTmpDir);
17385
17550
  } catch {
17386
17551
  return out;
17387
17552
  }
17388
17553
  for (const proj of dirs) {
17389
- const chatsDir = path36.join(geminiTmpDir, proj, "chats");
17554
+ const chatsDir = path37.join(geminiTmpDir, proj, "chats");
17390
17555
  let files;
17391
17556
  try {
17392
- if (!fs35.statSync(chatsDir).isDirectory()) continue;
17393
- files = fs35.readdirSync(chatsDir);
17557
+ if (!fs36.statSync(chatsDir).isDirectory()) continue;
17558
+ files = fs36.readdirSync(chatsDir);
17394
17559
  } catch {
17395
17560
  continue;
17396
17561
  }
17397
17562
  for (const f of files) {
17398
17563
  if (!f.endsWith(".jsonl")) continue;
17399
- out.push({ projectKey: proj, file: path36.join(chatsDir, f) });
17564
+ out.push({ projectKey: proj, file: path37.join(chatsDir, f) });
17400
17565
  }
17401
17566
  }
17402
17567
  return out;
17403
17568
  }
17404
17569
  function loadGeminiCost(start, end, geminiTmpDir) {
17405
17570
  const acc = emptyGeminiAccumulator();
17406
- if (!fs35.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17571
+ if (!fs36.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17407
17572
  for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
17408
17573
  processGeminiCostFile(file, projectKey, start, end, acc);
17409
17574
  }
@@ -17411,11 +17576,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
17411
17576
  }
17412
17577
  function aggregateReportFromAudit(period, opts = {}) {
17413
17578
  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);
17579
+ const auditLogPath = opts.auditLogPath ?? path37.join(os32.homedir(), ".node9", "audit.log");
17580
+ const claudeProjectsDir = opts.claudeProjectsDir ?? path37.join(os32.homedir(), ".claude", "projects");
17581
+ const codexSessionsDir = opts.codexSessionsDir ?? path37.join(os32.homedir(), ".codex", "sessions");
17582
+ const geminiTmpDir = opts.geminiTmpDir ?? path37.join(os32.homedir(), ".gemini", "tmp");
17583
+ const hasAuditFile = fs36.existsSync(auditLogPath);
17419
17584
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
17420
17585
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
17421
17586
  const { start, end } = getDateRange(period, now);
@@ -18113,12 +18278,12 @@ function registerDaemonCommand(program2) {
18113
18278
  init_core();
18114
18279
  init_daemon();
18115
18280
  import chalk15 from "chalk";
18116
- import fs36 from "fs";
18117
- import path37 from "path";
18118
- import os32 from "os";
18281
+ import fs37 from "fs";
18282
+ import path38 from "path";
18283
+ import os33 from "os";
18119
18284
  function readJson2(filePath) {
18120
18285
  try {
18121
- if (fs36.existsSync(filePath)) return JSON.parse(fs36.readFileSync(filePath, "utf-8"));
18286
+ if (fs37.existsSync(filePath)) return JSON.parse(fs37.readFileSync(filePath, "utf-8"));
18122
18287
  } catch {
18123
18288
  }
18124
18289
  return null;
@@ -18183,28 +18348,28 @@ function registerStatusCommand(program2) {
18183
18348
  console.log("");
18184
18349
  const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
18185
18350
  console.log(` Mode: ${modeLabel}`);
18186
- const projectConfig = path37.join(process.cwd(), "node9.config.json");
18187
- const globalConfig = path37.join(os32.homedir(), ".node9", "config.json");
18351
+ const projectConfig = path38.join(process.cwd(), "node9.config.json");
18352
+ const globalConfig = path38.join(os33.homedir(), ".node9", "config.json");
18188
18353
  console.log(
18189
- ` Local: ${fs36.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
18354
+ ` Local: ${fs37.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
18190
18355
  );
18191
18356
  console.log(
18192
- ` Global: ${fs36.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
18357
+ ` Global: ${fs37.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
18193
18358
  );
18194
18359
  if (mergedConfig.policy.sandboxPaths.length > 0) {
18195
18360
  console.log(
18196
18361
  ` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
18197
18362
  );
18198
18363
  }
18199
- const homeDir2 = os32.homedir();
18364
+ const homeDir2 = os33.homedir();
18200
18365
  const claudeSettings = readJson2(
18201
- path37.join(homeDir2, ".claude", "settings.json")
18366
+ path38.join(homeDir2, ".claude", "settings.json")
18202
18367
  );
18203
- const claudeConfig = readJson2(path37.join(homeDir2, ".claude.json"));
18368
+ const claudeConfig = readJson2(path38.join(homeDir2, ".claude.json"));
18204
18369
  const geminiSettings = readJson2(
18205
- path37.join(homeDir2, ".gemini", "settings.json")
18370
+ path38.join(homeDir2, ".gemini", "settings.json")
18206
18371
  );
18207
- const cursorConfig = readJson2(path37.join(homeDir2, ".cursor", "mcp.json"));
18372
+ const cursorConfig = readJson2(path38.join(homeDir2, ".cursor", "mcp.json"));
18208
18373
  const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
18209
18374
  if (agentFound) {
18210
18375
  console.log("");
@@ -18267,9 +18432,9 @@ init_setup();
18267
18432
  init_shields();
18268
18433
  init_service();
18269
18434
  import chalk16 from "chalk";
18270
- import fs37 from "fs";
18271
- import path38 from "path";
18272
- import os33 from "os";
18435
+ import fs38 from "fs";
18436
+ import path39 from "path";
18437
+ import os34 from "os";
18273
18438
  import https4 from "https";
18274
18439
  var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
18275
18440
  function fireTelemetryPing(agents) {
@@ -18345,15 +18510,15 @@ function registerInitCommand(program2) {
18345
18510
  }
18346
18511
  console.log("");
18347
18512
  }
18348
- const configPath = path38.join(os33.homedir(), ".node9", "config.json");
18349
- if (fs37.existsSync(configPath) && !options.force) {
18513
+ const configPath = path39.join(os34.homedir(), ".node9", "config.json");
18514
+ if (fs38.existsSync(configPath) && !options.force) {
18350
18515
  try {
18351
- const existing = JSON.parse(fs37.readFileSync(configPath, "utf-8"));
18516
+ const existing = JSON.parse(fs38.readFileSync(configPath, "utf-8"));
18352
18517
  const settings = existing.settings ?? {};
18353
18518
  if (settings.mode !== chosenMode) {
18354
18519
  settings.mode = chosenMode;
18355
18520
  existing.settings = settings;
18356
- fs37.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18521
+ fs38.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18357
18522
  console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
18358
18523
  } else {
18359
18524
  console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -18366,9 +18531,9 @@ function registerInitCommand(program2) {
18366
18531
  ...DEFAULT_CONFIG,
18367
18532
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
18368
18533
  };
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");
18534
+ const dir = path39.dirname(configPath);
18535
+ if (!fs38.existsSync(dir)) fs38.mkdirSync(dir, { recursive: true });
18536
+ fs38.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
18372
18537
  console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
18373
18538
  console.log(chalk16.gray(` Mode: ${chosenMode}`));
18374
18539
  }
@@ -18466,7 +18631,7 @@ function registerInitCommand(program2) {
18466
18631
  }
18467
18632
 
18468
18633
  // src/cli/commands/undo.ts
18469
- import path39 from "path";
18634
+ import path40 from "path";
18470
18635
  import chalk18 from "chalk";
18471
18636
 
18472
18637
  // src/tui/undo-navigator.ts
@@ -18625,7 +18790,7 @@ function findMatchingCwd(startDir, history) {
18625
18790
  let dir = startDir;
18626
18791
  while (true) {
18627
18792
  if (cwds.has(dir)) return dir;
18628
- const parent = path39.dirname(dir);
18793
+ const parent = path40.dirname(dir);
18629
18794
  if (parent === dir) return null;
18630
18795
  dir = parent;
18631
18796
  }
@@ -18758,90 +18923,7 @@ import chalk19 from "chalk";
18758
18923
  import { spawn as spawn7 } from "child_process";
18759
18924
  import { execa as execa2 } from "execa";
18760
18925
  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
18926
+ init_mcp_pin();
18845
18927
  init_mcp_tools();
18846
18928
  init_daemon();
18847
18929
  function sanitize4(value) {
@@ -18903,6 +18985,7 @@ function tokenize4(cmd) {
18903
18985
  return tokens;
18904
18986
  }
18905
18987
  async function runMcpGateway(upstreamCommand) {
18988
+ const gatewayCwd = process.cwd();
18906
18989
  const commandParts = tokenize4(upstreamCommand);
18907
18990
  const cmd = commandParts[0];
18908
18991
  const cmdArgs = commandParts.slice(1);
@@ -19125,7 +19208,7 @@ async function runMcpGateway(upstreamCommand) {
19125
19208
  if (parsed.result && Array.isArray(parsed.result.tools)) {
19126
19209
  const tools = parsed.result.tools || [];
19127
19210
  const currentHash = hashToolDefinitions(tools);
19128
- const pinStatus = checkPin(serverKey, currentHash);
19211
+ const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
19129
19212
  const token = getInternalToken();
19130
19213
  if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
19131
19214
  const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
@@ -20009,27 +20092,46 @@ function registerTrustCommand(program2) {
20009
20092
  }
20010
20093
 
20011
20094
  // src/cli/commands/mcp-pin.ts
20095
+ init_mcp_pin();
20012
20096
  import chalk21 from "chalk";
20097
+ import fs40 from "fs";
20013
20098
  function registerMcpPinCommand(program2) {
20014
20099
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
20015
20100
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
20016
20101
  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;
20102
+ const found = findPinsFilePath(process.cwd());
20103
+ const homeResult = readMcpPinsSafe();
20104
+ let repoEntries = {};
20105
+ let repoCorrupt = false;
20106
+ if (found.source === "repo") {
20107
+ try {
20108
+ const raw = fs40.readFileSync(found.path, "utf-8");
20109
+ const parsed = JSON.parse(raw);
20110
+ repoEntries = parsed.servers ?? {};
20111
+ } catch {
20112
+ repoCorrupt = true;
20025
20113
  }
20114
+ }
20115
+ if (repoCorrupt) {
20026
20116
  console.error(chalk21.red(`
20027
- \u274C Pin file is corrupt: ${result.detail}`));
20117
+ \u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
20118
+ process.exit(1);
20119
+ }
20120
+ if (!homeResult.ok && homeResult.reason === "corrupt") {
20121
+ console.error(chalk21.red(`
20122
+ \u274C Home pin file is corrupt: ${homeResult.detail}`));
20028
20123
  console.error(chalk21.yellow(" Run: node9 mcp pin reset\n"));
20029
20124
  process.exit(1);
20030
20125
  }
20031
- const entries = Object.entries(result.pins.servers);
20032
- if (entries.length === 0) {
20126
+ const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
20127
+ const merged = /* @__PURE__ */ new Map();
20128
+ for (const [key, entry] of Object.entries(homeEntries)) {
20129
+ merged.set(key, { entry, source: "home" });
20130
+ }
20131
+ for (const [key, entry] of Object.entries(repoEntries)) {
20132
+ merged.set(key, { entry, source: "repo" });
20133
+ }
20134
+ if (merged.size === 0) {
20033
20135
  console.log(chalk21.gray("\nNo MCP servers are pinned yet."));
20034
20136
  console.log(
20035
20137
  chalk21.gray("Pins are created automatically when the MCP gateway first connects.\n")
@@ -20037,13 +20139,47 @@ function registerMcpPinCommand(program2) {
20037
20139
  return;
20038
20140
  }
20039
20141
  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)}`);
20142
+ const showSource = found.source === "repo";
20143
+ for (const [key, { entry, source }] of merged) {
20144
+ const tag = showSource ? ` ${chalk21.yellow(`[${source}]`)}` : "";
20145
+ console.log(` ${chalk21.cyan(key)}${tag} ${chalk21.gray(entry.label)}`);
20042
20146
  console.log(` Tools (${entry.toolCount}): ${chalk21.white(entry.toolNames.join(", "))}`);
20043
20147
  console.log(` Hash: ${chalk21.gray(entry.toolsHash.slice(0, 16))}...`);
20044
20148
  console.log(` Pinned: ${chalk21.gray(entry.pinnedAt)}`);
20045
20149
  console.log("");
20046
20150
  }
20151
+ if (showSource) {
20152
+ console.log(chalk21.gray(` [repo] entries come from ${found.path}`));
20153
+ console.log(chalk21.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
20154
+ }
20155
+ });
20156
+ pinSubCmd.command("promote <serverKey>").description(
20157
+ "Copy a pin from ~/.node9/mcp-pins.json into <repo>/.node9/mcp-pins.json so teammates share the same vetted baseline"
20158
+ ).action((serverKey) => {
20159
+ try {
20160
+ const { repoPath, created } = promotePin(serverKey, process.cwd());
20161
+ if (created) {
20162
+ console.log(
20163
+ chalk21.green(
20164
+ `
20165
+ \u2705 Created ${repoPath} with the promoted pin for ${chalk21.cyan(serverKey)}.`
20166
+ )
20167
+ );
20168
+ } else {
20169
+ console.log(chalk21.green(`
20170
+ \u2705 Promoted ${chalk21.cyan(serverKey)} into ${repoPath}.`));
20171
+ }
20172
+ console.log(chalk21.gray(" Review the change and commit it:"));
20173
+ console.log(chalk21.cyan(` git add ${repoPath}`));
20174
+ console.log(chalk21.cyan(` git commit -m "pin ${serverKey} (node9)"`));
20175
+ console.log("");
20176
+ } catch (err2) {
20177
+ const msg = err2 instanceof Error ? err2.message : String(err2);
20178
+ console.error(chalk21.red(`
20179
+ \u274C ${msg}
20180
+ `));
20181
+ process.exit(1);
20182
+ }
20047
20183
  });
20048
20184
  pinSubCmd.command("update <serverKey>").description(
20049
20185
  "Remove a pin so the next gateway connection re-pins with current tool definitions"
@@ -20065,7 +20201,7 @@ function registerMcpPinCommand(program2) {
20065
20201
  process.exit(1);
20066
20202
  }
20067
20203
  const label = pins.servers[serverKey].label;
20068
- removePin2(serverKey);
20204
+ removePin(serverKey);
20069
20205
  console.log(chalk21.green(`
20070
20206
  \u{1F513} Pin removed for ${chalk21.cyan(serverKey)}`));
20071
20207
  console.log(chalk21.gray(` Server: ${label}`));
@@ -20078,7 +20214,7 @@ function registerMcpPinCommand(program2) {
20078
20214
  return;
20079
20215
  }
20080
20216
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
20081
- clearAllPins2();
20217
+ clearAllPins();
20082
20218
  console.log(chalk21.green(`
20083
20219
  \u{1F513} Cleared ${count} MCP pin(s).`));
20084
20220
  console.log(chalk21.gray(" Next connection to each server will re-pin.\n"));
@@ -20261,7 +20397,7 @@ init_scan();
20261
20397
 
20262
20398
  // src/cli/commands/sessions.ts
20263
20399
  import chalk24 from "chalk";
20264
- import fs40 from "fs";
20400
+ import fs41 from "fs";
20265
20401
  import path42 from "path";
20266
20402
  import os36 from "os";
20267
20403
  var CLAUDE_PRICING3 = {
@@ -20379,7 +20515,7 @@ function loadAuditEntries(auditPath) {
20379
20515
  const aPath = auditPath ?? path42.join(os36.homedir(), ".node9", "audit.log");
20380
20516
  let raw;
20381
20517
  try {
20382
- raw = fs40.readFileSync(aPath, "utf-8");
20518
+ raw = fs41.readFileSync(aPath, "utf-8");
20383
20519
  } catch {
20384
20520
  return [];
20385
20521
  }
@@ -20416,7 +20552,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
20416
20552
  }
20417
20553
  function buildGeminiSessions(days, allAuditEntries) {
20418
20554
  const tmpDir = path42.join(os36.homedir(), ".gemini", "tmp");
20419
- if (!fs40.existsSync(tmpDir)) return [];
20555
+ if (!fs41.existsSync(tmpDir)) return [];
20420
20556
  const cutoff = days !== null ? (() => {
20421
20557
  const d = /* @__PURE__ */ new Date();
20422
20558
  d.setDate(d.getDate() - days);
@@ -20425,7 +20561,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20425
20561
  })() : null;
20426
20562
  let slugDirs;
20427
20563
  try {
20428
- slugDirs = fs40.readdirSync(tmpDir);
20564
+ slugDirs = fs41.readdirSync(tmpDir);
20429
20565
  } catch {
20430
20566
  return [];
20431
20567
  }
@@ -20433,27 +20569,27 @@ function buildGeminiSessions(days, allAuditEntries) {
20433
20569
  for (const slug of slugDirs) {
20434
20570
  const slugPath = path42.join(tmpDir, slug);
20435
20571
  try {
20436
- if (!fs40.statSync(slugPath).isDirectory()) continue;
20572
+ if (!fs41.statSync(slugPath).isDirectory()) continue;
20437
20573
  } catch {
20438
20574
  continue;
20439
20575
  }
20440
20576
  let projectRoot = path42.join(os36.homedir(), slug);
20441
20577
  try {
20442
- projectRoot = fs40.readFileSync(path42.join(slugPath, ".project_root"), "utf-8").trim();
20578
+ projectRoot = fs41.readFileSync(path42.join(slugPath, ".project_root"), "utf-8").trim();
20443
20579
  } catch {
20444
20580
  }
20445
20581
  const chatsDir = path42.join(slugPath, "chats");
20446
- if (!fs40.existsSync(chatsDir)) continue;
20582
+ if (!fs41.existsSync(chatsDir)) continue;
20447
20583
  let chatFiles;
20448
20584
  try {
20449
- chatFiles = fs40.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20585
+ chatFiles = fs41.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20450
20586
  } catch {
20451
20587
  continue;
20452
20588
  }
20453
20589
  for (const chatFile of chatFiles) {
20454
20590
  let raw;
20455
20591
  try {
20456
- raw = fs40.readFileSync(path42.join(chatsDir, chatFile), "utf-8");
20592
+ raw = fs41.readFileSync(path42.join(chatsDir, chatFile), "utf-8");
20457
20593
  } catch {
20458
20594
  continue;
20459
20595
  }
@@ -20534,7 +20670,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20534
20670
  }
20535
20671
  function buildCodexSessions(days, allAuditEntries) {
20536
20672
  const sessionsBase = path42.join(os36.homedir(), ".codex", "sessions");
20537
- if (!fs40.existsSync(sessionsBase)) return [];
20673
+ if (!fs41.existsSync(sessionsBase)) return [];
20538
20674
  const cutoff = days !== null ? (() => {
20539
20675
  const d = /* @__PURE__ */ new Date();
20540
20676
  d.setDate(d.getDate() - days);
@@ -20543,28 +20679,28 @@ function buildCodexSessions(days, allAuditEntries) {
20543
20679
  })() : null;
20544
20680
  const jsonlFiles = [];
20545
20681
  try {
20546
- for (const year of fs40.readdirSync(sessionsBase)) {
20682
+ for (const year of fs41.readdirSync(sessionsBase)) {
20547
20683
  const yearPath = path42.join(sessionsBase, year);
20548
20684
  try {
20549
- if (!fs40.statSync(yearPath).isDirectory()) continue;
20685
+ if (!fs41.statSync(yearPath).isDirectory()) continue;
20550
20686
  } catch {
20551
20687
  continue;
20552
20688
  }
20553
- for (const month of fs40.readdirSync(yearPath)) {
20689
+ for (const month of fs41.readdirSync(yearPath)) {
20554
20690
  const monthPath = path42.join(yearPath, month);
20555
20691
  try {
20556
- if (!fs40.statSync(monthPath).isDirectory()) continue;
20692
+ if (!fs41.statSync(monthPath).isDirectory()) continue;
20557
20693
  } catch {
20558
20694
  continue;
20559
20695
  }
20560
- for (const day of fs40.readdirSync(monthPath)) {
20696
+ for (const day of fs41.readdirSync(monthPath)) {
20561
20697
  const dayPath = path42.join(monthPath, day);
20562
20698
  try {
20563
- if (!fs40.statSync(dayPath).isDirectory()) continue;
20699
+ if (!fs41.statSync(dayPath).isDirectory()) continue;
20564
20700
  } catch {
20565
20701
  continue;
20566
20702
  }
20567
- for (const file of fs40.readdirSync(dayPath)) {
20703
+ for (const file of fs41.readdirSync(dayPath)) {
20568
20704
  if (file.endsWith(".jsonl")) jsonlFiles.push(path42.join(dayPath, file));
20569
20705
  }
20570
20706
  }
@@ -20577,7 +20713,7 @@ function buildCodexSessions(days, allAuditEntries) {
20577
20713
  for (const filePath of jsonlFiles) {
20578
20714
  let lines;
20579
20715
  try {
20580
- lines = fs40.readFileSync(filePath, "utf-8").split("\n");
20716
+ lines = fs41.readFileSync(filePath, "utf-8").split("\n");
20581
20717
  } catch {
20582
20718
  continue;
20583
20719
  }
@@ -20658,7 +20794,7 @@ function buildSessions(days, historyPath) {
20658
20794
  const hPath = historyPath ?? path42.join(os36.homedir(), ".claude", "history.jsonl");
20659
20795
  let historyRaw;
20660
20796
  try {
20661
- historyRaw = fs40.readFileSync(hPath, "utf-8");
20797
+ historyRaw = fs41.readFileSync(hPath, "utf-8");
20662
20798
  } catch {
20663
20799
  return [];
20664
20800
  }
@@ -20683,7 +20819,7 @@ function buildSessions(days, historyPath) {
20683
20819
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
20684
20820
  let sessionLines = [];
20685
20821
  try {
20686
- sessionLines = fs40.readFileSync(jsonlFile, "utf-8").split("\n");
20822
+ sessionLines = fs41.readFileSync(jsonlFile, "utf-8").split("\n");
20687
20823
  } catch {
20688
20824
  }
20689
20825
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -20950,7 +21086,7 @@ function registerSessionsCommand(program2) {
20950
21086
  console.log(chalk24.cyan.bold("\u{1F4CB} node9 sessions") + chalk24.dim(" \u2014 what your AI agent did"));
20951
21087
  console.log("");
20952
21088
  const historyPath = path42.join(os36.homedir(), ".claude", "history.jsonl");
20953
- if (!fs40.existsSync(historyPath)) {
21089
+ if (!fs41.existsSync(historyPath)) {
20954
21090
  console.log(chalk24.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
20955
21091
  console.log(chalk24.gray(" Install Claude Code, run a few sessions, then try again.\n"));
20956
21092
  return;
@@ -20987,12 +21123,12 @@ function registerSessionsCommand(program2) {
20987
21123
 
20988
21124
  // src/cli/commands/skill-pin.ts
20989
21125
  import chalk25 from "chalk";
20990
- import fs41 from "fs";
21126
+ import fs42 from "fs";
20991
21127
  import os37 from "os";
20992
21128
  import path43 from "path";
20993
21129
  function wipeSkillSessions() {
20994
21130
  try {
20995
- fs41.rmSync(path43.join(os37.homedir(), ".node9", "skill-sessions"), {
21131
+ fs42.rmSync(path43.join(os37.homedir(), ".node9", "skill-sessions"), {
20996
21132
  recursive: true,
20997
21133
  force: true
20998
21134
  });
@@ -21050,7 +21186,7 @@ function registerSkillPinCommand(program2) {
21050
21186
  process.exit(1);
21051
21187
  }
21052
21188
  const rootPath = pins.roots[rootKey].rootPath;
21053
- removePin(rootKey);
21189
+ removePin2(rootKey);
21054
21190
  wipeSkillSessions();
21055
21191
  console.log(chalk25.green(`
21056
21192
  \u{1F513} Pin removed for ${chalk25.cyan(rootKey)}`));
@@ -21065,7 +21201,7 @@ function registerSkillPinCommand(program2) {
21065
21201
  return;
21066
21202
  }
21067
21203
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
21068
- clearAllPins();
21204
+ clearAllPins2();
21069
21205
  wipeSkillSessions();
21070
21206
  console.log(chalk25.green(`
21071
21207
  \u{1F513} Cleared ${count} skill pin(s).`));
@@ -21074,15 +21210,15 @@ function registerSkillPinCommand(program2) {
21074
21210
  }
21075
21211
 
21076
21212
  // src/cli/commands/decisions.ts
21077
- import fs42 from "fs";
21213
+ import fs43 from "fs";
21078
21214
  import os38 from "os";
21079
21215
  import path44 from "path";
21080
21216
  import chalk26 from "chalk";
21081
21217
  var DECISIONS_FILE2 = path44.join(os38.homedir(), ".node9", "decisions.json");
21082
21218
  function readDecisions() {
21083
21219
  try {
21084
- if (!fs42.existsSync(DECISIONS_FILE2)) return {};
21085
- const raw = fs42.readFileSync(DECISIONS_FILE2, "utf-8");
21220
+ if (!fs43.existsSync(DECISIONS_FILE2)) return {};
21221
+ const raw = fs43.readFileSync(DECISIONS_FILE2, "utf-8");
21086
21222
  const parsed = JSON.parse(raw);
21087
21223
  const out = {};
21088
21224
  for (const [k, v] of Object.entries(parsed)) {
@@ -21095,10 +21231,10 @@ function readDecisions() {
21095
21231
  }
21096
21232
  function writeDecisions(d) {
21097
21233
  const dir = path44.dirname(DECISIONS_FILE2);
21098
- if (!fs42.existsSync(dir)) fs42.mkdirSync(dir, { recursive: true });
21234
+ if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
21099
21235
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
21100
- fs42.writeFileSync(tmp, JSON.stringify(d, null, 2));
21101
- fs42.renameSync(tmp, DECISIONS_FILE2);
21236
+ fs43.writeFileSync(tmp, JSON.stringify(d, null, 2));
21237
+ fs43.renameSync(tmp, DECISIONS_FILE2);
21102
21238
  }
21103
21239
  function registerDecisionsCommand(program2) {
21104
21240
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -21155,7 +21291,7 @@ Persistent decisions (${entries.length})
21155
21291
 
21156
21292
  // src/cli/commands/dlp.ts
21157
21293
  import chalk27 from "chalk";
21158
- import fs43 from "fs";
21294
+ import fs44 from "fs";
21159
21295
  import path45 from "path";
21160
21296
  import os39 from "os";
21161
21297
  var AUDIT_LOG = path45.join(os39.homedir(), ".node9", "audit.log");
@@ -21166,7 +21302,7 @@ function stripAnsi(s) {
21166
21302
  }
21167
21303
  function loadResolved() {
21168
21304
  try {
21169
- const raw = JSON.parse(fs43.readFileSync(RESOLVED_FILE, "utf-8"));
21305
+ const raw = JSON.parse(fs44.readFileSync(RESOLVED_FILE, "utf-8"));
21170
21306
  return new Set(raw);
21171
21307
  } catch {
21172
21308
  return /* @__PURE__ */ new Set();
@@ -21174,13 +21310,13 @@ function loadResolved() {
21174
21310
  }
21175
21311
  function saveResolved(resolved) {
21176
21312
  try {
21177
- fs43.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21313
+ fs44.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21178
21314
  } catch {
21179
21315
  }
21180
21316
  }
21181
21317
  function loadDlpFindings() {
21182
- if (!fs43.existsSync(AUDIT_LOG)) return [];
21183
- return fs43.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
21318
+ if (!fs44.existsSync(AUDIT_LOG)) return [];
21319
+ return fs44.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
21184
21320
  if (!line.trim()) return [];
21185
21321
  try {
21186
21322
  const e = JSON.parse(line);
@@ -21279,13 +21415,13 @@ function registerDlpCommand(program2) {
21279
21415
  // src/cli/commands/mask.ts
21280
21416
  init_dlp();
21281
21417
  import chalk28 from "chalk";
21282
- import fs44 from "fs";
21418
+ import fs45 from "fs";
21283
21419
  import path46 from "path";
21284
21420
  import os40 from "os";
21285
21421
  function findJsonlFiles(dir) {
21286
21422
  const results = [];
21287
- if (!fs44.existsSync(dir)) return results;
21288
- for (const entry of fs44.readdirSync(dir, { withFileTypes: true })) {
21423
+ if (!fs45.existsSync(dir)) return results;
21424
+ for (const entry of fs45.readdirSync(dir, { withFileTypes: true })) {
21289
21425
  const full = path46.join(dir, entry.name);
21290
21426
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
21291
21427
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
@@ -21329,7 +21465,7 @@ function redactJson(obj) {
21329
21465
  function processFile(filePath, dryRun) {
21330
21466
  let raw;
21331
21467
  try {
21332
- raw = fs44.readFileSync(filePath, "utf-8");
21468
+ raw = fs45.readFileSync(filePath, "utf-8");
21333
21469
  } catch {
21334
21470
  return { redactedLines: 0, patterns: [] };
21335
21471
  }
@@ -21361,14 +21497,14 @@ function processFile(filePath, dryRun) {
21361
21497
  }
21362
21498
  }
21363
21499
  if (!dryRun && redactedLines > 0) {
21364
- fs44.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21500
+ fs45.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21365
21501
  }
21366
21502
  return { redactedLines, patterns };
21367
21503
  }
21368
21504
  function processJsonFile(filePath, dryRun) {
21369
21505
  let raw;
21370
21506
  try {
21371
- raw = fs44.readFileSync(filePath, "utf-8");
21507
+ raw = fs45.readFileSync(filePath, "utf-8");
21372
21508
  } catch {
21373
21509
  return { redactedLines: 0, patterns: [] };
21374
21510
  }
@@ -21381,14 +21517,14 @@ function processJsonFile(filePath, dryRun) {
21381
21517
  const { value, modified, found } = redactJson(parsed);
21382
21518
  if (!modified) return { redactedLines: 0, patterns: [] };
21383
21519
  if (!dryRun) {
21384
- fs44.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21520
+ fs45.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21385
21521
  }
21386
21522
  return { redactedLines: 1, patterns: found };
21387
21523
  }
21388
21524
  function findJsonFiles(dir) {
21389
21525
  const results = [];
21390
- if (!fs44.existsSync(dir)) return results;
21391
- for (const entry of fs44.readdirSync(dir, { withFileTypes: true })) {
21526
+ if (!fs45.existsSync(dir)) return results;
21527
+ for (const entry of fs45.readdirSync(dir, { withFileTypes: true })) {
21392
21528
  const full = path46.join(dir, entry.name);
21393
21529
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
21394
21530
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
@@ -21408,7 +21544,7 @@ function registerMaskCommand(program2) {
21408
21544
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
21409
21545
  const filtered = cutoff ? allFiles.filter((f) => {
21410
21546
  try {
21411
- return fs44.statSync(f.path).mtime >= cutoff;
21547
+ return fs45.statSync(f.path).mtime >= cutoff;
21412
21548
  } catch {
21413
21549
  return false;
21414
21550
  }
@@ -21464,20 +21600,20 @@ function registerMaskCommand(program2) {
21464
21600
  // src/cli.ts
21465
21601
  init_blast();
21466
21602
  var { version } = JSON.parse(
21467
- fs47.readFileSync(path49.join(__dirname, "../package.json"), "utf-8")
21603
+ fs48.readFileSync(path49.join(__dirname, "../package.json"), "utf-8")
21468
21604
  );
21469
21605
  var program = new Command();
21470
21606
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
21471
21607
  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
21608
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
21473
21609
  const credPath = path49.join(os43.homedir(), ".node9", "credentials.json");
21474
- if (!fs47.existsSync(path49.dirname(credPath)))
21475
- fs47.mkdirSync(path49.dirname(credPath), { recursive: true });
21610
+ if (!fs48.existsSync(path49.dirname(credPath)))
21611
+ fs48.mkdirSync(path49.dirname(credPath), { recursive: true });
21476
21612
  const profileName = options.profile || "default";
21477
21613
  let existingCreds = {};
21478
21614
  try {
21479
- if (fs47.existsSync(credPath)) {
21480
- const raw = JSON.parse(fs47.readFileSync(credPath, "utf-8"));
21615
+ if (fs48.existsSync(credPath)) {
21616
+ const raw = JSON.parse(fs48.readFileSync(credPath, "utf-8"));
21481
21617
  if (raw.apiKey) {
21482
21618
  existingCreds = {
21483
21619
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -21489,13 +21625,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21489
21625
  } catch {
21490
21626
  }
21491
21627
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
21492
- fs47.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21628
+ fs48.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21493
21629
  if (profileName === "default") {
21494
21630
  const configPath = path49.join(os43.homedir(), ".node9", "config.json");
21495
21631
  let config = {};
21496
21632
  try {
21497
- if (fs47.existsSync(configPath))
21498
- config = JSON.parse(fs47.readFileSync(configPath, "utf-8"));
21633
+ if (fs48.existsSync(configPath))
21634
+ config = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
21499
21635
  } catch {
21500
21636
  }
21501
21637
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -21510,9 +21646,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21510
21646
  approvers.cloud = false;
21511
21647
  }
21512
21648
  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 });
21649
+ if (!fs48.existsSync(path49.dirname(configPath)))
21650
+ fs48.mkdirSync(path49.dirname(configPath), { recursive: true });
21651
+ fs48.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
21516
21652
  }
21517
21653
  if (options.profile && profileName !== "default") {
21518
21654
  console.log(chalk30.green(`\u2705 Profile "${profileName}" saved`));
@@ -21650,14 +21786,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
21650
21786
  }
21651
21787
  if (options.purge) {
21652
21788
  const node9Dir = path49.join(os43.homedir(), ".node9");
21653
- if (fs47.existsSync(node9Dir)) {
21789
+ if (fs48.existsSync(node9Dir)) {
21654
21790
  const confirmed = await confirm2({
21655
21791
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
21656
21792
  default: false
21657
21793
  });
21658
21794
  if (confirmed) {
21659
- fs47.rmSync(node9Dir, { recursive: true });
21660
- if (fs47.existsSync(node9Dir)) {
21795
+ fs48.rmSync(node9Dir, { recursive: true });
21796
+ if (fs48.existsSync(node9Dir)) {
21661
21797
  console.error(
21662
21798
  chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
21663
21799
  );
@@ -21812,12 +21948,12 @@ Run "node9 addto claude" to register it as the statusLine.`
21812
21948
  if (subcommand === "debug") {
21813
21949
  const flagFile = path49.join(os43.homedir(), ".node9", "hud-debug");
21814
21950
  if (state === "on") {
21815
- fs47.mkdirSync(path49.dirname(flagFile), { recursive: true });
21816
- fs47.writeFileSync(flagFile, "");
21951
+ fs48.mkdirSync(path49.dirname(flagFile), { recursive: true });
21952
+ fs48.writeFileSync(flagFile, "");
21817
21953
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
21818
21954
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
21819
21955
  } else if (state === "off") {
21820
- if (fs47.existsSync(flagFile)) fs47.unlinkSync(flagFile);
21956
+ if (fs48.existsSync(flagFile)) fs48.unlinkSync(flagFile);
21821
21957
  console.log("HUD debug logging disabled.");
21822
21958
  } else {
21823
21959
  console.error("Usage: node9 hud debug on|off");
@@ -21933,7 +22069,7 @@ if (process.argv[2] !== "daemon") {
21933
22069
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
21934
22070
  const logPath = path49.join(os43.homedir(), ".node9", "hook-debug.log");
21935
22071
  const msg = reason instanceof Error ? reason.message : String(reason);
21936
- fs47.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
22072
+ fs48.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
21937
22073
  `);
21938
22074
  }
21939
22075
  process.exit(0);