@node9/proxy 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6305,6 +6305,164 @@ var init_core = __esm({
6305
6305
  }
6306
6306
  });
6307
6307
 
6308
+ // src/mcp-pin.ts
6309
+ function getHomePinsFilePath() {
6310
+ return import_path14.default.join(import_os11.default.homedir(), ".node9", "mcp-pins.json");
6311
+ }
6312
+ function getPinsFilePath() {
6313
+ return getHomePinsFilePath();
6314
+ }
6315
+ function findPinsFilePath(cwd) {
6316
+ const homeDir2 = import_os11.default.homedir();
6317
+ const homePath = getHomePinsFilePath();
6318
+ let current = import_path14.default.resolve(cwd ?? process.cwd());
6319
+ while (true) {
6320
+ if (current === homeDir2) break;
6321
+ const candidate = import_path14.default.join(current, ".node9", "mcp-pins.json");
6322
+ if (import_fs12.default.existsSync(candidate)) {
6323
+ return { path: candidate, source: "repo" };
6324
+ }
6325
+ const next = import_path14.default.dirname(current);
6326
+ if (next === current) break;
6327
+ current = next;
6328
+ }
6329
+ return { path: homePath, source: "home" };
6330
+ }
6331
+ function hashToolDefinitions(tools) {
6332
+ const sorted = [...tools].sort((a, b) => {
6333
+ const nameA = a.name ?? "";
6334
+ const nameB = b.name ?? "";
6335
+ return nameA.localeCompare(nameB);
6336
+ });
6337
+ const canonical = JSON.stringify(sorted);
6338
+ return import_crypto5.default.createHash("sha256").update(canonical).digest("hex");
6339
+ }
6340
+ function getServerKey(upstreamCommand) {
6341
+ return import_crypto5.default.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
6342
+ }
6343
+ function readPinsFile(filePath) {
6344
+ try {
6345
+ const raw = import_fs12.default.readFileSync(filePath, "utf-8");
6346
+ if (!raw.trim()) {
6347
+ return { ok: false, reason: "corrupt", detail: "empty file" };
6348
+ }
6349
+ const parsed = JSON.parse(raw);
6350
+ if (!parsed.servers || typeof parsed.servers !== "object" || Array.isArray(parsed.servers)) {
6351
+ return { ok: false, reason: "corrupt", detail: "invalid structure: missing servers object" };
6352
+ }
6353
+ return { ok: true, pins: { servers: parsed.servers } };
6354
+ } catch (err2) {
6355
+ if (err2.code === "ENOENT") {
6356
+ return { ok: false, reason: "missing" };
6357
+ }
6358
+ return { ok: false, reason: "corrupt", detail: String(err2) };
6359
+ }
6360
+ }
6361
+ function readMcpPinsSafe() {
6362
+ return readPinsFile(getHomePinsFilePath());
6363
+ }
6364
+ function readMcpPins() {
6365
+ const result = readMcpPinsSafe();
6366
+ if (result.ok) return result.pins;
6367
+ if (result.reason === "missing") return { servers: {} };
6368
+ throw new Error(`[node9] MCP pin file is corrupt: ${result.detail}`);
6369
+ }
6370
+ function writePinsFile(filePath, data) {
6371
+ import_fs12.default.mkdirSync(import_path14.default.dirname(filePath), { recursive: true });
6372
+ const tmp = `${filePath}.${import_crypto5.default.randomBytes(6).toString("hex")}.tmp`;
6373
+ const isHome = filePath === getHomePinsFilePath();
6374
+ import_fs12.default.writeFileSync(tmp, JSON.stringify(data, null, 2), isHome ? { mode: 384 } : {});
6375
+ import_fs12.default.renameSync(tmp, filePath);
6376
+ }
6377
+ function writeMcpPins(data) {
6378
+ writePinsFile(getHomePinsFilePath(), data);
6379
+ }
6380
+ function seedMcpPinsIfMissing() {
6381
+ const filePath = getPinsFilePath();
6382
+ if (import_fs12.default.existsSync(filePath)) return;
6383
+ writeMcpPins({ servers: {} });
6384
+ }
6385
+ function checkPin(serverKey, currentHash, cwd) {
6386
+ const found = findPinsFilePath(cwd);
6387
+ let repoEntry;
6388
+ if (found.source === "repo") {
6389
+ const repoResult = readPinsFile(found.path);
6390
+ if (!repoResult.ok) {
6391
+ return "corrupt";
6392
+ }
6393
+ repoEntry = repoResult.pins.servers[serverKey];
6394
+ }
6395
+ if (repoEntry) {
6396
+ return repoEntry.toolsHash === currentHash ? "match" : "mismatch";
6397
+ }
6398
+ const homeResult = readPinsFile(getHomePinsFilePath());
6399
+ if (!homeResult.ok) {
6400
+ if (homeResult.reason === "missing") return "new";
6401
+ return "corrupt";
6402
+ }
6403
+ const homeEntry = homeResult.pins.servers[serverKey];
6404
+ if (!homeEntry) return "new";
6405
+ return homeEntry.toolsHash === currentHash ? "match" : "mismatch";
6406
+ }
6407
+ function updatePin(serverKey, label, toolsHash, toolNames) {
6408
+ const pins = readMcpPins();
6409
+ pins.servers[serverKey] = {
6410
+ label,
6411
+ toolsHash,
6412
+ toolNames,
6413
+ toolCount: toolNames.length,
6414
+ pinnedAt: (/* @__PURE__ */ new Date()).toISOString()
6415
+ };
6416
+ writeMcpPins(pins);
6417
+ }
6418
+ function removePin(serverKey) {
6419
+ const pins = readMcpPins();
6420
+ delete pins.servers[serverKey];
6421
+ writeMcpPins(pins);
6422
+ }
6423
+ function clearAllPins() {
6424
+ writeMcpPins({ servers: {} });
6425
+ }
6426
+ function promotePin(serverKey, cwd) {
6427
+ const homePins = readMcpPins();
6428
+ const homeEntry = homePins.servers[serverKey];
6429
+ if (!homeEntry) {
6430
+ throw new Error(
6431
+ `[node9] Server "${serverKey}" is not pinned in ~/.node9/mcp-pins.json. Run \`node9 mcp pin list\` to see what's pinned.`
6432
+ );
6433
+ }
6434
+ const found = findPinsFilePath(cwd);
6435
+ let repoPath;
6436
+ let repoPins;
6437
+ let created = false;
6438
+ if (found.source === "repo") {
6439
+ repoPath = found.path;
6440
+ const result = readPinsFile(repoPath);
6441
+ if (!result.ok) {
6442
+ const detail = result.reason === "corrupt" ? result.detail : "missing";
6443
+ throw new Error(`[node9] Repo pin file at ${repoPath} is unreadable: ${detail}`);
6444
+ }
6445
+ repoPins = result.pins;
6446
+ } else {
6447
+ repoPath = import_path14.default.join(cwd ?? process.cwd(), ".node9", "mcp-pins.json");
6448
+ repoPins = { servers: {} };
6449
+ created = true;
6450
+ }
6451
+ repoPins.servers[serverKey] = { ...homeEntry };
6452
+ writePinsFile(repoPath, repoPins);
6453
+ return { repoPath, created };
6454
+ }
6455
+ var import_fs12, import_path14, import_os11, import_crypto5;
6456
+ var init_mcp_pin = __esm({
6457
+ "src/mcp-pin.ts"() {
6458
+ "use strict";
6459
+ import_fs12 = __toESM(require("fs"));
6460
+ import_path14 = __toESM(require("path"));
6461
+ import_os11 = __toESM(require("os"));
6462
+ import_crypto5 = __toESM(require("crypto"));
6463
+ }
6464
+ });
6465
+
6308
6466
  // src/setup.ts
