@node9/proxy 1.22.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.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
  }
@@ -10883,7 +11049,7 @@ function registerScanCommand(program2) {
10883
11049
  if (!drillDown) {
10884
11050
  const useInk2 = !options.classic;
10885
11051
  if (useInk2) {
10886
- const scanInkPath = import_path21.default.join(__dirname, "scan-ink.mjs");
11052
+ const scanInkPath = import_path22.default.join(__dirname, "scan-ink.mjs");
10887
11053
  const dynamicImport = new Function("id", "return import(id)");
10888
11054
  const mod = await dynamicImport(`file://${scanInkPath}`);
10889
11055
  const rangeLabel2 = options.all ? "all time" : `last ${options.days ?? 90} days`;
@@ -11108,14 +11274,14 @@ function registerScanCommand(program2) {
11108
11274
  }
11109
11275
  );
11110
11276
  }
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;
11277
+ 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
11278
  var init_scan = __esm({
11113
11279
  "src/cli/commands/scan.ts"() {
11114
11280
  "use strict";
11115
11281
  import_chalk5 = __toESM(require("chalk"));
11116
- import_fs19 = __toESM(require("fs"));
11117
- import_path21 = __toESM(require("path"));
11118
- import_os18 = __toESM(require("os"));
11282
+ import_fs20 = __toESM(require("fs"));
11283
+ import_path22 = __toESM(require("path"));
11284
+ import_os19 = __toESM(require("os"));
11119
11285
  init_shields();
11120
11286
  init_config();
11121
11287
  init_policy();
@@ -11242,11 +11408,11 @@ function commonPathPrefix(paths) {
11242
11408
  const prefix = common.join("/").replace(/\/?$/, "/");
11243
11409
  return prefix.length > 1 ? prefix : null;
11244
11410
  }
11245
- var import_crypto5, SuggestionTracker;
11411
+ var import_crypto6, SuggestionTracker;
11246
11412
  var init_suggestion_tracker = __esm({
11247
11413
  "src/daemon/suggestion-tracker.ts"() {
11248
11414
  "use strict";
11249
- import_crypto5 = require("crypto");
11415
+ import_crypto6 = require("crypto");
11250
11416
  SuggestionTracker = class {
11251
11417
  events = /* @__PURE__ */ new Map();
11252
11418
  threshold;
@@ -11292,7 +11458,7 @@ var init_suggestion_tracker = __esm({
11292
11458
  }
11293
11459
  } : { type: "ignoredTool", toolName };
11294
11460
  return {
11295
- id: (0, import_crypto5.randomUUID)(),
11461
+ id: (0, import_crypto6.randomUUID)(),
11296
11462
  toolName,
11297
11463
  allowCount: events.length,
11298
11464
  suggestedRule,
@@ -11306,12 +11472,12 @@ var init_suggestion_tracker = __esm({
11306
11472
  });
11307
11473
 
11308
11474
  // src/daemon/taint-store.ts
11309
- var import_fs20, import_path22, DEFAULT_TTL_MS, TaintStore;
11475
+ var import_fs21, import_path23, DEFAULT_TTL_MS, TaintStore;
11310
11476
  var init_taint_store = __esm({
11311
11477
  "src/daemon/taint-store.ts"() {
11312
11478
  "use strict";
11313
- import_fs20 = __toESM(require("fs"));
11314
- import_path22 = __toESM(require("path"));
11479
+ import_fs21 = __toESM(require("fs"));
11480
+ import_path23 = __toESM(require("path"));
11315
11481
  DEFAULT_TTL_MS = 60 * 60 * 1e3;
11316
11482
  TaintStore = class {
11317
11483
  records = /* @__PURE__ */ new Map();
@@ -11376,9 +11542,9 @@ var init_taint_store = __esm({
11376
11542
  /** Resolve to absolute path, falling back to path.resolve if file doesn't exist yet. */
11377
11543
  _resolve(filePath) {
11378
11544
  try {
11379
- return import_fs20.default.realpathSync.native(import_path22.default.resolve(filePath));
11545
+ return import_fs21.default.realpathSync.native(import_path23.default.resolve(filePath));
11380
11546
  } catch {
11381
- return import_path22.default.resolve(filePath);
11547
+ return import_path23.default.resolve(filePath);
11382
11548
  }
11383
11549
  }
11384
11550
  };
@@ -11496,8 +11662,8 @@ var init_session_history = __esm({
11496
11662
  // src/daemon/state.ts
11497
11663
  function loadInsightCounts() {
11498
11664
  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"));
11665
+ if (!import_fs22.default.existsSync(INSIGHT_COUNTS_FILE)) return;
11666
+ const data = JSON.parse(import_fs22.default.readFileSync(INSIGHT_COUNTS_FILE, "utf-8"));
11501
11667
  for (const [tool, count] of Object.entries(data)) {
11502
11668
  if (typeof count === "number" && count > 0) insightCounts.set(tool, count);
11503
11669
  }
@@ -11536,23 +11702,23 @@ function markRejectionHandlerRegistered() {
11536
11702
  daemonRejectionHandlerRegistered = true;
11537
11703
  }
11538
11704
  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`;
11705
+ const dir = import_path24.default.dirname(filePath);
11706
+ if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
11707
+ const tmpPath = `${filePath}.${(0, import_crypto7.randomUUID)()}.tmp`;
11542
11708
  try {
11543
- import_fs21.default.writeFileSync(tmpPath, data, options);
11709
+ import_fs22.default.writeFileSync(tmpPath, data, options);
11544
11710
  } catch (err2) {
11545
11711
  try {
11546
- import_fs21.default.unlinkSync(tmpPath);
11712
+ import_fs22.default.unlinkSync(tmpPath);
11547
11713
  } catch {
11548
11714
  }
11549
11715
  throw err2;
11550
11716
  }
11551
11717
  try {
11552
- import_fs21.default.renameSync(tmpPath, filePath);
11718
+ import_fs22.default.renameSync(tmpPath, filePath);
11553
11719
  } catch (err2) {
11554
11720
  try {
11555
- import_fs21.default.unlinkSync(tmpPath);
11721
+ import_fs22.default.unlinkSync(tmpPath);
11556
11722
  } catch {
11557
11723
  }
11558
11724
  throw err2;
@@ -11576,16 +11742,16 @@ function appendAuditLog(data) {
11576
11742
  decision: data.decision,
11577
11743
  source: "daemon"
11578
11744
  };
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");
11745
+ const dir = import_path24.default.dirname(AUDIT_LOG_FILE);
11746
+ if (!import_fs22.default.existsSync(dir)) import_fs22.default.mkdirSync(dir, { recursive: true });
11747
+ import_fs22.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
11582
11748
  } catch {
11583
11749
  }
11584
11750
  }
11585
11751
  function getAuditHistory(limit = 20) {
11586
11752
  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");
11753
+ if (!import_fs22.default.existsSync(AUDIT_LOG_FILE)) return [];
11754
+ const lines = import_fs22.default.readFileSync(AUDIT_LOG_FILE, "utf-8").trim().split("\n");
11589
11755
  if (lines.length === 1 && lines[0] === "") return [];
11590
11756
  return lines.slice(-limit).map((l) => JSON.parse(l)).reverse();
11591
11757
  } catch {
@@ -11594,7 +11760,7 @@ function getAuditHistory(limit = 20) {
11594
11760
  }
11595
11761
  function getOrgName() {
11596
11762
  try {
11597
- if (import_fs21.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11763
+ if (import_fs22.default.existsSync(CREDENTIALS_FILE)) return "Node9 Cloud";
11598
11764
  } catch {
11599
11765
  }
11600
11766
  return null;
@@ -11602,8 +11768,8 @@ function getOrgName() {
11602
11768
  function writeGlobalSetting(key, value) {
11603
11769
  let config = {};
11604
11770
  try {
11605
- if (import_fs21.default.existsSync(GLOBAL_CONFIG_FILE)) {
11606
- config = JSON.parse(import_fs21.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11771
+ if (import_fs22.default.existsSync(GLOBAL_CONFIG_FILE)) {
11772
+ config = JSON.parse(import_fs22.default.readFileSync(GLOBAL_CONFIG_FILE, "utf-8"));
11607
11773
  }
11608
11774
  } catch {
11609
11775
  }
@@ -11615,8 +11781,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11615
11781
  try {
11616
11782
  let trust = { entries: [] };
11617
11783
  try {
11618
- if (import_fs21.default.existsSync(TRUST_FILE2))
11619
- trust = JSON.parse(import_fs21.default.readFileSync(TRUST_FILE2, "utf-8"));
11784
+ if (import_fs22.default.existsSync(TRUST_FILE2))
11785
+ trust = JSON.parse(import_fs22.default.readFileSync(TRUST_FILE2, "utf-8"));
11620
11786
  } catch {
11621
11787
  }
11622
11788
  trust.entries = trust.entries.filter(
@@ -11633,8 +11799,8 @@ function writeTrustEntry(toolName, durationMs, commandPattern) {
11633
11799
  }
11634
11800
  function readPersistentDecisions() {
11635
11801
  try {
11636
- if (import_fs21.default.existsSync(DECISIONS_FILE)) {
11637
- return JSON.parse(import_fs21.default.readFileSync(DECISIONS_FILE, "utf-8"));
11802
+ if (import_fs22.default.existsSync(DECISIONS_FILE)) {
11803
+ return JSON.parse(import_fs22.default.readFileSync(DECISIONS_FILE, "utf-8"));
11638
11804
  }
11639
11805
  } catch {
11640
11806
  }
@@ -11662,7 +11828,7 @@ function estimateToolCost(tool, args) {
11662
11828
  const filePath = a.file_path ?? a.path;
11663
11829
  if (filePath) {
11664
11830
  try {
11665
- const bytes = import_fs21.default.statSync(filePath).size;
11831
+ const bytes = import_fs22.default.statSync(filePath).size;
11666
11832
  return bytes / BYTES_PER_TOKEN / 1e6 * INPUT_PRICE_PER_1M;
11667
11833
  } catch {
11668
11834
  }
@@ -11713,7 +11879,7 @@ function broadcastForensic(finding) {
11713
11879
  const severity = CRITICAL_FORENSIC_CATEGORIES.has(finding.type) ? "critical" : "warning";
11714
11880
  const event = {
11715
11881
  type: "forensic",
11716
- id: `fnd_${(0, import_crypto6.randomUUID)()}`,
11882
+ id: `fnd_${(0, import_crypto7.randomUUID)()}`,
11717
11883
  ts: Date.now(),
11718
11884
  sessionId: finding.sessionId,
11719
11885
  category: finding.type,
@@ -11733,7 +11899,7 @@ function abandonPending() {
11733
11899
  });
11734
11900
  if (autoStarted) {
11735
11901
  try {
11736
- import_fs21.default.unlinkSync(DAEMON_PID_FILE);
11902
+ import_fs22.default.unlinkSync(DAEMON_PID_FILE);
11737
11903
  } catch {
11738
11904
  }
11739
11905
  setTimeout(() => {
@@ -11744,8 +11910,8 @@ function abandonPending() {
11744
11910
  }
11745
11911
  function logActivitySocket(msg) {
11746
11912
  try {
11747
- import_fs21.default.appendFileSync(
11748
- import_path23.default.join(homeDir, ".node9", "hook-debug.log"),
11913
+ import_fs22.default.appendFileSync(
11914
+ import_path24.default.join(homeDir, ".node9", "hook-debug.log"),
11749
11915
  `[${(/* @__PURE__ */ new Date()).toISOString()}] [activity-socket] ${msg}
11750
11916
  `
11751
11917
  );
@@ -11767,13 +11933,13 @@ function shouldRebind(now = Date.now()) {
11767
11933
  function startActivitySocket() {
11768
11934
  bindActivitySocket();
11769
11935
  activityHealthInterval = setInterval(() => {
11770
- if (!import_fs21.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11936
+ if (!import_fs22.default.existsSync(ACTIVITY_SOCKET_PATH2)) attemptRebind("health-probe");
11771
11937
  }, ACTIVITY_HEALTH_PROBE_MS);
11772
11938
  activityHealthInterval.unref();
11773
11939
  process.on("exit", () => {
11774
11940
  if (activityHealthInterval) clearInterval(activityHealthInterval);
11775
11941
  try {
11776
- import_fs21.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11942
+ import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11777
11943
  } catch {
11778
11944
  }
11779
11945
  });
@@ -11801,7 +11967,7 @@ function attemptRebind(reason) {
11801
11967
  }
11802
11968
  function bindActivitySocket() {
11803
11969
  try {
11804
- import_fs21.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11970
+ import_fs22.default.unlinkSync(ACTIVITY_SOCKET_PATH2);
11805
11971
  } catch {
11806
11972
  }
11807
11973
  const ACTIVITY_MAX_BYTES = 1024 * 1024;
@@ -11905,28 +12071,28 @@ function bindActivitySocket() {
11905
12071
  });
11906
12072
  activitySocketServer = unixServer;
11907
12073
  }
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;
12074
+ 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
12075
  var init_state2 = __esm({
11910
12076
  "src/daemon/state.ts"() {
11911
12077
  "use strict";
11912
12078
  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");
12079
+ import_fs22 = __toESM(require("fs"));
12080
+ import_path24 = __toESM(require("path"));
12081
+ import_os20 = __toESM(require("os"));
12082
+ import_crypto7 = require("crypto");
11917
12083
  init_daemon();
11918
12084
  init_suggestion_tracker();
11919
12085
  init_taint_store();
11920
12086
  init_session_counters();
11921
12087
  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");
12088
+ homeDir = import_os20.default.homedir();
12089
+ DAEMON_PID_FILE = import_path24.default.join(homeDir, ".node9", "daemon.pid");
12090
+ DECISIONS_FILE = import_path24.default.join(homeDir, ".node9", "decisions.json");
12091
+ AUDIT_LOG_FILE = import_path24.default.join(homeDir, ".node9", "audit.log");
12092
+ TRUST_FILE2 = import_path24.default.join(homeDir, ".node9", "trust.json");
12093
+ GLOBAL_CONFIG_FILE = import_path24.default.join(homeDir, ".node9", "config.json");
12094
+ CREDENTIALS_FILE = import_path24.default.join(homeDir, ".node9", "credentials.json");
12095
+ INSIGHT_COUNTS_FILE = import_path24.default.join(homeDir, ".node9", "insight-counts.json");
11930
12096
  pending = /* @__PURE__ */ new Map();
11931
12097
  sseClients = /* @__PURE__ */ new Set();
11932
12098
  suggestionTracker = new SuggestionTracker(3);
@@ -11943,7 +12109,7 @@ var init_state2 = __esm({
11943
12109
  "2h": 2 * 60 * 6e4
11944
12110
  };
11945
12111
  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");
12112
+ ACTIVITY_SOCKET_PATH2 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path24.default.join(import_os20.default.tmpdir(), "node9-activity.sock");
11947
12113
  ACTIVITY_RING_SIZE = 100;
11948
12114
  activityRing = [];
11949
12115
  LARGE_RESPONSE_RING_SIZE = 20;
@@ -12021,8 +12187,8 @@ function readCredentials() {
12021
12187
  };
12022
12188
  }
12023
12189
  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"));
12190
+ const credPath = import_path25.default.join(import_os21.default.homedir(), ".node9", "credentials.json");
12191
+ const creds = JSON.parse(import_fs23.default.readFileSync(credPath, "utf-8"));
12026
12192
  const profileName = process.env.NODE9_PROFILE ?? "default";
12027
12193
  const profile = creds[profileName];
12028
12194
  if (typeof profile?.apiKey === "string" && profile.apiKey.length > 0) {
@@ -12048,7 +12214,7 @@ function readCredentials() {
12048
12214
  }
12049
12215
  function readCachedEtag() {
12050
12216
  try {
12051
- const raw = JSON.parse(import_fs22.default.readFileSync(rulesCacheFile(), "utf-8"));
12217
+ const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
12052
12218
  return typeof raw.etag === "string" ? raw.etag : void 0;
12053
12219
  } catch {
12054
12220
  return void 0;
@@ -12109,9 +12275,9 @@ function extractRules(body) {
12109
12275
  return [];
12110
12276
  }
12111
12277
  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");
12278
+ const dir = import_path25.default.dirname(rulesCacheFile());
12279
+ if (!import_fs23.default.existsSync(dir)) import_fs23.default.mkdirSync(dir, { recursive: true });
12280
+ import_fs23.default.writeFileSync(rulesCacheFile(), JSON.stringify(cache, null, 2) + "\n", "utf-8");
12115
12281
  }
12116
12282
  async function syncOnce() {
12117
12283
  const creds = readCredentials();
@@ -12268,7 +12434,7 @@ async function runCloudSync() {
12268
12434
  }
12269
12435
  function getCloudSyncStatus() {
12270
12436
  try {
12271
- const raw = JSON.parse(import_fs22.default.readFileSync(rulesCacheFile(), "utf-8"));
12437
+ const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
12272
12438
  if (!Array.isArray(raw.rules) || typeof raw.fetchedAt !== "string") return { cached: false };
12273
12439
  return {
12274
12440
  cached: true,
@@ -12285,7 +12451,7 @@ function getCloudSyncStatus() {
12285
12451
  }
12286
12452
  function getCloudRules() {
12287
12453
  try {
12288
- const raw = JSON.parse(import_fs22.default.readFileSync(rulesCacheFile(), "utf-8"));
12454
+ const raw = JSON.parse(import_fs23.default.readFileSync(rulesCacheFile(), "utf-8"));
12289
12455
  return Array.isArray(raw.rules) ? raw.rules : null;
12290
12456
  } catch {
12291
12457
  return null;
@@ -12319,14 +12485,14 @@ function startForensicBroadcast() {
12319
12485
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
12320
12486
  recurring.unref();
12321
12487
  }
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;
12488
+ 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
12489
  var init_sync = __esm({
12324
12490
  "src/daemon/sync.ts"() {
12325
12491
  "use strict";
12326
- import_fs22 = __toESM(require("fs"));
12492
+ import_fs23 = __toESM(require("fs"));
12327
12493
  import_https2 = __toESM(require("https"));
12328
- import_os20 = __toESM(require("os"));
12329
- import_path24 = __toESM(require("path"));
12494
+ import_os21 = __toESM(require("os"));
12495
+ import_path25 = __toESM(require("path"));
12330
12496
  init_config();
12331
12497
  init_blast();
12332
12498
  init_dist();
@@ -12345,7 +12511,7 @@ var init_sync = __esm({
12345
12511
  loop: "loops",
12346
12512
  "long-output-redacted": "longOutputRedactions"
12347
12513
  };
12348
- rulesCacheFile = () => import_path24.default.join(import_os20.default.homedir(), ".node9", "rules-cache.json");
12514
+ rulesCacheFile = () => import_path25.default.join(import_os21.default.homedir(), ".node9", "rules-cache.json");
12349
12515
  DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
12350
12516
  DEFAULT_INTERVAL_HOURS = 5;
12351
12517
  MIN_INTERVAL_HOURS = 1;
@@ -12358,68 +12524,68 @@ var init_sync = __esm({
12358
12524
  // src/daemon/dlp-scanner.ts
12359
12525
  function loadIndex() {
12360
12526
  try {
12361
- return JSON.parse(import_fs23.default.readFileSync(INDEX_FILE, "utf-8"));
12527
+ return JSON.parse(import_fs24.default.readFileSync(INDEX_FILE, "utf-8"));
12362
12528
  } catch {
12363
12529
  return {};
12364
12530
  }
12365
12531
  }
12366
12532
  function saveIndex(index) {
12367
12533
  try {
12368
- import_fs23.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12534
+ import_fs24.default.writeFileSync(INDEX_FILE, JSON.stringify(index), { encoding: "utf-8", mode: 384 });
12369
12535
  } catch {
12370
12536
  }
12371
12537
  }
12372
12538
  function appendAuditEntry(entry) {
12373
12539
  try {
12374
- import_fs23.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12540
+ import_fs24.default.appendFileSync(AUDIT_LOG_FILE, JSON.stringify(entry) + "\n");
12375
12541
  } catch {
12376
12542
  }
12377
12543
  }
12378
12544
  function runDlpScan() {
12379
- if (!import_fs23.default.existsSync(PROJECTS_DIR2)) return;
12545
+ if (!import_fs24.default.existsSync(PROJECTS_DIR2)) return;
12380
12546
  const index = loadIndex();
12381
12547
  let updated = false;
12382
12548
  let projDirs;
12383
12549
  try {
12384
- projDirs = import_fs23.default.readdirSync(PROJECTS_DIR2);
12550
+ projDirs = import_fs24.default.readdirSync(PROJECTS_DIR2);
12385
12551
  } catch {
12386
12552
  return;
12387
12553
  }
12388
12554
  for (const proj of projDirs) {
12389
- const projPath = import_path25.default.join(PROJECTS_DIR2, proj);
12555
+ const projPath = import_path26.default.join(PROJECTS_DIR2, proj);
12390
12556
  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;
12557
+ if (!import_fs24.default.lstatSync(projPath).isDirectory()) continue;
12558
+ const real = import_fs24.default.realpathSync(projPath);
12559
+ if (!real.startsWith(PROJECTS_DIR2 + import_path26.default.sep) && real !== PROJECTS_DIR2) continue;
12394
12560
  } catch {
12395
12561
  continue;
12396
12562
  }
12397
12563
  let files;
12398
12564
  try {
12399
- files = import_fs23.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12565
+ files = import_fs24.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
12400
12566
  } catch {
12401
12567
  continue;
12402
12568
  }
12403
12569
  for (const file of files) {
12404
- const filePath = import_path25.default.join(projPath, file);
12570
+ const filePath = import_path26.default.join(projPath, file);
12405
12571
  const lastOffset = index[filePath] ?? 0;
12406
12572
  let size;
12407
12573
  try {
12408
- size = import_fs23.default.statSync(filePath).size;
12574
+ size = import_fs24.default.statSync(filePath).size;
12409
12575
  } catch {
12410
12576
  continue;
12411
12577
  }
12412
12578
  if (size <= lastOffset) continue;
12413
12579
  let fd;
12414
12580
  try {
12415
- fd = import_fs23.default.openSync(filePath, "r");
12581
+ fd = import_fs24.default.openSync(filePath, "r");
12416
12582
  } catch {
12417
12583
  continue;
12418
12584
  }
12419
12585
  try {
12420
12586
  const chunkSize = size - lastOffset;
12421
12587
  const buf = Buffer.alloc(chunkSize);
12422
- import_fs23.default.readSync(fd, buf, 0, chunkSize, lastOffset);
12588
+ import_fs24.default.readSync(fd, buf, 0, chunkSize, lastOffset);
12423
12589
  const chunk = buf.toString("utf-8");
12424
12590
  for (const line of chunk.split("\n")) {
12425
12591
  if (!line.trim()) continue;
@@ -12439,7 +12605,7 @@ function runDlpScan() {
12439
12605
  if (typeof text !== "string") continue;
12440
12606
  const match = scanText(text);
12441
12607
  if (!match) continue;
12442
- const projLabel = decodeURIComponent(proj).replace(import_os21.default.homedir(), "~").slice(0, 40);
12608
+ const projLabel = decodeURIComponent(proj).replace(import_os22.default.homedir(), "~").slice(0, 40);
12443
12609
  const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
12444
12610
  appendAuditEntry({
12445
12611
  ts,
@@ -12464,7 +12630,7 @@ Run: node9 report --period 30d`
12464
12630
  updated = true;
12465
12631
  } finally {
12466
12632
  try {
12467
- import_fs23.default.closeSync(fd);
12633
+ import_fs24.default.closeSync(fd);
12468
12634
  } catch {
12469
12635
  }
12470
12636
  }
@@ -12490,30 +12656,30 @@ function startDlpScanner() {
12490
12656
  );
12491
12657
  timer.unref();
12492
12658
  }
12493
- var import_fs23, import_path25, import_os21, INDEX_FILE, PROJECTS_DIR2;
12659
+ var import_fs24, import_path26, import_os22, INDEX_FILE, PROJECTS_DIR2;
12494
12660
  var init_dlp_scanner = __esm({
12495
12661
  "src/daemon/dlp-scanner.ts"() {
12496
12662
  "use strict";
12497
- import_fs23 = __toESM(require("fs"));
12498
- import_path25 = __toESM(require("path"));
12499
- import_os21 = __toESM(require("os"));
12663
+ import_fs24 = __toESM(require("fs"));
12664
+ import_path26 = __toESM(require("path"));
12665
+ import_os22 = __toESM(require("os"));
12500
12666
  init_dlp();
12501
12667
  init_native();
12502
12668
  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");
12669
+ INDEX_FILE = import_path26.default.join(import_os22.default.homedir(), ".node9", "dlp-index.json");
12670
+ PROJECTS_DIR2 = import_path26.default.join(import_os22.default.homedir(), ".claude", "projects");
12505
12671
  }
12506
12672
  });
12507
12673
 
12508
12674
  // src/daemon/mcp-tools.ts
12509
12675
  function getMcpToolsFile() {
12510
- return import_path26.default.join(import_os22.default.homedir(), ".node9", "mcp-tools.json");
12676
+ return import_path27.default.join(import_os23.default.homedir(), ".node9", "mcp-tools.json");
12511
12677
  }
12512
12678
  function readMcpToolsConfig() {
12513
12679
  try {
12514
12680
  const file = getMcpToolsFile();
12515
- if (!import_fs24.default.existsSync(file)) return {};
12516
- const raw = import_fs24.default.readFileSync(file, "utf-8");
12681
+ if (!import_fs25.default.existsSync(file)) return {};
12682
+ const raw = import_fs25.default.readFileSync(file, "utf-8");
12517
12683
  return JSON.parse(raw);
12518
12684
  } catch {
12519
12685
  return {};
@@ -12522,11 +12688,11 @@ function readMcpToolsConfig() {
12522
12688
  function writeMcpToolsConfig(config) {
12523
12689
  try {
12524
12690
  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);
12691
+ const dir = import_path27.default.dirname(file);
12692
+ if (!import_fs25.default.existsSync(dir)) import_fs25.default.mkdirSync(dir, { recursive: true });
12693
+ const tmpPath = `${file}.${import_os23.default.hostname()}.${process.pid}.tmp`;
12694
+ import_fs25.default.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
12695
+ import_fs25.default.renameSync(tmpPath, file);
12530
12696
  } catch (e) {
12531
12697
  console.error("Failed to write mcp-tools.json", e);
12532
12698
  }
@@ -12565,13 +12731,13 @@ function approveServer(serverKey, disabledTools) {
12565
12731
  writeMcpToolsConfig(config);
12566
12732
  }
12567
12733
  }
12568
- var import_fs24, import_path26, import_os22;
12734
+ var import_fs25, import_path27, import_os23;
12569
12735
  var init_mcp_tools = __esm({
12570
12736
  "src/daemon/mcp-tools.ts"() {
12571
12737
  "use strict";
12572
- import_fs24 = __toESM(require("fs"));
12573
- import_path26 = __toESM(require("path"));
12574
- import_os22 = __toESM(require("os"));
12738
+ import_fs25 = __toESM(require("fs"));
12739
+ import_path27 = __toESM(require("path"));
12740
+ import_os23 = __toESM(require("os"));
12575
12741
  }
12576
12742
  });
12577
12743
 
@@ -12582,7 +12748,7 @@ function startDaemon() {
12582
12748
  startForensicBroadcast();
12583
12749
  startDlpScanner();
12584
12750
  loadInsightCounts();
12585
- const internalToken = (0, import_crypto7.randomUUID)();
12751
+ const internalToken = (0, import_crypto8.randomUUID)();
12586
12752
  const validToken = (req) => req.headers["x-node9-internal"] === internalToken || req.headers["x-node9-token"] === internalToken;
12587
12753
  const IDLE_TIMEOUT_MS = 12 * 60 * 60 * 1e3;
12588
12754
  const watchMode = process.env.NODE9_WATCH_MODE === "1";
@@ -12593,7 +12759,7 @@ function startDaemon() {
12593
12759
  idleTimer = setTimeout(() => {
12594
12760
  if (autoStarted) {
12595
12761
  try {
12596
- import_fs25.default.unlinkSync(DAEMON_PID_FILE);
12762
+ import_fs26.default.unlinkSync(DAEMON_PID_FILE);
12597
12763
  } catch {
12598
12764
  }
12599
12765
  }
@@ -12694,7 +12860,7 @@ data: ${JSON.stringify(item.data)}
12694
12860
  cwd,
12695
12861
  localSmartRuleMatched = false
12696
12862
  } = JSON.parse(body);
12697
- const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto7.randomUUID)();
12863
+ const id = fromCLI && typeof activityId === "string" && activityId || (0, import_crypto8.randomUUID)();
12698
12864
  const entry = {
12699
12865
  id,
12700
12866
  toolName,
@@ -12738,7 +12904,7 @@ data: ${JSON.stringify(item.data)}
12738
12904
  mcpServer: entry.mcpServer
12739
12905
  });
12740
12906
  }
12741
- const projectCwd = typeof cwd === "string" && import_path27.default.isAbsolute(cwd) ? cwd : void 0;
12907
+ const projectCwd = typeof cwd === "string" && import_path28.default.isAbsolute(cwd) ? cwd : void 0;
12742
12908
  const projectConfig = getConfig(projectCwd);
12743
12909
  const browserEnabled = projectConfig.settings.approvers?.browser !== false;
12744
12910
  const terminalEnabled = projectConfig.settings.approvers?.terminal !== false;
@@ -13030,8 +13196,8 @@ data: ${JSON.stringify(item.data)}
13030
13196
  if (!validToken(req)) return res.writeHead(403).end();
13031
13197
  const periodParam = reqUrl.searchParams.get("period") || "7d";
13032
13198
  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)) {
13199
+ const logPath = import_path28.default.join(import_os24.default.homedir(), ".node9", "audit.log");
13200
+ if (!import_fs26.default.existsSync(logPath)) {
13035
13201
  res.writeHead(200, { "Content-Type": "application/json" });
13036
13202
  return res.end(
13037
13203
  JSON.stringify({
@@ -13044,7 +13210,7 @@ data: ${JSON.stringify(item.data)}
13044
13210
  );
13045
13211
  }
13046
13212
  try {
13047
- const raw = import_fs25.default.readFileSync(logPath, "utf-8");
13213
+ const raw = import_fs26.default.readFileSync(logPath, "utf-8");
13048
13214
  const allEntries = raw.split("\n").flatMap((line) => {
13049
13215
  if (!line.trim()) return [];
13050
13216
  try {
@@ -13279,7 +13445,7 @@ data: ${JSON.stringify(item.data)}
13279
13445
  args: { toolCount: tools.length, status },
13280
13446
  decision: "mcp-discovered"
13281
13447
  });
13282
- const id = (0, import_crypto7.randomUUID)();
13448
+ const id = (0, import_crypto8.randomUUID)();
13283
13449
  const entry = {
13284
13450
  id,
13285
13451
  type: "mcp-discovery",
@@ -13367,14 +13533,14 @@ data: ${JSON.stringify(item.data)}
13367
13533
  server.on("error", (e) => {
13368
13534
  if (e.code === "EADDRINUSE") {
13369
13535
  try {
13370
- if (import_fs25.default.existsSync(DAEMON_PID_FILE)) {
13371
- const { pid } = JSON.parse(import_fs25.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13536
+ if (import_fs26.default.existsSync(DAEMON_PID_FILE)) {
13537
+ const { pid } = JSON.parse(import_fs26.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13372
13538
  process.kill(pid, 0);
13373
13539
  return process.exit(0);
13374
13540
  }
13375
13541
  } catch {
13376
13542
  try {
13377
- import_fs25.default.unlinkSync(DAEMON_PID_FILE);
13543
+ import_fs26.default.unlinkSync(DAEMON_PID_FILE);
13378
13544
  } catch {
13379
13545
  }
13380
13546
  server.listen(DAEMON_PORT, DAEMON_HOST);
@@ -13446,15 +13612,15 @@ data: ${JSON.stringify(item.data)}
13446
13612
  }
13447
13613
  startActivitySocket();
13448
13614
  }
13449
- var import_http, import_fs25, import_path27, import_os23, import_crypto7, import_child_process2, import_chalk6;
13615
+ var import_http, import_fs26, import_path28, import_os24, import_crypto8, import_child_process2, import_chalk6;
13450
13616
  var init_server = __esm({
13451
13617
  "src/daemon/server.ts"() {
13452
13618
  "use strict";
13453
13619
  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");
13620
+ import_fs26 = __toESM(require("fs"));
13621
+ import_path28 = __toESM(require("path"));
13622
+ import_os24 = __toESM(require("os"));
13623
+ import_crypto8 = require("crypto");
13458
13624
  import_child_process2 = require("child_process");
13459
13625
  import_chalk6 = __toESM(require("chalk"));
13460
13626
  init_core();
@@ -13473,8 +13639,8 @@ var init_server = __esm({
13473
13639
  function resolveNode9Binary() {
13474
13640
  try {
13475
13641
  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);
13642
+ if (typeof script === "string" && import_path29.default.isAbsolute(script) && import_fs27.default.existsSync(script)) {
13643
+ return import_fs27.default.realpathSync(script);
13478
13644
  }
13479
13645
  } catch {
13480
13646
  }
@@ -13492,11 +13658,11 @@ function xmlEscape(s) {
13492
13658
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13493
13659
  }
13494
13660
  function launchdPlist(binaryPath) {
13495
- const logDir = import_path28.default.join(import_os24.default.homedir(), ".node9");
13661
+ const logDir = import_path29.default.join(import_os25.default.homedir(), ".node9");
13496
13662
  const nodePath = xmlEscape(process.execPath);
13497
13663
  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"));
13664
+ const outLog = xmlEscape(import_path29.default.join(logDir, "daemon.log"));
13665
+ const errLog = xmlEscape(import_path29.default.join(logDir, "daemon-error.log"));
13500
13666
  return `<?xml version="1.0" encoding="UTF-8"?>
13501
13667
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
13502
13668
  <plist version="1.0">
@@ -13529,9 +13695,9 @@ function launchdPlist(binaryPath) {
13529
13695
  `;
13530
13696
  }
13531
13697
  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");
13698
+ const dir = import_path29.default.dirname(LAUNCHD_PLIST);
13699
+ if (!import_fs27.default.existsSync(dir)) import_fs27.default.mkdirSync(dir, { recursive: true });
13700
+ import_fs27.default.writeFileSync(LAUNCHD_PLIST, launchdPlist(binaryPath), "utf-8");
13535
13701
  (0, import_child_process3.spawnSync)("launchctl", ["unload", LAUNCHD_PLIST], { encoding: "utf8" });
13536
13702
  const r = (0, import_child_process3.spawnSync)("launchctl", ["load", "-w", LAUNCHD_PLIST], {
13537
13703
  encoding: "utf8",
@@ -13542,13 +13708,13 @@ function installLaunchd(binaryPath) {
13542
13708
  }
13543
13709
  }
13544
13710
  function uninstallLaunchd() {
13545
- if (import_fs26.default.existsSync(LAUNCHD_PLIST)) {
13711
+ if (import_fs27.default.existsSync(LAUNCHD_PLIST)) {
13546
13712
  (0, import_child_process3.spawnSync)("launchctl", ["unload", "-w", LAUNCHD_PLIST], { encoding: "utf8", timeout: 5e3 });
13547
- import_fs26.default.unlinkSync(LAUNCHD_PLIST);
13713
+ import_fs27.default.unlinkSync(LAUNCHD_PLIST);
13548
13714
  }
13549
13715
  }
13550
13716
  function isLaunchdInstalled() {
13551
- return import_fs26.default.existsSync(LAUNCHD_PLIST);
13717
+ return import_fs27.default.existsSync(LAUNCHD_PLIST);
13552
13718
  }
13553
13719
  function systemdUnit(binaryPath) {
13554
13720
  return `[Unit]
@@ -13567,12 +13733,12 @@ WantedBy=default.target
13567
13733
  `;
13568
13734
  }
13569
13735
  function installSystemd(binaryPath) {
13570
- if (!import_fs26.default.existsSync(SYSTEMD_UNIT_DIR)) {
13571
- import_fs26.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13736
+ if (!import_fs27.default.existsSync(SYSTEMD_UNIT_DIR)) {
13737
+ import_fs27.default.mkdirSync(SYSTEMD_UNIT_DIR, { recursive: true });
13572
13738
  }
13573
- import_fs26.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13739
+ import_fs27.default.writeFileSync(SYSTEMD_UNIT, systemdUnit(binaryPath), "utf-8");
13574
13740
  try {
13575
- (0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os24.default.userInfo().username], { timeout: 3e3 });
13741
+ (0, import_child_process3.execFileSync)("loginctl", ["enable-linger", import_os25.default.userInfo().username], { timeout: 3e3 });
13576
13742
  } catch {
13577
13743
  }
13578
13744
  const reload = (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], {
@@ -13592,23 +13758,23 @@ function installSystemd(binaryPath) {
13592
13758
  }
13593
13759
  }
13594
13760
  function uninstallSystemd() {
13595
- if (import_fs26.default.existsSync(SYSTEMD_UNIT)) {
13761
+ if (import_fs27.default.existsSync(SYSTEMD_UNIT)) {
13596
13762
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "disable", "--now", "node9-daemon"], {
13597
13763
  encoding: "utf8",
13598
13764
  timeout: 5e3
13599
13765
  });
13600
13766
  (0, import_child_process3.spawnSync)("systemctl", ["--user", "daemon-reload"], { encoding: "utf8", timeout: 5e3 });
13601
- import_fs26.default.unlinkSync(SYSTEMD_UNIT);
13767
+ import_fs27.default.unlinkSync(SYSTEMD_UNIT);
13602
13768
  }
13603
13769
  }
13604
13770
  function isSystemdInstalled() {
13605
- return import_fs26.default.existsSync(SYSTEMD_UNIT);
13771
+ return import_fs27.default.existsSync(SYSTEMD_UNIT);
13606
13772
  }
13607
13773
  function stopRunningDaemon() {
13608
- const pidFile = import_path28.default.join(import_os24.default.homedir(), ".node9", "daemon.pid");
13609
- if (!import_fs26.default.existsSync(pidFile)) return;
13774
+ const pidFile = import_path29.default.join(import_os25.default.homedir(), ".node9", "daemon.pid");
13775
+ if (!import_fs27.default.existsSync(pidFile)) return;
13610
13776
  try {
13611
- const data = JSON.parse(import_fs26.default.readFileSync(pidFile, "utf-8"));
13777
+ const data = JSON.parse(import_fs27.default.readFileSync(pidFile, "utf-8"));
13612
13778
  const pid = data.pid;
13613
13779
  const MAX_PID2 = 4194304;
13614
13780
  if (typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= MAX_PID2) {
@@ -13628,7 +13794,7 @@ function stopRunningDaemon() {
13628
13794
  }
13629
13795
  }
13630
13796
  try {
13631
- import_fs26.default.unlinkSync(pidFile);
13797
+ import_fs27.default.unlinkSync(pidFile);
13632
13798
  } catch {
13633
13799
  }
13634
13800
  } catch {
@@ -13698,26 +13864,26 @@ function isDaemonServiceInstalled() {
13698
13864
  if (process.platform === "linux") return isSystemdInstalled();
13699
13865
  return false;
13700
13866
  }
13701
- var import_fs26, import_path28, import_os24, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
13867
+ var import_fs27, import_path29, import_os25, import_child_process3, LAUNCHD_LABEL, LAUNCHD_PLIST, SYSTEMD_UNIT_DIR, SYSTEMD_UNIT;
13702
13868
  var init_service = __esm({
13703
13869
  "src/daemon/service.ts"() {
13704
13870
  "use strict";
13705
- import_fs26 = __toESM(require("fs"));
13706
- import_path28 = __toESM(require("path"));
13707
- import_os24 = __toESM(require("os"));
13871
+ import_fs27 = __toESM(require("fs"));
13872
+ import_path29 = __toESM(require("path"));
13873
+ import_os25 = __toESM(require("os"));
13708
13874
  import_child_process3 = require("child_process");
13709
13875
  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");
13876
+ LAUNCHD_PLIST = import_path29.default.join(import_os25.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
13877
+ SYSTEMD_UNIT_DIR = import_path29.default.join(import_os25.default.homedir(), ".config", "systemd", "user");
13878
+ SYSTEMD_UNIT = import_path29.default.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
13713
13879
  }
13714
13880
  });
13715
13881
 
13716
13882
  // src/daemon/index.ts
13717
13883
  function stopDaemon() {
13718
- if (!import_fs27.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
13884
+ if (!import_fs28.default.existsSync(DAEMON_PID_FILE)) return console.log(import_chalk7.default.yellow("Not running."));
13719
13885
  try {
13720
- const data = JSON.parse(import_fs27.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13886
+ const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13721
13887
  const pid = data.pid;
13722
13888
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
13723
13889
  console.log(import_chalk7.default.gray("Cleaned up invalid PID file."));
@@ -13729,7 +13895,7 @@ function stopDaemon() {
13729
13895
  console.log(import_chalk7.default.gray("Cleaned up stale PID file."));
13730
13896
  } finally {
13731
13897
  try {
13732
- import_fs27.default.unlinkSync(DAEMON_PID_FILE);
13898
+ import_fs28.default.unlinkSync(DAEMON_PID_FILE);
13733
13899
  } catch {
13734
13900
  }
13735
13901
  }
@@ -13738,9 +13904,9 @@ function daemonStatus() {
13738
13904
  const serviceInstalled = isDaemonServiceInstalled();
13739
13905
  const serviceLabel = serviceInstalled ? import_chalk7.default.green("installed (starts on login)") : import_chalk7.default.yellow("not installed \u2014 run: node9 daemon install");
13740
13906
  let processStatus;
13741
- if (import_fs27.default.existsSync(DAEMON_PID_FILE)) {
13907
+ if (import_fs28.default.existsSync(DAEMON_PID_FILE)) {
13742
13908
  try {
13743
- const data = JSON.parse(import_fs27.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13909
+ const data = JSON.parse(import_fs28.default.readFileSync(DAEMON_PID_FILE, "utf-8"));
13744
13910
  const pid = data.pid;
13745
13911
  const port = data.port;
13746
13912
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || pid > MAX_PID) {
@@ -13762,11 +13928,11 @@ function daemonStatus() {
13762
13928
  console.log(` Service : ${serviceLabel}
13763
13929
  `);
13764
13930
  }
13765
- var import_fs27, import_chalk7, MAX_PID;
13931
+ var import_fs28, import_chalk7, MAX_PID;
13766
13932
  var init_daemon2 = __esm({
13767
13933
  "src/daemon/index.ts"() {
13768
13934
  "use strict";
13769
- import_fs27 = __toESM(require("fs"));
13935
+ import_fs28 = __toESM(require("fs"));
13770
13936
  import_chalk7 = __toESM(require("chalk"));
13771
13937
  init_server();
13772
13938
  init_state2();
@@ -13807,19 +13973,19 @@ function getModelContextLimit(model) {
13807
13973
  }
13808
13974
  function readSessionUsage() {
13809
13975
  const projectsDir = import_path47.default.join(import_os41.default.homedir(), ".claude", "projects");
13810
- if (!import_fs45.default.existsSync(projectsDir)) return null;
13976
+ if (!import_fs46.default.existsSync(projectsDir)) return null;
13811
13977
  let latestFile = null;
13812
13978
  let latestMtime = 0;
13813
13979
  try {
13814
- for (const dir of import_fs45.default.readdirSync(projectsDir)) {
13980
+ for (const dir of import_fs46.default.readdirSync(projectsDir)) {
13815
13981
  const dirPath = import_path47.default.join(projectsDir, dir);
13816
13982
  try {
13817
- if (!import_fs45.default.statSync(dirPath).isDirectory()) continue;
13818
- for (const file of import_fs45.default.readdirSync(dirPath)) {
13983
+ if (!import_fs46.default.statSync(dirPath).isDirectory()) continue;
13984
+ for (const file of import_fs46.default.readdirSync(dirPath)) {
13819
13985
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
13820
13986
  const filePath = import_path47.default.join(dirPath, file);
13821
13987
  try {
13822
- const mtime = import_fs45.default.statSync(filePath).mtimeMs;
13988
+ const mtime = import_fs46.default.statSync(filePath).mtimeMs;
13823
13989
  if (mtime > latestMtime) {
13824
13990
  latestMtime = mtime;
13825
13991
  latestFile = filePath;
@@ -13834,7 +14000,7 @@ function readSessionUsage() {
13834
14000
  }
13835
14001
  if (!latestFile) return null;
13836
14002
  try {
13837
- const lines = import_fs45.default.readFileSync(latestFile, "utf-8").split("\n");
14003
+ const lines = import_fs46.default.readFileSync(latestFile, "utf-8").split("\n");
13838
14004
  let lastModel = "";
13839
14005
  let lastInput = 0;
13840
14006
  let lastOutput = 0;
@@ -13934,9 +14100,9 @@ function renderPending(activity) {
13934
14100
  }
13935
14101
  async function ensureDaemon() {
13936
14102
  let pidPort = null;
13937
- if (import_fs45.default.existsSync(PID_FILE)) {
14103
+ if (import_fs46.default.existsSync(PID_FILE)) {
13938
14104
  try {
13939
- const { port } = JSON.parse(import_fs45.default.readFileSync(PID_FILE, "utf-8"));
14105
+ const { port } = JSON.parse(import_fs46.default.readFileSync(PID_FILE, "utf-8"));
13940
14106
  pidPort = port;
13941
14107
  } catch {
13942
14108
  console.error(import_chalk29.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -14094,7 +14260,7 @@ function buildRecoveryCardLines(req) {
14094
14260
  function readApproversFromDisk() {
14095
14261
  const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
14096
14262
  try {
14097
- const raw = JSON.parse(import_fs45.default.readFileSync(configPath, "utf-8"));
14263
+ const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
14098
14264
  const settings = raw.settings ?? {};
14099
14265
  return settings.approvers ?? {};
14100
14266
  } catch {
@@ -14112,13 +14278,13 @@ function approverStatusLine() {
14112
14278
  function toggleApprover(channel) {
14113
14279
  const configPath = import_path47.default.join(import_os41.default.homedir(), ".node9", "config.json");
14114
14280
  try {
14115
- const raw = JSON.parse(import_fs45.default.readFileSync(configPath, "utf-8"));
14281
+ const raw = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
14116
14282
  const settings = raw.settings ?? {};
14117
14283
  const approvers = settings.approvers ?? {};
14118
14284
  approvers[channel] = approvers[channel] === false;
14119
14285
  settings.approvers = approvers;
14120
14286
  raw.settings = settings;
14121
- import_fs45.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14287
+ import_fs46.default.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
14122
14288
  } catch (err2) {
14123
14289
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
14124
14290
  `);
@@ -14290,7 +14456,7 @@ async function startTail(options = {}) {
14290
14456
  }
14291
14457
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
14292
14458
  try {
14293
- import_fs45.default.appendFileSync(
14459
+ import_fs46.default.appendFileSync(
14294
14460
  import_path47.default.join(import_os41.default.homedir(), ".node9", "hook-debug.log"),
14295
14461
  `[tail] POST /decision failed: ${String(err2)}
14296
14462
  `
@@ -14357,7 +14523,7 @@ async function startTail(options = {}) {
14357
14523
  }
14358
14524
  const auditLog = import_path47.default.join(import_os41.default.homedir(), ".node9", "audit.log");
14359
14525
  try {
14360
- const unackedDlp = import_fs45.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14526
+ const unackedDlp = import_fs46.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
14361
14527
  if (unackedDlp > 0) {
14362
14528
  console.log("");
14363
14529
  console.log(
@@ -14397,7 +14563,7 @@ async function startTail(options = {}) {
14397
14563
  if (stallWarned) return;
14398
14564
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
14399
14565
  try {
14400
- const auditMtime = import_fs45.default.statSync(auditLog).mtimeMs;
14566
+ const auditMtime = import_fs46.default.statSync(auditLog).mtimeMs;
14401
14567
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
14402
14568
  console.log("");
14403
14569
  console.log(
@@ -14582,13 +14748,13 @@ async function startTail(options = {}) {
14582
14748
  process.exit(1);
14583
14749
  });
14584
14750
  }
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;
14751
+ 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
14752
  var init_tail = __esm({
14587
14753
  "src/tui/tail.ts"() {
14588
14754
  "use strict";
14589
14755
  import_http2 = __toESM(require("http"));
14590
14756
  import_chalk29 = __toESM(require("chalk"));
14591
- import_fs45 = __toESM(require("fs"));
14757
+ import_fs46 = __toESM(require("fs"));
14592
14758
  import_os41 = __toESM(require("os"));
14593
14759
  import_path47 = __toESM(require("path"));
14594
14760
  import_readline6 = __toESM(require("readline"));
@@ -14717,9 +14883,9 @@ function formatTimeLeft(resetsAt) {
14717
14883
  return ` (${m}m left)`;
14718
14884
  }
14719
14885
  function safeReadJson(filePath) {
14720
- if (!import_fs46.default.existsSync(filePath)) return null;
14886
+ if (!import_fs47.default.existsSync(filePath)) return null;
14721
14887
  try {
14722
- return JSON.parse(import_fs46.default.readFileSync(filePath, "utf-8"));
14888
+ return JSON.parse(import_fs47.default.readFileSync(filePath, "utf-8"));
14723
14889
  } catch {
14724
14890
  return null;
14725
14891
  }
@@ -14740,10 +14906,10 @@ function countHooksInFile(filePath) {
14740
14906
  return Object.keys(cfg.hooks).length;
14741
14907
  }
14742
14908
  function countRulesInDir(rulesDir) {
14743
- if (!import_fs46.default.existsSync(rulesDir)) return 0;
14909
+ if (!import_fs47.default.existsSync(rulesDir)) return 0;
14744
14910
  let count = 0;
14745
14911
  try {
14746
- for (const entry of import_fs46.default.readdirSync(rulesDir, { withFileTypes: true })) {
14912
+ for (const entry of import_fs47.default.readdirSync(rulesDir, { withFileTypes: true })) {
14747
14913
  if (entry.isDirectory()) {
14748
14914
  count += countRulesInDir(import_path48.default.join(rulesDir, entry.name));
14749
14915
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -14769,7 +14935,7 @@ function countConfigs(cwd) {
14769
14935
  let hooksCount = 0;
14770
14936
  const userMcpServers = /* @__PURE__ */ new Set();
14771
14937
  const projectMcpServers = /* @__PURE__ */ new Set();
14772
- if (import_fs46.default.existsSync(import_path48.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14938
+ if (import_fs47.default.existsSync(import_path48.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
14773
14939
  rulesCount += countRulesInDir(import_path48.default.join(claudeDir, "rules"));
14774
14940
  const userSettings = import_path48.default.join(claudeDir, "settings.json");
14775
14941
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
@@ -14780,18 +14946,18 @@ function countConfigs(cwd) {
14780
14946
  userMcpServers.delete(name);
14781
14947
  }
14782
14948
  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++;
14949
+ if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
14950
+ if (import_fs47.default.existsSync(import_path48.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
14785
14951
  const projectClaudeDir = import_path48.default.join(cwd, ".claude");
14786
14952
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
14787
14953
  if (!overlapsUserScope) {
14788
- if (import_fs46.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14954
+ if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
14789
14955
  rulesCount += countRulesInDir(import_path48.default.join(projectClaudeDir, "rules"));
14790
14956
  const projSettings = import_path48.default.join(projectClaudeDir, "settings.json");
14791
14957
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
14792
14958
  hooksCount += countHooksInFile(projSettings);
14793
14959
  }
14794
- if (import_fs46.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14960
+ if (import_fs47.default.existsSync(import_path48.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
14795
14961
  const localSettings = import_path48.default.join(projectClaudeDir, "settings.local.json");
14796
14962
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
14797
14963
  hooksCount += countHooksInFile(localSettings);
@@ -14829,11 +14995,11 @@ function readActiveShieldsHud() {
14829
14995
  }
14830
14996
  try {
14831
14997
  const shieldsPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "shields.json");
14832
- if (!import_fs46.default.existsSync(shieldsPath)) {
14998
+ if (!import_fs47.default.existsSync(shieldsPath)) {
14833
14999
  shieldsCache = { value: [], ts: now };
14834
15000
  return [];
14835
15001
  }
14836
- const parsed = JSON.parse(import_fs46.default.readFileSync(shieldsPath, "utf-8"));
15002
+ const parsed = JSON.parse(import_fs47.default.readFileSync(shieldsPath, "utf-8"));
14837
15003
  if (!Array.isArray(parsed.active)) {
14838
15004
  shieldsCache = { value: [], ts: now };
14839
15005
  return [];
@@ -14935,17 +15101,17 @@ function renderContextLine(stdin) {
14935
15101
  async function main() {
14936
15102
  try {
14937
15103
  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"))) {
15104
+ if (import_fs47.default.existsSync(import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug"))) {
14939
15105
  try {
14940
15106
  const logPath = import_path48.default.join(import_os42.default.homedir(), ".node9", "hud-debug.log");
14941
15107
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
14942
15108
  let size = 0;
14943
15109
  try {
14944
- size = import_fs46.default.statSync(logPath).size;
15110
+ size = import_fs47.default.statSync(logPath).size;
14945
15111
  } catch {
14946
15112
  }
14947
15113
  if (size < MAX_LOG_SIZE) {
14948
- import_fs46.default.appendFileSync(
15114
+ import_fs47.default.appendFileSync(
14949
15115
  logPath,
14950
15116
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
14951
15117
  );
@@ -14969,8 +15135,8 @@ async function main() {
14969
15135
  import_path48.default.join(cwd, "node9.config.json"),
14970
15136
  import_path48.default.join(import_os42.default.homedir(), ".node9", "config.json")
14971
15137
  ]) {
14972
- if (!import_fs46.default.existsSync(configPath)) continue;
14973
- const cfg = JSON.parse(import_fs46.default.readFileSync(configPath, "utf-8"));
15138
+ if (!import_fs47.default.existsSync(configPath)) continue;
15139
+ const cfg = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
14974
15140
  const hud = cfg.settings?.hud;
14975
15141
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
14976
15142
  }
@@ -14988,11 +15154,11 @@ async function main() {
14988
15154
  renderOffline();
14989
15155
  }
14990
15156
  }
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;
15157
+ 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
15158
  var init_hud = __esm({
14993
15159
  "src/cli/hud.ts"() {
14994
15160
  "use strict";
14995
- import_fs46 = __toESM(require("fs"));
15161
+ import_fs47 = __toESM(require("fs"));
14996
15162
  import_path48 = __toESM(require("path"));
14997
15163
  import_os42 = __toESM(require("os"));
14998
15164
  import_http3 = __toESM(require("http"));
@@ -15021,7 +15187,7 @@ init_core();
15021
15187
  init_setup();
15022
15188
  init_daemon2();
15023
15189
  var import_chalk30 = __toESM(require("chalk"));
15024
- var import_fs47 = __toESM(require("fs"));
15190
+ var import_fs48 = __toESM(require("fs"));
15025
15191
  var import_path49 = __toESM(require("path"));
15026
15192
  var import_os43 = __toESM(require("os"));
15027
15193
  var import_prompts2 = require("@inquirer/prompts");
@@ -15205,18 +15371,18 @@ async function runProxy(targetCommand) {
15205
15371
 
15206
15372
  // src/cli/daemon-starter.ts
15207
15373
  var import_child_process5 = require("child_process");
15208
- var import_path29 = __toESM(require("path"));
15209
- var import_fs28 = __toESM(require("fs"));
15374
+ var import_path30 = __toESM(require("path"));
15375
+ var import_fs29 = __toESM(require("fs"));
15210
15376
  init_daemon();
15211
15377
  function isTestingMode() {
15212
15378
  return /^(1|true|yes)$/i.test(process.env.NODE9_TESTING ?? "");
15213
15379
  }
15214
15380
  async function autoStartDaemonAndWait() {
15215
15381
  if (isTestingMode()) return false;
15216
- if (!import_path29.default.isAbsolute(process.argv[1])) return false;
15382
+ if (!import_path30.default.isAbsolute(process.argv[1])) return false;
15217
15383
  let resolvedArgv1;
15218
15384
  try {
15219
- resolvedArgv1 = import_fs28.default.realpathSync(process.argv[1]);
15385
+ resolvedArgv1 = import_fs29.default.realpathSync(process.argv[1]);
15220
15386
  } catch {
15221
15387
  return false;
15222
15388
  }
@@ -15243,10 +15409,10 @@ async function autoStartDaemonAndWait() {
15243
15409
 
15244
15410
  // src/cli/commands/check.ts
15245
15411
  var import_chalk9 = __toESM(require("chalk"));
15246
- var import_fs31 = __toESM(require("fs"));
15412
+ var import_fs32 = __toESM(require("fs"));
15247
15413
  var import_child_process7 = require("child_process");
15248
- var import_path32 = __toESM(require("path"));
15249
- var import_os27 = __toESM(require("os"));
15414
+ var import_path33 = __toESM(require("path"));
15415
+ var import_os28 = __toESM(require("os"));
15250
15416
  init_orchestrator();
15251
15417
  init_daemon();
15252
15418
  init_config();
@@ -15254,12 +15420,12 @@ init_policy();
15254
15420
 
15255
15421
  // src/undo.ts
15256
15422
  var import_child_process6 = require("child_process");
15257
- var import_crypto8 = __toESM(require("crypto"));
15258
- var import_fs29 = __toESM(require("fs"));
15423
+ var import_crypto9 = __toESM(require("crypto"));
15424
+ var import_fs30 = __toESM(require("fs"));
15259
15425
  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");
15426
+ var import_path31 = __toESM(require("path"));
15427
+ var import_os26 = __toESM(require("os"));
15428
+ var ACTIVITY_SOCKET_PATH3 = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path31.default.join(import_os26.default.tmpdir(), "node9-activity.sock");
15263
15429
  function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15264
15430
  try {
15265
15431
  const payload = JSON.stringify({
@@ -15279,22 +15445,22 @@ function notifySnapshotTaken(hash, tool, argsSummary, fileCount) {
15279
15445
  } catch {
15280
15446
  }
15281
15447
  }
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");
15448
+ var SNAPSHOT_STACK_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots.json");
15449
+ var UNDO_LATEST_PATH = import_path31.default.join(import_os26.default.homedir(), ".node9", "undo_latest.txt");
15284
15450
  var MAX_SNAPSHOTS = 10;
15285
15451
  var GIT_TIMEOUT = 15e3;
15286
15452
  function readStack() {
15287
15453
  try {
15288
- if (import_fs29.default.existsSync(SNAPSHOT_STACK_PATH))
15289
- return JSON.parse(import_fs29.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15454
+ if (import_fs30.default.existsSync(SNAPSHOT_STACK_PATH))
15455
+ return JSON.parse(import_fs30.default.readFileSync(SNAPSHOT_STACK_PATH, "utf-8"));
15290
15456
  } catch {
15291
15457
  }
15292
15458
  return [];
15293
15459
  }
15294
15460
  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));
15461
+ const dir = import_path31.default.dirname(SNAPSHOT_STACK_PATH);
15462
+ if (!import_fs30.default.existsSync(dir)) import_fs30.default.mkdirSync(dir, { recursive: true });
15463
+ import_fs30.default.writeFileSync(SNAPSHOT_STACK_PATH, JSON.stringify(stack, null, 2));
15298
15464
  }
15299
15465
  function extractFilePath(args) {
15300
15466
  if (!args || typeof args !== "object") return null;
@@ -15314,12 +15480,12 @@ function buildArgsSummary(tool, args) {
15314
15480
  return "";
15315
15481
  }
15316
15482
  function findProjectRoot(filePath) {
15317
- let dir = import_path30.default.dirname(filePath);
15483
+ let dir = import_path31.default.dirname(filePath);
15318
15484
  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"))) {
15485
+ if (import_fs30.default.existsSync(import_path31.default.join(dir, ".git")) || import_fs30.default.existsSync(import_path31.default.join(dir, "package.json"))) {
15320
15486
  return dir;
15321
15487
  }
15322
- const parent = import_path30.default.dirname(dir);
15488
+ const parent = import_path31.default.dirname(dir);
15323
15489
  if (parent === dir) return process.cwd();
15324
15490
  dir = parent;
15325
15491
  }
@@ -15327,7 +15493,7 @@ function findProjectRoot(filePath) {
15327
15493
  function normalizeCwdForHash(cwd) {
15328
15494
  let normalized;
15329
15495
  try {
15330
- normalized = import_fs29.default.realpathSync(cwd);
15496
+ normalized = import_fs30.default.realpathSync(cwd);
15331
15497
  } catch {
15332
15498
  normalized = cwd;
15333
15499
  }
@@ -15336,17 +15502,17 @@ function normalizeCwdForHash(cwd) {
15336
15502
  return normalized;
15337
15503
  }
15338
15504
  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);
15505
+ const hash = import_crypto9.default.createHash("sha256").update(normalizeCwdForHash(cwd)).digest("hex").slice(0, 16);
15506
+ return import_path31.default.join(import_os26.default.homedir(), ".node9", "snapshots", hash);
15341
15507
  }
15342
15508
  function cleanOrphanedIndexFiles(shadowDir) {
15343
15509
  try {
15344
15510
  const cutoff = Date.now() - 6e4;
15345
- for (const f of import_fs29.default.readdirSync(shadowDir)) {
15511
+ for (const f of import_fs30.default.readdirSync(shadowDir)) {
15346
15512
  if (f.startsWith("index_")) {
15347
- const fp = import_path30.default.join(shadowDir, f);
15513
+ const fp = import_path31.default.join(shadowDir, f);
15348
15514
  try {
15349
- if (import_fs29.default.statSync(fp).mtimeMs < cutoff) import_fs29.default.unlinkSync(fp);
15515
+ if (import_fs30.default.statSync(fp).mtimeMs < cutoff) import_fs30.default.unlinkSync(fp);
15350
15516
  } catch {
15351
15517
  }
15352
15518
  }
@@ -15358,7 +15524,7 @@ function writeShadowExcludes(shadowDir, ignorePaths) {
15358
15524
  const hardcoded = [".git", ".node9"];
15359
15525
  const lines = [...hardcoded, ...ignorePaths].join("\n");
15360
15526
  try {
15361
- import_fs29.default.writeFileSync(import_path30.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15527
+ import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "info", "exclude"), lines + "\n", "utf8");
15362
15528
  } catch {
15363
15529
  }
15364
15530
  }
@@ -15371,25 +15537,25 @@ function ensureShadowRepo(shadowDir, cwd) {
15371
15537
  timeout: 3e3
15372
15538
  });
15373
15539
  if (check.status === 0) {
15374
- const ptPath = import_path30.default.join(shadowDir, "project-path.txt");
15540
+ const ptPath = import_path31.default.join(shadowDir, "project-path.txt");
15375
15541
  try {
15376
- const stored = import_fs29.default.readFileSync(ptPath, "utf8").trim();
15542
+ const stored = import_fs30.default.readFileSync(ptPath, "utf8").trim();
15377
15543
  if (stored === normalizedCwd) return true;
15378
15544
  if (process.env.NODE9_DEBUG === "1")
15379
15545
  console.error(
15380
15546
  `[Node9] Shadow repo path mismatch: stored="${stored}" expected="${normalizedCwd}" \u2014 reinitializing`
15381
15547
  );
15382
- import_fs29.default.rmSync(shadowDir, { recursive: true, force: true });
15548
+ import_fs30.default.rmSync(shadowDir, { recursive: true, force: true });
15383
15549
  } catch {
15384
15550
  try {
15385
- import_fs29.default.writeFileSync(ptPath, normalizedCwd, "utf8");
15551
+ import_fs30.default.writeFileSync(ptPath, normalizedCwd, "utf8");
15386
15552
  } catch {
15387
15553
  }
15388
15554
  return true;
15389
15555
  }
15390
15556
  }
15391
15557
  try {
15392
- import_fs29.default.mkdirSync(shadowDir, { recursive: true });
15558
+ import_fs30.default.mkdirSync(shadowDir, { recursive: true });
15393
15559
  } catch {
15394
15560
  }
15395
15561
  const init = (0, import_child_process6.spawnSync)("git", ["init", "--bare", shadowDir], { timeout: 5e3 });
@@ -15398,7 +15564,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15398
15564
  if (process.env.NODE9_DEBUG === "1") console.error("[Node9] git init --bare failed:", reason);
15399
15565
  return false;
15400
15566
  }
15401
- const configFile = import_path30.default.join(shadowDir, "config");
15567
+ const configFile = import_path31.default.join(shadowDir, "config");
15402
15568
  (0, import_child_process6.spawnSync)("git", ["config", "--file", configFile, "core.untrackedCache", "true"], {
15403
15569
  timeout: 3e3
15404
15570
  });
@@ -15406,7 +15572,7 @@ function ensureShadowRepo(shadowDir, cwd) {
15406
15572
  timeout: 3e3
15407
15573
  });
15408
15574
  try {
15409
- import_fs29.default.writeFileSync(import_path30.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15575
+ import_fs30.default.writeFileSync(import_path31.default.join(shadowDir, "project-path.txt"), normalizedCwd, "utf8");
15410
15576
  } catch {
15411
15577
  }
15412
15578
  return true;
@@ -15429,12 +15595,12 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15429
15595
  let indexFile = null;
15430
15596
  try {
15431
15597
  const rawFilePath = extractFilePath(args);
15432
- const absFilePath = rawFilePath && import_path30.default.isAbsolute(rawFilePath) ? rawFilePath : null;
15598
+ const absFilePath = rawFilePath && import_path31.default.isAbsolute(rawFilePath) ? rawFilePath : null;
15433
15599
  const cwd = absFilePath ? findProjectRoot(absFilePath) : process.cwd();
15434
15600
  const shadowDir = getShadowRepoDir(cwd);
15435
15601
  if (!ensureShadowRepo(shadowDir, cwd)) return null;
15436
15602
  writeShadowExcludes(shadowDir, ignorePaths);
15437
- indexFile = import_path30.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15603
+ indexFile = import_path31.default.join(shadowDir, `index_${process.pid}_${Date.now()}`);
15438
15604
  const shadowEnv = {
15439
15605
  ...process.env,
15440
15606
  GIT_DIR: shadowDir,
@@ -15506,7 +15672,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15506
15672
  writeStack(stack);
15507
15673
  const entry = stack[stack.length - 1];
15508
15674
  notifySnapshotTaken(commitHash.slice(0, 7), tool, entry.argsSummary, capturedFiles.length);
15509
- import_fs29.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
15675
+ import_fs30.default.writeFileSync(UNDO_LATEST_PATH, commitHash);
15510
15676
  if (shouldGc) {
15511
15677
  (0, import_child_process6.spawn)("git", ["gc", "--auto"], { env: shadowEnv, detached: true, stdio: "ignore" }).unref();
15512
15678
  }
@@ -15517,7 +15683,7 @@ async function createShadowSnapshot(tool = "unknown", args = {}, ignorePaths = [
15517
15683
  } finally {
15518
15684
  if (indexFile) {
15519
15685
  try {
15520
- import_fs29.default.unlinkSync(indexFile);
15686
+ import_fs30.default.unlinkSync(indexFile);
15521
15687
  } catch {
15522
15688
  }
15523
15689
  }
@@ -15593,9 +15759,9 @@ function applyUndo(hash, cwd) {
15593
15759
  timeout: GIT_TIMEOUT
15594
15760
  }).stdout?.toString().trim().split("\n").filter(Boolean) ?? [];
15595
15761
  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);
15762
+ const fullPath = import_path31.default.join(dir, file);
15763
+ if (!snapshotFiles.has(file) && import_fs30.default.existsSync(fullPath)) {
15764
+ import_fs30.default.unlinkSync(fullPath);
15599
15765
  }
15600
15766
  }
15601
15767
  return true;
@@ -15605,17 +15771,17 @@ function applyUndo(hash, cwd) {
15605
15771
  }
15606
15772
 
15607
15773
  // 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");
15774
+ var import_fs31 = __toESM(require("fs"));
15775
+ var import_path32 = __toESM(require("path"));
15776
+ var import_os27 = __toESM(require("os"));
15777
+ var import_crypto10 = __toESM(require("crypto"));
15778
+ function getPinsFilePath2() {
15779
+ return import_path32.default.join(import_os27.default.homedir(), ".node9", "skill-pins.json");
15614
15780
  }
15615
15781
  var MAX_FILES = 5e3;
15616
15782
  var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
15617
15783
  function sha256Bytes(buf) {
15618
- return import_crypto9.default.createHash("sha256").update(buf).digest("hex");
15784
+ return import_crypto10.default.createHash("sha256").update(buf).digest("hex");
15619
15785
  }
15620
15786
  function walkDir(root) {
15621
15787
  const out = [];
@@ -15624,18 +15790,18 @@ function walkDir(root) {
15624
15790
  if (out.length >= MAX_FILES) return;
15625
15791
  let entries;
15626
15792
  try {
15627
- entries = import_fs30.default.readdirSync(dir, { withFileTypes: true });
15793
+ entries = import_fs31.default.readdirSync(dir, { withFileTypes: true });
15628
15794
  } catch {
15629
15795
  return;
15630
15796
  }
15631
15797
  entries.sort((a, b) => a.name.localeCompare(b.name));
15632
15798
  for (const entry of entries) {
15633
15799
  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;
15800
+ const full = import_path32.default.join(dir, entry.name);
15801
+ const rel = relDir ? import_path32.default.posix.join(relDir, entry.name) : entry.name;
15636
15802
  let lst;
15637
15803
  try {
15638
- lst = import_fs30.default.lstatSync(full);
15804
+ lst = import_fs31.default.lstatSync(full);
15639
15805
  } catch {
15640
15806
  continue;
15641
15807
  }
@@ -15647,7 +15813,7 @@ function walkDir(root) {
15647
15813
  if (!lst.isFile()) continue;
15648
15814
  if (totalBytes + lst.size > MAX_TOTAL_BYTES) continue;
15649
15815
  try {
15650
- const buf = import_fs30.default.readFileSync(full);
15816
+ const buf = import_fs31.default.readFileSync(full);
15651
15817
  totalBytes += buf.length;
15652
15818
  out.push({ rel, hash: sha256Bytes(buf) });
15653
15819
  } catch {
@@ -15661,32 +15827,32 @@ function walkDir(root) {
15661
15827
  function hashSkillRoot(absPath) {
15662
15828
  let lst;
15663
15829
  try {
15664
- lst = import_fs30.default.lstatSync(absPath);
15830
+ lst = import_fs31.default.lstatSync(absPath);
15665
15831
  } catch {
15666
15832
  return { exists: false, contentHash: "", fileCount: 0 };
15667
15833
  }
15668
15834
  if (lst.isSymbolicLink()) return { exists: false, contentHash: "", fileCount: 0 };
15669
15835
  if (lst.isFile()) {
15670
15836
  try {
15671
- return { exists: true, contentHash: sha256Bytes(import_fs30.default.readFileSync(absPath)), fileCount: 1 };
15837
+ return { exists: true, contentHash: sha256Bytes(import_fs31.default.readFileSync(absPath)), fileCount: 1 };
15672
15838
  } catch {
15673
15839
  return { exists: false, contentHash: "", fileCount: 0 };
15674
15840
  }
15675
15841
  }
15676
15842
  if (lst.isDirectory()) {
15677
15843
  const entries = walkDir(absPath);
15678
- const contentHash = import_crypto9.default.createHash("sha256").update(entries.join("\n")).digest("hex");
15844
+ const contentHash = import_crypto10.default.createHash("sha256").update(entries.join("\n")).digest("hex");
15679
15845
  return { exists: true, contentHash, fileCount: entries.length };
15680
15846
  }
15681
15847
  return { exists: false, contentHash: "", fileCount: 0 };
15682
15848
  }
15683
15849
  function getRootKey(absPath) {
15684
- return import_crypto9.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15850
+ return import_crypto10.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
15685
15851
  }
15686
15852
  function readSkillPinsSafe() {
15687
- const filePath = getPinsFilePath();
15853
+ const filePath = getPinsFilePath2();
15688
15854
  try {
15689
- const raw = import_fs30.default.readFileSync(filePath, "utf-8");
15855
+ const raw = import_fs31.default.readFileSync(filePath, "utf-8");
15690
15856
  if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
15691
15857
  const parsed = JSON.parse(raw);
15692
15858
  if (!parsed.roots || typeof parsed.roots !== "object" || Array.isArray(parsed.roots)) {
@@ -15705,18 +15871,18 @@ function readSkillPins() {
15705
15871
  throw new Error(`[node9] skill pin file is corrupt: ${result.detail}`);
15706
15872
  }
15707
15873
  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);
15874
+ const filePath = getPinsFilePath2();
15875
+ import_fs31.default.mkdirSync(import_path32.default.dirname(filePath), { recursive: true });
15876
+ const tmp = `${filePath}.${import_crypto10.default.randomBytes(6).toString("hex")}.tmp`;
15877
+ import_fs31.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
15878
+ import_fs31.default.renameSync(tmp, filePath);
15713
15879
  }
15714
- function removePin(rootKey) {
15880
+ function removePin2(rootKey) {
15715
15881
  const pins = readSkillPins();
15716
15882
  delete pins.roots[rootKey];
15717
15883
  writeSkillPins(pins);
15718
15884
  }
15719
- function clearAllPins() {
15885
+ function clearAllPins2() {
15720
15886
  writeSkillPins({ roots: {} });
15721
15887
  }
15722
15888
  function verifyAndPinRoots(roots) {
@@ -15753,36 +15919,36 @@ function verifyAndPinRoots(roots) {
15753
15919
  return { kind: "verified" };
15754
15920
  }
15755
15921
  function defaultSkillRoots(_cwd) {
15756
- const marketplaces = import_path31.default.join(import_os26.default.homedir(), ".claude", "plugins", "marketplaces");
15922
+ const marketplaces = import_path32.default.join(import_os27.default.homedir(), ".claude", "plugins", "marketplaces");
15757
15923
  const roots = [];
15758
15924
  let registries;
15759
15925
  try {
15760
- registries = import_fs30.default.readdirSync(marketplaces, { withFileTypes: true });
15926
+ registries = import_fs31.default.readdirSync(marketplaces, { withFileTypes: true });
15761
15927
  } catch {
15762
15928
  return [];
15763
15929
  }
15764
15930
  for (const registry of registries) {
15765
15931
  if (!registry.isDirectory()) continue;
15766
- const pluginsDir = import_path31.default.join(marketplaces, registry.name, "plugins");
15932
+ const pluginsDir = import_path32.default.join(marketplaces, registry.name, "plugins");
15767
15933
  let plugins;
15768
15934
  try {
15769
- plugins = import_fs30.default.readdirSync(pluginsDir, { withFileTypes: true });
15935
+ plugins = import_fs31.default.readdirSync(pluginsDir, { withFileTypes: true });
15770
15936
  } catch {
15771
15937
  continue;
15772
15938
  }
15773
15939
  for (const plugin of plugins) {
15774
15940
  if (!plugin.isDirectory()) continue;
15775
- roots.push(import_path31.default.join(pluginsDir, plugin.name));
15941
+ roots.push(import_path32.default.join(pluginsDir, plugin.name));
15776
15942
  }
15777
15943
  }
15778
15944
  return roots;
15779
15945
  }
15780
15946
  function resolveUserSkillRoot(entry, cwd) {
15781
15947
  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);
15948
+ if (entry.startsWith("~/") || entry === "~") return import_path32.default.join(import_os27.default.homedir(), entry.slice(1));
15949
+ if (import_path32.default.isAbsolute(entry)) return entry;
15950
+ if (!cwd || !import_path32.default.isAbsolute(cwd)) return null;
15951
+ return import_path32.default.join(cwd, entry);
15786
15952
  }
15787
15953
 
15788
15954
  // src/cli/commands/check.ts
@@ -15829,9 +15995,9 @@ function registerCheckCommand(program2) {
15829
15995
  } catch (err2) {
15830
15996
  const tempConfig = getConfig();
15831
15997
  if (process.env.NODE9_DEBUG === "1" || tempConfig.settings.enableHookLogDebug) {
15832
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
15998
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
15833
15999
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
15834
- import_fs31.default.appendFileSync(
16000
+ import_fs32.default.appendFileSync(
15835
16001
  logPath,
15836
16002
  `[${(/* @__PURE__ */ new Date()).toISOString()}] JSON_PARSE_ERROR: ${errMsg}
15837
16003
  RAW: ${raw}
@@ -15844,14 +16010,14 @@ RAW: ${raw}
15844
16010
  const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
15845
16011
  if (process.env.NODE9_DEBUG === "1") {
15846
16012
  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 });
16013
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16014
+ if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
16015
+ import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
15850
16016
  const sanitized = JSON.stringify({
15851
16017
  ...payload,
15852
16018
  prompt: `<redacted, ${prompt.length} bytes>`
15853
16019
  });
15854
- import_fs31.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
16020
+ import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${sanitized}
15855
16021
  `);
15856
16022
  } catch {
15857
16023
  }
@@ -15871,8 +16037,8 @@ RAW: ${raw}
15871
16037
  );
15872
16038
  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
16039
  try {
15874
- const ttyFd = import_fs31.default.openSync("/dev/tty", "w");
15875
- import_fs31.default.writeSync(
16040
+ const ttyFd = import_fs32.default.openSync("/dev/tty", "w");
16041
+ import_fs32.default.writeSync(
15876
16042
  ttyFd,
15877
16043
  import_chalk9.default.bgRed.white.bold(`
15878
16044
  \u{1F6A8} NODE9 DLP \u2014 PROMPT BLOCKED
@@ -15882,7 +16048,7 @@ RAW: ${raw}
15882
16048
 
15883
16049
  `)
15884
16050
  );
15885
- import_fs31.default.closeSync(ttyFd);
16051
+ import_fs32.default.closeSync(ttyFd);
15886
16052
  } catch {
15887
16053
  }
15888
16054
  const isCodex = agent2 === "Codex";
@@ -15900,16 +16066,16 @@ RAW: ${raw}
15900
16066
  );
15901
16067
  process.exit(2);
15902
16068
  }
15903
- const safeCwdForConfig = typeof payload.cwd === "string" && import_path32.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16069
+ const safeCwdForConfig = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
15904
16070
  const config = getConfig(safeCwdForConfig);
15905
16071
  if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
15906
16072
  try {
15907
16073
  const scriptPath = process.argv[1];
15908
- if (typeof scriptPath !== "string" || !import_path32.default.isAbsolute(scriptPath))
16074
+ if (typeof scriptPath !== "string" || !import_path33.default.isAbsolute(scriptPath))
15909
16075
  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)
16076
+ const resolvedScript = import_fs32.default.realpathSync(scriptPath);
16077
+ const packageDist = import_fs32.default.realpathSync(import_path33.default.resolve(__dirname, "../.."));
16078
+ if (!resolvedScript.startsWith(packageDist + import_path33.default.sep) && resolvedScript !== packageDist)
15913
16079
  throw new Error(
15914
16080
  `node9: daemon spawn aborted \u2014 argv[1] (${resolvedScript}) is outside package dist (${packageDist})`
15915
16081
  );
@@ -15931,10 +16097,10 @@ RAW: ${raw}
15931
16097
  });
15932
16098
  d.unref();
15933
16099
  } catch (spawnErr) {
15934
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
16100
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
15935
16101
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
15936
16102
  try {
15937
- import_fs31.default.appendFileSync(
16103
+ import_fs32.default.appendFileSync(
15938
16104
  logPath,
15939
16105
  `[${(/* @__PURE__ */ new Date()).toISOString()}] daemon-autostart-failed: ${msg}
15940
16106
  `
@@ -15944,10 +16110,10 @@ RAW: ${raw}
15944
16110
  }
15945
16111
  }
15946
16112
  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}
16113
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16114
+ if (!import_fs32.default.existsSync(import_path33.default.dirname(logPath)))
16115
+ import_fs32.default.mkdirSync(import_path33.default.dirname(logPath), { recursive: true });
16116
+ import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${raw}
15951
16117
  `);
15952
16118
  }
15953
16119
  const toolName = sanitize2(payload.tool_name ?? payload.name ?? "");
@@ -15960,8 +16126,8 @@ RAW: ${raw}
15960
16126
  const isHumanDecision = blockedByContext.toLowerCase().includes("user") || blockedByContext.toLowerCase().includes("daemon") || blockedByContext.toLowerCase().includes("decision");
15961
16127
  let ttyFd = null;
15962
16128
  try {
15963
- ttyFd = import_fs31.default.openSync("/dev/tty", "w");
15964
- const writeTty = (line) => import_fs31.default.writeSync(ttyFd, line + "\n");
16129
+ ttyFd = import_fs32.default.openSync("/dev/tty", "w");
16130
+ const writeTty = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
15965
16131
  if (blockedByContext.includes("DLP") || blockedByContext.includes("Secret Detected") || blockedByContext.includes("Credential Review")) {
15966
16132
  writeTty(import_chalk9.default.bgRed.white.bold(`
15967
16133
  \u{1F6A8} NODE9 DLP ALERT \u2014 CREDENTIAL DETECTED `));
@@ -15980,7 +16146,7 @@ RAW: ${raw}
15980
16146
  } finally {
15981
16147
  if (ttyFd !== null)
15982
16148
  try {
15983
- import_fs31.default.closeSync(ttyFd);
16149
+ import_fs32.default.closeSync(ttyFd);
15984
16150
  } catch {
15985
16151
  }
15986
16152
  }
@@ -16016,17 +16182,17 @@ RAW: ${raw}
16016
16182
  const safeSessionId = /^[A-Za-z0-9_\-]{1,128}$/.test(rawSessionId) ? rawSessionId : "";
16017
16183
  if (skillPinCfg.enabled && safeSessionId) {
16018
16184
  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`);
16185
+ const sessionsDir = import_path33.default.join(import_os28.default.homedir(), ".node9", "skill-sessions");
16186
+ const flagPath = import_path33.default.join(sessionsDir, `${safeSessionId}.json`);
16021
16187
  let flag = null;
16022
16188
  try {
16023
- flag = JSON.parse(import_fs31.default.readFileSync(flagPath, "utf-8"));
16189
+ flag = JSON.parse(import_fs32.default.readFileSync(flagPath, "utf-8"));
16024
16190
  } catch {
16025
16191
  }
16026
16192
  const writeFlag = (data2) => {
16027
16193
  try {
16028
- import_fs31.default.mkdirSync(sessionsDir, { recursive: true });
16029
- import_fs31.default.writeFileSync(
16194
+ import_fs32.default.mkdirSync(sessionsDir, { recursive: true });
16195
+ import_fs32.default.writeFileSync(
16030
16196
  flagPath,
16031
16197
  JSON.stringify({ ...data2, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
16032
16198
  { mode: 384 }
@@ -16037,8 +16203,8 @@ RAW: ${raw}
16037
16203
  const sendSkillWarn = (detail, recoveryCmd) => {
16038
16204
  let ttyFd = null;
16039
16205
  try {
16040
- ttyFd = import_fs31.default.openSync("/dev/tty", "w");
16041
- const w = (line) => import_fs31.default.writeSync(ttyFd, line + "\n");
16206
+ ttyFd = import_fs32.default.openSync("/dev/tty", "w");
16207
+ const w = (line) => import_fs32.default.writeSync(ttyFd, line + "\n");
16042
16208
  w(import_chalk9.default.yellow(`
16043
16209
  \u26A0\uFE0F Node9: installed skill drift detected`));
16044
16210
  w(import_chalk9.default.gray(` ${detail}`));
@@ -16053,7 +16219,7 @@ RAW: ${raw}
16053
16219
  } finally {
16054
16220
  if (ttyFd !== null)
16055
16221
  try {
16056
- import_fs31.default.closeSync(ttyFd);
16222
+ import_fs32.default.closeSync(ttyFd);
16057
16223
  } catch {
16058
16224
  }
16059
16225
  }
@@ -16069,7 +16235,7 @@ RAW: ${raw}
16069
16235
  return;
16070
16236
  }
16071
16237
  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;
16238
+ const absoluteCwd = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16073
16239
  const extraRoots = skillPinCfg.roots;
16074
16240
  const resolvedExtra = extraRoots.map((r) => resolveUserSkillRoot(r, absoluteCwd)).filter((r) => typeof r === "string");
16075
16241
  const roots = [...defaultSkillRoots(absoluteCwd), ...resolvedExtra];
@@ -16110,10 +16276,10 @@ RAW: ${raw}
16110
16276
  }
16111
16277
  try {
16112
16278
  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);
16279
+ for (const name of import_fs32.default.readdirSync(sessionsDir)) {
16280
+ const p = import_path33.default.join(sessionsDir, name);
16115
16281
  try {
16116
- if (import_fs31.default.statSync(p).mtimeMs < cutoff) import_fs31.default.unlinkSync(p);
16282
+ if (import_fs32.default.statSync(p).mtimeMs < cutoff) import_fs32.default.unlinkSync(p);
16117
16283
  } catch {
16118
16284
  }
16119
16285
  }
@@ -16123,9 +16289,9 @@ RAW: ${raw}
16123
16289
  } catch (err2) {
16124
16290
  if (process.env.NODE9_DEBUG === "1") {
16125
16291
  try {
16126
- const dbg = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
16292
+ const dbg = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16127
16293
  const msg = err2 instanceof Error ? err2.message : String(err2);
16128
- import_fs31.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16294
+ import_fs32.default.appendFileSync(dbg, `[${(/* @__PURE__ */ new Date()).toISOString()}] SKILL_PIN_ERROR: ${msg}
16129
16295
  `);
16130
16296
  } catch {
16131
16297
  }
@@ -16135,7 +16301,7 @@ RAW: ${raw}
16135
16301
  if (shouldSnapshot(toolName, toolInput, config)) {
16136
16302
  await createShadowSnapshot(toolName, toolInput, config.policy.snapshot.ignorePaths);
16137
16303
  }
16138
- const safeCwdForAuth = typeof payload.cwd === "string" && import_path32.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16304
+ const safeCwdForAuth = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16139
16305
  const result = await authorizeHeadless(toolName, toolInput, meta, {
16140
16306
  cwd: safeCwdForAuth
16141
16307
  });
@@ -16147,12 +16313,12 @@ RAW: ${raw}
16147
16313
  }
16148
16314
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && !process.stdout.isTTY && config.settings.autoStartDaemon) {
16149
16315
  try {
16150
- const tty = import_fs31.default.openSync("/dev/tty", "w");
16151
- import_fs31.default.writeSync(
16316
+ const tty = import_fs32.default.openSync("/dev/tty", "w");
16317
+ import_fs32.default.writeSync(
16152
16318
  tty,
16153
16319
  import_chalk9.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically...\n")
16154
16320
  );
16155
- import_fs31.default.closeSync(tty);
16321
+ import_fs32.default.closeSync(tty);
16156
16322
  } catch {
16157
16323
  }
16158
16324
  const daemonReady = await autoStartDaemonAndWait();
@@ -16179,9 +16345,9 @@ RAW: ${raw}
16179
16345
  });
16180
16346
  } catch (err2) {
16181
16347
  if (process.env.NODE9_DEBUG === "1") {
16182
- const logPath = import_path32.default.join(import_os27.default.homedir(), ".node9", "hook-debug.log");
16348
+ const logPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16183
16349
  const errMsg = err2 instanceof Error ? err2.message : String(err2);
16184
- import_fs31.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16350
+ import_fs32.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${errMsg}
16185
16351
  `);
16186
16352
  }
16187
16353
  process.exit(0);
@@ -16215,9 +16381,9 @@ RAW: ${raw}
16215
16381
  }
16216
16382
 
16217
16383
  // 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"));
16384
+ var import_fs33 = __toESM(require("fs"));
16385
+ var import_path34 = __toESM(require("path"));
16386
+ var import_os29 = __toESM(require("os"));
16221
16387
  init_audit();
16222
16388
  init_config();
16223
16389
  init_daemon();
@@ -16295,10 +16461,10 @@ function registerLogCommand(program2) {
16295
16461
  };
16296
16462
  if (agent) entry.agent = agent;
16297
16463
  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");
16464
+ const logPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "audit.log");
16465
+ if (!import_fs33.default.existsSync(import_path34.default.dirname(logPath)))
16466
+ import_fs33.default.mkdirSync(import_path34.default.dirname(logPath), { recursive: true });
16467
+ import_fs33.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
16302
16468
  if ((tool === "Bash" || tool === "bash") && isDaemonRunning()) {
16303
16469
  const command = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
16304
16470
  if (command) {
@@ -16331,7 +16497,7 @@ function registerLogCommand(program2) {
16331
16497
  }
16332
16498
  }
16333
16499
  }
16334
- const safeCwd = typeof payload.cwd === "string" && import_path33.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16500
+ const safeCwd = typeof payload.cwd === "string" && import_path34.default.isAbsolute(payload.cwd) ? payload.cwd : void 0;
16335
16501
  const config = getConfig(safeCwd);
16336
16502
  if ((tool === "Bash" || tool === "bash") && config.settings.enableUndo !== false) {
16337
16503
  const bashCommand = typeof rawInput === "object" && rawInput !== null && "command" in rawInput && typeof rawInput.command === "string" ? rawInput.command : null;
@@ -16352,9 +16518,9 @@ function registerLogCommand(program2) {
16352
16518
  const msg = err2 instanceof Error ? err2.message : String(err2);
16353
16519
  process.stderr.write(`[Node9] audit log error: ${msg}
16354
16520
  `);
16355
- const debugPath = import_path33.default.join(import_os28.default.homedir(), ".node9", "hook-debug.log");
16521
+ const debugPath = import_path34.default.join(import_os29.default.homedir(), ".node9", "hook-debug.log");
16356
16522
  try {
16357
- import_fs32.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16523
+ import_fs33.default.appendFileSync(debugPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] LOG_ERROR: ${msg}
16358
16524
  `);
16359
16525
  } catch {
16360
16526
  }
@@ -16754,14 +16920,14 @@ function registerConfigShowCommand(program2) {
16754
16920
 
16755
16921
  // src/cli/commands/doctor.ts
16756
16922
  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"));
16923
+ var import_fs34 = __toESM(require("fs"));
16924
+ var import_path35 = __toESM(require("path"));
16925
+ var import_os30 = __toESM(require("os"));
16760
16926
  var import_child_process8 = require("child_process");
16761
16927
  init_daemon();
16762
16928
  function registerDoctorCommand(program2, version2) {
16763
16929
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
16764
- const homeDir2 = import_os29.default.homedir();
16930
+ const homeDir2 = import_os30.default.homedir();
16765
16931
  let failures = 0;
16766
16932
  function pass(msg) {
16767
16933
  console.log(import_chalk11.default.green(" \u2705 ") + msg);
@@ -16810,10 +16976,10 @@ function registerDoctorCommand(program2, version2) {
16810
16976
  );
16811
16977
  }
16812
16978
  section("Configuration");
16813
- const globalConfigPath = import_path34.default.join(homeDir2, ".node9", "config.json");
16814
- if (import_fs33.default.existsSync(globalConfigPath)) {
16979
+ const globalConfigPath = import_path35.default.join(homeDir2, ".node9", "config.json");
16980
+ if (import_fs34.default.existsSync(globalConfigPath)) {
16815
16981
  try {
16816
- JSON.parse(import_fs33.default.readFileSync(globalConfigPath, "utf-8"));
16982
+ JSON.parse(import_fs34.default.readFileSync(globalConfigPath, "utf-8"));
16817
16983
  pass("~/.node9/config.json found and valid");
16818
16984
  } catch {
16819
16985
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -16821,10 +16987,10 @@ function registerDoctorCommand(program2, version2) {
16821
16987
  } else {
16822
16988
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
16823
16989
  }
16824
- const projectConfigPath = import_path34.default.join(process.cwd(), "node9.config.json");
16825
- if (import_fs33.default.existsSync(projectConfigPath)) {
16990
+ const projectConfigPath = import_path35.default.join(process.cwd(), "node9.config.json");
16991
+ if (import_fs34.default.existsSync(projectConfigPath)) {
16826
16992
  try {
16827
- JSON.parse(import_fs33.default.readFileSync(projectConfigPath, "utf-8"));
16993
+ JSON.parse(import_fs34.default.readFileSync(projectConfigPath, "utf-8"));
16828
16994
  pass("node9.config.json found and valid (project)");
16829
16995
  } catch {
16830
16996
  fail(
@@ -16833,8 +16999,8 @@ function registerDoctorCommand(program2, version2) {
16833
16999
  );
16834
17000
  }
16835
17001
  }
16836
- const credsPath = import_path34.default.join(homeDir2, ".node9", "credentials.json");
16837
- if (import_fs33.default.existsSync(credsPath)) {
17002
+ const credsPath = import_path35.default.join(homeDir2, ".node9", "credentials.json");
17003
+ if (import_fs34.default.existsSync(credsPath)) {
16838
17004
  pass("Cloud credentials found (~/.node9/credentials.json)");
16839
17005
  } else {
16840
17006
  warn(
@@ -16843,10 +17009,10 @@ function registerDoctorCommand(program2, version2) {
16843
17009
  );
16844
17010
  }
16845
17011
  section("Agent Hooks");
16846
- const claudeSettingsPath = import_path34.default.join(homeDir2, ".claude", "settings.json");
16847
- if (import_fs33.default.existsSync(claudeSettingsPath)) {
17012
+ const claudeSettingsPath = import_path35.default.join(homeDir2, ".claude", "settings.json");
17013
+ if (import_fs34.default.existsSync(claudeSettingsPath)) {
16848
17014
  try {
16849
- const cs = JSON.parse(import_fs33.default.readFileSync(claudeSettingsPath, "utf-8"));
17015
+ const cs = JSON.parse(import_fs34.default.readFileSync(claudeSettingsPath, "utf-8"));
16850
17016
  const hasHook = cs.hooks?.PreToolUse?.some(
16851
17017
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16852
17018
  );
@@ -16862,10 +17028,10 @@ function registerDoctorCommand(program2, version2) {
16862
17028
  } else {
16863
17029
  warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
16864
17030
  }
16865
- const geminiSettingsPath = import_path34.default.join(homeDir2, ".gemini", "settings.json");
16866
- if (import_fs33.default.existsSync(geminiSettingsPath)) {
17031
+ const geminiSettingsPath = import_path35.default.join(homeDir2, ".gemini", "settings.json");
17032
+ if (import_fs34.default.existsSync(geminiSettingsPath)) {
16867
17033
  try {
16868
- const gs = JSON.parse(import_fs33.default.readFileSync(geminiSettingsPath, "utf-8"));
17034
+ const gs = JSON.parse(import_fs34.default.readFileSync(geminiSettingsPath, "utf-8"));
16869
17035
  const hasHook = gs.hooks?.BeforeTool?.some(
16870
17036
  (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
16871
17037
  );
@@ -16881,10 +17047,10 @@ function registerDoctorCommand(program2, version2) {
16881
17047
  } else {
16882
17048
  warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
16883
17049
  }
16884
- const cursorHooksPath = import_path34.default.join(homeDir2, ".cursor", "hooks.json");
16885
- if (import_fs33.default.existsSync(cursorHooksPath)) {
17050
+ const cursorHooksPath = import_path35.default.join(homeDir2, ".cursor", "hooks.json");
17051
+ if (import_fs34.default.existsSync(cursorHooksPath)) {
16886
17052
  try {
16887
- const cur = JSON.parse(import_fs33.default.readFileSync(cursorHooksPath, "utf-8"));
17053
+ const cur = JSON.parse(import_fs34.default.readFileSync(cursorHooksPath, "utf-8"));
16888
17054
  const hasHook = cur.hooks?.preToolUse?.some(
16889
17055
  (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
16890
17056
  );
@@ -16924,9 +17090,9 @@ function registerDoctorCommand(program2, version2) {
16924
17090
 
16925
17091
  // src/cli/commands/audit.ts
16926
17092
  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"));
17093
+ var import_fs35 = __toESM(require("fs"));
17094
+ var import_path36 = __toESM(require("path"));
17095
+ var import_os31 = __toESM(require("os"));
16930
17096
  function formatRelativeTime(timestamp) {
16931
17097
  const diff = Date.now() - new Date(timestamp).getTime();
16932
17098
  const sec = Math.floor(diff / 1e3);
@@ -16939,14 +17105,14 @@ function formatRelativeTime(timestamp) {
16939
17105
  }
16940
17106
  function registerAuditCommand(program2) {
16941
17107
  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)) {
17108
+ const logPath = import_path36.default.join(import_os31.default.homedir(), ".node9", "audit.log");
17109
+ if (!import_fs35.default.existsSync(logPath)) {
16944
17110
  console.log(
16945
17111
  import_chalk12.default.yellow("No audit logs found. Run node9 with an agent to generate entries.")
16946
17112
  );
16947
17113
  return;
16948
17114
  }
16949
- const raw = import_fs34.default.readFileSync(logPath, "utf-8");
17115
+ const raw = import_fs35.default.readFileSync(logPath, "utf-8");
16950
17116
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
16951
17117
  let entries = lines.flatMap((line) => {
16952
17118
  try {
@@ -17002,9 +17168,9 @@ function registerAuditCommand(program2) {
17002
17168
  var import_chalk13 = __toESM(require("chalk"));
17003
17169
 
17004
17170
  // 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"));
17171
+ var import_fs36 = __toESM(require("fs"));
17172
+ var import_os32 = __toESM(require("os"));
17173
+ var import_path37 = __toESM(require("path"));
17008
17174
  init_costSync();
17009
17175
  init_litellm();
17010
17176
  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 +17252,8 @@ function getDateRange(period, now) {
17086
17252
  }
17087
17253
  }
17088
17254
  function parseAuditLog(logPath) {
17089
- if (!import_fs35.default.existsSync(logPath)) return [];
17090
- const raw = import_fs35.default.readFileSync(logPath, "utf-8");
17255
+ if (!import_fs36.default.existsSync(logPath)) return [];
17256
+ const raw = import_fs36.default.readFileSync(logPath, "utf-8");
17091
17257
  return raw.split("\n").flatMap((line) => {
17092
17258
  if (!line.trim()) return [];
17093
17259
  try {
@@ -17147,25 +17313,25 @@ function freezeClaudeCost(acc) {
17147
17313
  };
17148
17314
  }
17149
17315
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17150
- const projPath = import_path36.default.join(projectsDir, proj);
17316
+ const projPath = import_path37.default.join(projectsDir, proj);
17151
17317
  let files;
17152
17318
  try {
17153
- const stat = import_fs35.default.statSync(projPath);
17319
+ const stat = import_fs36.default.statSync(projPath);
17154
17320
  if (!stat.isDirectory()) return;
17155
- files = import_fs35.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17321
+ files = import_fs36.default.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
17156
17322
  } catch {
17157
17323
  return;
17158
17324
  }
17159
17325
  const startMs = start.getTime();
17160
17326
  for (const file of files) {
17161
- const filePath = import_path36.default.join(projPath, file);
17327
+ const filePath = import_path37.default.join(projPath, file);
17162
17328
  try {
17163
- if (import_fs35.default.statSync(filePath).mtimeMs < startMs) continue;
17329
+ if (import_fs36.default.statSync(filePath).mtimeMs < startMs) continue;
17164
17330
  } catch {
17165
17331
  continue;
17166
17332
  }
17167
17333
  try {
17168
- const raw = import_fs35.default.readFileSync(filePath, "utf-8");
17334
+ const raw = import_fs36.default.readFileSync(filePath, "utf-8");
17169
17335
  for (const line of raw.split("\n")) {
17170
17336
  if (!line.trim()) continue;
17171
17337
  let entry;
@@ -17215,10 +17381,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
17215
17381
  }
17216
17382
  function loadClaudeCost(start, end, projectsDir) {
17217
17383
  const acc = emptyClaudeCostAccumulator();
17218
- if (!import_fs35.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
17384
+ if (!import_fs36.default.existsSync(projectsDir)) return freezeClaudeCost(acc);
17219
17385
  let dirs;
17220
17386
  try {
17221
- dirs = import_fs35.default.readdirSync(projectsDir);
17387
+ dirs = import_fs36.default.readdirSync(projectsDir);
17222
17388
  } catch {
17223
17389
  return freezeClaudeCost(acc);
17224
17390
  }
@@ -17230,7 +17396,7 @@ function loadClaudeCost(start, end, projectsDir) {
17230
17396
  function processCodexCostFile(filePath, start, end, acc) {
17231
17397
  let lines;
17232
17398
  try {
17233
- lines = import_fs35.default.readFileSync(filePath, "utf-8").split("\n");
17399
+ lines = import_fs36.default.readFileSync(filePath, "utf-8").split("\n");
17234
17400
  } catch {
17235
17401
  return;
17236
17402
  }
@@ -17275,31 +17441,31 @@ function processCodexCostFile(filePath, start, end, acc) {
17275
17441
  }
17276
17442
  function listCodexSessionFiles(sessionsBase) {
17277
17443
  const jsonlFiles = [];
17278
- if (!import_fs35.default.existsSync(sessionsBase)) return jsonlFiles;
17444
+ if (!import_fs36.default.existsSync(sessionsBase)) return jsonlFiles;
17279
17445
  try {
17280
- for (const year of import_fs35.default.readdirSync(sessionsBase)) {
17281
- const yearPath = import_path36.default.join(sessionsBase, year);
17446
+ for (const year of import_fs36.default.readdirSync(sessionsBase)) {
17447
+ const yearPath = import_path37.default.join(sessionsBase, year);
17282
17448
  try {
17283
- if (!import_fs35.default.statSync(yearPath).isDirectory()) continue;
17449
+ if (!import_fs36.default.statSync(yearPath).isDirectory()) continue;
17284
17450
  } catch {
17285
17451
  continue;
17286
17452
  }
17287
- for (const month of import_fs35.default.readdirSync(yearPath)) {
17288
- const monthPath = import_path36.default.join(yearPath, month);
17453
+ for (const month of import_fs36.default.readdirSync(yearPath)) {
17454
+ const monthPath = import_path37.default.join(yearPath, month);
17289
17455
  try {
17290
- if (!import_fs35.default.statSync(monthPath).isDirectory()) continue;
17456
+ if (!import_fs36.default.statSync(monthPath).isDirectory()) continue;
17291
17457
  } catch {
17292
17458
  continue;
17293
17459
  }
17294
- for (const day of import_fs35.default.readdirSync(monthPath)) {
17295
- const dayPath = import_path36.default.join(monthPath, day);
17460
+ for (const day of import_fs36.default.readdirSync(monthPath)) {
17461
+ const dayPath = import_path37.default.join(monthPath, day);
17296
17462
  try {
17297
- if (!import_fs35.default.statSync(dayPath).isDirectory()) continue;
17463
+ if (!import_fs36.default.statSync(dayPath).isDirectory()) continue;
17298
17464
  } catch {
17299
17465
  continue;
17300
17466
  }
17301
- for (const file of import_fs35.default.readdirSync(dayPath)) {
17302
- if (file.endsWith(".jsonl")) jsonlFiles.push(import_path36.default.join(dayPath, file));
17467
+ for (const file of import_fs36.default.readdirSync(dayPath)) {
17468
+ if (file.endsWith(".jsonl")) jsonlFiles.push(import_path37.default.join(dayPath, file));
17303
17469
  }
17304
17470
  }
17305
17471
  }
@@ -17352,13 +17518,13 @@ function freezeGeminiCost(acc) {
17352
17518
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
17353
17519
  const startMs = start.getTime();
17354
17520
  try {
17355
- if (import_fs35.default.statSync(filePath).mtimeMs < startMs) return;
17521
+ if (import_fs36.default.statSync(filePath).mtimeMs < startMs) return;
17356
17522
  } catch {
17357
17523
  return;
17358
17524
  }
17359
17525
  let raw;
17360
17526
  try {
17361
- raw = import_fs35.default.readFileSync(filePath, "utf-8");
17527
+ raw = import_fs36.default.readFileSync(filePath, "utf-8");
17362
17528
  } catch {
17363
17529
  return;
17364
17530
  }
@@ -17407,30 +17573,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
17407
17573
  const out = [];
17408
17574
  let dirs;
17409
17575
  try {
17410
- if (!import_fs35.default.statSync(geminiTmpDir).isDirectory()) return out;
17411
- dirs = import_fs35.default.readdirSync(geminiTmpDir);
17576
+ if (!import_fs36.default.statSync(geminiTmpDir).isDirectory()) return out;
17577
+ dirs = import_fs36.default.readdirSync(geminiTmpDir);
17412
17578
  } catch {
17413
17579
  return out;
17414
17580
  }
17415
17581
  for (const proj of dirs) {
17416
- const chatsDir = import_path36.default.join(geminiTmpDir, proj, "chats");
17582
+ const chatsDir = import_path37.default.join(geminiTmpDir, proj, "chats");
17417
17583
  let files;
17418
17584
  try {
17419
- if (!import_fs35.default.statSync(chatsDir).isDirectory()) continue;
17420
- files = import_fs35.default.readdirSync(chatsDir);
17585
+ if (!import_fs36.default.statSync(chatsDir).isDirectory()) continue;
17586
+ files = import_fs36.default.readdirSync(chatsDir);
17421
17587
  } catch {
17422
17588
  continue;
17423
17589
  }
17424
17590
  for (const f of files) {
17425
17591
  if (!f.endsWith(".jsonl")) continue;
17426
- out.push({ projectKey: proj, file: import_path36.default.join(chatsDir, f) });
17592
+ out.push({ projectKey: proj, file: import_path37.default.join(chatsDir, f) });
17427
17593
  }
17428
17594
  }
17429
17595
  return out;
17430
17596
  }
17431
17597
  function loadGeminiCost(start, end, geminiTmpDir) {
17432
17598
  const acc = emptyGeminiAccumulator();
17433
- if (!import_fs35.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17599
+ if (!import_fs36.default.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
17434
17600
  for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
17435
17601
  processGeminiCostFile(file, projectKey, start, end, acc);
17436
17602
  }
@@ -17438,11 +17604,11 @@ function loadGeminiCost(start, end, geminiTmpDir) {
17438
17604
  }
17439
17605
  function aggregateReportFromAudit(period, opts = {}) {
17440
17606
  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);
17607
+ const auditLogPath = opts.auditLogPath ?? import_path37.default.join(import_os32.default.homedir(), ".node9", "audit.log");
17608
+ const claudeProjectsDir = opts.claudeProjectsDir ?? import_path37.default.join(import_os32.default.homedir(), ".claude", "projects");
17609
+ const codexSessionsDir = opts.codexSessionsDir ?? import_path37.default.join(import_os32.default.homedir(), ".codex", "sessions");
17610
+ const geminiTmpDir = opts.geminiTmpDir ?? import_path37.default.join(import_os32.default.homedir(), ".gemini", "tmp");
17611
+ const hasAuditFile = import_fs36.default.existsSync(auditLogPath);
17446
17612
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
17447
17613
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
17448
17614
  const { start, end } = getDateRange(period, now);
@@ -18138,14 +18304,14 @@ function registerDaemonCommand(program2) {
18138
18304
 
18139
18305
  // src/cli/commands/status.ts
18140
18306
  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"));
18307
+ var import_fs37 = __toESM(require("fs"));
18308
+ var import_path38 = __toESM(require("path"));
18309
+ var import_os33 = __toESM(require("os"));
18144
18310
  init_core();
18145
18311
  init_daemon();
18146
18312
  function readJson2(filePath) {
18147
18313
  try {
18148
- if (import_fs36.default.existsSync(filePath)) return JSON.parse(import_fs36.default.readFileSync(filePath, "utf-8"));
18314
+ if (import_fs37.default.existsSync(filePath)) return JSON.parse(import_fs37.default.readFileSync(filePath, "utf-8"));
18149
18315
  } catch {
18150
18316
  }
18151
18317
  return null;
@@ -18210,28 +18376,28 @@ function registerStatusCommand(program2) {
18210
18376
  console.log("");
18211
18377
  const modeLabel = settings.mode === "audit" ? import_chalk15.default.blue("audit") : settings.mode === "strict" ? import_chalk15.default.red("strict") : import_chalk15.default.white("standard");
18212
18378
  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");
18379
+ const projectConfig = import_path38.default.join(process.cwd(), "node9.config.json");
18380
+ const globalConfig = import_path38.default.join(import_os33.default.homedir(), ".node9", "config.json");
18215
18381
  console.log(
18216
- ` Local: ${import_fs36.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
18382
+ ` Local: ${import_fs37.default.existsSync(projectConfig) ? import_chalk15.default.green("Active (node9.config.json)") : import_chalk15.default.gray("Not present")}`
18217
18383
  );
18218
18384
  console.log(
18219
- ` Global: ${import_fs36.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
18385
+ ` Global: ${import_fs37.default.existsSync(globalConfig) ? import_chalk15.default.green("Active (~/.node9/config.json)") : import_chalk15.default.gray("Not present")}`
18220
18386
  );
18221
18387
  if (mergedConfig.policy.sandboxPaths.length > 0) {
18222
18388
  console.log(
18223
18389
  ` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
18224
18390
  );
18225
18391
  }
18226
- const homeDir2 = import_os32.default.homedir();
18392
+ const homeDir2 = import_os33.default.homedir();
18227
18393
  const claudeSettings = readJson2(
18228
- import_path37.default.join(homeDir2, ".claude", "settings.json")
18394
+ import_path38.default.join(homeDir2, ".claude", "settings.json")
18229
18395
  );
18230
- const claudeConfig = readJson2(import_path37.default.join(homeDir2, ".claude.json"));
18396
+ const claudeConfig = readJson2(import_path38.default.join(homeDir2, ".claude.json"));
18231
18397
  const geminiSettings = readJson2(
18232
- import_path37.default.join(homeDir2, ".gemini", "settings.json")
18398
+ import_path38.default.join(homeDir2, ".gemini", "settings.json")
18233
18399
  );
18234
- const cursorConfig = readJson2(import_path37.default.join(homeDir2, ".cursor", "mcp.json"));
18400
+ const cursorConfig = readJson2(import_path38.default.join(homeDir2, ".cursor", "mcp.json"));
18235
18401
  const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig;
18236
18402
  if (agentFound) {
18237
18403
  console.log("");
@@ -18290,9 +18456,9 @@ function registerStatusCommand(program2) {
18290
18456
 
18291
18457
  // src/cli/commands/init.ts
18292
18458
  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"));
18459
+ var import_fs38 = __toESM(require("fs"));
18460
+ var import_path39 = __toESM(require("path"));
18461
+ var import_os34 = __toESM(require("os"));
18296
18462
  var import_https4 = __toESM(require("https"));
18297
18463
  init_core();
18298
18464
  init_setup();
@@ -18372,15 +18538,15 @@ function registerInitCommand(program2) {
18372
18538
  }
18373
18539
  console.log("");
18374
18540
  }
18375
- const configPath = import_path38.default.join(import_os33.default.homedir(), ".node9", "config.json");
18376
- if (import_fs37.default.existsSync(configPath) && !options.force) {
18541
+ const configPath = import_path39.default.join(import_os34.default.homedir(), ".node9", "config.json");
18542
+ if (import_fs38.default.existsSync(configPath) && !options.force) {
18377
18543
  try {
18378
- const existing = JSON.parse(import_fs37.default.readFileSync(configPath, "utf-8"));
18544
+ const existing = JSON.parse(import_fs38.default.readFileSync(configPath, "utf-8"));
18379
18545
  const settings = existing.settings ?? {};
18380
18546
  if (settings.mode !== chosenMode) {
18381
18547
  settings.mode = chosenMode;
18382
18548
  existing.settings = settings;
18383
- import_fs37.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18549
+ import_fs38.default.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
18384
18550
  console.log(import_chalk16.default.green(`\u2705 Mode updated: ${chosenMode}`));
18385
18551
  } else {
18386
18552
  console.log(import_chalk16.default.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -18393,9 +18559,9 @@ function registerInitCommand(program2) {
18393
18559
  ...DEFAULT_CONFIG,
18394
18560
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
18395
18561
  };
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");
18562
+ const dir = import_path39.default.dirname(configPath);
18563
+ if (!import_fs38.default.existsSync(dir)) import_fs38.default.mkdirSync(dir, { recursive: true });
18564
+ import_fs38.default.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
18399
18565
  console.log(import_chalk16.default.green(`\u2705 Config created: ${configPath}`));
18400
18566
  console.log(import_chalk16.default.gray(` Mode: ${chosenMode}`));
18401
18567
  }
@@ -18493,7 +18659,7 @@ function registerInitCommand(program2) {
18493
18659
  }
18494
18660
 
18495
18661
  // src/cli/commands/undo.ts
18496
- var import_path39 = __toESM(require("path"));
18662
+ var import_path40 = __toESM(require("path"));
18497
18663
  var import_chalk18 = __toESM(require("chalk"));
18498
18664
 
18499
18665
  // src/tui/undo-navigator.ts
@@ -18652,7 +18818,7 @@ function findMatchingCwd(startDir, history) {
18652
18818
  let dir = startDir;
18653
18819
  while (true) {
18654
18820
  if (cwds.has(dir)) return dir;
18655
- const parent = import_path39.default.dirname(dir);
18821
+ const parent = import_path40.default.dirname(dir);
18656
18822
  if (parent === dir) return null;
18657
18823
  dir = parent;
18658
18824
  }
@@ -18785,90 +18951,7 @@ var import_child_process10 = require("child_process");
18785
18951
  var import_execa3 = require("execa");
18786
18952
  init_orchestrator();
18787
18953
  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
18954
+ init_mcp_pin();
18872
18955
  init_mcp_tools();
18873
18956
  init_daemon();
18874
18957
  function sanitize4(value) {
@@ -18930,6 +19013,7 @@ function tokenize4(cmd) {
18930
19013
  return tokens;
18931
19014
  }
18932
19015
  async function runMcpGateway(upstreamCommand) {
19016
+ const gatewayCwd = process.cwd();
18933
19017
  const commandParts = tokenize4(upstreamCommand);
18934
19018
  const cmd = commandParts[0];
18935
19019
  const cmdArgs = commandParts.slice(1);
@@ -19152,7 +19236,7 @@ async function runMcpGateway(upstreamCommand) {
19152
19236
  if (parsed.result && Array.isArray(parsed.result.tools)) {
19153
19237
  const tools = parsed.result.tools || [];
19154
19238
  const currentHash = hashToolDefinitions(tools);
19155
- const pinStatus = checkPin(serverKey, currentHash);
19239
+ const pinStatus = checkPin(serverKey, currentHash, gatewayCwd);
19156
19240
  const token = getInternalToken();
19157
19241
  if (isDaemonRunning() && process.env.NODE9_TESTING !== "1") {
19158
19242
  const toolSummary = tools.map((t) => ({ name: t.name, description: t.description }));
@@ -20037,26 +20121,45 @@ function registerTrustCommand(program2) {
20037
20121
 
20038
20122
  // src/cli/commands/mcp-pin.ts
20039
20123
  var import_chalk21 = __toESM(require("chalk"));
20124
+ init_mcp_pin();
20125
+ var import_fs40 = __toESM(require("fs"));
20040
20126
  function registerMcpPinCommand(program2) {
20041
20127
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
20042
20128
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
20043
20129
  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;
20130
+ const found = findPinsFilePath(process.cwd());
20131
+ const homeResult = readMcpPinsSafe();
20132
+ let repoEntries = {};
20133
+ let repoCorrupt = false;
20134
+ if (found.source === "repo") {
20135
+ try {
20136
+ const raw = import_fs40.default.readFileSync(found.path, "utf-8");
20137
+ const parsed = JSON.parse(raw);
20138
+ repoEntries = parsed.servers ?? {};
20139
+ } catch {
20140
+ repoCorrupt = true;
20052
20141
  }
20142
+ }
20143
+ if (repoCorrupt) {
20053
20144
  console.error(import_chalk21.default.red(`
20054
- \u274C Pin file is corrupt: ${result.detail}`));
20145
+ \u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
20146
+ process.exit(1);
20147
+ }
20148
+ if (!homeResult.ok && homeResult.reason === "corrupt") {
20149
+ console.error(import_chalk21.default.red(`
20150
+ \u274C Home pin file is corrupt: ${homeResult.detail}`));
20055
20151
  console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
20056
20152
  process.exit(1);
20057
20153
  }
20058
- const entries = Object.entries(result.pins.servers);
20059
- if (entries.length === 0) {
20154
+ const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
20155
+ const merged = /* @__PURE__ */ new Map();
20156
+ for (const [key, entry] of Object.entries(homeEntries)) {
20157
+ merged.set(key, { entry, source: "home" });
20158
+ }
20159
+ for (const [key, entry] of Object.entries(repoEntries)) {
20160
+ merged.set(key, { entry, source: "repo" });
20161
+ }
20162
+ if (merged.size === 0) {
20060
20163
  console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
20061
20164
  console.log(
20062
20165
  import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
@@ -20064,13 +20167,47 @@ function registerMcpPinCommand(program2) {
20064
20167
  return;
20065
20168
  }
20066
20169
  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)}`);
20170
+ const showSource = found.source === "repo";
20171
+ for (const [key, { entry, source }] of merged) {
20172
+ const tag = showSource ? ` ${import_chalk21.default.yellow(`[${source}]`)}` : "";
20173
+ console.log(` ${import_chalk21.default.cyan(key)}${tag} ${import_chalk21.default.gray(entry.label)}`);
20069
20174
  console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
20070
20175
  console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
20071
20176
  console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
20072
20177
  console.log("");
20073
20178
  }
20179
+ if (showSource) {
20180
+ console.log(import_chalk21.default.gray(` [repo] entries come from ${found.path}`));
20181
+ console.log(import_chalk21.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
20182
+ }
20183
+ });
20184
+ pinSubCmd.command("promote <serverKey>").description(
20185
+ "Copy a pin from ~/.node9/mcp-pins.json into <repo>/.node9/mcp-pins.json so teammates share the same vetted baseline"
20186
+ ).action((serverKey) => {
20187
+ try {
20188
+ const { repoPath, created } = promotePin(serverKey, process.cwd());
20189
+ if (created) {
20190
+ console.log(
20191
+ import_chalk21.default.green(
20192
+ `
20193
+ \u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
20194
+ )
20195
+ );
20196
+ } else {
20197
+ console.log(import_chalk21.default.green(`
20198
+ \u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
20199
+ }
20200
+ console.log(import_chalk21.default.gray(" Review the change and commit it:"));
20201
+ console.log(import_chalk21.default.cyan(` git add ${repoPath}`));
20202
+ console.log(import_chalk21.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
20203
+ console.log("");
20204
+ } catch (err2) {
20205
+ const msg = err2 instanceof Error ? err2.message : String(err2);
20206
+ console.error(import_chalk21.default.red(`
20207
+ \u274C ${msg}
20208
+ `));
20209
+ process.exit(1);
20210
+ }
20074
20211
  });
20075
20212
  pinSubCmd.command("update <serverKey>").description(
20076
20213
  "Remove a pin so the next gateway connection re-pins with current tool definitions"
@@ -20092,7 +20229,7 @@ function registerMcpPinCommand(program2) {
20092
20229
  process.exit(1);
20093
20230
  }
20094
20231
  const label = pins.servers[serverKey].label;
20095
- removePin2(serverKey);
20232
+ removePin(serverKey);
20096
20233
  console.log(import_chalk21.default.green(`
20097
20234
  \u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
20098
20235
  console.log(import_chalk21.default.gray(` Server: ${label}`));
@@ -20105,7 +20242,7 @@ function registerMcpPinCommand(program2) {
20105
20242
  return;
20106
20243
  }
20107
20244
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
20108
- clearAllPins2();
20245
+ clearAllPins();
20109
20246
  console.log(import_chalk21.default.green(`
20110
20247
  \u{1F513} Cleared ${count} MCP pin(s).`));
20111
20248
  console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
@@ -20288,7 +20425,7 @@ init_scan();
20288
20425
 
20289
20426
  // src/cli/commands/sessions.ts
20290
20427
  var import_chalk24 = __toESM(require("chalk"));
20291
- var import_fs40 = __toESM(require("fs"));
20428
+ var import_fs41 = __toESM(require("fs"));
20292
20429
  var import_path42 = __toESM(require("path"));
20293
20430
  var import_os36 = __toESM(require("os"));
20294
20431
  var CLAUDE_PRICING3 = {
@@ -20406,7 +20543,7 @@ function loadAuditEntries(auditPath) {
20406
20543
  const aPath = auditPath ?? import_path42.default.join(import_os36.default.homedir(), ".node9", "audit.log");
20407
20544
  let raw;
20408
20545
  try {
20409
- raw = import_fs40.default.readFileSync(aPath, "utf-8");
20546
+ raw = import_fs41.default.readFileSync(aPath, "utf-8");
20410
20547
  } catch {
20411
20548
  return [];
20412
20549
  }
@@ -20443,7 +20580,7 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
20443
20580
  }
20444
20581
  function buildGeminiSessions(days, allAuditEntries) {
20445
20582
  const tmpDir = import_path42.default.join(import_os36.default.homedir(), ".gemini", "tmp");
20446
- if (!import_fs40.default.existsSync(tmpDir)) return [];
20583
+ if (!import_fs41.default.existsSync(tmpDir)) return [];
20447
20584
  const cutoff = days !== null ? (() => {
20448
20585
  const d = /* @__PURE__ */ new Date();
20449
20586
  d.setDate(d.getDate() - days);
@@ -20452,7 +20589,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20452
20589
  })() : null;
20453
20590
  let slugDirs;
20454
20591
  try {
20455
- slugDirs = import_fs40.default.readdirSync(tmpDir);
20592
+ slugDirs = import_fs41.default.readdirSync(tmpDir);
20456
20593
  } catch {
20457
20594
  return [];
20458
20595
  }
@@ -20460,27 +20597,27 @@ function buildGeminiSessions(days, allAuditEntries) {
20460
20597
  for (const slug of slugDirs) {
20461
20598
  const slugPath = import_path42.default.join(tmpDir, slug);
20462
20599
  try {
20463
- if (!import_fs40.default.statSync(slugPath).isDirectory()) continue;
20600
+ if (!import_fs41.default.statSync(slugPath).isDirectory()) continue;
20464
20601
  } catch {
20465
20602
  continue;
20466
20603
  }
20467
20604
  let projectRoot = import_path42.default.join(import_os36.default.homedir(), slug);
20468
20605
  try {
20469
- projectRoot = import_fs40.default.readFileSync(import_path42.default.join(slugPath, ".project_root"), "utf-8").trim();
20606
+ projectRoot = import_fs41.default.readFileSync(import_path42.default.join(slugPath, ".project_root"), "utf-8").trim();
20470
20607
  } catch {
20471
20608
  }
20472
20609
  const chatsDir = import_path42.default.join(slugPath, "chats");
20473
- if (!import_fs40.default.existsSync(chatsDir)) continue;
20610
+ if (!import_fs41.default.existsSync(chatsDir)) continue;
20474
20611
  let chatFiles;
20475
20612
  try {
20476
- chatFiles = import_fs40.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20613
+ chatFiles = import_fs41.default.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
20477
20614
  } catch {
20478
20615
  continue;
20479
20616
  }
20480
20617
  for (const chatFile of chatFiles) {
20481
20618
  let raw;
20482
20619
  try {
20483
- raw = import_fs40.default.readFileSync(import_path42.default.join(chatsDir, chatFile), "utf-8");
20620
+ raw = import_fs41.default.readFileSync(import_path42.default.join(chatsDir, chatFile), "utf-8");
20484
20621
  } catch {
20485
20622
  continue;
20486
20623
  }
@@ -20561,7 +20698,7 @@ function buildGeminiSessions(days, allAuditEntries) {
20561
20698
  }
20562
20699
  function buildCodexSessions(days, allAuditEntries) {
20563
20700
  const sessionsBase = import_path42.default.join(import_os36.default.homedir(), ".codex", "sessions");
20564
- if (!import_fs40.default.existsSync(sessionsBase)) return [];
20701
+ if (!import_fs41.default.existsSync(sessionsBase)) return [];
20565
20702
  const cutoff = days !== null ? (() => {
20566
20703
  const d = /* @__PURE__ */ new Date();
20567
20704
  d.setDate(d.getDate() - days);
@@ -20570,28 +20707,28 @@ function buildCodexSessions(days, allAuditEntries) {
20570
20707
  })() : null;
20571
20708
  const jsonlFiles = [];
20572
20709
  try {
20573
- for (const year of import_fs40.default.readdirSync(sessionsBase)) {
20710
+ for (const year of import_fs41.default.readdirSync(sessionsBase)) {
20574
20711
  const yearPath = import_path42.default.join(sessionsBase, year);
20575
20712
  try {
20576
- if (!import_fs40.default.statSync(yearPath).isDirectory()) continue;
20713
+ if (!import_fs41.default.statSync(yearPath).isDirectory()) continue;
20577
20714
  } catch {
20578
20715
  continue;
20579
20716
  }
20580
- for (const month of import_fs40.default.readdirSync(yearPath)) {
20717
+ for (const month of import_fs41.default.readdirSync(yearPath)) {
20581
20718
  const monthPath = import_path42.default.join(yearPath, month);
20582
20719
  try {
20583
- if (!import_fs40.default.statSync(monthPath).isDirectory()) continue;
20720
+ if (!import_fs41.default.statSync(monthPath).isDirectory()) continue;
20584
20721
  } catch {
20585
20722
  continue;
20586
20723
  }
20587
- for (const day of import_fs40.default.readdirSync(monthPath)) {
20724
+ for (const day of import_fs41.default.readdirSync(monthPath)) {
20588
20725
  const dayPath = import_path42.default.join(monthPath, day);
20589
20726
  try {
20590
- if (!import_fs40.default.statSync(dayPath).isDirectory()) continue;
20727
+ if (!import_fs41.default.statSync(dayPath).isDirectory()) continue;
20591
20728
  } catch {
20592
20729
  continue;
20593
20730
  }
20594
- for (const file of import_fs40.default.readdirSync(dayPath)) {
20731
+ for (const file of import_fs41.default.readdirSync(dayPath)) {
20595
20732
  if (file.endsWith(".jsonl")) jsonlFiles.push(import_path42.default.join(dayPath, file));
20596
20733
  }
20597
20734
  }
@@ -20604,7 +20741,7 @@ function buildCodexSessions(days, allAuditEntries) {
20604
20741
  for (const filePath of jsonlFiles) {
20605
20742
  let lines;
20606
20743
  try {
20607
- lines = import_fs40.default.readFileSync(filePath, "utf-8").split("\n");
20744
+ lines = import_fs41.default.readFileSync(filePath, "utf-8").split("\n");
20608
20745
  } catch {
20609
20746
  continue;
20610
20747
  }
@@ -20685,7 +20822,7 @@ function buildSessions(days, historyPath) {
20685
20822
  const hPath = historyPath ?? import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
20686
20823
  let historyRaw;
20687
20824
  try {
20688
- historyRaw = import_fs40.default.readFileSync(hPath, "utf-8");
20825
+ historyRaw = import_fs41.default.readFileSync(hPath, "utf-8");
20689
20826
  } catch {
20690
20827
  return [];
20691
20828
  }
@@ -20710,7 +20847,7 @@ function buildSessions(days, historyPath) {
20710
20847
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
20711
20848
  let sessionLines = [];
20712
20849
  try {
20713
- sessionLines = import_fs40.default.readFileSync(jsonlFile, "utf-8").split("\n");
20850
+ sessionLines = import_fs41.default.readFileSync(jsonlFile, "utf-8").split("\n");
20714
20851
  } catch {
20715
20852
  }
20716
20853
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -20977,7 +21114,7 @@ function registerSessionsCommand(program2) {
20977
21114
  console.log(import_chalk24.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk24.default.dim(" \u2014 what your AI agent did"));
20978
21115
  console.log("");
20979
21116
  const historyPath = import_path42.default.join(import_os36.default.homedir(), ".claude", "history.jsonl");
20980
- if (!import_fs40.default.existsSync(historyPath)) {
21117
+ if (!import_fs41.default.existsSync(historyPath)) {
20981
21118
  console.log(import_chalk24.default.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
20982
21119
  console.log(import_chalk24.default.gray(" Install Claude Code, run a few sessions, then try again.\n"));
20983
21120
  return;
@@ -21014,12 +21151,12 @@ function registerSessionsCommand(program2) {
21014
21151
 
21015
21152
  // src/cli/commands/skill-pin.ts
21016
21153
  var import_chalk25 = __toESM(require("chalk"));
21017
- var import_fs41 = __toESM(require("fs"));
21154
+ var import_fs42 = __toESM(require("fs"));
21018
21155
  var import_os37 = __toESM(require("os"));
21019
21156
  var import_path43 = __toESM(require("path"));
21020
21157
  function wipeSkillSessions() {
21021
21158
  try {
21022
- import_fs41.default.rmSync(import_path43.default.join(import_os37.default.homedir(), ".node9", "skill-sessions"), {
21159
+ import_fs42.default.rmSync(import_path43.default.join(import_os37.default.homedir(), ".node9", "skill-sessions"), {
21023
21160
  recursive: true,
21024
21161
  force: true
21025
21162
  });
@@ -21077,7 +21214,7 @@ function registerSkillPinCommand(program2) {
21077
21214
  process.exit(1);
21078
21215
  }
21079
21216
  const rootPath = pins.roots[rootKey].rootPath;
21080
- removePin(rootKey);
21217
+ removePin2(rootKey);
21081
21218
  wipeSkillSessions();
21082
21219
  console.log(import_chalk25.default.green(`
21083
21220
  \u{1F513} Pin removed for ${import_chalk25.default.cyan(rootKey)}`));
@@ -21092,7 +21229,7 @@ function registerSkillPinCommand(program2) {
21092
21229
  return;
21093
21230
  }
21094
21231
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
21095
- clearAllPins();
21232
+ clearAllPins2();
21096
21233
  wipeSkillSessions();
21097
21234
  console.log(import_chalk25.default.green(`
21098
21235
  \u{1F513} Cleared ${count} skill pin(s).`));
@@ -21101,15 +21238,15 @@ function registerSkillPinCommand(program2) {
21101
21238
  }
21102
21239
 
21103
21240
  // src/cli/commands/decisions.ts
21104
- var import_fs42 = __toESM(require("fs"));
21241
+ var import_fs43 = __toESM(require("fs"));
21105
21242
  var import_os38 = __toESM(require("os"));
21106
21243
  var import_path44 = __toESM(require("path"));
21107
21244
  var import_chalk26 = __toESM(require("chalk"));
21108
21245
  var DECISIONS_FILE2 = import_path44.default.join(import_os38.default.homedir(), ".node9", "decisions.json");
21109
21246
  function readDecisions() {
21110
21247
  try {
21111
- if (!import_fs42.default.existsSync(DECISIONS_FILE2)) return {};
21112
- const raw = import_fs42.default.readFileSync(DECISIONS_FILE2, "utf-8");
21248
+ if (!import_fs43.default.existsSync(DECISIONS_FILE2)) return {};
21249
+ const raw = import_fs43.default.readFileSync(DECISIONS_FILE2, "utf-8");
21113
21250
  const parsed = JSON.parse(raw);
21114
21251
  const out = {};
21115
21252
  for (const [k, v] of Object.entries(parsed)) {
@@ -21122,10 +21259,10 @@ function readDecisions() {
21122
21259
  }
21123
21260
  function writeDecisions(d) {
21124
21261
  const dir = import_path44.default.dirname(DECISIONS_FILE2);
21125
- if (!import_fs42.default.existsSync(dir)) import_fs42.default.mkdirSync(dir, { recursive: true });
21262
+ if (!import_fs43.default.existsSync(dir)) import_fs43.default.mkdirSync(dir, { recursive: true });
21126
21263
  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);
21264
+ import_fs43.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
21265
+ import_fs43.default.renameSync(tmp, DECISIONS_FILE2);
21129
21266
  }
21130
21267
  function registerDecisionsCommand(program2) {
21131
21268
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -21182,7 +21319,7 @@ Persistent decisions (${entries.length})
21182
21319
 
21183
21320
  // src/cli/commands/dlp.ts
21184
21321
  var import_chalk27 = __toESM(require("chalk"));
21185
- var import_fs43 = __toESM(require("fs"));
21322
+ var import_fs44 = __toESM(require("fs"));
21186
21323
  var import_path45 = __toESM(require("path"));
21187
21324
  var import_os39 = __toESM(require("os"));
21188
21325
  var AUDIT_LOG = import_path45.default.join(import_os39.default.homedir(), ".node9", "audit.log");
@@ -21193,7 +21330,7 @@ function stripAnsi(s) {
21193
21330
  }
21194
21331
  function loadResolved() {
21195
21332
  try {
21196
- const raw = JSON.parse(import_fs43.default.readFileSync(RESOLVED_FILE, "utf-8"));
21333
+ const raw = JSON.parse(import_fs44.default.readFileSync(RESOLVED_FILE, "utf-8"));
21197
21334
  return new Set(raw);
21198
21335
  } catch {
21199
21336
  return /* @__PURE__ */ new Set();
@@ -21201,13 +21338,13 @@ function loadResolved() {
21201
21338
  }
21202
21339
  function saveResolved(resolved) {
21203
21340
  try {
21204
- import_fs43.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21341
+ import_fs44.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
21205
21342
  } catch {
21206
21343
  }
21207
21344
  }
21208
21345
  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) => {
21346
+ if (!import_fs44.default.existsSync(AUDIT_LOG)) return [];
21347
+ return import_fs44.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
21211
21348
  if (!line.trim()) return [];
21212
21349
  try {
21213
21350
  const e = JSON.parse(line);
@@ -21305,14 +21442,14 @@ function registerDlpCommand(program2) {
21305
21442
 
21306
21443
  // src/cli/commands/mask.ts
21307
21444
  var import_chalk28 = __toESM(require("chalk"));
21308
- var import_fs44 = __toESM(require("fs"));
21445
+ var import_fs45 = __toESM(require("fs"));
21309
21446
  var import_path46 = __toESM(require("path"));
21310
21447
  var import_os40 = __toESM(require("os"));
21311
21448
  init_dlp();
21312
21449
  function findJsonlFiles(dir) {
21313
21450
  const results = [];
21314
- if (!import_fs44.default.existsSync(dir)) return results;
21315
- for (const entry of import_fs44.default.readdirSync(dir, { withFileTypes: true })) {
21451
+ if (!import_fs45.default.existsSync(dir)) return results;
21452
+ for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
21316
21453
  const full = import_path46.default.join(dir, entry.name);
21317
21454
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
21318
21455
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
@@ -21356,7 +21493,7 @@ function redactJson(obj) {
21356
21493
  function processFile(filePath, dryRun) {
21357
21494
  let raw;
21358
21495
  try {
21359
- raw = import_fs44.default.readFileSync(filePath, "utf-8");
21496
+ raw = import_fs45.default.readFileSync(filePath, "utf-8");
21360
21497
  } catch {
21361
21498
  return { redactedLines: 0, patterns: [] };
21362
21499
  }
@@ -21388,14 +21525,14 @@ function processFile(filePath, dryRun) {
21388
21525
  }
21389
21526
  }
21390
21527
  if (!dryRun && redactedLines > 0) {
21391
- import_fs44.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21528
+ import_fs45.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
21392
21529
  }
21393
21530
  return { redactedLines, patterns };
21394
21531
  }
21395
21532
  function processJsonFile(filePath, dryRun) {
21396
21533
  let raw;
21397
21534
  try {
21398
- raw = import_fs44.default.readFileSync(filePath, "utf-8");
21535
+ raw = import_fs45.default.readFileSync(filePath, "utf-8");
21399
21536
  } catch {
21400
21537
  return { redactedLines: 0, patterns: [] };
21401
21538
  }
@@ -21408,14 +21545,14 @@ function processJsonFile(filePath, dryRun) {
21408
21545
  const { value, modified, found } = redactJson(parsed);
21409
21546
  if (!modified) return { redactedLines: 0, patterns: [] };
21410
21547
  if (!dryRun) {
21411
- import_fs44.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21548
+ import_fs45.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
21412
21549
  }
21413
21550
  return { redactedLines: 1, patterns: found };
21414
21551
  }
21415
21552
  function findJsonFiles(dir) {
21416
21553
  const results = [];
21417
- if (!import_fs44.default.existsSync(dir)) return results;
21418
- for (const entry of import_fs44.default.readdirSync(dir, { withFileTypes: true })) {
21554
+ if (!import_fs45.default.existsSync(dir)) return results;
21555
+ for (const entry of import_fs45.default.readdirSync(dir, { withFileTypes: true })) {
21419
21556
  const full = import_path46.default.join(dir, entry.name);
21420
21557
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
21421
21558
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
@@ -21435,7 +21572,7 @@ function registerMaskCommand(program2) {
21435
21572
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
21436
21573
  const filtered = cutoff ? allFiles.filter((f) => {
21437
21574
  try {
21438
- return import_fs44.default.statSync(f.path).mtime >= cutoff;
21575
+ return import_fs45.default.statSync(f.path).mtime >= cutoff;
21439
21576
  } catch {
21440
21577
  return false;
21441
21578
  }
@@ -21491,20 +21628,20 @@ function registerMaskCommand(program2) {
21491
21628
  // src/cli.ts
21492
21629
  init_blast();
21493
21630
  var { version } = JSON.parse(
21494
- import_fs47.default.readFileSync(import_path49.default.join(__dirname, "../package.json"), "utf-8")
21631
+ import_fs48.default.readFileSync(import_path49.default.join(__dirname, "../package.json"), "utf-8")
21495
21632
  );
21496
21633
  var program = new import_commander.Command();
21497
21634
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
21498
21635
  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
21636
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
21500
21637
  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 });
21638
+ if (!import_fs48.default.existsSync(import_path49.default.dirname(credPath)))
21639
+ import_fs48.default.mkdirSync(import_path49.default.dirname(credPath), { recursive: true });
21503
21640
  const profileName = options.profile || "default";
21504
21641
  let existingCreds = {};
21505
21642
  try {
21506
- if (import_fs47.default.existsSync(credPath)) {
21507
- const raw = JSON.parse(import_fs47.default.readFileSync(credPath, "utf-8"));
21643
+ if (import_fs48.default.existsSync(credPath)) {
21644
+ const raw = JSON.parse(import_fs48.default.readFileSync(credPath, "utf-8"));
21508
21645
  if (raw.apiKey) {
21509
21646
  existingCreds = {
21510
21647
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -21516,13 +21653,13 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21516
21653
  } catch {
21517
21654
  }
21518
21655
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
21519
- import_fs47.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21656
+ import_fs48.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
21520
21657
  if (profileName === "default") {
21521
21658
  const configPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "config.json");
21522
21659
  let config = {};
21523
21660
  try {
21524
- if (import_fs47.default.existsSync(configPath))
21525
- config = JSON.parse(import_fs47.default.readFileSync(configPath, "utf-8"));
21661
+ if (import_fs48.default.existsSync(configPath))
21662
+ config = JSON.parse(import_fs48.default.readFileSync(configPath, "utf-8"));
21526
21663
  } catch {
21527
21664
  }
21528
21665
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -21537,9 +21674,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21537
21674
  approvers.cloud = false;
21538
21675
  }
21539
21676
  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 });
21677
+ if (!import_fs48.default.existsSync(import_path49.default.dirname(configPath)))
21678
+ import_fs48.default.mkdirSync(import_path49.default.dirname(configPath), { recursive: true });
21679
+ import_fs48.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
21543
21680
  }
21544
21681
  if (options.profile && profileName !== "default") {
21545
21682
  console.log(import_chalk30.default.green(`\u2705 Profile "${profileName}" saved`));
@@ -21677,14 +21814,14 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
21677
21814
  }
21678
21815
  if (options.purge) {
21679
21816
  const node9Dir = import_path49.default.join(import_os43.default.homedir(), ".node9");
21680
- if (import_fs47.default.existsSync(node9Dir)) {
21817
+ if (import_fs48.default.existsSync(node9Dir)) {
21681
21818
  const confirmed = await (0, import_prompts2.confirm)({
21682
21819
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
21683
21820
  default: false
21684
21821
  });
21685
21822
  if (confirmed) {
21686
- import_fs47.default.rmSync(node9Dir, { recursive: true });
21687
- if (import_fs47.default.existsSync(node9Dir)) {
21823
+ import_fs48.default.rmSync(node9Dir, { recursive: true });
21824
+ if (import_fs48.default.existsSync(node9Dir)) {
21688
21825
  console.error(
21689
21826
  import_chalk30.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
21690
21827
  );
@@ -21839,12 +21976,12 @@ Run "node9 addto claude" to register it as the statusLine.`
21839
21976
  if (subcommand === "debug") {
21840
21977
  const flagFile = import_path49.default.join(import_os43.default.homedir(), ".node9", "hud-debug");
21841
21978
  if (state === "on") {
21842
- import_fs47.default.mkdirSync(import_path49.default.dirname(flagFile), { recursive: true });
21843
- import_fs47.default.writeFileSync(flagFile, "");
21979
+ import_fs48.default.mkdirSync(import_path49.default.dirname(flagFile), { recursive: true });
21980
+ import_fs48.default.writeFileSync(flagFile, "");
21844
21981
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
21845
21982
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
21846
21983
  } else if (state === "off") {
21847
- if (import_fs47.default.existsSync(flagFile)) import_fs47.default.unlinkSync(flagFile);
21984
+ if (import_fs48.default.existsSync(flagFile)) import_fs48.default.unlinkSync(flagFile);
21848
21985
  console.log("HUD debug logging disabled.");
21849
21986
  } else {
21850
21987
  console.error("Usage: node9 hud debug on|off");
@@ -21960,7 +22097,7 @@ if (process.argv[2] !== "daemon") {
21960
22097
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
21961
22098
  const logPath = import_path49.default.join(import_os43.default.homedir(), ".node9", "hook-debug.log");
21962
22099
  const msg = reason instanceof Error ? reason.message : String(reason);
21963
- import_fs47.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
22100
+ import_fs48.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
21964
22101
  `);
21965
22102
  }
21966
22103
  process.exit(0);