@node9/proxy 1.35.0 → 1.35.2

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.
Files changed (3) hide show
  1. package/dist/cli.js +478 -467
  2. package/dist/cli.mjs +474 -463
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -185,8 +185,8 @@ function sanitizeConfig(raw) {
185
185
  }
186
186
  }
187
187
  const lines = result.error.issues.map((issue) => {
188
- const path54 = issue.path.length > 0 ? issue.path.join(".") : "root";
189
- return ` \u2022 ${path54}: ${issue.message}`;
188
+ const path55 = issue.path.length > 0 ? issue.path.join(".") : "root";
189
+ return ` \u2022 ${path55}: ${issue.message}`;
190
190
  });
191
191
  return {
192
192
  sanitized,
@@ -1240,9 +1240,9 @@ function matchesPattern(text, patterns) {
1240
1240
  const withoutDotSlash = text.replace(/^\.\//, "");
1241
1241
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1242
1242
  }
1243
- function getNestedValue(obj, path54) {
1243
+ function getNestedValue(obj, path55) {
1244
1244
  if (!obj || typeof obj !== "object") return null;
1245
- const segments = path54.split(".");
1245
+ const segments = path55.split(".");
1246
1246
  for (const seg of segments) {
1247
1247
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1248
1248
  }
@@ -8136,7 +8136,7 @@ function binaryInPath(binary) {
8136
8136
  return false;
8137
8137
  }
8138
8138
  function detectAgents(homeDir2 = os12.homedir()) {
8139
- const exists = (p) => {
8139
+ const exists2 = (p) => {
8140
8140
  try {
8141
8141
  return fs13.existsSync(p);
8142
8142
  } catch (err2) {
@@ -8150,7 +8150,7 @@ function detectAgents(homeDir2 = os12.homedir()) {
8150
8150
  };
8151
8151
  const desktopPath = claudeDesktopConfigPath(homeDir2);
8152
8152
  return {
8153
- claude: exists(path15.join(homeDir2, ".claude")) || exists(path15.join(homeDir2, ".claude.json")),
8153
+ claude: exists2(path15.join(homeDir2, ".claude")) || exists2(path15.join(homeDir2, ".claude.json")),
8154
8154
  // Antigravity (agy) shares the ~/.gemini root, so a bare
8155
8155
  // `exists(~/.gemini)` would report the (EOL'd) Gemini CLI as
8156
8156
  // installed on every agy machine — and `node9 init` would then
@@ -8160,35 +8160,35 @@ function detectAgents(homeDir2 = os12.homedir()) {
8160
8160
  // creates ~/.gemini/settings.json on first run; agy does not touch
8161
8161
  // it (it uses antigravity-cli/settings.json) — that file is the
8162
8162
  // legacy-CLI discriminator.
8163
- gemini: exists(path15.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8163
+ gemini: exists2(path15.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8164
8164
  // agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
8165
8165
  // creates antigravity-ide/. PATH fallback covers installed-but-
8166
8166
  // never-launched (same class as opencode #186).
8167
- antigravity: exists(path15.join(homeDir2, ".gemini", "antigravity-cli")) || exists(path15.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8167
+ antigravity: exists2(path15.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(path15.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8168
8168
  // GitHub Copilot CLI creates ~/.copilot on first launch; PATH
8169
8169
  // fallback covers installed-but-never-launched (same as opencode #186).
8170
- copilot: exists(path15.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8171
- cursor: exists(path15.join(homeDir2, ".cursor")),
8172
- codex: exists(path15.join(homeDir2, ".codex")),
8173
- windsurf: exists(path15.join(homeDir2, ".codeium", "windsurf")),
8174
- vscode: exists(path15.join(homeDir2, ".vscode")),
8175
- claudeDesktop: desktopPath !== null && exists(path15.dirname(desktopPath)),
8170
+ copilot: exists2(path15.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8171
+ cursor: exists2(path15.join(homeDir2, ".cursor")),
8172
+ codex: exists2(path15.join(homeDir2, ".codex")),
8173
+ windsurf: exists2(path15.join(homeDir2, ".codeium", "windsurf")),
8174
+ vscode: exists2(path15.join(homeDir2, ".vscode")),
8175
+ claudeDesktop: desktopPath !== null && exists2(path15.dirname(desktopPath)),
8176
8176
  // Opencode creates ~/.config/opencode lazily on first launch — fall back
8177
8177
  // to a PATH lookup so installed-but-never-launched CLIs are still wired.
8178
- opencode: exists(path15.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8178
+ opencode: exists2(path15.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8179
8179
  // Pi (https://pi.dev): config dir is ~/.pi/agent (CONFIG_DIR_NAME=".pi"
8180
8180
  // + agentDir, verified against opensources/pi-main/packages/coding-agent/
8181
8181
  // src/config.ts:449,475). The Bun-compiled binary path may create this
8182
8182
  // dir lazily on first launch — same class of bug as opencode's #186
8183
8183
  // (design R6) — so fall back to PATH lookup for installed-but-never-
8184
8184
  // launched pi.
8185
- pi: exists(path15.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8185
+ pi: exists2(path15.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8186
8186
  // Hermes Agent (https://github.com/NousResearch/hermes-agent): home dir
8187
8187
  // is $HERMES_HOME (default ~/.hermes) per hermes_constants.py:30. config.yaml
8188
8188
  // appears after `hermes setup` has run; the directory alone exists from
8189
8189
  // install time. PATH fallback covers the rare case where the user blew
8190
8190
  // away ~/.hermes but kept the binary.
8191
- hermes: exists(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8191
+ hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8192
8192
  };
8193
8193
  }
8194
8194
  async function setupCursor() {
@@ -16904,9 +16904,9 @@ __export(tail_exports, {
16904
16904
  });
16905
16905
  import http2 from "http";
16906
16906
  import chalk29 from "chalk";
16907
- import fs50 from "fs";
16908
- import os45 from "os";
16909
- import path51 from "path";
16907
+ import fs51 from "fs";
16908
+ import os46 from "os";
16909
+ import path52 from "path";
16910
16910
  import readline6 from "readline";
16911
16911
  import { spawn as spawn8 } from "child_process";
16912
16912
  function shortenPathSummary(s) {
@@ -16930,20 +16930,20 @@ function getModelContextLimit(model) {
16930
16930
  return 2e5;
16931
16931
  }
16932
16932
  function readSessionUsage() {
16933
- const projectsDir = path51.join(os45.homedir(), ".claude", "projects");
16934
- if (!fs50.existsSync(projectsDir)) return null;
16933
+ const projectsDir = path52.join(os46.homedir(), ".claude", "projects");
16934
+ if (!fs51.existsSync(projectsDir)) return null;
16935
16935
  let latestFile = null;
16936
16936
  let latestMtime = 0;
16937
16937
  try {
16938
- for (const dir of fs50.readdirSync(projectsDir)) {
16939
- const dirPath = path51.join(projectsDir, dir);
16938
+ for (const dir of fs51.readdirSync(projectsDir)) {
16939
+ const dirPath = path52.join(projectsDir, dir);
16940
16940
  try {
16941
- if (!fs50.statSync(dirPath).isDirectory()) continue;
16942
- for (const file of fs50.readdirSync(dirPath)) {
16941
+ if (!fs51.statSync(dirPath).isDirectory()) continue;
16942
+ for (const file of fs51.readdirSync(dirPath)) {
16943
16943
  if (!file.endsWith(".jsonl") || file.startsWith("agent-")) continue;
16944
- const filePath = path51.join(dirPath, file);
16944
+ const filePath = path52.join(dirPath, file);
16945
16945
  try {
16946
- const mtime = fs50.statSync(filePath).mtimeMs;
16946
+ const mtime = fs51.statSync(filePath).mtimeMs;
16947
16947
  if (mtime > latestMtime) {
16948
16948
  latestMtime = mtime;
16949
16949
  latestFile = filePath;
@@ -16958,7 +16958,7 @@ function readSessionUsage() {
16958
16958
  }
16959
16959
  if (!latestFile) return null;
16960
16960
  try {
16961
- const lines = fs50.readFileSync(latestFile, "utf-8").split("\n");
16961
+ const lines = fs51.readFileSync(latestFile, "utf-8").split("\n");
16962
16962
  let lastModel = "";
16963
16963
  let lastInput = 0;
16964
16964
  let lastOutput = 0;
@@ -17019,7 +17019,7 @@ function formatBase(activity) {
17019
17019
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
17020
17020
  const icon = getIcon(activity.tool);
17021
17021
  const toolName = activity.tool.slice(0, 16).padEnd(16);
17022
- const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os45.homedir(), "~");
17022
+ const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os46.homedir(), "~");
17023
17023
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
17024
17024
  return `${chalk29.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk29.white.bold(toolName)} ${chalk29.dim(argsPreview)}`;
17025
17025
  }
@@ -17058,9 +17058,9 @@ function renderPending(activity) {
17058
17058
  }
17059
17059
  async function ensureDaemon() {
17060
17060
  let pidPort = null;
17061
- if (fs50.existsSync(PID_FILE)) {
17061
+ if (fs51.existsSync(PID_FILE)) {
17062
17062
  try {
17063
- const { port } = JSON.parse(fs50.readFileSync(PID_FILE, "utf-8"));
17063
+ const { port } = JSON.parse(fs51.readFileSync(PID_FILE, "utf-8"));
17064
17064
  pidPort = port;
17065
17065
  } catch {
17066
17066
  console.error(chalk29.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
@@ -17216,9 +17216,9 @@ function buildRecoveryCardLines(req) {
17216
17216
  ];
17217
17217
  }
17218
17218
  function readApproversFromDisk() {
17219
- const configPath = path51.join(os45.homedir(), ".node9", "config.json");
17219
+ const configPath = path52.join(os46.homedir(), ".node9", "config.json");
17220
17220
  try {
17221
- const raw = JSON.parse(fs50.readFileSync(configPath, "utf-8"));
17221
+ const raw = JSON.parse(fs51.readFileSync(configPath, "utf-8"));
17222
17222
  const settings = raw.settings ?? {};
17223
17223
  return settings.approvers ?? {};
17224
17224
  } catch {
@@ -17234,15 +17234,15 @@ function approverStatusLine() {
17234
17234
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
17235
17235
  }
17236
17236
  function toggleApprover(channel) {
17237
- const configPath = path51.join(os45.homedir(), ".node9", "config.json");
17237
+ const configPath = path52.join(os46.homedir(), ".node9", "config.json");
17238
17238
  try {
17239
- const raw = JSON.parse(fs50.readFileSync(configPath, "utf-8"));
17239
+ const raw = JSON.parse(fs51.readFileSync(configPath, "utf-8"));
17240
17240
  const settings = raw.settings ?? {};
17241
17241
  const approvers = settings.approvers ?? {};
17242
17242
  approvers[channel] = approvers[channel] === false;
17243
17243
  settings.approvers = approvers;
17244
17244
  raw.settings = settings;
17245
- fs50.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
17245
+ fs51.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
17246
17246
  } catch (err2) {
17247
17247
  process.stderr.write(`[node9] toggleApprover failed: ${String(err2)}
17248
17248
  `);
@@ -17414,8 +17414,8 @@ async function startTail(options = {}) {
17414
17414
  }
17415
17415
  postDecisionHttp(req2.id, httpDecision, authToken, port, httpOpts).catch((err2) => {
17416
17416
  try {
17417
- fs50.appendFileSync(
17418
- path51.join(os45.homedir(), ".node9", "hook-debug.log"),
17417
+ fs51.appendFileSync(
17418
+ path52.join(os46.homedir(), ".node9", "hook-debug.log"),
17419
17419
  `[tail] POST /decision failed: ${String(err2)}
17420
17420
  `
17421
17421
  );
@@ -17479,9 +17479,9 @@ async function startTail(options = {}) {
17479
17479
  };
17480
17480
  process.stdin.on("keypress", onKeypress);
17481
17481
  }
17482
- const auditLog = path51.join(os45.homedir(), ".node9", "audit.log");
17482
+ const auditLog = path52.join(os46.homedir(), ".node9", "audit.log");
17483
17483
  try {
17484
- const unackedDlp = fs50.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
17484
+ const unackedDlp = fs51.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
17485
17485
  if (unackedDlp > 0) {
17486
17486
  console.log("");
17487
17487
  console.log(
@@ -17521,7 +17521,7 @@ async function startTail(options = {}) {
17521
17521
  if (stallWarned) return;
17522
17522
  if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
17523
17523
  try {
17524
- const auditMtime = fs50.statSync(auditLog).mtimeMs;
17524
+ const auditMtime = fs51.statSync(auditLog).mtimeMs;
17525
17525
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
17526
17526
  console.log("");
17527
17527
  console.log(
@@ -17712,7 +17712,7 @@ var init_tail = __esm({
17712
17712
  "use strict";
17713
17713
  init_daemon2();
17714
17714
  init_daemon();
17715
- PID_FILE = path51.join(os45.homedir(), ".node9", "daemon.pid");
17715
+ PID_FILE = path52.join(os46.homedir(), ".node9", "daemon.pid");
17716
17716
  ICONS = {
17717
17717
  bash: "\u{1F4BB}",
17718
17718
  shell: "\u{1F4BB}",
@@ -17760,9 +17760,9 @@ __export(hud_exports, {
17760
17760
  main: () => main,
17761
17761
  renderEnvironmentLine: () => renderEnvironmentLine
17762
17762
  });
17763
- import fs51 from "fs";
17764
- import path52 from "path";
17765
- import os46 from "os";
17763
+ import fs52 from "fs";
17764
+ import path53 from "path";
17765
+ import os47 from "os";
17766
17766
  import http3 from "http";
17767
17767
  async function readStdin() {
17768
17768
  const chunks = [];
@@ -17838,9 +17838,9 @@ function formatTimeLeft(resetsAt) {
17838
17838
  return ` (${m}m left)`;
17839
17839
  }
17840
17840
  function safeReadJson(filePath) {
17841
- if (!fs51.existsSync(filePath)) return null;
17841
+ if (!fs52.existsSync(filePath)) return null;
17842
17842
  try {
17843
- return JSON.parse(fs51.readFileSync(filePath, "utf-8"));
17843
+ return JSON.parse(fs52.readFileSync(filePath, "utf-8"));
17844
17844
  } catch {
17845
17845
  return null;
17846
17846
  }
@@ -17861,12 +17861,12 @@ function countHooksInFile(filePath) {
17861
17861
  return Object.keys(cfg.hooks).length;
17862
17862
  }
17863
17863
  function countRulesInDir(rulesDir) {
17864
- if (!fs51.existsSync(rulesDir)) return 0;
17864
+ if (!fs52.existsSync(rulesDir)) return 0;
17865
17865
  let count = 0;
17866
17866
  try {
17867
- for (const entry of fs51.readdirSync(rulesDir, { withFileTypes: true })) {
17867
+ for (const entry of fs52.readdirSync(rulesDir, { withFileTypes: true })) {
17868
17868
  if (entry.isDirectory()) {
17869
- count += countRulesInDir(path52.join(rulesDir, entry.name));
17869
+ count += countRulesInDir(path53.join(rulesDir, entry.name));
17870
17870
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
17871
17871
  count++;
17872
17872
  }
@@ -17877,46 +17877,46 @@ function countRulesInDir(rulesDir) {
17877
17877
  }
17878
17878
  function isSamePath(a, b) {
17879
17879
  try {
17880
- return path52.resolve(a) === path52.resolve(b);
17880
+ return path53.resolve(a) === path53.resolve(b);
17881
17881
  } catch {
17882
17882
  return false;
17883
17883
  }
17884
17884
  }
17885
17885
  function countConfigs(cwd) {
17886
- const homeDir2 = os46.homedir();
17887
- const claudeDir = path52.join(homeDir2, ".claude");
17886
+ const homeDir2 = os47.homedir();
17887
+ const claudeDir = path53.join(homeDir2, ".claude");
17888
17888
  let claudeMdCount = 0;
17889
17889
  let rulesCount = 0;
17890
17890
  let hooksCount = 0;
17891
17891
  const userMcpServers = /* @__PURE__ */ new Set();
17892
17892
  const projectMcpServers = /* @__PURE__ */ new Set();
17893
- if (fs51.existsSync(path52.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
17894
- rulesCount += countRulesInDir(path52.join(claudeDir, "rules"));
17895
- const userSettings = path52.join(claudeDir, "settings.json");
17893
+ if (fs52.existsSync(path53.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
17894
+ rulesCount += countRulesInDir(path53.join(claudeDir, "rules"));
17895
+ const userSettings = path53.join(claudeDir, "settings.json");
17896
17896
  for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
17897
17897
  hooksCount += countHooksInFile(userSettings);
17898
- const userClaudeJson = path52.join(homeDir2, ".claude.json");
17898
+ const userClaudeJson = path53.join(homeDir2, ".claude.json");
17899
17899
  for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
17900
17900
  for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
17901
17901
  userMcpServers.delete(name);
17902
17902
  }
17903
17903
  if (cwd) {
17904
- if (fs51.existsSync(path52.join(cwd, "CLAUDE.md"))) claudeMdCount++;
17905
- if (fs51.existsSync(path52.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
17906
- const projectClaudeDir = path52.join(cwd, ".claude");
17904
+ if (fs52.existsSync(path53.join(cwd, "CLAUDE.md"))) claudeMdCount++;
17905
+ if (fs52.existsSync(path53.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
17906
+ const projectClaudeDir = path53.join(cwd, ".claude");
17907
17907
  const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
17908
17908
  if (!overlapsUserScope) {
17909
- if (fs51.existsSync(path52.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
17910
- rulesCount += countRulesInDir(path52.join(projectClaudeDir, "rules"));
17911
- const projSettings = path52.join(projectClaudeDir, "settings.json");
17909
+ if (fs52.existsSync(path53.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
17910
+ rulesCount += countRulesInDir(path53.join(projectClaudeDir, "rules"));
17911
+ const projSettings = path53.join(projectClaudeDir, "settings.json");
17912
17912
  for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
17913
17913
  hooksCount += countHooksInFile(projSettings);
17914
17914
  }
17915
- if (fs51.existsSync(path52.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
17916
- const localSettings = path52.join(projectClaudeDir, "settings.local.json");
17915
+ if (fs52.existsSync(path53.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
17916
+ const localSettings = path53.join(projectClaudeDir, "settings.local.json");
17917
17917
  for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
17918
17918
  hooksCount += countHooksInFile(localSettings);
17919
- const mcpJsonServers = getMcpServerNames(path52.join(cwd, ".mcp.json"));
17919
+ const mcpJsonServers = getMcpServerNames(path53.join(cwd, ".mcp.json"));
17920
17920
  const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
17921
17921
  for (const name of disabledMcpJson) mcpJsonServers.delete(name);
17922
17922
  for (const name of mcpJsonServers) projectMcpServers.add(name);
@@ -17949,12 +17949,12 @@ function readActiveShieldsHud() {
17949
17949
  return shieldsCache.value;
17950
17950
  }
17951
17951
  try {
17952
- const shieldsPath = path52.join(os46.homedir(), ".node9", "shields.json");
17953
- if (!fs51.existsSync(shieldsPath)) {
17952
+ const shieldsPath = path53.join(os47.homedir(), ".node9", "shields.json");
17953
+ if (!fs52.existsSync(shieldsPath)) {
17954
17954
  shieldsCache = { value: [], ts: now };
17955
17955
  return [];
17956
17956
  }
17957
- const parsed = JSON.parse(fs51.readFileSync(shieldsPath, "utf-8"));
17957
+ const parsed = JSON.parse(fs52.readFileSync(shieldsPath, "utf-8"));
17958
17958
  if (!Array.isArray(parsed.active)) {
17959
17959
  shieldsCache = { value: [], ts: now };
17960
17960
  return [];
@@ -18056,17 +18056,17 @@ function renderContextLine(stdin) {
18056
18056
  async function main() {
18057
18057
  try {
18058
18058
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
18059
- if (fs51.existsSync(path52.join(os46.homedir(), ".node9", "hud-debug"))) {
18059
+ if (fs52.existsSync(path53.join(os47.homedir(), ".node9", "hud-debug"))) {
18060
18060
  try {
18061
- const logPath = path52.join(os46.homedir(), ".node9", "hud-debug.log");
18061
+ const logPath = path53.join(os47.homedir(), ".node9", "hud-debug.log");
18062
18062
  const MAX_LOG_SIZE = 10 * 1024 * 1024;
18063
18063
  let size = 0;
18064
18064
  try {
18065
- size = fs51.statSync(logPath).size;
18065
+ size = fs52.statSync(logPath).size;
18066
18066
  } catch {
18067
18067
  }
18068
18068
  if (size < MAX_LOG_SIZE) {
18069
- fs51.appendFileSync(
18069
+ fs52.appendFileSync(
18070
18070
  logPath,
18071
18071
  JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
18072
18072
  );
@@ -18087,11 +18087,11 @@ async function main() {
18087
18087
  try {
18088
18088
  const cwd = stdin.cwd ?? process.cwd();
18089
18089
  for (const configPath of [
18090
- path52.join(cwd, "node9.config.json"),
18091
- path52.join(os46.homedir(), ".node9", "config.json")
18090
+ path53.join(cwd, "node9.config.json"),
18091
+ path53.join(os47.homedir(), ".node9", "config.json")
18092
18092
  ]) {
18093
- if (!fs51.existsSync(configPath)) continue;
18094
- const cfg = JSON.parse(fs51.readFileSync(configPath, "utf-8"));
18093
+ if (!fs52.existsSync(configPath)) continue;
18094
+ const cfg = JSON.parse(fs52.readFileSync(configPath, "utf-8"));
18095
18095
  const hud = cfg.settings?.hud;
18096
18096
  if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
18097
18097
  }
@@ -18138,9 +18138,9 @@ init_setup();
18138
18138
  init_daemon2();
18139
18139
  import { Command } from "commander";
18140
18140
  import chalk30 from "chalk";
18141
- import fs52 from "fs";
18142
- import path53 from "path";
18143
- import os47 from "os";
18141
+ import fs53 from "fs";
18142
+ import path54 from "path";
18143
+ import os48 from "os";
18144
18144
  import { confirm as confirm2 } from "@inquirer/prompts";
18145
18145
 
18146
18146
  // src/utils/duration.ts
@@ -19930,13 +19930,182 @@ function registerConfigShowCommand(program2) {
19930
19930
  init_daemon();
19931
19931
  init_config();
19932
19932
  import chalk11 from "chalk";
19933
+ import fs39 from "fs";
19934
+ import path40 from "path";
19935
+ import os35 from "os";
19936
+ import { execSync } from "child_process";
19937
+
19938
+ // src/agent-wiring.ts
19939
+ init_setup();
19933
19940
  import fs38 from "fs";
19934
19941
  import path39 from "path";
19935
19942
  import os34 from "os";
19936
- import { execSync } from "child_process";
19943
+ import * as yaml2 from "yaml";
19944
+ function readJson2(filePath) {
19945
+ if (!fs38.existsSync(filePath)) return null;
19946
+ try {
19947
+ return JSON.parse(fs38.readFileSync(filePath, "utf-8"));
19948
+ } catch {
19949
+ return "invalid";
19950
+ }
19951
+ }
19952
+ function matchersHaveNode9Hook(matchers) {
19953
+ return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
19954
+ }
19955
+ function flatHaveNode9Hook(entries) {
19956
+ return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
19957
+ }
19958
+ function readHookRoot(filePath, format) {
19959
+ if (!fs38.existsSync(filePath)) return "absent";
19960
+ let raw;
19961
+ try {
19962
+ raw = fs38.readFileSync(filePath, "utf-8");
19963
+ } catch {
19964
+ return "absent";
19965
+ }
19966
+ try {
19967
+ const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
19968
+ return parsed?.hooks ?? {};
19969
+ } catch {
19970
+ return "invalid";
19971
+ }
19972
+ }
19973
+ function eventWired(root, ev, format) {
19974
+ const arr = root[ev.key];
19975
+ if (format === "matcher") return matchersHaveNode9Hook(arr);
19976
+ return flatHaveNode9Hook(arr);
19977
+ }
19978
+ function readMcp(filePath) {
19979
+ const parsed = readJson2(filePath);
19980
+ if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
19981
+ const servers = parsed.mcpServers ?? {};
19982
+ const entries = Object.entries(servers);
19983
+ const present = entries.some(([, s]) => s?.command === "node9");
19984
+ const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
19985
+ return { wrapped, present };
19986
+ }
19987
+ var exists = (p) => {
19988
+ try {
19989
+ return fs38.existsSync(p);
19990
+ } catch {
19991
+ return false;
19992
+ }
19993
+ };
19994
+ var ck = (key) => ({ key, kind: "check" });
19995
+ var lg = (key) => ({ key, kind: "log" });
19996
+ var DEFAULT_LABEL_PAD = 11;
19997
+ var hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
19998
+ var AGENT_SPECS = [
19999
+ {
20000
+ id: "claude",
20001
+ label: "Claude Code",
20002
+ setupCommand: "node9 setup claude",
20003
+ hookFile: (h) => path39.join(h, ".claude", "settings.json"),
20004
+ hookFormat: "matcher",
20005
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
20006
+ mcpFile: (h) => path39.join(h, ".claude.json"),
20007
+ present: (h) => exists(path39.join(h, ".claude", "settings.json")) || exists(path39.join(h, ".claude.json"))
20008
+ },
20009
+ {
20010
+ id: "gemini",
20011
+ label: "Gemini CLI",
20012
+ setupCommand: "node9 setup gemini",
20013
+ hookFile: (h) => path39.join(h, ".gemini", "settings.json"),
20014
+ hookFormat: "matcher",
20015
+ hookEvents: [ck("BeforeTool"), lg("AfterTool")],
20016
+ mcpFile: (h) => path39.join(h, ".gemini", "settings.json"),
20017
+ present: (h) => exists(path39.join(h, ".gemini", "settings.json"))
20018
+ },
20019
+ {
20020
+ id: "codex",
20021
+ label: "Codex",
20022
+ setupCommand: "node9 setup codex",
20023
+ hookFile: (h) => path39.join(h, ".codex", "hooks.json"),
20024
+ hookFormat: "matcher",
20025
+ hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
20026
+ present: (h) => exists(path39.join(h, ".codex"))
20027
+ },
20028
+ {
20029
+ id: "antigravity",
20030
+ label: "Antigravity",
20031
+ setupCommand: "node9 setup antigravity",
20032
+ hookFile: (h) => path39.join(h, ".gemini", "config", "hooks.json"),
20033
+ hookFormat: "matcher",
20034
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
20035
+ mcpFile: (h) => path39.join(h, ".gemini", "config", "mcp_config.json"),
20036
+ present: (h) => exists(path39.join(h, ".gemini", "config", "hooks.json")) || exists(path39.join(h, ".gemini", "antigravity-cli")) || exists(path39.join(h, ".gemini", "antigravity-ide"))
20037
+ },
20038
+ {
20039
+ id: "copilot",
20040
+ label: "GitHub Copilot",
20041
+ setupCommand: "node9 setup copilot",
20042
+ hookFile: (h) => path39.join(h, ".copilot", "hooks", "node9.json"),
20043
+ hookFormat: "flat",
20044
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
20045
+ mcpFile: (h) => path39.join(h, ".copilot", "mcp-config.json"),
20046
+ present: (h) => exists(path39.join(h, ".copilot"))
20047
+ },
20048
+ {
20049
+ id: "cursor",
20050
+ label: "Cursor",
20051
+ setupCommand: "node9 setup cursor",
20052
+ // MCP-only — no hook file (see note above).
20053
+ hookFormat: "flat",
20054
+ hookEvents: [],
20055
+ mcpFile: (h) => path39.join(h, ".cursor", "mcp.json"),
20056
+ present: (h) => exists(path39.join(h, ".cursor", "mcp.json"))
20057
+ },
20058
+ {
20059
+ id: "hermes",
20060
+ label: "Hermes Agent",
20061
+ setupCommand: "node9 setup hermes",
20062
+ hookFile: (h) => hermesConfigPath(h),
20063
+ hookFormat: "yaml",
20064
+ hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
20065
+ labelPad: 14,
20066
+ // 'post_tool_call' is wider than the default
20067
+ present: (h) => exists(hermesConfigPath(h))
20068
+ }
20069
+ ];
20070
+ function getAgentWiring(home = os34.homedir()) {
20071
+ const detected = detectAgents(home);
20072
+ return AGENT_SPECS.map((spec) => {
20073
+ const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
20074
+ const primary = spec.hookEvents[0];
20075
+ const rootPresent = root !== "absent" && root !== "invalid";
20076
+ const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
20077
+ const hooks = spec.hookEvents.map((ev) => ({
20078
+ label: hookLabelOf(ev, pad),
20079
+ wired: rootPresent && eventWired(root, ev, spec.hookFormat)
20080
+ }));
20081
+ let wireState;
20082
+ if (root === "absent") wireState = "absent";
20083
+ else if (root === "invalid") wireState = "invalid";
20084
+ else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
20085
+ const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home)) : null;
20086
+ const anyHookWired = hooks.some((h) => h.wired);
20087
+ return {
20088
+ id: spec.id,
20089
+ label: spec.label,
20090
+ setupCommand: spec.setupCommand,
20091
+ installed: detected[spec.id],
20092
+ present: spec.present(home),
20093
+ hooks,
20094
+ wireState,
20095
+ hookLabel: primary ? `${primary.key} hook` : "MCP proxy",
20096
+ settingsPath: spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "",
20097
+ configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
20098
+ mcpServers: mcp ? mcp.wrapped : null,
20099
+ mcpProtected: mcp ? mcp.present : false,
20100
+ isProtected: anyHookWired || (mcp?.present ?? false)
20101
+ };
20102
+ });
20103
+ }
20104
+
20105
+ // src/cli/commands/doctor.ts
19937
20106
  function registerDoctorCommand(program2, version2) {
19938
20107
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(async () => {
19939
- const homeDir2 = os34.homedir();
20108
+ const homeDir2 = os35.homedir();
19940
20109
  let failures = 0;
19941
20110
  function pass(msg) {
19942
20111
  console.log(chalk11.green(" \u2705 ") + msg);
@@ -19985,10 +20154,10 @@ function registerDoctorCommand(program2, version2) {
19985
20154
  );
19986
20155
  }
19987
20156
  section("Configuration");
19988
- const globalConfigPath = path39.join(homeDir2, ".node9", "config.json");
19989
- if (fs38.existsSync(globalConfigPath)) {
20157
+ const globalConfigPath = path40.join(homeDir2, ".node9", "config.json");
20158
+ if (fs39.existsSync(globalConfigPath)) {
19990
20159
  try {
19991
- JSON.parse(fs38.readFileSync(globalConfigPath, "utf-8"));
20160
+ JSON.parse(fs39.readFileSync(globalConfigPath, "utf-8"));
19992
20161
  pass("~/.node9/config.json found and valid");
19993
20162
  } catch {
19994
20163
  fail("~/.node9/config.json is invalid JSON", "Run: node9 init --force");
@@ -19996,10 +20165,10 @@ function registerDoctorCommand(program2, version2) {
19996
20165
  } else {
19997
20166
  warn("~/.node9/config.json not found (using defaults)", "Run: node9 init");
19998
20167
  }
19999
- const projectConfigPath = path39.join(process.cwd(), "node9.config.json");
20000
- if (fs38.existsSync(projectConfigPath)) {
20168
+ const projectConfigPath = path40.join(process.cwd(), "node9.config.json");
20169
+ if (fs39.existsSync(projectConfigPath)) {
20001
20170
  try {
20002
- JSON.parse(fs38.readFileSync(projectConfigPath, "utf-8"));
20171
+ JSON.parse(fs39.readFileSync(projectConfigPath, "utf-8"));
20003
20172
  pass("node9.config.json found and valid (project)");
20004
20173
  } catch {
20005
20174
  fail(
@@ -20008,8 +20177,8 @@ function registerDoctorCommand(program2, version2) {
20008
20177
  );
20009
20178
  }
20010
20179
  }
20011
- const credsPath = path39.join(homeDir2, ".node9", "credentials.json");
20012
- if (fs38.existsSync(credsPath)) {
20180
+ const credsPath = path40.join(homeDir2, ".node9", "credentials.json");
20181
+ if (fs39.existsSync(credsPath)) {
20013
20182
  pass("Cloud credentials found (~/.node9/credentials.json)");
20014
20183
  } else {
20015
20184
  warn(
@@ -20018,62 +20187,25 @@ function registerDoctorCommand(program2, version2) {
20018
20187
  );
20019
20188
  }
20020
20189
  section("Agent Hooks");
20021
- const claudeSettingsPath = path39.join(homeDir2, ".claude", "settings.json");
20022
- if (fs38.existsSync(claudeSettingsPath)) {
20023
- try {
20024
- const cs = JSON.parse(fs38.readFileSync(claudeSettingsPath, "utf-8"));
20025
- const hasHook = cs.hooks?.PreToolUse?.some(
20026
- (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
20027
- );
20028
- if (hasHook) pass("Claude Code \u2014 PreToolUse hook active");
20029
- else
20030
- fail(
20031
- "Claude Code \u2014 hooks file found but node9 hook missing",
20032
- "Run: node9 setup claude"
20033
- );
20034
- } catch {
20035
- fail("Claude Code \u2014 ~/.claude/settings.json is invalid JSON");
20036
- }
20037
- } else {
20038
- warn("Claude Code \u2014 not configured", "Run: node9 setup claude");
20039
- }
20040
- const geminiSettingsPath = path39.join(homeDir2, ".gemini", "settings.json");
20041
- if (fs38.existsSync(geminiSettingsPath)) {
20042
- try {
20043
- const gs = JSON.parse(fs38.readFileSync(geminiSettingsPath, "utf-8"));
20044
- const hasHook = gs.hooks?.BeforeTool?.some(
20045
- (m) => m.hooks.some((h) => h.command?.includes("node9") || h.command?.includes("cli.js"))
20046
- );
20047
- if (hasHook) pass("Gemini CLI \u2014 BeforeTool hook active");
20048
- else
20049
- fail(
20050
- "Gemini CLI \u2014 hooks file found but node9 hook missing",
20051
- "Run: node9 setup gemini"
20052
- );
20053
- } catch {
20054
- fail("Gemini CLI \u2014 ~/.gemini/settings.json is invalid JSON");
20190
+ const notConfigured = [];
20191
+ for (const a of getAgentWiring(homeDir2)) {
20192
+ const anyHookWired = a.hooks.some((h) => h.wired);
20193
+ if (a.isProtected) {
20194
+ pass(`${a.label} \u2014 ${anyHookWired ? `${a.hookLabel} active` : "MCP proxy active"}`);
20195
+ } else if (a.wireState === "invalid") {
20196
+ fail(`${a.label} \u2014 settings file is invalid JSON`, a.settingsPath);
20197
+ } else if (a.wireState === "unwired") {
20198
+ fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
20199
+ } else {
20200
+ notConfigured.push(a.label);
20055
20201
  }
20056
- } else {
20057
- warn("Gemini CLI \u2014 not configured", "Run: node9 setup gemini (skip if not using Gemini)");
20058
20202
  }
20059
- const cursorHooksPath = path39.join(homeDir2, ".cursor", "hooks.json");
20060
- if (fs38.existsSync(cursorHooksPath)) {
20061
- try {
20062
- const cur = JSON.parse(fs38.readFileSync(cursorHooksPath, "utf-8"));
20063
- const hasHook = cur.hooks?.preToolUse?.some(
20064
- (h) => h.command?.includes("node9") || h.command?.includes("cli.js")
20065
- );
20066
- if (hasHook) pass("Cursor \u2014 preToolUse hook active");
20067
- else
20068
- fail(
20069
- "Cursor \u2014 hooks file found but node9 hook missing",
20070
- "Run: node9 setup cursor"
20071
- );
20072
- } catch {
20073
- fail("Cursor \u2014 ~/.cursor/hooks.json is invalid JSON");
20074
- }
20075
- } else {
20076
- warn("Cursor \u2014 not configured", "Run: node9 setup cursor (skip if not using Cursor)");
20203
+ if (notConfigured.length > 0) {
20204
+ console.log(
20205
+ chalk11.gray(
20206
+ ` \xB7 Not configured: ${notConfigured.join(", ")} \u2014 run \`node9 setup <agent>\` if you use one`
20207
+ )
20208
+ );
20077
20209
  }
20078
20210
  section("Daemon (optional)");
20079
20211
  if (isDaemonRunning()) {
@@ -20090,7 +20222,7 @@ function registerDoctorCommand(program2, version2) {
20090
20222
  try {
20091
20223
  const { shipLagBytes: shipLagBytes2, readWatermark: readWatermark2, AUDIT_SHIP_WATERMARK: AUDIT_SHIP_WATERMARK2 } = await Promise.resolve().then(() => (init_audit_shipper(), audit_shipper_exports));
20092
20224
  const cfg = getConfig();
20093
- const creds = fs38.existsSync(path39.join(os34.homedir(), ".node9", "credentials.json"));
20225
+ const creds = fs39.existsSync(path40.join(os35.homedir(), ".node9", "credentials.json"));
20094
20226
  if (!creds) {
20095
20227
  warn("Not logged in \u2014 audit rows stay local", "Run: node9 login <api-key>");
20096
20228
  } else if (!cfg.settings.approvers.cloud) {
@@ -20140,9 +20272,9 @@ function registerDoctorCommand(program2, version2) {
20140
20272
 
20141
20273
  // src/cli/commands/audit.ts
20142
20274
  import chalk12 from "chalk";
20143
- import fs39 from "fs";
20144
- import path40 from "path";
20145
- import os35 from "os";
20275
+ import fs40 from "fs";
20276
+ import path41 from "path";
20277
+ import os36 from "os";
20146
20278
  function formatRelativeTime(timestamp) {
20147
20279
  const diff = Date.now() - new Date(timestamp).getTime();
20148
20280
  const sec = Math.floor(diff / 1e3);
@@ -20155,14 +20287,14 @@ function formatRelativeTime(timestamp) {
20155
20287
  }
20156
20288
  function registerAuditCommand(program2) {
20157
20289
  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) => {
20158
- const logPath = path40.join(os35.homedir(), ".node9", "audit.log");
20159
- if (!fs39.existsSync(logPath)) {
20290
+ const logPath = path41.join(os36.homedir(), ".node9", "audit.log");
20291
+ if (!fs40.existsSync(logPath)) {
20160
20292
  console.log(
20161
20293
  chalk12.yellow("No audit logs found. Run node9 with an agent to generate entries.")
20162
20294
  );
20163
20295
  return;
20164
20296
  }
20165
- const raw = fs39.readFileSync(logPath, "utf-8");
20297
+ const raw = fs40.readFileSync(logPath, "utf-8");
20166
20298
  const lines = raw.split("\n").filter((l) => l.trim() !== "");
20167
20299
  let entries = lines.flatMap((line) => {
20168
20300
  try {
@@ -20221,9 +20353,9 @@ import chalk13 from "chalk";
20221
20353
  init_costSync();
20222
20354
  init_litellm();
20223
20355
  init_cost_codex();
20224
- import fs40 from "fs";
20225
- import os36 from "os";
20226
- import path41 from "path";
20356
+ import fs41 from "fs";
20357
+ import os37 from "os";
20358
+ import path42 from "path";
20227
20359
  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;
20228
20360
  function buildTestTimestamps(allEntries) {
20229
20361
  const testTs = /* @__PURE__ */ new Set();
@@ -20303,8 +20435,8 @@ function getDateRange(period, now) {
20303
20435
  }
20304
20436
  }
20305
20437
  function parseAuditLog(logPath) {
20306
- if (!fs40.existsSync(logPath)) return [];
20307
- const raw = fs40.readFileSync(logPath, "utf-8");
20438
+ if (!fs41.existsSync(logPath)) return [];
20439
+ const raw = fs41.readFileSync(logPath, "utf-8");
20308
20440
  return raw.split("\n").flatMap((line) => {
20309
20441
  if (!line.trim()) return [];
20310
20442
  try {
@@ -20351,25 +20483,25 @@ function freezeClaudeCost(acc) {
20351
20483
  };
20352
20484
  }
20353
20485
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
20354
- const projPath = path41.join(projectsDir, proj);
20486
+ const projPath = path42.join(projectsDir, proj);
20355
20487
  let files;
20356
20488
  try {
20357
- const stat = fs40.statSync(projPath);
20489
+ const stat = fs41.statSync(projPath);
20358
20490
  if (!stat.isDirectory()) return;
20359
- files = fs40.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
20491
+ files = fs41.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
20360
20492
  } catch {
20361
20493
  return;
20362
20494
  }
20363
20495
  const startMs = start.getTime();
20364
20496
  for (const file of files) {
20365
- const filePath = path41.join(projPath, file);
20497
+ const filePath = path42.join(projPath, file);
20366
20498
  try {
20367
- if (fs40.statSync(filePath).mtimeMs < startMs) continue;
20499
+ if (fs41.statSync(filePath).mtimeMs < startMs) continue;
20368
20500
  } catch {
20369
20501
  continue;
20370
20502
  }
20371
20503
  try {
20372
- const raw = fs40.readFileSync(filePath, "utf-8");
20504
+ const raw = fs41.readFileSync(filePath, "utf-8");
20373
20505
  for (const line of raw.split("\n")) {
20374
20506
  if (!line.trim()) continue;
20375
20507
  let entry;
@@ -20419,10 +20551,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
20419
20551
  }
20420
20552
  function loadClaudeCost(start, end, projectsDir) {
20421
20553
  const acc = emptyClaudeCostAccumulator();
20422
- if (!fs40.existsSync(projectsDir)) return freezeClaudeCost(acc);
20554
+ if (!fs41.existsSync(projectsDir)) return freezeClaudeCost(acc);
20423
20555
  let dirs;
20424
20556
  try {
20425
- dirs = fs40.readdirSync(projectsDir);
20557
+ dirs = fs41.readdirSync(projectsDir);
20426
20558
  } catch {
20427
20559
  return freezeClaudeCost(acc);
20428
20560
  }
@@ -20434,7 +20566,7 @@ function loadClaudeCost(start, end, projectsDir) {
20434
20566
  function processCodexCostFile(filePath, start, end, acc) {
20435
20567
  let lines;
20436
20568
  try {
20437
- lines = fs40.readFileSync(filePath, "utf-8").split("\n");
20569
+ lines = fs41.readFileSync(filePath, "utf-8").split("\n");
20438
20570
  } catch {
20439
20571
  return;
20440
20572
  }
@@ -20489,31 +20621,31 @@ function processCodexCostFile(filePath, start, end, acc) {
20489
20621
  }
20490
20622
  function listCodexSessionFiles2(sessionsBase) {
20491
20623
  const jsonlFiles = [];
20492
- if (!fs40.existsSync(sessionsBase)) return jsonlFiles;
20624
+ if (!fs41.existsSync(sessionsBase)) return jsonlFiles;
20493
20625
  try {
20494
- for (const year of fs40.readdirSync(sessionsBase)) {
20495
- const yearPath = path41.join(sessionsBase, year);
20626
+ for (const year of fs41.readdirSync(sessionsBase)) {
20627
+ const yearPath = path42.join(sessionsBase, year);
20496
20628
  try {
20497
- if (!fs40.statSync(yearPath).isDirectory()) continue;
20629
+ if (!fs41.statSync(yearPath).isDirectory()) continue;
20498
20630
  } catch {
20499
20631
  continue;
20500
20632
  }
20501
- for (const month of fs40.readdirSync(yearPath)) {
20502
- const monthPath = path41.join(yearPath, month);
20633
+ for (const month of fs41.readdirSync(yearPath)) {
20634
+ const monthPath = path42.join(yearPath, month);
20503
20635
  try {
20504
- if (!fs40.statSync(monthPath).isDirectory()) continue;
20636
+ if (!fs41.statSync(monthPath).isDirectory()) continue;
20505
20637
  } catch {
20506
20638
  continue;
20507
20639
  }
20508
- for (const day of fs40.readdirSync(monthPath)) {
20509
- const dayPath = path41.join(monthPath, day);
20640
+ for (const day of fs41.readdirSync(monthPath)) {
20641
+ const dayPath = path42.join(monthPath, day);
20510
20642
  try {
20511
- if (!fs40.statSync(dayPath).isDirectory()) continue;
20643
+ if (!fs41.statSync(dayPath).isDirectory()) continue;
20512
20644
  } catch {
20513
20645
  continue;
20514
20646
  }
20515
- for (const file of fs40.readdirSync(dayPath)) {
20516
- if (file.endsWith(".jsonl")) jsonlFiles.push(path41.join(dayPath, file));
20647
+ for (const file of fs41.readdirSync(dayPath)) {
20648
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path42.join(dayPath, file));
20517
20649
  }
20518
20650
  }
20519
20651
  }
@@ -20578,13 +20710,13 @@ function freezeGeminiCost(acc) {
20578
20710
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
20579
20711
  const startMs = start.getTime();
20580
20712
  try {
20581
- if (fs40.statSync(filePath).mtimeMs < startMs) return;
20713
+ if (fs41.statSync(filePath).mtimeMs < startMs) return;
20582
20714
  } catch {
20583
20715
  return;
20584
20716
  }
20585
20717
  let raw;
20586
20718
  try {
20587
- raw = fs40.readFileSync(filePath, "utf-8");
20719
+ raw = fs41.readFileSync(filePath, "utf-8");
20588
20720
  } catch {
20589
20721
  return;
20590
20722
  }
@@ -20633,30 +20765,30 @@ function listGeminiSessionFiles2(geminiTmpDir2) {
20633
20765
  const out = [];
20634
20766
  let dirs;
20635
20767
  try {
20636
- if (!fs40.statSync(geminiTmpDir2).isDirectory()) return out;
20637
- dirs = fs40.readdirSync(geminiTmpDir2);
20768
+ if (!fs41.statSync(geminiTmpDir2).isDirectory()) return out;
20769
+ dirs = fs41.readdirSync(geminiTmpDir2);
20638
20770
  } catch {
20639
20771
  return out;
20640
20772
  }
20641
20773
  for (const proj of dirs) {
20642
- const chatsDir = path41.join(geminiTmpDir2, proj, "chats");
20774
+ const chatsDir = path42.join(geminiTmpDir2, proj, "chats");
20643
20775
  let files;
20644
20776
  try {
20645
- if (!fs40.statSync(chatsDir).isDirectory()) continue;
20646
- files = fs40.readdirSync(chatsDir);
20777
+ if (!fs41.statSync(chatsDir).isDirectory()) continue;
20778
+ files = fs41.readdirSync(chatsDir);
20647
20779
  } catch {
20648
20780
  continue;
20649
20781
  }
20650
20782
  for (const f of files) {
20651
20783
  if (!f.endsWith(".jsonl")) continue;
20652
- out.push({ projectKey: proj, file: path41.join(chatsDir, f) });
20784
+ out.push({ projectKey: proj, file: path42.join(chatsDir, f) });
20653
20785
  }
20654
20786
  }
20655
20787
  return out;
20656
20788
  }
20657
20789
  function loadGeminiCost(start, end, geminiTmpDir2) {
20658
20790
  const acc = emptyGeminiAccumulator();
20659
- if (!fs40.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
20791
+ if (!fs41.existsSync(geminiTmpDir2)) return freezeGeminiCost(acc);
20660
20792
  for (const { projectKey, file } of listGeminiSessionFiles2(geminiTmpDir2)) {
20661
20793
  processGeminiCostFile(file, projectKey, start, end, acc);
20662
20794
  }
@@ -20664,11 +20796,11 @@ function loadGeminiCost(start, end, geminiTmpDir2) {
20664
20796
  }
20665
20797
  function aggregateReportFromAudit(period, opts = {}) {
20666
20798
  const now = opts.now ?? /* @__PURE__ */ new Date();
20667
- const auditLogPath = opts.auditLogPath ?? path41.join(os36.homedir(), ".node9", "audit.log");
20668
- const claudeProjectsDir = opts.claudeProjectsDir ?? path41.join(os36.homedir(), ".claude", "projects");
20669
- const codexSessionsDir2 = opts.codexSessionsDir ?? path41.join(os36.homedir(), ".codex", "sessions");
20670
- const geminiTmpDir2 = opts.geminiTmpDir ?? path41.join(os36.homedir(), ".gemini", "tmp");
20671
- const hasAuditFile = fs40.existsSync(auditLogPath);
20799
+ const auditLogPath = opts.auditLogPath ?? path42.join(os37.homedir(), ".node9", "audit.log");
20800
+ const claudeProjectsDir = opts.claudeProjectsDir ?? path42.join(os37.homedir(), ".claude", "projects");
20801
+ const codexSessionsDir2 = opts.codexSessionsDir ?? path42.join(os37.homedir(), ".codex", "sessions");
20802
+ const geminiTmpDir2 = opts.geminiTmpDir ?? path42.join(os37.homedir(), ".gemini", "tmp");
20803
+ const hasAuditFile = fs41.existsSync(auditLogPath);
20672
20804
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath);
20673
20805
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
20674
20806
  const { start, end } = getDateRange(period, now);
@@ -21365,52 +21497,10 @@ function registerDaemonCommand(program2) {
21365
21497
  // src/cli/commands/status.ts
21366
21498
  init_core();
21367
21499
  init_daemon();
21368
- init_setup();
21369
21500
  import chalk15 from "chalk";
21370
- import fs41 from "fs";
21371
- import path42 from "path";
21372
- import os37 from "os";
21373
- import * as yaml2 from "yaml";
21374
- function readHermesHooks(configPath) {
21375
- if (!fs41.existsSync(configPath)) return null;
21376
- let raw;
21377
- try {
21378
- raw = fs41.readFileSync(configPath, "utf-8");
21379
- } catch {
21380
- return null;
21381
- }
21382
- try {
21383
- const cfg = yaml2.parse(raw);
21384
- const has = (event) => (cfg?.hooks?.[event] ?? []).some(
21385
- (e) => typeof e?.command === "string" && isNode9Hook(e.command)
21386
- );
21387
- return { pre: has("pre_tool_call"), post: has("post_tool_call") };
21388
- } catch {
21389
- console.error(
21390
- chalk15.yellow(
21391
- ` \u26A0\uFE0F Hermes config.yaml at ${configPath} is not valid YAML \u2014 showing as unwired.`
21392
- )
21393
- );
21394
- return { pre: false, post: false };
21395
- }
21396
- }
21397
- function readJson2(filePath) {
21398
- try {
21399
- if (fs41.existsSync(filePath)) return JSON.parse(fs41.readFileSync(filePath, "utf-8"));
21400
- } catch {
21401
- }
21402
- return null;
21403
- }
21404
- function matchersHaveNode9Hook(matchers) {
21405
- return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
21406
- }
21407
- function flatHaveNode9Hook(entries) {
21408
- return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
21409
- }
21410
- function wrappedMcpServers(servers) {
21411
- if (!servers) return [];
21412
- return Object.entries(servers).filter(([, s]) => s.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
21413
- }
21501
+ import fs42 from "fs";
21502
+ import path43 from "path";
21503
+ import os38 from "os";
21414
21504
  function printAgentSection(label, hookPairs, wrapped) {
21415
21505
  console.log(chalk15.bold(` ${label}`));
21416
21506
  for (const { name, present } of hookPairs) {
@@ -21464,115 +21554,36 @@ function registerStatusCommand(program2) {
21464
21554
  console.log("");
21465
21555
  const modeLabel = settings.mode === "audit" ? chalk15.blue("audit") : settings.mode === "strict" ? chalk15.red("strict") : chalk15.white("standard");
21466
21556
  console.log(` Mode: ${modeLabel}`);
21467
- const projectConfig = path42.join(process.cwd(), "node9.config.json");
21468
- const globalConfig = path42.join(os37.homedir(), ".node9", "config.json");
21557
+ const projectConfig = path43.join(process.cwd(), "node9.config.json");
21558
+ const globalConfig = path43.join(os38.homedir(), ".node9", "config.json");
21469
21559
  console.log(
21470
- ` Local: ${fs41.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
21560
+ ` Local: ${fs42.existsSync(projectConfig) ? chalk15.green("Active (node9.config.json)") : chalk15.gray("Not present")}`
21471
21561
  );
21472
21562
  console.log(
21473
- ` Global: ${fs41.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
21563
+ ` Global: ${fs42.existsSync(globalConfig) ? chalk15.green("Active (~/.node9/config.json)") : chalk15.gray("Not present")}`
21474
21564
  );
21475
21565
  if (mergedConfig.policy.sandboxPaths.length > 0) {
21476
21566
  console.log(
21477
21567
  ` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
21478
21568
  );
21479
21569
  }
21480
- const homeDir2 = os37.homedir();
21481
- const claudeSettings = readJson2(
21482
- path42.join(homeDir2, ".claude", "settings.json")
21483
- );
21484
- const claudeConfig = readJson2(path42.join(homeDir2, ".claude.json"));
21485
- const geminiSettings = readJson2(
21486
- path42.join(homeDir2, ".gemini", "settings.json")
21487
- );
21488
- const cursorConfig = readJson2(path42.join(homeDir2, ".cursor", "mcp.json"));
21489
- const antigravityHooks = readJson2(
21490
- path42.join(homeDir2, ".gemini", "config", "hooks.json")
21491
- );
21492
- const antigravityMcp = readJson2(
21493
- path42.join(homeDir2, ".gemini", "config", "mcp_config.json")
21494
- );
21495
- const antigravityPresent = antigravityHooks !== null || fs41.existsSync(path42.join(homeDir2, ".gemini", "antigravity-cli")) || fs41.existsSync(path42.join(homeDir2, ".gemini", "antigravity-ide"));
21496
- const copilotHooks = readJson2(
21497
- path42.join(homeDir2, ".copilot", "hooks", "node9.json")
21498
- );
21499
- const copilotMcp = readJson2(
21500
- path42.join(homeDir2, ".copilot", "mcp-config.json")
21501
- );
21502
- const copilotPresent = fs41.existsSync(path42.join(homeDir2, ".copilot"));
21503
- const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
21504
- const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
21505
- if (agentFound) {
21570
+ const wiring = getAgentWiring(os38.homedir()).filter((a) => a.present);
21571
+ if (wiring.length > 0) {
21506
21572
  console.log("");
21507
21573
  console.log(chalk15.bold(" Agent Wiring:"));
21508
21574
  console.log("");
21509
- if (claudeSettings || claudeConfig) {
21510
- const preHook = matchersHaveNode9Hook(claudeSettings?.hooks?.PreToolUse);
21511
- const postHook = matchersHaveNode9Hook(claudeSettings?.hooks?.PostToolUse);
21512
- printAgentSection(
21513
- "Claude Code",
21514
- [
21515
- { name: "PreToolUse (node9 check)", present: preHook },
21516
- { name: "PostToolUse (node9 log)", present: postHook }
21517
- ],
21518
- wrappedMcpServers(claudeConfig?.mcpServers)
21519
- );
21520
- console.log("");
21521
- }
21522
- if (geminiSettings) {
21523
- const beforeHook = matchersHaveNode9Hook(geminiSettings.hooks?.BeforeTool);
21524
- const afterHook = matchersHaveNode9Hook(geminiSettings.hooks?.AfterTool);
21525
- printAgentSection(
21526
- "Gemini CLI",
21527
- [
21528
- { name: "BeforeTool (node9 check)", present: beforeHook },
21529
- { name: "AfterTool (node9 log)", present: afterHook }
21530
- ],
21531
- wrappedMcpServers(geminiSettings.mcpServers)
21532
- );
21533
- console.log("");
21534
- }
21535
- if (antigravityPresent) {
21536
- const preHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PreToolUse);
21537
- const postHook = matchersHaveNode9Hook(antigravityHooks?.hooks?.PostToolUse);
21538
- printAgentSection(
21539
- "Antigravity",
21540
- [
21541
- { name: "PreToolUse (node9 check)", present: preHook },
21542
- { name: "PostToolUse (node9 log)", present: postHook }
21543
- ],
21544
- wrappedMcpServers(antigravityMcp?.mcpServers)
21545
- );
21546
- console.log("");
21547
- }
21548
- if (copilotPresent) {
21549
- const preHook = flatHaveNode9Hook(copilotHooks?.hooks?.PreToolUse);
21550
- const postHook = flatHaveNode9Hook(copilotHooks?.hooks?.PostToolUse);
21551
- const promptHook = flatHaveNode9Hook(copilotHooks?.hooks?.UserPromptSubmit);
21552
- printAgentSection(
21553
- "GitHub Copilot",
21554
- [
21555
- { name: "PreToolUse (node9 check)", present: preHook },
21556
- { name: "PostToolUse (node9 log)", present: postHook },
21557
- { name: "UserPromptSubmit (node9 check)", present: promptHook }
21558
- ],
21559
- wrappedMcpServers(copilotMcp?.mcpServers)
21560
- );
21561
- console.log("");
21562
- }
21563
- if (cursorConfig) {
21564
- printAgentSection("Cursor", [], wrappedMcpServers(cursorConfig.mcpServers));
21565
- console.log("");
21566
- }
21567
- if (hermesHooks) {
21575
+ for (const a of wiring) {
21576
+ if (a.wireState === "invalid") {
21577
+ console.error(
21578
+ chalk15.yellow(
21579
+ ` \u26A0\uFE0F ${a.label} config at ${a.settingsPath} is not valid ${a.configFormat} \u2014 showing as unwired.`
21580
+ )
21581
+ );
21582
+ }
21568
21583
  printAgentSection(
21569
- "Hermes Agent",
21570
- [
21571
- { name: "pre_tool_call (node9 check)", present: hermesHooks.pre },
21572
- { name: "post_tool_call (node9 log)", present: hermesHooks.post }
21573
- ],
21574
- null
21575
- // Hermes has no MCP surface
21584
+ a.label,
21585
+ a.hooks.map((h) => ({ name: h.label, present: h.wired })),
21586
+ a.mcpServers
21576
21587
  );
21577
21588
  console.log("");
21578
21589
  }
@@ -21595,9 +21606,9 @@ init_setup();
21595
21606
  init_shields();
21596
21607
  init_service();
21597
21608
  import chalk16 from "chalk";
21598
- import fs42 from "fs";
21599
- import path43 from "path";
21600
- import os38 from "os";
21609
+ import fs43 from "fs";
21610
+ import path44 from "path";
21611
+ import os39 from "os";
21601
21612
  import https4 from "https";
21602
21613
  var DEFAULT_SHIELDS = ["bash-safe", "filesystem", "project-jail"];
21603
21614
  function buildTelemetryPayload(agents, firstInstall) {
@@ -21683,16 +21694,16 @@ function registerInitCommand(program2) {
21683
21694
  }
21684
21695
  console.log("");
21685
21696
  }
21686
- const configPath = path43.join(os38.homedir(), ".node9", "config.json");
21687
- const isFirstInstall = !fs42.existsSync(configPath);
21688
- if (fs42.existsSync(configPath) && !options.force) {
21697
+ const configPath = path44.join(os39.homedir(), ".node9", "config.json");
21698
+ const isFirstInstall = !fs43.existsSync(configPath);
21699
+ if (fs43.existsSync(configPath) && !options.force) {
21689
21700
  try {
21690
- const existing = JSON.parse(fs42.readFileSync(configPath, "utf-8"));
21701
+ const existing = JSON.parse(fs43.readFileSync(configPath, "utf-8"));
21691
21702
  const settings = existing.settings ?? {};
21692
21703
  if (settings.mode !== chosenMode) {
21693
21704
  settings.mode = chosenMode;
21694
21705
  existing.settings = settings;
21695
- fs42.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
21706
+ fs43.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
21696
21707
  console.log(chalk16.green(`\u2705 Mode updated: ${chosenMode}`));
21697
21708
  } else {
21698
21709
  console.log(chalk16.blue(`\u2139\uFE0F Config already exists: ${configPath}`));
@@ -21705,9 +21716,9 @@ function registerInitCommand(program2) {
21705
21716
  ...DEFAULT_CONFIG,
21706
21717
  settings: { ...DEFAULT_CONFIG.settings, mode: chosenMode }
21707
21718
  };
21708
- const dir = path43.dirname(configPath);
21709
- if (!fs42.existsSync(dir)) fs42.mkdirSync(dir, { recursive: true });
21710
- fs42.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
21719
+ const dir = path44.dirname(configPath);
21720
+ if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
21721
+ fs43.writeFileSync(configPath, JSON.stringify(configToSave, null, 2) + "\n");
21711
21722
  console.log(chalk16.green(`\u2705 Config created: ${configPath}`));
21712
21723
  console.log(chalk16.gray(` Mode: ${chosenMode}`));
21713
21724
  }
@@ -21812,7 +21823,7 @@ function registerInitCommand(program2) {
21812
21823
  }
21813
21824
 
21814
21825
  // src/cli/commands/undo.ts
21815
- import path44 from "path";
21826
+ import path45 from "path";
21816
21827
  import chalk18 from "chalk";
21817
21828
 
21818
21829
  // src/tui/undo-navigator.ts
@@ -21971,7 +21982,7 @@ function findMatchingCwd(startDir, history) {
21971
21982
  let dir = startDir;
21972
21983
  while (true) {
21973
21984
  if (cwds.has(dir)) return dir;
21974
- const parent = path44.dirname(dir);
21985
+ const parent = path45.dirname(dir);
21975
21986
  if (parent === dir) return null;
21976
21987
  dir = parent;
21977
21988
  }
@@ -22606,9 +22617,9 @@ function registerMcpGatewayCommand(program2) {
22606
22617
 
22607
22618
  // src/mcp-server/index.ts
22608
22619
  import readline5 from "readline";
22609
- import fs43 from "fs";
22610
- import os39 from "os";
22611
- import path45 from "path";
22620
+ import fs44 from "fs";
22621
+ import os40 from "os";
22622
+ import path46 from "path";
22612
22623
  import { spawnSync as spawnSync4 } from "child_process";
22613
22624
  init_core();
22614
22625
  init_daemon();
@@ -22859,13 +22870,13 @@ function handleStatus() {
22859
22870
  lines.push(`Active shields: ${activeShields.length > 0 ? activeShields.join(", ") : "none"}`);
22860
22871
  lines.push(`Smart rules: ${config.policy.smartRules.length} loaded`);
22861
22872
  lines.push(`DLP: ${config.policy.dlp?.enabled !== false ? "enabled" : "disabled"}`);
22862
- const projectConfig = path45.join(process.cwd(), "node9.config.json");
22863
- const globalConfig = path45.join(os39.homedir(), ".node9", "config.json");
22873
+ const projectConfig = path46.join(process.cwd(), "node9.config.json");
22874
+ const globalConfig = path46.join(os40.homedir(), ".node9", "config.json");
22864
22875
  lines.push(
22865
- `Project config (node9.config.json): ${fs43.existsSync(projectConfig) ? "present" : "not found"}`
22876
+ `Project config (node9.config.json): ${fs44.existsSync(projectConfig) ? "present" : "not found"}`
22866
22877
  );
22867
22878
  lines.push(
22868
- `Global config (~/.node9/config.json): ${fs43.existsSync(globalConfig) ? "present" : "not found"}`
22879
+ `Global config (~/.node9/config.json): ${fs44.existsSync(globalConfig) ? "present" : "not found"}`
22869
22880
  );
22870
22881
  return lines.join("\n");
22871
22882
  }
@@ -22939,21 +22950,21 @@ function handleShieldDisable(args) {
22939
22950
  writeActiveShields(active.filter((s) => s !== name));
22940
22951
  return `Shield "${name}" disabled.`;
22941
22952
  }
22942
- var GLOBAL_CONFIG_PATH = path45.join(os39.homedir(), ".node9", "config.json");
22953
+ var GLOBAL_CONFIG_PATH = path46.join(os40.homedir(), ".node9", "config.json");
22943
22954
  var APPROVER_CHANNELS = ["native", "browser", "cloud", "terminal"];
22944
22955
  function readGlobalConfigRaw() {
22945
22956
  try {
22946
- if (fs43.existsSync(GLOBAL_CONFIG_PATH)) {
22947
- return JSON.parse(fs43.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
22957
+ if (fs44.existsSync(GLOBAL_CONFIG_PATH)) {
22958
+ return JSON.parse(fs44.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
22948
22959
  }
22949
22960
  } catch {
22950
22961
  }
22951
22962
  return {};
22952
22963
  }
22953
22964
  function writeGlobalConfigRaw(data) {
22954
- const dir = path45.dirname(GLOBAL_CONFIG_PATH);
22955
- if (!fs43.existsSync(dir)) fs43.mkdirSync(dir, { recursive: true });
22956
- fs43.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
22965
+ const dir = path46.dirname(GLOBAL_CONFIG_PATH);
22966
+ if (!fs44.existsSync(dir)) fs44.mkdirSync(dir, { recursive: true });
22967
+ fs44.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(data, null, 2) + "\n");
22957
22968
  }
22958
22969
  function handleApproverList() {
22959
22970
  const config = getConfig();
@@ -22997,9 +23008,9 @@ function handleApproverSet(args) {
22997
23008
  function handleAuditGet(args) {
22998
23009
  const limit = Math.min(typeof args.limit === "number" ? args.limit : 20, 100);
22999
23010
  const filter = typeof args.filter === "string" && args.filter !== "all" ? args.filter : null;
23000
- const auditPath = path45.join(os39.homedir(), ".node9", "audit.log");
23001
- if (!fs43.existsSync(auditPath)) return "No audit log found.";
23002
- const rawLines = fs43.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
23011
+ const auditPath = path46.join(os40.homedir(), ".node9", "audit.log");
23012
+ if (!fs44.existsSync(auditPath)) return "No audit log found.";
23013
+ const rawLines = fs44.readFileSync(auditPath, "utf-8").trim().split("\n").filter(Boolean);
23003
23014
  const parsed = [];
23004
23015
  for (const line of rawLines) {
23005
23016
  try {
@@ -23334,7 +23345,7 @@ function registerTrustCommand(program2) {
23334
23345
  // src/cli/commands/mcp-pin.ts
23335
23346
  init_mcp_pin();
23336
23347
  import chalk21 from "chalk";
23337
- import fs44 from "fs";
23348
+ import fs45 from "fs";
23338
23349
  function registerMcpPinCommand(program2) {
23339
23350
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
23340
23351
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
@@ -23345,7 +23356,7 @@ function registerMcpPinCommand(program2) {
23345
23356
  let repoCorrupt = false;
23346
23357
  if (found.source === "repo") {
23347
23358
  try {
23348
- const raw = fs44.readFileSync(found.path, "utf-8");
23359
+ const raw = fs45.readFileSync(found.path, "utf-8");
23349
23360
  const parsed = JSON.parse(raw);
23350
23361
  repoEntries = parsed.servers ?? {};
23351
23362
  } catch {
@@ -23662,9 +23673,9 @@ init_litellm();
23662
23673
  init_cost_gemini();
23663
23674
  init_cost_codex();
23664
23675
  import chalk24 from "chalk";
23665
- import fs45 from "fs";
23666
- import path46 from "path";
23667
- import os40 from "os";
23676
+ import fs46 from "fs";
23677
+ import path47 from "path";
23678
+ import os41 from "os";
23668
23679
  function modelPrice(model) {
23669
23680
  const t = pricingFor(model);
23670
23681
  if (!t) return null;
@@ -23681,10 +23692,10 @@ function encodeProjectPath(projectPath) {
23681
23692
  }
23682
23693
  function sessionJsonlPath(projectPath, sessionId) {
23683
23694
  const encoded = encodeProjectPath(projectPath);
23684
- return path46.join(os40.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
23695
+ return path47.join(os41.homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
23685
23696
  }
23686
23697
  function projectLabel(projectPath) {
23687
- return projectPath.replace(os40.homedir(), "~");
23698
+ return projectPath.replace(os41.homedir(), "~");
23688
23699
  }
23689
23700
  function parseHistoryLines(lines) {
23690
23701
  const entries = [];
@@ -23753,10 +23764,10 @@ function parseSessionLines(lines) {
23753
23764
  return { toolCalls, costUSD, hasSnapshot, modifiedFiles };
23754
23765
  }
23755
23766
  function loadAuditEntries(auditPath) {
23756
- const aPath = auditPath ?? path46.join(os40.homedir(), ".node9", "audit.log");
23767
+ const aPath = auditPath ?? path47.join(os41.homedir(), ".node9", "audit.log");
23757
23768
  let raw;
23758
23769
  try {
23759
- raw = fs45.readFileSync(aPath, "utf-8");
23770
+ raw = fs46.readFileSync(aPath, "utf-8");
23760
23771
  } catch {
23761
23772
  return [];
23762
23773
  }
@@ -23792,8 +23803,8 @@ function auditEntriesInWindow(entries, windowStart, windowEnd) {
23792
23803
  return result;
23793
23804
  }
23794
23805
  function buildGeminiSessions(days, allAuditEntries) {
23795
- const tmpDir = path46.join(os40.homedir(), ".gemini", "tmp");
23796
- if (!fs45.existsSync(tmpDir)) return [];
23806
+ const tmpDir = path47.join(os41.homedir(), ".gemini", "tmp");
23807
+ if (!fs46.existsSync(tmpDir)) return [];
23797
23808
  const cutoff = days !== null ? (() => {
23798
23809
  const d = /* @__PURE__ */ new Date();
23799
23810
  d.setDate(d.getDate() - days);
@@ -23802,35 +23813,35 @@ function buildGeminiSessions(days, allAuditEntries) {
23802
23813
  })() : null;
23803
23814
  let slugDirs;
23804
23815
  try {
23805
- slugDirs = fs45.readdirSync(tmpDir);
23816
+ slugDirs = fs46.readdirSync(tmpDir);
23806
23817
  } catch {
23807
23818
  return [];
23808
23819
  }
23809
23820
  const summaries = [];
23810
23821
  for (const slug of slugDirs) {
23811
- const slugPath = path46.join(tmpDir, slug);
23822
+ const slugPath = path47.join(tmpDir, slug);
23812
23823
  try {
23813
- if (!fs45.statSync(slugPath).isDirectory()) continue;
23824
+ if (!fs46.statSync(slugPath).isDirectory()) continue;
23814
23825
  } catch {
23815
23826
  continue;
23816
23827
  }
23817
- let projectRoot = path46.join(os40.homedir(), slug);
23828
+ let projectRoot = path47.join(os41.homedir(), slug);
23818
23829
  try {
23819
- projectRoot = fs45.readFileSync(path46.join(slugPath, ".project_root"), "utf-8").trim();
23830
+ projectRoot = fs46.readFileSync(path47.join(slugPath, ".project_root"), "utf-8").trim();
23820
23831
  } catch {
23821
23832
  }
23822
- const chatsDir = path46.join(slugPath, "chats");
23823
- if (!fs45.existsSync(chatsDir)) continue;
23833
+ const chatsDir = path47.join(slugPath, "chats");
23834
+ if (!fs46.existsSync(chatsDir)) continue;
23824
23835
  let chatFiles;
23825
23836
  try {
23826
- chatFiles = fs45.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
23837
+ chatFiles = fs46.readdirSync(chatsDir).filter((f) => f.endsWith(".json"));
23827
23838
  } catch {
23828
23839
  continue;
23829
23840
  }
23830
23841
  for (const chatFile of chatFiles) {
23831
23842
  let raw;
23832
23843
  try {
23833
- raw = fs45.readFileSync(path46.join(chatsDir, chatFile), "utf-8");
23844
+ raw = fs46.readFileSync(path47.join(chatsDir, chatFile), "utf-8");
23834
23845
  } catch {
23835
23846
  continue;
23836
23847
  }
@@ -23910,8 +23921,8 @@ function buildGeminiSessions(days, allAuditEntries) {
23910
23921
  return summaries;
23911
23922
  }
23912
23923
  function buildCodexSessions(days, allAuditEntries) {
23913
- const sessionsBase = path46.join(os40.homedir(), ".codex", "sessions");
23914
- if (!fs45.existsSync(sessionsBase)) return [];
23924
+ const sessionsBase = path47.join(os41.homedir(), ".codex", "sessions");
23925
+ if (!fs46.existsSync(sessionsBase)) return [];
23915
23926
  const cutoff = days !== null ? (() => {
23916
23927
  const d = /* @__PURE__ */ new Date();
23917
23928
  d.setDate(d.getDate() - days);
@@ -23920,29 +23931,29 @@ function buildCodexSessions(days, allAuditEntries) {
23920
23931
  })() : null;
23921
23932
  const jsonlFiles = [];
23922
23933
  try {
23923
- for (const year of fs45.readdirSync(sessionsBase)) {
23924
- const yearPath = path46.join(sessionsBase, year);
23934
+ for (const year of fs46.readdirSync(sessionsBase)) {
23935
+ const yearPath = path47.join(sessionsBase, year);
23925
23936
  try {
23926
- if (!fs45.statSync(yearPath).isDirectory()) continue;
23937
+ if (!fs46.statSync(yearPath).isDirectory()) continue;
23927
23938
  } catch {
23928
23939
  continue;
23929
23940
  }
23930
- for (const month of fs45.readdirSync(yearPath)) {
23931
- const monthPath = path46.join(yearPath, month);
23941
+ for (const month of fs46.readdirSync(yearPath)) {
23942
+ const monthPath = path47.join(yearPath, month);
23932
23943
  try {
23933
- if (!fs45.statSync(monthPath).isDirectory()) continue;
23944
+ if (!fs46.statSync(monthPath).isDirectory()) continue;
23934
23945
  } catch {
23935
23946
  continue;
23936
23947
  }
23937
- for (const day of fs45.readdirSync(monthPath)) {
23938
- const dayPath = path46.join(monthPath, day);
23948
+ for (const day of fs46.readdirSync(monthPath)) {
23949
+ const dayPath = path47.join(monthPath, day);
23939
23950
  try {
23940
- if (!fs45.statSync(dayPath).isDirectory()) continue;
23951
+ if (!fs46.statSync(dayPath).isDirectory()) continue;
23941
23952
  } catch {
23942
23953
  continue;
23943
23954
  }
23944
- for (const file of fs45.readdirSync(dayPath)) {
23945
- if (file.endsWith(".jsonl")) jsonlFiles.push(path46.join(dayPath, file));
23955
+ for (const file of fs46.readdirSync(dayPath)) {
23956
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path47.join(dayPath, file));
23946
23957
  }
23947
23958
  }
23948
23959
  }
@@ -23954,7 +23965,7 @@ function buildCodexSessions(days, allAuditEntries) {
23954
23965
  for (const filePath of jsonlFiles) {
23955
23966
  let lines;
23956
23967
  try {
23957
- lines = fs45.readFileSync(filePath, "utf-8").split("\n");
23968
+ lines = fs46.readFileSync(filePath, "utf-8").split("\n");
23958
23969
  } catch {
23959
23970
  continue;
23960
23971
  }
@@ -24040,10 +24051,10 @@ function buildCodexSessions(days, allAuditEntries) {
24040
24051
  return summaries;
24041
24052
  }
24042
24053
  function buildSessions(days, historyPath) {
24043
- const hPath = historyPath ?? path46.join(os40.homedir(), ".claude", "history.jsonl");
24054
+ const hPath = historyPath ?? path47.join(os41.homedir(), ".claude", "history.jsonl");
24044
24055
  let historyRaw = "";
24045
24056
  try {
24046
- historyRaw = fs45.readFileSync(hPath, "utf-8");
24057
+ historyRaw = fs46.readFileSync(hPath, "utf-8");
24047
24058
  } catch {
24048
24059
  }
24049
24060
  const cutoff = days !== null ? (() => {
@@ -24067,7 +24078,7 @@ function buildSessions(days, historyPath) {
24067
24078
  const jsonlFile = sessionJsonlPath(entry.project, entry.sessionId);
24068
24079
  let sessionLines = [];
24069
24080
  try {
24070
- sessionLines = fs45.readFileSync(jsonlFile, "utf-8").split("\n");
24081
+ sessionLines = fs46.readFileSync(jsonlFile, "utf-8").split("\n");
24071
24082
  } catch {
24072
24083
  }
24073
24084
  const { toolCalls, costUSD, hasSnapshot, modifiedFiles } = parseSessionLines(sessionLines);
@@ -24367,12 +24378,12 @@ function registerSessionsCommand(program2) {
24367
24378
 
24368
24379
  // src/cli/commands/skill-pin.ts
24369
24380
  import chalk25 from "chalk";
24370
- import fs46 from "fs";
24371
- import os41 from "os";
24372
- import path47 from "path";
24381
+ import fs47 from "fs";
24382
+ import os42 from "os";
24383
+ import path48 from "path";
24373
24384
  function wipeSkillSessions() {
24374
24385
  try {
24375
- fs46.rmSync(path47.join(os41.homedir(), ".node9", "skill-sessions"), {
24386
+ fs47.rmSync(path48.join(os42.homedir(), ".node9", "skill-sessions"), {
24376
24387
  recursive: true,
24377
24388
  force: true
24378
24389
  });
@@ -24454,15 +24465,15 @@ function registerSkillPinCommand(program2) {
24454
24465
  }
24455
24466
 
24456
24467
  // src/cli/commands/decisions.ts
24457
- import fs47 from "fs";
24458
- import os42 from "os";
24459
- import path48 from "path";
24468
+ import fs48 from "fs";
24469
+ import os43 from "os";
24470
+ import path49 from "path";
24460
24471
  import chalk26 from "chalk";
24461
- var DECISIONS_FILE2 = path48.join(os42.homedir(), ".node9", "decisions.json");
24472
+ var DECISIONS_FILE2 = path49.join(os43.homedir(), ".node9", "decisions.json");
24462
24473
  function readDecisions() {
24463
24474
  try {
24464
- if (!fs47.existsSync(DECISIONS_FILE2)) return {};
24465
- const raw = fs47.readFileSync(DECISIONS_FILE2, "utf-8");
24475
+ if (!fs48.existsSync(DECISIONS_FILE2)) return {};
24476
+ const raw = fs48.readFileSync(DECISIONS_FILE2, "utf-8");
24466
24477
  const parsed = JSON.parse(raw);
24467
24478
  const out = {};
24468
24479
  for (const [k, v] of Object.entries(parsed)) {
@@ -24474,11 +24485,11 @@ function readDecisions() {
24474
24485
  }
24475
24486
  }
24476
24487
  function writeDecisions(d) {
24477
- const dir = path48.dirname(DECISIONS_FILE2);
24478
- if (!fs47.existsSync(dir)) fs47.mkdirSync(dir, { recursive: true });
24488
+ const dir = path49.dirname(DECISIONS_FILE2);
24489
+ if (!fs48.existsSync(dir)) fs48.mkdirSync(dir, { recursive: true });
24479
24490
  const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
24480
- fs47.writeFileSync(tmp, JSON.stringify(d, null, 2));
24481
- fs47.renameSync(tmp, DECISIONS_FILE2);
24491
+ fs48.writeFileSync(tmp, JSON.stringify(d, null, 2));
24492
+ fs48.renameSync(tmp, DECISIONS_FILE2);
24482
24493
  }
24483
24494
  function registerDecisionsCommand(program2) {
24484
24495
  const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
@@ -24535,18 +24546,18 @@ Persistent decisions (${entries.length})
24535
24546
 
24536
24547
  // src/cli/commands/dlp.ts
24537
24548
  import chalk27 from "chalk";
24538
- import fs48 from "fs";
24539
- import path49 from "path";
24540
- import os43 from "os";
24541
- var AUDIT_LOG = path49.join(os43.homedir(), ".node9", "audit.log");
24542
- var RESOLVED_FILE = path49.join(os43.homedir(), ".node9", "dlp-resolved.json");
24549
+ import fs49 from "fs";
24550
+ import path50 from "path";
24551
+ import os44 from "os";
24552
+ var AUDIT_LOG = path50.join(os44.homedir(), ".node9", "audit.log");
24553
+ var RESOLVED_FILE = path50.join(os44.homedir(), ".node9", "dlp-resolved.json");
24543
24554
  var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
24544
24555
  function stripAnsi(s) {
24545
24556
  return s.replace(ANSI_RE, "");
24546
24557
  }
24547
24558
  function loadResolved() {
24548
24559
  try {
24549
- const raw = JSON.parse(fs48.readFileSync(RESOLVED_FILE, "utf-8"));
24560
+ const raw = JSON.parse(fs49.readFileSync(RESOLVED_FILE, "utf-8"));
24550
24561
  return new Set(raw);
24551
24562
  } catch {
24552
24563
  return /* @__PURE__ */ new Set();
@@ -24554,13 +24565,13 @@ function loadResolved() {
24554
24565
  }
24555
24566
  function saveResolved(resolved) {
24556
24567
  try {
24557
- fs48.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
24568
+ fs49.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
24558
24569
  } catch {
24559
24570
  }
24560
24571
  }
24561
24572
  function loadDlpFindings() {
24562
- if (!fs48.existsSync(AUDIT_LOG)) return [];
24563
- return fs48.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
24573
+ if (!fs49.existsSync(AUDIT_LOG)) return [];
24574
+ return fs49.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
24564
24575
  if (!line.trim()) return [];
24565
24576
  try {
24566
24577
  const e = JSON.parse(line);
@@ -24659,14 +24670,14 @@ function registerDlpCommand(program2) {
24659
24670
  // src/cli/commands/mask.ts
24660
24671
  init_dlp();
24661
24672
  import chalk28 from "chalk";
24662
- import fs49 from "fs";
24663
- import path50 from "path";
24664
- import os44 from "os";
24673
+ import fs50 from "fs";
24674
+ import path51 from "path";
24675
+ import os45 from "os";
24665
24676
  function findJsonlFiles(dir) {
24666
24677
  const results = [];
24667
- if (!fs49.existsSync(dir)) return results;
24668
- for (const entry of fs49.readdirSync(dir, { withFileTypes: true })) {
24669
- const full = path50.join(dir, entry.name);
24678
+ if (!fs50.existsSync(dir)) return results;
24679
+ for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
24680
+ const full = path51.join(dir, entry.name);
24670
24681
  if (entry.isDirectory()) results.push(...findJsonlFiles(full));
24671
24682
  else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
24672
24683
  }
@@ -24709,7 +24720,7 @@ function redactJson(obj) {
24709
24720
  function processFile(filePath, dryRun) {
24710
24721
  let raw;
24711
24722
  try {
24712
- raw = fs49.readFileSync(filePath, "utf-8");
24723
+ raw = fs50.readFileSync(filePath, "utf-8");
24713
24724
  } catch {
24714
24725
  return { redactedLines: 0, patterns: [] };
24715
24726
  }
@@ -24741,14 +24752,14 @@ function processFile(filePath, dryRun) {
24741
24752
  }
24742
24753
  }
24743
24754
  if (!dryRun && redactedLines > 0) {
24744
- fs49.writeFileSync(filePath, newLines.join("\n"), "utf-8");
24755
+ fs50.writeFileSync(filePath, newLines.join("\n"), "utf-8");
24745
24756
  }
24746
24757
  return { redactedLines, patterns };
24747
24758
  }
24748
24759
  function processJsonFile(filePath, dryRun) {
24749
24760
  let raw;
24750
24761
  try {
24751
- raw = fs49.readFileSync(filePath, "utf-8");
24762
+ raw = fs50.readFileSync(filePath, "utf-8");
24752
24763
  } catch {
24753
24764
  return { redactedLines: 0, patterns: [] };
24754
24765
  }
@@ -24761,15 +24772,15 @@ function processJsonFile(filePath, dryRun) {
24761
24772
  const { value, modified, found } = redactJson(parsed);
24762
24773
  if (!modified) return { redactedLines: 0, patterns: [] };
24763
24774
  if (!dryRun) {
24764
- fs49.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
24775
+ fs50.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
24765
24776
  }
24766
24777
  return { redactedLines: 1, patterns: found };
24767
24778
  }
24768
24779
  function findJsonFiles(dir) {
24769
24780
  const results = [];
24770
- if (!fs49.existsSync(dir)) return results;
24771
- for (const entry of fs49.readdirSync(dir, { withFileTypes: true })) {
24772
- const full = path50.join(dir, entry.name);
24781
+ if (!fs50.existsSync(dir)) return results;
24782
+ for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
24783
+ const full = path51.join(dir, entry.name);
24773
24784
  if (entry.isDirectory()) results.push(...findJsonFiles(full));
24774
24785
  else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
24775
24786
  }
@@ -24778,9 +24789,9 @@ function findJsonFiles(dir) {
24778
24789
  function registerMaskCommand(program2) {
24779
24790
  program2.command("mask").description("Redact plaintext secrets from local AI session history files").option("--dry-run", "show what would be redacted without making changes").option("--all", "scan all history (default: last 30 days)").action(async (options) => {
24780
24791
  const dryRun = !!options.dryRun;
24781
- const home = os44.homedir();
24782
- const claudeDir = path50.join(home, ".claude", "projects");
24783
- const geminiDir = path50.join(home, ".gemini", "tmp");
24792
+ const home = os45.homedir();
24793
+ const claudeDir = path51.join(home, ".claude", "projects");
24794
+ const geminiDir = path51.join(home, ".gemini", "tmp");
24784
24795
  const allFiles = [
24785
24796
  ...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
24786
24797
  ...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
@@ -24788,7 +24799,7 @@ function registerMaskCommand(program2) {
24788
24799
  const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
24789
24800
  const filtered = cutoff ? allFiles.filter((f) => {
24790
24801
  try {
24791
- return fs49.statSync(f.path).mtime >= cutoff;
24802
+ return fs50.statSync(f.path).mtime >= cutoff;
24792
24803
  } catch {
24793
24804
  return false;
24794
24805
  }
@@ -24844,20 +24855,20 @@ function registerMaskCommand(program2) {
24844
24855
  // src/cli.ts
24845
24856
  init_blast();
24846
24857
  var { version } = JSON.parse(
24847
- fs52.readFileSync(path53.join(__dirname, "../package.json"), "utf-8")
24858
+ fs53.readFileSync(path54.join(__dirname, "../package.json"), "utf-8")
24848
24859
  );
24849
24860
  var program = new Command();
24850
24861
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
24851
24862
  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) => {
24852
24863
  const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
24853
- const credPath = path53.join(os47.homedir(), ".node9", "credentials.json");
24854
- if (!fs52.existsSync(path53.dirname(credPath)))
24855
- fs52.mkdirSync(path53.dirname(credPath), { recursive: true });
24864
+ const credPath = path54.join(os48.homedir(), ".node9", "credentials.json");
24865
+ if (!fs53.existsSync(path54.dirname(credPath)))
24866
+ fs53.mkdirSync(path54.dirname(credPath), { recursive: true });
24856
24867
  const profileName = options.profile || "default";
24857
24868
  let existingCreds = {};
24858
24869
  try {
24859
- if (fs52.existsSync(credPath)) {
24860
- const raw = JSON.parse(fs52.readFileSync(credPath, "utf-8"));
24870
+ if (fs53.existsSync(credPath)) {
24871
+ const raw = JSON.parse(fs53.readFileSync(credPath, "utf-8"));
24861
24872
  if (raw.apiKey) {
24862
24873
  existingCreds = {
24863
24874
  default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
@@ -24869,14 +24880,14 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
24869
24880
  } catch {
24870
24881
  }
24871
24882
  existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
24872
- fs52.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
24883
+ fs53.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
24873
24884
  let effectiveCloud = null;
24874
24885
  if (profileName === "default") {
24875
- const configPath = path53.join(os47.homedir(), ".node9", "config.json");
24886
+ const configPath = path54.join(os48.homedir(), ".node9", "config.json");
24876
24887
  let config = {};
24877
24888
  try {
24878
- if (fs52.existsSync(configPath))
24879
- config = JSON.parse(fs52.readFileSync(configPath, "utf-8"));
24889
+ if (fs53.existsSync(configPath))
24890
+ config = JSON.parse(fs53.readFileSync(configPath, "utf-8"));
24880
24891
  } catch {
24881
24892
  }
24882
24893
  if (!config.settings || typeof config.settings !== "object") config.settings = {};
@@ -24891,9 +24902,9 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
24891
24902
  approvers.cloud = false;
24892
24903
  }
24893
24904
  s.approvers = approvers;
24894
- if (!fs52.existsSync(path53.dirname(configPath)))
24895
- fs52.mkdirSync(path53.dirname(configPath), { recursive: true });
24896
- fs52.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
24905
+ if (!fs53.existsSync(path54.dirname(configPath)))
24906
+ fs53.mkdirSync(path54.dirname(configPath), { recursive: true });
24907
+ fs53.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
24897
24908
  effectiveCloud = approvers.cloud === true;
24898
24909
  }
24899
24910
  if (options.profile && profileName !== "default") {
@@ -25052,15 +25063,15 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
25052
25063
  }
25053
25064
  }
25054
25065
  if (options.purge) {
25055
- const node9Dir = path53.join(os47.homedir(), ".node9");
25056
- if (fs52.existsSync(node9Dir)) {
25066
+ const node9Dir = path54.join(os48.homedir(), ".node9");
25067
+ if (fs53.existsSync(node9Dir)) {
25057
25068
  const confirmed = await confirm2({
25058
25069
  message: `Permanently delete ${node9Dir} (config, audit log, credentials)?`,
25059
25070
  default: false
25060
25071
  });
25061
25072
  if (confirmed) {
25062
- fs52.rmSync(node9Dir, { recursive: true });
25063
- if (fs52.existsSync(node9Dir)) {
25073
+ fs53.rmSync(node9Dir, { recursive: true });
25074
+ if (fs53.existsSync(node9Dir)) {
25064
25075
  console.error(
25065
25076
  chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
25066
25077
  );
@@ -25175,7 +25186,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
25175
25186
  });
25176
25187
  program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
25177
25188
  try {
25178
- const dashboardPath = path53.join(__dirname, "dashboard.mjs");
25189
+ const dashboardPath = path54.join(__dirname, "dashboard.mjs");
25179
25190
  const dynamicImport = new Function("id", "return import(id)");
25180
25191
  const mod = await dynamicImport(`file://${dashboardPath}`);
25181
25192
  await mod.startMonitor();
@@ -25213,14 +25224,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
25213
25224
  Run "node9 addto claude" to register it as the statusLine.`
25214
25225
  ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
25215
25226
  if (subcommand === "debug") {
25216
- const flagFile = path53.join(os47.homedir(), ".node9", "hud-debug");
25227
+ const flagFile = path54.join(os48.homedir(), ".node9", "hud-debug");
25217
25228
  if (state === "on") {
25218
- fs52.mkdirSync(path53.dirname(flagFile), { recursive: true });
25219
- fs52.writeFileSync(flagFile, "");
25229
+ fs53.mkdirSync(path54.dirname(flagFile), { recursive: true });
25230
+ fs53.writeFileSync(flagFile, "");
25220
25231
  console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
25221
25232
  console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
25222
25233
  } else if (state === "off") {
25223
- if (fs52.existsSync(flagFile)) fs52.unlinkSync(flagFile);
25234
+ if (fs53.existsSync(flagFile)) fs53.unlinkSync(flagFile);
25224
25235
  console.log("HUD debug logging disabled.");
25225
25236
  } else {
25226
25237
  console.error("Usage: node9 hud debug on|off");
@@ -25337,9 +25348,9 @@ if (process.argv[2] !== "daemon") {
25337
25348
  const isCheckHook = process.argv[2] === "check";
25338
25349
  if (isCheckHook) {
25339
25350
  if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
25340
- const logPath = path53.join(os47.homedir(), ".node9", "hook-debug.log");
25351
+ const logPath = path54.join(os48.homedir(), ".node9", "hook-debug.log");
25341
25352
  const msg = reason instanceof Error ? reason.message : String(reason);
25342
- fs52.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
25353
+ fs53.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
25343
25354
  `);
25344
25355
  }
25345
25356
  process.exit(0);