@node9/proxy 1.21.0 → 1.21.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.
package/dist/cli.mjs CHANGED
@@ -13628,12 +13628,12 @@ __export(tail_exports, {
13628
13628
  startTail: () => startTail
13629
13629
  });
13630
13630
  import http2 from "http";
13631
- import chalk30 from "chalk";
13631
+ import chalk29 from "chalk";
13632
13632
  import fs45 from "fs";
13633
13633
  import os41 from "os";
13634
13634
  import path47 from "path";
13635
13635
  import readline6 from "readline";
13636
- import { spawn as spawn9 } from "child_process";
13636
+ import { spawn as spawn8 } from "child_process";
13637
13637
  function shortenPathSummary(s) {
13638
13638
  if (!s || !s.startsWith("/")) return s;
13639
13639
  const parts = s.split("/").filter(Boolean);
@@ -13708,10 +13708,10 @@ function readSessionUsage() {
13708
13708
  }
13709
13709
  }
13710
13710
  function formatContextStat(stat) {
13711
- const pctColor = stat.fillPct >= 80 ? chalk30.red : stat.fillPct >= 50 ? chalk30.yellow : chalk30.cyan;
13711
+ const pctColor = stat.fillPct >= 80 ? chalk29.red : stat.fillPct >= 50 ? chalk29.yellow : chalk29.cyan;
13712
13712
  const k = (n) => `${Math.round(n / 1e3)}k`;
13713
13713
  const modelShort = stat.model.replace(/@.*$/, "").replace(/-\d{8}$/, "").replace(/^claude-/, "");
13714
- return chalk30.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + chalk30.dim(
13714
+ return chalk29.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + chalk29.dim(
13715
13715
  ` (${k(stat.inputTokens)}/${k(getModelContextLimit(stat.model))} out ${k(stat.outputTokens)} \xB7 ${modelShort})`
13716
13716
  );
13717
13717
  }
@@ -13734,11 +13734,11 @@ function agentLabel(agent, mcpServer, sessionId) {
13734
13734
  const tag = sessionTag(sessionId);
13735
13735
  const tagSuffix = tag ? `\xB7${tag}` : "";
13736
13736
  if (!agent || agent === "Terminal") {
13737
- return mcpServer ? chalk30.dim(`[\u2192 ${mcpServer}] `) : "";
13737
+ return mcpServer ? chalk29.dim(`[\u2192 ${mcpServer}] `) : "";
13738
13738
  }
13739
13739
  const short = agent === "Claude Code" ? "Claude" : agent === "Gemini CLI" ? "Gemini" : agent === "Unknown Agent" ? "" : agent.split(" ")[0];
13740
- if (!short) return mcpServer ? chalk30.dim(`[\u2192 ${mcpServer}] `) : "";
13741
- return mcpServer ? chalk30.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : chalk30.dim(`[${short}${tagSuffix}] `);
13740
+ if (!short) return mcpServer ? chalk29.dim(`[\u2192 ${mcpServer}] `) : "";
13741
+ return mcpServer ? chalk29.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : chalk29.dim(`[${short}${tagSuffix}] `);
13742
13742
  }
13743
13743
  function formatBase(activity) {
13744
13744
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
@@ -13746,20 +13746,20 @@ function formatBase(activity) {
13746
13746
  const toolName = activity.tool.slice(0, 16).padEnd(16);
13747
13747
  const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(os41.homedir(), "~");
13748
13748
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
13749
- return `${chalk30.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk30.white.bold(toolName)} ${chalk30.dim(argsPreview)}`;
13749
+ return `${chalk29.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${chalk29.white.bold(toolName)} ${chalk29.dim(argsPreview)}`;
13750
13750
  }
13751
13751
  function renderResult(activity, result) {
13752
13752
  const base = formatBase(activity);
13753
13753
  let status;
13754
13754
  if (result.status === "allow") {
13755
- status = chalk30.green("\u2713 ALLOW");
13755
+ status = chalk29.green("\u2713 ALLOW");
13756
13756
  } else if (result.status === "dlp") {
13757
- status = chalk30.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
13757
+ status = chalk29.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
13758
13758
  } else {
13759
- status = chalk30.red("\u2717 BLOCK");
13759
+ status = chalk29.red("\u2717 BLOCK");
13760
13760
  }
13761
13761
  const cost = result.costEstimate ?? activity.costEstimate;
13762
- const costSuffix = cost == null ? "" : chalk30.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
13762
+ const costSuffix = cost == null ? "" : chalk29.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
13763
13763
  if (process.stdout.isTTY) {
13764
13764
  if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
13765
13765
  readline6.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
@@ -13776,7 +13776,7 @@ function renderResult(activity, result) {
13776
13776
  }
13777
13777
  function renderPending(activity) {
13778
13778
  if (!process.stdout.isTTY) return;
13779
- const line = `${formatBase(activity)} ${chalk30.yellow("\u25CF \u2026")}`;
13779
+ const line = `${formatBase(activity)} ${chalk29.yellow("\u25CF \u2026")}`;
13780
13780
  pendingShownForId = activity.id;
13781
13781
  pendingWrappedLines = wrappedLineCount(line);
13782
13782
  process.stdout.write(`${line}\r`);
@@ -13788,7 +13788,7 @@ async function ensureDaemon() {
13788
13788
  const { port } = JSON.parse(fs45.readFileSync(PID_FILE, "utf-8"));
13789
13789
  pidPort = port;
13790
13790
  } catch {
13791
- console.error(chalk30.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
13791
+ console.error(chalk29.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
13792
13792
  }
13793
13793
  }
13794
13794
  const checkPort = pidPort ?? DAEMON_PORT;
@@ -13799,8 +13799,8 @@ async function ensureDaemon() {
13799
13799
  if (res.ok) return checkPort;
13800
13800
  } catch {
13801
13801
  }
13802
- console.log(chalk30.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
13803
- const child = spawn9(process.execPath, [process.argv[1], "daemon"], {
13802
+ console.log(chalk29.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
13803
+ const child = spawn8(process.execPath, [process.argv[1], "daemon"], {
13804
13804
  detached: true,
13805
13805
  stdio: "ignore",
13806
13806
  env: { ...process.env, NODE9_AUTO_STARTED: "1" }
@@ -13816,7 +13816,7 @@ async function ensureDaemon() {
13816
13816
  } catch {
13817
13817
  }
13818
13818
  }
13819
- console.error(chalk30.red("\u274C Daemon failed to start. Try: node9 daemon start"));
13819
+ console.error(chalk29.red("\u274C Daemon failed to start. Try: node9 daemon start"));
13820
13820
  process.exit(1);
13821
13821
  }
13822
13822
  function postDecisionHttp(id, decision, authToken, port, opts) {
@@ -13885,7 +13885,7 @@ function buildCardLines(req, localCount = 0) {
13885
13885
  const severityIcon = isBlock ? `${RED}\u{1F6D1}` : `${YELLOW}\u26A0 `;
13886
13886
  const rawDesc = req.riskMetadata?.ruleDescription ?? "";
13887
13887
  const description = rawDesc ? cleanReason(rawDesc) : "";
13888
- const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${chalk30.dim(`(${req.agent})`)}` : "";
13888
+ const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${chalk29.dim(`(${req.agent})`)}` : "";
13889
13889
  const lines = [
13890
13890
  ``,
13891
13891
  `${BOLD2}${CYAN}\u2554\u2550\u2550 Node9 Approval Required \u2550\u2550\u2557${RESET2}`,
@@ -13954,7 +13954,7 @@ function approverStatusLine() {
13954
13954
  const a = readApproversFromDisk();
13955
13955
  const fmt = (label, key) => {
13956
13956
  const on = a[key] !== false;
13957
- return `[${key[0]}]${label.slice(1)} ${on ? chalk30.green("\u2713") : chalk30.dim("\u2717")}`;
13957
+ return `[${key[0]}]${label.slice(1)} ${on ? chalk29.green("\u2713") : chalk29.dim("\u2717")}`;
13958
13958
  };
13959
13959
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
13960
13960
  }
@@ -13999,7 +13999,7 @@ async function startTail(options = {}) {
13999
13999
  req2.end();
14000
14000
  });
14001
14001
  if (result.ok) {
14002
- console.log(chalk30.green("\u2713 Flight Recorder buffer cleared."));
14002
+ console.log(chalk29.green("\u2713 Flight Recorder buffer cleared."));
14003
14003
  } else if (result.code === "ECONNREFUSED") {
14004
14004
  throw new Error("Daemon is not running. Start it with: node9 daemon start");
14005
14005
  } else if (result.code === "ETIMEDOUT") {
@@ -14045,7 +14045,7 @@ async function startTail(options = {}) {
14045
14045
  const channel = name === "n" ? "native" : name === "c" ? "cloud" : name === "t" ? "terminal" : null;
14046
14046
  if (channel) {
14047
14047
  toggleApprover(channel);
14048
- console.log(chalk30.dim(` Approvers: ${approverStatusLine()}`));
14048
+ console.log(chalk29.dim(` Approvers: ${approverStatusLine()}`));
14049
14049
  }
14050
14050
  };
14051
14051
  process.stdin.on("keypress", idleKeypressHandler);
@@ -14111,7 +14111,7 @@ async function startTail(options = {}) {
14111
14111
  localAllowCounts.get(req2.toolName) ?? 0
14112
14112
  )
14113
14113
  );
14114
- const decisionStamp = action === "always-allow" ? chalk30.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? chalk30.cyan("\u23F1 TRUST 30m") : action === "allow" ? chalk30.green("\u2713 ALLOWED") : action === "redirect" ? chalk30.yellow("\u21A9 REDIRECT AI") : chalk30.red("\u2717 DENIED");
14114
+ const decisionStamp = action === "always-allow" ? chalk29.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? chalk29.cyan("\u23F1 TRUST 30m") : action === "allow" ? chalk29.green("\u2713 ALLOWED") : action === "redirect" ? chalk29.yellow("\u21A9 REDIRECT AI") : chalk29.red("\u2717 DENIED");
14115
14115
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${decisionStamp} ${GRAY}(terminal)${RESET2}`, ``);
14116
14116
  for (const line of stampedLines) process.stdout.write(line + "\n");
14117
14117
  process.stdout.write(SHOW_CURSOR);
@@ -14162,7 +14162,7 @@ async function startTail(options = {}) {
14162
14162
  );
14163
14163
  const stampedLines = buildCardLines(req2, priorCount);
14164
14164
  if (externalDecision) {
14165
- const source = externalDecision === "allow" ? chalk30.green("\u2713 ALLOWED") : chalk30.red("\u2717 DENIED");
14165
+ const source = externalDecision === "allow" ? chalk29.green("\u2713 ALLOWED") : chalk29.red("\u2717 DENIED");
14166
14166
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${source} ${GRAY}(external)${RESET2}`, ``);
14167
14167
  }
14168
14168
  for (const line of stampedLines) process.stdout.write(line + "\n");
@@ -14210,25 +14210,25 @@ async function startTail(options = {}) {
14210
14210
  if (unackedDlp > 0) {
14211
14211
  console.log("");
14212
14212
  console.log(
14213
- chalk30.bgRed.white.bold(
14213
+ chalk29.bgRed.white.bold(
14214
14214
  ` \u26A0\uFE0F DLP ALERT: ${unackedDlp} secret${unackedDlp !== 1 ? "s" : ""} found in Claude response text \u2014 run: node9 dlp `
14215
14215
  )
14216
14216
  );
14217
14217
  }
14218
14218
  } catch {
14219
14219
  }
14220
- console.log(chalk30.cyan.bold(`
14220
+ console.log(chalk29.cyan.bold(`
14221
14221
  \u{1F6F0}\uFE0F Node9 tail`));
14222
14222
  if (canApprove) {
14223
- console.log(chalk30.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
14224
- console.log(chalk30.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
14223
+ console.log(chalk29.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
14224
+ console.log(chalk29.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
14225
14225
  }
14226
14226
  const ctxStat = readSessionUsage();
14227
14227
  if (ctxStat) console.log(" " + formatContextStat(ctxStat));
14228
14228
  if (options.history) {
14229
- console.log(chalk30.dim("Showing history + live events.\n"));
14229
+ console.log(chalk29.dim("Showing history + live events.\n"));
14230
14230
  } else {
14231
- console.log(chalk30.dim("Showing live events only. Use --history to include past.\n"));
14231
+ console.log(chalk29.dim("Showing live events only. Use --history to include past.\n"));
14232
14232
  }
14233
14233
  process.on("SIGINT", () => {
14234
14234
  exitIdleMode();
@@ -14238,7 +14238,7 @@ async function startTail(options = {}) {
14238
14238
  readline6.clearLine(process.stdout, 0);
14239
14239
  readline6.cursorTo(process.stdout, 0);
14240
14240
  }
14241
- console.log(chalk30.dim("\n\u{1F6F0}\uFE0F Disconnected."));
14241
+ console.log(chalk29.dim("\n\u{1F6F0}\uFE0F Disconnected."));
14242
14242
  process.exit(0);
14243
14243
  });
14244
14244
  const STALL_THRESHOLD_MS = 6e4;
@@ -14250,7 +14250,7 @@ async function startTail(options = {}) {
14250
14250
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
14251
14251
  console.log("");
14252
14252
  console.log(
14253
- chalk30.yellow(
14253
+ chalk29.yellow(
14254
14254
  "\u26A0\uFE0F Tail appears stalled \u2014 hooks are firing but no events are arriving. Try: node9 daemon restart"
14255
14255
  )
14256
14256
  );
@@ -14267,7 +14267,7 @@ async function startTail(options = {}) {
14267
14267
  },
14268
14268
  (res) => {
14269
14269
  if (res.statusCode !== 200) {
14270
- console.error(chalk30.red(`Failed to connect: HTTP ${res.statusCode}`));
14270
+ console.error(chalk29.red(`Failed to connect: HTTP ${res.statusCode}`));
14271
14271
  process.exit(1);
14272
14272
  }
14273
14273
  if (canApprove) enterIdleMode();
@@ -14298,7 +14298,7 @@ async function startTail(options = {}) {
14298
14298
  readline6.clearLine(process.stdout, 0);
14299
14299
  readline6.cursorTo(process.stdout, 0);
14300
14300
  }
14301
- console.log(chalk30.red("\n\u274C Daemon disconnected."));
14301
+ console.log(chalk29.red("\n\u274C Daemon disconnected."));
14302
14302
  process.exit(1);
14303
14303
  });
14304
14304
  }
@@ -14311,7 +14311,7 @@ async function startTail(options = {}) {
14311
14311
  const parsed = JSON.parse(rawData);
14312
14312
  const msg = parsed.message ?? "Flight recorder is down \u2014 run: node9 daemon restart";
14313
14313
  console.log("");
14314
- console.log(chalk30.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
14314
+ console.log(chalk29.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
14315
14315
  } catch {
14316
14316
  }
14317
14317
  return;
@@ -14396,9 +14396,9 @@ async function startTail(options = {}) {
14396
14396
  const rawSummary = data.argsSummary ?? data.tool;
14397
14397
  const summary = shortenPathSummary(rawSummary);
14398
14398
  const fileCount = data.fileCount ?? 0;
14399
- const files = fileCount > 0 ? chalk30.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
14399
+ const files = fileCount > 0 ? chalk29.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
14400
14400
  process.stdout.write(
14401
- `${chalk30.dim(time)} ${chalk30.cyan("\u{1F4F8} snapshot")} ${chalk30.dim(hash)} ${summary}${files}
14401
+ `${chalk29.dim(time)} ${chalk29.cyan("\u{1F4F8} snapshot")} ${chalk29.dim(hash)} ${summary}${files}
14402
14402
  `
14403
14403
  );
14404
14404
  return;
@@ -14415,18 +14415,18 @@ async function startTail(options = {}) {
14415
14415
  if (event === "execution-result") {
14416
14416
  const exec = data;
14417
14417
  const time = new Date(Date.now()).toLocaleTimeString([], { hour12: false });
14418
- const arrow = exec.isError ? chalk30.red(" \u21B3 \u2717") : chalk30.green(" \u21B3 \u2713");
14418
+ const arrow = exec.isError ? chalk29.red(" \u21B3 \u2717") : chalk29.green(" \u21B3 \u2713");
14419
14419
  const label = agentLabel(exec.agent, exec.mcpServer);
14420
14420
  const tool = (exec.tool ?? "").slice(0, 16);
14421
- const duration = typeof exec.durationMs === "number" ? chalk30.dim(` (${exec.durationMs}ms)`) : "";
14421
+ const duration = typeof exec.durationMs === "number" ? chalk29.dim(` (${exec.durationMs}ms)`) : "";
14422
14422
  console.log(
14423
- `${chalk30.gray(time)} ${arrow} ${label}${chalk30.dim(tool)}${chalk30.dim(" completed")}${duration}`
14423
+ `${chalk29.gray(time)} ${arrow} ${label}${chalk29.dim(tool)}${chalk29.dim(" completed")}${duration}`
14424
14424
  );
14425
14425
  }
14426
14426
  }
14427
14427
  req.on("error", (err2) => {
14428
14428
  const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
14429
- console.error(chalk30.red(`
14429
+ console.error(chalk29.red(`
14430
14430
  \u274C ${msg}`));
14431
14431
  process.exit(1);
14432
14432
  });
@@ -14862,7 +14862,7 @@ init_core();
14862
14862
  init_setup();
14863
14863
  init_daemon2();
14864
14864
  import { Command } from "commander";
14865
- import chalk31 from "chalk";
14865
+ import chalk30 from "chalk";
14866
14866
  import fs47 from "fs";
14867
14867
  import path49 from "path";
14868
14868
  import os43 from "os";
@@ -15656,7 +15656,7 @@ function detectAiAgent(payload) {
15656
15656
  return "Terminal";
15657
15657
  }
15658
15658
  function registerCheckCommand(program2) {
15659
- program2.command("check").description("Hook handler \u2014 evaluates a tool call before execution").argument("[data]", "JSON string of the tool call").action(async (data) => {
15659
+ program2.command("check", { hidden: true }).description("Hook handler \u2014 evaluates a tool call before execution").argument("[data]", "JSON string of the tool call").action(async (data) => {
15660
15660
  const processPayload = async (raw) => {
15661
15661
  try {
15662
15662
  if (!raw || raw.trim() === "") process.exit(0);
@@ -16054,7 +16054,7 @@ function sanitize3(value) {
16054
16054
  return value.replace(/[\x00-\x1F\x7F]/g, "");
16055
16055
  }
16056
16056
  function registerLogCommand(program2) {
16057
- program2.command("log").description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").action(async (data) => {
16057
+ program2.command("log", { hidden: true }).description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").action(async (data) => {
16058
16058
  const logPayload = async (raw) => {
16059
16059
  try {
16060
16060
  if (!raw || raw.trim() === "") process.exit(0);
@@ -16807,6 +16807,35 @@ function isTestEntry(entry, testTs) {
16807
16807
  }
16808
16808
  return false;
16809
16809
  }
16810
+ var SUPERSEDE_WINDOW_MS = 6e4;
16811
+ function buildSupersededSet(entries) {
16812
+ const superseded = /* @__PURE__ */ new Set();
16813
+ for (let i = 0; i < entries.length; i++) {
16814
+ const e = entries[i];
16815
+ if (e.decision !== "deny") continue;
16816
+ if (e.checkedBy !== "smart-rule-block-override") continue;
16817
+ if (!e.argsHash || !e.sessionId) continue;
16818
+ const eTs = Date.parse(e.ts);
16819
+ if (Number.isNaN(eTs)) continue;
16820
+ for (let j = i + 1; j < entries.length; j++) {
16821
+ const next = entries[j];
16822
+ const nextTs = Date.parse(next.ts);
16823
+ if (Number.isNaN(nextTs)) continue;
16824
+ if (nextTs - eTs > SUPERSEDE_WINDOW_MS) break;
16825
+ if (next.argsHash !== e.argsHash) continue;
16826
+ if (next.sessionId !== e.sessionId) continue;
16827
+ if (next.tool !== e.tool) continue;
16828
+ if (next.decision === "allow" && next.checkedBy === "daemon") {
16829
+ superseded.add(`${e.ts}|${e.argsHash}`);
16830
+ break;
16831
+ }
16832
+ }
16833
+ }
16834
+ return superseded;
16835
+ }
16836
+ function supersedeKey(e) {
16837
+ return `${e.ts}|${e.argsHash ?? ""}`;
16838
+ }
16810
16839
  function getDateRange(period, now) {
16811
16840
  const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
16812
16841
  const end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
@@ -17258,6 +17287,7 @@ function aggregateReportFromAudit(period, opts = {}) {
17258
17287
  }
17259
17288
  return true;
17260
17289
  });
17290
+ const superseded = buildSupersededSet(entries);
17261
17291
  let userApproved = 0;
17262
17292
  let userDenied = 0;
17263
17293
  let timedOut = 0;
@@ -17275,6 +17305,7 @@ function aggregateReportFromAudit(period, opts = {}) {
17275
17305
  const dailyMap = /* @__PURE__ */ new Map();
17276
17306
  const hourMap = /* @__PURE__ */ new Map();
17277
17307
  for (const e of entries) {
17308
+ if (superseded.has(supersedeKey(e))) continue;
17278
17309
  const allow = isAllow(e.decision);
17279
17310
  const dateKey = e.ts.slice(0, 10);
17280
17311
  const userInteracted = e.source === "daemon";
@@ -17285,6 +17316,7 @@ function aggregateReportFromAudit(period, opts = {}) {
17285
17316
  if (e.checkedBy === "timeout") timedOut++;
17286
17317
  else if (e.checkedBy === "observe-mode-dlp-would-block") observeDlp++;
17287
17318
  else if (isDlp(e.checkedBy)) dlpBlocked++;
17319
+ else if (e.checkedBy === "local-decision") userDenied++;
17288
17320
  else if (e.checkedBy !== "loop-detected") hardBlocked++;
17289
17321
  }
17290
17322
  if (e.checkedBy === "loop-detected") loopHits++;
@@ -17292,8 +17324,11 @@ function aggregateReportFromAudit(period, opts = {}) {
17292
17324
  t.calls++;
17293
17325
  if (!allow) t.blocked++;
17294
17326
  toolMap.set(e.tool, t);
17295
- if (!allow && e.checkedBy) {
17296
- blockMap.set(e.checkedBy, (blockMap.get(e.checkedBy) ?? 0) + 1);
17327
+ if (!allow) {
17328
+ const key = e.checkedBy ?? (e.source === "daemon" ? "local-decision" : null);
17329
+ if (key) {
17330
+ blockMap.set(key, (blockMap.get(key) ?? 0) + 1);
17331
+ }
17297
17332
  }
17298
17333
  if (!allow && e.ruleName) {
17299
17334
  ruleMap.set(e.ruleName, (ruleMap.get(e.ruleName) ?? 0) + 1);
@@ -17322,7 +17357,9 @@ function aggregateReportFromAudit(period, opts = {}) {
17322
17357
  start,
17323
17358
  end,
17324
17359
  excludedTests,
17325
- total: entries.length,
17360
+ // Subtract superseded rows so the headline event count agrees with
17361
+ // the bucket counters (which skip them in the loop above).
17362
+ total: entries.length - superseded.size,
17326
17363
  userApproved,
17327
17364
  userDenied,
17328
17365
  timedOut,
@@ -18220,7 +18257,7 @@ function registerInitCommand(program2) {
18220
18257
  const agentList = found.join(", ");
18221
18258
  console.log(chalk16.green.bold(`\u{1F6E1}\uFE0F Node9 is protecting ${agentList}!`));
18222
18259
  console.log("");
18223
- console.log(chalk16.white(" Watch live: ") + chalk16.cyan("node9 tail"));
18260
+ console.log(chalk16.white(" Watch live: ") + chalk16.cyan("node9 monitor"));
18224
18261
  console.log("");
18225
18262
  console.log(chalk16.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
18226
18263
  console.log(
@@ -18517,72 +18554,11 @@ function registerUndoCommand(program2) {
18517
18554
  });
18518
18555
  }
18519
18556
 
18520
- // src/cli/commands/watch.ts
18521
- init_daemon();
18522
- import chalk19 from "chalk";
18523
- import { spawn as spawn7, spawnSync as spawnSync4 } from "child_process";
18524
- function registerWatchCommand(program2) {
18525
- program2.command("watch").description("Run a command under Node9 watch mode (daemon stays alive for the session)").argument("<command>", "Command to run").argument("[args...]", "Arguments for the command").action(async (cmd, args) => {
18526
- let port = DAEMON_PORT;
18527
- try {
18528
- const res = await fetch(`http://127.0.0.1:${DAEMON_PORT}/settings`, {
18529
- signal: AbortSignal.timeout(500)
18530
- });
18531
- if (res.ok) {
18532
- const data = await res.json();
18533
- if (typeof data.port === "number") port = data.port;
18534
- } else {
18535
- throw new Error("not running");
18536
- }
18537
- } catch {
18538
- console.error(chalk19.dim("\u{1F6E1}\uFE0F Starting Node9 daemon (watch mode)..."));
18539
- const child = spawn7(process.execPath, [process.argv[1], "daemon"], {
18540
- detached: true,
18541
- stdio: "ignore",
18542
- env: { ...process.env, NODE9_AUTO_STARTED: "1", NODE9_WATCH_MODE: "1" }
18543
- });
18544
- child.unref();
18545
- let ready = false;
18546
- for (let i = 0; i < 20; i++) {
18547
- await new Promise((r) => setTimeout(r, 250));
18548
- try {
18549
- const r = await fetch(`http://127.0.0.1:${DAEMON_PORT}/settings`, {
18550
- signal: AbortSignal.timeout(500)
18551
- });
18552
- if (r.ok) {
18553
- ready = true;
18554
- break;
18555
- }
18556
- } catch {
18557
- }
18558
- }
18559
- if (!ready) {
18560
- console.error(chalk19.red("\u274C Daemon failed to start. Try: node9 daemon start"));
18561
- process.exit(1);
18562
- }
18563
- }
18564
- console.error(
18565
- chalk19.cyan.bold("\u{1F6E1}\uFE0F Node9 watch") + chalk19.dim(` \u2192 localhost:${port}`) + chalk19.dim(
18566
- "\n Tip: run `node9 tail` in another terminal to review and approve AI actions.\n"
18567
- )
18568
- );
18569
- const result = spawnSync4(cmd, args, {
18570
- stdio: "inherit",
18571
- env: { ...process.env, NODE9_WATCH_MODE: "1" }
18572
- });
18573
- if (result.error) {
18574
- console.error(chalk19.red(`\u274C Failed to run command: ${result.error.message}`));
18575
- process.exit(1);
18576
- }
18577
- process.exit(result.status ?? 0);
18578
- });
18579
- }
18580
-
18581
18557
  // src/mcp-gateway/index.ts
18582
18558
  init_orchestrator();
18583
18559
  import readline4 from "readline";
18584
- import chalk20 from "chalk";
18585
- import { spawn as spawn8 } from "child_process";
18560
+ import chalk19 from "chalk";
18561
+ import { spawn as spawn7 } from "child_process";
18586
18562
  import { execa as execa2 } from "execa";
18587
18563
  init_provenance();
18588
18564
 
@@ -18742,13 +18718,13 @@ async function runMcpGateway(upstreamCommand) {
18742
18718
  const prov = checkProvenance(executable);
18743
18719
  if (prov.trustLevel === "suspect") {
18744
18720
  console.error(
18745
- chalk20.red(
18721
+ chalk19.red(
18746
18722
  `\u26A0\uFE0F Node9: Upstream MCP server binary is suspect \u2014 ${prov.reason} (${prov.resolvedPath})`
18747
18723
  )
18748
18724
  );
18749
- console.error(chalk20.red(" Verify this binary is trusted before proceeding."));
18725
+ console.error(chalk19.red(" Verify this binary is trusted before proceeding."));
18750
18726
  }
18751
- console.error(chalk20.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
18727
+ console.error(chalk19.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
18752
18728
  const UPSTREAM_INJECTOR_VARS = /* @__PURE__ */ new Set([
18753
18729
  "NODE_OPTIONS",
18754
18730
  "NODE_PATH",
@@ -18767,7 +18743,7 @@ async function runMcpGateway(upstreamCommand) {
18767
18743
  const safeEnv = Object.fromEntries(
18768
18744
  Object.entries(process.env).filter(([k]) => !UPSTREAM_INJECTOR_VARS.has(k))
18769
18745
  );
18770
- const child = spawn8(executable, cmdArgs, {
18746
+ const child = spawn7(executable, cmdArgs, {
18771
18747
  stdio: ["pipe", "pipe", "inherit"],
18772
18748
  // control stdin/stdout; inherit stderr
18773
18749
  shell: false,
@@ -18861,10 +18837,10 @@ async function runMcpGateway(upstreamCommand) {
18861
18837
  mcpServer
18862
18838
  });
18863
18839
  if (!result.approved) {
18864
- console.error(chalk20.red(`
18840
+ console.error(chalk19.red(`
18865
18841
  \u{1F6D1} Node9 MCP Gateway: Action Blocked`));
18866
- console.error(chalk20.gray(` Tool: ${toolName}`));
18867
- console.error(chalk20.gray(` Reason: ${result.reason ?? "Security Policy"}
18842
+ console.error(chalk19.gray(` Tool: ${toolName}`));
18843
+ console.error(chalk19.gray(` Reason: ${result.reason ?? "Security Policy"}
18868
18844
  `));
18869
18845
  const blockedByLabel = result.blockedByLabel ?? result.reason ?? "Security Policy";
18870
18846
  const isHumanDecision = blockedByLabel.toLowerCase().includes("user") || blockedByLabel.toLowerCase().includes("daemon") || blockedByLabel.toLowerCase().includes("decision");
@@ -18976,7 +18952,7 @@ async function runMcpGateway(upstreamCommand) {
18976
18952
  updatePin(serverKey, upstreamCommand, currentHash, toolNames);
18977
18953
  pinState = "validated";
18978
18954
  console.error(
18979
- chalk20.green(
18955
+ chalk19.green(
18980
18956
  `\u{1F512} Node9: Pinned ${toolNames.length} tool definition(s) for this MCP server`
18981
18957
  )
18982
18958
  );
@@ -18989,11 +18965,11 @@ async function runMcpGateway(upstreamCommand) {
18989
18965
  } else if (pinStatus === "corrupt") {
18990
18966
  pinState = "quarantined";
18991
18967
  console.error(
18992
- chalk20.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
18968
+ chalk19.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
18993
18969
  );
18994
- console.error(chalk20.red(" Tool calls are blocked until the pin file is repaired."));
18970
+ console.error(chalk19.red(" Tool calls are blocked until the pin file is repaired."));
18995
18971
  console.error(
18996
- chalk20.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
18972
+ chalk19.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
18997
18973
  `)
18998
18974
  );
18999
18975
  const errorResponse = {
@@ -19010,13 +18986,13 @@ async function runMcpGateway(upstreamCommand) {
19010
18986
  } else {
19011
18987
  pinState = "quarantined";
19012
18988
  console.error(
19013
- chalk20.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
18989
+ chalk19.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
19014
18990
  );
19015
18991
  console.error(
19016
- chalk20.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
18992
+ chalk19.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
19017
18993
  );
19018
- console.error(chalk20.red(" Session quarantined \u2014 all tool calls blocked."));
19019
- console.error(chalk20.yellow(` Run: node9 mcp pin update ${serverKey}
18994
+ console.error(chalk19.red(" Session quarantined \u2014 all tool calls blocked."));
18995
+ console.error(chalk19.yellow(` Run: node9 mcp pin update ${serverKey}
19020
18996
  `));
19021
18997
  const errorResponse = {
19022
18998
  jsonrpc: "2.0",
@@ -19059,7 +19035,7 @@ async function runMcpGateway(upstreamCommand) {
19059
19035
  const toolName = callId !== void 0 ? pendingCallNames.get(callId) ?? "unknown" : "unknown";
19060
19036
  if (callId !== void 0) pendingCallNames.delete(callId);
19061
19037
  console.error(
19062
- chalk20.yellow(
19038
+ chalk19.yellow(
19063
19039
  `\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
19064
19040
  )
19065
19041
  );
@@ -19113,7 +19089,7 @@ import readline5 from "readline";
19113
19089
  import fs39 from "fs";
19114
19090
  import os35 from "os";
19115
19091
  import path41 from "path";
19116
- import { spawnSync as spawnSync5 } from "child_process";
19092
+ import { spawnSync as spawnSync4 } from "child_process";
19117
19093
  init_core();
19118
19094
  init_daemon();
19119
19095
  init_shields();
@@ -19587,7 +19563,7 @@ function handleRuleAdd(args) {
19587
19563
  return `Rule "${name}" added to ~/.node9/config.json \u2014 verdict: ${verdict} when ${field} matches "${pattern}"`;
19588
19564
  }
19589
19565
  function runCliCommand(subArgs) {
19590
- const result = spawnSync5(process.execPath, [process.argv[1], ...subArgs], {
19566
+ const result = spawnSync4(process.execPath, [process.argv[1], ...subArgs], {
19591
19567
  encoding: "utf-8",
19592
19568
  timeout: 6e4,
19593
19569
  // Disable colors — stdout is piped (not a TTY), chalk auto-detects, but be explicit
@@ -19782,7 +19758,7 @@ function registerMcpServerCommand(program2) {
19782
19758
 
19783
19759
  // src/cli/commands/trust.ts
19784
19760
  init_trusted_hosts();
19785
- import chalk21 from "chalk";
19761
+ import chalk20 from "chalk";
19786
19762
  function isValidHost(host) {
19787
19763
  return /^(\*\.)?[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(host);
19788
19764
  }
@@ -19792,51 +19768,51 @@ function registerTrustCommand(program2) {
19792
19768
  const normalized = normalizeHost(host.trim());
19793
19769
  if (!isValidHost(normalized)) {
19794
19770
  console.error(
19795
- chalk21.red(`
19771
+ chalk20.red(`
19796
19772
  \u274C Invalid host: "${host}"
19797
- `) + chalk21.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
19773
+ `) + chalk20.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
19798
19774
  );
19799
19775
  process.exit(1);
19800
19776
  }
19801
19777
  addTrustedHost(normalized);
19802
- console.log(chalk21.green(`
19778
+ console.log(chalk20.green(`
19803
19779
  \u2705 ${normalized} added to trusted hosts.`));
19804
19780
  console.log(
19805
- chalk21.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
19781
+ chalk20.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
19806
19782
  );
19807
19783
  });
19808
19784
  trustCmd.command("remove <host>").description("Remove a trusted host").action((host) => {
19809
19785
  const normalized = normalizeHost(host.trim());
19810
19786
  const removed = removeTrustedHost(normalized);
19811
19787
  if (!removed) {
19812
- console.error(chalk21.yellow(`
19788
+ console.error(chalk20.yellow(`
19813
19789
  \u26A0\uFE0F "${normalized}" is not in the trusted hosts list.
19814
19790
  `));
19815
19791
  process.exit(1);
19816
19792
  }
19817
- console.log(chalk21.green(`
19793
+ console.log(chalk20.green(`
19818
19794
  \u2705 ${normalized} removed from trusted hosts.
19819
19795
  `));
19820
19796
  });
19821
19797
  trustCmd.command("list").description("Show all trusted hosts").action(() => {
19822
19798
  const hosts = readTrustedHosts();
19823
19799
  if (hosts.length === 0) {
19824
- console.log(chalk21.gray("\n No trusted hosts configured.\n"));
19825
- console.log(` Add one: ${chalk21.cyan("node9 trust add api.mycompany.com")}
19800
+ console.log(chalk20.gray("\n No trusted hosts configured.\n"));
19801
+ console.log(` Add one: ${chalk20.cyan("node9 trust add api.mycompany.com")}
19826
19802
  `);
19827
19803
  return;
19828
19804
  }
19829
- console.log(chalk21.bold("\n\u{1F513} Trusted Hosts\n"));
19805
+ console.log(chalk20.bold("\n\u{1F513} Trusted Hosts\n"));
19830
19806
  for (const entry of hosts) {
19831
19807
  const date = new Date(entry.addedAt).toLocaleDateString();
19832
- console.log(` ${chalk21.cyan(entry.host.padEnd(40))} ${chalk21.gray(`added ${date}`)}`);
19808
+ console.log(` ${chalk20.cyan(entry.host.padEnd(40))} ${chalk20.gray(`added ${date}`)}`);
19833
19809
  }
19834
19810
  console.log("");
19835
19811
  });
19836
19812
  }
19837
19813
 
19838
19814
  // src/cli/commands/mcp-pin.ts
19839
- import chalk22 from "chalk";
19815
+ import chalk21 from "chalk";
19840
19816
  function registerMcpPinCommand(program2) {
19841
19817
  const pinCmd = program2.command("mcp").description("Manage MCP server tool definition pinning (rug pull defense)");
19842
19818
  const pinSubCmd = pinCmd.command("pin").description("Manage pinned MCP server tool definitions");
@@ -19844,31 +19820,31 @@ function registerMcpPinCommand(program2) {
19844
19820
  const result = readMcpPinsSafe();
19845
19821
  if (!result.ok) {
19846
19822
  if (result.reason === "missing") {
19847
- console.log(chalk22.gray("\nNo MCP servers are pinned yet."));
19823
+ console.log(chalk21.gray("\nNo MCP servers are pinned yet."));
19848
19824
  console.log(
19849
- chalk22.gray("Pins are created automatically when the MCP gateway first connects.\n")
19825
+ chalk21.gray("Pins are created automatically when the MCP gateway first connects.\n")
19850
19826
  );
19851
19827
  return;
19852
19828
  }
19853
- console.error(chalk22.red(`
19829
+ console.error(chalk21.red(`
19854
19830
  \u274C Pin file is corrupt: ${result.detail}`));
19855
- console.error(chalk22.yellow(" Run: node9 mcp pin reset\n"));
19831
+ console.error(chalk21.yellow(" Run: node9 mcp pin reset\n"));
19856
19832
  process.exit(1);
19857
19833
  }
19858
19834
  const entries = Object.entries(result.pins.servers);
19859
19835
  if (entries.length === 0) {
19860
- console.log(chalk22.gray("\nNo MCP servers are pinned yet."));
19836
+ console.log(chalk21.gray("\nNo MCP servers are pinned yet."));
19861
19837
  console.log(
19862
- chalk22.gray("Pins are created automatically when the MCP gateway first connects.\n")
19838
+ chalk21.gray("Pins are created automatically when the MCP gateway first connects.\n")
19863
19839
  );
19864
19840
  return;
19865
19841
  }
19866
- console.log(chalk22.bold("\n\u{1F512} Pinned MCP Servers\n"));
19842
+ console.log(chalk21.bold("\n\u{1F512} Pinned MCP Servers\n"));
19867
19843
  for (const [key, entry] of entries) {
19868
- console.log(` ${chalk22.cyan(key)} ${chalk22.gray(entry.label)}`);
19869
- console.log(` Tools (${entry.toolCount}): ${chalk22.white(entry.toolNames.join(", "))}`);
19870
- console.log(` Hash: ${chalk22.gray(entry.toolsHash.slice(0, 16))}...`);
19871
- console.log(` Pinned: ${chalk22.gray(entry.pinnedAt)}`);
19844
+ console.log(` ${chalk21.cyan(key)} ${chalk21.gray(entry.label)}`);
19845
+ console.log(` Tools (${entry.toolCount}): ${chalk21.white(entry.toolNames.join(", "))}`);
19846
+ console.log(` Hash: ${chalk21.gray(entry.toolsHash.slice(0, 16))}...`);
19847
+ console.log(` Pinned: ${chalk21.gray(entry.pinnedAt)}`);
19872
19848
  console.log("");
19873
19849
  }
19874
19850
  });
@@ -19879,127 +19855,127 @@ function registerMcpPinCommand(program2) {
19879
19855
  try {
19880
19856
  pins = readMcpPins();
19881
19857
  } catch {
19882
- console.error(chalk22.red("\n\u274C Pin file is corrupt."));
19883
- console.error(chalk22.yellow(" Run: node9 mcp pin reset\n"));
19858
+ console.error(chalk21.red("\n\u274C Pin file is corrupt."));
19859
+ console.error(chalk21.yellow(" Run: node9 mcp pin reset\n"));
19884
19860
  process.exit(1);
19885
19861
  }
19886
19862
  if (!pins.servers[serverKey]) {
19887
- console.error(chalk22.red(`
19863
+ console.error(chalk21.red(`
19888
19864
  \u274C No pin found for server key "${serverKey}"
19889
19865
  `));
19890
- console.error(`Run ${chalk22.cyan("node9 mcp pin list")} to see pinned servers.
19866
+ console.error(`Run ${chalk21.cyan("node9 mcp pin list")} to see pinned servers.
19891
19867
  `);
19892
19868
  process.exit(1);
19893
19869
  }
19894
19870
  const label = pins.servers[serverKey].label;
19895
19871
  removePin2(serverKey);
19896
- console.log(chalk22.green(`
19897
- \u{1F513} Pin removed for ${chalk22.cyan(serverKey)}`));
19898
- console.log(chalk22.gray(` Server: ${label}`));
19899
- console.log(chalk22.gray(" Next connection will re-pin with current tool definitions.\n"));
19872
+ console.log(chalk21.green(`
19873
+ \u{1F513} Pin removed for ${chalk21.cyan(serverKey)}`));
19874
+ console.log(chalk21.gray(` Server: ${label}`));
19875
+ console.log(chalk21.gray(" Next connection will re-pin with current tool definitions.\n"));
19900
19876
  });
19901
19877
  pinSubCmd.command("reset").description("Clear all MCP pins (next connection to each server will re-pin)").action(() => {
19902
19878
  const result = readMcpPinsSafe();
19903
19879
  if (!result.ok && result.reason === "missing") {
19904
- console.log(chalk22.gray("\nNo pins to clear.\n"));
19880
+ console.log(chalk21.gray("\nNo pins to clear.\n"));
19905
19881
  return;
19906
19882
  }
19907
19883
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
19908
19884
  clearAllPins2();
19909
- console.log(chalk22.green(`
19885
+ console.log(chalk21.green(`
19910
19886
  \u{1F513} Cleared ${count} MCP pin(s).`));
19911
- console.log(chalk22.gray(" Next connection to each server will re-pin.\n"));
19887
+ console.log(chalk21.gray(" Next connection to each server will re-pin.\n"));
19912
19888
  });
19913
19889
  }
19914
19890
 
19915
19891
  // src/cli/commands/sync.ts
19916
19892
  init_sync();
19917
- import chalk23 from "chalk";
19893
+ import chalk22 from "chalk";
19918
19894
  function registerSyncCommand(program2) {
19919
19895
  const policy = program2.command("policy").description("Manage cloud policy rules");
19920
19896
  policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
19921
- process.stdout.write(chalk23.cyan("Syncing cloud policy rules\u2026"));
19897
+ process.stdout.write(chalk22.cyan("Syncing cloud policy rules\u2026"));
19922
19898
  const result = await runCloudSync();
19923
19899
  process.stdout.write("\n");
19924
19900
  if (!result.ok) {
19925
- console.error(chalk23.red(`\u2717 ${result.reason}`));
19901
+ console.error(chalk22.red(`\u2717 ${result.reason}`));
19926
19902
  process.exit(1);
19927
19903
  }
19928
19904
  if (result.unchanged) {
19929
19905
  console.log(
19930
- chalk23.green(
19906
+ chalk22.green(
19931
19907
  `\u2713 Already up to date \u2014 ${result.rules} rule${result.rules === 1 ? "" : "s"} cached`
19932
19908
  )
19933
19909
  );
19934
- console.log(chalk23.gray(` Cached at: ${result.fetchedAt}`));
19935
- console.log(chalk23.gray(` Server returned 304 (no changes since last sync)`));
19910
+ console.log(chalk22.gray(` Cached at: ${result.fetchedAt}`));
19911
+ console.log(chalk22.gray(` Server returned 304 (no changes since last sync)`));
19936
19912
  } else {
19937
19913
  console.log(
19938
- chalk23.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
19914
+ chalk22.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
19939
19915
  );
19940
- console.log(chalk23.gray(` Cached at: ${result.fetchedAt}`));
19941
- console.log(chalk23.gray(` File: ~/.node9/rules-cache.json`));
19916
+ console.log(chalk22.gray(` Cached at: ${result.fetchedAt}`));
19917
+ console.log(chalk22.gray(` File: ~/.node9/rules-cache.json`));
19942
19918
  }
19943
19919
  });
19944
19920
  policy.command("show").description("List all cloud policy rules in the local cache").action(() => {
19945
19921
  const status = getCloudSyncStatus();
19946
19922
  if (!status.cached) {
19947
- console.log(chalk23.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
19923
+ console.log(chalk22.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
19948
19924
  return;
19949
19925
  }
19950
19926
  const rules = getCloudRules() ?? [];
19951
19927
  const age = Math.round((Date.now() - new Date(status.fetchedAt).getTime()) / 6e4);
19952
19928
  console.log(
19953
- chalk23.bold(`
19954
- Cloud policy rules`) + chalk23.gray(
19929
+ chalk22.bold(`
19930
+ Cloud policy rules`) + chalk22.gray(
19955
19931
  ` (${rules.length} rule${rules.length === 1 ? "" : "s"}, synced ${age}m ago)
19956
19932
  `
19957
19933
  )
19958
19934
  );
19959
19935
  if (rules.length === 0) {
19960
- console.log(chalk23.gray(" No rules defined in cloud policy.\n"));
19936
+ console.log(chalk22.gray(" No rules defined in cloud policy.\n"));
19961
19937
  return;
19962
19938
  }
19963
19939
  for (const rule of rules) {
19964
19940
  const r = rule;
19965
- const verdictColor = r.verdict === "block" ? chalk23.red : r.verdict === "allow" ? chalk23.green : chalk23.yellow;
19941
+ const verdictColor = r.verdict === "block" ? chalk22.red : r.verdict === "allow" ? chalk22.green : chalk22.yellow;
19966
19942
  console.log(
19967
19943
  ` ${verdictColor(
19968
19944
  String(r.verdict ?? "unknown").toUpperCase().padEnd(6)
19969
- )} ${chalk23.white(String(r.name ?? "(unnamed)"))}`
19945
+ )} ${chalk22.white(String(r.name ?? "(unnamed)"))}`
19970
19946
  );
19971
- if (r.reason) console.log(chalk23.gray(` ${String(r.reason)}`));
19947
+ if (r.reason) console.log(chalk22.gray(` ${String(r.reason)}`));
19972
19948
  }
19973
19949
  console.log("");
19974
19950
  });
19975
19951
  policy.command("status").description("Show current cloud policy cache status").action(() => {
19976
19952
  const s = getCloudSyncStatus();
19977
19953
  if (!s.cached) {
19978
- console.log(chalk23.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
19954
+ console.log(chalk22.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
19979
19955
  return;
19980
19956
  }
19981
19957
  const age = Math.round((Date.now() - new Date(s.fetchedAt).getTime()) / 6e4);
19982
19958
  console.log(`
19983
- Rules : ${chalk23.green(String(s.rules))} cloud rules loaded`);
19959
+ Rules : ${chalk22.green(String(s.rules))} cloud rules loaded`);
19984
19960
  console.log(
19985
- ` Synced : ${chalk23.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
19961
+ ` Synced : ${chalk22.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
19986
19962
  );
19987
19963
  if (s.workspaceId) {
19988
- console.log(` Workspace: ${chalk23.gray(s.workspaceId)}`);
19964
+ console.log(` Workspace: ${chalk22.gray(s.workspaceId)}`);
19989
19965
  }
19990
19966
  if (s.panicMode) {
19991
19967
  console.log(
19992
- ` ${chalk23.red.bold("\u{1F6A8} Panic mode : ON")} ` + chalk23.dim("(every review-verdict becomes block)")
19968
+ ` ${chalk22.red.bold("\u{1F6A8} Panic mode : ON")} ` + chalk22.dim("(every review-verdict becomes block)")
19993
19969
  );
19994
19970
  }
19995
19971
  if (s.shadowMode) {
19996
19972
  console.log(
19997
- ` ${chalk23.yellow.bold("\u{1F441} Shadow mode : ON")} ` + chalk23.dim("(blocks become would-block log entries)")
19973
+ ` ${chalk22.yellow.bold("\u{1F441} Shadow mode : ON")} ` + chalk22.dim("(blocks become would-block log entries)")
19998
19974
  );
19999
19975
  }
20000
19976
  if (s.syncIntervalHours) {
20001
19977
  console.log(
20002
- chalk23.gray(
19978
+ chalk22.gray(
20003
19979
  ` Polling : every ${s.syncIntervalHours} hour${s.syncIntervalHours === 1 ? "" : "s"}`
20004
19980
  )
20005
19981
  );
@@ -20010,7 +19986,7 @@ function registerSyncCommand(program2) {
20010
19986
 
20011
19987
  // src/cli/commands/agents.ts
20012
19988
  init_setup();
20013
- import chalk24 from "chalk";
19989
+ import chalk23 from "chalk";
20014
19990
  var SETUP_FN = {
20015
19991
  claude: setupClaude,
20016
19992
  gemini: setupGemini,
@@ -20039,23 +20015,23 @@ function registerAgentsCommand(program2) {
20039
20015
  console.log(` ${"Agent".padEnd(14)}${"Installed".padEnd(11)}${"Wired".padEnd(8)}Mode`);
20040
20016
  console.log(" " + "\u2500".repeat(44));
20041
20017
  for (const s of statuses) {
20042
- const installed = s.installed ? chalk24.green("\u2713") : chalk24.gray("\u2717");
20043
- const wired = !s.installed ? chalk24.gray("\u2014") : s.wired ? chalk24.green("\u2713") : chalk24.yellow("\u2717");
20044
- const mode = s.mode ? chalk24.gray(s.mode) : chalk24.gray("\u2014");
20045
- const hint = s.installed && !s.wired ? chalk24.gray(` \u2190 node9 agents add ${s.name}`) : "";
20018
+ const installed = s.installed ? chalk23.green("\u2713") : chalk23.gray("\u2717");
20019
+ const wired = !s.installed ? chalk23.gray("\u2014") : s.wired ? chalk23.green("\u2713") : chalk23.yellow("\u2717");
20020
+ const mode = s.mode ? chalk23.gray(s.mode) : chalk23.gray("\u2014");
20021
+ const hint = s.installed && !s.wired ? chalk23.gray(` \u2190 node9 agents add ${s.name}`) : "";
20046
20022
  console.log(` ${s.label.padEnd(14)}${installed} ${wired} ${mode}${hint}`);
20047
20023
  }
20048
20024
  console.log("");
20049
20025
  if (!anyInstalled) {
20050
20026
  console.log(
20051
- chalk24.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + chalk24.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
20027
+ chalk23.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + chalk23.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
20052
20028
  );
20053
20029
  return;
20054
20030
  }
20055
20031
  const unwired = statuses.filter((s) => s.installed && !s.wired);
20056
20032
  if (unwired.length > 0) {
20057
20033
  console.log(
20058
- chalk24.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + chalk24.white(`node9 agents add ${unwired[0].name}`) + "\n"
20034
+ chalk23.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + chalk23.white(`node9 agents add ${unwired[0].name}`) + "\n"
20059
20035
  );
20060
20036
  }
20061
20037
  });
@@ -20063,7 +20039,7 @@ function registerAgentsCommand(program2) {
20063
20039
  const name = agent.toLowerCase();
20064
20040
  const fn = SETUP_FN[name];
20065
20041
  if (!fn) {
20066
- console.error(chalk24.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
20042
+ console.error(chalk23.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
20067
20043
  process.exit(1);
20068
20044
  }
20069
20045
  await fn();
@@ -20072,14 +20048,14 @@ function registerAgentsCommand(program2) {
20072
20048
  const name = agent.toLowerCase();
20073
20049
  const fn = TEARDOWN_FN[name];
20074
20050
  if (!fn) {
20075
- console.error(chalk24.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
20051
+ console.error(chalk23.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
20076
20052
  process.exit(1);
20077
20053
  }
20078
- console.log(chalk24.cyan(`
20054
+ console.log(chalk23.cyan(`
20079
20055
  \u{1F6E1}\uFE0F Node9: removing from ${name}...
20080
20056
  `));
20081
20057
  fn();
20082
- console.log(chalk24.gray("\n Restart the agent for changes to take effect."));
20058
+ console.log(chalk23.gray("\n Restart the agent for changes to take effect."));
20083
20059
  });
20084
20060
  }
20085
20061
 
@@ -20087,7 +20063,7 @@ function registerAgentsCommand(program2) {
20087
20063
  init_scan();
20088
20064
 
20089
20065
  // src/cli/commands/sessions.ts
20090
- import chalk25 from "chalk";
20066
+ import chalk24 from "chalk";
20091
20067
  import fs40 from "fs";
20092
20068
  import path42 from "path";
20093
20069
  import os36 from "os";
@@ -20596,11 +20572,11 @@ function toolInputSummary(tool, input) {
20596
20572
  }
20597
20573
  function toolColor(tool) {
20598
20574
  const t = tool.toLowerCase();
20599
- if (t === "bash" || t === "execute_bash") return chalk25.red;
20600
- if (t === "write") return chalk25.green;
20601
- if (t === "edit" || t === "notebookedit") return chalk25.yellow;
20602
- if (t === "read") return chalk25.cyan;
20603
- return chalk25.gray;
20575
+ if (t === "bash" || t === "execute_bash") return chalk24.red;
20576
+ if (t === "write") return chalk24.green;
20577
+ if (t === "edit" || t === "notebookedit") return chalk24.yellow;
20578
+ if (t === "read") return chalk24.cyan;
20579
+ return chalk24.gray;
20604
20580
  }
20605
20581
  function barStr2(value, max, width) {
20606
20582
  if (max === 0 || width <= 0) return "\u2591".repeat(width);
@@ -20610,7 +20586,7 @@ function barStr2(value, max, width) {
20610
20586
  function colorBar2(value, max, width) {
20611
20587
  const s = barStr2(value, max, width);
20612
20588
  const filled = Math.max(1, Math.round(max > 0 ? value / max * width : 0));
20613
- return chalk25.cyan(s.slice(0, filled)) + chalk25.dim(s.slice(filled));
20589
+ return chalk24.cyan(s.slice(0, filled)) + chalk24.dim(s.slice(filled));
20614
20590
  }
20615
20591
  function renderSummary(summaries) {
20616
20592
  const totalTools = summaries.reduce((n, s) => n + s.toolCalls.length, 0);
@@ -20640,45 +20616,45 @@ function renderSummary(summaries) {
20640
20616
  }
20641
20617
  const topProjects = [...projCosts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
20642
20618
  const W = 20;
20643
- console.log(chalk25.dim(" " + "\u2500".repeat(70)));
20619
+ console.log(chalk24.dim(" " + "\u2500".repeat(70)));
20644
20620
  console.log(
20645
- " " + chalk25.bold.white(String(summaries.length).padEnd(4)) + chalk25.dim("sessions ") + chalk25.bold.yellow(fmtCost3(totalCost).padEnd(10)) + chalk25.dim("total ") + chalk25.bold.white(String(totalTools).padEnd(6)) + chalk25.dim("tool calls ") + chalk25.bold.white(String(totalFiles)) + chalk25.dim(" files modified") + (totalBlocked > 0 ? chalk25.dim(" ") + chalk25.red.bold(String(totalBlocked)) + chalk25.dim(" blocked by node9") : "")
20621
+ " " + chalk24.bold.white(String(summaries.length).padEnd(4)) + chalk24.dim("sessions ") + chalk24.bold.yellow(fmtCost3(totalCost).padEnd(10)) + chalk24.dim("total ") + chalk24.bold.white(String(totalTools).padEnd(6)) + chalk24.dim("tool calls ") + chalk24.bold.white(String(totalFiles)) + chalk24.dim(" files modified") + (totalBlocked > 0 ? chalk24.dim(" ") + chalk24.red.bold(String(totalBlocked)) + chalk24.dim(" blocked by node9") : "")
20646
20622
  );
20647
20623
  console.log(
20648
- " " + chalk25.dim("avg ") + chalk25.white(fmtCost3(avgCost).padEnd(10)) + chalk25.dim("/session ") + chalk25.green(String(snapshots)) + chalk25.dim(` of ${summaries.length} sessions had snapshots`)
20624
+ " " + chalk24.dim("avg ") + chalk24.white(fmtCost3(avgCost).padEnd(10)) + chalk24.dim("/session ") + chalk24.green(String(snapshots)) + chalk24.dim(` of ${summaries.length} sessions had snapshots`)
20649
20625
  );
20650
20626
  console.log("");
20651
- console.log(" " + chalk25.dim("Tool breakdown:"));
20627
+ console.log(" " + chalk24.dim("Tool breakdown:"));
20652
20628
  const maxGroup = Math.max(...Object.values(groups));
20653
20629
  for (const [label, count] of Object.entries(groups)) {
20654
20630
  if (count === 0) continue;
20655
20631
  const pct = totalTools > 0 ? Math.round(count / totalTools * 100) : 0;
20656
20632
  console.log(
20657
- " " + label.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + chalk25.white(String(count).padStart(4)) + chalk25.dim(` (${String(pct)}%)`)
20633
+ " " + label.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + chalk24.white(String(count).padStart(4)) + chalk24.dim(` (${String(pct)}%)`)
20658
20634
  );
20659
20635
  }
20660
20636
  console.log("");
20661
20637
  if (topProjects.length > 1) {
20662
- console.log(" " + chalk25.dim("Cost by project:"));
20638
+ console.log(" " + chalk24.dim("Cost by project:"));
20663
20639
  const maxProjCost = topProjects[0][1];
20664
20640
  for (const [proj, cost] of topProjects) {
20665
20641
  console.log(
20666
- " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + chalk25.yellow(fmtCost3(cost))
20642
+ " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + chalk24.yellow(fmtCost3(cost))
20667
20643
  );
20668
20644
  }
20669
20645
  console.log("");
20670
20646
  }
20671
- console.log(chalk25.dim(" " + "\u2500".repeat(70)));
20647
+ console.log(chalk24.dim(" " + "\u2500".repeat(70)));
20672
20648
  console.log("");
20673
20649
  }
20674
20650
  function renderList(summaries, totalCost) {
20675
20651
  if (summaries.length === 0) {
20676
- console.log(chalk25.yellow(" No sessions found in the requested range.\n"));
20652
+ console.log(chalk24.yellow(" No sessions found in the requested range.\n"));
20677
20653
  return;
20678
20654
  }
20679
- const totalLabel = totalCost > 0 ? chalk25.dim(" ~" + fmtCost3(totalCost) + " total") : "";
20655
+ const totalLabel = totalCost > 0 ? chalk24.dim(" ~" + fmtCost3(totalCost) + " total") : "";
20680
20656
  console.log(
20681
- " " + chalk25.white(String(summaries.length)) + chalk25.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
20657
+ " " + chalk24.white(String(summaries.length)) + chalk24.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
20682
20658
  );
20683
20659
  console.log("");
20684
20660
  let lastGroup = "";
@@ -20686,49 +20662,49 @@ function renderList(summaries, totalCost) {
20686
20662
  const activeDate = fmtDate2(s.lastActiveTime);
20687
20663
  const group = activeDate + " " + s.projectLabel;
20688
20664
  if (group !== lastGroup) {
20689
- console.log(chalk25.dim(" \u2500\u2500\u2500 ") + chalk25.bold(activeDate) + chalk25.dim(" " + s.projectLabel));
20665
+ console.log(chalk24.dim(" \u2500\u2500\u2500 ") + chalk24.bold(activeDate) + chalk24.dim(" " + s.projectLabel));
20690
20666
  lastGroup = group;
20691
20667
  }
20692
20668
  const startDate = fmtDate2(s.startTime);
20693
- const dateRange = startDate !== activeDate ? chalk25.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
20694
- const timeStr = chalk25.dim(fmtTime(s.startTime));
20695
- const prompt = chalk25.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
20696
- const tools = s.toolCalls.length > 0 ? chalk25.dim(String(s.toolCalls.length).padStart(3) + " tools") : chalk25.dim(" 0 tools");
20697
- const cost = s.costUSD > 0 ? chalk25.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
20698
- const blocked = s.blockedCalls.length > 0 ? chalk25.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
20699
- const snap = s.hasSnapshot ? chalk25.green(" \u{1F4F8}") : "";
20700
- const agentBadge = s.agent === "gemini" ? chalk25.blue(" [Gemini]") : s.agent === "codex" ? chalk25.magenta(" [Codex]") : chalk25.cyan(" [Claude]");
20701
- const sid = chalk25.dim(" " + s.sessionId.slice(0, 8));
20669
+ const dateRange = startDate !== activeDate ? chalk24.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
20670
+ const timeStr = chalk24.dim(fmtTime(s.startTime));
20671
+ const prompt = chalk24.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
20672
+ const tools = s.toolCalls.length > 0 ? chalk24.dim(String(s.toolCalls.length).padStart(3) + " tools") : chalk24.dim(" 0 tools");
20673
+ const cost = s.costUSD > 0 ? chalk24.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
20674
+ const blocked = s.blockedCalls.length > 0 ? chalk24.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
20675
+ const snap = s.hasSnapshot ? chalk24.green(" \u{1F4F8}") : "";
20676
+ const agentBadge = s.agent === "gemini" ? chalk24.blue(" [Gemini]") : s.agent === "codex" ? chalk24.magenta(" [Codex]") : chalk24.cyan(" [Claude]");
20677
+ const sid = chalk24.dim(" " + s.sessionId.slice(0, 8));
20702
20678
  console.log(
20703
20679
  ` ${timeStr} ${prompt} ${tools}${cost}${blocked}${snap}${agentBadge}${sid}${dateRange}`
20704
20680
  );
20705
20681
  }
20706
20682
  console.log("");
20707
20683
  console.log(
20708
- chalk25.dim(" Run") + " " + chalk25.cyan("node9 sessions --detail <session-id>") + chalk25.dim(" for full tool trace.")
20684
+ chalk24.dim(" Run") + " " + chalk24.cyan("node9 sessions --detail <session-id>") + chalk24.dim(" for full tool trace.")
20709
20685
  );
20710
20686
  console.log("");
20711
20687
  }
20712
20688
  function renderDetail(s) {
20713
20689
  console.log("");
20714
- console.log(chalk25.bold(" Session ") + chalk25.dim(s.sessionId));
20690
+ console.log(chalk24.bold(" Session ") + chalk24.dim(s.sessionId));
20715
20691
  console.log(
20716
- chalk25.bold(" Prompt ") + chalk25.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
20692
+ chalk24.bold(" Prompt ") + chalk24.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
20717
20693
  );
20718
- console.log(chalk25.bold(" Project ") + chalk25.white(s.projectLabel));
20694
+ console.log(chalk24.bold(" Project ") + chalk24.white(s.projectLabel));
20719
20695
  if (s.agent) {
20720
- const agentLabel2 = s.agent === "gemini" ? chalk25.blue("Gemini CLI") : s.agent === "codex" ? chalk25.magenta("Codex") : chalk25.cyan("Claude Code");
20721
- console.log(chalk25.bold(" Agent ") + agentLabel2);
20696
+ const agentLabel2 = s.agent === "gemini" ? chalk24.blue("Gemini CLI") : s.agent === "codex" ? chalk24.magenta("Codex") : chalk24.cyan("Claude Code");
20697
+ console.log(chalk24.bold(" Agent ") + agentLabel2);
20722
20698
  }
20723
- console.log(chalk25.bold(" When ") + chalk25.white(fmtDateTime(s.startTime)));
20699
+ console.log(chalk24.bold(" When ") + chalk24.white(fmtDateTime(s.startTime)));
20724
20700
  if (s.costUSD > 0)
20725
- console.log(chalk25.bold(" Cost ") + chalk25.yellow("~" + fmtCost3(s.costUSD)));
20701
+ console.log(chalk24.bold(" Cost ") + chalk24.yellow("~" + fmtCost3(s.costUSD)));
20726
20702
  console.log(
20727
- chalk25.bold(" Snapshot ") + (s.hasSnapshot ? chalk25.green("\u2713 taken") : chalk25.dim("none"))
20703
+ chalk24.bold(" Snapshot ") + (s.hasSnapshot ? chalk24.green("\u2713 taken") : chalk24.dim("none"))
20728
20704
  );
20729
20705
  console.log("");
20730
20706
  if (s.toolCalls.length === 0 && s.blockedCalls.length === 0) {
20731
- console.log(chalk25.dim(" No tool calls recorded.\n"));
20707
+ console.log(chalk24.dim(" No tool calls recorded.\n"));
20732
20708
  return;
20733
20709
  }
20734
20710
  const timeline = [
@@ -20741,32 +20717,32 @@ function renderDetail(s) {
20741
20717
  });
20742
20718
  const headerParts = [`Tool calls (${s.toolCalls.length})`];
20743
20719
  if (s.blockedCalls.length > 0)
20744
- headerParts.push(chalk25.red(`${s.blockedCalls.length} blocked by node9`));
20745
- console.log(chalk25.bold(" " + headerParts.join(" \xB7 ")));
20720
+ headerParts.push(chalk24.red(`${s.blockedCalls.length} blocked by node9`));
20721
+ console.log(chalk24.bold(" " + headerParts.join(" \xB7 ")));
20746
20722
  console.log("");
20747
20723
  for (const entry of timeline) {
20748
20724
  if (entry.kind === "tool") {
20749
20725
  const tc = entry.tc;
20750
20726
  const colorFn = toolColor(tc.tool);
20751
20727
  const toolPad = colorFn(tc.tool.padEnd(16));
20752
- const detail = chalk25.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
20753
- const ts = tc.timestamp ? chalk25.dim(fmtTime(tc.timestamp) + " ") : " ";
20728
+ const detail = chalk24.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
20729
+ const ts = tc.timestamp ? chalk24.dim(fmtTime(tc.timestamp) + " ") : " ";
20754
20730
  console.log(` ${ts}${toolPad} ${detail}`);
20755
20731
  } else {
20756
20732
  const bc = entry.bc;
20757
- const ts = bc.timestamp ? chalk25.dim(fmtTime(bc.timestamp) + " ") : " ";
20758
- const label = chalk25.red("\u{1F6D1} BLOCKED".padEnd(16));
20759
- const toolName = chalk25.red(bc.tool.padEnd(10));
20760
- const argsSummary = bc.args ? chalk25.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : chalk25.dim("[args not logged]");
20761
- const reason = bc.checkedBy ? chalk25.dim(" \u2190 " + bc.checkedBy) : "";
20733
+ const ts = bc.timestamp ? chalk24.dim(fmtTime(bc.timestamp) + " ") : " ";
20734
+ const label = chalk24.red("\u{1F6D1} BLOCKED".padEnd(16));
20735
+ const toolName = chalk24.red(bc.tool.padEnd(10));
20736
+ const argsSummary = bc.args ? chalk24.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : chalk24.dim("[args not logged]");
20737
+ const reason = bc.checkedBy ? chalk24.dim(" \u2190 " + bc.checkedBy) : "";
20762
20738
  console.log(` ${ts}${label} ${toolName} ${argsSummary}${reason}`);
20763
20739
  }
20764
20740
  }
20765
20741
  console.log("");
20766
20742
  if (s.modifiedFiles.length > 0) {
20767
- console.log(chalk25.bold(` Files modified (${s.modifiedFiles.length}):`));
20743
+ console.log(chalk24.bold(` Files modified (${s.modifiedFiles.length}):`));
20768
20744
  for (const f of s.modifiedFiles) {
20769
- console.log(" " + chalk25.yellow(f));
20745
+ console.log(" " + chalk24.yellow(f));
20770
20746
  }
20771
20747
  console.log("");
20772
20748
  }
@@ -20774,19 +20750,19 @@ function renderDetail(s) {
20774
20750
  function registerSessionsCommand(program2) {
20775
20751
  program2.command("sessions").description("Show what your AI agent did \u2014 sessions, tool calls, cost, and file changes").option("--all", "Show all sessions (default: last 7 days)").option("--days <n>", "Show last N days of sessions", "7").option("--detail <sessionId>", "Show full tool trace for a session").action((options) => {
20776
20752
  console.log("");
20777
- console.log(chalk25.cyan.bold("\u{1F4CB} node9 sessions") + chalk25.dim(" \u2014 what your AI agent did"));
20753
+ console.log(chalk24.cyan.bold("\u{1F4CB} node9 sessions") + chalk24.dim(" \u2014 what your AI agent did"));
20778
20754
  console.log("");
20779
20755
  const historyPath = path42.join(os36.homedir(), ".claude", "history.jsonl");
20780
20756
  if (!fs40.existsSync(historyPath)) {
20781
- console.log(chalk25.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
20782
- console.log(chalk25.gray(" Install Claude Code, run a few sessions, then try again.\n"));
20757
+ console.log(chalk24.yellow(" No Claude session history found at ~/.claude/history.jsonl"));
20758
+ console.log(chalk24.gray(" Install Claude Code, run a few sessions, then try again.\n"));
20783
20759
  return;
20784
20760
  }
20785
20761
  const days = options.detail || options.all ? null : Math.max(1, parseInt(options.days, 10) || 7);
20786
20762
  const rangeLabel = options.detail ? "all time" : options.all ? "all time" : `last ${String(days)} days`;
20787
- console.log(chalk25.dim(" " + rangeLabel));
20763
+ console.log(chalk24.dim(" " + rangeLabel));
20788
20764
  console.log("");
20789
- process.stdout.write(chalk25.dim(" Loading\u2026"));
20765
+ process.stdout.write(chalk24.dim(" Loading\u2026"));
20790
20766
  const summaries = buildSessions(days);
20791
20767
  if (process.stdout.isTTY) {
20792
20768
  process.stdout.clearLine(0);
@@ -20799,8 +20775,8 @@ function registerSessionsCommand(program2) {
20799
20775
  (s) => s.sessionId === options.detail || s.sessionId.startsWith(options.detail)
20800
20776
  );
20801
20777
  if (!target) {
20802
- console.log(chalk25.red(` Session not found: ${options.detail}`));
20803
- console.log(chalk25.dim(" Run `node9 sessions` to list recent sessions.\n"));
20778
+ console.log(chalk24.red(` Session not found: ${options.detail}`));
20779
+ console.log(chalk24.dim(" Run `node9 sessions` to list recent sessions.\n"));
20804
20780
  return;
20805
20781
  }
20806
20782
  renderDetail(target);
@@ -20813,7 +20789,7 @@ function registerSessionsCommand(program2) {
20813
20789
  }
20814
20790
 
20815
20791
  // src/cli/commands/skill-pin.ts
20816
- import chalk26 from "chalk";
20792
+ import chalk25 from "chalk";
20817
20793
  import fs41 from "fs";
20818
20794
  import os37 from "os";
20819
20795
  import path43 from "path";
@@ -20833,29 +20809,29 @@ function registerSkillPinCommand(program2) {
20833
20809
  const result = readSkillPinsSafe();
20834
20810
  if (!result.ok) {
20835
20811
  if (result.reason === "missing") {
20836
- console.log(chalk26.gray("\nNo skill roots are pinned yet."));
20812
+ console.log(chalk25.gray("\nNo skill roots are pinned yet."));
20837
20813
  console.log(
20838
- chalk26.gray("Pins are created automatically on the first tool call of each session.\n")
20814
+ chalk25.gray("Pins are created automatically on the first tool call of each session.\n")
20839
20815
  );
20840
20816
  return;
20841
20817
  }
20842
- console.error(chalk26.red(`
20818
+ console.error(chalk25.red(`
20843
20819
  \u274C Pin file is corrupt: ${result.detail}`));
20844
- console.error(chalk26.yellow(" Run: node9 skill pin reset\n"));
20820
+ console.error(chalk25.yellow(" Run: node9 skill pin reset\n"));
20845
20821
  process.exit(1);
20846
20822
  }
20847
20823
  const entries = Object.entries(result.pins.roots);
20848
20824
  if (entries.length === 0) {
20849
- console.log(chalk26.gray("\nNo skill roots are pinned yet.\n"));
20825
+ console.log(chalk25.gray("\nNo skill roots are pinned yet.\n"));
20850
20826
  return;
20851
20827
  }
20852
- console.log(chalk26.bold("\n\u{1F512} Pinned Skill Roots\n"));
20828
+ console.log(chalk25.bold("\n\u{1F512} Pinned Skill Roots\n"));
20853
20829
  for (const [key, entry] of entries) {
20854
- const missing = entry.exists ? "" : chalk26.yellow(" (not present at pin time)");
20855
- console.log(` ${chalk26.cyan(key)} ${chalk26.gray(entry.rootPath)}${missing}`);
20830
+ const missing = entry.exists ? "" : chalk25.yellow(" (not present at pin time)");
20831
+ console.log(` ${chalk25.cyan(key)} ${chalk25.gray(entry.rootPath)}${missing}`);
20856
20832
  console.log(` Files (${entry.fileCount})`);
20857
- console.log(` Hash: ${chalk26.gray(entry.contentHash.slice(0, 16))}...`);
20858
- console.log(` Pinned: ${chalk26.gray(entry.pinnedAt)}
20833
+ console.log(` Hash: ${chalk25.gray(entry.contentHash.slice(0, 16))}...`);
20834
+ console.log(` Pinned: ${chalk25.gray(entry.pinnedAt)}
20859
20835
  `);
20860
20836
  }
20861
20837
  });
@@ -20864,39 +20840,39 @@ function registerSkillPinCommand(program2) {
20864
20840
  try {
20865
20841
  pins = readSkillPins();
20866
20842
  } catch {
20867
- console.error(chalk26.red("\n\u274C Pin file is corrupt."));
20868
- console.error(chalk26.yellow(" Run: node9 skill pin reset\n"));
20843
+ console.error(chalk25.red("\n\u274C Pin file is corrupt."));
20844
+ console.error(chalk25.yellow(" Run: node9 skill pin reset\n"));
20869
20845
  process.exit(1);
20870
20846
  }
20871
20847
  if (!pins.roots[rootKey]) {
20872
- console.error(chalk26.red(`
20848
+ console.error(chalk25.red(`
20873
20849
  \u274C No pin found for root key "${rootKey}"
20874
20850
  `));
20875
- console.error(`Run ${chalk26.cyan("node9 skill pin list")} to see pinned roots.
20851
+ console.error(`Run ${chalk25.cyan("node9 skill pin list")} to see pinned roots.
20876
20852
  `);
20877
20853
  process.exit(1);
20878
20854
  }
20879
20855
  const rootPath = pins.roots[rootKey].rootPath;
20880
20856
  removePin(rootKey);
20881
20857
  wipeSkillSessions();
20882
- console.log(chalk26.green(`
20883
- \u{1F513} Pin removed for ${chalk26.cyan(rootKey)}`));
20884
- console.log(chalk26.gray(` ${rootPath}`));
20885
- console.log(chalk26.gray(" Next session will re-pin with current state.\n"));
20858
+ console.log(chalk25.green(`
20859
+ \u{1F513} Pin removed for ${chalk25.cyan(rootKey)}`));
20860
+ console.log(chalk25.gray(` ${rootPath}`));
20861
+ console.log(chalk25.gray(" Next session will re-pin with current state.\n"));
20886
20862
  });
20887
20863
  pinSubCmd.command("reset").description("Clear all skill pins and wipe session verification flags").action(() => {
20888
20864
  const result = readSkillPinsSafe();
20889
20865
  if (!result.ok && result.reason === "missing") {
20890
20866
  wipeSkillSessions();
20891
- console.log(chalk26.gray("\nNo pins to clear.\n"));
20867
+ console.log(chalk25.gray("\nNo pins to clear.\n"));
20892
20868
  return;
20893
20869
  }
20894
20870
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
20895
20871
  clearAllPins();
20896
20872
  wipeSkillSessions();
20897
- console.log(chalk26.green(`
20873
+ console.log(chalk25.green(`
20898
20874
  \u{1F513} Cleared ${count} skill pin(s).`));
20899
- console.log(chalk26.gray(" Next session will re-pin with current state.\n"));
20875
+ console.log(chalk25.gray(" Next session will re-pin with current state.\n"));
20900
20876
  });
20901
20877
  }
20902
20878
 
@@ -20904,7 +20880,7 @@ function registerSkillPinCommand(program2) {
20904
20880
  import fs42 from "fs";
20905
20881
  import os38 from "os";
20906
20882
  import path44 from "path";
20907
- import chalk27 from "chalk";
20883
+ import chalk26 from "chalk";
20908
20884
  var DECISIONS_FILE2 = path44.join(os38.homedir(), ".node9", "decisions.json");
20909
20885
  function readDecisions() {
20910
20886
  try {
@@ -20933,55 +20909,55 @@ function registerDecisionsCommand(program2) {
20933
20909
  const decisions = readDecisions();
20934
20910
  const entries = Object.entries(decisions);
20935
20911
  if (entries.length === 0) {
20936
- console.log(chalk27.gray(" No persistent decisions stored."));
20912
+ console.log(chalk26.gray(" No persistent decisions stored."));
20937
20913
  console.log(
20938
- chalk27.gray(` File: ${DECISIONS_FILE2}
20939
- `) + chalk27.gray(' Decisions are written when you click "Always Allow" or')
20914
+ chalk26.gray(` File: ${DECISIONS_FILE2}
20915
+ `) + chalk26.gray(' Decisions are written when you click "Always Allow" or')
20940
20916
  );
20941
- console.log(chalk27.gray(' "Always Deny" in node9 tail or the native popup.'));
20917
+ console.log(chalk26.gray(' "Always Deny" in node9 tail or the native popup.'));
20942
20918
  return;
20943
20919
  }
20944
- console.log(chalk27.bold(`
20920
+ console.log(chalk26.bold(`
20945
20921
  Persistent decisions (${entries.length})
20946
20922
  `));
20947
20923
  const w = Math.max(...entries.map(([k]) => k.length));
20948
20924
  for (const [tool, verdict] of entries.sort()) {
20949
- const colored = verdict === "allow" ? chalk27.green(verdict) : chalk27.red(verdict);
20925
+ const colored = verdict === "allow" ? chalk26.green(verdict) : chalk26.red(verdict);
20950
20926
  console.log(` ${tool.padEnd(w)} ${colored}`);
20951
20927
  }
20952
20928
  console.log(
20953
- chalk27.gray(`
20929
+ chalk26.gray(`
20954
20930
  Stored in ${DECISIONS_FILE2}
20955
- `) + chalk27.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
20931
+ `) + chalk26.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
20956
20932
  );
20957
20933
  });
20958
20934
  cmd.command("clear <toolName>").description("Remove a persistent decision for one tool").action((toolName) => {
20959
20935
  const decisions = readDecisions();
20960
20936
  if (!(toolName in decisions)) {
20961
- console.log(chalk27.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
20937
+ console.log(chalk26.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
20962
20938
  process.exitCode = 1;
20963
20939
  return;
20964
20940
  }
20965
20941
  delete decisions[toolName];
20966
20942
  writeDecisions(decisions);
20967
- console.log(chalk27.green(` \u2713 Cleared persistent decision for "${toolName}".`));
20943
+ console.log(chalk26.green(` \u2713 Cleared persistent decision for "${toolName}".`));
20968
20944
  });
20969
20945
  cmd.command("clear-all").description("Remove every persistent decision (irreversible)").action(() => {
20970
20946
  const decisions = readDecisions();
20971
20947
  const count = Object.keys(decisions).length;
20972
20948
  if (count === 0) {
20973
- console.log(chalk27.gray(" Nothing to clear \u2014 no persistent decisions stored."));
20949
+ console.log(chalk26.gray(" Nothing to clear \u2014 no persistent decisions stored."));
20974
20950
  return;
20975
20951
  }
20976
20952
  writeDecisions({});
20977
20953
  console.log(
20978
- chalk27.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
20954
+ chalk26.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
20979
20955
  );
20980
20956
  });
20981
20957
  }
20982
20958
 
20983
20959
  // src/cli/commands/dlp.ts
20984
- import chalk28 from "chalk";
20960
+ import chalk27 from "chalk";
20985
20961
  import fs43 from "fs";
20986
20962
  import path45 from "path";
20987
20963
  import os39 from "os";
@@ -21036,14 +21012,14 @@ function registerDlpCommand(program2) {
21036
21012
  cmd.command("resolve").description("Mark all current DLP findings as resolved").action(() => {
21037
21013
  const findings = loadDlpFindings();
21038
21014
  if (findings.length === 0) {
21039
- console.log(chalk28.green("\n \u2705 No response-DLP findings to resolve.\n"));
21015
+ console.log(chalk27.green("\n \u2705 No response-DLP findings to resolve.\n"));
21040
21016
  return;
21041
21017
  }
21042
21018
  const resolved = loadResolved();
21043
21019
  for (const e of findings) resolved.add(entryKey(e));
21044
21020
  saveResolved(resolved);
21045
21021
  console.log(
21046
- chalk28.green(
21022
+ chalk27.green(
21047
21023
  `
21048
21024
  \u2705 ${findings.length} finding${findings.length !== 1 ? "s" : ""} marked as resolved.
21049
21025
  `
@@ -21057,47 +21033,47 @@ function registerDlpCommand(program2) {
21057
21033
  const resolvedCount = findings.length - open.length;
21058
21034
  console.log("");
21059
21035
  console.log(
21060
- chalk28.bold.cyan("\u{1F510} node9 dlp") + chalk28.dim(" \u2014 secrets found in Claude response text")
21036
+ chalk27.bold.cyan("\u{1F510} node9 dlp") + chalk27.dim(" \u2014 secrets found in Claude response text")
21061
21037
  );
21062
21038
  console.log("");
21063
21039
  if (open.length === 0) {
21064
21040
  if (resolvedCount > 0) {
21065
- console.log(chalk28.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
21041
+ console.log(chalk27.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
21066
21042
  } else {
21067
21043
  console.log(
21068
- chalk28.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
21044
+ chalk27.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
21069
21045
  );
21070
21046
  }
21071
21047
  console.log("");
21072
21048
  return;
21073
21049
  }
21074
21050
  console.log(
21075
- chalk28.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + chalk28.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
21051
+ chalk27.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + chalk27.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
21076
21052
  );
21077
21053
  console.log("");
21078
21054
  console.log(
21079
- chalk28.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
21055
+ chalk27.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
21080
21056
  );
21081
- console.log(chalk28.dim(" Rotate each affected key immediately.\n"));
21057
+ console.log(chalk27.dim(" Rotate each affected key immediately.\n"));
21082
21058
  for (const e of open) {
21083
21059
  console.log(
21084
- " " + chalk28.red("\u25CF") + " " + chalk28.white(e.dlpPattern ?? "Secret") + chalk28.dim(" " + fmtDate3(e.ts))
21060
+ " " + chalk27.red("\u25CF") + " " + chalk27.white(e.dlpPattern ?? "Secret") + chalk27.dim(" " + fmtDate3(e.ts))
21085
21061
  );
21086
21062
  if (e.dlpSample) {
21087
- console.log(" " + chalk28.dim("Sample: ") + chalk28.yellow(stripAnsi(e.dlpSample)));
21063
+ console.log(" " + chalk27.dim("Sample: ") + chalk27.yellow(stripAnsi(e.dlpSample)));
21088
21064
  }
21089
21065
  if (e.project) {
21090
- console.log(" " + chalk28.dim("Project: ") + chalk28.dim(stripAnsi(e.project)));
21066
+ console.log(" " + chalk27.dim("Project: ") + chalk27.dim(stripAnsi(e.project)));
21091
21067
  }
21092
21068
  console.log("");
21093
21069
  }
21094
- console.log(" " + chalk28.bold("Next steps:"));
21095
- console.log(" " + chalk28.cyan("1.") + " Rotate any exposed keys shown above");
21070
+ console.log(" " + chalk27.bold("Next steps:"));
21071
+ console.log(" " + chalk27.cyan("1.") + " Rotate any exposed keys shown above");
21096
21072
  console.log(
21097
- " " + chalk28.cyan("2.") + " Run " + chalk28.white("node9 dlp resolve") + " to acknowledge"
21073
+ " " + chalk27.cyan("2.") + " Run " + chalk27.white("node9 dlp resolve") + " to acknowledge"
21098
21074
  );
21099
21075
  console.log(
21100
- " " + chalk28.cyan("3.") + " Run " + chalk28.white("node9 report") + " for full audit history"
21076
+ " " + chalk27.cyan("3.") + " Run " + chalk27.white("node9 report") + " for full audit history"
21101
21077
  );
21102
21078
  console.log("");
21103
21079
  });
@@ -21105,7 +21081,7 @@ function registerDlpCommand(program2) {
21105
21081
 
21106
21082
  // src/cli/commands/mask.ts
21107
21083
  init_dlp();
21108
- import chalk29 from "chalk";
21084
+ import chalk28 from "chalk";
21109
21085
  import fs44 from "fs";
21110
21086
  import path46 from "path";
21111
21087
  import os40 from "os";
@@ -21241,12 +21217,12 @@ function registerMaskCommand(program2) {
21241
21217
  }
21242
21218
  }) : allFiles;
21243
21219
  if (filtered.length === 0) {
21244
- console.log(chalk29.yellow(" No session files found."));
21220
+ console.log(chalk28.yellow(" No session files found."));
21245
21221
  return;
21246
21222
  }
21247
21223
  console.log("");
21248
21224
  if (dryRun) {
21249
- console.log(chalk29.dim(" Dry run \u2014 no files will be modified.\n"));
21225
+ console.log(chalk28.dim(" Dry run \u2014 no files will be modified.\n"));
21250
21226
  }
21251
21227
  let totalFiles = 0;
21252
21228
  let totalLines = 0;
@@ -21262,23 +21238,23 @@ function registerMaskCommand(program2) {
21262
21238
  });
21263
21239
  const verb = dryRun ? "Would redact" : "Redacted";
21264
21240
  console.log(
21265
- " " + chalk29.dim(shortPath.slice(0, 60).padEnd(62)) + chalk29.red(`${verb}: `) + chalk29.yellow(patterns.join(", ")) + chalk29.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
21241
+ " " + chalk28.dim(shortPath.slice(0, 60).padEnd(62)) + chalk28.red(`${verb}: `) + chalk28.yellow(patterns.join(", ")) + chalk28.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
21266
21242
  );
21267
21243
  }
21268
21244
  }
21269
21245
  console.log("");
21270
21246
  if (totalFiles === 0) {
21271
- console.log(chalk29.green(" No secrets found in session history."));
21247
+ console.log(chalk28.green(" No secrets found in session history."));
21272
21248
  } else {
21273
21249
  const verb = dryRun ? "would be modified" : "modified";
21274
21250
  console.log(
21275
- chalk29.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + chalk29.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
21251
+ chalk28.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + chalk28.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
21276
21252
  );
21277
- console.log(" Patterns: " + chalk29.yellow(totalPatterns.join(", ")));
21253
+ console.log(" Patterns: " + chalk28.yellow(totalPatterns.join(", ")));
21278
21254
  if (!dryRun) {
21279
21255
  console.log("");
21280
21256
  console.log(
21281
- chalk29.dim(
21257
+ chalk28.dim(
21282
21258
  " Note: secrets were already sent to the AI provider during the active session.\n This cleans your local disk only. Rotate any exposed keys."
21283
21259
  )
21284
21260
  );
@@ -21342,17 +21318,17 @@ program.command("login").argument("<apiKey>").option("--local", "Save key for au
21342
21318
  fs47.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
21343
21319
  }
21344
21320
  if (options.profile && profileName !== "default") {
21345
- console.log(chalk31.green(`\u2705 Profile "${profileName}" saved`));
21346
- console.log(chalk31.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
21321
+ console.log(chalk30.green(`\u2705 Profile "${profileName}" saved`));
21322
+ console.log(chalk30.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
21347
21323
  } else if (options.local) {
21348
- console.log(chalk31.green(`\u2705 Privacy mode \u{1F6E1}\uFE0F`));
21349
- console.log(chalk31.gray(` All decisions stay on this machine.`));
21324
+ console.log(chalk30.green(`\u2705 Privacy mode \u{1F6E1}\uFE0F`));
21325
+ console.log(chalk30.gray(` All decisions stay on this machine.`));
21350
21326
  } else {
21351
- console.log(chalk31.green(`\u2705 Logged in \u2014 agent mode`));
21352
- console.log(chalk31.gray(` Team policy enforced for all calls via Node9 cloud.`));
21327
+ console.log(chalk30.green(`\u2705 Logged in \u2014 agent mode`));
21328
+ console.log(chalk30.gray(` Team policy enforced for all calls via Node9 cloud.`));
21353
21329
  }
21354
21330
  });
21355
- program.command("addto").description("Integrate Node9 with an AI agent").addHelpText(
21331
+ program.command("addto", { hidden: true }).description("Integrate Node9 with an AI agent").addHelpText(
21356
21332
  "after",
21357
21333
  "\n Supported targets: claude gemini cursor codex windsurf vscode hud"
21358
21334
  ).argument(
@@ -21367,13 +21343,13 @@ program.command("addto").description("Integrate Node9 with an AI agent").addHelp
21367
21343
  if (target === "vscode") return await setupVSCode();
21368
21344
  if (target === "hud") return setupHud();
21369
21345
  console.error(
21370
- chalk31.red(
21346
+ chalk30.red(
21371
21347
  `Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hud`
21372
21348
  )
21373
21349
  );
21374
21350
  process.exit(1);
21375
21351
  });
21376
- program.command("setup").description('Alias for "addto" \u2014 integrate Node9 with an AI agent').addHelpText(
21352
+ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014 integrate Node9 with an AI agent').addHelpText(
21377
21353
  "after",
21378
21354
  "\n Supported targets: claude gemini cursor codex windsurf vscode hud"
21379
21355
  ).argument(
@@ -21381,17 +21357,17 @@ program.command("setup").description('Alias for "addto" \u2014 integrate Node9 w
21381
21357
  "The agent to protect: claude | gemini | cursor | codex | windsurf | vscode | hud"
21382
21358
  ).action(async (target) => {
21383
21359
  if (!target) {
21384
- console.log(chalk31.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
21385
- console.log(" Usage: " + chalk31.white("node9 setup <target>") + "\n");
21360
+ console.log(chalk30.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
21361
+ console.log(" Usage: " + chalk30.white("node9 setup <target>") + "\n");
21386
21362
  console.log(" Targets:");
21387
- console.log(" " + chalk31.green("claude") + " \u2014 Claude Code (hook mode)");
21388
- console.log(" " + chalk31.green("gemini") + " \u2014 Gemini CLI (hook mode)");
21389
- console.log(" " + chalk31.green("cursor") + " \u2014 Cursor (MCP proxy)");
21390
- console.log(" " + chalk31.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
21391
- console.log(" " + chalk31.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
21392
- console.log(" " + chalk31.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
21363
+ console.log(" " + chalk30.green("claude") + " \u2014 Claude Code (hook mode)");
21364
+ console.log(" " + chalk30.green("gemini") + " \u2014 Gemini CLI (hook mode)");
21365
+ console.log(" " + chalk30.green("cursor") + " \u2014 Cursor (MCP proxy)");
21366
+ console.log(" " + chalk30.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
21367
+ console.log(" " + chalk30.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
21368
+ console.log(" " + chalk30.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
21393
21369
  process.stdout.write(
21394
- " " + chalk31.green("hud") + " \u2014 Claude Code security statusline\n"
21370
+ " " + chalk30.green("hud") + " \u2014 Claude Code security statusline\n"
21395
21371
  );
21396
21372
  console.log("");
21397
21373
  return;
@@ -21405,13 +21381,13 @@ program.command("setup").description('Alias for "addto" \u2014 integrate Node9 w
21405
21381
  if (t === "vscode") return await setupVSCode();
21406
21382
  if (t === "hud") return setupHud();
21407
21383
  console.error(
21408
- chalk31.red(
21384
+ chalk30.red(
21409
21385
  `Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hud`
21410
21386
  )
21411
21387
  );
21412
21388
  process.exit(1);
21413
21389
  });
21414
- program.command("removefrom").description("Remove Node9 hooks from an AI agent configuration").addHelpText(
21390
+ program.command("removefrom", { hidden: true }).description("Remove Node9 hooks from an AI agent configuration").addHelpText(
21415
21391
  "after",
21416
21392
  "\n Supported targets: claude gemini cursor codex windsurf vscode hud"
21417
21393
  ).argument(
@@ -21428,33 +21404,33 @@ program.command("removefrom").description("Remove Node9 hooks from an AI agent c
21428
21404
  else if (target === "hud") fn = teardownHud;
21429
21405
  else {
21430
21406
  console.error(
21431
- chalk31.red(
21407
+ chalk30.red(
21432
21408
  `Unknown target: "${target}". Supported: claude, gemini, cursor, codex, windsurf, vscode, hud`
21433
21409
  )
21434
21410
  );
21435
21411
  process.exit(1);
21436
21412
  }
21437
- console.log(chalk31.cyan(`
21413
+ console.log(chalk30.cyan(`
21438
21414
  \u{1F6E1}\uFE0F Node9: removing hooks from ${target}...
21439
21415
  `));
21440
21416
  try {
21441
21417
  fn();
21442
21418
  } catch (err2) {
21443
- console.error(chalk31.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
21419
+ console.error(chalk30.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
21444
21420
  process.exit(1);
21445
21421
  }
21446
- console.log(chalk31.gray("\n Restart the agent for changes to take effect."));
21422
+ console.log(chalk30.gray("\n Restart the agent for changes to take effect."));
21447
21423
  });
21448
21424
  program.command("uninstall").description("Remove all Node9 hooks and optionally delete config files").option("--purge", "Also delete ~/.node9/ directory (config, audit log, credentials)").action(async (options) => {
21449
- console.log(chalk31.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
21450
- console.log(chalk31.bold("Stopping daemon..."));
21425
+ console.log(chalk30.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
21426
+ console.log(chalk30.bold("Stopping daemon..."));
21451
21427
  try {
21452
21428
  stopDaemon();
21453
- console.log(chalk31.green(" \u2705 Daemon stopped"));
21429
+ console.log(chalk30.green(" \u2705 Daemon stopped"));
21454
21430
  } catch {
21455
- console.log(chalk31.blue(" \u2139\uFE0F Daemon was not running"));
21431
+ console.log(chalk30.blue(" \u2139\uFE0F Daemon was not running"));
21456
21432
  }
21457
- console.log(chalk31.bold("\nRemoving hooks..."));
21433
+ console.log(chalk30.bold("\nRemoving hooks..."));
21458
21434
  let teardownFailed = false;
21459
21435
  for (const [label, fn] of [
21460
21436
  ["Claude", teardownClaude],
@@ -21469,7 +21445,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
21469
21445
  } catch (err2) {
21470
21446
  teardownFailed = true;
21471
21447
  console.error(
21472
- chalk31.red(
21448
+ chalk30.red(
21473
21449
  ` \u26A0\uFE0F Failed to remove ${label} hooks: ${err2 instanceof Error ? err2.message : String(err2)}`
21474
21450
  )
21475
21451
  );
@@ -21486,28 +21462,28 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
21486
21462
  fs47.rmSync(node9Dir, { recursive: true });
21487
21463
  if (fs47.existsSync(node9Dir)) {
21488
21464
  console.error(
21489
- chalk31.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
21465
+ chalk30.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
21490
21466
  );
21491
21467
  } else {
21492
- console.log(chalk31.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
21468
+ console.log(chalk30.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
21493
21469
  }
21494
21470
  } else {
21495
- console.log(chalk31.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
21471
+ console.log(chalk30.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
21496
21472
  }
21497
21473
  } else {
21498
- console.log(chalk31.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
21474
+ console.log(chalk30.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
21499
21475
  }
21500
21476
  } else {
21501
21477
  console.log(
21502
- chalk31.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
21478
+ chalk30.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
21503
21479
  );
21504
21480
  }
21505
21481
  if (teardownFailed) {
21506
- console.error(chalk31.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
21482
+ console.error(chalk30.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
21507
21483
  process.exit(1);
21508
21484
  }
21509
- console.log(chalk31.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g @node9/proxy"));
21510
- console.log(chalk31.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
21485
+ console.log(chalk30.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g @node9/proxy"));
21486
+ console.log(chalk30.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
21511
21487
  });
21512
21488
  registerDoctorCommand(program, version);
21513
21489
  program.command("explain").description(
@@ -21520,7 +21496,7 @@ program.command("explain").description(
21520
21496
  try {
21521
21497
  args = JSON.parse(trimmed);
21522
21498
  } catch {
21523
- console.error(chalk31.red(`
21499
+ console.error(chalk30.red(`
21524
21500
  \u274C Invalid JSON: ${trimmed}
21525
21501
  `));
21526
21502
  process.exit(1);
@@ -21531,54 +21507,54 @@ program.command("explain").description(
21531
21507
  }
21532
21508
  const result = await explainPolicy(tool, args);
21533
21509
  console.log("");
21534
- console.log(chalk31.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
21510
+ console.log(chalk30.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
21535
21511
  console.log("");
21536
- console.log(` ${chalk31.bold("Tool:")} ${chalk31.white(result.tool)}`);
21512
+ console.log(` ${chalk30.bold("Tool:")} ${chalk30.white(result.tool)}`);
21537
21513
  if (argsRaw) {
21538
21514
  const preview2 = argsRaw.length > 80 ? argsRaw.slice(0, 77) + "\u2026" : argsRaw;
21539
- console.log(` ${chalk31.bold("Input:")} ${chalk31.gray(preview2)}`);
21515
+ console.log(` ${chalk30.bold("Input:")} ${chalk30.gray(preview2)}`);
21540
21516
  }
21541
21517
  console.log("");
21542
- console.log(chalk31.bold("Config Sources (Waterfall):"));
21518
+ console.log(chalk30.bold("Config Sources (Waterfall):"));
21543
21519
  for (const tier of result.waterfall) {
21544
- const num3 = chalk31.gray(` ${tier.tier}.`);
21520
+ const num3 = chalk30.gray(` ${tier.tier}.`);
21545
21521
  const label = tier.label.padEnd(16);
21546
21522
  let statusStr;
21547
21523
  if (tier.tier === 1) {
21548
- statusStr = chalk31.gray(tier.note ?? "");
21524
+ statusStr = chalk30.gray(tier.note ?? "");
21549
21525
  } else if (tier.status === "active") {
21550
- const loc = tier.path ? chalk31.gray(tier.path) : "";
21551
- const note = tier.note ? chalk31.gray(`(${tier.note})`) : "";
21552
- statusStr = chalk31.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
21526
+ const loc = tier.path ? chalk30.gray(tier.path) : "";
21527
+ const note = tier.note ? chalk30.gray(`(${tier.note})`) : "";
21528
+ statusStr = chalk30.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
21553
21529
  } else {
21554
- statusStr = chalk31.gray("\u25CB " + (tier.note ?? "not found"));
21530
+ statusStr = chalk30.gray("\u25CB " + (tier.note ?? "not found"));
21555
21531
  }
21556
- console.log(`${num3} ${chalk31.white(label)} ${statusStr}`);
21532
+ console.log(`${num3} ${chalk30.white(label)} ${statusStr}`);
21557
21533
  }
21558
21534
  console.log("");
21559
- console.log(chalk31.bold("Policy Evaluation:"));
21535
+ console.log(chalk30.bold("Policy Evaluation:"));
21560
21536
  for (const step of result.steps) {
21561
21537
  const isFinal = step.isFinal;
21562
21538
  let icon;
21563
- if (step.outcome === "allow") icon = chalk31.green(" \u2705");
21564
- else if (step.outcome === "review") icon = chalk31.red(" \u{1F534}");
21565
- else if (step.outcome === "skip") icon = chalk31.gray(" \u2500 ");
21566
- else icon = chalk31.gray(" \u25CB ");
21539
+ if (step.outcome === "allow") icon = chalk30.green(" \u2705");
21540
+ else if (step.outcome === "review") icon = chalk30.red(" \u{1F534}");
21541
+ else if (step.outcome === "skip") icon = chalk30.gray(" \u2500 ");
21542
+ else icon = chalk30.gray(" \u25CB ");
21567
21543
  const name = step.name.padEnd(18);
21568
- const nameStr = isFinal ? chalk31.white.bold(name) : chalk31.white(name);
21569
- const detail = isFinal ? chalk31.white(step.detail) : chalk31.gray(step.detail);
21570
- const arrow = isFinal ? chalk31.yellow(" \u2190 STOP") : "";
21544
+ const nameStr = isFinal ? chalk30.white.bold(name) : chalk30.white(name);
21545
+ const detail = isFinal ? chalk30.white(step.detail) : chalk30.gray(step.detail);
21546
+ const arrow = isFinal ? chalk30.yellow(" \u2190 STOP") : "";
21571
21547
  console.log(`${icon} ${nameStr} ${detail}${arrow}`);
21572
21548
  }
21573
21549
  console.log("");
21574
21550
  if (result.decision === "allow") {
21575
- console.log(chalk31.green.bold(" Decision: \u2705 ALLOW") + chalk31.gray(" \u2014 no approval needed"));
21551
+ console.log(chalk30.green.bold(" Decision: \u2705 ALLOW") + chalk30.gray(" \u2014 no approval needed"));
21576
21552
  } else {
21577
21553
  console.log(
21578
- chalk31.red.bold(" Decision: \u{1F534} REVIEW") + chalk31.gray(" \u2014 human approval required")
21554
+ chalk30.red.bold(" Decision: \u{1F534} REVIEW") + chalk30.gray(" \u2014 human approval required")
21579
21555
  );
21580
21556
  if (result.blockedByLabel) {
21581
- console.log(chalk31.gray(` Reason: ${result.blockedByLabel}`));
21557
+ console.log(chalk30.gray(` Reason: ${result.blockedByLabel}`));
21582
21558
  }
21583
21559
  }
21584
21560
  console.log("");
@@ -21593,7 +21569,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
21593
21569
  try {
21594
21570
  await startTail2(options);
21595
21571
  } catch (err2) {
21596
- console.error(chalk31.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
21572
+ console.error(chalk30.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
21597
21573
  process.exit(1);
21598
21574
  }
21599
21575
  });
@@ -21604,11 +21580,10 @@ program.command("monitor").description("Live interactive dashboard \u2014 activi
21604
21580
  const mod = await dynamicImport(`file://${dashboardPath}`);
21605
21581
  await mod.startMonitor();
21606
21582
  } catch (err2) {
21607
- console.error(chalk31.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
21583
+ console.error(chalk30.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
21608
21584
  process.exit(1);
21609
21585
  }
21610
21586
  });
21611
- registerWatchCommand(program);
21612
21587
  registerMcpGatewayCommand(program);
21613
21588
  registerMcpServerCommand(program);
21614
21589
  registerMcpPinCommand(program);
@@ -21616,7 +21591,7 @@ registerSkillPinCommand(program);
21616
21591
  registerDecisionsCommand(program);
21617
21592
  registerCheckCommand(program);
21618
21593
  registerLogCommand(program);
21619
- program.command("hud").description("Render node9 security statusline (spawned by Claude Code statusLine)").addHelpText(
21594
+ program.command("hud", { hidden: true }).description("Render node9 security statusline (spawned by Claude Code statusLine)").addHelpText(
21620
21595
  "after",
21621
21596
  `
21622
21597
  Outputs up to 3 lines to stdout, then exits:
@@ -21660,7 +21635,7 @@ program.command("pause").description("Temporarily disable Node9 protection for a
21660
21635
  const ms = parseDuration(options.duration);
21661
21636
  if (ms === null) {
21662
21637
  console.error(
21663
- chalk31.red(`
21638
+ chalk30.red(`
21664
21639
  \u274C Invalid duration: "${options.duration}". Use format like 15m, 1h, 30s.
21665
21640
  `)
21666
21641
  );
@@ -21668,20 +21643,20 @@ program.command("pause").description("Temporarily disable Node9 protection for a
21668
21643
  }
21669
21644
  pauseNode9(ms, options.duration);
21670
21645
  const expiresAt = new Date(Date.now() + ms).toLocaleTimeString();
21671
- console.log(chalk31.yellow(`
21646
+ console.log(chalk30.yellow(`
21672
21647
  \u23F8 Node9 paused until ${expiresAt}`));
21673
- console.log(chalk31.gray(` All tool calls will be allowed without review.`));
21674
- console.log(chalk31.gray(` Run "node9 resume" to re-enable early.
21648
+ console.log(chalk30.gray(` All tool calls will be allowed without review.`));
21649
+ console.log(chalk30.gray(` Run "node9 resume" to re-enable early.
21675
21650
  `));
21676
21651
  });
21677
21652
  program.command("resume").description("Re-enable Node9 protection immediately").action(() => {
21678
21653
  const { paused } = checkPause();
21679
21654
  if (!paused) {
21680
- console.log(chalk31.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
21655
+ console.log(chalk30.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
21681
21656
  return;
21682
21657
  }
21683
21658
  resumeNode9();
21684
- console.log(chalk31.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
21659
+ console.log(chalk30.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
21685
21660
  });
21686
21661
  var HOOK_BASED_AGENTS = {
21687
21662
  claude: "claude",
@@ -21694,15 +21669,15 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
21694
21669
  if (HOOK_BASED_AGENTS[firstArg2] !== void 0) {
21695
21670
  const target = HOOK_BASED_AGENTS[firstArg2];
21696
21671
  console.error(
21697
- chalk31.yellow(`
21672
+ chalk30.yellow(`
21698
21673
  \u26A0\uFE0F Node9 proxy mode does not support "${target}" directly.`)
21699
21674
  );
21700
- console.error(chalk31.white(`
21675
+ console.error(chalk30.white(`
21701
21676
  "${target}" uses its own hook system. Use:`));
21702
21677
  console.error(
21703
- chalk31.green(` node9 addto ${target} `) + chalk31.gray("# one-time setup")
21678
+ chalk30.green(` node9 addto ${target} `) + chalk30.gray("# one-time setup")
21704
21679
  );
21705
- console.error(chalk31.green(` ${target} `) + chalk31.gray("# run normally"));
21680
+ console.error(chalk30.green(` ${target} `) + chalk30.gray("# run normally"));
21706
21681
  process.exit(1);
21707
21682
  }
21708
21683
  const runArgs = firstArg2 === "shell" ? commandArgs.slice(1) : commandArgs;
@@ -21719,7 +21694,7 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
21719
21694
  }
21720
21695
  );
21721
21696
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && getConfig().settings.autoStartDaemon) {
21722
- console.error(chalk31.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
21697
+ console.error(chalk30.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
21723
21698
  const daemonReady = await autoStartDaemonAndWait();
21724
21699
  if (daemonReady) result = await authorizeHeadless("shell", { command: fullCommand });
21725
21700
  }
@@ -21732,12 +21707,12 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
21732
21707
  }
21733
21708
  if (!result.approved) {
21734
21709
  console.error(
21735
- chalk31.red(`
21710
+ chalk30.red(`
21736
21711
  \u274C Node9 Blocked: ${result.reason || "Dangerous command detected."}`)
21737
21712
  );
21738
21713
  process.exit(1);
21739
21714
  }
21740
- console.error(chalk31.green("\n\u2705 Approved \u2014 running command...\n"));
21715
+ console.error(chalk30.green("\n\u2705 Approved \u2014 running command...\n"));
21741
21716
  await runProxy(fullCommand);
21742
21717
  } else {
21743
21718
  program.help();