6309
6467
  function hasNode9McpServer(servers) {
6310
6468
  const entry = servers["node9"];
@@ -6330,32 +6488,32 @@ function isStaleHookCommand(command) {
6330
6488
  const tokens = command.split(/\s+/);
6331
6489
  for (const tok of tokens) {
6332
6490
  if (!tok.startsWith("/")) continue;
6333
- if (!import_fs12.default.existsSync(tok)) return true;
6491
+ if (!import_fs13.default.existsSync(tok)) return true;
6334
6492
  }
6335
6493
  return false;
6336
6494
  }
6337
6495
  function readJson(filePath) {
6338
6496
  try {
6339
- if (import_fs12.default.existsSync(filePath)) {
6340
- return JSON.parse(import_fs12.default.readFileSync(filePath, "utf-8"));
6497
+ if (import_fs13.default.existsSync(filePath)) {
6498
+ return JSON.parse(import_fs13.default.readFileSync(filePath, "utf-8"));
6341
6499
  }
6342
6500
  } catch {
6343
6501
  }
6344
6502
  return null;
6345
6503
  }
6346
6504
  function writeJson(filePath, data) {
6347
- const dir = import_path14.default.dirname(filePath);
6348
- if (!import_fs12.default.existsSync(dir)) import_fs12.default.mkdirSync(dir, { recursive: true });
6349
- import_fs12.default.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
6505
+ const dir = import_path15.default.dirname(filePath);
6506
+ if (!import_fs13.default.existsSync(dir)) import_fs13.default.mkdirSync(dir, { recursive: true });
6507
+ import_fs13.default.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
6350
6508
  }
6351
6509
  function isNode9Hook(cmd) {
6352
6510
  if (!cmd) return false;
6353
6511
  return /(?:^|[\s/\\])node9 (?:check|log)/.test(cmd) || /(?:^|[\s/\\])cli\.js (?:check|log)/.test(cmd);
6354
6512
  }
6355
6513
  function teardownClaude() {
6356
- const homeDir2 = import_os11.default.homedir();
6357
- const hooksPath = import_path14.default.join(homeDir2, ".claude", "settings.json");
6358
- const mcpPath = import_path14.default.join(homeDir2, ".claude", ".mcp.json");
6514
+ const homeDir2 = import_os12.default.homedir();
6515
+ const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
6516
+ const mcpPath = import_path15.default.join(homeDir2, ".claude", ".mcp.json");
6359
6517
  let changed = false;
6360
6518
  const settings = readJson(hooksPath);
6361
6519
  if (settings?.hooks) {
@@ -6403,8 +6561,8 @@ function teardownClaude() {
6403
6561
  }
6404
6562
  }
6405
6563
  function teardownGemini() {
6406
- const homeDir2 = import_os11.default.homedir();
6407
- const settingsPath = import_path14.default.join(homeDir2, ".gemini", "settings.json");
6564
+ const homeDir2 = import_os12.default.homedir();
6565
+ const settingsPath = import_path15.default.join(homeDir2, ".gemini", "settings.json");
6408
6566
  const settings = readJson(settingsPath);
6409
6567
  if (!settings) {
6410
6568
  console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.gemini/settings.json not found \u2014 nothing to remove"));
@@ -6447,8 +6605,8 @@ function teardownGemini() {
6447
6605
  }
6448
6606
  }
6449
6607
  function teardownCursor() {
6450
- const homeDir2 = import_os11.default.homedir();
6451
- const mcpPath = import_path14.default.join(homeDir2, ".cursor", "mcp.json");
6608
+ const homeDir2 = import_os12.default.homedir();
6609
+ const mcpPath = import_path15.default.join(homeDir2, ".cursor", "mcp.json");
6452
6610
  const mcpConfig = readJson(mcpPath);
6453
6611
  if (!mcpConfig?.mcpServers) {
6454
6612
  console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.cursor/mcp.json not found \u2014 nothing to remove"));
@@ -6479,9 +6637,10 @@ function teardownCursor() {
6479
6637
  }
6480
6638
  }
6481
6639
  async function setupClaude() {
6482
- const homeDir2 = import_os11.default.homedir();
6483
- const mcpPath = import_path14.default.join(homeDir2, ".claude", ".mcp.json");
6484
- const hooksPath = import_path14.default.join(homeDir2, ".claude", "settings.json");
6640
+ seedMcpPinsIfMissing();
6641
+ const homeDir2 = import_os12.default.homedir();
6642
+ const mcpPath = import_path15.default.join(homeDir2, ".claude", ".mcp.json");
6643
+ const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
6485
6644
  const claudeConfig = readJson(mcpPath) ?? {};
6486
6645
  const settings = readJson(hooksPath) ?? {};
6487
6646
  const servers = claudeConfig.mcpServers ?? {};
@@ -6631,8 +6790,9 @@ async function setupClaude() {
6631
6790
  }
6632
6791
  }
6633
6792
  async function setupGemini() {
6634
- const homeDir2 = import_os11.default.homedir();
6635
- const settingsPath = import_path14.default.join(homeDir2, ".gemini", "settings.json");
6793
+ seedMcpPinsIfMissing();
6794
+ const homeDir2 = import_os12.default.homedir();
6795
+ const settingsPath = import_path15.default.join(homeDir2, ".gemini", "settings.json");
6636
6796
  const settings = readJson(settingsPath) ?? {};
6637
6797
  const servers = settings.mcpServers ?? {};
6638
6798
  let hooksChanged = false;
@@ -6727,9 +6887,9 @@ async function setupGemini() {
6727
6887
  printDaemonTip();
6728
6888
  }
6729
6889
  }
6730
- function claudeDesktopConfigPath(homeDir2 = import_os11.default.homedir()) {
6890
+ function claudeDesktopConfigPath(homeDir2 = import_os12.default.homedir()) {
6731
6891
  if (process.platform === "darwin") {
6732
- return import_path14.default.join(
6892
+ return import_path15.default.join(
6733
6893
  homeDir2,
6734
6894
  "Library",
6735
6895
  "Application Support",
@@ -6738,18 +6898,18 @@ function claudeDesktopConfigPath(homeDir2 = import_os11.default.homedir()) {
6738
6898
  );
6739
6899
  }
6740
6900
  if (process.platform === "linux") {
6741
- return import_path14.default.join(homeDir2, ".config", "Claude", "claude_desktop_config.json");
6901
+ return import_path15.default.join(homeDir2, ".config", "Claude", "claude_desktop_config.json");
6742
6902
  }
6743
6903
  if (process.platform === "win32") {
6744
- const appData = process.env.APPDATA ?? import_path14.default.join(homeDir2, "AppData", "Roaming");
6745
- return import_path14.default.join(appData, "Claude", "claude_desktop_config.json");
6904
+ const appData = process.env.APPDATA ?? import_path15.default.join(homeDir2, "AppData", "Roaming");
6905
+ return import_path15.default.join(appData, "Claude", "claude_desktop_config.json");
6746
6906
  }
6747
6907
  return null;
6748
6908
  }
6749
- function detectAgents(homeDir2 = import_os11.default.homedir()) {
6909
+ function detectAgents(homeDir2 = import_os12.default.homedir()) {
6750
6910
  const exists = (p) => {
6751
6911
  try {
6752
- return import_fs12.default.existsSync(p);
6912
+ return import_fs13.default.existsSync(p);
6753
6913
  } catch (err2) {
6754
6914
  const code = err2.code;
6755
6915
  if (code !== "ENOENT") {
@@ -6761,18 +6921,19 @@ function detectAgents(homeDir2 = import_os11.default.homedir()) {
6761
6921
  };
6762
6922
  const desktopPath = claudeDesktopConfigPath(homeDir2);
6763
6923
  return {
6764
- claude: exists(import_path14.default.join(homeDir2, ".claude")) || exists(import_path14.default.join(homeDir2, ".claude.json")),
6765
- gemini: exists(import_path14.default.join(homeDir2, ".gemini")),
6766
- cursor: exists(import_path14.default.join(homeDir2, ".cursor")),
6767
- codex: exists(import_path14.default.join(homeDir2, ".codex")),
6768
- windsurf: exists(import_path14.default.join(homeDir2, ".codeium", "windsurf")),
6769
- vscode: exists(import_path14.default.join(homeDir2, ".vscode")),
6770
- claudeDesktop: desktopPath !== null && exists(import_path14.default.dirname(desktopPath))
6924
+ claude: exists(import_path15.default.join(homeDir2, ".claude")) || exists(import_path15.default.join(homeDir2, ".claude.json")),
6925
+ gemini: exists(import_path15.default.join(homeDir2, ".gemini")),
6926
+ cursor: exists(import_path15.default.join(homeDir2, ".cursor")),
6927
+ codex: exists(import_path15.default.join(homeDir2, ".codex")),
6928
+ windsurf: exists(import_path15.default.join(homeDir2, ".codeium", "windsurf")),
6929
+ vscode: exists(import_path15.default.join(homeDir2, ".vscode")),
6930
+ claudeDesktop: desktopPath !== null && exists(import_path15.default.dirname(desktopPath))
6771
6931
  };
6772
6932
  }
6773
6933
  async function setupCursor() {
6774
- const homeDir2 = import_os11.default.homedir();
6775
- const mcpPath = import_path14.default.join(homeDir2, ".cursor", "mcp.json");
6934
+ seedMcpPinsIfMissing();
6935
+ const homeDir2 = import_os12.default.homedir();
6936
+ const mcpPath = import_path15.default.join(homeDir2, ".cursor", "mcp.json");
6776
6937
  const mcpConfig = readJson(mcpPath) ?? {};
6777
6938
  const servers = mcpConfig.mcpServers ?? {};
6778
6939
  let anythingChanged = false;
@@ -6838,22 +6999,23 @@ async function setupCursor() {
6838
6999
  }
6839
7000
  function readToml(filePath) {
6840
7001
  try {
6841
- if (import_fs12.default.existsSync(filePath)) {
6842
- return (0, import_smol_toml.parse)(import_fs12.default.readFileSync(filePath, "utf-8"));
7002
+ if (import_fs13.default.existsSync(filePath)) {
7003
+ return (0, import_smol_toml.parse)(import_fs13.default.readFileSync(filePath, "utf-8"));
6843
7004
  }
6844
7005
  } catch {
6845
7006
  }
6846
7007
  return null;
6847
7008
  }
6848
7009
  function writeToml(filePath, data) {
6849
- const dir = import_path14.default.dirname(filePath);
6850
- if (!import_fs12.default.existsSync(dir)) import_fs12.default.mkdirSync(dir, { recursive: true });
6851
- import_fs12.default.writeFileSync(filePath, (0, import_smol_toml.stringify)(data));
7010
+ const dir = import_path15.default.dirname(filePath);
7011
+ if (!import_fs13.default.existsSync(dir)) import_fs13.default.mkdirSync(dir, { recursive: true });
7012
+ import_fs13.default.writeFileSync(filePath, (0, import_smol_toml.stringify)(data));
6852
7013
  }
6853
7014
  async function setupCodex() {
6854
- const homeDir2 = import_os11.default.homedir();
6855
- const configPath = import_path14.default.join(homeDir2, ".codex", "config.toml");
6856
- const hooksPath = import_path14.default.join(homeDir2, ".codex", "hooks.json");
7015
+ seedMcpPinsIfMissing();
7016
+ const homeDir2 = import_os12.default.homedir();
7017
+ const configPath = import_path15.default.join(homeDir2, ".codex", "config.toml");
7018
+ const hooksPath = import_path15.default.join(homeDir2, ".codex", "hooks.json");
6857
7019
  const config = readToml(configPath) ?? {};
6858
7020
  const servers = config.mcp_servers ?? {};
6859
7021
  let anythingChanged = false;
@@ -7003,9 +7165,9 @@ async function setupCodex() {
7003
7165
  }
7004
7166
  }
7005
7167
  function teardownCodex() {
7006
- const homeDir2 = import_os11.default.homedir();
7007
- const configPath = import_path14.default.join(homeDir2, ".codex", "config.toml");
7008
- const hooksPath = import_path14.default.join(homeDir2, ".codex", "hooks.json");
7168
+ const homeDir2 = import_os12.default.homedir();
7169
+ const configPath = import_path15.default.join(homeDir2, ".codex", "config.toml");
7170
+ const hooksPath = import_path15.default.join(homeDir2, ".codex", "hooks.json");
7009
7171
  const hooksFile = readJson(hooksPath);
7010
7172
  if (hooksFile?.hooks) {
7011
7173
  let hooksChanged = false;
@@ -7052,8 +7214,8 @@ function teardownCodex() {
7052
7214
  }
7053
7215
  }
7054
7216
  function setupHud() {
7055
- const homeDir2 = import_os11.default.homedir();
7056
- const hooksPath = import_path14.default.join(homeDir2, ".claude", "settings.json");
7217
+ const homeDir2 = import_os12.default.homedir();
7218
+ const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
7057
7219
  const settings = readJson(hooksPath) ?? {};
7058
7220
  const hudCommand = fullPathCommand("hud");
7059
7221
  const statusLineObj = { type: "command", command: hudCommand };
@@ -7079,8 +7241,8 @@ function setupHud() {
7079
7241
  console.log(import_chalk.default.gray(" Restart Claude Code to activate."));
7080
7242
  }
7081
7243
  function teardownHud() {
7082
- const homeDir2 = import_os11.default.homedir();
7083
- const hooksPath = import_path14.default.join(homeDir2, ".claude", "settings.json");
7244
+ const homeDir2 = import_os12.default.homedir();
7245
+ const hooksPath = import_path15.default.join(homeDir2, ".claude", "settings.json");
7084
7246
  const settings = readJson(hooksPath);
7085
7247
  if (!settings) {
7086
7248
  console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.claude/settings.json not found \u2014 nothing to remove"));
@@ -7098,8 +7260,9 @@ function teardownHud() {
7098
7260
  console.log(import_chalk.default.gray(" Restart Claude Code for changes to take effect."));
7099
7261
  }
7100
7262
  async function setupWindsurf() {
7101
- const homeDir2 = import_os11.default.homedir();
7102
- const mcpPath = import_path14.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7263
+ seedMcpPinsIfMissing();
7264
+ const homeDir2 = import_os12.default.homedir();
7265
+ const mcpPath = import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7103
7266
  const mcpConfig = readJson(mcpPath) ?? {};
7104
7267
  const servers = mcpConfig.mcpServers ?? {};
7105
7268
  let anythingChanged = false;
@@ -7159,8 +7322,8 @@ async function setupWindsurf() {
7159
7322
  }
7160
7323
  }
7161
7324
  function teardownWindsurf() {
7162
- const homeDir2 = import_os11.default.homedir();
7163
- const mcpPath = import_path14.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7325
+ const homeDir2 = import_os12.default.homedir();
7326
+ const mcpPath = import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json");
7164
7327
  const mcpConfig = readJson(mcpPath);
7165
7328
  if (!mcpConfig?.mcpServers) {
7166
7329
  console.log(
@@ -7201,8 +7364,9 @@ function hasNode9McpServerVSCode(servers) {
7201
7364
  return !!entry && entry.command === "node9" && Array.isArray(entry.args) && entry.args[0] === "mcp-server";
7202
7365
  }
7203
7366
  async function setupVSCode() {
7204
- const homeDir2 = import_os11.default.homedir();
7205
- const mcpPath = import_path14.default.join(homeDir2, ".vscode", "mcp.json");
7367
+ seedMcpPinsIfMissing();
7368
+ const homeDir2 = import_os12.default.homedir();
7369
+ const mcpPath = import_path15.default.join(homeDir2, ".vscode", "mcp.json");
7206
7370
  const mcpConfig = readJson(mcpPath) ?? {};
7207
7371
  const servers = mcpConfig.servers ?? {};
7208
7372
  let anythingChanged = false;
@@ -7263,8 +7427,8 @@ async function setupVSCode() {
7263
7427
  }
7264
7428
  }
7265
7429
  function teardownVSCode() {
7266
- const homeDir2 = import_os11.default.homedir();
7267
- const mcpPath = import_path14.default.join(homeDir2, ".vscode", "mcp.json");
7430
+ const homeDir2 = import_os12.default.homedir();
7431
+ const mcpPath = import_path15.default.join(homeDir2, ".vscode", "mcp.json");
7268
7432
  const mcpConfig = readJson(mcpPath);
7269
7433
  if (!mcpConfig?.servers) {
7270
7434
  console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.vscode/mcp.json not found \u2014 nothing to remove"));
@@ -7297,6 +7461,7 @@ function teardownVSCode() {
7297
7461
  }
7298
7462
  }
7299
7463
  async function setupClaudeDesktop() {
7464
+ seedMcpPinsIfMissing();
7300
7465
  const configPath = claudeDesktopConfigPath();
7301
7466
  if (!configPath) {
7302
7467
  console.log(import_chalk.default.yellow(" \u26A0\uFE0F Claude Desktop is not supported on this platform."));
@@ -7395,32 +7560,32 @@ function teardownClaudeDesktop() {
7395
7560
  console.log(import_chalk.default.blue(" \u2139\uFE0F No Node9-wrapped MCP servers found in Claude Desktop config"));
7396
7561
  }
7397
7562
  }
7398
- function getAgentsStatus(homeDir2 = import_os11.default.homedir()) {
7563
+ function getAgentsStatus(homeDir2 = import_os12.default.homedir()) {
7399
7564
  const detected = detectAgents(homeDir2);
7400
7565
  const claudeWired = (() => {
7401
- const settings = readJson(import_path14.default.join(homeDir2, ".claude", "settings.json"));
7566
+ const settings = readJson(import_path15.default.join(homeDir2, ".claude", "settings.json"));
7402
7567
  return !!settings?.hooks?.PreToolUse?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
7403
7568
  })();
7404
7569
  const geminiWired = (() => {
7405
- const settings = readJson(import_path14.default.join(homeDir2, ".gemini", "settings.json"));
7570
+ const settings = readJson(import_path15.default.join(homeDir2, ".gemini", "settings.json"));
7406
7571
  return !!settings?.hooks?.BeforeTool?.some((m) => m.hooks.some((h) => isNode9Hook(h.command)));
7407
7572
  })();
7408
7573
  const cursorWired = (() => {
7409
- const cfg = readJson(import_path14.default.join(homeDir2, ".cursor", "mcp.json"));
7574
+ const cfg = readJson(import_path15.default.join(homeDir2, ".cursor", "mcp.json"));
7410
7575
  return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
7411
7576
  })();
7412
7577
  const codexWired = (() => {
7413
- const cfg = readToml(import_path14.default.join(homeDir2, ".codex", "config.toml"));
7578
+ const cfg = readToml(import_path15.default.join(homeDir2, ".codex", "config.toml"));
7414
7579
  return !!(cfg?.mcp_servers && hasNode9McpServer(cfg.mcp_servers));
7415
7580
  })();
7416
7581
  const windsurfWired = (() => {
7417
7582
  const cfg = readJson(
7418
- import_path14.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json")
7583
+ import_path15.default.join(homeDir2, ".codeium", "windsurf", "mcp_config.json")
7419
7584
  );
7420
7585
  return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
7421
7586
  })();
7422
7587
  const vscodeWired = (() => {
7423
- const cfg = readJson(import_path14.default.join(homeDir2, ".vscode", "mcp.json"));
7588
+ const cfg = readJson(import_path15.default.join(homeDir2, ".vscode", "mcp.json"));
7424
7589
  return !!(cfg?.servers && hasNode9McpServerVSCode(cfg.servers));
7425
7590
  })();
7426
7591
  return [
@@ -7480,16 +7645,17 @@ function getAgentsStatus(homeDir2 = import_os11.default.homedir()) {
7480
7645
  }
7481
7646
  ];
7482
7647
  }
7483
- var import_fs12, import_path14, import_os11, import_chalk, import_prompts, import_smol_toml, NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS;
7648
+ var import_fs13, import_path15, import_os12, import_chalk, import_prompts, import_smol_toml, NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS;
7484
7649
  var init_setup = __esm({
7485
7650
  "src/setup.ts"() {
7486
7651
  "use strict";
7487
- import_fs12 = __toESM(require("fs"));
7488
- import_path14 = __toESM(require("path"));
7489
- import_os11 = __toESM(require("os"));
7652
+ import_fs13 = __toESM(require("fs"));
7653
+ import_path15 = __toESM(require("path"));
7654
+ import_os12 = __toESM(require("os"));
7490
7655
  import_chalk = __toESM(require("chalk"));
7491
7656
  import_prompts = require("@inquirer/prompts");
7492
7657
  import_smol_toml = require("smol-toml");
7658
+ init_mcp_pin();
7493
7659
  NODE9_MCP_SERVER_ENTRY = { command: "node9", args: ["mcp-server"] };
7494
7660
  CODEX_PRE_TOOL_MATCHERS = ["^Bash$", "^apply_patch$", "^mcp__.*"];
7495
7661
  }
@@ -7685,79 +7851,79 @@ var init_scan_summary = __esm({
7685
7851
  function buildSensitivePaths(home, cwd) {
7686
7852
  return [
7687
7853
  {
7688
- full: import_path15.default.join(home, ".ssh", "id_rsa"),
7854
+ full: import_path16.default.join(home, ".ssh", "id_rsa"),
7689
7855
  label: "~/.ssh/id_rsa",
7690
7856
  description: "RSA private key \u2014 grants SSH access to your servers",
7691
7857
  score: 20
7692
7858
  },
7693
7859
  {
7694
- full: import_path15.default.join(home, ".ssh", "id_ed25519"),
7860
+ full: import_path16.default.join(home, ".ssh", "id_ed25519"),
7695
7861
  label: "~/.ssh/id_ed25519",
7696
7862
  description: "Ed25519 private key \u2014 grants SSH access to your servers",
7697
7863
  score: 20
7698
7864
  },
7699
7865
  {
7700
- full: import_path15.default.join(home, ".ssh", "id_ecdsa"),
7866
+ full: import_path16.default.join(home, ".ssh", "id_ecdsa"),
7701
7867
  label: "~/.ssh/id_ecdsa",
7702
7868
  description: "ECDSA private key \u2014 grants SSH access to your servers",
7703
7869
  score: 20
7704
7870
  },
7705
7871
  {
7706
- full: import_path15.default.join(home, ".aws", "credentials"),
7872
+ full: import_path16.default.join(home, ".aws", "credentials"),
7707
7873
  label: "~/.aws/credentials",
7708
7874
  description: "AWS access keys \u2014 full cloud account access",
7709
7875
  score: 20
7710
7876
  },
7711
7877
  {
7712
- full: import_path15.default.join(home, ".aws", "config"),
7878
+ full: import_path16.default.join(home, ".aws", "config"),
7713
7879
  label: "~/.aws/config",
7714
7880
  description: "AWS configuration \u2014 account and region settings",
7715
7881
  score: 5
7716
7882
  },
7717
7883
  {
7718
- full: import_path15.default.join(home, ".config", "gcloud", "credentials.db"),
7884
+ full: import_path16.default.join(home, ".config", "gcloud", "credentials.db"),
7719
7885
  label: "~/.config/gcloud/credentials.db",
7720
7886
  description: "Google Cloud credentials",
7721
7887
  score: 15
7722
7888
  },
7723
7889
  {
7724
- full: import_path15.default.join(home, ".docker", "config.json"),
7890
+ full: import_path16.default.join(home, ".docker", "config.json"),
7725
7891
  label: "~/.docker/config.json",
7726
7892
  description: "Docker registry auth tokens",
7727
7893
  score: 10
7728
7894
  },
7729
7895
  {
7730
- full: import_path15.default.join(home, ".netrc"),
7896
+ full: import_path16.default.join(home, ".netrc"),
7731
7897
  label: "~/.netrc",
7732
7898
  description: "FTP/HTTP credentials in plain text",
7733
7899
  score: 15
7734
7900
  },
7735
7901
  {
7736
- full: import_path15.default.join(home, ".npmrc"),
7902
+ full: import_path16.default.join(home, ".npmrc"),
7737
7903
  label: "~/.npmrc",
7738
7904
  description: "npm auth token \u2014 can publish packages as you",
7739
7905
  score: 10
7740
7906
  },
7741
7907
  {
7742
- full: import_path15.default.join(home, ".node9", "credentials.json"),
7908
+ full: import_path16.default.join(home, ".node9", "credentials.json"),
7743
7909
  label: "~/.node9/credentials.json",
7744
7910
  description: "Node9 cloud API key",
7745
7911
  score: 10
7746
7912
  },
7747
7913
  {
7748
- full: import_path15.default.join(cwd, ".env"),
7914
+ full: import_path16.default.join(cwd, ".env"),
7749
7915
  label: ".env (current folder)",
7750
7916
  description: "App secrets \u2014 database passwords, API keys",
7751
7917
  score: 20
7752
7918
  },
7753
7919
  {
7754
- full: import_path15.default.join(cwd, ".env.local"),
7920
+ full: import_path16.default.join(cwd, ".env.local"),
7755
7921
  label: ".env.local (current folder)",
7756
7922
  description: "Local overrides \u2014 often contains real credentials",
7757
7923
  score: 15
7758
7924
  },
7759
7925
  {
7760
- full: import_path15.default.join(cwd, ".env.production"),
7926
+ full: import_path16.default.join(cwd, ".env.production"),
7761
7927
  label: ".env.production (current folder)",
7762
7928
  description: "Production secrets",
7763
7929
  score: 20
@@ -7766,7 +7932,7 @@ function buildSensitivePaths(home, cwd) {
7766
7932
  }
7767
7933
  function isReadable(filePath) {
7768
7934
  try {
7769
- import_fs13.default.accessSync(filePath, import_fs13.default.constants.R_OK);
7935
+ import_fs14.default.accessSync(filePath, import_fs14.default.constants.R_OK);
7770
7936
  return true;
7771
7937
  } catch {
7772
7938
  return false;
@@ -7779,13 +7945,13 @@ function scoreLabel(score) {
7779
7945
  return import_chalk2.default.red.bold(`${score}/100 Critical`);
7780
7946
  }
7781
7947
  function runBlast() {
7782
- const home = import_os12.default.homedir();
7948
+ const home = import_os13.default.homedir();
7783
7949
  const cwd = process.cwd();
7784
7950
  const paths = buildSensitivePaths(home, cwd);
7785
7951
  let scoreDeduction = 0;
7786
7952
  const reachable = [];
7787
7953
  for (const p of paths) {
7788
- if (import_fs13.default.existsSync(p.full) && isReadable(p.full)) {
7954
+ if (import_fs14.default.existsSync(p.full) && isReadable(p.full)) {
7789
7955
  reachable.push(p);
7790
7956
  scoreDeduction += p.score;
7791
7957
  }
@@ -7803,7 +7969,7 @@ function runBlast() {
7803
7969
  }
7804
7970
  function registerBlastCommand(program2) {
7805
7971
  program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
7806
- const home = import_os12.default.homedir();
7972
+ const home = import_os13.default.homedir();
7807
7973
  const cwd = process.cwd();
7808
7974
  const { reachable, envFindings, score } = runBlast();
7809
7975
  console.log("");
@@ -7850,14 +8016,14 @@ function registerBlastCommand(program2) {
7850
8016
  console.log("");
7851
8017
  });
7852
8018
  }
7853
- var import_chalk2, import_fs13, import_path15, import_os12;
8019
+ var import_chalk2, import_fs14, import_path16, import_os13;
7854
8020
  var init_blast = __esm({
7855
8021
  "src/cli/commands/blast.ts"() {
7856
8022
  "use strict";
7857
8023
  import_chalk2 = __toESM(require("chalk"));
7858
- import_fs13 = __toESM(require("fs"));
7859
- import_path15 = __toESM(require("path"));
7860
- import_os12 = __toESM(require("os"));
8024
+ import_fs14 = __toESM(require("fs"));
8025
+ import_path16 = __toESM(require("path"));
8026
+ import_os13 = __toESM(require("os"));
7861
8027
  init_dlp();
7862
8028
  }
7863
8029
  });
@@ -7985,13 +8151,13 @@ var init_scan_json = __esm({
7985
8151
 
7986
8152
  // src/cli/render/scan-history.ts
7987
8153
  function defaultHistoryPath() {
7988
- return import_path16.default.join(import_os13.default.homedir(), ".node9", "scan-history.json");
8154
+ return import_path17.default.join(import_os14.default.homedir(), ".node9", "scan-history.json");
7989
8155
  }
7990
8156
  function readPreviousScan(opts = {}) {
7991
8157
  const filePath = opts.path ?? defaultHistoryPath();
7992
8158
  try {
7993
- if (!import_fs14.default.existsSync(filePath)) return null;
7994
- const raw = import_fs14.default.readFileSync(filePath, "utf8");
8159
+ if (!import_fs15.default.existsSync(filePath)) return null;
8160
+ const raw = import_fs15.default.readFileSync(filePath, "utf8");
7995
8161
  const parsed = JSON.parse(raw);
7996
8162
  if (!Array.isArray(parsed) || parsed.length === 0) return null;
7997
8163
  const last = parsed[parsed.length - 1];
@@ -8005,11 +8171,11 @@ function appendScanHistory(record, opts = {}) {
8005
8171
  const filePath = opts.path ?? defaultHistoryPath();
8006
8172
  const cap = opts.cap ?? SCAN_HISTORY_CAP;
8007
8173
  try {
8008
- import_fs14.default.mkdirSync(import_path16.default.dirname(filePath), { recursive: true });
8174
+ import_fs15.default.mkdirSync(import_path17.default.dirname(filePath), { recursive: true });
8009
8175
  let history = [];
8010
- if (import_fs14.default.existsSync(filePath)) {
8176
+ if (import_fs15.default.existsSync(filePath)) {
8011
8177
  try {
8012
- const parsed = JSON.parse(import_fs14.default.readFileSync(filePath, "utf8"));
8178
+ const parsed = JSON.parse(import_fs15.default.readFileSync(filePath, "utf8"));
8013
8179
  if (Array.isArray(parsed)) {
8014
8180
  history = parsed.filter(isValidRecord);
8015
8181
  }
@@ -8020,7 +8186,7 @@ function appendScanHistory(record, opts = {}) {
8020
8186
  if (history.length > cap) {
8021
8187
  history = history.slice(history.length - cap);
8022
8188
  }
8023
- import_fs14.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
8189
+ import_fs15.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
8024
8190
  } catch (err2) {
8025
8191
  process.stderr.write(
8026
8192
  `[node9] Warning: could not write scan-history.json: ${err2.message}
@@ -8042,13 +8208,13 @@ function isValidRecord(x) {
8042
8208
  const r = x;
8043
8209
  return typeof r.timestamp === "string" && typeof r.score === "number" && typeof r.blocked === "number" && typeof r.review === "number" && typeof r.leaks === "number" && typeof r.loops === "number" && typeof r.totalCalls === "number";
8044
8210
  }
8045
- var import_fs14, import_path16, import_os13, SCAN_HISTORY_CAP;
8211
+ var import_fs15, import_path17, import_os14, SCAN_HISTORY_CAP;
8046
8212
  var init_scan_history = __esm({
8047
8213
  "src/cli/render/scan-history.ts"() {
8048
8214
  "use strict";
8049
- import_fs14 = __toESM(require("fs"));
8050
- import_path16 = __toESM(require("path"));
8051
- import_os13 = __toESM(require("os"));
8215
+ import_fs15 = __toESM(require("fs"));
8216
+ import_path17 = __toESM(require("path"));
8217
+ import_os14 = __toESM(require("os"));
8052
8218
  SCAN_HISTORY_CAP = 30;
8053
8219
  }
8054
8220
  });
@@ -8059,7 +8225,7 @@ function normalizeModel(raw) {
8059
8225
  }
8060
8226
  function readCache() {
8061
8227
  try {
8062
- const raw = JSON.parse(import_fs15.default.readFileSync(CACHE_FILE(), "utf-8"));
8228
+ const raw = JSON.parse(import_fs16.default.readFileSync(CACHE_FILE(), "utf-8"));
8063
8229
  if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
8064
8230
  return null;
8065
8231
  }
@@ -8073,18 +8239,18 @@ function readCache() {
8073
8239
  function writeCache(prices) {
8074
8240
  try {
8075
8241
  const target = CACHE_FILE();
8076
- const dir = import_path17.default.dirname(target);
8077
- if (!import_fs15.default.existsSync(dir)) import_fs15.default.mkdirSync(dir, { recursive: true });
8242
+ const dir = import_path18.default.dirname(target);
8243
+ if (!import_fs16.default.existsSync(dir)) import_fs16.default.mkdirSync(dir, { recursive: true });
8078
8244
  const tmp = target + ".tmp";
8079
8245
  const body = {
8080
8246
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
8081
8247
  prices
8082
8248
  };
8083
- import_fs15.default.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
8084
- import_fs15.default.renameSync(tmp, target);
8249
+ import_fs16.default.writeFileSync(tmp, JSON.stringify(body) + "\n", "utf-8");
8250
+ import_fs16.default.renameSync(tmp, target);
8085
8251
  } catch (err2) {
8086
8252
  try {
8087
- import_fs15.default.appendFileSync(
8253
+ import_fs16.default.appendFileSync(
8088
8254
  HOOK_DEBUG_LOG,
8089
8255
  `[pricing] cache write failed: ${err2.message}
8090
8256
  `
@@ -8177,13 +8343,13 @@ function pricingFor(model) {
8177
8343
  lookupCache.set(norm, resolved);
8178
8344
  return resolved;
8179
8345
  }
8180
- var import_fs15, import_path17, import_os14, LITELLM_URL, BUNDLED_PRICING, CACHE_FILE, TTL_MS, memCache, memCacheAt, lookupCache;
8346
+ var import_fs16, import_path18, import_os15, LITELLM_URL, BUNDLED_PRICING, CACHE_FILE, TTL_MS, memCache, memCacheAt, lookupCache;
8181
8347
  var init_litellm = __esm({
8182
8348
  "src/pricing/litellm.ts"() {
8183
8349
  "use strict";
8184
- import_fs15 = __toESM(require("fs"));
8185
- import_path17 = __toESM(require("path"));
8186
- import_os14 = __toESM(require("os"));
8350
+ import_fs16 = __toESM(require("fs"));
8351
+ import_path18 = __toESM(require("path"));
8352
+ import_os15 = __toESM(require("os"));
8187
8353
  init_audit();
8188
8354
  LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
8189
8355
  BUNDLED_PRICING = {
@@ -8210,7 +8376,7 @@ var init_litellm = __esm({
8210
8376
  "gemini-2.0-flash": [75e-9, 3e-7, 0, 0],
8211
8377
  "gemini-1.5-pro": [125e-8, 5e-6, 0, 0]
8212
8378
  };
8213
- CACHE_FILE = () => import_path17.default.join(import_os14.default.homedir(), ".node9", "model-pricing.json");
8379
+ CACHE_FILE = () => import_path18.default.join(import_os15.default.homedir(), ".node9", "model-pricing.json");
8214
8380
  TTL_MS = 24 * 60 * 60 * 1e3;
8215
8381
  memCache = null;
8216
8382
  memCacheAt = 0;
@@ -8223,10 +8389,10 @@ function decodeProjectDirName(dirName) {
8223
8389
  return dirName.replace(/-/g, "/");
8224
8390
  }
8225
8391
  function parseJSONLFile(filePath, fallbackWorkingDir) {
8226
- const runId = import_path18.default.basename(filePath, ".jsonl");
8392
+ const runId = import_path19.default.basename(filePath, ".jsonl");
8227
8393
  let content;
8228
8394
  try {
8229
- content = import_fs16.default.readFileSync(filePath, "utf8");
8395
+ content = import_fs17.default.readFileSync(filePath, "utf8");
8230
8396
  } catch {
8231
8397
  return /* @__PURE__ */ new Map();
8232
8398
  }
@@ -8282,34 +8448,34 @@ function parseJSONLFile(filePath, fallbackWorkingDir) {
8282
8448
  return daily;
8283
8449
  }
8284
8450
  function collectEntries(sinceMs) {
8285
- const projectsDir = import_path18.default.join(import_os15.default.homedir(), ".claude", "projects");
8286
- if (!import_fs16.default.existsSync(projectsDir)) return [];
8451
+ const projectsDir = import_path19.default.join(import_os16.default.homedir(), ".claude", "projects");
8452
+ if (!import_fs17.default.existsSync(projectsDir)) return [];
8287
8453
  const combined = /* @__PURE__ */ new Map();
8288
8454
  let dirs;
8289
8455
  try {
8290
- dirs = import_fs16.default.readdirSync(projectsDir);
8456
+ dirs = import_fs17.default.readdirSync(projectsDir);
8291
8457
  } catch {
8292
8458
  return [];
8293
8459
  }
8294
8460
  for (const dir of dirs) {
8295
- const dirPath = import_path18.default.join(projectsDir, dir);
8461
+ const dirPath = import_path19.default.join(projectsDir, dir);
8296
8462
  try {
8297
- if (!import_fs16.default.statSync(dirPath).isDirectory()) continue;
8463
+ if (!import_fs17.default.statSync(dirPath).isDirectory()) continue;
8298
8464
  } catch {
8299
8465
  continue;
8300
8466
  }
8301
8467
  let files;
8302
8468
  try {
8303
- files = import_fs16.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8469
+ files = import_fs17.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8304
8470
  } catch {
8305
8471
  continue;
8306
8472
  }
8307
8473
  const fallbackWorkingDir = decodeProjectDirName(dir);
8308
8474
  for (const file of files) {
8309
- const filePath = import_path18.default.join(dirPath, file);
8475
+ const filePath = import_path19.default.join(dirPath, file);
8310
8476
  if (sinceMs !== void 0) {
8311
8477
  try {
8312
- if (import_fs16.default.statSync(filePath).mtimeMs < sinceMs) continue;
8478
+ if (import_fs17.default.statSync(filePath).mtimeMs < sinceMs) continue;
8313
8479
  } catch {
8314
8480
  continue;
8315
8481
  }
@@ -8339,10 +8505,10 @@ async function syncCost() {
8339
8505
  if (entries.length === 0) return;
8340
8506
  let username = "unknown";
8341
8507
  try {
8342
- username = import_os15.default.userInfo().username;
8508
+ username = import_os16.default.userInfo().username;
8343
8509
  } catch {
8344
8510
  }
8345
- const machineId = `${import_os15.default.hostname()}:${username}`;
8511
+ const machineId = `${import_os16.default.hostname()}:${username}`;
8346
8512
  try {
8347
8513
  const res = await fetch(`${creds.apiUrl}/cost-sync`, {
8348
8514
  method: "POST",
@@ -8351,11 +8517,11 @@ async function syncCost() {
8351
8517
  signal: AbortSignal.timeout(15e3)
8352
8518
  });
8353
8519
  if (!res.ok) {
8354
- import_fs16.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
8520
+ import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] HTTP ${res.status}
8355
8521
  `);
8356
8522
  }
8357
8523
  } catch (err2) {
8358
- import_fs16.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
8524
+ import_fs17.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2.message}
8359
8525
  `);
8360
8526
  }
8361
8527
  }
@@ -8368,13 +8534,13 @@ function startCostSync() {
8368
8534
  }, SYNC_INTERVAL_MS);
8369
8535
  timer.unref();
8370
8536
  }
8371
- var import_fs16, import_path18, import_os15, SYNC_INTERVAL_MS;
8537
+ var import_fs17, import_path19, import_os16, SYNC_INTERVAL_MS;
8372
8538
  var init_costSync = __esm({
8373
8539
  "src/costSync.ts"() {
8374
8540
  "use strict";
8375
- import_fs16 = __toESM(require("fs"));
8376
- import_path18 = __toESM(require("path"));
8377
- import_os15 = __toESM(require("os"));
8541
+ import_fs17 = __toESM(require("fs"));
8542
+ import_path19 = __toESM(require("path"));
8543
+ import_os16 = __toESM(require("os"));
8378
8544
  init_config();
8379
8545
  init_audit();
8380
8546
  init_litellm();
@@ -8405,7 +8571,7 @@ function freshWatermark() {
8405
8571
  function loadWatermark() {
8406
8572
  let raw;
8407
8573
  try {
8408
- raw = import_fs17.default.readFileSync(WATERMARK_FILE(), "utf-8");
8574
+ raw = import_fs18.default.readFileSync(WATERMARK_FILE(), "utf-8");
8409
8575
  } catch {
8410
8576
  return { status: "fresh", wm: freshWatermark() };
8411
8577
  }
@@ -8457,28 +8623,28 @@ function loadWatermark() {
8457
8623
  function saveWatermark(wm) {
8458
8624
  if (wm.schemaVersion > WATERMARK_SCHEMA_VERSION) return;
8459
8625
  const target = WATERMARK_FILE();
8460
- const dir = import_path19.default.dirname(target);
8461
- if (!import_fs17.default.existsSync(dir)) import_fs17.default.mkdirSync(dir, { recursive: true });
8626
+ const dir = import_path20.default.dirname(target);
8627
+ if (!import_fs18.default.existsSync(dir)) import_fs18.default.mkdirSync(dir, { recursive: true });
8462
8628
  const tmp = target + ".tmp";
8463
- import_fs17.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
8464
- import_fs17.default.renameSync(tmp, target);
8629
+ import_fs18.default.writeFileSync(tmp, JSON.stringify(wm, null, 2) + "\n", "utf-8");
8630
+ import_fs18.default.renameSync(tmp, target);
8465
8631
  }
8466
8632
  function listJsonlFiles() {
8467
8633
  const root = PROJECTS_DIR();
8468
- if (!import_fs17.default.existsSync(root)) return [];
8634
+ if (!import_fs18.default.existsSync(root)) return [];
8469
8635
  const out = [];
8470
- for (const entry of import_fs17.default.readdirSync(root, { withFileTypes: true })) {
8636
+ for (const entry of import_fs18.default.readdirSync(root, { withFileTypes: true })) {
8471
8637
  if (!entry.isDirectory()) continue;
8472
- const projectDir = import_path19.default.join(root, entry.name);
8638
+ const projectDir = import_path20.default.join(root, entry.name);
8473
8639
  let inner;
8474
8640
  try {
8475
- inner = import_fs17.default.readdirSync(projectDir, { withFileTypes: true });
8641
+ inner = import_fs18.default.readdirSync(projectDir, { withFileTypes: true });
8476
8642
  } catch {
8477
8643
  continue;
8478
8644
  }
8479
8645
  for (const file of inner) {
8480
8646
  if (file.isFile() && file.name.endsWith(".jsonl")) {
8481
- out.push(import_path19.default.join(projectDir, file.name));
8647
+ out.push(import_path20.default.join(projectDir, file.name));
8482
8648
  }
8483
8649
  }
8484
8650
  }
@@ -8486,7 +8652,7 @@ function listJsonlFiles() {
8486
8652
  }
8487
8653
  function fileSize(p) {
8488
8654
  try {
8489
- return import_fs17.default.statSync(p).size;
8655
+ return import_fs18.default.statSync(p).size;
8490
8656
  } catch {
8491
8657
  return 0;
8492
8658
  }
@@ -8494,7 +8660,7 @@ function fileSize(p) {
8494
8660
  async function scanDelta(filePath, fromByte, onLine) {
8495
8661
  const size = fileSize(filePath);
8496
8662
  if (size <= fromByte) return fromByte;
8497
- const stream = import_fs17.default.createReadStream(filePath, {
8663
+ const stream = import_fs18.default.createReadStream(filePath, {
8498
8664
  start: fromByte,
8499
8665
  end: size - 1,
8500
8666
  highWaterMark: 64 * 1024
@@ -8606,7 +8772,7 @@ async function tickForensicBroadcast(offsets) {
8606
8772
  continue;
8607
8773
  }
8608
8774
  if (size <= offset) continue;
8609
- const sessionId = import_path19.default.basename(file, ".jsonl");
8775
+ const sessionId = import_path20.default.basename(file, ".jsonl");
8610
8776
  const newOffset = await scanDelta(file, offset, (obj, lineIndex) => {
8611
8777
  out.push(...extractFindingsFromLine(obj, sessionId, lineIndex));
8612
8778
  });
@@ -8665,7 +8831,7 @@ function emptyTick(uploadAs) {
8665
8831
  function readRawWatermarkPreservingOffsets() {
8666
8832
  let raw;
8667
8833
  try {
8668
- raw = import_fs17.default.readFileSync(WATERMARK_FILE(), "utf-8");
8834
+ raw = import_fs18.default.readFileSync(WATERMARK_FILE(), "utf-8");
8669
8835
  } catch {
8670
8836
  return null;
8671
8837
  }
@@ -8699,13 +8865,13 @@ async function runActualTick(wm) {
8699
8865
  if (!known) {
8700
8866
  let mtimeMs = 0;
8701
8867
  try {
8702
- mtimeMs = import_fs17.default.statSync(filePath).mtime.getTime();
8868
+ mtimeMs = import_fs18.default.statSync(filePath).mtime.getTime();
8703
8869
  } catch {
8704
8870
  continue;
8705
8871
  }
8706
8872
  if (mtimeMs >= watermarkCreatedAt) {
8707
8873
  filesNew++;
8708
- const sessionId2 = import_path19.default.basename(filePath, ".jsonl");
8874
+ const sessionId2 = import_path20.default.basename(filePath, ".jsonl");
8709
8875
  const newScannedTo2 = await scanDelta(filePath, 0, (obj, lineIndex) => {
8710
8876
  totalToolCalls++;
8711
8877
  toolCallsBySession[sessionId2] = (toolCallsBySession[sessionId2] ?? 0) + 1;
@@ -8723,7 +8889,7 @@ async function runActualTick(wm) {
8723
8889
  filesSkipped++;
8724
8890
  continue;
8725
8891
  }
8726
- const sessionId = import_path19.default.basename(filePath, ".jsonl");
8892
+ const sessionId = import_path20.default.basename(filePath, ".jsonl");
8727
8893
  const newScannedTo = await scanDelta(filePath, known.scannedTo, (obj, lineIndex) => {
8728
8894
  totalToolCalls++;
8729
8895
  toolCallsBySession[sessionId] = (toolCallsBySession[sessionId] ?? 0) + 1;
@@ -8745,18 +8911,18 @@ async function runActualTick(wm) {
8745
8911
  schemaFuture: false
8746
8912
  };
8747
8913
  }
8748
- var import_fs17, import_os16, import_path19, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
8914
+ var import_fs18, import_os17, import_path20, import_readline, PROJECTS_DIR, WATERMARK_FILE, MAX_LINE_BYTES, WATERMARK_SCHEMA_VERSION, LONG_OUTPUT_THRESHOLD_BYTES2;
8749
8915
  var init_scan_watermark = __esm({
8750
8916
  "src/daemon/scan-watermark.ts"() {
8751
8917
  "use strict";
8752
- import_fs17 = __toESM(require("fs"));
8753
- import_os16 = __toESM(require("os"));
8754
- import_path19 = __toESM(require("path"));
8918
+ import_fs18 = __toESM(require("fs"));
8919
+ import_os17 = __toESM(require("os"));
8920
+ import_path20 = __toESM(require("path"));
8755
8921
  import_readline = __toESM(require("readline"));
8756
8922
  init_dlp();
8757
8923
  init_dist();
8758
- PROJECTS_DIR = () => import_path19.default.join(import_os16.default.homedir(), ".claude", "projects");
8759
- WATERMARK_FILE = () => import_path19.default.join(import_os16.default.homedir(), ".node9", "scan-watermark.json");
8924
+ PROJECTS_DIR = () => import_path20.default.join(import_os17.default.homedir(), ".claude", "projects");
8925
+ WATERMARK_FILE = () => import_path20.default.join(import_os17.default.homedir(), ".node9", "scan-watermark.json");
8760
8926
  MAX_LINE_BYTES = 2 * 1024 * 1024;
8761
8927
  WATERMARK_SCHEMA_VERSION = 2;
8762
8928
  LONG_OUTPUT_THRESHOLD_BYTES2 = LONG_OUTPUT_THRESHOLD_BYTES;
@@ -8804,40 +8970,40 @@ function parseSinceCutoff(raw, now = /* @__PURE__ */ new Date()) {
8804
8970
  return now.getTime() - 90 * 864e5;
8805
8971
  }
8806
8972
  function* iterateJsonlFiles(cutoffMs) {
8807
- const projectsDir = import_path20.default.join(import_os17.default.homedir(), ".claude", "projects");
8973
+ const projectsDir = import_path21.default.join(import_os18.default.homedir(), ".claude", "projects");
8808
8974
  let dirs;
8809
8975
  try {
8810
- dirs = import_fs18.default.readdirSync(projectsDir);
8976
+ dirs = import_fs19.default.readdirSync(projectsDir);
8811
8977
  } catch {
8812
8978
  return;
8813
8979
  }
8814
8980
  for (const dir of dirs) {
8815
- const dirPath = import_path20.default.join(projectsDir, dir);
8981
+ const dirPath = import_path21.default.join(projectsDir, dir);
8816
8982
  let stats;
8817
8983
  try {
8818
- stats = import_fs18.default.statSync(dirPath);
8984
+ stats = import_fs19.default.statSync(dirPath);
8819
8985
  } catch {
8820
8986
  continue;
8821
8987
  }
8822
8988
  if (!stats.isDirectory()) continue;
8823
8989
  let files;
8824
8990
  try {
8825
- files = import_fs18.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8991
+ files = import_fs19.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
8826
8992
  } catch {
8827
8993
  continue;
8828
8994
  }
8829
8995
  for (const file of files) {
8830
- const filePath = import_path20.default.join(dirPath, file);
8996
+ const filePath = import_path21.default.join(dirPath, file);
8831
8997
  let mtime = 0;
8832
8998
  try {
8833
- mtime = import_fs18.default.statSync(filePath).mtimeMs;
8999
+ mtime = import_fs19.default.statSync(filePath).mtimeMs;
8834
9000
  } catch {
8835
9001
  continue;
8836
9002
  }
8837
9003
  if (mtime < cutoffMs) continue;
8838
9004
  yield {
8839
9005
  filePath,
8840
- sessionId: import_path20.default.basename(file, ".jsonl"),
9006
+ sessionId: import_path21.default.basename(file, ".jsonl"),
8841
9007
  projectDir: dir
8842
9008
  };
8843
9009
  }
@@ -8890,7 +9056,7 @@ async function runUploadHistory(opts) {
8890
9056
  filesScanned++;
8891
9057
  let content;
8892
9058
  try {
8893
- content = import_fs18.default.readFileSync(filePath, "utf8");
9059
+ content = import_fs19.default.readFileSync(filePath, "utf8");
8894
9060
  } catch {
8895
9061
  continue;
8896
9062
  }
@@ -8976,10 +9142,10 @@ async function runUploadHistory(opts) {
8976
9142
  const costUrl = creds.apiUrl.endsWith("/policies/sync") ? creds.apiUrl.replace(/\/policies\/sync$/, "/cost-sync") : `${creds.apiUrl.replace(/\/$/, "")}/cost-sync`;
8977
9143
  let username = "unknown";
8978
9144
  try {
8979
- username = import_os17.default.userInfo().username;
9145
+ username = import_os18.default.userInfo().username;
8980
9146
  } catch {
8981
9147
  }
8982
- const machineId = `${import_os17.default.hostname()}:${username}`;
9148
+ const machineId = `${import_os18.default.hostname()}:${username}`;
8983
9149
  await postJson(costUrl, creds.apiKey, {
8984
9150
  machineId,
8985
9151
  entries: dailyEntries
@@ -9029,14 +9195,14 @@ async function postJson(url, apiKey, body) {
9029
9195
  req.end();
9030
9196
  });
9031
9197
  }
9032
- var import_fs18, import_https, import_os17, import_path20, import_chalk4, FINDING_TO_SIGNAL2;
9198
+ var import_fs19, import_https, import_os18, import_path21, import_chalk4, FINDING_TO_SIGNAL2;
9033
9199
  var init_scan_upload_history = __esm({
9034
9200
  "src/scan-upload-history.ts"() {
9035
9201
  "use strict";
9036
- import_fs18 = __toESM(require("fs"));
9202
+ import_fs19 = __toESM(require("fs"));
9037
9203
  import_https = __toESM(require("https"));
9038
- import_os17 = __toESM(require("os"));
9039
- import_path20 = __toESM(require("path"));
9204
+ import_os18 = __toESM(require("os"));
9205
+ import_path21 = __toESM(require("path"));
9040
9206
  import_chalk4 = __toESM(require("chalk"));
9041
9207
  init_dist();
9042
9208
  init_config();
@@ -9282,14 +9448,14 @@ function buildRuleSources() {
9282
9448
  }
9283
9449
  function countScanFiles() {
9284
9450
  let total = 0;
9285
- const claudeDir = import_path21.default.join(import_os18.default.homedir(), ".claude", "projects");
9286
- if (import_fs19.default.existsSync(claudeDir)) {
9451
+ const claudeDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
9452
+ if (import_fs20.default.existsSync(claudeDir)) {
9287
9453
  try {
9288
- for (const proj of import_fs19.default.readdirSync(claudeDir)) {
9289
- const p = import_path21.default.join(claudeDir, proj);
9454
+ for (const proj of import_fs20.default.readdirSync(claudeDir)) {
9455
+ const p = import_path22.default.join(claudeDir, proj);
9290
9456
  try {
9291
- if (!import_fs19.default.statSync(p).isDirectory()) continue;
9292
- total += import_fs19.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
9457
+ if (!import_fs20.default.statSync(p).isDirectory()) continue;
9458
+ total += import_fs20.default.readdirSync(p).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-")).length;
9293
9459
  } catch {
9294
9460
  continue;
9295
9461
  }
@@ -9297,17 +9463,17 @@ function countScanFiles() {
9297
9463
  } catch {
9298
9464
  }
9299
9465
  }
9300
- const geminiDir = import_path21.default.join(import_os18.default.homedir(), ".gemini", "tmp");
9301
- if (import_fs19.default.existsSync(geminiDir)) {
9466
+ const geminiDir = import_path22.default.join(import_os19.default.homedir(), ".gemini", "tmp");
9467
+ if (import_fs20.default.existsSync(geminiDir)) {
9302
9468
  try {
9303
- for (const slug of import_fs19.default.readdirSync(geminiDir)) {
9304
- const p = import_path21.default.join(geminiDir, slug);
9469
+ for (const slug of import_fs20.default.readdirSync(geminiDir)) {
9470
+ const p = import_path22.default.join(geminiDir, slug);
9305
9471
  try {
9306
- if (!import_fs19.default.statSync(p).isDirectory()) continue;
9307
- const chatsDir = import_path21.default.join(p, "chats");
9308
- if (import_fs19.default.existsSync(chatsDir)) {
9472
+ if (!import_fs20.default.statSync(p).isDirectory()) continue;
9473
+ const chatsDir = import_path22.default.join(p, "chats");
9474
+ if (import_fs20.default.existsSync(chatsDir)) {
9309
9475
  try {
9310
- total += import_fs19.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
9476
+ total += import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json")).length;
9311
9477
  } catch {
9312
9478
  }
9313
9479
  }
@@ -9318,22 +9484,22 @@ function countScanFiles() {
9318
9484
  } catch {
9319
9485
  }
9320
9486
  }
9321
- const codexDir = import_path21.default.join(import_os18.default.homedir(), ".codex", "sessions");
9322
- if (import_fs19.default.existsSync(codexDir)) {
9487
+ const codexDir = import_path22.default.join(import_os19.default.homedir(), ".codex", "sessions");
9488
+ if (import_fs20.default.existsSync(codexDir)) {
9323
9489
  try {
9324
- for (const year of import_fs19.default.readdirSync(codexDir)) {
9325
- const yp = import_path21.default.join(codexDir, year);
9490
+ for (const year of import_fs20.default.readdirSync(codexDir)) {
9491
+ const yp = import_path22.default.join(codexDir, year);
9326
9492
  try {
9327
- if (!import_fs19.default.statSync(yp).isDirectory()) continue;
9328
- for (const month of import_fs19.default.readdirSync(yp)) {
9329
- const mp = import_path21.default.join(yp, month);
9493
+ if (!import_fs20.default.statSync(yp).isDirectory()) continue;
9494
+ for (const month of import_fs20.default.readdirSync(yp)) {
9495
+ const mp = import_path22.default.join(yp, month);
9330
9496
  try {
9331
- if (!import_fs19.default.statSync(mp).isDirectory()) continue;
9332
- for (const day of import_fs19.default.readdirSync(mp)) {
9333
- const dp = import_path21.default.join(mp, day);
9497
+ if (!import_fs20.default.statSync(mp).isDirectory()) continue;
9498
+ for (const day of import_fs20.default.readdirSync(mp)) {
9499
+ const dp = import_path22.default.join(mp, day);
9334
9500
  try {
9335
- if (!import_fs19.default.statSync(dp).isDirectory()) continue;
9336
- total += import_fs19.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
9501
+ if (!import_fs20.default.statSync(dp).isDirectory()) continue;
9502
+ total += import_fs20.default.readdirSync(dp).filter((f) => f.endsWith(".jsonl")).length;
9337
9503
  } catch {
9338
9504
  continue;
9339
9505
  }
@@ -9369,7 +9535,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9369
9535
  const sessionId = file.replace(/\.jsonl$/, "");
9370
9536
  let raw;
9371
9537
  try {
9372
- raw = import_fs19.default.readFileSync(import_path21.default.join(projPath, file), "utf-8");
9538
+ raw = import_fs20.default.readFileSync(import_path22.default.join(projPath, file), "utf-8");
9373
9539
  } catch {
9374
9540
  return;
9375
9541
  }
@@ -9421,7 +9587,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9421
9587
  if (block.type !== "tool_result") continue;
9422
9588
  const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
9423
9589
  if (filePath) {
9424
- const ext = import_path21.default.extname(filePath).toLowerCase();
9590
+ const ext = import_path22.default.extname(filePath).toLowerCase();
9425
9591
  if (CODE_EXTENSIONS.has(ext)) continue;
9426
9592
  }
9427
9593
  const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
@@ -9478,7 +9644,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9478
9644
  const rawCmd = String(input.command ?? "").trimStart();
9479
9645
  if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
9480
9646
  const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
9481
- const inputFileExt = inputFilePath ? import_path21.default.extname(inputFilePath).toLowerCase() : "";
9647
+ const inputFileExt = inputFilePath ? import_path22.default.extname(inputFilePath).toLowerCase() : "";
9482
9648
  if (CODE_EXTENSIONS.has(inputFileExt)) continue;
9483
9649
  const dlpMatch = scanArgs(input);
9484
9650
  if (dlpMatch) {
@@ -9575,19 +9741,19 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
9575
9741
  }
9576
9742
  }
9577
9743
  function processClaudeProject(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
9578
- const projPath = import_path21.default.join(projectsDir, proj);
9744
+ const projPath = import_path22.default.join(projectsDir, proj);
9579
9745
  try {
9580
- if (!import_fs19.default.statSync(projPath).isDirectory()) return;
9746
+ if (!import_fs20.default.statSync(projPath).isDirectory()) return;
9581
9747
  } catch {
9582
9748
  return;
9583
9749
  }
9584
- const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os18.default.homedir(), "~")).slice(
9750
+ const projLabel = stripTerminalEscapes(decodeURIComponent(proj).replace(import_os19.default.homedir(), "~")).slice(
9585
9751
  0,
9586
9752
  40
9587
9753
  );
9588
9754
  let files;
9589
9755
  try {
9590
- files = import_fs19.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
9756
+ files = import_fs20.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
9591
9757
  } catch {
9592
9758
  return;
9593
9759
  }
@@ -9621,12 +9787,12 @@ function emptyClaudeScan() {
9621
9787
  };
9622
9788
  }
9623
9789
  function scanClaudeHistory(startDate, onProgress, onLine) {
9624
- const projectsDir = import_path21.default.join(import_os18.default.homedir(), ".claude", "projects");
9790
+ const projectsDir = import_path22.default.join(import_os19.default.homedir(), ".claude", "projects");
9625
9791
  const result = emptyClaudeScan();
9626
- if (!import_fs19.default.existsSync(projectsDir)) return result;
9792
+ if (!import_fs20.default.existsSync(projectsDir)) return result;
9627
9793
  let projDirs;
9628
9794
  try {
9629
- projDirs = import_fs19.default.readdirSync(projectsDir);
9795
+ projDirs = import_fs20.default.readdirSync(projectsDir);
9630
9796
  } catch {
9631
9797
  return result;
9632
9798
  }
@@ -9647,7 +9813,7 @@ function scanClaudeHistory(startDate, onProgress, onLine) {
9647
9813
  return result;
9648
9814
  }
9649
9815
  function scanGeminiHistory(startDate, onProgress, onLine) {
9650
- const tmpDir = import_path21.default.join(import_os18.default.homedir(), ".gemini", "tmp");
9816
+ const tmpDir = import_path22.default.join(import_os19.default.homedir(), ".gemini", "tmp");
9651
9817
  const result = {
9652
9818
  filesScanned: 0,
9653
9819
  sessions: 0,
@@ -9662,33 +9828,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
9662
9828
  sessionsWithEarlySecrets: 0
9663
9829
  };
9664
9830
  const dedup = emptyScanDedup();
9665
- if (!import_fs19.default.existsSync(tmpDir)) return result;
9831
+ if (!import_fs20.default.existsSync(tmpDir)) return result;
9666
9832
  let slugDirs;
9667
9833
  try {
9668
- slugDirs = import_fs19.default.readdirSync(tmpDir);
9834
+ slugDirs = import_fs20.default.readdirSync(tmpDir);
9669
9835
  } catch {
9670
9836
  return result;
9671
9837
  }
9672
9838
  const ruleSources = buildRuleSources();
9673
9839
  for (const slug of slugDirs) {
9674
- const slugPath = import_path21.default.join(tmpDir, slug);
9840
+ const slugPath = import_path22.default.join(tmpDir, slug);
9675
9841
  try {
9676
- if (!import_fs19.default.statSync(slugPath).isDirectory()) continue;
9842
+ if (!import_fs20.default.statSync(slugPath).isDirectory()) continue;
9677
9843
  } catch {
9678
9844
  continue;
9679
9845
  }
9680
9846
  let projLabel = stripTerminalEscapes(slug).slice(0, 40);
9681
9847
  try {
9682
9848
  projLabel = stripTerminalEscapes(
9683
- import_fs19.default.readFileSync(import_path21.default.join(slugPath, ".project_root"), "utf-8").trim()
9684
- ).replace(import_os18.default.homedir(), "~").slice(0, 40);
9849
+ import_fs20.default.readFileSync(import_path22.default.join(slugPath, ".project_root"), "utf-8").trim()
9850
+ ).replace(import_os19.default.homedir(), "~").slice(0, 40);
9685
9851
  } catch {
9686
9852
  }
9687
- const chatsDir = import_path21.default.join(slugPath, "chats");
9688
- if (!import_fs19.default.existsSync(chatsDir)) continue;
9853
+ const chatsDir = import_path22.default.join(slugPath, "chats");
9854
+ if (!import_fs20.default.existsSync(chatsDir)) continue;
9689
9855
  let chatFiles;
9690
9856
  try {
9691
- chatFiles = import_fs19.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
9857
+ chatFiles = import_fs20.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
9692
9858
  } catch {
9693
9859
  continue;
9694
9860
  }
@@ -9698,7 +9864,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
9698
9864
  const sessionId = chatFile.replace(/\.json$/, "");
9699
9865
  let raw;
9700
9866
  try {
9701
- raw = import_fs19.default.readFileSync(import_path21.default.join(chatsDir, chatFile), "utf-8");
9867
+ raw = import_fs20.default.readFileSync(import_path22.default.join(chatsDir, chatFile), "utf-8");
9702
9868
  } catch {
9703
9869
  continue;
9704
9870
  }
@@ -9860,7 +10026,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
9860
10026
  return result;
9861
10027
  }
9862
10028
  function scanCodexHistory(startDate, onProgress, onLine) {
9863
- const sessionsBase = import_path21.default.join(import_os18.default.homedir(), ".codex", "sessions");
10029
+ const sessionsBase = import_path22.default.join(import_os19.default.homedir(), ".codex", "sessions");
9864
10030
  const result = {
9865
10031
  filesScanned: 0,
9866
10032
  sessions: 0,
@@ -9875,32 +10041,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
9875
10041
  sessionsWithEarlySecrets: 0
9876
10042
  };
9877
10043
  const dedup = emptyScanDedup();
9878
- if (!import_fs19.default.existsSync(sessionsBase)) return result;
10044
+ if (!import_fs20.default.existsSync(sessionsBase)) return result;
9879
10045
  const jsonlFiles = [];
9880
10046
  try {
9881
- for (const year of import_fs19.default.readdirSync(sessionsBase)) {
9882
- const yearPath = import_path21.default.join(sessionsBase, year);
10047
+ for (const year of import_fs20.default.readdirSync(sessionsBase)) {
10048
+ const yearPath = import_path22.default.join(sessionsBase, year);
9883
10049
  try {
9884
- if (!import_fs19.default.statSync(yearPath).isDirectory()) continue;
10050
+ if (!import_fs20.default.statSync(yearPath).isDirectory()) continue;
9885
10051
  } catch {
9886
10052
  continue;
9887
10053
  }
9888
- for (const month of import_fs19.default.readdirSync(yearPath)) {
9889
- const monthPath = import_path21.default.join(yearPath, month);
10054
+ for (const month of import_fs20.default.readdirSync(yearPath)) {
10055
+ const monthPath = import_path22.default.join(yearPath, month);
9890
10056
  try {
9891
- if (!import_fs19.default.statSync(monthPath).isDirectory()) continue;
10057
+ if (!import_fs20.default.statSync(monthPath).isDirectory()) continue;
9892
10058
  } catch {
9893
10059
  continue;
9894
10060
  }
9895
- for (const day of import_fs19.default.readdirSync(monthPath)) {
9896
- const dayPath = import_path21.default.join(monthPath, day);
10061
+ for (const day of import_fs20.default.readdirSync(monthPath)) {
10062
+ const dayPath = import_path22.default.join(monthPath, day);
9897
10063
  try {
9898
- if (!import_fs19.default.statSync(dayPath).isDirectory()) continue;
10064
+ if (!import_fs20.default.statSync(dayPath).isDirectory()) continue;
9899
10065
  } catch {
9900
10066
  continue;
9901
10067
  }
9902
- for (const file of import_fs19.default.readdirSync(dayPath)) {
9903
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path21.default.join(dayPath, file));
10068
+ for (const file of import_fs20.default.readdirSync(dayPath)) {
10069
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path22.default.join(dayPath, file));
9904
10070
  }
9905
10071
  }
9906
10072
  }
@@ -9914,7 +10080,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
9914
10080
  onProgress?.(result.filesScanned);
9915
10081
  let lines;
9916
10082
  try {
9917
- lines = import_fs19.default.readFileSync(filePath, "utf-8").split("\n");
10083
+ lines = import_fs20.default.readFileSync(filePath, "utf-8").split("\n");
9918
10084
  } catch {
9919
10085
  continue;
9920
10086
  }
@@ -9940,7 +10106,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
9940
10106
  sessionId = String(payload["id"] ?? filePath);
9941
10107
  startTime = String(payload["timestamp"] ?? "");
9942
10108
  const cwd = String(payload["cwd"] ?? "");
9943
- projLabel = stripTerminalEscapes(cwd.replace(import_os18.default.homedir(), "~")).slice(0, 40);
10109
+ projLabel = stripTerminalEscapes(cwd.replace(import_os19.default.homedir(), "~")).slice(0, 40);
9944
10110
  continue;
9945
10111
  }
9946
10112
  if (entry.type === "event_msg" && payload["type"] === "token_count") {
@@ -10093,17 +10259,17 @@ function scanCodexHistory(startDate, onProgress, onLine) {
10093
10259
  return result;
10094
10260
  }
10095
10261
  function scanShellConfig() {
10096
- const home = import_os18.default.homedir();
10262
+ const home = import_os19.default.homedir();
10097
10263
  const configFiles = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map(
10098
- (f) => import_path21.default.join(home, f)
10264
+ (f) => import_path22.default.join(home, f)
10099
10265
  );
10100
10266
  const findings = [];
10101
10267
  const seen = /* @__PURE__ */ new Set();
10102
10268
  for (const filePath of configFiles) {
10103
- if (!import_fs19.default.existsSync(filePath)) continue;
10269
+ if (!import_fs20.default.existsSync(filePath)) continue;
10104
10270
  let lines;
10105
10271
  try {
10106
- lines = import_fs19.default.readFileSync(filePath, "utf-8").split("\n");
10272
+ lines = import_fs20.default.readFileSync(filePath, "utf-8").split("\n");
10107
10273
  } catch {
10108
10274
  continue;
10109
10275
  }
@@ -10817,7 +10983,8 @@ function registerScanCommand(program2) {
10817
10983
  " node9 is still worth running \u2014 it monitors every tool call in real time.\n"
10818
10984
  )
10819
10985
  );
10820
- } else {
10986
+ }
10987
+ {
10821
10988
  const totalRisky = totalFindings + scan.dlpFindings.length;
10822
10989
  const score = classifyScore(blast.score);
10823
10990
  const severityDisplay = score.band === "critical" ? import_chalk5.default.red.bold(score.label) : score.color(score.label);
@@ -10883,7 +11050,7 @@ function registerScanCommand(program2) {
10883
11050
  if (!drillDown) {
10884
11051
  const useInk2 = !options.classic;
10885
11052
  if (useInk2) {
10886
- const scanInkPath = import_path21.default.join(__dirname, "scan-ink.mjs");
11053
+ const scanInkPath = import_path22.default.join(__dirname, "scan-ink.mjs");
10887
11054
  const dynamicImport = new Function("id", "return import(id)");
10888
11055
  const mod = await dynamicImport(`file://${scanInkPath}`);
10889
11056
  const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
@@ -11108,14 +11275,14 @@ function registerScanCommand(program2) {
11108
11275
  }
11109
11276
  );
11110
11277
  }
11111
- var import_chalk5, import_fs19, import_path21, import_os18, import_string_width2, CLAUDE_PRICING, GEMINI_PRICING, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, FIXTURE_TOKEN_PATTERNS, TERMINAL_ESCAPE_RE2, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
11278
+ var import_chalk5, import_fs20, import_path22, import_os19, import_string_width2, CLAUDE_PRICING, GEMINI_PRICING, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, FIXTURE_TOKEN_PATTERNS, TERMINAL_ESCAPE_RE2, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
11112
11279
  var init_scan = __esm({
11113
11280
  "src/cli/commands/scan.ts"() {
11114
11281
  "use strict";
11115
11282
  import_chalk5 = __toESM(require("chalk"));
11116
- import_fs19 = __toESM(require("fs"));
11117
- import_path21 = __toESM(require("path"));
11118
- import_os18 = __toESM(require("os"));
11283
+ import_fs20 = __toESM(require("fs"));
11284
+ import_path22 = __toESM(require("path"));
11285
+ import_os19 = __toESM(require("os"));
11119
11286
  init_shields();
11120
11287
  init_config();
11121
11288
  init_policy();
@@ -11242,11 +11409,11 @@ function commonPathPrefix(paths) {
11242
11409
  const prefix = common.join("/").replace(/\/?$/, "/");
11243
11410
  return prefix.length > 1 ? prefix : null;
11244
11411
  }
11245
- var import_crypto5, SuggestionTracker;
11412
+ var import_crypto6, SuggestionTracker;
11246
11413
  var init_suggestion_tracker = __esm({
11247
11414
  "src/daemon/suggestion-tracker.ts"() {
11248
11415
  "use strict";
11249
- import_crypto5 = require("crypto");
11416
+ import_crypto6 = require("crypto");
11250
11417
  SuggestionTracker = class {
11251
11418
  events = /* @__PURE__ */ new Map();
11252
11419
  threshold;
@@ -11292,7 +11459,7 @@ var init_suggestion_tracker = __esm({
11292
11459
  }
11293
11460
  } : { type: "ignoredTool", toolName };
11294
11461
  return {
11295
- id: (0, import_crypto5.randomUUID)(),
11462
+ id: (0, import_crypto6.randomUUID)(),
11296
11463
  toolName,
11297
11464
  allowCount: events.length,
11298
11465
  suggestedRule,
@@ -11306,12 +11473,12 @@ var init_suggestion_tracker = __esm({
11306
11473
  });
11307
11474
 
11308
11475
  // src/daemon/taint-store.ts
11309
- var import_fs20, import_path22, DEFAULT_TTL_MS, TaintStore;
11476
+ var import_fs21, import_path23, DEFAULT_TTL_MS, TaintStore;
11310
11477
  var init_taint_store = __esm({
11311
11478
  "src/daemon/taint-store.ts"() {
11312
11479
  "use strict";
11313
- import_fs20 = __toESM(require("fs"));
11314
- import_path22 = __toESM(require("path"));
11480
+ import_fs21 = __toESM(require("fs"));
11481
+ import_path23 = __toESM(require("path"));
11315
11482
  DEFAULT_TTL_MS = 60 * 60 * 1e3;
11316
11483
  TaintStore = class {
11317
11484
  records = /* @__PURE__ */ new Map();
@@ -11376,9 +11543,9 @@ var init_taint_store = __esm({
11376
11543
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
11377
11544
  _resolve(filePath) {
11378
11545
  try {
11379
- return import_fs20.default.realpathSync.native(import_path22.default.resolve(filePath));
11546
+ return import_fs21.default.realpathSync.native(import_path23.default.resolve(filePath));
11380
11547
  } catch {
11381
- return import_path22.default.resolve(filePath);
11548
+ return import_path23.default.resolve(filePath);
11382
11549
  }
11383
11550
  }
11384
11551
  };
@@ -11496,8 +11663,8 @@ var init_session_history = __esm({
11496
11663
  // src/daemon/state.ts
11497
11664
  function loadInsightCounts() {
11498
11665
  try {
11499
- if (!import_fs21.default.existsSync(INSIGHT_COUNTS_FILE)) return;
11500
- const data = JSON.parse(import_fs21.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
11666
+ if (!import_fs22.default.existsSync(INSIGHT_COUNTS_FILE)) return;
11667
+ const data = JSON.parse(import_fs22.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
11501
11668
  for (const [tool, count] of Object.entries(data)) {
11502
11669
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
11503
11670
  }
@@ -11536,23 +11703,23 @@ function markRejectionHandlerRegistered() {
11536
11703
  daemonRejectionHandlerRegistered = true;
11537
11704
  }
11538
11705
  function atomicWriteSync2(filePath, data, options) {
11539
- const dir = import_path23.default.dirname(filePath);
11540
- if (!import_fs21.default.existsSync(dir)) import_fs21.default.mkdirSync(dir, { recursive: true });
11541
- const tmpPath = `${filePath}.${(0, import_crypto6.randomUUID)()}.tmp`;
11706
+ const dir = import_path24.default.dirname(filePath);
11707
+ if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
11708
+ const tmpPath = `${filePath}.${(0, import_crypto7.randomUUID)()}.tmp`;
11542
11709
  try {
11543
- import_fs21.default.writeFileSync(tmpPath, data, options);
11710
+ import_fs22.default.writeFileSync(tmpPath, data, options);
11544
11711
  } catch (err2) {
11545
11712
  try {
11546
- import_fs21.default.unlinkSync(tmpPath);
11713
+ import_fs22.default.unlinkSync(tmpPath);
11547
11714
  } catch {
11548
11715
  }
11549
11716
  throw err2;
11550
11717
  }
11551
11718
  try {
11552
- import_fs21.default.renameSync(tmpPath, filePath);
11719
+ import_fs22.default.renameSync(tmpPath, filePath);
11553
11720
  } catch (err2) {
11554
11721
  try {
11555
- import_fs21.default.unlinkSync(tmpPath);
11722
+ import_fs22.default.unlinkSync(tmpPath);
11556
11723
  } catch {
11557
11724
  }
11558
11725
  throw err2;
@@ -11576,16 +11743,16 @@ function appendAuditLog(data) {
11576
11743
  decision: data.decision,
11577
11744
  source: "daemon"
11578
11745
  };
11579
- const dir = import_path23.default.dirname(AUDIT_LOG_FILE);
11580
- if (!import_fs21.default.existsSync(dir)) import_fs21.default.mkdirSync(dir, { recursive: true });
11581
- import_fs21.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
11746
+ const dir = import_path24.default.dirname(AUDIT_LOG_FILE);
11747
+ if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
11748
+ import_fs22.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
11582
11749
  } catch {
11583
11750
  }
11584
11751
  }
11585
11752
  function getAuditHistory(limit = 20) {
11586
11753
  try {
11587
- if (!import_fs21.default.existsSync(AUDIT_LOG_FILE)) return [];
11588
- const lines = import_fs21.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
11754
+ if (!import_fs22.default.existsSync(AUDIT_LOG_FILE)) return [];
11755
+ const lines = import_fs22.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
11589
11756
  if (lines.length === 1 && lines[0] === "") return [];
11590
11757
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
11591
11758
  } catch {
@@ -11594,7 +11761,7 @@ function getAuditHistory(limit = 20) {
11594
11761
  }
11595
11762
  function getOrgName() {
11596
11763
  try {
11597
- if (import_fs21.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11764
+ if (import_fs22.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11598
11765
  } catch {
11599
11766
  }
11600
11767
  return null;
@@ -11602,8 +11769,8 @@ function getOrgName() {
11602
11769
  function writeGlobalSetting(key, value) {
11603
11770
  let config = {};
11604
11771
  try {
11605
- if (import_fs21.default.existsSync(GLOBAL_CONFIG_FILE)) {
11606
- config = JSON.parse(import_fs21.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11772
+ if (import_fs22.default.existsSync(GLOBAL_CONFIG_FILE)) {
11773
+ config = JSON.parse(import_fs22.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11607
11774
  }
11608
11775
  } catch {
11609
11776
  }
@@ -11615,8 +11782,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11615
11782
  try {
11616
11783
  let trust = { entries: [] };
11617
11784
  try {
11618
- if (import_fs21.default.existsSync(TRUST_FILE2))
11619
- trust = JSON.parse(import_fs21.default.readFileSync(TRUST_FILE2, "utf-8"));
11785
+ if (import_fs22.default.existsSync(TRUST_FILE2))
11786
+ trust = JSON.parse(import_fs22.default.readFileSync(TRUST_FILE2, "utf-8"));
11620
11787
  } catch {
11621
11788
  }
11622
11789
  trust.entries = trust.entries.filter(
@@ -11633,8 +11800,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11633
11800
  }
11634
11801
  function readPersistentDecisions() {
11635
11802
  try {
11636
- if (import_fs21.default.existsSync(DECISIONS_FILE)) {
11637
- return JSON.parse(import_fs21.default.readFileSync(DECISIONS_FILE, "utf-8"));
11803
+ if (import_fs22.default.existsSync(DECISIONS_FILE)) {
11804
+ return JSON.parse(import_fs22.default.readFileSync(DECISIONS_FILE, "utf-8"));
11638
11805
  }
11639
11806
  } catch {
11640
11807
  }
@@ -11662,7 +11829,7 @@ function estimateToolCost(tool, args) {
11662
11829
  const filePath = a.file_path ?? a.path;
11663
11830
  if (filePath) {
11664
11831
  try {
11665
- const bytes = import_fs21.default.statSync(filePath).size;
11832
+ const bytes = import_fs22.default.statSync(filePath).size;
11666
11833
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
11667
11834
  } catch {
11668
11835
  }
@@ -11713,7 +11880,7 @@ function broadcastForensic(finding) {
11713
11880
  const severity = CRITICAL_FORENSIC_CATEGORIES.has(finding.type) ? "critical" : "warning";
11714
11881
  const event = {
11715
11882
  type: "forensic",
11716
- id: `fnd_${(0, import_crypto6.randomUUID)()}`,
11883
+ id: `fnd_${(0, import_crypto7.randomUUID)()}`,
11717
11884
  ts: Date.now(),
11718
11885
  sessionId: finding.sessionId,
11719
11886
  category: finding.type,
@@ -11733,7 +11900,7 @@ function abandonPending() {
11733
11900
  });
11734
11901
  if (autoStarted) {
11735
11902
  try {
11736
- import_fs21.default.unlinkSync(DAEMON_PID_FILE);
11903
+ import_fs22.default.unlinkSync(DAEMON_PID_FILE);
11737
11904
  } catch {
11738
11905
  }
11739
11906
  setTimeout(() => {
@@ -11744,8 +11911,8 @@ function abandonPending() {
11744
11911
  }
11745
11912
  function logActivitySocket(msg) {
11746
11913
  try {
11747
- import_fs21.default.appendFileSync(
11748
- import_path23.default.join(homeDir, ".node9", "hook-debug.log"),
11914
+ import_fs22.default.appendFileSync(
11915
+ import_path24.default.join(homeDir, ".node9", "hook-debug.log"),
11749
11916
  `[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
11750
11917
  `
11751
11918
  );
@@ -11767,13 +11934,13 @@ function shouldRebind(now = Date.now()) {
11767
11934
  function startActivitySocket() {
11768
11935
  bindActivitySocket();
11769
11936
  activityHealthInterval = setInterval(() => {
11770
- if (!import_fs21.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11937
+ if (!import_fs22.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11771
11938
  }, ACTIVITY_HEALTH_PROBE_MS);
11772
11939
  activityHealthInterval.unref();
11773
11940
  process.on("exit", () => {
11774
11941
  if (activityHealthInterval) clearInterval(activityHealthInterval);
11775
11942
  try {
11776
- import_fs21.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11943
+ import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11777
11944
  } catch {
11778
11945
  }
11779
11946
  });
@@ -11801,7 +11968,7 @@ function attemptRebind(reason) {
11801
11968
  }
11802
11969
  function bindActivitySocket() {
11803
11970
  try {
11804
- import_fs21.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11971
+ import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11805
11972
  } catch {
11806
11973
  }
11807
11974
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
@@ -11905,28 +12072,28 @@ function bindActivitySocket() {
11905
12072
  });
11906
12073
  activitySocketServer = unixServer;
11907
12074
  }
11908
- var import_net2, import_fs21, import_path23, import_os19, import_crypto6, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
12075
+ var import_net2, import_fs22, import_path24, import_os20, import_crypto7, homeDir, DAEMON_PID_FILE, DECISIONS_FILE, AUDIT_LOG_FILE, TRUST_FILE2, GLOBAL_CONFIG_FILE, CREDENTIALS_FILE, INSIGHT_COUNTS_FILE, pending, sseClients, suggestionTracker, taintStore, insightCounts, _abandonTimer, _hadBrowserClient, _daemonServer, daemonRejectionHandlerRegistered, AUTO_DENY_MS, TRUST_DURATIONS, autoStarted, ACTIVITY_SOCKET_PATH2, ACTIVITY_RING_SIZE, activityRing, LARGE_RESPONSE_RING_SIZE, largeResponseRing, cachedScanResult, cachedScanTs, SCAN_CACHE_TTL_MS, SECRET_KEY_RE, INPUT_PRICE_PER_1M, OUTPUT_PRICE_PER_1M, BYTES_PER_TOKEN, CRITICAL_FORENSIC_CATEGORIES, WRITE_TOOL_NAMES, ACTIVITY_REBIND_MAX_ATTEMPTS, ACTIVITY_REBIND_WINDOW_MS, ACTIVITY_HEALTH_PROBE_MS, activitySocketServer, activityHealthInterval, activityRebindAttempts, activityCircuitTripped;
11909
12076
  var init_state2 = __esm({
11910
12077
  "src/daemon/state.ts"() {
11911
12078
  "use strict";
11912
12079
  import_net2 = __toESM(require("net"));
11913
- import_fs21 = __toESM(require("fs"));
11914
- import_path23 = __toESM(require("path"));
11915
- import_os19 = __toESM(require("os"));
11916
- import_crypto6 = require("crypto");
12080
+ import_fs22 = __toESM(require("fs"));
12081
+ import_path24 = __toESM(require("path"));
12082
+ import_os20 = __toESM(require("os"));
12083
+ import_crypto7 = require("crypto");
11917
12084
  init_daemon();
11918
12085
  init_suggestion_tracker();
11919
12086
  init_taint_store();
11920
12087
  init_session_counters();
11921
12088
  init_session_history();
11922
- homeDir = import_os19.default.homedir();
11923
- DAEMON_PID_FILE = import_path23.default.join(homeDir, ".node9", "daemon.pid");
11924
- DECISIONS_FILE = import_path23.default.join(homeDir, ".node9", "decisions.json");
11925
- AUDIT_LOG_FILE = import_path23.default.join(homeDir, ".node9", "audit.log");
11926
- TRUST_FILE2 = import_path23.default.join(homeDir, ".node9", "trust.json");
11927
- GLOBAL_CONFIG_FILE = import_path23.default.join(homeDir, ".node9", "config.json");
11928
- CREDENTIALS_FILE = import_path23.default.join(homeDir, ".node9", "credentials.json");
11929
- INSIGHT_COUNTS_FILE = import_path23.default.join(homeDir, ".node9", "insight-counts.json");
12089
+ homeDir = import_os20.default.homedir();
12090
+ DAEMON_PID_FILE = import_path24.default.join(homeDir, ".node9", "daemon.pid");
12091
+ DECISIONS_FILE = import_path24.default.join(homeDir, ".node9", "decisions.json");
12092
+ AUDIT_LOG_FILE = import_path24.default.join(homeDir, ".node9", "audit.log");
12093
+ TRUST_FILE2 = import_path24.default.join(homeDir, ".node9", "trust.json");
12094
+ GLOBAL_CONFIG_FILE = import_path24.default.join(homeDir, ".node9", "config.json");
12095
+ CREDENTIALS_FILE = import_path24.default.join(homeDir, ".node9", "credentials.json");
12096
+ INSIGHT_COUNTS_FILE = import_path24.default.join(homeDir, ".node9", "insight-counts.json");
11930
12097
  pending = /* @__PURE__ */ new Map();
11931
12098
  sseClients = /* @__PURE__ */ new Set();
11932
12099
  suggestionTracker = new SuggestionTracker(3);
@@ -11943,7 +12110,7 @@ var init_state2 = __esm({
11943
12110
  "2h": 2 * 60 * 6e4
11944
12111
  };
11945
12112
  autoStarted = process.env.NODE9_AUTO_STARTED === "1";
11946
- ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path23.default.join(import_os19.default.tmpdir(), "node9-activity.sock");
12113
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path24.default.join(import_os20.default.tmpdir(), "node9-activity.sock");
11947
12114
  ACTIVITY_RING_SIZE = 100;
11948
12115
  activityRing = [];
11949
12116
  LARGE_RESPONSE_RING_SIZE = 20;
@@ -12021,8 +12188,8 @@ function readCredentials() {
12021
12188
  };
12022
12189
  }
12023
12190
  try {
12024
- const credPath = import_path24.default.join(import_os20.default.homedir(), ".node9", "credentials.json");
12025
- const creds = JSON.parse(import_fs22.default.readFileSync(credPath, "utf-8"));
12191
+ const credPath = import_path25.default.join(import_os21.default.homedir(), ".node9", "credentials.json");
12192
+ const creds = JSON.parse(import_fs23.default.readFileSync(credPath, "utf-8"));
12026
12193
  const profileName = process.env.NODE9_PROFILE ?? "default";
12027
12194
  const profile = creds[profileName];
12028
12195
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -12048,7 +12215,7 @@ function readCredentials() {
12048
12215
  }
12049
12216
  function readCachedEtag() {
12050
12217
  try {
12051
- const raw = JSON.parse(import_fs22.default.readFileSync(rulesCacheFile(), "utf-8"));
12218
+ const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
12052
12219
  return typeof raw.etag === "string" ? raw.etag : void 0;
12053
12220
  } catch {
12054
12221
  return void 0;
@@ -12109,9 +12276,9 @@ function extractRules(body) {
12109
12276
  return [];
12110
12277
  }
12111
12278
  function writeCache2(cache) {
12112
- const dir = import_path24.default.dirname(rulesCacheFile());
12113
- if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
12114
- import_fs22.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
12279
+ const dir = import_path25.default.dirname(rulesCacheFile());
12280
+ if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
12281
+ import_fs23.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
12115
12282
  }
12116
12283
  async function syncOnce() {
12117
12284
  const creds = readCredentials();
@@ -12268,7 +12435,7 @@ async function runCloudSync() {
12268
12435
  }
12269
12436
  function getCloudSyncStatus() {
12270
12437
  try {
12271
- const raw = JSON.parse(import_fs22.default.readFileSync(rulesCacheFile(), "utf-8"));
12438
+ const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
12272
12439
  if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
12273
12440
  return {
12274
12441
  cached: true,
@@ -12285,7 +12452,7 @@ function getCloudSyncStatus() {
12285
12452
  }
12286
12453
  function getCloudRules() {
12287
12454
  try {
12288
- const raw = JSON.parse(import_fs22.default.readFileSync(rulesCacheFile(), "utf-8"));
12455
+ const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
12289
12456
  return Array.isArray(raw.rules) ? raw.rules : null;
12290
12457
  } catch {
12291
12458
  return null;
@@ -12319,14 +12486,14 @@ function startForensicBroadcast() {
12319
12486
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
12320
12487
  recurring.unref();
12321
12488
  }
12322
- var import_fs22, import_https2, import_os20, import_path24, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
12489
+ var import_fs23, import_https2, import_os21, import_path25, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_HOURS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
12323
12490
  var init_sync = __esm({
12324
12491
  "src/daemon/sync.ts"() {
12325
12492
  "use strict";
12326
- import_fs22 = __toESM(require("fs"));
12493
+ import_fs23 = __toESM(require("fs"));
12327
12494
  import_https2 = __toESM(require("https"));
12328
- import_os20 = __toESM(require("os"));
12329
- import_path24 = __toESM(require("path"));
12495
+ import_os21 = __toESM(require("os"));
12496
+ import_path25 = __toESM(require("path"));
12330
12497
  init_config();
12331
12498
  init_blast();
12332
12499
  init_dist();
@@ -12345,7 +12512,7 @@ var init_sync = __esm({
12345
12512
  loop: "loops",
12346
12513
  "long-output-redacted": "longOutputRedactions"
12347
12514
  };
12348
- rulesCacheFile = () => import_path24.default.join(import_os20.default.homedir(), ".node9", "rules-cache.json");
12515
+ rulesCacheFile = () => import_path25.default.join(import_os21.default.homedir(), ".node9", "rules-cache.json");
12349
12516
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
12350
12517
  DEFAULT_INTERVAL_HOURS = 5;
12351
12518
  MIN_INTERVAL_HOURS = 1;
@@ -12358,68 +12525,68 @@ var init_sync = __esm({
12358
12525
  // src/daemon/dlp-scanner.ts
12359
12526
  function loadIndex() {
12360
12527
  try {
12361
- return JSON.parse(import_fs23.default.readFileSync(INDEX_FILE, "utf-8"));
12528
+ return JSON.parse(import_fs24.default.readFileSync(INDEX_FILE, "utf-8"));
12362
12529
  } catch {
12363
12530
  return {};
12364
12531
  }
12365
12532
  }
12366
12533
  function saveIndex(index) {
12367
12534
  try {
12368
- import_fs23.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12535
+ import_fs24.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12369
12536
  } catch {
12370
12537
  }
12371
12538
  }
12372
12539
  function appendAuditEntry(entry) {
12373
12540
  try {
12374
- import_fs23.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12541
+ import_fs24.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12375
12542
  } catch {
12376
12543
  }
12377
12544
  }
12378
12545
  function runDlpScan() {
12379
- if (!import_fs23.default.existsSync(PROJECTS_DIR2)) return;
12546
+ if (!import_fs24.default.existsSync(PROJECTS_DIR2)) return;
12380
12547
  const index = loadIndex();
12381
12548
  let updated = false;
12382
12549
  let projDirs;
12383
12550
  try {
12384
- projDirs = import_fs23.default.readdirSync(PROJECTS_DIR2);
12551
+ projDirs = import_fs24.default.readdirSync(PROJECTS_DIR2);
12385
12552
  } catch {
12386
12553
  return;
12387
12554
  }
12388
12555
  for (const proj of projDirs) {
12389
- const projPath = import_path25.default.join(PROJECTS_DIR2, proj);
12556
+ const projPath = import_path26.default.join(PROJECTS_DIR2, proj);
12390
12557
  try {
12391
- if (!import_fs23.default.lstatSync(projPath).isDirectory()) continue;
12392
- const real = import_fs23.default.realpathSync(projPath);
12393
- if (!real.startsWith(PROJECTS_DIR2 + import_path25.default.sep) && real !== PROJECTS_DIR2) continue;
12558
+ if (!import_fs24.default.lstatSync(projPath).isDirectory()) continue;
12559
+ const real = import_fs24.default.realpathSync(projPath);
12560
+ if (!real.startsWith(PROJECTS_DIR2 + import_path26.default.sep) && real !== PROJECTS_DIR2) continue;
12394
12561
  } catch {
12395
12562
  continue;
12396
12563
  }
12397
12564
  let files;
12398
12565
  try {
12399
- files = import_fs23.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12566
+ files = import_fs24.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12400
12567
  } catch {
12401
12568
  continue;
12402
12569
  }
12403
12570
  for (const file of files) {
12404
- const filePath = import_path25.default.join(projPath, file);
12571
+ const filePath = import_path26.default.join(projPath, file);
12405
12572
  const lastOffset = index[filePath] ?? 0;
12406
12573
  let size;
12407
12574
  try {
12408
- size = import_fs23.default.statSync(filePath).size;
12575
+ size = import_fs24.default.statSync(filePath).size;
12409
12576
  } catch {
12410
12577
  continue;
12411
12578
  }
12412
12579
  if (size <= lastOffset) continue;
12413
12580
  let fd;
12414
12581
  try {
12415
- fd = import_fs23.default.openSync(filePath, "r");
12582
+ fd = import_fs24.default.openSync(filePath, "r");
12416
12583
  } catch {
12417
12584
  continue;
12418
12585
  }
12419
12586
  try {
12420
12587
  const chunkSize = size - lastOffset;
12421
12588
  const buf = Buffer.alloc(chunkSize);
12422
- import_fs23.default.readSync(fd, buf, 0, chunkSize, lastOffset);
12589
+ import_fs24.default.readSync(fd, buf, 0, chunkSize, lastOffset);
12423
12590
  const chunk = buf.toString("utf-8");
12424
12591
  for (const line of chunk.split("\n")) {
12425
12592
  if (!line.trim()) continue;
@@ -12439,7 +12606,7 @@ function runDlpScan() {
12439
12606
  if (typeof text !== "string") continue;
12440
12607
  const match = scanText(text);
12441
12608
  if (!match) continue;
12442
- const projLabel = decodeURIComponent(proj).replace(import_os21.default.homedir(), "~").slice(0, 40);
12609
+ const projLabel = decodeURIComponent(proj).replace(import_os22.default.homedir(), "~").slice(0, 40);
12443
12610
  const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
12444
12611
  appendAuditEntry({
12445
12612
  ts,
@@ -12464,7 +12631,7 @@ Run: node9 report --period 30d`
12464
12631
  updated = true;
12465
12632
  } finally {
12466
12633
  try {
12467
- import_fs23.default.closeSync(fd);
12634
+ import_fs24.default.closeSync(fd);
12468
12635
  } catch {
12469
12636
  }
12470
12637
  }
@@ -12490,30 +12657,30 @@ function startDlpScanner() {
12490
12657
  );
12491
12658
  timer.unref();
12492
12659
  }
12493
- var import_fs23, import_path25, import_os21, INDEX_FILE, PROJECTS_DIR2;
12660
+ var import_fs24, import_path26, import_os22, INDEX_FILE, PROJECTS_DIR2;
12494
12661
  var init_dlp_scanner = __esm({
12495
12662
  "src/daemon/dlp-scanner.ts"() {
12496
12663
  "use strict";
12497
- import_fs23 = __toESM(require("fs"));
12498
- import_path25 = __toESM(require("path"));
12499
- import_os21 = __toESM(require("os"));
12664
+ import_fs24 = __toESM(require("fs"));
12665
+ import_path26 = __toESM(require("path"));
12666
+ import_os22 = __toESM(require("os"));
12500
12667
  init_dlp();
12501
12668
  init_native();
12502
12669
  init_state2();
12503
- INDEX_FILE = import_path25.default.join(import_os21.default.homedir(), ".node9", "dlp-index.json");
12504
- PROJECTS_DIR2 = import_path25.default.join(import_os21.default.homedir(), ".claude", "projects");
12670
+ INDEX_FILE = import_path26.default.join(import_os22.default.homedir(), ".node9", "dlp-index.json");
12671
+ PROJECTS_DIR2 = import_path26.default.join(import_os22.default.homedir(), ".claude", "projects");
12505
12672
  }
12506
12673
  });
12507
12674
 
12508
12675
  // src/daemon/mcp-tools.ts
12509
12676
  function getMcpToolsFile() {
12510
- return import_path26.default.join(import_os22.default.homedir(), ".node9", "mcp-tools.json");
12677
+ return import_path27.default.join(import_os23.default.homedir(), ".node9", "mcp-tools.json");
12511
12678
  }
12512
12679
  function readMcpToolsConfig() {
12513
12680
  try {
12514
12681
  const file = getMcpToolsFile();
12515
- if (!import_fs24.default.existsSync(file)) return {};
12516
- const raw = import_fs24.default.readFileSync(file, "utf-8");
12682
+ if (!import_fs25.default.existsSync(file)) return {};
12683
+ const raw = import_fs25.default.readFileSync(file, "utf-8");
12517
12684
  return JSON.parse(raw);
12518
12685
  } catch {
12519
12686
  return {};
@@ -12522,11 +12689,11 @@ function readMcpToolsConfig() {
12522
12689
  function writeMcpToolsConfig(config) {
12523
12690
  try {
12524
12691
  const file = getMcpToolsFile();
12525
- const dir = import_path26.default.dirname(file);
12526
- if (!import_fs24.default.existsSync(dir)) import_fs24.default.mkdirSync(dir, { recursive: true });
12527
- const tmpPath = `${file}.${import_os22.default.hostname()}.${process.pid}.tmp`;
12528
- import_fs24.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
12529
- import_fs24.default.renameSync(tmpPath, file);
12692
+ const dir = import_path27.default.dirname(file);
12693
+ if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
12694
+ const tmpPath = `${file}.${import_os23.default.hostname()}.${process.pid}.tmp`;
12695
+ import_fs25.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
12696
+ import_fs25.default.renameSync(tmpPath, file);
12530
12697
  } catch (e) {
12531
12698
  console.error("Failed to write mcp-tools.json", e);
12532
12699
  }
@@ -12565,13 +12732,13 @@ function approveServer(serverKey, disabledTools) {
12565
12732
  writeMcpToolsConfig(config);
12566
12733
  }
12567
12734
  }
12568
- var import_fs24, import_path26, import_os22;
12735
+ var import_fs25, import_path27, import_os23;
12569
12736
  var init_mcp_tools = __esm({
12570
12737
  "src/daemon/mcp-tools.ts"() {
12571
12738
  "use strict";
12572
- import_fs24 = __toESM(require("fs"));
12573
- import_path26 = __toESM(require("path"));
12574
- import_os22 = __toESM(require("os"));
12739
+ import_fs25 = __toESM(require("fs"));
12740
+ import_path27 = __toESM(require("path"));
12741
+ import_os23 = __toESM(require("os"));
12575
12742
  }
12576
12743
  });
12577
12744
 
@@ -12582,7 +12749,7 @@ function startDaemon() {
12582
12749
  startForensicBroadcast();
12583
12750
  startDlpScanner();
12584
12751
  loadInsightCounts();
12585
- const internalToken = (0, import_crypto7.randomUUID)();
12752
+ const internalToken = (0, import_crypto8.randomUUID)();
12586
12753
  const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
12587
12754
  const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
12588
12755
  const watchMode = process.env.NODE9_WATCH_MODE === "1";
@@ -12593,7 +12760,7 @@ function startDaemon() {
12593
12760
  idleTimer = setTimeout(() => {
12594
12761
  if (autoStarted) {
12595
12762
  try {
12596
- import_fs25.default.unlinkSync(DAEMON_PID_FILE);
12763
+ import_fs26.default.unlinkSync(DAEMON_PID_FILE);
12597
12764
  } catch {
12598
12765
  }
12599
12766
  }
@@ -12694,7 +12861,7 @@ data: ${JSON.stringify(item.data)}
12694
12861
  cwd,
12695
12862
  localSmartRuleMatched = false
12696
12863
  } = JSON.parse(body);
12697
- const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto7.randomUUID)();
12864
+ const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto8.randomUUID)();
12698
12865
  const entry = {
12699
12866
  id,
12700
12867
  toolName,
@@ -12738,7 +12905,7 @@ data: ${JSON.stringify(item.data)}
12738
12905
  mcpServer: entry.mcpServer
12739
12906
  });
12740
12907
  }
12741
- const projectCwd = typeof cwd === "string" && import_path27.default.isAbsolute(cwd) ? cwd : void 0;
12908
+ const projectCwd = typeof cwd === "string" && import_path28.default.isAbsolute(cwd) ? cwd : void 0;
12742
12909
  const projectConfig = getConfig(projectCwd);
12743
12910
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
12744
12911
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -13030,8 +13197,8 @@ data: ${JSON.stringify(item.data)}
13030
13197
  if (!validToken(req)) return res.writeHead(403).end();
13031
13198
  const periodParam = reqUrl.searchParams.get("period") || "7d";
13032
13199
  const period = ["today", "7d", "30d", "month"].includes(periodParam) ? periodParam : "7d";
13033
- const logPath = import_path27.default.join(import_os23.default.homedir(), ".node9", "audit.log");
13034
- if (!import_fs25.default.existsSync(logPath)) {
13200
+ const logPath = import_path28.default.join(import_os24.default.homedir(), ".node9", "audit.log");
13201
+ if (!import_fs26.default.existsSync(logPath)) {
13035
13202
  res.writeHead(200, { "Content-Type": "application/json" });
13036
13203
  return res.end(
13037
13204
  JSON.stringify({
@@ -13044,7 +13211,7 @@ data: ${JSON.stringify(item.data)}
13044
13211
  );
13045
13212
  }
13046
13213
  try {
13047
- const raw = import_fs25.default.readFileSync(logPath, "utf-8");
13214
+ const raw = import_fs26.default.readFileSync(logPath, "utf-8");
13048
13215
  const allEntries = raw.split("\n").flatMap((line) => {
13049
13216
  if (!line.trim()) return [];
13050
13217
  try {
@@ -13279,7 +13446,7 @@ data: ${JSON.stringify(item.data)}
13279
13446
  args: { toolCount: tools.length, status },
13280
13447
  decision: "mcp-discovered"
13281
13448
  });
13282
- const id = (0, import_crypto7.randomUUID)();
13449
+ const id = (0, import_crypto8.randomUUID)();
13283
13450
  const entry = {
13284
13451
  id,
13285
13452
  type: "mcp-discovery",
@@ -13367,14 +13534,14 @@ data: ${JSON.stringify(item.data)}
13367
13534
  server.on("error", (e) => {
13368
13535
  if (e.code === "EADDRINUSE") {
13369
13536
  try {
13370
- if (import_fs25.default.existsSync(DAEMON_PID_FILE)) {
13371
- const { pid } = JSON.parse(import_fs25.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13537
+ if (import_fs26.default.existsSync(DAEMON_PID_FILE)) {
13538
+ const { pid } = JSON.parse(import_fs26.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13372
13539
  process.kill(pid, 0);
13373
13540
  return process.exit(0);
13374
13541
  }
13375
13542
  } catch {
13376
13543
  try {
13377
- import_fs25.default.unlinkSync(DAEMON_PID_FILE);
13544
+ import_fs26.default.unlinkSync(DAEMON_PID_FILE);
13378
13545
  } catch {
13379
13546
  }
13380
13547
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -13446,15 +13613,15 @@ data: ${JSON.stringify(item.data)}
13446
13613
  }
13447
13614
  startActivitySocket();
13448
13615
  }
13449
- var import_http, import_fs25, import_path27, import_os23, import_crypto7, import_child_process2, import_chalk6;
13616
+ var import_http, import_fs26, import_path28, import_os24, import_crypto8, import_child_process2, import_chalk6;
13450
13617
  var init_server = __esm({
13451
13618
  "src/daemon/server.ts"() {
13452
13619
  "use strict";
13453
13620
  import_http = __toESM(require("http"));
13454
- import_fs25 = __toESM(require("fs"));
13455
- import_path27 = __toESM(require("path"));
13456
- import_os23 = __toESM(require("os"));
13457
- import_crypto7 = require("crypto");
13621
+ import_fs26 = __toESM(require("fs"));
13622
+ import_path28 = __toESM(require("path"));
13623
+ import_os24 = __toESM(require("os"));
13624
+ import_crypto8 = require("crypto");
13458
13625
  import_child_process2 = require("child_process");
13459
13626
  import_chalk6 = __toESM(require("chalk"));
13460
13627
  init_core();
@@ -13473,8 +13640,8 @@ var init_server = __esm({
13473
13640
  function resolveNode9Binary() {
13474
13641
  try {
13475
13642
  const script = process.argv[1];
13476
- if (typeof script === "string" && import_path28.default.isAbsolute(script) && import_fs26.default.existsSync(script)) {
13477
- return import_fs26.default.realpathSync(script);
13643
+ if (typeof script === "string" && import_path29.default.isAbsolute(script) && import_fs27.default.existsSync(script)) {
13644
+ return import_fs27.default.realpathSync(script);
13478
13645
  }
13479
13646
  } catch {
13480
13647
  }
@@ -13492,11 +13659,11 @@ function xmlEscape(s) {
13492
13659
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13493
13660
  }
13494
13661
  function launchdPlist(binaryPath) {
13495
- const logDir = import_path28.default.join(import_os24.default.homedir(), ".node9");
13662
+ const logDir = import_path29.default.join(import_os25.default.homedir(), ".node9");
13496
13663
  const nodePath = xmlEscape(process.execPath);
13497
13664
  const scriptPath = xmlEscape(binaryPath);
13498
- const outLog = xmlEscape(import_path28.default.join(logDir, "daemon.log"));
13499
- const errLog = xmlEscape(import_path28.default.join(logDir, "daemon-error.log"));
13665
+ const outLog = xmlEscape(import_path29.default.join(logDir, "daemon.log"));
13666
+ const errLog = xmlEscape(import_path29.default.join(logDir, "daemon-error.log"));
13500
13667
  return `<?xml version="1.0" encoding="UTF-8"?>
13501
13668
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
13502
13669
  <plist version="1.0">
@@ -13529,9 +13696,9 @@ function launchdPlist(binaryPath) {
13529
13696
  `;
13530
13697
  }
13531
13698
  function installLaunchd(binaryPath) {
13532
- const dir = import_path28.default.dirname(LAUNCHD_PLIST);
13533
- if (!import_fs26.default.existsSync(dir)) import_fs26.default.mkdirSync(dir, { recursive: true });
13534
- import_fs26.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
13699
+ const dir = import_path29.default.dirname(LAUNCHD_PLIST);
13700
+ if (!import_fs27.default.existsSync(dir)) import_fs27.default.mkdirSync(dir, { recursive: true });
13701
+ import_fs27.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
13535
13702
  (0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
13536
13703
  const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
13537
13704
  encoding: "utf8",
@@ -13542,13 +13709,13 @@ function installLaunchd(binaryPath) {
13542
13709
  }
13543
13710
  }
13544
13711
  function uninstallLaunchd() {
13545
- if (import_fs26.default.existsSync(LAUNCHD_PLIST)) {
13712
+ if (import_fs27.default.existsSync(LAUNCHD_PLIST)) {
13546
13713
  (0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
13547
- import_fs26.default.unlinkSync(LAUNCHD_PLIST);
13714
+ import_fs27.default.unlinkSync(LAUNCHD_PLIST);
13548
13715
  }
13549
13716
  }
13550
13717
  function isLaunchdInstalled() {
13551
- return import_fs26.default.existsSync(LAUNCHD_PLIST);
13718
+ return import_fs27.default.existsSync(LAUNCHD_PLIST);
13552
13719
  }
13553
13720
  function systemdUnit(binaryPath) {
13554
13721
  return `[Unit]
@@ -13567,12 +13734,12 @@ WantedBy=default.target
13567
13734
  `;
13568
13735
  }
13569
13736
  function installSystemd(binaryPath) {
13570
- if (!import_fs26.default.existsSync(SYSTEMD_UNIT_DIR)) {
13571
- import_fs26.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13737
+ if (!import_fs27.default.existsSync(SYSTEMD_UNIT_DIR)) {
13738
+ import_fs27.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13572
13739
  }
13573
- import_fs26.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13740
+ import_fs27.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13574
13741
  try {
13575
- (0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os24.default.userInfo().username], { timeout: 3e3 });
13742
+ (0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os25.default.userInfo().username], { timeout: 3e3 });
13576
13743
  } catch {
13577
13744
  }
13578
13745
  const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
@@ -13592,23 +13759,23 @@ function installSystemd(binaryPath) {
13592
13759
  }
13593
13760
  }
13594
13761
  function uninstallSystemd() {
13595
- if (import_fs26.default.existsSync(SYSTEMD_UNIT)) {
13762
+ if (import_fs27.default.existsSync(SYSTEMD_UNIT)) {
13596
13763
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
13597
13764
  encoding: "utf8",
13598
13765
  timeout: 5e3
13599
13766
  });
13600
13767
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
13601
- import_fs26.default.unlinkSync(SYSTEMD_UNIT);
13768
+ import_fs27.default.unlinkSync(SYSTEMD_UNIT);
13602
13769
  }
13603
13770
  }
13604
13771
  function isSystemdInstalled() {
13605
- return import_fs26.default.existsSync(SYSTEMD_UNIT);
13772
+ return import_fs27.default.existsSync(SYSTEMD_UNIT);
13606
13773
  }
13607
13774
  function stopRunningDaemon() {
13608
- const pidFile = import_path28.default.join(import_os24.default.homedir(), ".node9", "daemon.pid");
13609
- if (!import_fs26.default.existsSync(pidFile)) return;
13775
+ const pidFile = import_path29.default.join(import_os25.default.homedir(), ".node9", "daemon.pid");
13776
+ if (!import_fs27.default.existsSync(pidFile)) return;
13610
13777
  try {
13611
- const data = JSON.parse(import_fs26.default.readFileSync(pidFile, "utf-8"));
13778
+ const data = JSON.parse(import_fs27.default.readFileSync(pidFile, "utf-8"));
13612
13779
  const pid = data.pid;
13613
13780
  const MAX_PID2 = 4194304;
13614
13781
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -13628,7 +13795,7 @@ function stopRunningDaemon() {
13628
13795
  }
13629
13796
  }
13630
13797
  try {
13631
- import_fs26.default.unlinkSync(pidFile);
13798
+ import_fs27.default.unlinkSync(pidFile);
13632
13799
  } catch {
13633
13800
  }
13634
13801
  } catch {
@@ -13698,26 +13865,26 @@ function isDaemonServiceInstalled() {
13698
13865
  if (process.platform === "linux") return isSystemdInstalled();
13699
13866
  return false;
13700
13867
  }
13701
- var import_fs26, import_path28, import_os24, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
13868
+ var import_fs27, import_path29, import_os25, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
13702
13869
  var init_service = __esm({
13703
13870
  "src/daemon/service.ts"() {
13704
13871
  "use strict";
13705
- import_fs26 = __toESM(require("fs"));
13706
- import_path28 = __toESM(require("path"));
13707
- import_os24 = __toESM(require("os"));
13872
+ import_fs27 = __toESM(require("fs"));
13873
+ import_path29 = __toESM(require("path"));
13874
+ import_os25 = __toESM(require("os"));
13708
13875
  import_child_process3 = require("child_process");
13709
13876
  LAUNCHD_LABEL = "ai.node9.daemon";
13710
- LAUNCHD_PLIST = import_path28.default.join(import_os24.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
13711
- SYSTEMD_UNIT_DIR = import_path28.default.join(import_os24.default.homedir(), ".config", "systemd", "user");
13712
- SYSTEMD_UNIT = import_path28.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
13877
+ LAUNCHD_PLIST = import_path29.default.join(import_os25.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
13878
+ SYSTEMD_UNIT_DIR = import_path29.default.join(import_os25.default.homedir(), ".config", "systemd", "user");
13879
+ SYSTEMD_UNIT = import_path29.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
13713
13880
  }
13714
13881
  });
13715
13882
 
13716
13883
  // src/daemon/index.ts
13717
13884
  function stopDaemon() {
13718
- if (!import_fs27.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
13885
+ if (!import_fs28.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
13719
13886
  try {
13720
- const data = JSON.parse(import_fs27.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13887
+ const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13721
13888
  const pid = data.pid;
13722
13889
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
13723
13890
  console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
@@ -13729,7 +13896,7 @@ function stopDaemon() {
13729
13896
  console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
13730
13897
  } finally {
13731
13898
  try {
13732
- import_fs27.default.unlinkSync(DAEMON_PID_FILE);
13899
+ import_fs28.default.unlinkSync(DAEMON_PID_FILE);
13733
13900
  } catch {
13734
13901
  }
13735
13902
  }
@@ -13738,9 +13905,9 @@ function daemonStatus() {
13738
13905
  const serviceInstalled = isDaemonServiceInstalled();
13739
13906
  const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
13740
13907
  let processStatus;
13741
- if (import_fs27.default.existsSync(DAEMON_PID_FILE)) {
13908
+ if (import_fs28.default.existsSync(DAEMON_PID_FILE)) {
13742
13909
  try {
13743
- const data = JSON.parse(import_fs27.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13910
+ const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13744
13911
  const pid = data.pid;
13745
13912
  const port = data.port;
13746
13913
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -13762,11 +13929,11 @@ function daemonStatus() {
13762
13929
  console.log(` Service : ${serviceLabel}
13763
13930
  `);
13764
13931
  }
13765
- var import_fs27, import_chalk7, MAX_PID;
13932
+ var import_fs28, import_chalk7, MAX_PID;
13766
13933
  var init_daemon2 = __esm({
13767
13934
  "src/daemon/index.ts"() {
13768
13935
  "use strict";
13769
- import_fs27 = __toESM(require("fs"));
13936
+ import_fs28 = __toESM(require("fs"));
13770
13937
  import_chalk7 = __toESM(require("chalk"));
13771
13938
  init_server();
13772
13939
  init_state2();
@@ -13807,19 +13974,19 @@ function getModelContextLimit(model) {
13807
13974
  }
13808
13975
  function readSessionUsage() {
13809
13976
  const projectsDir = import_path47.default.join(import_os41.default.homedir(), ".claude", "projects");
13810
- if (!import_fs45.default.existsSync(projectsDir)) return null;
13977
+ if (!import_fs46.default.existsSync(projectsDir)) return null;
13811
13978
  let latestFile = null;
13812
13979
  let latestMtime = 0;
13813
13980
  try {
13814
- for (const dir of import_fs45.default.readdirSync(projectsDir)) {
13981
+ for (const dir of import_fs46.default.readdirSync(projectsDir)) {
13815
13982
  const dirPath = import_path47.default.join(projectsDir, dir);
13816
13983
  try {
13817
- if (!import_fs45.default.statSync(dirPath).isDirectory()) continue;
13818
- for (const file of import_fs45.default.readdirSync(dirPath)) {
13984
+ if (!import_fs46.default.statSync(dirPath).isDirectory()) continue;
13985
+ for (const file of import_fs46.default.readdirSync(dirPath)) {
13819
13986
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
13820
13987
  const filePath = import_path47.default.join(dirPath, file);
13821
13988
  try {
13822
- const mtime = import_fs45.default.statSync(filePath).mtimeMs;
13989
+ const mtime = import_fs46.default.statSync(filePath).mtimeMs;
13823
13990
  if (mtime > latestMtime) {
13824
13991
  latestMtime = mtime;
13825
13992
  latestFile = filePath;
@@ -13834,7 +14001,7 @@ function readSessionUsage() {
13834
14001
  }
13835
14002
  if (!latestFile) return null;
13836
14003
  try {
13837
- const lines = import_fs45.default.readFileSync(latestFile, "utf-8").split("\n");
14004
+ const lines = import_fs46.default.readFileSync(latestFile, "utf-8").split("\n");
13838
14005
  let lastModel = "";
13839
14006
  let lastInput = 0;
13840
14007
  let lastOutput = 0;
@@ -13934,9 +14101,9 @@ function renderPending(activity) {
13934
14101
  }
13935
14102
  async function ensureDaemon() {
13936
14103
  let pidPort = null;
13937
- if (import_fs45.default.existsSync(PID_FILE)) {
14104
+ if (import_fs46.default.existsSync(PID_FILE)) {
13938
14105
  try {
13939
- const { port } = JSON.parse(import_fs45.default.readFileSync(PID_FILE, "utf-8"));
14106
+ const { port } = JSON.parse(import_fs46.default.readFileSync(PID_FILE, "utf-8"));
13940
14107
  pidPort = port;
13941
14108
  } catch {
13942
14109
  console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -14094,7 +14261,7 @@ function buildRecoveryCardLines(req) {
14094
14261
  function readApproversFromDisk() {
14095
14262
  const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
14096
14263
  try {
14097
- const raw = JSON.parse(import_fs45.default.readFileSync(configPath, "utf-8"));
14264
+ const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
14098
14265
  const settings = raw.settings ?? {};
14099
14266
  return settings.approvers ?? {};
14100
14267
  } catch {
@@ -14112,13 +14279,13 @@ function approverStatusLine() {
14112
14279
  function toggleApprover(channel) {
14113
14280
  const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
14114
14281
  try {
14115
- const raw = JSON.parse(import_fs45.default.readFileSync(configPath, "utf-8"));
14282
+ const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
14116
14283
  const settings = raw.settings ?? {};
14117
14284
  const approvers = settings.approvers ?? {};
14118
14285
  approvers[channel] = approvers[channel] === false;
14119
14286
  settings.approvers = approvers;
14120
14287
  raw.settings = settings;
14121
- import_fs45.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14288
+ import_fs46.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14122
14289
  } catch (err2) {
14123
14290
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
14124
14291
  `);
@@ -14290,7 +14457,7 @@ async function startTail(options = {}) {
14290
14457
  }
14291
14458
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
14292
14459
  try {
14293
- import_fs45.default.appendFileSync(
14460
+ import_fs46.default.appendFileSync(
14294
14461
  import_path47.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log"),
14295
14462
  `[tail] POST /decision failed: ${String(err2)}
14296
14463
  `
@@ -14357,7 +14524,7 @@ async function startTail(options = {}) {
14357
14524
  }
14358
14525
  const auditLog = import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
14359
14526
  try {
14360
- const unackedDlp = import_fs45.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14527
+ const unackedDlp = import_fs46.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14361
14528
  if (unackedDlp > 0) {
14362
14529
  console.log("");
14363
14530
  console.log(
@@ -14397,7 +14564,7 @@ async function startTail(options = {}) {
14397
14564
  if (stallWarned) return;
14398
14565
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
14399
14566
  try {
14400
- const auditMtime = import_fs45.default.statSync(auditLog).mtimeMs;
14567
+ const auditMtime = import_fs46.default.statSync(auditLog).mtimeMs;
14401
14568
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
14402
14569
  console.log("");
14403
14570
  console.log(
@@ -14582,13 +14749,13 @@ async function startTail(options = {}) {
14582
14749
  process.exit(1);
14583
14750
  });
14584
14751
  }
14585
- var import_http2, import_chalk29, import_fs45, import_os41, import_path47, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
14752
+ var import_http2, import_chalk29, import_fs46, import_os41, import_path47, import_readline6, import_child_process12, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
14586
14753
  var init_tail = __esm({
14587
14754
  "src/tui/tail.ts"() {
14588
14755
  "use strict";
14589
14756
  import_http2 = __toESM(require("http"));
14590
14757
  import_chalk29 = __toESM(require("chalk"));
14591
- import_fs45 = __toESM(require("fs"));
14758
+ import_fs46 = __toESM(require("fs"));
14592
14759
  import_os41 = __toESM(require("os"));
14593
14760
  import_path47 = __toESM(require("path"));
14594
14761
  import_readline6 = __toESM(require("readline"));
@@ -14717,9 +14884,9 @@ function formatTimeLeft(resetsAt) {
14717
14884
  return ` (${m}m left)`;
14718
14885
  }
14719
14886
  function safeReadJson(filePath) {
14720
- if (!import_fs46.default.existsSync(filePath)) return null;
14887
+ if (!import_fs47.default.existsSync(filePath)) return null;
14721
14888
  try {
14722
- return JSON.parse(import_fs46.default.readFileSync(filePath, "utf-8"));
14889
+ return JSON.parse(import_fs47.default.readFileSync(filePath, "utf-8"));
14723
14890
  } catch {
14724
14891
  return null;
14725
14892
  }
@@ -14740,10 +14907,10 @@ function countHooksInFile(filePath) {
14740
14907
  return Object.keys(cfg.hooks).length;
14741
14908
  }
14742
14909
  function countRulesInDir(rulesDir) {
14743
- if (!import_fs46.default.existsSync(rulesDir)) return 0;
14910
+ if (!import_fs47.default.existsSync(rulesDir)) return 0;
14744
14911
  let count = 0;
14745
14912
  try {
14746
- for (const entry of import_fs46.default.readdirSync(rulesDir, { withFileTypes: true })) {
14913
+ for (const entry of import_fs47.default.readdirSync(rulesDir, { withFileTypes: true })) {
14747
14914
  if (entry.isDirectory()) {
14748
14915
  count += countRulesInDir(import_path48.default.join(rulesDir, entry.name));
14749
14916
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -14769,7 +14936,7 @@ function countConfigs(cwd) {
14769
14936
  let hooksCount = 0;
14770
14937
  const userMcpServers = /* @__PURE__ */ new Set();
14771
14938
  const projectMcpServers = /* @__PURE__ */ new Set();
14772
- if (import_fs46.default.existsSync(import_path48.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14939
+ if (import_fs47.default.existsSync(import_path48.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14773
14940
  rulesCount += countRulesInDir(import_path48.default.join(claudeDir, "rules"));
14774
14941
  const userSettings = import_path48.default.join(claudeDir, "settings.json");
14775
14942
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
@@ -14780,18 +14947,18 @@ function countConfigs(cwd) {
14780
14947
  userMcpServers.delete(name);
14781
14948
  }
14782
14949
  if (cwd) {
14783
- if (import_fs46.default.existsSync(import_path48.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
14784
- if (import_fs46.default.existsSync(import_path48.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
14950
+ if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
14951
+ if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
14785
14952
  const projectClaudeDir = import_path48.default.join(cwd, ".claude");
14786
14953
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
14787
14954
  if (!overlapsUserScope) {
14788
- if (import_fs46.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14955
+ if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14789
14956
  rulesCount += countRulesInDir(import_path48.default.join(projectClaudeDir, "rules"));
14790
14957
  const projSettings = import_path48.default.join(projectClaudeDir, "settings.json");
14791
14958
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
14792
14959
  hooksCount += countHooksInFile(projSettings);
14793
14960
  }
14794
- if (import_fs46.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14961
+ if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14795
14962
  const localSettings = import_path48.default.join(projectClaudeDir, "settings.local.json");
14796
14963
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
14797
14964
  hooksCount += countHooksInFile(localSettings);
@@ -14829,11 +14996,11 @@ function readActiveShieldsHud() {
14829
14996
  }
14830
14997
  try {
14831
14998
  const shieldsPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "shields.json");
14832
- if (!import_fs46.default.existsSync(shieldsPath)) {
14999
+ if (!import_fs47.default.existsSync(shieldsPath)) {
14833
15000
  shieldsCache = { value: [], ts: now };
14834
15001
  return [];
14835
15002
  }
14836
- const parsed = JSON.parse(import_fs46.default.readFileSync(shieldsPath, "utf-8"));
15003
+ const parsed = JSON.parse(import_fs47.default.readFileSync(shieldsPath, "utf-8"));
14837
15004
  if (!Array.isArray(parsed.active)) {
14838
15005
  shieldsCache = { value: [], ts: now };
14839
15006
  return [];
@@ -14935,17 +15102,17 @@ function renderContextLine(stdin) {
14935
15102
  async function main() {
14936
15103
  try {
14937
15104
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
14938
- if (import_fs46.default.existsSync(import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug"))) {
15105
+ if (import_fs47.default.existsSync(import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug"))) {
14939
15106
  try {
14940
15107
  const logPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug.log");
14941
15108
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
14942
15109
  let size = 0;
14943
15110
  try {
14944
- size = import_fs46.default.statSync(logPath).size;
15111
+ size = import_fs47.default.statSync(logPath).size;
14945
15112
  } catch {
14946
15113
  }
14947
15114
  if (size < MAX_LOG_SIZE) {
14948
- import_fs46.default.appendFileSync(
15115
+ import_fs47.default.appendFileSync(
14949
15116
  logPath,
14950
15117
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
14951
15118
  );
@@ -14969,8 +15136,8 @@ async function main() {
14969
15136
  import_path48.default.join(cwd, "node9.config.json"),
14970
15137
  import_path48.default.join(import_os42.default.homedir(), ".node9", "config.json")
14971
15138
  ]) {
14972
- if (!import_fs46.default.existsSync(configPath)) continue;
14973
- const cfg = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
15139
+ if (!import_fs47.default.existsSync(configPath)) continue;
15140
+ const cfg = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
14974
15141
  const hud = cfg.settings?.hud;
14975
15142
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
14976
15143
  }
@@ -14988,11 +15155,11 @@ async function main() {
14988
15155
  renderOffline();
14989
15156
  }
14990
15157
  }
14991
- var import_fs46, import_path48, import_os42, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
15158
+ var import_fs47, import_path48, import_os42, import_http3, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
14992
15159
  var init_hud = __esm({
14993
15160
  "src/cli/hud.ts"() {
14994
15161
  "use strict";
14995
- import_fs46 = __toESM(require("fs"));
15162
+ import_fs47 = __toESM(require("fs"));
14996
15163
  import_path48 = __toESM(require("path"));
14997
15164
  import_os42 = __toESM(require("os"));
14998
15165
  import_http3 = __toESM(require("http"));
@@ -15021,7 +15188,7 @@ init_core();
15021
15188
  init_setup();
15022
15189
  init_daemon2();
15023
15190
  var import_chalk30 = __toESM(require("chalk"));
15024
- var import_fs47 = __toESM(require("fs"));
15191
+ var import_fs48 = __toESM(require("fs"));
15025
15192
  var import_path49 = __toESM(require("path"));
15026
15193
  var import_os43 = __toESM(require("os"));
15027
15194
  var import_prompts2 = require("@inquirer/prompts");
@@ -15205,18 +15372,18 @@ async function runProxy(targetCommand) {
15205
15372
 
15206
15373
  // src/cli/daemon-starter.ts
15207
15374
  var import_child_process5 = require("child_process");
15208
- var import_path29 = __toESM(require("path"));
15209
- var import_fs28 = __toESM(require("fs"));
15375
+ var import_path30 = __toESM(require("path"));
15376
+ var import_fs29 = __toESM(require("fs"));
15210
15377
  init_daemon();
15211
15378
  function isTestingMode() {
15212
15379
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
15213
15380
  }
15214
15381
  async function autoStartDaemonAndWait() {
15215
15382
  if (isTestingMode()) return false;
15216
- if (!import_path29.default.isAbsolute(process.argv[1])) return false;
15383
+ if (!import_path30.default.isAbsolute(process.argv[1])) return false;
15217
15384
  let resolvedArgv1;
15218
15385
  try {
15219
- resolvedArgv1 = import_fs28.default.realpathSync(process.argv[1]);
15386
+ resolvedArgv1 = import_fs29.default.realpathSync(process.argv[1]);
15220
15387
  } catch {
15221
15388
  return false;
15222
15389
  }
@@ -15243,10 +15410,10 @@ async function autoStartDaemonAndWait() {
15243
15410
 
15244
15411
  // src/cli/commands/check.ts
15245
15412
  var import_chalk9 = __toESM(require("chalk"));
15246
- var import_fs31 = __toESM(require("fs"));
15413
+ var import_fs32 = __toESM(require("fs"));
15247
15414
  var import_child_process7 = require("child_process");
15248
- var import_path32 = __toESM(require("path"));
15249
- var import_os27 = __toESM(require("os"));
15415
+ var import_path33 = __toESM(require("path"));
15416
+ var import_os28 = __toESM(require("os"));
15250
15417
  init_orchestrator();
15251
15418
  init_daemon();
15252
15419
  init_config();
@@ -15254,12 +15421,12 @@ init_policy();
15254
15421
 
15255
15422
  // src/undo.ts
15256
15423
  var import_child_process6 = require("child_process");
15257
- var import_crypto8 = __toESM(require("crypto"));
15258
- var import_fs29 = __toESM(require("fs"));
15424
+ var import_crypto9 = __toESM(require("crypto"));
15425
+ var import_fs30 = __toESM(require("fs"));
15259
15426
  var import_net3 = __toESM(require("net"));
15260
- var import_path30 = __toESM(require("path"));
15261
- var import_os25 = __toESM(require("os"));
15262
- var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path30.default.join(import_os25.default.tmpdir(), "node9-activity.sock");
15427
+ var import_path31 = __toESM(require("path"));
15428
+ var import_os26 = __toESM(require("os"));
15429
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path31.default.join(import_os26.default.tmpdir(), "node9-activity.sock");
15263
15430
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15264
15431
  try {
15265
15432
  const payload = JSON.stringify({
@@ -15279,22 +15446,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15279
15446
  } catch {
15280
15447
  }
15281
15448
  }
15282
- var SNAPSHOT_STACK_PATH = import_path30.default.join(import_os25.default.homedir(), ".node9", "snapshots.json");
15283
- var UNDO_LATEST_PATH = import_path30.default.join(import_os25.default.homedir(), ".node9", "undo_latest.txt");
15449
+ var SNAPSHOT_STACK_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots.json");
15450
+ var UNDO_LATEST_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "undo_latest.txt");
15284
15451
  var MAX_SNAPSHOTS = 10;
15285
15452
  var GIT_TIMEOUT = 15e3;
15286
15453
  function readStack() {
15287
15454
  try {
15288
- if (import_fs29.default.existsSync(SNAPSHOT_STACK_PATH))
15289
- return JSON.parse(import_fs29.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15455
+ if (import_fs30.default.existsSync(SNAPSHOT_STACK_PATH))
15456
+ return JSON.parse(import_fs30.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15290
15457
  } catch {
15291
15458
  }
15292
15459
  return [];
15293
15460
  }
15294
15461
  function writeStack(stack) {
15295
- const dir = import_path30.default.dirname(SNAPSHOT_STACK_PATH);
15296
- if (!import_fs29.default.existsSync(dir)) import_fs29.default.mkdirSync(dir, { recursive: true });
15297
- import_fs29.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
15462
+ const dir = import_path31.default.dirname(SNAPSHOT_STACK_PATH);
15463
+ if (!import_fs30.default.existsSync(dir)) import_fs30.default.mkdirSync(dir, { recursive: true });
15464
+ import_fs30.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
15298
15465
  }
15299
15466
  function extractFilePath(args) {
15300
15467
  if (!args || typeof args !== "object") return null;
@@ -15314,12 +15481,12 @@ function buildArgsSummary(tool, args) {
15314
15481
  return "";
15315
15482
  }
15316
15483
  function findProjectRoot(filePath) {
15317
- let dir = import_path30.default.dirname(filePath);
15484
+ let dir = import_path31.default.dirname(filePath);
15318
15485
  while (true) {
15319
- if (import_fs29.default.existsSync(import_path30.default.join(dir, ".git")) || import_fs29.default.existsSync(import_path30.default.join(dir, "package.json"))) {
15486
+ if (import_fs30.default.existsSync(import_path31.default.join(dir, ".git")) || import_fs30.default.existsSync(import_path31.default.join(dir, "package.json"))) {
15320
15487
  return dir;
15321
15488
  }
15322
- const parent = import_path30.default.dirname(dir);
15489
+ const parent = import_path31.default.dirname(dir);
15323
15490
  if (parent === dir) return process.cwd();
15324
15491
  dir = parent;
15325
15492
  }
@@ -15327,7 +15494,7 @@ function findProjectRoot(filePath) {
15327
15494
  function normalizeCwdForHash(cwd) {
15328
15495
  let normalized;
15329
15496
  try {
15330
- normalized = import_fs29.default.realpathSync(cwd);
15497
+ normalized = import_fs30.default.realpathSync(cwd);
15331
15498
  } catch {
15332
15499
  normalized = cwd;
15333
15500
  }
@@ -15336,17 +15503,17 @@ function normalizeCwdForHash(cwd) {
15336
15503
  return normalized;
15337
15504
  }
15338
15505
  function getShadowRepoDir(cwd) {
15339
- const hash = import_crypto8.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
15340
- return import_path30.default.join(import_os25.default.homedir(), ".node9", "snapshots", hash);
15506
+ const hash = import_crypto9.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
15507
+ return import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots", hash);
15341
15508
  }
15342
15509
  function cleanOrphanedIndexFiles(shadowDir) {
15343
15510
  try {
15344
15511
  const cutoff = Date.now() - 6e4;
15345
- for (const f of import_fs29.default.readdirSync(shadowDir)) {
15512
+ for (const f of import_fs30.default.readdirSync(shadowDir)) {
15346
15513
  if (f.startsWith("index_")) {
15347
- const fp = import_path30.default.join(shadowDir, f);
15514
+ const fp = import_path31.default.join(shadowDir, f);
15348
15515
  try {
15349
- if (import_fs29.default.statSync(fp).mtimeMs < cutoff) import_fs29.default.unlinkSync(fp);
15516
+ if (import_fs30.default.statSync(fp).mtimeMs < cutoff) import_fs30.default.unlinkSync(fp);
15350
15517
  } catch {
15351
15518
  }
15352
15519
  }
@@ -15358,7 +15525,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
15358
15525
  const hardcoded = [".git", ".node9"];
15359
15526
  const lines = [...hardcoded, ...ignorePaths].join("\n");
15360
15527
  try {
15361
- import_fs29.default.writeFileSync(import_path30.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15528
+ import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15362
15529
  } catch {
15363
15530
  }
15364
15531
  }
@@ -15371,25 +15538,25 @@ function ensureShadowRepo(shadowDir, cwd) {
15371
15538
  timeout: 3e3
15372
15539
  });
15373
15540
  if (check.status === 0) {
15374
- const ptPath = import_path30.default.join(shadowDir, "project-path.txt");
15541
+ const ptPath = import_path31.default.join(shadowDir, "project-path.txt");
15375
15542
  try {
15376
- const stored = import_fs29.default.readFileSync(ptPath, "utf8").trim();
15543
+ const stored = import_fs30.default.readFileSync(ptPath, "utf8").trim();
15377
15544
  if (stored === normalizedCwd) return true;
15378
15545
  if (process.env.NODE9_DEBUG === "1")
15379
15546
  console.error(
15380
15547
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
15381
15548
  );
15382
- import_fs29.default.rmSync(shadowDir, { recursive: true, force: true });
15549
+ import_fs30.default.rmSync(shadowDir, { recursive: true, force: true });
15383
15550
  } catch {
15384
15551
  try {
15385
- import_fs29.default.writeFileSync(ptPath, normalizedCwd, "utf8");
15552
+ import_fs30.default.writeFileSync(ptPath, normalizedCwd, "utf8");
15386
15553
  } catch {
15387
15554
  }
15388
15555
  return true;
15389
15556
  }
15390
15557
  }
15391
15558
  try {
15392
- import_fs29.default.mkdirSync(shadowDir, { recursive: true });
15559
+ import_fs30.default.mkdirSync(shadowDir, { recursive: true });
15393
15560
  } catch {
15394
15561
  }
15395
15562
  const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -15398,7 +15565,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15398
15565
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
15399
15566
  return false;
15400
15567
  }
15401
- const configFile = import_path30.default.join(shadowDir, "config");
15568
+ const configFile = import_path31.default.join(shadowDir, "config");
15402
15569
  (0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
15403
15570
  timeout: 3e3
15404
15571
  });
@@ -15406,7 +15573,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15406
15573
  timeout: 3e3
15407
15574
  });
15408
15575
  try {
15409
- import_fs29.default.writeFileSync(import_path30.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15576
+ import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15410
15577
  } catch {
15411
15578
  }
15412
15579
  return true;
@@ -15429,12 +15596,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15429
15596
  let indexFile = null;
15430
15597
  try {
15431
15598
  const rawFilePath = extractFilePath(args);
15432
- const absFilePath = rawFilePath && import_path30.default.isAbsolute(rawFilePath) ? rawFilePath : null;
15599
+ const absFilePath = rawFilePath && import_path31.default.isAbsolute(rawFilePath) ? rawFilePath : null;
15433
15600
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
15434
15601
  const shadowDir = getShadowRepoDir(cwd);
15435
15602
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
15436
15603
  writeShadowExcludes(shadowDir, ignorePaths);
15437
- indexFile = import_path30.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15604
+ indexFile = import_path31.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15438
15605
  const shadowEnv = {
15439
15606
  ...process.env,
15440
15607
  GIT_DIR: shadowDir,
@@ -15506,7 +15673,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15506
15673
  writeStack(stack);
15507
15674
  const entry = stack[stack.length - 1];
15508
15675
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
15509
- import_fs29.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
15676
+ import_fs30.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
15510
15677
  if (shouldGc) {
15511
15678
  (0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
15512
15679
  }
@@ -15517,7 +15684,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15517
15684
  } finally {
15518
15685
  if (indexFile) {
15519
15686
  try {
15520
- import_fs29.default.unlinkSync(indexFile);
15687
+ import_fs30.default.unlinkSync(indexFile);
15521
15688
  } catch {
15522
15689
  }
15523
15690
  }
@@ -15593,9 +15760,9 @@ function applyUndo(hash, cwd) {
15593
15760
  timeout: GIT_TIMEOUT
15594
15761
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
15595
15762
  for (const file of [...tracked, ...untracked]) {
15596
- const fullPath = import_path30.default.join(dir, file);
15597
- if (!snapshotFiles.has(file) && import_fs29.default.existsSync(fullPath)) {
15598
- import_fs29.default.unlinkSync(fullPath);
15763
+ const fullPath = import_path31.default.join(dir, file);
15764
+ if (!snapshotFiles.has(file) && import_fs30.default.existsSync(fullPath)) {
15765
+ import_fs30.default.unlinkSync(fullPath);
15599
15766
  }
15600
15767
  }
15601
15768
  return true;
@@ -15605,17 +15772,17 @@ function applyUndo(hash, cwd) {
15605
15772
  }
15606
15773
 
15607
15774
  // src/skill-pin.ts
15608
- var import_fs30 = __toESM(require("fs"));
15609
- var import_path31 = __toESM(require("path"));
15610
- var import_os26 = __toESM(require("os"));
15611
- var import_crypto9 = __toESM(require("crypto"));
15612
- function getPinsFilePath() {
15613
- return import_path31.default.join(import_os26.default.homedir(), ".node9", "skill-pins.json");
15775
+ var import_fs31 = __toESM(require("fs"));
15776
+ var import_path32 = __toESM(require("path"));
15777
+ var import_os27 = __toESM(require("os"));
15778
+ var import_crypto10 = __toESM(require("crypto"));
15779
+ function getPinsFilePath2() {
15780
+ return import_path32.default.join(import_os27.default.homedir(), ".node9", "skill-pins.json");
15614
15781
  }
15615
15782
  var MAX_FILES = 5e3;
15616
15783
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
15617
15784
  function sha256Bytes(buf) {
15618
- return import_crypto9.default.createHash("sha256").update(buf).digest("hex");
15785
+ return import_crypto10.default.createHash("sha256").update(buf).digest("hex");
15619
15786
  }
15620
15787
  function walkDir(root) {
15621
15788
  const out = [];
@@ -15624,18 +15791,18 @@ function walkDir(root) {
15624
15791
  if (out.length >= MAX_FILES) return;
15625
15792
  let entries;
15626
15793
  try {
15627
- entries = import_fs30.default.readdirSync(dir, { withFileTypes: true });
15794
+ entries = import_fs31.default.readdirSync(dir, { withFileTypes: true });
15628
15795
  } catch {
15629
15796
  return;
15630
15797
  }
15631
15798
  entries.sort((a, b) => a.name.localeCompare(b.name));
15632
15799
  for (const entry of entries) {
15633
15800
  if (out.length >= MAX_FILES) return;
15634
- const full = import_path31.default.join(dir, entry.name);
15635
- const rel = relDir ? import_path31.default.posix.join(relDir, entry.name) : entry.name;
15801
+ const full = import_path32.default.join(dir, entry.name);
15802
+ const rel = relDir ? import_path32.default.posix.join(relDir, entry.name) : entry.name;
15636
15803
  let lst;
15637
15804
  try {
15638
- lst = import_fs30.default.lstatSync(full);
15805
+ lst = import_fs31.default.lstatSync(full);
15639
15806
  } catch {
15640
15807
  continue;
15641
15808
  }
@@ -15647,7 +15814,7 @@ function walkDir(root) {
15647
15814
  if (!lst.isFile()) continue;
15648
15815
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
15649
15816
  try {
15650
- const buf = import_fs30.default.readFileSync(full);
15817
+ const buf = import_fs31.default.readFileSync(full);
15651
15818
  totalBytes += buf.length;
15652
15819
  out.push({ rel, hash: sha256Bytes(buf) });
15653
15820
  } catch {
@@ -15661,32 +15828,32 @@ function walkDir(root) {
15661
15828
  function hashSkillRoot(absPath) {
15662
15829
  let lst;
15663
15830
  try {
15664
- lst = import_fs30.default.lstatSync(absPath);
15831
+ lst = import_fs31.default.lstatSync(absPath);
15665
15832
  } catch {
15666
15833
  return { exists: false, contentHash: "", fileCount: 0 };
15667
15834
  }
15668
15835
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
15669
15836
  if (lst.isFile()) {
15670
15837
  try {
15671
- return { exists: true, contentHash: sha256Bytes(import_fs30.default.readFileSync(absPath)), fileCount: 1 };
15838
+ return { exists: true, contentHash: sha256Bytes(import_fs31.default.readFileSync(absPath)), fileCount: 1 };
15672
15839
  } catch {
15673
15840
  return { exists: false, contentHash: "", fileCount: 0 };
15674
15841
  }
15675
15842
  }
15676
15843
  if (lst.isDirectory()) {
15677
15844
  const entries = walkDir(absPath);
15678
- const contentHash = import_crypto9.default.createHash("sha256").update(entries.join("\n")).digest("hex");
15845
+ const contentHash = import_crypto10.default.createHash("sha256").update(entries.join("\n")).digest("hex");
15679
15846
  return { exists: true, contentHash, fileCount: entries.length };
15680
15847
  }
15681
15848
  return { exists: false, contentHash: "", fileCount: 0 };
15682
15849
  }
15683
15850
  function getRootKey(absPath) {
15684
- return import_crypto9.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15851
+ return import_crypto10.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15685
15852
  }
15686
15853
  function readSkillPinsSafe() {
15687
- const filePath = getPinsFilePath();
15854
+ const filePath = getPinsFilePath2();
15688
15855
  try {
15689
- const raw = import_fs30.default.readFileSync(filePath, "utf-8");
15856
+ const raw = import_fs31.default.readFileSync(filePath, "utf-8");
15690
15857
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
15691
15858
  const parsed = JSON.parse(raw);
15692
15859
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -15705,18 +15872,18 @@ function readSkillPins() {
15705
15872
  throw new Error(`[node9] skill pin file is corrupt: ${result.detail}`);
15706
15873
  }
15707
15874
  function writeSkillPins(data) {
15708
- const filePath = getPinsFilePath();
15709
- import_fs30.default.mkdirSync(import_path31.default.dirname(filePath), { recursive: true });
15710
- const tmp = `${filePath}.${import_crypto9.default.randomBytes(6).toString("hex")}.tmp`;
15711
- import_fs30.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15712
- import_fs30.default.renameSync(tmp, filePath);
15875
+ const filePath = getPinsFilePath2();
15876
+ import_fs31.default.mkdirSync(import_path32.default.dirname(filePath), { recursive: true });
15877
+ const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
15878
+ import_fs31.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15879
+ import_fs31.default.renameSync(tmp, filePath);
15713
15880
  }
15714
- function removePin(rootKey) {
15881
+ function removePin2(rootKey) {
15715
15882
  const pins = readSkillPins();
15716
15883
  delete pins.roots[rootKey];
15717
15884
  writeSkillPins(pins);
15718
15885
  }
15719
- function clearAllPins() {
15886
+ function clearAllPins2() {
15720
15887
  writeSkillPins({ roots: {} });
15721
15888
  }
15722
15889
  function verifyAndPinRoots(roots) {
@@ -15753,36 +15920,36 @@ function verifyAndPinRoots(roots) {
15753
15920
  return { kind: "verified" };
15754
15921
  }
15755
15922
  function defaultSkillRoots(_cwd) {
15756
- const marketplaces = import_path31.default.join(import_os26.default.homedir(), ".claude", "plugins", "marketplaces");
15923
+ const marketplaces = import_path32.default.join(import_os27.default.homedir(), ".claude", "plugins", "marketplaces");
15757
15924
  const roots = [];
15758
15925
  let registries;
15759
15926
  try {
15760
- registries = import_fs30.default.readdirSync(marketplaces, { withFileTypes: true });
15927
+ registries = import_fs31.default.readdirSync(marketplaces, { withFileTypes: true });
15761
15928
  } catch {
15762
15929
  return [];
15763
15930
  }
15764
15931
  for (const registry of registries) {
15765
15932
  if (!registry.isDirectory()) continue;
15766
- const pluginsDir = import_path31.default.join(marketplaces, registry.name, "plugins");
15933
+ const pluginsDir = import_path32.default.join(marketplaces, registry.name, "plugins");
15767
15934
  let plugins;
15768
15935
  try {
15769
- plugins = import_fs30.default.readdirSync(pluginsDir, { withFileTypes: true });
15936
+ plugins = import_fs31.default.readdirSync(pluginsDir, { withFileTypes: true });
15770
15937
  } catch {
15771
15938
  continue;
15772
15939
  }
15773
15940
  for (const plugin of plugins) {
15774
15941
  if (!plugin.isDirectory()) continue;
15775
- roots.push(import_path31.default.join(pluginsDir, plugin.name));
15942
+ roots.push(import_path32.default.join(pluginsDir, plugin.name));
15776
15943
  }
15777
15944
  }
15778
15945
  return roots;
15779
15946
  }
15780
15947
  function resolveUserSkillRoot(entry, cwd) {
15781
15948
  if (!entry) return null;
15782
- if (entry.startsWith("~/") || entry === "~") return import_path31.default.join(import_os26.default.homedir(), entry.slice(1));
15783
- if (import_path31.default.isAbsolute(entry)) return entry;
15784
- if (!cwd || !import_path31.default.isAbsolute(cwd)) return null;
15785
- return import_path31.default.join(cwd, entry);
15949
+ if (entry.startsWith("~/") || entry === "~") return import_path32.default.join(import_os27.default.homedir(), entry.slice(1));
15950
+ if (import_path32.default.isAbsolute(entry)) return entry;
15951
+ if (!cwd || !import_path32.default.isAbsolute(cwd)) return null;
15952
+ return import_path32.default.join(cwd, entry);
15786
15953
  }
15787
15954
 
15788
15955
  // src/cli/commands/check.ts
@@ -15829,9 +15996,9 @@ function registerCheckCommand(program2) {
15829
15996
  } catch (err2) {
15830
15997
  const tempConfig = getConfig();
15831
15998
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
15832
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
15999
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
15833
16000
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
15834
- import_fs31.default.appendFileSync(
16001
+ import_fs32.default.appendFileSync(
15835
16002
  logPath,
15836
16003
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
15837
16004
  RAW: ${raw}
@@ -15844,14 +16011,14 @@ RAW: ${raw}
15844
16011
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
15845
16012
  if (process.env.NODE9_DEBUG === "1") {
15846
16013
  try {
15847
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
15848
- if (!import_fs31.default.existsSync(import_path32.default.dirname(logPath)))
15849
- import_fs31.default.mkdirSync(import_path32.default.dirname(logPath), { recursive: true });
16014
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16015
+ if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
16016
+ import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
15850
16017
  const sanitized = JSON.stringify({
15851
16018
  ...payload,
15852
16019
  prompt: `<redacted, ${prompt.length} bytes>`
15853
16020
  });
15854
- import_fs31.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
16021
+ import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
15855
16022
  `);
15856
16023
  } catch {
15857
16024
  }
@@ -15871,8 +16038,8 @@ RAW: ${raw}
15871
16038
  );
15872
16039
  const reason = `\u{1F6A8} Node9 DLP: ${dlpMatch.patternName} detected in prompt (${dlpMatch.redactedSample}). Prompt was not submitted \u2014 remove the credential and try again.`;
15873
16040
  try {
15874
- const ttyFd = import_fs31.default.openSync("/dev/tty", "w");
15875
- import_fs31.default.writeSync(
16041
+ const ttyFd = import_fs32.default.openSync("/dev/tty", "w");
16042
+ import_fs32.default.writeSync(
15876
16043
  ttyFd,
15877
16044
  import_chalk9.default.bgRed.white.bold(`
15878
16045
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -15882,7 +16049,7 @@ RAW: ${raw}
15882
16049
 
15883
16050
  `)
15884
16051
  );
15885
- import_fs31.default.closeSync(ttyFd);
16052
+ import_fs32.default.closeSync(ttyFd);
15886
16053
  } catch {
15887
16054
  }
15888
16055
  const isCodex = agent2 === "Codex";
@@ -15900,16 +16067,16 @@ RAW: ${raw}
15900
16067
  );
15901
16068
  process.exit(2);
15902
16069
  }
15903
- const safeCwdForConfig = typeof payload.cwd === "string" && import_path32.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16070
+ const safeCwdForConfig = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15904
16071
  const config = getConfig(safeCwdForConfig);
15905
16072
  if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
15906
16073
  try {
15907
16074
  const scriptPath = process.argv[1];
15908
- if (typeof scriptPath !== "string" || !import_path32.default.isAbsolute(scriptPath))
16075
+ if (typeof scriptPath !== "string" || !import_path33.default.isAbsolute(scriptPath))
15909
16076
  throw new Error("node9: argv[1] is not an absolute path");
15910
- const resolvedScript = import_fs31.default.realpathSync(scriptPath);
15911
- const packageDist = import_fs31.default.realpathSync(import_path32.default.resolve(__dirname, "../.."));
15912
- if (!resolvedScript.startsWith(packageDist + import_path32.default.sep) && resolvedScript !== packageDist)
16077
+ const resolvedScript = import_fs32.default.realpathSync(scriptPath);
16078
+ const packageDist = import_fs32.default.realpathSync(import_path33.default.resolve(__dirname, "../.."));
16079
+ if (!resolvedScript.startsWith(packageDist + import_path33.default.sep) && resolvedScript !== packageDist)
15913
16080
  throw new Error(
15914
16081
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
15915
16082
  );
@@ -15931,10 +16098,10 @@ RAW: ${raw}
15931
16098
  });
15932
16099
  d.unref();
15933
16100
  } catch (spawnErr) {
15934
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
16101
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
15935
16102
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
15936
16103
  try {
15937
- import_fs31.default.appendFileSync(
16104
+ import_fs32.default.appendFileSync(
15938
16105
  logPath,
15939
16106
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
15940
16107
  `
@@ -15944,10 +16111,10 @@ RAW: ${raw}
15944
16111
  }
15945
16112
  }
15946
16113
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
15947
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
15948
- if (!import_fs31.default.existsSync(import_path32.default.dirname(logPath)))
15949
- import_fs31.default.mkdirSync(import_path32.default.dirname(logPath), { recursive: true });
15950
- import_fs31.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
16114
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16115
+ if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
16116
+ import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
16117
+ import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
15951
16118
  `);
15952
16119
  }
15953
16120
  const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
@@ -15960,8 +16127,8 @@ RAW: ${raw}
15960
16127
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
15961
16128
  let ttyFd = null;
15962
16129
  try {
15963
- ttyFd = import_fs31.default.openSync("/dev/tty", "w");
15964
- const writeTty = (line) => import_fs31.default.writeSync(ttyFd, line + "\n");
16130
+ ttyFd = import_fs32.default.openSync("/dev/tty", "w");
16131
+ const writeTty = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
15965
16132
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
15966
16133
  writeTty(import_chalk9.default.bgRed.white.bold(`
15967
16134
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -15980,7 +16147,7 @@ RAW: ${raw}
15980
16147
  } finally {
15981
16148
  if (ttyFd !== null)
15982
16149
  try {
15983
- import_fs31.default.closeSync(ttyFd);
16150
+ import_fs32.default.closeSync(ttyFd);
15984
16151
  } catch {
15985
16152
  }
15986
16153
  }
@@ -16016,17 +16183,17 @@ RAW: ${raw}
16016
16183
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
16017
16184
  if (skillPinCfg.enabled && safeSessionId) {
16018
16185
  try {
16019
- const sessionsDir = import_path32.default.join(import_os27.default.homedir(), ".node9", "skill-sessions");
16020
- const flagPath = import_path32.default.join(sessionsDir, `${safeSessionId}.json`);
16186
+ const sessionsDir = import_path33.default.join(import_os28.default.homedir(), ".node9", "skill-sessions");
16187
+ const flagPath = import_path33.default.join(sessionsDir, `${safeSessionId}.json`);
16021
16188
  let flag = null;
16022
16189
  try {
16023
- flag = JSON.parse(import_fs31.default.readFileSync(flagPath, "utf-8"));
16190
+ flag = JSON.parse(import_fs32.default.readFileSync(flagPath, "utf-8"));
16024
16191
  } catch {
16025
16192
  }
16026
16193
  const writeFlag = (data2) => {
16027
16194
  try {
16028
- import_fs31.default.mkdirSync(sessionsDir, { recursive: true });
16029
- import_fs31.default.writeFileSync(
16195
+ import_fs32.default.mkdirSync(sessionsDir, { recursive: true });
16196
+ import_fs32.default.writeFileSync(
16030
16197
  flagPath,
16031
16198
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
16032
16199
  { mode: 384 }
@@ -16037,8 +16204,8 @@ RAW: ${raw}
16037
16204
  const sendSkillWarn = (detail, recoveryCmd) => {
16038
16205
  let ttyFd = null;
16039
16206
  try {
16040
- ttyFd = import_fs31.default.openSync("/dev/tty", "w");
16041
- const w = (line) => import_fs31.default.writeSync(ttyFd, line + "\n");
16207
+ ttyFd = import_fs32.default.openSync("/dev/tty", "w");
16208
+ const w = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
16042
16209
  w(import_chalk9.default.yellow(`
16043
16210
  \u26A0\uFE0F Node9: installed skill drift detected`));
16044
16211
  w(import_chalk9.default.gray(` ${detail}`));
@@ -16053,7 +16220,7 @@ RAW: ${raw}
16053
16220
  } finally {
16054
16221
  if (ttyFd !== null)
16055
16222
  try {
16056
- import_fs31.default.closeSync(ttyFd);
16223
+ import_fs32.default.closeSync(ttyFd);
16057
16224
  } catch {
16058
16225
  }
16059
16226
  }
@@ -16069,7 +16236,7 @@ RAW: ${raw}
16069
16236
  return;
16070
16237
  }
16071
16238
  if (!flag || flag.state !== "verified" && flag.state !== "warned") {
16072
- const absoluteCwd = typeof payload.cwd === "string" && import_path32.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16239
+ const absoluteCwd = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16073
16240
  const extraRoots = skillPinCfg.roots;
16074
16241
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
16075
16242
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -16110,10 +16277,10 @@ RAW: ${raw}
16110
16277
  }
16111
16278
  try {
16112
16279
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
16113
- for (const name of import_fs31.default.readdirSync(sessionsDir)) {
16114
- const p = import_path32.default.join(sessionsDir, name);
16280
+ for (const name of import_fs32.default.readdirSync(sessionsDir)) {
16281
+ const p = import_path33.default.join(sessionsDir, name);
16115
16282
  try {
16116
- if (import_fs31.default.statSync(p).mtimeMs < cutoff) import_fs31.default.unlinkSync(p);
16283
+ if (import_fs32.default.statSync(p).mtimeMs < cutoff) import_fs32.default.unlinkSync(p);
16117
16284
  } catch {
16118
16285
  }
16119
16286
  }
@@ -16123,9 +16290,9 @@ RAW: ${raw}
16123
16290
  } catch (err2) {
16124
16291
  if (process.env.NODE9_DEBUG === "1") {
16125
16292
  try {
16126
- const dbg = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
16293
+ const dbg = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16127
16294
  const msg = err2 instanceof Error ? err2.message : String(err2);
16128
- import_fs31.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16295
+ import_fs32.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16129
16296
  `);
16130
16297
  } catch {
16131
16298
  }
@@ -16135,7 +16302,7 @@ RAW: ${raw}
16135
16302
  if (shouldSnapshot(toolName, toolInput, config)) {
16136
16303
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
16137
16304
  }
16138
- const safeCwdForAuth = typeof payload.cwd === "string" && import_path32.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16305
+ const safeCwdForAuth = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16139
16306
  const result = await authorizeHeadless(toolName, toolInput, meta, {
16140
16307
  cwd: safeCwdForAuth
16141
16308
  });
@@ -16147,12 +16314,12 @@ RAW: ${raw}
16147
16314
  }
16148
16315
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
16149
16316
  try {
16150
- const tty = import_fs31.default.openSync("/dev/tty", "w");
16151
- import_fs31.default.writeSync(
16317
+ const tty = import_fs32.default.openSync("/dev/tty", "w");
16318
+ import_fs32.default.writeSync(
16152
16319
  tty,
16153
16320
  import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
16154
16321
  );
16155
- import_fs31.default.closeSync(tty);
16322
+ import_fs32.default.closeSync(tty);
16156
16323
  } catch {
16157
16324
  }
16158
16325
  const daemonReady = await autoStartDaemonAndWait();
@@ -16179,9 +16346,9 @@ RAW: ${raw}
16179
16346
  });
16180
16347
  } catch (err2) {
16181
16348
  if (process.env.NODE9_DEBUG === "1") {
16182
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
16349
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16183
16350
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
16184
- import_fs31.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16351
+ import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16185
16352
  `);
16186
16353
  }
16187
16354
  process.exit(0);
@@ -16215,9 +16382,9 @@ RAW: ${raw}
16215
16382
  }
16216
16383
 
16217
16384
  // src/cli/commands/log.ts
16218
- var import_fs32 = __toESM(require("fs"));
16219
- var import_path33 = __toESM(require("path"));
16220
- var import_os28 = __toESM(require("os"));
16385
+ var import_fs33 = __toESM(require("fs"));
16386
+ var import_path34 = __toESM(require("path"));
16387
+ var import_os29 = __toESM(require("os"));
16221
16388
  init_audit();
16222
16389
  init_config();
16223
16390
  init_daemon();
@@ -16295,10 +16462,10 @@ function registerLogCommand(program2) {
16295
16462
  };
16296
16463
  if (agent) entry.agent = agent;
16297
16464
  if (payload.session_id) entry.sessionId = payload.session_id;
16298
- const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "audit.log");
16299
- if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
16300
- import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
16301
- import_fs32.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
16465
+ const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "audit.log");
16466
+ if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
16467
+ import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
16468
+ import_fs33.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
16302
16469
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
16303
16470
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
16304
16471
  if (command) {
@@ -16331,7 +16498,7 @@ function registerLogCommand(program2) {
16331
16498
  }
16332
16499
  }
16333
16500
  }
16334
- const safeCwd = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16501
+ const safeCwd = typeof payload.cwd === "string" && import_path34.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16335
16502
  const config = getConfig(safeCwd);
16336
16503
  if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
16337
16504
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
@@ -16352,9 +16519,9 @@ function registerLogCommand(program2) {
16352
16519
  const msg = err2 instanceof Error ? err2.message : String(err2);
16353
16520
  process.stderr.write(`[Node9] audit log error: ${msg}
16354
16521
  `);
16355
- const debugPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16522
+ const debugPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
16356
16523
  try {
16357
- import_fs32.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16524
+ import_fs33.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16358
16525
  `);
16359
16526
  } catch {
16360
16527
  }
@@ -16754,14 +16921,14 @@ function registerConfigShowCommand(program2) {
16754
16921
 
16755
16922
  // src/cli/commands/doctor.ts
16756
16923
  var import_chalk11 = __toESM(require("chalk"));
16757
- var import_fs33 = __toESM(require("fs"));
16758
- var import_path34 = __toESM(require("path"));
16759
- var import_os29 = __toESM(require("os"));
16924
+ var import_fs34 = __toESM(require("fs"));
16925
+ var import_path35 = __toESM(require("path"));
16926
+ var import_os30 = __toESM(require("os"));
16760
16927
  var import_child_process8 = require("child_process");
16761
16928
  init_daemon();
16762
16929
  function registerDoctorCommand(program2, version2) {
16763
16930
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
16764
- const homeDir2 = import_os29.default.homedir();
16931
+ const homeDir2 = import_os30.default.homedir();
16765
16932
  let failures = 0;
16766
16933
  function pass(msg) {
16767
16934
  console.log(import_chalk11.default.green(" \u2705 ") + msg);
@@ -16810,10 +16977,10 @@ function registerDoctorCommand(program2, version2) {
16810
16977
  );
16811
16978
  }
16812
16979
  section("Configuration");
16813
- const globalConfigPath = import_path34.default.join(homeDir2, ".node9", "config.json");
16814
- if (import_fs33.default.existsSync(globalConfigPath)) {
16980
+ const globalConfigPath = import_path35.default.join(homeDir2, ".node9", "config.json");
16981
+ if (import_fs34.default.existsSync(globalConfigPath)) {
16815
16982
  try {
16816
- JSON.parse(import_fs33.default.readFileSync(globalConfigPath, "utf-8"));
16983
+ JSON.parse(import_fs34.default.readFileSync(globalConfigPath, "utf-8"));
16817
16984
  pass("~/.node9/config.json found and valid");
16818
16985
  } catch {
16819
16986
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -16821,10 +16988,10 @@ function registerDoctorCommand(program2, version2) {
16821
16988
  } else {
16822
16989
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
16823
16990
  }
16824
- const projectConfigPath = import_path34.default.join(process.cwd(), "node9.config.json");
16825
- if (import_fs33.default.existsSync(projectConfigPath)) {
16991
+ const projectConfigPath = import_path35.default.join(process.cwd(), "node9.config.json");
16992
+ if (import_fs34.default.existsSync(projectConfigPath)) {
16826
16993
  try {
16827
- JSON.parse(import_fs33.default.readFileSync(projectConfigPath, "utf-8"));
16994
+ JSON.parse(import_fs34.default.readFileSync(projectConfigPath, "utf-8"));
16828
16995
  pass("node9.config.json found and valid (project)");
16829
16996
  } catch {
16830
16997
  fail(
@@ -16833,8 +17000,8 @@ function registerDoctorCommand(program2, version2) {
16833
17000
  );
16834
17001
  }
16835
17002
  }
16836
- const credsPath = import_path34.default.join(homeDir2, ".node9", "credentials.json");
16837
- if (import_fs33.default.existsSync(credsPath)) {
17003
+ const credsPath = import_path35.default.join(homeDir2, ".node9", "credentials.json");
17004
+ if (import_fs34.default.existsSync(credsPath)) {
16838
17005
  pass("Cloud credentials found (~/.node9/credentials.json)");
16839
17006
  } else {
16840
17007
  warn(
@@ -16843,10 +17010,10 @@ function registerDoctorCommand(program2, version2) {
16843
17010
  );
16844
17011
  }
16845
17012
  section("Agent Hooks");
16846
- const claudeSettingsPath = import_path34.default.join(homeDir2, ".claude", "settings.json");
16847
- if (import_fs33.default.existsSync(claudeSettingsPath)) {
17013
+ const claudeSettingsPath = import_path35.default.join(homeDir2, ".claude", "settings.json");
17014
+ if (import_fs34.default.existsSync(claudeSettingsPath)) {
16848
17015
  try {
16849
- const cs = JSON.parse(import_fs33.default.readFileSync(claudeSettingsPath, "utf-8"));
17016
+ const cs = JSON.parse(import_fs34.default.readFileSync(claudeSettingsPath, "utf-8"));
16850
17017
  const hasHook = cs.hooks?.PreToolUse?.some(
16851
17018
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16852
17019
  );
@@ -16862,10 +17029,10 @@ function registerDoctorCommand(program2, version2) {
16862
17029
  } else {
16863
17030
  warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
16864
17031
  }
16865
- const geminiSettingsPath = import_path34.default.join(homeDir2, ".gemini", "settings.json");
16866
- if (import_fs33.default.existsSync(geminiSettingsPath)) {
17032
+ const geminiSettingsPath = import_path35.default.join(homeDir2, ".gemini", "settings.json");
17033
+ if (import_fs34.default.existsSync(geminiSettingsPath)) {
16867
17034
  try {
16868
- const gs = JSON.parse(import_fs33.default.readFileSync(geminiSettingsPath, "utf-8"));
17035
+ const gs = JSON.parse(import_fs34.default.readFileSync(geminiSettingsPath, "utf-8"));
16869
17036
  const hasHook = gs.hooks?.BeforeTool?.some(
16870
17037
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16871
17038
  );
@@ -16881,10 +17048,10 @@ function registerDoctorCommand(program2, version2) {
16881
17048
  } else {
16882
17049
  warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
16883
17050
  }
16884
- const cursorHooksPath = import_path34.default.join(homeDir2, ".cursor", "hooks.json");
16885
- if (import_fs33.default.existsSync(cursorHooksPath)) {
17051
+ const cursorHooksPath = import_path35.default.join(homeDir2, ".cursor", "hooks.json");
17052
+ if (import_fs34.default.existsSync(cursorHooksPath)) {
16886
17053
  try {
16887
- const cur = JSON.parse(import_fs33.default.readFileSync(cursorHooksPath, "utf-8"));
17054
+ const cur = JSON.parse(import_fs34.default.readFileSync(cursorHooksPath, "utf-8"));
16888
17055
  const hasHook = cur.hooks?.preToolUse?.some(
16889
17056
  (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
16890
17057
  );
@@ -16924,9 +17091,9 @@ function registerDoctorCommand(program2, version2) {
16924
17091
 
16925
17092
  // src/cli/commands/audit.ts
16926
17093
  var import_chalk12 = __toESM(require("chalk"));
16927
- var import_fs34 = __toESM(require("fs"));
16928
- var import_path35 = __toESM(require("path"));
16929
- var import_os30 = __toESM(require("os"));
17094
+ var import_fs35 = __toESM(require("fs"));
17095
+ var import_path36 = __toESM(require("path"));
17096
+ var import_os31 = __toESM(require("os"));
16930
17097
  function formatRelativeTime(timestamp) {
16931
17098
  const diff = Date.now() - new Date(timestamp).getTime();
16932
17099
  const sec = Math.floor(diff / 1e3);
@@ -16939,14 +17106,14 @@ function formatRelativeTime(timestamp) {
16939
17106
  }
16940
17107
  function registerAuditCommand(program2) {
16941
17108
  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) => {
16942
- const logPath = import_path35.default.join(import_os30.default.homedir(), ".node9", "audit.log");
16943
- if (!import_fs34.default.existsSync(logPath)) {
17109
+ const logPath = import_path36.default.join(import_os31.default.homedir(), ".node9", "audit.log");
17110
+ if (!import_fs35.default.existsSync(logPath)) {
16944
17111
  console.log(
16945
17112
  import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
16946
17113
  );
16947
17114
  return;
16948
17115
  }
16949
- const raw = import_fs34.default.readFileSync(logPath, "utf-8");
17116
+ const raw = import_fs35.default.readFileSync(logPath, "utf-8");
16950
17117
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
16951
17118
  let entries = lines.flatMap((line) => {
16952
17119
  try {
@@ -17002,9 +17169,9 @@ function registerAuditCommand(program2) {
17002
17169
  var import_chalk13 = __toESM(require("chalk"));
17003
17170
 
17004
17171
  // src/cli/aggregate/report-audit.ts
17005
- var import_fs35 = __toESM(require("fs"));
17006
- var import_os31 = __toESM(require("os"));
17007
- var import_path36 = __toESM(require("path"));
17172
+ var import_fs36 = __toESM(require("fs"));
17173
+ var import_os32 = __toESM(require("os"));
17174
+ var import_path37 = __toESM(require("path"));
17008
17175
  init_costSync();
17009
17176
  init_litellm();
17010
17177
  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;
@@ -17086,8 +17253,8 @@ function getDateRange(period, now) {
17086
17253
  }
17087
17254
  }
17088
17255
  function parseAuditLog(logPath) {
17089
- if (!import_fs35.default.existsSync(logPath)) return [];
17090
- const raw = import_fs35.default.readFileSync(logPath, "utf-8");
17256
+ if (!import_fs36.default.existsSync(logPath)) return [];
17257
+ const raw = import_fs36.default.readFileSync(logPath, "utf-8");
17091
17258
  return raw.split("\n").flatMap((line) => {
17092
17259
  if (!line.trim()) return [];
17093
17260
  try {
@@ -17147,25 +17314,25 @@ function freezeClaudeCost(acc) {
17147
17314
  };
17148
17315
  }
17149
17316
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17150
- const projPath = import_path36.default.join(projectsDir, proj);
17317
+ const projPath = import_path37.default.join(projectsDir, proj);
17151
17318
  let files;
17152
17319
  try {
17153
- const stat = import_fs35.default.statSync(projPath);
17320
+ const stat = import_fs36.default.statSync(projPath);
17154
17321
  if (!stat.isDirectory()) return;
17155
- files = import_fs35.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17322
+ files = import_fs36.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17156
17323
  } catch {
17157
17324
  return;
17158
17325
  }
17159
17326
  const startMs = start.getTime();
17160
17327
  for (const file of files) {
17161
- const filePath = import_path36.default.join(projPath, file);
17328
+ const filePath = import_path37.default.join(projPath, file);
17162
17329
  try {
17163
- if (import_fs35.default.statSync(filePath).mtimeMs < startMs) continue;
17330
+ if (import_fs36.default.statSync(filePath).mtimeMs < startMs) continue;
17164
17331
  } catch {
17165
17332
  continue;
17166
17333
  }
17167
17334
  try {
17168
- const raw = import_fs35.default.readFileSync(filePath, "utf-8");
17335
+ const raw = import_fs36.default.readFileSync(filePath, "utf-8");
17169
17336
  for (const line of raw.split("\n")) {
17170
17337
  if (!line.trim()) continue;
17171
17338
  let entry;
@@ -17215,10 +17382,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17215
17382
  }
17216
17383
  function loadClaudeCost(start, end, projectsDir) {
17217
17384
  const acc = emptyClaudeCostAccumulator();
17218
- if (!import_fs35.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
17385
+ if (!import_fs36.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
17219
17386
  let dirs;
17220
17387
  try {
17221
- dirs = import_fs35.default.readdirSync(projectsDir);
17388
+ dirs = import_fs36.default.readdirSync(projectsDir);
17222
17389
  } catch {
17223
17390
  return freezeClaudeCost(acc);
17224
17391
  }
@@ -17230,7 +17397,7 @@ function loadClaudeCost(start, end, projectsDir) {
17230
17397
  function processCodexCostFile(filePath, start, end, acc) {
17231
17398
  let lines;
17232
17399
  try {
17233
- lines = import_fs35.default.readFileSync(filePath, "utf-8").split("\n");
17400
+ lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
17234
17401
  } catch {
17235
17402
  return;
17236
17403
  }
@@ -17275,31 +17442,31 @@ function processCodexCostFile(filePath, start, end, acc) {
17275
17442
  }
17276
17443
  function listCodexSessionFiles(sessionsBase) {
17277
17444
  const jsonlFiles = [];
17278
- if (!import_fs35.default.existsSync(sessionsBase)) return jsonlFiles;
17445
+ if (!import_fs36.default.existsSync(sessionsBase)) return jsonlFiles;
17279
17446
  try {
17280
- for (const year of import_fs35.default.readdirSync(sessionsBase)) {
17281
- const yearPath = import_path36.default.join(sessionsBase, year);
17447
+ for (const year of import_fs36.default.readdirSync(sessionsBase)) {
17448
+ const yearPath = import_path37.default.join(sessionsBase, year);
17282
17449
  try {
17283
- if (!import_fs35.default.statSync(yearPath).isDirectory()) continue;
17450
+ if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
17284
17451
  } catch {
17285
17452
  continue;
17286
17453
  }
17287
- for (const month of import_fs35.default.readdirSync(yearPath)) {
17288
- const monthPath = import_path36.default.join(yearPath, month);
17454
+ for (const month of import_fs36.default.readdirSync(yearPath)) {
17455
+ const monthPath = import_path37.default.join(yearPath, month);
17289
17456
  try {
17290
- if (!import_fs35.default.statSync(monthPath).isDirectory()) continue;
17457
+ if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
17291
17458
  } catch {
17292
17459
  continue;
17293
17460
  }
17294
- for (const day of import_fs35.default.readdirSync(monthPath)) {
17295
- const dayPath = import_path36.default.join(monthPath, day);
17461
+ for (const day of import_fs36.default.readdirSync(monthPath)) {
17462
+ const dayPath = import_path37.default.join(monthPath, day);
17296
17463
  try {
17297
- if (!import_fs35.default.statSync(dayPath).isDirectory()) continue;
17464
+ if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
17298
17465
  } catch {
17299
17466
  continue;
17300
17467
  }
17301
- for (const file of import_fs35.default.readdirSync(dayPath)) {
17302
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path36.default.join(dayPath, file));
17468
+ for (const file of import_fs36.default.readdirSync(dayPath)) {
17469
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path37.default.join(dayPath, file));
17303
17470
  }
17304
17471
  }
17305
17472
  }
@@ -17352,13 +17519,13 @@ function freezeGeminiCost(acc) {
17352
17519
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
17353
17520
  const startMs = start.getTime();
17354
17521
  try {
17355
- if (import_fs35.default.statSync(filePath).mtimeMs < startMs) return;
17522
+ if (import_fs36.default.statSync(filePath).mtimeMs < startMs) return;
17356
17523
  } catch {
17357
17524
  return;
17358
17525
  }
17359
17526
  let raw;
17360
17527
  try {
17361
- raw = import_fs35.default.readFileSync(filePath, "utf-8");
17528
+ raw = import_fs36.default.readFileSync(filePath, "utf-8");
17362
17529
  } catch {
17363
17530
  return;
17364
17531
  }
@@ -17407,30 +17574,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
17407
17574
  const out = [];
17408
17575
  let dirs;
17409
17576
  try {
17410
- if (!import_fs35.default.statSync(geminiTmpDir).isDirectory()) return out;
17411
- dirs = import_fs35.default.readdirSync(geminiTmpDir);
17577
+ if (!import_fs36.default.statSync(geminiTmpDir).isDirectory()) return out;
17578
+ dirs = import_fs36.default.readdirSync(geminiTmpDir);
17412
17579
  } catch {
17413
17580
  return out;
17414
17581
  }
17415
17582
  for (const proj of dirs) {
17416
- const chatsDir = import_path36.default.join(geminiTmpDir, proj, "chats");
17583
+ const chatsDir = import_path37.default.join(geminiTmpDir, proj, "chats");
17417
17584
  let files;
17418
17585
  try {
17419
- if (!import_fs35.default.statSync(chatsDir).isDirectory()) continue;
17420
- files = import_fs35.default.readdirSync(chatsDir);
17586
+ if (!import_fs36.default.statSync(chatsDir).isDirectory()) continue;
17587
+ files = import_fs36.default.readdirSync(chatsDir);
17421
17588
  } catch {
17422
17589
  continue;
17423
17590
  }
17424
17591
  for (const f of files) {
17425
17592
  if (!f.endsWith(".jsonl")) continue;
17426
- out.push({ projectKey: proj, file: import_path36.default.join(chatsDir, f) });
17593
+ out.push({ projectKey: proj, file: import_path37.default.join(chatsDir, f) });
17427
17594
  }
17428
17595
  }
17429
17596
  return out;
17430
17597
  }
17431
17598
  function loadGeminiCost(start, end, geminiTmpDir) {
17432
17599
  const acc = emptyGeminiAccumulator();
17433
- if (!import_fs35.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17600
+ if (!import_fs36.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17434
17601
  for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
17435
17602
  processGeminiCostFile(file, projectKey, start, end, acc);
17436
17603
  }
@@ -17438,11 +17605,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
17438
17605
  }
17439
17606
  function aggregateReportFromAudit(period, opts = {}) {
17440
17607
  const now = opts.now ?? /* @__PURE__ */ new Date();
17441
- const auditLogPath = opts.auditLogPath ?? import_path36.default.join(import_os31.default.homedir(), ".node9", "audit.log");
17442
- const claudeProjectsDir = opts.claudeProjectsDir ?? import_path36.default.join(import_os31.default.homedir(), ".claude", "projects");
17443
- const codexSessionsDir = opts.codexSessionsDir ?? import_path36.default.join(import_os31.default.homedir(), ".codex", "sessions");
17444
- const geminiTmpDir = opts.geminiTmpDir ?? import_path36.default.join(import_os31.default.homedir(), ".gemini", "tmp");
17445
- const hasAuditFile = import_fs35.default.existsSync(auditLogPath);
17608
+ const auditLogPath = opts.auditLogPath ?? import_path37.default.join(import_os32.default.homedir(), ".node9", "audit.log");
17609
+ const claudeProjectsDir = opts.claudeProjectsDir ?? import_path37.default.join(import_os32.default.homedir(), ".claude", "projects");
17610
+ const codexSessionsDir = opts.codexSessionsDir ?? import_path37.default.join(import_os32.default.homedir(), ".codex", "sessions");
17611
+ const geminiTmpDir = opts.geminiTmpDir ?? import_path37.default.join(import_os32.default.homedir(), ".gemini", "tmp");
17612
+ const hasAuditFile = import_fs36.default.existsSync(auditLogPath);
17446
17613
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
17447
17614
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
17448
17615
  const { start, end } = getDateRange(period, now);
@@ -18138,14 +18305,14 @@ function registerDaemonCommand(program2) {
18138
18305
 
18139
18306
  // src/cli/commands/status.ts
18140
18307
  var import_chalk15 = __toESM(require("chalk"));
18141
- var import_fs36 = __toESM(require("fs"));
18142
- var import_path37 = __toESM(require("path"));
18143
- var import_os32 = __toESM(require("os"));
18308
+ var import_fs37 = __toESM(require("fs"));
18309
+ var import_path38 = __toESM(require("path"));
18310
+ var import_os33 = __toESM(require("os"));
18144
18311
  init_core();
18145
18312
  init_daemon();
18146
18313
  function readJson2(filePath) {
18147
18314
  try {
18148
- if (import_fs36.default.existsSync(filePath)) return JSON.parse(import_fs36.default.readFileSync(filePath, "utf-8"));
18315
+ if (import_fs37.default.existsSync(filePath)) return JSON.parse(import_fs37.default.readFileSync(filePath, "utf-8"));
18149
18316
  } catch {
18150
18317
  }
18151
18318
  return null;
@@ -18210,28 +18377,28 @@ function registerStatusCommand(program2) {
18210
18377
  console.log("");
18211
18378
  const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
18212
18379
  console.log(` Mode: ${modeLabel}`);
18213
- const projectConfig = import_path37.default.join(process.cwd(), "node9.config.json");
18214
- const globalConfig = import_path37.default.join(import_os32.default.homedir(), ".node9", "config.json");
18380
+ const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
18381
+ const globalConfig = import_path38.default.join(import_os33.default.homedir(), ".node9", "config.json");
18215
18382
  console.log(
18216
- ` Local: ${import_fs36.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
18383
+ ` Local: ${import_fs37.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
18217
18384
  );
18218
18385
  console.log(
18219
- ` Global: ${import_fs36.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
18386
+ ` Global: ${import_fs37.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
18220
18387
  );
18221
18388
  if (mergedConfig.policy.sandboxPaths.length > 0) {
18222
18389
  console.log(
18223
18390
  ` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
18224
18391
  );
18225
18392
  }
18226
- const homeDir2 = import_os32.default.homedir();
18393
+ const homeDir2 = import_os33.default.homedir();
18227
18394
  const claudeSettings = readJson2(
18228
- import_path37.default.join(homeDir2, ".claude", "settings.json")
18395
+ import_path38.default.join(homeDir2, ".claude", "settings.json")
18229
18396
  );
18230
- const claudeConfig = readJson2(import_path37.default.join(homeDir2, ".claude.json"));
18397
+ const claudeConfig = readJson2(import_path38.default.join(homeDir2, ".claude.json"));
18231
18398
  const geminiSettings = readJson2(
18232
- import_path37.default.join(homeDir2, ".gemini", "settings.json")
18399
+ import_path38.default.join(homeDir2, ".gemini", "settings.json")
18233
18400
  );
18234
- const cursorConfig = readJson2(import_path37.default.join(homeDir2, ".cursor", "mcp.json"));
18401
+ const cursorConfig = readJson2(import_path38.default.join(homeDir2, ".cursor", "mcp.json"));
18235
18402
  const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
18236
18403
  if (agentFound) {
18237
18404
  console.log("");
@@ -18290,9 +18457,9 @@ function registerStatusCommand(program2) {
18290
18457
 
18291
18458
  // src/cli/commands/init.ts
18292
18459
  var import_chalk16 = __toESM(require("chalk"));
18293
- var import_fs37 = __toESM(require("fs"));
18294
- var import_path38 = __toESM(require("path"));
18295
- var import_os33 = __toESM(require("os"));
18460
+ var import_fs38 = __toESM(require("fs"));
18461
+ var import_path39 = __toESM(require("path"));
18462
+ var import_os34 = __toESM(require("os"));
18296
18463
  var import_https4 = __toESM(require("https"));
18297
18464
  init_core();
18298
18465
  init_setup();
@@ -18372,15 +18539,15 @@ function registerInitCommand(program2) {
18372
18539
  }
18373
18540
  console.log("");
18374
18541
  }
18375
- const configPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "config.json");
18376
- if (import_fs37.default.existsSync(configPath) && !options.force) {
18542
+ const configPath = import_path39.default.join(import_os34.default.homedir(), ".node9", "config.json");
18543
+ if (import_fs38.default.existsSync(configPath) && !options.force) {
18377
18544
  try {
18378
- const existing = JSON.parse(import_fs37.default.readFileSync(configPath, "utf-8"));
18545
+ const existing = JSON.parse(import_fs38.default.readFileSync(configPath, "utf-8"));
18379
18546
  const settings = existing.settings ?? {};
18380
18547
  if (settings.mode !== chosenMode) {
18381
18548
  settings.mode = chosenMode;
18382
18549
  existing.settings = settings;
18383
- import_fs37.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18550
+ import_fs38.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18384
18551
  console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
18385
18552
  } else {
18386
18553
  console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -18393,9 +18560,9 @@ function registerInitCommand(program2) {
18393
18560
  ...DEFAULT_CONFIG,
18394
18561
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
18395
18562
  };
18396
- const dir = import_path38.default.dirname(configPath);
18397
- if (!import_fs37.default.existsSync(dir)) import_fs37.default.mkdirSync(dir, { recursive: true });
18398
- import_fs37.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
18563
+ const dir = import_path39.default.dirname(configPath);
18564
+ if (!import_fs38.default.existsSync(dir)) import_fs38.default.mkdirSync(dir, { recursive: true });
18565
+ import_fs38.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
18399
18566
  console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
18400
18567
  console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
18401
18568
  }
@@ -18493,7 +18660,7 @@ function registerInitCommand(program2) {
18493
18660
  }
18494
18661
 
18495
18662
  // src/cli/commands/undo.ts
18496
- var import_path39 = __toESM(require("path"));
18663
+ var import_path40 = __toESM(require("path"));
18497
18664
  var import_chalk18 = __toESM(require("chalk"));
18498
18665
 
18499
18666
  // src/tui/undo-navigator.ts
@@ -18652,7 +18819,7 @@ function findMatchingCwd(startDir, history) {
18652
18819
  let dir = startDir;
18653
18820
  while (true) {
18654
18821
  if (cwds.has(dir)) return dir;
18655
- const parent = import_path39.default.dirname(dir);
18822
+ const parent = import_path40.default.dirname(dir);
18656
18823
  if (parent === dir) return null;
18657
18824
  dir = parent;
18658
18825
  }
@@ -18785,90 +18952,7 @@ var import_child_process10 = require("child_process");
18785
18952
  var import_execa3 = require("execa");
18786
18953
  init_orchestrator();
18787
18954
  init_provenance();
18788
-
18789
- // src/mcp-pin.ts
18790
- var import_fs38 = __toESM(require("fs"));
18791
- var import_path40 = __toESM(require("path"));
18792
- var import_os34 = __toESM(require("os"));
18793
- var import_crypto10 = __toESM(require("crypto"));
18794
- function getPinsFilePath2() {
18795
- return import_path40.default.join(import_os34.default.homedir(), ".node9", "mcp-pins.json");
18796
- }
18797
- function hashToolDefinitions(tools) {
18798
- const sorted = [...tools].sort((a, b) => {
18799
- const nameA = a.name ?? "";
18800
- const nameB = b.name ?? "";
18801
- return nameA.localeCompare(nameB);
18802
- });
18803
- const canonical = JSON.stringify(sorted);
18804
- return import_crypto10.default.createHash("sha256").update(canonical).digest("hex");
18805
- }
18806
- function getServerKey(upstreamCommand) {
18807
- return import_crypto10.default.createHash("sha256").update(upstreamCommand).digest("hex").slice(0, 16);
18808
- }
18809
- function readMcpPinsSafe() {
18810
- const filePath = getPinsFilePath2();
18811
- try {
18812
- const raw = import_fs38.default.readFileSync(filePath, "utf-8");
18813
- if (!raw.trim()) {
18814
- return { ok: false, reason: "corrupt", detail: "empty file" };
18815
- }
18816
- const parsed = JSON.parse(raw);
18817
- if (!parsed.servers || typeof parsed.servers !== "object" || Array.isArray(parsed.servers)) {
18818
- return { ok: false, reason: "corrupt", detail: "invalid structure: missing servers object" };
18819
- }
18820
- return { ok: true, pins: { servers: parsed.servers } };
18821
- } catch (err2) {
18822
- if (err2.code === "ENOENT") {
18823
- return { ok: false, reason: "missing" };
18824
- }
18825
- return { ok: false, reason: "corrupt", detail: String(err2) };
18826
- }
18827
- }
18828
- function readMcpPins() {
18829
- const result = readMcpPinsSafe();
18830
- if (result.ok) return result.pins;
18831
- if (result.reason === "missing") return { servers: {} };
18832
- throw new Error(`[node9] MCP pin file is corrupt: ${result.detail}`);
18833
- }
18834
- function writeMcpPins(data) {
18835
- const filePath = getPinsFilePath2();
18836
- import_fs38.default.mkdirSync(import_path40.default.dirname(filePath), { recursive: true });
18837
- const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
18838
- import_fs38.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
18839
- import_fs38.default.renameSync(tmp, filePath);
18840
- }
18841
- function checkPin(serverKey, currentHash) {
18842
- const result = readMcpPinsSafe();
18843
- if (!result.ok) {
18844
- if (result.reason === "missing") return "new";
18845
- return "corrupt";
18846
- }
18847
- const entry = result.pins.servers[serverKey];
18848
- if (!entry) return "new";
18849
- return entry.toolsHash === currentHash ? "match" : "mismatch";
18850
- }
18851
- function updatePin(serverKey, label, toolsHash, toolNames) {
18852
- const pins = readMcpPins();
18853
- pins.servers[serverKey] = {
18854
- label,
18855
- toolsHash,
18856
- toolNames,
18857
- toolCount: toolNames.length,
18858
- pinnedAt: (/* @__PURE__ */ new Date()).toISOString()
18859
- };
18860
- writeMcpPins(pins);
18861
- }
18862
- function removePin2(serverKey) {
18863
- const pins = readMcpPins();
18864
- delete pins.servers[serverKey];
18865
- writeMcpPins(pins);
18866
- }
18867
- function clearAllPins2() {
18868
- writeMcpPins({ servers: {} });
18869
- }
18870
-
18871
- // src/mcp-gateway/index.ts
18955
+ init_mcp_pin();
18872
18956
  init_mcp_tools();
18873
18957
  init_daemon();
18874
18958
  function sanitize4(value) {
@@ -18930,6 +19014,7 @@ function tokenize4(cmd) {
18930
19014
  return tokens;
18931
19015
  }
18932
19016
  async function runMcpGateway(upstreamCommand) {
19017
+ const gatewayCwd = process.cwd();
18933
19018
  const commandParts = tokenize4(upstreamCommand);
18934
19019
  const cmd = commandParts[0];
18935
19020
  const cmdArgs = commandParts.slice(1);
@@ -19152,7 +19237,7 @@ async function runMcpGateway(upstreamCommand) {
19152
19237
  if (parsed.result && Array.isArray(parsed.result.tools)) {
19153
19238
  const tools = parsed.result.tools || [];
19154
19239
  const currentHash = hashToolDefinitions(tools);
19155
- const pinStatus = checkPin(serverKey, currentHash);
19240
+ const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
19156
19241
  const token = getInternalToken();
19157
19242
  if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
19158
19243
  const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
@@ -20037,26 +20122,45 @@ function registerTrustCommand(program2) {
20037
20122
 
20038
20123
  // src/cli/commands/mcp-pin.ts
20039
20124
  var import_chalk21 = __toESM(require("chalk"));
20125
+ init_mcp_pin();
20126
+ var import_fs40 = __toESM(require("fs"));
20040
20127
  function registerMcpPinCommand(program2) {
20041
20128
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
20042
20129
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
20043
20130
  pinSubCmd.command("list").description("Show all pinned MCP servers and their tool definition hashes").action(() => {
20044
- const result = readMcpPinsSafe();
20045
- if (!result.ok) {
20046
- if (result.reason === "missing") {
20047
- console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
20048
- console.log(
20049
- import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
20050
- );
20051
- return;
20131
+ const found = findPinsFilePath(process.cwd());
20132
+ const homeResult = readMcpPinsSafe();
20133
+ let repoEntries = {};
20134
+ let repoCorrupt = false;
20135
+ if (found.source === "repo") {
20136
+ try {
20137
+ const raw = import_fs40.default.readFileSync(found.path, "utf-8");
20138
+ const parsed = JSON.parse(raw);
20139
+ repoEntries = parsed.servers ?? {};
20140
+ } catch {
20141
+ repoCorrupt = true;
20052
20142
  }
20143
+ }
20144
+ if (repoCorrupt) {
20053
20145
  console.error(import_chalk21.default.red(`
20054
- \u274C Pin file is corrupt: ${result.detail}`));
20146
+ \u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
20147
+ process.exit(1);
20148
+ }
20149
+ if (!homeResult.ok && homeResult.reason === "corrupt") {
20150
+ console.error(import_chalk21.default.red(`
20151
+ \u274C Home pin file is corrupt: ${homeResult.detail}`));
20055
20152
  console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
20056
20153
  process.exit(1);
20057
20154
  }
20058
- const entries = Object.entries(result.pins.servers);
20059
- if (entries.length === 0) {
20155
+ const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
20156
+ const merged = /* @__PURE__ */ new Map();
20157
+ for (const [key, entry] of Object.entries(homeEntries)) {
20158
+ merged.set(key, { entry, source: "home" });
20159
+ }
20160
+ for (const [key, entry] of Object.entries(repoEntries)) {
20161
+ merged.set(key, { entry, source: "repo" });
20162
+ }
20163
+ if (merged.size === 0) {
20060
20164
  console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
20061
20165
  console.log(
20062
20166
  import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
@@ -20064,13 +20168,47 @@ function registerMcpPinCommand(program2) {
20064
20168
  return;
20065
20169
  }
20066
20170
  console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
20067
- for (const [key, entry] of entries) {
20068
- console.log(` ${import_chalk21.default.cyan(key)} ${import_chalk21.default.gray(entry.label)}`);
20171
+ const showSource = found.source === "repo";
20172
+ for (const [key, { entry, source }] of merged) {
20173
+ const tag = showSource ? ` ${import_chalk21.default.yellow(`[${source}]`)}` : "";
20174
+ console.log(` ${import_chalk21.default.cyan(key)}${tag} ${import_chalk21.default.gray(entry.label)}`);
20069
20175
  console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
20070
20176
  console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
20071
20177
  console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
20072
20178
  console.log("");
20073
20179
  }
20180
+ if (showSource) {
20181
+ console.log(import_chalk21.default.gray(` [repo] entries come from ${found.path}`));
20182
+ console.log(import_chalk21.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
20183
+ }
20184
+ });
20185
+ pinSubCmd.command("promote <serverKey>").description(
20186
+ "Copy a pin from ~/.node9/mcp-pins.json into <repo>/.node9/mcp-pins.json so teammates share the same vetted baseline"
20187
+ ).action((serverKey) => {
20188
+ try {
20189
+ const { repoPath, created } = promotePin(serverKey, process.cwd());
20190
+ if (created) {
20191
+ console.log(
20192
+ import_chalk21.default.green(
20193
+ `
20194
+ \u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
20195
+ )
20196
+ );
20197
+ } else {
20198
+ console.log(import_chalk21.default.green(`
20199
+ \u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
20200
+ }
20201
+ console.log(import_chalk21.default.gray(" Review the change and commit it:"));
20202
+ console.log(import_chalk21.default.cyan(` git add ${repoPath}`));
20203
+ console.log(import_chalk21.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
20204
+ console.log("");
20205
+ } catch (err2) {
20206
+ const msg = err2 instanceof Error ? err2.message : String(err2);
20207
+ console.error(import_chalk21.default.red(`
20208
+ \u274C ${msg}
20209
+ `));
20210
+ process.exit(1);
20211
+ }
20074
20212
  });
20075
20213
  pinSubCmd.command("update <serverKey>").description(
20076
20214
  "Remove a pin so the next gateway connection re-pins with current tool definitions"
@@ -20092,7 +20230,7 @@ function registerMcpPinCommand(program2) {
20092
20230
  process.exit(1);
20093
20231
  }
20094
20232
  const label = pins.servers[serverKey].label;
20095
- removePin2(serverKey);
20233
+ removePin(serverKey);
20096
20234
  console.log(import_chalk21.default.green(`
20097
20235
  \u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
20098
20236
  console.log(import_chalk21.default.gray(` Server: ${label}`));
@@ -20105,7 +20243,7 @@ function registerMcpPinCommand(program2) {
20105
20243
  return;
20106
20244
  }
20107
20245
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
20108
- clearAllPins2();
20246
+ clearAllPins();
20109
20247
  console.log(import_chalk21.default.green(`
20110
20248
  \u{1F513} Cleared ${count} MCP pin(s).`));
20111
20249
  console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
@@ -20288,7 +20426,7 @@ init_scan();
20288
20426
 
20289
20427
  // src/cli/commands/sessions.ts
20290
20428
  var import_chalk24 = __toESM(require("chalk"));
20291
- var import_fs40 = __toESM(require("fs"));
20429
+ var import_fs41 = __toESM(require("fs"));
20292
20430
  var import_path42 = __toESM(require("path"));
20293
20431
  var import_os36 = __toESM(require("os"));
20294
20432
  var CLAUDE_PRICING3 = {
@@ -20406,7 +20544,7 @@ function loadAuditEntries(auditPath) {
20406
20544
  const aPath = auditPath ?? import_path42.default.join(import_os36.default.homedir(), ".node9", "audit.log");
20407
20545
  let raw;
20408
20546
  try {
20409
- raw = import_fs40.default.readFileSync(aPath, "utf-8");
20547
+ raw = import_fs41.default.readFileSync(aPath, "utf-8");
20410
20548
  } catch {
20411
20549
  return [];
20412
20550
  }
@@ -20443,7 +20581,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
20443
20581
  }
20444
20582
  function buildGeminiSessions(days, allAuditEntries) {
20445
20583
  const tmpDir = import_path42.default.join(import_os36.default.homedir(), ".gemini", "tmp");
20446
- if (!import_fs40.default.existsSync(tmpDir)) return [];
20584
+ if (!import_fs41.default.existsSync(tmpDir)) return [];
20447
20585
  const cutoff = days !== null ? (() => {
20448
20586
  const d = /* @__PURE__ */ new Date();
20449
20587
  d.setDate(d.getDate() - days);
@@ -20452,7 +20590,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20452
20590
  })() : null;
20453
20591
  let slugDirs;
20454
20592
  try {
20455
- slugDirs = import_fs40.default.readdirSync(tmpDir);
20593
+ slugDirs = import_fs41.default.readdirSync(tmpDir);
20456
20594
  } catch {
20457
20595
  return [];
20458
20596
  }
@@ -20460,27 +20598,27 @@ function buildGeminiSessions(days, allAuditEntries) {
20460
20598
  for (const slug of slugDirs) {
20461
20599
  const slugPath = import_path42.default.join(tmpDir, slug);
20462
20600
  try {
20463
- if (!import_fs40.default.statSync(slugPath).isDirectory()) continue;
20601
+ if (!import_fs41.default.statSync(slugPath).isDirectory()) continue;
20464
20602
  } catch {
20465
20603
  continue;
20466
20604
  }
20467
20605
  let projectRoot = import_path42.default.join(import_os36.default.homedir(), slug);
20468
20606
  try {
20469
- projectRoot = import_fs40.default.readFileSync(import_path42.default.join(slugPath, ".project_root"), "utf-8").trim();
20607
+ projectRoot = import_fs41.default.readFileSync(import_path42.default.join(slugPath, ".project_root"), "utf-8").trim();
20470
20608
  } catch {
20471
20609
  }
20472
20610
  const chatsDir = import_path42.default.join(slugPath, "chats");
20473
- if (!import_fs40.default.existsSync(chatsDir)) continue;
20611
+ if (!import_fs41.default.existsSync(chatsDir)) continue;
20474
20612
  let chatFiles;
20475
20613
  try {
20476
- chatFiles = import_fs40.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20614
+ chatFiles = import_fs41.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20477
20615
  } catch {
20478
20616
  continue;
20479
20617
  }
20480
20618
  for (const chatFile of chatFiles) {
20481
20619
  let raw;
20482
20620
  try {
20483
- raw = import_fs40.default.readFileSync(import_path42.default.join(chatsDir, chatFile), "utf-8");
20621
+ raw = import_fs41.default.readFileSync(import_path42.default.join(chatsDir, chatFile), "utf-8");
20484
20622
  } catch {
20485
20623
  continue;
20486
20624
  }
@@ -20561,7 +20699,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20561
20699
  }
20562
20700
  function buildCodexSessions(days, allAuditEntries) {
20563
20701
  const sessionsBase = import_path42.default.join(import_os36.default.homedir(), ".codex", "sessions");
20564
- if (!import_fs40.default.existsSync(sessionsBase)) return [];
20702
+ if (!import_fs41.default.existsSync(sessionsBase)) return [];
20565
20703
  const cutoff = days !== null ? (() => {
20566
20704
  const d = /* @__PURE__ */ new Date();
20567
20705
  d.setDate(d.getDate() - days);
@@ -20570,28 +20708,28 @@ function buildCodexSessions(days, allAuditEntries) {
20570
20708
  })() : null;
20571
20709
  const jsonlFiles = [];
20572
20710
  try {
20573
- for (const year of import_fs40.default.readdirSync(sessionsBase)) {
20711
+ for (const year of import_fs41.default.readdirSync(sessionsBase)) {
20574
20712
  const yearPath = import_path42.default.join(sessionsBase, year);
20575
20713
  try {
20576
- if (!import_fs40.default.statSync(yearPath).isDirectory()) continue;
20714
+ if (!import_fs41.default.statSync(yearPath).isDirectory()) continue;
20577
20715
  } catch {
20578
20716
  continue;
20579
20717
  }
20580
- for (const month of import_fs40.default.readdirSync(yearPath)) {
20718
+ for (const month of import_fs41.default.readdirSync(yearPath)) {
20581
20719
  const monthPath = import_path42.default.join(yearPath, month);
20582
20720
  try {
20583
- if (!import_fs40.default.statSync(monthPath).isDirectory()) continue;
20721
+ if (!import_fs41.default.statSync(monthPath).isDirectory()) continue;
20584
20722
  } catch {
20585
20723
  continue;
20586
20724
  }
20587
- for (const day of import_fs40.default.readdirSync(monthPath)) {
20725
+ for (const day of import_fs41.default.readdirSync(monthPath)) {
20588
20726
  const dayPath = import_path42.default.join(monthPath, day);
20589
20727
  try {
20590
- if (!import_fs40.default.statSync(dayPath).isDirectory()) continue;
20728
+ if (!import_fs41.default.statSync(dayPath).isDirectory()) continue;
20591
20729
  } catch {
20592
20730
  continue;
20593
20731
  }
20594
- for (const file of import_fs40.default.readdirSync(dayPath)) {
20732
+ for (const file of import_fs41.default.readdirSync(dayPath)) {
20595
20733
  if (file.endsWith(".jsonl")) jsonlFiles.push(import_path42.default.join(dayPath, file));
20596
20734
  }
20597
20735
  }
@@ -20604,7 +20742,7 @@ function buildCodexSessions(days, allAuditEntries) {
20604
20742
  for (const filePath of jsonlFiles) {
20605
20743
  let lines;
20606
20744
  try {
20607
- lines = import_fs40.default.readFileSync(filePath, "utf-8").split("\n");
20745
+ lines = import_fs41.default.readFileSync(filePath, "utf-8").split("\n");
20608
20746
  } catch {
20609
20747
  continue;
20610
20748
  }
@@ -20685,7 +20823,7 @@ function buildSessions(days, historyPath) {
20685
20823
  const hPath = historyPath ?? import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
20686
20824
  let historyRaw;
20687
20825
  try {
20688
- historyRaw = import_fs40.default.readFileSync(hPath, "utf-8");
20826
+ historyRaw = import_fs41.default.readFileSync(hPath, "utf-8");
20689
20827
  } catch {
20690
20828
  return [];
20691
20829
  }
@@ -20710,7 +20848,7 @@ function buildSessions(days, historyPath) {
20710
20848
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
20711
20849
  let sessionLines = [];
20712
20850
  try {
20713
- sessionLines = import_fs40.default.readFileSync(jsonlFile, "utf-8").split("\n");
20851
+ sessionLines = import_fs41.default.readFileSync(jsonlFile, "utf-8").split("\n");
20714
20852
  } catch {
20715
20853
  }
20716
20854
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -20977,7 +21115,7 @@ function registerSessionsCommand(program2) {
20977
21115
  console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
20978
21116
  console.log("");
20979
21117
  const historyPath = import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
20980
- if (!import_fs40.default.existsSync(historyPath)) {
21118
+ if (!import_fs41.default.existsSync(historyPath)) {
20981
21119
  console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
20982
21120
  console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
20983
21121
  return;
@@ -21014,12 +21152,12 @@ function registerSessionsCommand(program2) {
21014
21152
 
21015
21153
  // src/cli/commands/skill-pin.ts
21016
21154
  var import_chalk25 = __toESM(require("chalk"));
21017
- var import_fs41 = __toESM(require("fs"));
21155
+ var import_fs42 = __toESM(require("fs"));
21018
21156
  var import_os37 = __toESM(require("os"));
21019
21157
  var import_path43 = __toESM(require("path"));
21020
21158
  function wipeSkillSessions() {
21021
21159
  try {
21022
- import_fs41.default.rmSync(import_path43.default.join(import_os37.default.homedir(), ".node9", "skill-sessions"), {
21160
+ import_fs42.default.rmSync(import_path43.default.join(import_os37.default.homedir(), ".node9", "skill-sessions"), {
21023
21161
  recursive: true,
21024
21162
  force: true
21025
21163
  });
@@ -21077,7 +21215,7 @@ function registerSkillPinCommand(program2) {
21077
21215
  process.exit(1);
21078
21216
  }
21079
21217
  const rootPath = pins.roots[rootKey].rootPath;
21080
- removePin(rootKey);
21218
+ removePin2(rootKey);
21081
21219
  wipeSkillSessions();
21082
21220
  console.log(import_chalk25.default.green(`
21083
21221
  \u{1F513} Pin removed for ${import_chalk25.default.cyan(rootKey)}`));
@@ -21092,7 +21230,7 @@ function registerSkillPinCommand(program2) {
21092
21230
  return;
21093
21231
  }
21094
21232
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
21095
- clearAllPins();
21233
+ clearAllPins2();
21096
21234
  wipeSkillSessions();
21097
21235
  console.log(import_chalk25.default.green(`
21098
21236
  \u{1F513} Cleared ${count} skill pin(s).`));
@@ -21101,15 +21239,15 @@ function registerSkillPinCommand(program2) {
21101
21239
  }
21102
21240
 
21103
21241
  // src/cli/commands/decisions.ts
21104
- var import_fs42 = __toESM(require("fs"));
21242
+ var import_fs43 = __toESM(require("fs"));
21105
21243
  var import_os38 = __toESM(require("os"));
21106
21244
  var import_path44 = __toESM(require("path"));
21107
21245
  var import_chalk26 = __toESM(require("chalk"));
21108
21246
  var DECISIONS_FILE2 = import_path44.default.join(import_os38.default.homedir(), ".node9", "decisions.json");
21109
21247
  function readDecisions() {
21110
21248
  try {
21111
- if (!import_fs42.default.existsSync(DECISIONS_FILE2)) return {};
21112
- const raw = import_fs42.default.readFileSync(DECISIONS_FILE2, "utf-8");
21249
+ if (!import_fs43.default.existsSync(DECISIONS_FILE2)) return {};
21250
+ const raw = import_fs43.default.readFileSync(DECISIONS_FILE2, "utf-8");
21113
21251
  const parsed = JSON.parse(raw);
21114
21252
  const out = {};
21115
21253
  for (const [k, v] of Object.entries(parsed)) {
@@ -21122,10 +21260,10 @@ function readDecisions() {
21122
21260
  }
21123
21261
  function writeDecisions(d) {
21124
21262
  const dir = import_path44.default.dirname(DECISIONS_FILE2);
21125
- if (!import_fs42.default.existsSync(dir)) import_fs42.default.mkdirSync(dir, { recursive: true });
21263
+ if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
21126
21264
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
21127
- import_fs42.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
21128
- import_fs42.default.renameSync(tmp, DECISIONS_FILE2);
21265
+ import_fs43.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
21266
+ import_fs43.default.renameSync(tmp, DECISIONS_FILE2);
21129
21267
  }
21130
21268
  function registerDecisionsCommand(program2) {
21131
21269
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -21182,7 +21320,7 @@ Persistent decisions (${entries.length})
21182
21320
 
21183
21321
  // src/cli/commands/dlp.ts
21184
21322
  var import_chalk27 = __toESM(require("chalk"));
21185
- var import_fs43 = __toESM(require("fs"));
21323
+ var import_fs44 = __toESM(require("fs"));
21186
21324
  var import_path45 = __toESM(require("path"));
21187
21325
  var import_os39 = __toESM(require("os"));
21188
21326
  var AUDIT_LOG = import_path45.default.join(import_os39.default.homedir(), ".node9", "audit.log");
@@ -21193,7 +21331,7 @@ function stripAnsi(s) {
21193
21331
  }
21194
21332
  function loadResolved() {
21195
21333
  try {
21196
- const raw = JSON.parse(import_fs43.default.readFileSync(RESOLVED_FILE, "utf-8"));
21334
+ const raw = JSON.parse(import_fs44.default.readFileSync(RESOLVED_FILE, "utf-8"));
21197
21335
  return new Set(raw);
21198
21336
  } catch {
21199
21337
  return /* @__PURE__ */ new Set();
@@ -21201,13 +21339,13 @@ function loadResolved() {
21201
21339
  }
21202
21340
  function saveResolved(resolved) {
21203
21341
  try {
21204
- import_fs43.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21342
+ import_fs44.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21205
21343
  } catch {
21206
21344
  }
21207
21345
  }
21208
21346
  function loadDlpFindings() {
21209
- if (!import_fs43.default.existsSync(AUDIT_LOG)) return [];
21210
- return import_fs43.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
21347
+ if (!import_fs44.default.existsSync(AUDIT_LOG)) return [];
21348
+ return import_fs44.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
21211
21349
  if (!line.trim()) return [];
21212
21350
  try {
21213
21351
  const e = JSON.parse(line);
@@ -21305,14 +21443,14 @@ function registerDlpCommand(program2) {
21305
21443
 
21306
21444
  // src/cli/commands/mask.ts
21307
21445
  var import_chalk28 = __toESM(require("chalk"));
21308
- var import_fs44 = __toESM(require("fs"));
21446
+ var import_fs45 = __toESM(require("fs"));
21309
21447
  var import_path46 = __toESM(require("path"));
21310
21448
  var import_os40 = __toESM(require("os"));
21311
21449
  init_dlp();
21312
21450
  function findJsonlFiles(dir) {
21313
21451
  const results = [];
21314
- if (!import_fs44.default.existsSync(dir)) return results;
21315
- for (const entry of import_fs44.default.readdirSync(dir, { withFileTypes: true })) {
21452
+ if (!import_fs45.default.existsSync(dir)) return results;
21453
+ for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
21316
21454
  const full = import_path46.default.join(dir, entry.name);
21317
21455
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
21318
21456
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
@@ -21356,7 +21494,7 @@ function redactJson(obj) {
21356
21494
  function processFile(filePath, dryRun) {
21357
21495
  let raw;
21358
21496
  try {
21359
- raw = import_fs44.default.readFileSync(filePath, "utf-8");
21497
+ raw = import_fs45.default.readFileSync(filePath, "utf-8");
21360
21498
  } catch {
21361
21499
  return { redactedLines: 0, patterns: [] };
21362
21500
  }
@@ -21388,14 +21526,14 @@ function processFile(filePath, dryRun) {
21388
21526
  }
21389
21527
  }
21390
21528
  if (!dryRun && redactedLines > 0) {
21391
- import_fs44.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21529
+ import_fs45.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21392
21530
  }
21393
21531
  return { redactedLines, patterns };
21394
21532
  }
21395
21533
  function processJsonFile(filePath, dryRun) {
21396
21534
  let raw;
21397
21535
  try {
21398
- raw = import_fs44.default.readFileSync(filePath, "utf-8");
21536
+ raw = import_fs45.default.readFileSync(filePath, "utf-8");
21399
21537
  } catch {
21400
21538
  return { redactedLines: 0, patterns: [] };
21401
21539
  }
@@ -21408,14 +21546,14 @@ function processJsonFile(filePath, dryRun) {
21408
21546
  const { value, modified, found } = redactJson(parsed);
21409
21547
  if (!modified) return { redactedLines: 0, patterns: [] };
21410
21548
  if (!dryRun) {
21411
- import_fs44.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21549
+ import_fs45.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21412
21550
  }
21413
21551
  return { redactedLines: 1, patterns: found };
21414
21552
  }
21415
21553
  function findJsonFiles(dir) {
21416
21554
  const results = [];
21417
- if (!import_fs44.default.existsSync(dir)) return results;
21418
- for (const entry of import_fs44.default.readdirSync(dir, { withFileTypes: true })) {
21555
+ if (!import_fs45.default.existsSync(dir)) return results;
21556
+ for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
21419
21557
  const full = import_path46.default.join(dir, entry.name);
21420
21558
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
21421
21559
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
@@ -21435,7 +21573,7 @@ function registerMaskCommand(program2) {
21435
21573
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
21436
21574
  const filtered = cutoff ? allFiles.filter((f) => {
21437
21575
  try {
21438
- return import_fs44.default.statSync(f.path).mtime >= cutoff;
21576
+ return import_fs45.default.statSync(f.path).mtime >= cutoff;
21439
21577
  } catch {
21440
21578
  return false;
21441
21579
  }
@@ -21491,20 +21629,20 @@ function registerMaskCommand(program2) {
21491
21629
  // src/cli.ts
21492
21630
  init_blast();
21493
21631
  var { version } = JSON.parse(
21494
- import_fs47.default.readFileSync(import_path49.default.join(__dirname, "../package.json"), "utf-8")
21632
+ import_fs48.default.readFileSync(import_path49.default.join(__dirname, "../package.json"), "utf-8")
21495
21633
  );
21496
21634
  var program = new import_commander.Command();
21497
21635
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
21498
21636
  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) => {
21499
21637
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
21500
21638
  const credPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "credentials.json");
21501
- if (!import_fs47.default.existsSync(import_path49.default.dirname(credPath)))
21502
- import_fs47.default.mkdirSync(import_path49.default.dirname(credPath), { recursive: true });
21639
+ if (!import_fs48.default.existsSync(import_path49.default.dirname(credPath)))
21640
+ import_fs48.default.mkdirSync(import_path49.default.dirname(credPath), { recursive: true });
21503
21641
  const profileName = options.profile || "default";
21504
21642
  let existingCreds = {};
21505
21643
  try {
21506
- if (import_fs47.default.existsSync(credPath)) {
21507
- const raw = JSON.parse(import_fs47.default.readFileSync(credPath, "utf-8"));
21644
+ if (import_fs48.default.existsSync(credPath)) {
21645
+ const raw = JSON.parse(import_fs48.default.readFileSync(credPath, "utf-8"));
21508
21646
  if (raw.apiKey) {
21509
21647
  existingCreds = {
21510
21648
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -21516,13 +21654,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21516
21654
  } catch {
21517
21655
  }
21518
21656
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
21519
- import_fs47.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21657
+ import_fs48.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21520
21658
  if (profileName === "default") {
21521
21659
  const configPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json");
21522
21660
  let config = {};
21523
21661
  try {
21524
- if (import_fs47.default.existsSync(configPath))
21525
- config = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
21662
+ if (import_fs48.default.existsSync(configPath))
21663
+ config = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
21526
21664
  } catch {
21527
21665
  }
21528
21666
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -21537,9 +21675,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21537
21675
  approvers.cloud = false;
21538
21676
  }
21539
21677
  s.approvers = approvers;
21540
- if (!import_fs47.default.existsSync(import_path49.default.dirname(configPath)))
21541
- import_fs47.default.mkdirSync(import_path49.default.dirname(configPath), { recursive: true });
21542
- import_fs47.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
21678
+ if (!import_fs48.default.existsSync(import_path49.default.dirname(configPath)))
21679
+ import_fs48.default.mkdirSync(import_path49.default.dirname(configPath), { recursive: true });
21680
+ import_fs48.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
21543
21681
  }
21544
21682
  if (options.profile && profileName !== "default") {
21545
21683
  console.log(import_chalk30.default.green(`\u2705 Profile "${profileName}" saved`));
@@ -21677,14 +21815,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
21677
21815
  }
21678
21816
  if (options.purge) {
21679
21817
  const node9Dir = import_path49.default.join(import_os43.default.homedir(), ".node9");
21680
- if (import_fs47.default.existsSync(node9Dir)) {
21818
+ if (import_fs48.default.existsSync(node9Dir)) {
21681
21819
  const confirmed = await (0, import_prompts2.confirm)({
21682
21820
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
21683
21821
  default: false
21684
21822
  });
21685
21823
  if (confirmed) {
21686
- import_fs47.default.rmSync(node9Dir, { recursive: true });
21687
- if (import_fs47.default.existsSync(node9Dir)) {
21824
+ import_fs48.default.rmSync(node9Dir, { recursive: true });
21825
+ if (import_fs48.default.existsSync(node9Dir)) {
21688
21826
  console.error(
21689
21827
  import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
21690
21828
  );
@@ -21839,12 +21977,12 @@ Run "node9 addto claude" to register it as the statusLine.`
21839
21977
  if (subcommand === "debug") {
21840
21978
  const flagFile = import_path49.default.join(import_os43.default.homedir(), ".node9", "hud-debug");
21841
21979
  if (state === "on") {
21842
- import_fs47.default.mkdirSync(import_path49.default.dirname(flagFile), { recursive: true });
21843
- import_fs47.default.writeFileSync(flagFile, "");
21980
+ import_fs48.default.mkdirSync(import_path49.default.dirname(flagFile), { recursive: true });
21981
+ import_fs48.default.writeFileSync(flagFile, "");
21844
21982
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
21845
21983
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
21846
21984
  } else if (state === "off") {
21847
- if (import_fs47.default.existsSync(flagFile)) import_fs47.default.unlinkSync(flagFile);
21985
+ if (import_fs48.default.existsSync(flagFile)) import_fs48.default.unlinkSync(flagFile);
21848
21986
  console.log("HUD debug logging disabled.");
21849
21987
  } else {
21850
21988
  console.error("Usage: node9 hud debug on|off");
@@ -21960,7 +22098,7 @@ if (process.argv[2] !== "daemon") {
21960
22098
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
21961
22099
  const logPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
21962
22100
  const msg = reason instanceof Error ? reason.message : String(reason);
21963
- import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
22101
+ import_fs48.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
21964
22102
  `);
21965
22103
  }
21966
22104
  process.exit(0);