@node9/proxy 1.51.0 → 1.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -240,8 +240,8 @@ function sanitizeConfig(raw) {
240
240
  }
241
241
  }
242
242
  const lines = result.error.issues.map((issue) => {
243
- const path65 = issue.path.length > 0 ? issue.path.join(".") : "root";
244
- return ` \u2022 ${path65}: ${issue.message}`;
243
+ const path66 = issue.path.length > 0 ? issue.path.join(".") : "root";
244
+ return ` \u2022 ${path66}: ${issue.message}`;
245
245
  });
246
246
  return {
247
247
  sanitized,
@@ -1362,9 +1362,9 @@ function matchesPattern(text, patterns) {
1362
1362
  const withoutDotSlash = text.replace(/^\.\//, "");
1363
1363
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1364
1364
  }
1365
- function getNestedValue(obj, path65) {
1365
+ function getNestedValue(obj, path66) {
1366
1366
  if (!obj || typeof obj !== "object") return null;
1367
- const segments = path65.split(".");
1367
+ const segments = path66.split(".");
1368
1368
  for (const seg of segments) {
1369
1369
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1370
1370
  }
@@ -4297,11 +4297,11 @@ function getGlobalSettings() {
4297
4297
  };
4298
4298
  }
4299
4299
  function getCredentials() {
4300
- const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
4300
+ const DEFAULT_API_URL3 = "https://api.node9.ai/api/v1/intercept";
4301
4301
  if (process.env.NODE9_API_KEY) {
4302
4302
  return {
4303
4303
  apiKey: process.env.NODE9_API_KEY,
4304
- apiUrl: process.env.NODE9_API_URL || DEFAULT_API_URL2
4304
+ apiUrl: process.env.NODE9_API_URL || DEFAULT_API_URL3
4305
4305
  };
4306
4306
  }
4307
4307
  try {
@@ -4313,13 +4313,13 @@ function getCredentials() {
4313
4313
  if (profile?.apiKey) {
4314
4314
  return {
4315
4315
  apiKey: profile.apiKey,
4316
- apiUrl: profile.apiUrl || DEFAULT_API_URL2
4316
+ apiUrl: profile.apiUrl || DEFAULT_API_URL3
4317
4317
  };
4318
4318
  }
4319
4319
  if (creds.apiKey) {
4320
4320
  return {
4321
4321
  apiKey: creds.apiKey,
4322
- apiUrl: creds.apiUrl || DEFAULT_API_URL2
4322
+ apiUrl: creds.apiUrl || DEFAULT_API_URL3
4323
4323
  };
4324
4324
  }
4325
4325
  }
@@ -7787,6 +7787,35 @@ var init_setup_pi_shim = __esm({
7787
7787
  });
7788
7788
 
7789
7789
  // src/setup.ts
7790
+ function isNonInteractive() {
7791
+ return process.env.NODE9_NONINTERACTIVE === "1";
7792
+ }
7793
+ async function confirm(opts) {
7794
+ if (isNonInteractive()) return opts.default ?? false;
7795
+ return (0, import_prompts.confirm)(opts);
7796
+ }
7797
+ async function setupAgent(agent) {
7798
+ if (agent === "claude") await setupClaude();
7799
+ else if (agent === "gemini") await setupGemini();
7800
+ else if (agent === "antigravity") await setupAntigravity();
7801
+ else if (agent === "copilot") await setupCopilot();
7802
+ else if (agent === "cursor") await setupCursor();
7803
+ else if (agent === "codex") await setupCodex();
7804
+ else if (agent === "windsurf") await setupWindsurf();
7805
+ else if (agent === "vscode") await setupVSCode();
7806
+ else if (agent === "claudeDesktop") await setupClaudeDesktop();
7807
+ else if (agent === "opencode") await setupOpencode();
7808
+ else if (agent === "pi") await setupPi();
7809
+ else if (agent === "hermes") setupHermes();
7810
+ }
7811
+ async function setupDetectedAgents() {
7812
+ const detected = detectAgents();
7813
+ const found = Object.keys(detected).filter((k) => detected[k]);
7814
+ for (const agent of found) {
7815
+ await setupAgent(agent);
7816
+ }
7817
+ return found;
7818
+ }
7790
7819
  function hasNode9McpServer(servers) {
7791
7820
  const entry = servers["node9"];
7792
7821
  return !!entry && entry.command === "node9" && Array.isArray(entry.args) && entry.args[0] === "mcp-server";
@@ -8107,7 +8136,7 @@ async function setupClaude() {
8107
8136
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8108
8137
  }
8109
8138
  console.log("");
8110
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8139
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
8111
8140
  if (proceed) {
8112
8141
  for (const { name, upstream } of serversToWrap) {
8113
8142
  servers[name] = {
@@ -8212,7 +8241,7 @@ async function setupGemini() {
8212
8241
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8213
8242
  }
8214
8243
  console.log("");
8215
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8244
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
8216
8245
  if (proceed) {
8217
8246
  for (const { name, upstream } of serversToWrap) {
8218
8247
  servers[name] = {
@@ -8338,7 +8367,7 @@ async function setupAntigravity() {
8338
8367
  " \u26A0\uFE0F Found node9 hooks for the legacy Gemini CLI in ~/.gemini/settings.json.\n Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18.\n Keep them only if you still use Gemini CLI (e.g. enterprise Code Assist)."
8339
8368
  )
8340
8369
  );
8341
- const clean = await (0, import_prompts.confirm)({
8370
+ const clean = await confirm({
8342
8371
  message: "Remove the legacy Gemini CLI hooks?",
8343
8372
  default: false
8344
8373
  });
@@ -8360,7 +8389,7 @@ async function setupAntigravity() {
8360
8389
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8361
8390
  }
8362
8391
  console.log("");
8363
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8392
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
8364
8393
  if (proceed) {
8365
8394
  for (const { name, upstream } of serversToWrap) {
8366
8395
  servers[name] = {
@@ -8505,7 +8534,7 @@ async function setupCopilot() {
8505
8534
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8506
8535
  }
8507
8536
  console.log("");
8508
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8537
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
8509
8538
  if (proceed) {
8510
8539
  for (const { name, upstream } of serversToWrap) {
8511
8540
  servers[name] = {
@@ -8706,7 +8735,7 @@ async function setupCursor() {
8706
8735
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8707
8736
  }
8708
8737
  console.log("");
8709
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8738
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
8710
8739
  if (proceed) {
8711
8740
  for (const { name, upstream } of serversToWrap) {
8712
8741
  servers[name] = {
@@ -8857,7 +8886,7 @@ async function setupCodex() {
8857
8886
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8858
8887
  }
8859
8888
  console.log("");
8860
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8889
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
8861
8890
  if (proceed) {
8862
8891
  for (const { name, upstream } of serversToWrap) {
8863
8892
  servers[name] = {
@@ -9034,7 +9063,7 @@ async function setupWindsurf() {
9034
9063
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
9035
9064
  }
9036
9065
  console.log("");
9037
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
9066
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
9038
9067
  if (proceed) {
9039
9068
  for (const { name, upstream } of serversToWrap) {
9040
9069
  servers[name] = {
@@ -9138,7 +9167,7 @@ async function setupVSCode() {
9138
9167
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
9139
9168
  }
9140
9169
  console.log("");
9141
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
9170
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
9142
9171
  if (proceed) {
9143
9172
  for (const { name, upstream } of serversToWrap) {
9144
9173
  servers[name] = {
@@ -9238,7 +9267,7 @@ async function setupClaudeDesktop() {
9238
9267
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
9239
9268
  }
9240
9269
  console.log("");
9241
- const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
9270
+ const proceed = await confirm({ message: "Wrap these MCP servers?", default: true });
9242
9271
  if (proceed) {
9243
9272
  for (const { name, upstream } of serversToWrap) {
9244
9273
  servers[name] = {
@@ -16880,7 +16909,7 @@ function readCredentials() {
16880
16909
  if (process.env.NODE9_API_KEY) {
16881
16910
  return {
16882
16911
  apiKey: process.env.NODE9_API_KEY,
16883
- apiUrl: process.env.NODE9_API_URL ?? DEFAULT_API_URL
16912
+ apiUrl: process.env.NODE9_API_URL ?? DEFAULT_API_URL2
16884
16913
  };
16885
16914
  }
16886
16915
  try {
@@ -16899,11 +16928,11 @@ function readCredentials() {
16899
16928
  // Anything else is taken as-is so users can override the full
16900
16929
  // URL via NODE9_API_URL or a non-standard apiUrl.
16901
16930
  /\/intercept$/.test(profile.apiUrl) ? profile.apiUrl + "/policies/sync" : profile.apiUrl
16902
- ) : DEFAULT_API_URL
16931
+ ) : DEFAULT_API_URL2
16903
16932
  };
16904
16933
  }
16905
16934
  if (typeof creds.apiKey === "string" && creds.apiKey.length > 0) {
16906
- return { apiKey: creds.apiKey, apiUrl: DEFAULT_API_URL };
16935
+ return { apiKey: creds.apiKey, apiUrl: DEFAULT_API_URL2 };
16907
16936
  }
16908
16937
  } catch {
16909
16938
  }
@@ -17251,7 +17280,7 @@ function startForensicBroadcast() {
17251
17280
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
17252
17281
  recurring.unref();
17253
17282
  }
17254
- var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17283
+ var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17255
17284
  var init_sync = __esm({
17256
17285
  "src/daemon/sync.ts"() {
17257
17286
  "use strict";
@@ -17283,7 +17312,7 @@ var init_sync = __esm({
17283
17312
  "long-output-redacted": "longOutputRedactions"
17284
17313
  };
17285
17314
  rulesCacheFile = () => import_path31.default.join(import_os29.default.homedir(), ".node9", "rules-cache.json");
17286
- DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
17315
+ DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept/policies/sync";
17287
17316
  DEFAULT_INTERVAL_HOURS = 5;
17288
17317
  MIN_INTERVAL_SECONDS = 15;
17289
17318
  MAX_INTERVAL_SECONDS = 24 * 60 * 60;
@@ -19085,10 +19114,10 @@ function readSessionUsage() {
19085
19114
  }
19086
19115
  }
19087
19116
  function formatContextStat(stat) {
19088
- const pctColor = stat.fillPct >= 80 ? import_chalk35.default.red : stat.fillPct >= 50 ? import_chalk35.default.yellow : import_chalk35.default.cyan;
19117
+ const pctColor = stat.fillPct >= 80 ? import_chalk36.default.red : stat.fillPct >= 50 ? import_chalk36.default.yellow : import_chalk36.default.cyan;
19089
19118
  const k = (n) => `${Math.round(n / 1e3)}k`;
19090
19119
  const modelShort = stat.model.replace(/@.*$/, "").replace(/-\d{8}$/, "").replace(/^claude-/, "");
19091
- return import_chalk35.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk35.default.dim(
19120
+ return import_chalk36.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk36.default.dim(
19092
19121
  ` (${k(stat.inputTokens)}/${k(getModelContextLimit(stat.model))} out ${k(stat.outputTokens)} \xB7 ${modelShort})`
19093
19122
  );
19094
19123
  }
@@ -19111,11 +19140,11 @@ function agentLabel(agent, mcpServer, sessionId) {
19111
19140
  const tag = sessionTag(sessionId);
19112
19141
  const tagSuffix = tag ? `\xB7${tag}` : "";
19113
19142
  if (!agent || agent === "Terminal") {
19114
- return mcpServer ? import_chalk35.default.dim(`[\u2192 ${mcpServer}] `) : "";
19143
+ return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
19115
19144
  }
19116
19145
  const short = agent === "Claude Code" ? "Claude" : agent === "Gemini CLI" ? "Gemini" : agent === "Unknown Agent" ? "" : agent.split(" ")[0];
19117
- if (!short) return mcpServer ? import_chalk35.default.dim(`[\u2192 ${mcpServer}] `) : "";
19118
- return mcpServer ? import_chalk35.default.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : import_chalk35.default.dim(`[${short}${tagSuffix}] `);
19146
+ if (!short) return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
19147
+ return mcpServer ? import_chalk36.default.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : import_chalk36.default.dim(`[${short}${tagSuffix}] `);
19119
19148
  }
19120
19149
  function formatBase(activity) {
19121
19150
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
@@ -19123,20 +19152,20 @@ function formatBase(activity) {
19123
19152
  const toolName = activity.tool.slice(0, 16).padEnd(16);
19124
19153
  const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os55.default.homedir(), "~");
19125
19154
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
19126
- return `${import_chalk35.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk35.default.white.bold(toolName)} ${import_chalk35.default.dim(argsPreview)}`;
19155
+ return `${import_chalk36.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk36.default.white.bold(toolName)} ${import_chalk36.default.dim(argsPreview)}`;
19127
19156
  }
19128
19157
  function renderResult(activity, result) {
19129
19158
  const base = formatBase(activity);
19130
19159
  let status;
19131
19160
  if (result.status === "allow") {
19132
- status = import_chalk35.default.green("\u2713 ALLOW");
19161
+ status = import_chalk36.default.green("\u2713 ALLOW");
19133
19162
  } else if (result.status === "dlp") {
19134
- status = import_chalk35.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
19163
+ status = import_chalk36.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
19135
19164
  } else {
19136
- status = import_chalk35.default.red("\u2717 BLOCK");
19165
+ status = import_chalk36.default.red("\u2717 BLOCK");
19137
19166
  }
19138
19167
  const cost = result.costEstimate ?? activity.costEstimate;
19139
- const costSuffix = cost == null ? "" : import_chalk35.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
19168
+ const costSuffix = cost == null ? "" : import_chalk36.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
19140
19169
  if (process.stdout.isTTY) {
19141
19170
  if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
19142
19171
  import_readline6.default.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
@@ -19153,7 +19182,7 @@ function renderResult(activity, result) {
19153
19182
  }
19154
19183
  function renderPending(activity) {
19155
19184
  if (!process.stdout.isTTY) return;
19156
- const line = `${formatBase(activity)} ${import_chalk35.default.yellow("\u25CF \u2026")}`;
19185
+ const line = `${formatBase(activity)} ${import_chalk36.default.yellow("\u25CF \u2026")}`;
19157
19186
  pendingShownForId = activity.id;
19158
19187
  pendingWrappedLines = wrappedLineCount(line);
19159
19188
  process.stdout.write(`${line}\r`);
@@ -19165,7 +19194,7 @@ async function ensureDaemon() {
19165
19194
  const { port } = JSON.parse(import_fs64.default.readFileSync(PID_FILE, "utf-8"));
19166
19195
  pidPort = port;
19167
19196
  } catch {
19168
- console.error(import_chalk35.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
19197
+ console.error(import_chalk36.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
19169
19198
  }
19170
19199
  }
19171
19200
  const checkPort = pidPort ?? DAEMON_PORT;
@@ -19176,7 +19205,7 @@ async function ensureDaemon() {
19176
19205
  if (res.ok) return checkPort;
19177
19206
  } catch {
19178
19207
  }
19179
- console.log(import_chalk35.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
19208
+ console.log(import_chalk36.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
19180
19209
  const child = (0, import_child_process14.spawn)(process.execPath, [process.argv[1], "daemon"], {
19181
19210
  detached: true,
19182
19211
  stdio: "ignore",
@@ -19193,7 +19222,7 @@ async function ensureDaemon() {
19193
19222
  } catch {
19194
19223
  }
19195
19224
  }
19196
- console.error(import_chalk35.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
19225
+ console.error(import_chalk36.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
19197
19226
  process.exit(1);
19198
19227
  }
19199
19228
  function postDecisionHttp(id, decision, authToken, port, opts) {
@@ -19203,7 +19232,7 @@ function postDecisionHttp(id, decision, authToken, port, opts) {
19203
19232
  if (opts?.trustDuration) bodyObj.trustDuration = opts.trustDuration;
19204
19233
  if (opts?.reason) bodyObj.reason = opts.reason;
19205
19234
  const body = JSON.stringify(bodyObj);
19206
- const req = import_http4.default.request(
19235
+ const req = import_http5.default.request(
19207
19236
  {
19208
19237
  hostname: "127.0.0.1",
19209
19238
  port,
@@ -19262,7 +19291,7 @@ function buildCardLines(req, localCount = 0) {
19262
19291
  const severityIcon = isBlock ? `${RED}\u{1F6D1}` : `${YELLOW}\u26A0 `;
19263
19292
  const rawDesc = req.riskMetadata?.ruleDescription ?? "";
19264
19293
  const description = rawDesc ? cleanReason(rawDesc) : "";
19265
- const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk35.default.dim(`(${req.agent})`)}` : "";
19294
+ const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk36.default.dim(`(${req.agent})`)}` : "";
19266
19295
  const lines = [
19267
19296
  ``,
19268
19297
  `${BOLD2}${CYAN}\u2554\u2550\u2550 Node9 Approval Required \u2550\u2550\u2557${RESET2}`,
@@ -19331,7 +19360,7 @@ function approverStatusLine() {
19331
19360
  const a = readApproversFromDisk();
19332
19361
  const fmt = (label2, key) => {
19333
19362
  const on = a[key] !== false;
19334
- return `[${key[0]}]${label2.slice(1)} ${on ? import_chalk35.default.green("\u2713") : import_chalk35.default.dim("\u2717")}`;
19363
+ return `[${key[0]}]${label2.slice(1)} ${on ? import_chalk36.default.green("\u2713") : import_chalk36.default.dim("\u2717")}`;
19335
19364
  };
19336
19365
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
19337
19366
  }
@@ -19354,7 +19383,7 @@ async function startTail(options = {}) {
19354
19383
  const port = await ensureDaemon();
19355
19384
  if (options.clear) {
19356
19385
  const result = await new Promise((resolve) => {
19357
- const req2 = import_http4.default.request(
19386
+ const req2 = import_http5.default.request(
19358
19387
  { method: "POST", hostname: "127.0.0.1", port, path: "/events/clear" },
19359
19388
  (res) => {
19360
19389
  const status = res.statusCode ?? 0;
@@ -19376,7 +19405,7 @@ async function startTail(options = {}) {
19376
19405
  req2.end();
19377
19406
  });
19378
19407
  if (result.ok) {
19379
- console.log(import_chalk35.default.green("\u2713 Flight Recorder buffer cleared."));
19408
+ console.log(import_chalk36.default.green("\u2713 Flight Recorder buffer cleared."));
19380
19409
  } else if (result.code === "ECONNREFUSED") {
19381
19410
  throw new Error("Daemon is not running. Start it with: node9 daemon start");
19382
19411
  } else if (result.code === "ETIMEDOUT") {
@@ -19422,7 +19451,7 @@ async function startTail(options = {}) {
19422
19451
  const channel = name === "n" ? "native" : name === "c" ? "cloud" : name === "t" ? "terminal" : null;
19423
19452
  if (channel) {
19424
19453
  toggleApprover(channel);
19425
- console.log(import_chalk35.default.dim(` Approvers: ${approverStatusLine()}`));
19454
+ console.log(import_chalk36.default.dim(` Approvers: ${approverStatusLine()}`));
19426
19455
  }
19427
19456
  };
19428
19457
  process.stdin.on("keypress", idleKeypressHandler);
@@ -19488,7 +19517,7 @@ async function startTail(options = {}) {
19488
19517
  localAllowCounts.get(req2.toolName) ?? 0
19489
19518
  )
19490
19519
  );
19491
- const decisionStamp = action === "always-allow" ? import_chalk35.default.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? import_chalk35.default.cyan("\u23F1 TRUST 30m") : action === "allow" ? import_chalk35.default.green("\u2713 ALLOWED") : action === "redirect" ? import_chalk35.default.yellow("\u21A9 REDIRECT AI") : import_chalk35.default.red("\u2717 DENIED");
19520
+ const decisionStamp = action === "always-allow" ? import_chalk36.default.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? import_chalk36.default.cyan("\u23F1 TRUST 30m") : action === "allow" ? import_chalk36.default.green("\u2713 ALLOWED") : action === "redirect" ? import_chalk36.default.yellow("\u21A9 REDIRECT AI") : import_chalk36.default.red("\u2717 DENIED");
19492
19521
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${decisionStamp} ${GRAY}(terminal)${RESET2}`, ``);
19493
19522
  for (const line of stampedLines) process.stdout.write(line + "\n");
19494
19523
  process.stdout.write(SHOW_CURSOR);
@@ -19539,7 +19568,7 @@ async function startTail(options = {}) {
19539
19568
  );
19540
19569
  const stampedLines = buildCardLines(req2, priorCount);
19541
19570
  if (externalDecision) {
19542
- const source = externalDecision === "allow" ? import_chalk35.default.green("\u2713 ALLOWED") : import_chalk35.default.red("\u2717 DENIED");
19571
+ const source = externalDecision === "allow" ? import_chalk36.default.green("\u2713 ALLOWED") : import_chalk36.default.red("\u2717 DENIED");
19543
19572
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${source} ${GRAY}(external)${RESET2}`, ``);
19544
19573
  }
19545
19574
  for (const line of stampedLines) process.stdout.write(line + "\n");
@@ -19587,25 +19616,25 @@ async function startTail(options = {}) {
19587
19616
  if (unackedDlp > 0) {
19588
19617
  console.log("");
19589
19618
  console.log(
19590
- import_chalk35.default.bgRed.white.bold(
19619
+ import_chalk36.default.bgRed.white.bold(
19591
19620
  ` \u26A0\uFE0F DLP ALERT: ${unackedDlp} secret${unackedDlp !== 1 ? "s" : ""} found in Claude response text \u2014 run: node9 dlp `
19592
19621
  )
19593
19622
  );
19594
19623
  }
19595
19624
  } catch {
19596
19625
  }
19597
- console.log(import_chalk35.default.cyan.bold(`
19626
+ console.log(import_chalk36.default.cyan.bold(`
19598
19627
  \u{1F6F0}\uFE0F Node9 tail`));
19599
19628
  if (canApprove) {
19600
- console.log(import_chalk35.default.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
19601
- console.log(import_chalk35.default.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
19629
+ console.log(import_chalk36.default.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
19630
+ console.log(import_chalk36.default.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
19602
19631
  }
19603
19632
  const ctxStat = readSessionUsage();
19604
19633
  if (ctxStat) console.log(" " + formatContextStat(ctxStat));
19605
19634
  if (options.history) {
19606
- console.log(import_chalk35.default.dim("Showing history + live events.\n"));
19635
+ console.log(import_chalk36.default.dim("Showing history + live events.\n"));
19607
19636
  } else {
19608
- console.log(import_chalk35.default.dim("Showing live events only. Use --history to include past.\n"));
19637
+ console.log(import_chalk36.default.dim("Showing live events only. Use --history to include past.\n"));
19609
19638
  }
19610
19639
  process.on("SIGINT", () => {
19611
19640
  exitIdleMode();
@@ -19615,7 +19644,7 @@ async function startTail(options = {}) {
19615
19644
  import_readline6.default.clearLine(process.stdout, 0);
19616
19645
  import_readline6.default.cursorTo(process.stdout, 0);
19617
19646
  }
19618
- console.log(import_chalk35.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
19647
+ console.log(import_chalk36.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
19619
19648
  process.exit(0);
19620
19649
  });
19621
19650
  const STALL_THRESHOLD_MS = 6e4;
@@ -19627,7 +19656,7 @@ async function startTail(options = {}) {
19627
19656
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
19628
19657
  console.log("");
19629
19658
  console.log(
19630
- import_chalk35.default.yellow(
19659
+ import_chalk36.default.yellow(
19631
19660
  "\u26A0\uFE0F Tail appears stalled \u2014 hooks are firing but no events are arriving. Try: node9 daemon restart"
19632
19661
  )
19633
19662
  );
@@ -19637,14 +19666,14 @@ async function startTail(options = {}) {
19637
19666
  }, STALL_THRESHOLD_MS / 2);
19638
19667
  stallWatchdog.unref();
19639
19668
  const sseUrl = `http://127.0.0.1:${port}/events?capabilities=input`;
19640
- const req = import_http4.default.get(
19669
+ const req = import_http5.default.get(
19641
19670
  sseUrl,
19642
19671
  {
19643
19672
  headers: authToken ? { "X-Node9-Internal": authToken } : {}
19644
19673
  },
19645
19674
  (res) => {
19646
19675
  if (res.statusCode !== 200) {
19647
- console.error(import_chalk35.default.red(`Failed to connect: HTTP ${res.statusCode}`));
19676
+ console.error(import_chalk36.default.red(`Failed to connect: HTTP ${res.statusCode}`));
19648
19677
  process.exit(1);
19649
19678
  }
19650
19679
  if (canApprove) enterIdleMode();
@@ -19675,7 +19704,7 @@ async function startTail(options = {}) {
19675
19704
  import_readline6.default.clearLine(process.stdout, 0);
19676
19705
  import_readline6.default.cursorTo(process.stdout, 0);
19677
19706
  }
19678
- console.log(import_chalk35.default.red("\n\u274C Daemon disconnected."));
19707
+ console.log(import_chalk36.default.red("\n\u274C Daemon disconnected."));
19679
19708
  process.exit(1);
19680
19709
  });
19681
19710
  }
@@ -19688,7 +19717,7 @@ async function startTail(options = {}) {
19688
19717
  const parsed = JSON.parse(rawData);
19689
19718
  const msg = parsed.message ?? "Flight recorder is down \u2014 run: node9 daemon restart";
19690
19719
  console.log("");
19691
- console.log(import_chalk35.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
19720
+ console.log(import_chalk36.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
19692
19721
  } catch {
19693
19722
  }
19694
19723
  return;
@@ -19773,9 +19802,9 @@ async function startTail(options = {}) {
19773
19802
  const rawSummary = data.argsSummary ?? data.tool;
19774
19803
  const summary = shortenPathSummary(rawSummary);
19775
19804
  const fileCount = data.fileCount ?? 0;
19776
- const files = fileCount > 0 ? import_chalk35.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
19805
+ const files = fileCount > 0 ? import_chalk36.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
19777
19806
  process.stdout.write(
19778
- `${import_chalk35.default.dim(time)} ${import_chalk35.default.cyan("\u{1F4F8} snapshot")} ${import_chalk35.default.dim(hash)} ${summary}${files}
19807
+ `${import_chalk36.default.dim(time)} ${import_chalk36.default.cyan("\u{1F4F8} snapshot")} ${import_chalk36.default.dim(hash)} ${summary}${files}
19779
19808
  `
19780
19809
  );
19781
19810
  return;
@@ -19792,28 +19821,28 @@ async function startTail(options = {}) {
19792
19821
  if (event === "execution-result") {
19793
19822
  const exec = data;
19794
19823
  const time = new Date(Date.now()).toLocaleTimeString([], { hour12: false });
19795
- const arrow = exec.isError ? import_chalk35.default.red(" \u21B3 \u2717") : import_chalk35.default.green(" \u21B3 \u2713");
19824
+ const arrow = exec.isError ? import_chalk36.default.red(" \u21B3 \u2717") : import_chalk36.default.green(" \u21B3 \u2713");
19796
19825
  const label2 = agentLabel(exec.agent, exec.mcpServer);
19797
19826
  const tool = (exec.tool ?? "").slice(0, 16);
19798
- const duration = typeof exec.durationMs === "number" ? import_chalk35.default.dim(` (${exec.durationMs}ms)`) : "";
19827
+ const duration = typeof exec.durationMs === "number" ? import_chalk36.default.dim(` (${exec.durationMs}ms)`) : "";
19799
19828
  console.log(
19800
- `${import_chalk35.default.gray(time)} ${arrow} ${label2}${import_chalk35.default.dim(tool)}${import_chalk35.default.dim(" completed")}${duration}`
19829
+ `${import_chalk36.default.gray(time)} ${arrow} ${label2}${import_chalk36.default.dim(tool)}${import_chalk36.default.dim(" completed")}${duration}`
19801
19830
  );
19802
19831
  }
19803
19832
  }
19804
19833
  req.on("error", (err2) => {
19805
19834
  const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
19806
- console.error(import_chalk35.default.red(`
19835
+ console.error(import_chalk36.default.red(`
19807
19836
  \u274C ${msg}`));
19808
19837
  process.exit(1);
19809
19838
  });
19810
19839
  }
19811
- var import_http4, import_chalk35, import_fs64, import_os55, import_path62, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
19840
+ var import_http5, import_chalk36, import_fs64, import_os55, import_path62, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
19812
19841
  var init_tail = __esm({
19813
19842
  "src/tui/tail.ts"() {
19814
19843
  "use strict";
19815
- import_http4 = __toESM(require("http"));
19816
- import_chalk35 = __toESM(require("chalk"));
19844
+ import_http5 = __toESM(require("http"));
19845
+ import_chalk36 = __toESM(require("chalk"));
19817
19846
  import_fs64 = __toESM(require("fs"));
19818
19847
  import_os55 = __toESM(require("os"));
19819
19848
  import_path62 = __toESM(require("path"));
@@ -19886,7 +19915,7 @@ function queryDaemon() {
19886
19915
  return new Promise((resolve) => {
19887
19916
  const timeout = setTimeout(() => resolve(null), 50);
19888
19917
  try {
19889
- const req = import_http5.default.get(
19918
+ const req = import_http6.default.get(
19890
19919
  `http://${DAEMON_HOST}:${DAEMON_PORT}/status`,
19891
19920
  { timeout: 50 },
19892
19921
  (res) => {
@@ -20214,14 +20243,14 @@ async function main() {
20214
20243
  renderOffline();
20215
20244
  }
20216
20245
  }
20217
- var import_fs65, import_path63, import_os56, import_http5, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
20246
+ var import_fs65, import_path63, import_os56, import_http6, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
20218
20247
  var init_hud = __esm({
20219
20248
  "src/cli/hud.ts"() {
20220
20249
  "use strict";
20221
20250
  import_fs65 = __toESM(require("fs"));
20222
20251
  import_path63 = __toESM(require("path"));
20223
20252
  import_os56 = __toESM(require("os"));
20224
- import_http5 = __toESM(require("http"));
20253
+ import_http6 = __toESM(require("http"));
20225
20254
  init_daemon();
20226
20255
  RESET3 = "\x1B[0m";
20227
20256
  BOLD3 = "\x1B[1m";
@@ -20278,8 +20307,69 @@ function agentTeardownTargets() {
20278
20307
 
20279
20308
  // src/cli.ts
20280
20309
  init_agent_wiring();
20310
+
20311
+ // src/credentials.ts
20312
+ var fs15 = __toESM(require("fs"));
20313
+ var os14 = __toESM(require("os"));
20314
+ var path17 = __toESM(require("path"));
20315
+ var DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
20316
+ function writeCredentialsAndConfig(apiKey, opts = {}) {
20317
+ const profileName = opts.profileName || "default";
20318
+ const home = opts.homeDir ?? os14.homedir();
20319
+ const credPath = path17.join(home, ".node9", "credentials.json");
20320
+ if (!fs15.existsSync(path17.dirname(credPath))) {
20321
+ fs15.mkdirSync(path17.dirname(credPath), { recursive: true });
20322
+ }
20323
+ let existingCreds = {};
20324
+ try {
20325
+ if (fs15.existsSync(credPath)) {
20326
+ const raw = JSON.parse(fs15.readFileSync(credPath, "utf-8"));
20327
+ existingCreds = raw.apiKey ? { default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL } } : raw;
20328
+ }
20329
+ } catch {
20330
+ }
20331
+ existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL };
20332
+ fs15.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), {
20333
+ mode: 384
20334
+ });
20335
+ let effectiveCloud = null;
20336
+ if (profileName === "default") {
20337
+ const configPath = path17.join(home, ".node9", "config.json");
20338
+ let config = {};
20339
+ try {
20340
+ if (fs15.existsSync(configPath)) {
20341
+ config = JSON.parse(fs15.readFileSync(configPath, "utf-8"));
20342
+ }
20343
+ } catch {
20344
+ }
20345
+ if (!config.settings || typeof config.settings !== "object") {
20346
+ config.settings = {};
20347
+ }
20348
+ const s = config.settings;
20349
+ const approvers = s.approvers || {
20350
+ native: true,
20351
+ browser: true,
20352
+ cloud: true,
20353
+ terminal: true
20354
+ };
20355
+ if (opts.isLocal) {
20356
+ approvers.cloud = false;
20357
+ }
20358
+ s.approvers = approvers;
20359
+ if (!fs15.existsSync(path17.dirname(configPath))) {
20360
+ fs15.mkdirSync(path17.dirname(configPath), { recursive: true });
20361
+ }
20362
+ fs15.writeFileSync(configPath, JSON.stringify(config, null, 2), {
20363
+ mode: 384
20364
+ });
20365
+ effectiveCloud = approvers.cloud === true;
20366
+ }
20367
+ return { profileName, effectiveCloud };
20368
+ }
20369
+
20370
+ // src/cli.ts
20281
20371
  init_daemon2();
20282
- var import_chalk36 = __toESM(require("chalk"));
20372
+ var import_chalk37 = __toESM(require("chalk"));
20283
20373
  var import_fs66 = __toESM(require("fs"));
20284
20374
  var import_path64 = __toESM(require("path"));
20285
20375
  var import_os57 = __toESM(require("os"));
@@ -24154,18 +24244,7 @@ function registerInitCommand(program2) {
24154
24244
  console.log("");
24155
24245
  for (const agent of found) {
24156
24246
  console.log(import_chalk16.default.bold(`Wiring ${agent}...`));
24157
- if (agent === "claude") await setupClaude();
24158
- else if (agent === "gemini") await setupGemini();
24159
- else if (agent === "antigravity") await setupAntigravity();
24160
- else if (agent === "copilot") await setupCopilot();
24161
- else if (agent === "cursor") await setupCursor();
24162
- else if (agent === "codex") await setupCodex();
24163
- else if (agent === "windsurf") await setupWindsurf();
24164
- else if (agent === "vscode") await setupVSCode();
24165
- else if (agent === "claudeDesktop") await setupClaudeDesktop();
24166
- else if (agent === "opencode") await setupOpencode();
24167
- else if (agent === "pi") await setupPi();
24168
- else if (agent === "hermes") setupHermes();
24247
+ await setupAgent(agent);
24169
24248
  console.log("");
24170
24249
  }
24171
24250
  if ((process.platform === "darwin" || process.platform === "linux") && process.stdout.isTTY) {
@@ -24228,13 +24307,110 @@ function registerInitCommand(program2) {
24228
24307
  );
24229
24308
  }
24230
24309
 
24310
+ // src/cli/commands/connect.ts
24311
+ var import_http4 = __toESM(require("http"));
24312
+ var import_https7 = __toESM(require("https"));
24313
+ var import_url3 = require("url");
24314
+ var import_chalk17 = __toESM(require("chalk"));
24315
+ init_setup();
24316
+ init_sync();
24317
+ var DEFAULT_CONNECT_URL = "https://api.node9.ai/api/v1/cli/connect";
24318
+ function resolveConnectUrl(apiUrl) {
24319
+ if (apiUrl) return apiUrl;
24320
+ const base = process.env.NODE9_API_URL;
24321
+ if (base) return base.replace(/\/intercept\/?$/, "") + "/cli/connect";
24322
+ return DEFAULT_CONNECT_URL;
24323
+ }
24324
+ function postConnect(url, token) {
24325
+ return new Promise((resolve, reject) => {
24326
+ const body = JSON.stringify({ token });
24327
+ const u = new import_url3.URL(url);
24328
+ const lib = u.protocol === "http:" ? import_http4.default : import_https7.default;
24329
+ const req = lib.request(
24330
+ {
24331
+ method: "POST",
24332
+ hostname: u.hostname,
24333
+ port: u.port || (u.protocol === "http:" ? 80 : 443),
24334
+ path: u.pathname + u.search,
24335
+ headers: {
24336
+ "Content-Type": "application/json",
24337
+ "Content-Length": Buffer.byteLength(body)
24338
+ },
24339
+ timeout: 15e3
24340
+ },
24341
+ (res) => {
24342
+ let data = "";
24343
+ res.on("data", (c) => data += c);
24344
+ res.on("end", () => {
24345
+ const code = res.statusCode ?? 0;
24346
+ if (code >= 200 && code < 300) {
24347
+ try {
24348
+ resolve(JSON.parse(data));
24349
+ } catch {
24350
+ reject(new Error("Unexpected response from the server."));
24351
+ }
24352
+ } else if (code === 400 || code === 401) {
24353
+ reject(
24354
+ new Error(
24355
+ "This connect link expired or was already used \u2014 generate a new one in the dashboard."
24356
+ )
24357
+ );
24358
+ } else {
24359
+ reject(new Error(`Connect failed (HTTP ${code}).`));
24360
+ }
24361
+ });
24362
+ }
24363
+ );
24364
+ req.on("error", (e) => reject(e));
24365
+ req.on("timeout", () => {
24366
+ req.destroy();
24367
+ reject(new Error("Connection timed out."));
24368
+ });
24369
+ req.write(body);
24370
+ req.end();
24371
+ });
24372
+ }
24373
+ function registerConnectCommand(program2) {
24374
+ program2.command("connect").argument("<token>", "A connect token from the dashboard").option("--profile <name>", 'Save as a named profile (default: "default")').option("--api-url <url>", "Override the connect endpoint (self-host / dev)").description("Connect this machine to a node9 workspace using a dashboard token").action(async (token, options) => {
24375
+ let resp;
24376
+ try {
24377
+ resp = await postConnect(resolveConnectUrl(options.apiUrl), token);
24378
+ } catch (e) {
24379
+ console.error(import_chalk17.default.red(`\u2717 ${e instanceof Error ? e.message : "Connect failed."}`));
24380
+ process.exitCode = 1;
24381
+ return;
24382
+ }
24383
+ writeCredentialsAndConfig(resp.apiKey, { profileName: options.profile });
24384
+ process.env.NODE9_NONINTERACTIVE = "1";
24385
+ let wired = [];
24386
+ try {
24387
+ wired = await setupDetectedAgents();
24388
+ } catch {
24389
+ }
24390
+ if (!isTestingMode()) {
24391
+ try {
24392
+ await runCloudSync();
24393
+ } catch {
24394
+ }
24395
+ }
24396
+ console.log(import_chalk17.default.green(`\u2705 Connected to ${resp.workspaceName}`));
24397
+ if (wired.length) {
24398
+ console.log(import_chalk17.default.gray(` Wired: ${wired.join(", ")}`));
24399
+ } else {
24400
+ console.log(
24401
+ import_chalk17.default.gray(" No agents detected yet \u2014 run `node9 init` after installing one.")
24402
+ );
24403
+ }
24404
+ });
24405
+ }
24406
+
24231
24407
  // src/cli/commands/undo.ts
24232
24408
  var import_path50 = __toESM(require("path"));
24233
- var import_chalk18 = __toESM(require("chalk"));
24409
+ var import_chalk19 = __toESM(require("chalk"));
24234
24410
 
24235
24411
  // src/tui/undo-navigator.ts
24236
24412
  var import_readline3 = __toESM(require("readline"));
24237
- var import_chalk17 = __toESM(require("chalk"));
24413
+ var import_chalk18 = __toESM(require("chalk"));
24238
24414
  var RESET = "\x1B[0m";
24239
24415
  var BOLD = "\x1B[1m";
24240
24416
  var CLEAR_SCREEN = "\x1B[2J\x1B[H";
@@ -24252,15 +24428,15 @@ function renderDiff(raw) {
24252
24428
  );
24253
24429
  for (const line of lines) {
24254
24430
  if (line.startsWith("+++") || line.startsWith("---")) {
24255
- process.stdout.write(import_chalk17.default.bold(line) + "\n");
24431
+ process.stdout.write(import_chalk18.default.bold(line) + "\n");
24256
24432
  } else if (line.startsWith("+")) {
24257
- process.stdout.write(import_chalk17.default.green(line) + "\n");
24433
+ process.stdout.write(import_chalk18.default.green(line) + "\n");
24258
24434
  } else if (line.startsWith("-")) {
24259
- process.stdout.write(import_chalk17.default.red(line) + "\n");
24435
+ process.stdout.write(import_chalk18.default.red(line) + "\n");
24260
24436
  } else if (line.startsWith("@@")) {
24261
- process.stdout.write(import_chalk17.default.cyan(line) + "\n");
24437
+ process.stdout.write(import_chalk18.default.cyan(line) + "\n");
24262
24438
  } else {
24263
- process.stdout.write(import_chalk17.default.gray(line) + "\n");
24439
+ process.stdout.write(import_chalk18.default.gray(line) + "\n");
24264
24440
  }
24265
24441
  }
24266
24442
  }
@@ -24279,23 +24455,23 @@ function render(entries, idx) {
24279
24455
  const step = idx + 1;
24280
24456
  process.stdout.write(CLEAR_SCREEN);
24281
24457
  process.stdout.write(
24282
- import_chalk17.default.magenta.bold(`\u23EA Node9 Undo`) + import_chalk17.default.gray(` \u2500\u2500 step ${step} of ${total}`) + (entry.files?.length ? import_chalk17.default.gray(
24458
+ import_chalk18.default.magenta.bold(`\u23EA Node9 Undo`) + import_chalk18.default.gray(` \u2500\u2500 step ${step} of ${total}`) + (entry.files?.length ? import_chalk18.default.gray(
24283
24459
  ` \u2500\u2500 ${entry.files.slice(0, 2).join(", ")}${entry.files.length > 2 ? ` +${entry.files.length - 2} more` : ""}`
24284
24460
  ) : "") + "\n\n"
24285
24461
  );
24286
24462
  process.stdout.write(
24287
- ` ${BOLD}Tool:${RESET} ${import_chalk17.default.cyan(entry.tool)}` + (entry.argsSummary ? import_chalk17.default.gray(" \u2192 " + entry.argsSummary) : "") + "\n"
24463
+ ` ${BOLD}Tool:${RESET} ${import_chalk18.default.cyan(entry.tool)}` + (entry.argsSummary ? import_chalk18.default.gray(" \u2192 " + entry.argsSummary) : "") + "\n"
24288
24464
  );
24289
- process.stdout.write(` ${BOLD}When:${RESET} ${import_chalk17.default.gray(formatAge(entry.timestamp))}
24465
+ process.stdout.write(` ${BOLD}When:${RESET} ${import_chalk18.default.gray(formatAge(entry.timestamp))}
24290
24466
  `);
24291
- process.stdout.write(` ${BOLD}Dir: ${RESET} ${import_chalk17.default.gray(entry.cwd)}
24467
+ process.stdout.write(` ${BOLD}Dir: ${RESET} ${import_chalk18.default.gray(entry.cwd)}
24292
24468
  `);
24293
24469
  if (entry.files && entry.files.length > 0) {
24294
- process.stdout.write(` ${BOLD}Files:${RESET} ${import_chalk17.default.gray(entry.files.join(", "))}
24470
+ process.stdout.write(` ${BOLD}Files:${RESET} ${import_chalk18.default.gray(entry.files.join(", "))}
24295
24471
  `);
24296
24472
  }
24297
24473
  if (idx < total - 1 && isSessionBoundary(entries, idx + 1)) {
24298
- process.stdout.write(import_chalk17.default.gray("\n \u2500\u2500 session boundary above \u2500\u2500\n"));
24474
+ process.stdout.write(import_chalk18.default.gray("\n \u2500\u2500 session boundary above \u2500\u2500\n"));
24299
24475
  }
24300
24476
  process.stdout.write("\n");
24301
24477
  const diff = entry.diff ?? computeUndoDiff(entry.hash, entry.cwd);
@@ -24303,12 +24479,12 @@ function render(entries, idx) {
24303
24479
  renderDiff(diff);
24304
24480
  } else {
24305
24481
  process.stdout.write(
24306
- import_chalk17.default.gray(" (no diff \u2014 working tree may already match this snapshot)\n")
24482
+ import_chalk18.default.gray(" (no diff \u2014 working tree may already match this snapshot)\n")
24307
24483
  );
24308
24484
  }
24309
24485
  process.stdout.write("\n");
24310
24486
  process.stdout.write(
24311
- import_chalk17.default.gray(" ") + (idx < total - 1 ? import_chalk17.default.white("[\u2190] older") : import_chalk17.default.gray("[\u2190] older")) + import_chalk17.default.gray(" ") + (idx > 0 ? import_chalk17.default.white("[\u2192] newer") : import_chalk17.default.gray("[\u2192] newer")) + import_chalk17.default.gray(" ") + import_chalk17.default.green("[\u21B5] restore here") + import_chalk17.default.gray(" ") + import_chalk17.default.yellow("[s] session start") + import_chalk17.default.gray(" ") + import_chalk17.default.gray("[q] quit") + "\n"
24487
+ import_chalk18.default.gray(" ") + (idx < total - 1 ? import_chalk18.default.white("[\u2190] older") : import_chalk18.default.gray("[\u2190] older")) + import_chalk18.default.gray(" ") + (idx > 0 ? import_chalk18.default.white("[\u2192] newer") : import_chalk18.default.gray("[\u2192] newer")) + import_chalk18.default.gray(" ") + import_chalk18.default.green("[\u21B5] restore here") + import_chalk18.default.gray(" ") + import_chalk18.default.yellow("[s] session start") + import_chalk18.default.gray(" ") + import_chalk18.default.gray("[q] quit") + "\n"
24312
24488
  );
24313
24489
  }
24314
24490
  async function runUndoNavigator(entries) {
@@ -24362,19 +24538,19 @@ async function runUndoNavigator(entries) {
24362
24538
  cleanup();
24363
24539
  process.stdout.write(CLEAR_SCREEN);
24364
24540
  const entry = display[idx];
24365
- process.stdout.write(import_chalk17.default.magenta.bold("\n\u23EA Restoring snapshot...\n\n"));
24541
+ process.stdout.write(import_chalk18.default.magenta.bold("\n\u23EA Restoring snapshot...\n\n"));
24366
24542
  if (applyUndo(entry.hash, entry.cwd)) {
24367
- process.stdout.write(import_chalk17.default.green("\u2705 Reverted successfully.\n\n"));
24543
+ process.stdout.write(import_chalk18.default.green("\u2705 Reverted successfully.\n\n"));
24368
24544
  resolve({ restored: true });
24369
24545
  } else {
24370
- process.stdout.write(import_chalk17.default.red("\u274C Undo failed.\n\n"));
24546
+ process.stdout.write(import_chalk18.default.red("\u274C Undo failed.\n\n"));
24371
24547
  resolve({ restored: false });
24372
24548
  }
24373
24549
  } else if (name === "q" || key?.ctrl && name === "c") {
24374
24550
  done = true;
24375
24551
  cleanup();
24376
24552
  process.stdout.write(CLEAR_SCREEN);
24377
- process.stdout.write(import_chalk17.default.gray("\nCancelled.\n\n"));
24553
+ process.stdout.write(import_chalk18.default.gray("\nCancelled.\n\n"));
24378
24554
  resolve({ restored: false });
24379
24555
  }
24380
24556
  };
@@ -24410,39 +24586,39 @@ function registerUndoCommand(program2) {
24410
24586
  if (history.length === 0) {
24411
24587
  if (!options.all && allHistory.length > 0) {
24412
24588
  console.log(
24413
- import_chalk18.default.yellow(
24589
+ import_chalk19.default.yellow(
24414
24590
  `
24415
24591
  \u2139\uFE0F No snapshots found for the current directory (${process.cwd()}).
24416
- Run ${import_chalk18.default.cyan("node9 undo --all")} to see snapshots from all projects.
24592
+ Run ${import_chalk19.default.cyan("node9 undo --all")} to see snapshots from all projects.
24417
24593
  `
24418
24594
  )
24419
24595
  );
24420
24596
  } else {
24421
- console.log(import_chalk18.default.yellow("\n\u2139\uFE0F No undo snapshots found.\n"));
24597
+ console.log(import_chalk19.default.yellow("\n\u2139\uFE0F No undo snapshots found.\n"));
24422
24598
  }
24423
24599
  return;
24424
24600
  }
24425
24601
  if (options.list) {
24426
- console.log(import_chalk18.default.magenta.bold("\n\u23EA Snapshot History\n"));
24602
+ console.log(import_chalk19.default.magenta.bold("\n\u23EA Snapshot History\n"));
24427
24603
  console.log(
24428
- import_chalk18.default.gray(
24604
+ import_chalk19.default.gray(
24429
24605
  ` ${"#".padEnd(3)} ${"File / Command".padEnd(30)} ${"Tool".padEnd(8)} ${"When".padEnd(10)} Dir`
24430
24606
  )
24431
24607
  );
24432
- console.log(import_chalk18.default.gray(" " + "\u2500".repeat(80)));
24608
+ console.log(import_chalk19.default.gray(" " + "\u2500".repeat(80)));
24433
24609
  const display = [...history].reverse();
24434
24610
  let prevTs = null;
24435
24611
  for (let i = 0; i < display.length; i++) {
24436
24612
  const e = display[i];
24437
24613
  const isGap = prevTs !== null && prevTs - e.timestamp > 6e4;
24438
- if (isGap) console.log(import_chalk18.default.gray(" \u2500\u2500 earlier \u2500\u2500"));
24614
+ if (isGap) console.log(import_chalk19.default.gray(" \u2500\u2500 earlier \u2500\u2500"));
24439
24615
  const label2 = (e.argsSummary || e.files?.[0] || "\u2014").slice(0, 30).padEnd(30);
24440
24616
  const tool = e.tool.slice(0, 8).padEnd(8);
24441
24617
  const when = formatAge2(e.timestamp).padEnd(10);
24442
24618
  const dir = e.cwd.length > 30 ? "\u2026" + e.cwd.slice(-29) : e.cwd;
24443
24619
  console.log(
24444
- import_chalk18.default.white(
24445
- ` ${String(i + 1).padEnd(3)} ${label2} ${import_chalk18.default.cyan(tool)} ${import_chalk18.default.gray(when)} ${import_chalk18.default.gray(dir)}`
24620
+ import_chalk19.default.white(
24621
+ ` ${String(i + 1).padEnd(3)} ${label2} ${import_chalk19.default.cyan(tool)} ${import_chalk19.default.gray(when)} ${import_chalk19.default.gray(dir)}`
24446
24622
  )
24447
24623
  );
24448
24624
  prevTs = e.timestamp;
@@ -24455,7 +24631,7 @@ function registerUndoCommand(program2) {
24455
24631
  const idx = history.length - steps;
24456
24632
  if (idx < 0) {
24457
24633
  console.log(
24458
- import_chalk18.default.yellow(
24634
+ import_chalk19.default.yellow(
24459
24635
  `
24460
24636
  \u2139\uFE0F Only ${history.length} snapshot(s) available, cannot go back ${steps}.
24461
24637
  `
@@ -24466,47 +24642,47 @@ function registerUndoCommand(program2) {
24466
24642
  const snapshot = history[idx];
24467
24643
  const ageStr = formatAge2(snapshot.timestamp);
24468
24644
  console.log(
24469
- import_chalk18.default.magenta.bold(`
24645
+ import_chalk19.default.magenta.bold(`
24470
24646
  \u23EA Node9 Undo${steps > 1 ? ` (${steps} steps back)` : ""}`)
24471
24647
  );
24472
24648
  console.log(
24473
- import_chalk18.default.white(
24474
- ` Tool: ${import_chalk18.default.cyan(snapshot.tool)}${snapshot.argsSummary ? import_chalk18.default.gray(" \u2192 " + snapshot.argsSummary) : ""}`
24649
+ import_chalk19.default.white(
24650
+ ` Tool: ${import_chalk19.default.cyan(snapshot.tool)}${snapshot.argsSummary ? import_chalk19.default.gray(" \u2192 " + snapshot.argsSummary) : ""}`
24475
24651
  )
24476
24652
  );
24477
- console.log(import_chalk18.default.white(` When: ${import_chalk18.default.gray(ageStr)}`));
24478
- console.log(import_chalk18.default.white(` Dir: ${import_chalk18.default.gray(snapshot.cwd)}`));
24653
+ console.log(import_chalk19.default.white(` When: ${import_chalk19.default.gray(ageStr)}`));
24654
+ console.log(import_chalk19.default.white(` Dir: ${import_chalk19.default.gray(snapshot.cwd)}`));
24479
24655
  if (steps > 1)
24480
24656
  console.log(
24481
- import_chalk18.default.yellow(` Note: This will also undo the ${steps - 1} action(s) after it.`)
24657
+ import_chalk19.default.yellow(` Note: This will also undo the ${steps - 1} action(s) after it.`)
24482
24658
  );
24483
24659
  console.log("");
24484
24660
  const diff = snapshot.diff ?? computeUndoDiff(snapshot.hash, snapshot.cwd);
24485
24661
  if (diff) {
24486
24662
  const lines = diff.split("\n").filter((l) => !l.startsWith("diff --git") && !l.startsWith("index "));
24487
24663
  for (const line of lines) {
24488
- if (line.startsWith("+++") || line.startsWith("---")) console.log(import_chalk18.default.bold(line));
24489
- else if (line.startsWith("+")) console.log(import_chalk18.default.green(line));
24490
- else if (line.startsWith("-")) console.log(import_chalk18.default.red(line));
24491
- else if (line.startsWith("@@")) console.log(import_chalk18.default.cyan(line));
24492
- else console.log(import_chalk18.default.gray(line));
24664
+ if (line.startsWith("+++") || line.startsWith("---")) console.log(import_chalk19.default.bold(line));
24665
+ else if (line.startsWith("+")) console.log(import_chalk19.default.green(line));
24666
+ else if (line.startsWith("-")) console.log(import_chalk19.default.red(line));
24667
+ else if (line.startsWith("@@")) console.log(import_chalk19.default.cyan(line));
24668
+ else console.log(import_chalk19.default.gray(line));
24493
24669
  }
24494
24670
  console.log("");
24495
24671
  } else {
24496
24672
  console.log(
24497
- import_chalk18.default.gray(" (no diff available \u2014 working tree may already match snapshot)\n")
24673
+ import_chalk19.default.gray(" (no diff available \u2014 working tree may already match snapshot)\n")
24498
24674
  );
24499
24675
  }
24500
24676
  const { confirm: confirm3 } = await import("@inquirer/prompts");
24501
24677
  const proceed = await confirm3({ message: `Revert to this snapshot?`, default: false });
24502
24678
  if (proceed) {
24503
24679
  if (applyUndo(snapshot.hash, snapshot.cwd)) {
24504
- console.log(import_chalk18.default.green("\n\u2705 Reverted successfully.\n"));
24680
+ console.log(import_chalk19.default.green("\n\u2705 Reverted successfully.\n"));
24505
24681
  } else {
24506
- console.error(import_chalk18.default.red("\n\u274C Undo failed. Ensure you are in a Git repository.\n"));
24682
+ console.error(import_chalk19.default.red("\n\u274C Undo failed. Ensure you are in a Git repository.\n"));
24507
24683
  }
24508
24684
  } else {
24509
- console.log(import_chalk18.default.gray("\nCancelled.\n"));
24685
+ console.log(import_chalk19.default.gray("\nCancelled.\n"));
24510
24686
  }
24511
24687
  return;
24512
24688
  }
@@ -24516,7 +24692,7 @@ function registerUndoCommand(program2) {
24516
24692
 
24517
24693
  // src/mcp-gateway/index.ts
24518
24694
  var import_readline4 = __toESM(require("readline"));
24519
- var import_chalk19 = __toESM(require("chalk"));
24695
+ var import_chalk20 = __toESM(require("chalk"));
24520
24696
  var import_child_process10 = require("child_process");
24521
24697
  var import_execa3 = require("execa");
24522
24698
  init_orchestrator();
@@ -24652,13 +24828,13 @@ async function runMcpGateway(upstreamCommand) {
24652
24828
  const prov = checkProvenance(executable);
24653
24829
  if (prov.trustLevel === "suspect") {
24654
24830
  console.error(
24655
- import_chalk19.default.red(
24831
+ import_chalk20.default.red(
24656
24832
  `\u26A0\uFE0F Node9: Upstream MCP server binary is suspect \u2014 ${prov.reason} (${prov.resolvedPath})`
24657
24833
  )
24658
24834
  );
24659
- console.error(import_chalk19.default.red(" Verify this binary is trusted before proceeding."));
24835
+ console.error(import_chalk20.default.red(" Verify this binary is trusted before proceeding."));
24660
24836
  }
24661
- console.error(import_chalk19.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
24837
+ console.error(import_chalk20.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
24662
24838
  const UPSTREAM_INJECTOR_VARS = /* @__PURE__ */ new Set([
24663
24839
  "NODE_OPTIONS",
24664
24840
  "NODE_PATH",
@@ -24771,10 +24947,10 @@ async function runMcpGateway(upstreamCommand) {
24771
24947
  mcpServer
24772
24948
  });
24773
24949
  if (!result.approved) {
24774
- console.error(import_chalk19.default.red(`
24950
+ console.error(import_chalk20.default.red(`
24775
24951
  \u{1F6D1} Node9 MCP Gateway: Action Blocked`));
24776
- console.error(import_chalk19.default.gray(` Tool: ${toolName}`));
24777
- console.error(import_chalk19.default.gray(` Reason: ${result.reason ?? "Security Policy"}
24952
+ console.error(import_chalk20.default.gray(` Tool: ${toolName}`));
24953
+ console.error(import_chalk20.default.gray(` Reason: ${result.reason ?? "Security Policy"}
24778
24954
  `));
24779
24955
  const blockedByLabel = result.blockedByLabel ?? result.reason ?? "Security Policy";
24780
24956
  const isHumanDecision = blockedByLabel.toLowerCase().includes("user") || blockedByLabel.toLowerCase().includes("daemon") || blockedByLabel.toLowerCase().includes("decision");
@@ -24887,7 +25063,7 @@ async function runMcpGateway(upstreamCommand) {
24887
25063
  updatePin(serverKey, upstreamCommand, currentHash, toolNames);
24888
25064
  pinState = "validated";
24889
25065
  console.error(
24890
- import_chalk19.default.green(
25066
+ import_chalk20.default.green(
24891
25067
  `\u{1F512} Node9: Pinned ${toolNames.length} tool definition(s) for this MCP server`
24892
25068
  )
24893
25069
  );
@@ -24900,11 +25076,11 @@ async function runMcpGateway(upstreamCommand) {
24900
25076
  } else if (pinStatus === "corrupt") {
24901
25077
  pinState = "quarantined";
24902
25078
  console.error(
24903
- import_chalk19.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
25079
+ import_chalk20.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
24904
25080
  );
24905
- console.error(import_chalk19.default.red(" Tool calls are blocked until the pin file is repaired."));
25081
+ console.error(import_chalk20.default.red(" Tool calls are blocked until the pin file is repaired."));
24906
25082
  console.error(
24907
- import_chalk19.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
25083
+ import_chalk20.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
24908
25084
  `)
24909
25085
  );
24910
25086
  const errorResponse = {
@@ -24921,13 +25097,13 @@ async function runMcpGateway(upstreamCommand) {
24921
25097
  } else {
24922
25098
  pinState = "quarantined";
24923
25099
  console.error(
24924
- import_chalk19.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
25100
+ import_chalk20.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
24925
25101
  );
24926
25102
  console.error(
24927
- import_chalk19.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
25103
+ import_chalk20.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
24928
25104
  );
24929
- console.error(import_chalk19.default.red(" Session quarantined \u2014 all tool calls blocked."));
24930
- console.error(import_chalk19.default.yellow(` Run: node9 mcp pin update ${serverKey}
25105
+ console.error(import_chalk20.default.red(" Session quarantined \u2014 all tool calls blocked."));
25106
+ console.error(import_chalk20.default.yellow(` Run: node9 mcp pin update ${serverKey}
24931
25107
  `));
24932
25108
  reportPinMismatchToCloud(serverKey, clientName);
24933
25109
  const errorResponse = {
@@ -24971,7 +25147,7 @@ async function runMcpGateway(upstreamCommand) {
24971
25147
  const toolName = callId !== void 0 ? pendingCallNames.get(callId) ?? "unknown" : "unknown";
24972
25148
  if (callId !== void 0) pendingCallNames.delete(callId);
24973
25149
  console.error(
24974
- import_chalk19.default.yellow(
25150
+ import_chalk20.default.yellow(
24975
25151
  `\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
24976
25152
  )
24977
25153
  );
@@ -25938,7 +26114,7 @@ function registerMcpServerCommand(program2) {
25938
26114
  }
25939
26115
 
25940
26116
  // src/cli/commands/trust.ts
25941
- var import_chalk20 = __toESM(require("chalk"));
26117
+ var import_chalk21 = __toESM(require("chalk"));
25942
26118
  init_trusted_hosts();
25943
26119
  function isValidHost(host) {
25944
26120
  return /^(\*\.)?[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(host);
@@ -25949,51 +26125,51 @@ function registerTrustCommand(program2) {
25949
26125
  const normalized = normalizeHost(host.trim());
25950
26126
  if (!isValidHost(normalized)) {
25951
26127
  console.error(
25952
- import_chalk20.default.red(`
26128
+ import_chalk21.default.red(`
25953
26129
  \u274C Invalid host: "${host}"
25954
- `) + import_chalk20.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
26130
+ `) + import_chalk21.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
25955
26131
  );
25956
26132
  process.exit(1);
25957
26133
  }
25958
26134
  addTrustedHost(normalized);
25959
- console.log(import_chalk20.default.green(`
26135
+ console.log(import_chalk21.default.green(`
25960
26136
  \u2705 ${normalized} added to trusted hosts.`));
25961
26137
  console.log(
25962
- import_chalk20.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
26138
+ import_chalk21.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
25963
26139
  );
25964
26140
  });
25965
26141
  trustCmd.command("remove <host>").description("Remove a trusted host").action((host) => {
25966
26142
  const normalized = normalizeHost(host.trim());
25967
26143
  const removed = removeTrustedHost(normalized);
25968
26144
  if (!removed) {
25969
- console.error(import_chalk20.default.yellow(`
26145
+ console.error(import_chalk21.default.yellow(`
25970
26146
  \u26A0\uFE0F "${normalized}" is not in the trusted hosts list.
25971
26147
  `));
25972
26148
  process.exit(1);
25973
26149
  }
25974
- console.log(import_chalk20.default.green(`
26150
+ console.log(import_chalk21.default.green(`
25975
26151
  \u2705 ${normalized} removed from trusted hosts.
25976
26152
  `));
25977
26153
  });
25978
26154
  trustCmd.command("list").description("Show all trusted hosts").action(() => {
25979
26155
  const hosts = readTrustedHosts();
25980
26156
  if (hosts.length === 0) {
25981
- console.log(import_chalk20.default.gray("\n No trusted hosts configured.\n"));
25982
- console.log(` Add one: ${import_chalk20.default.cyan("node9 trust add api.mycompany.com")}
26157
+ console.log(import_chalk21.default.gray("\n No trusted hosts configured.\n"));
26158
+ console.log(` Add one: ${import_chalk21.default.cyan("node9 trust add api.mycompany.com")}
25983
26159
  `);
25984
26160
  return;
25985
26161
  }
25986
- console.log(import_chalk20.default.bold("\n\u{1F513} Trusted Hosts\n"));
26162
+ console.log(import_chalk21.default.bold("\n\u{1F513} Trusted Hosts\n"));
25987
26163
  for (const entry of hosts) {
25988
26164
  const date = new Date(entry.addedAt).toLocaleDateString();
25989
- console.log(` ${import_chalk20.default.cyan(entry.host.padEnd(40))} ${import_chalk20.default.gray(`added ${date}`)}`);
26165
+ console.log(` ${import_chalk21.default.cyan(entry.host.padEnd(40))} ${import_chalk21.default.gray(`added ${date}`)}`);
25990
26166
  }
25991
26167
  console.log("");
25992
26168
  });
25993
26169
  }
25994
26170
 
25995
26171
  // src/cli/commands/mcp-pin.ts
25996
- var import_chalk21 = __toESM(require("chalk"));
26172
+ var import_chalk22 = __toESM(require("chalk"));
25997
26173
  init_mcp_pin();
25998
26174
  var import_fs54 = __toESM(require("fs"));
25999
26175
  function registerMcpPinCommand(program2) {
@@ -26014,14 +26190,14 @@ function registerMcpPinCommand(program2) {
26014
26190
  }
26015
26191
  }
26016
26192
  if (repoCorrupt) {
26017
- console.error(import_chalk21.default.red(`
26193
+ console.error(import_chalk22.default.red(`
26018
26194
  \u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
26019
26195
  process.exit(1);
26020
26196
  }
26021
26197
  if (!homeResult.ok && homeResult.reason === "corrupt") {
26022
- console.error(import_chalk21.default.red(`
26198
+ console.error(import_chalk22.default.red(`
26023
26199
  \u274C Home pin file is corrupt: ${homeResult.detail}`));
26024
- console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
26200
+ console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
26025
26201
  process.exit(1);
26026
26202
  }
26027
26203
  const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
@@ -26033,25 +26209,25 @@ function registerMcpPinCommand(program2) {
26033
26209
  merged.set(key, { entry, source: "repo" });
26034
26210
  }
26035
26211
  if (merged.size === 0) {
26036
- console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
26212
+ console.log(import_chalk22.default.gray("\nNo MCP servers are pinned yet."));
26037
26213
  console.log(
26038
- import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
26214
+ import_chalk22.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
26039
26215
  );
26040
26216
  return;
26041
26217
  }
26042
- console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
26218
+ console.log(import_chalk22.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
26043
26219
  const showSource = found.source === "repo";
26044
26220
  for (const [key, { entry, source }] of merged) {
26045
- const tag = showSource ? ` ${import_chalk21.default.yellow(`[${source}]`)}` : "";
26046
- console.log(` ${import_chalk21.default.cyan(key)}${tag} ${import_chalk21.default.gray(entry.label)}`);
26047
- console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
26048
- console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
26049
- console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
26221
+ const tag = showSource ? ` ${import_chalk22.default.yellow(`[${source}]`)}` : "";
26222
+ console.log(` ${import_chalk22.default.cyan(key)}${tag} ${import_chalk22.default.gray(entry.label)}`);
26223
+ console.log(` Tools (${entry.toolCount}): ${import_chalk22.default.white(entry.toolNames.join(", "))}`);
26224
+ console.log(` Hash: ${import_chalk22.default.gray(entry.toolsHash.slice(0, 16))}...`);
26225
+ console.log(` Pinned: ${import_chalk22.default.gray(entry.pinnedAt)}`);
26050
26226
  console.log("");
26051
26227
  }
26052
26228
  if (showSource) {
26053
- console.log(import_chalk21.default.gray(` [repo] entries come from ${found.path}`));
26054
- console.log(import_chalk21.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
26229
+ console.log(import_chalk22.default.gray(` [repo] entries come from ${found.path}`));
26230
+ console.log(import_chalk22.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
26055
26231
  }
26056
26232
  });
26057
26233
  pinSubCmd.command("promote <serverKey>").description(
@@ -26061,22 +26237,22 @@ function registerMcpPinCommand(program2) {
26061
26237
  const { repoPath, created } = promotePin(serverKey, process.cwd());
26062
26238
  if (created) {
26063
26239
  console.log(
26064
- import_chalk21.default.green(
26240
+ import_chalk22.default.green(
26065
26241
  `
26066
- \u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
26242
+ \u2705 Created ${repoPath} with the promoted pin for ${import_chalk22.default.cyan(serverKey)}.`
26067
26243
  )
26068
26244
  );
26069
26245
  } else {
26070
- console.log(import_chalk21.default.green(`
26071
- \u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
26246
+ console.log(import_chalk22.default.green(`
26247
+ \u2705 Promoted ${import_chalk22.default.cyan(serverKey)} into ${repoPath}.`));
26072
26248
  }
26073
- console.log(import_chalk21.default.gray(" Review the change and commit it:"));
26074
- console.log(import_chalk21.default.cyan(` git add ${repoPath}`));
26075
- console.log(import_chalk21.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
26249
+ console.log(import_chalk22.default.gray(" Review the change and commit it:"));
26250
+ console.log(import_chalk22.default.cyan(` git add ${repoPath}`));
26251
+ console.log(import_chalk22.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
26076
26252
  console.log("");
26077
26253
  } catch (err2) {
26078
26254
  const msg = err2 instanceof Error ? err2.message : String(err2);
26079
- console.error(import_chalk21.default.red(`
26255
+ console.error(import_chalk22.default.red(`
26080
26256
  \u274C ${msg}
26081
26257
  `));
26082
26258
  process.exit(1);
@@ -26089,138 +26265,138 @@ function registerMcpPinCommand(program2) {
26089
26265
  try {
26090
26266
  pins = readMcpPins();
26091
26267
  } catch {
26092
- console.error(import_chalk21.default.red("\n\u274C Pin file is corrupt."));
26093
- console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
26268
+ console.error(import_chalk22.default.red("\n\u274C Pin file is corrupt."));
26269
+ console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
26094
26270
  process.exit(1);
26095
26271
  }
26096
26272
  if (!pins.servers[serverKey]) {
26097
- console.error(import_chalk21.default.red(`
26273
+ console.error(import_chalk22.default.red(`
26098
26274
  \u274C No pin found for server key "${serverKey}"
26099
26275
  `));
26100
- console.error(`Run ${import_chalk21.default.cyan("node9 mcp pin list")} to see pinned servers.
26276
+ console.error(`Run ${import_chalk22.default.cyan("node9 mcp pin list")} to see pinned servers.
26101
26277
  `);
26102
26278
  process.exit(1);
26103
26279
  }
26104
26280
  const label2 = pins.servers[serverKey].label;
26105
26281
  removePin(serverKey);
26106
- console.log(import_chalk21.default.green(`
26107
- \u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
26108
- console.log(import_chalk21.default.gray(` Server: ${label2}`));
26109
- console.log(import_chalk21.default.gray(" Next connection will re-pin with current tool definitions.\n"));
26282
+ console.log(import_chalk22.default.green(`
26283
+ \u{1F513} Pin removed for ${import_chalk22.default.cyan(serverKey)}`));
26284
+ console.log(import_chalk22.default.gray(` Server: ${label2}`));
26285
+ console.log(import_chalk22.default.gray(" Next connection will re-pin with current tool definitions.\n"));
26110
26286
  });
26111
26287
  pinSubCmd.command("reset").description("Clear all MCP pins (next connection to each server will re-pin)").action(() => {
26112
26288
  const result = readMcpPinsSafe();
26113
26289
  if (!result.ok && result.reason === "missing") {
26114
- console.log(import_chalk21.default.gray("\nNo pins to clear.\n"));
26290
+ console.log(import_chalk22.default.gray("\nNo pins to clear.\n"));
26115
26291
  return;
26116
26292
  }
26117
26293
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
26118
26294
  clearAllPins();
26119
- console.log(import_chalk21.default.green(`
26295
+ console.log(import_chalk22.default.green(`
26120
26296
  \u{1F513} Cleared ${count} MCP pin(s).`));
26121
- console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
26297
+ console.log(import_chalk22.default.gray(" Next connection to each server will re-pin.\n"));
26122
26298
  });
26123
26299
  }
26124
26300
 
26125
26301
  // src/cli/commands/sync.ts
26126
- var import_chalk22 = __toESM(require("chalk"));
26302
+ var import_chalk23 = __toESM(require("chalk"));
26127
26303
  init_sync();
26128
26304
  function registerSyncCommand(program2) {
26129
26305
  const policy = program2.command("policy").description("Manage cloud policy rules");
26130
26306
  policy.command("push").description("Push this machine's effective policy to the node9 dashboard").action(async () => {
26131
- process.stdout.write(import_chalk22.default.cyan("Pushing policy to the dashboard\u2026"));
26307
+ process.stdout.write(import_chalk23.default.cyan("Pushing policy to the dashboard\u2026"));
26132
26308
  const result = await runPolicyPush();
26133
26309
  process.stdout.write("\n");
26134
26310
  if (!result.ok) {
26135
- console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
26311
+ console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
26136
26312
  process.exit(1);
26137
26313
  }
26138
- console.log(import_chalk22.default.green("\u2713 Policy mirrored to the dashboard"));
26139
- console.log(import_chalk22.default.gray(" See it under Security Policy \u2192 Machines"));
26314
+ console.log(import_chalk23.default.green("\u2713 Policy mirrored to the dashboard"));
26315
+ console.log(import_chalk23.default.gray(" See it under Security Policy \u2192 Machines"));
26140
26316
  });
26141
26317
  policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
26142
- process.stdout.write(import_chalk22.default.cyan("Syncing cloud policy rules\u2026"));
26318
+ process.stdout.write(import_chalk23.default.cyan("Syncing cloud policy rules\u2026"));
26143
26319
  const result = await runCloudSync();
26144
26320
  process.stdout.write("\n");
26145
26321
  if (!result.ok) {
26146
- console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
26322
+ console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
26147
26323
  process.exit(1);
26148
26324
  }
26149
26325
  if (result.unchanged) {
26150
26326
  console.log(
26151
- import_chalk22.default.green(
26327
+ import_chalk23.default.green(
26152
26328
  `\u2713 Already up to date \u2014 ${result.rules} rule${result.rules === 1 ? "" : "s"} cached`
26153
26329
  )
26154
26330
  );
26155
- console.log(import_chalk22.default.gray(` Cached at: ${result.fetchedAt}`));
26156
- console.log(import_chalk22.default.gray(` Server returned 304 (no changes since last sync)`));
26331
+ console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
26332
+ console.log(import_chalk23.default.gray(` Server returned 304 (no changes since last sync)`));
26157
26333
  } else {
26158
26334
  console.log(
26159
- import_chalk22.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
26335
+ import_chalk23.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
26160
26336
  );
26161
- console.log(import_chalk22.default.gray(` Cached at: ${result.fetchedAt}`));
26162
- console.log(import_chalk22.default.gray(` File: ~/.node9/rules-cache.json`));
26337
+ console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
26338
+ console.log(import_chalk23.default.gray(` File: ~/.node9/rules-cache.json`));
26163
26339
  }
26164
26340
  });
26165
26341
  policy.command("show").description("List all cloud policy rules in the local cache").action(() => {
26166
26342
  const status = getCloudSyncStatus();
26167
26343
  if (!status.cached) {
26168
- console.log(import_chalk22.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
26344
+ console.log(import_chalk23.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
26169
26345
  return;
26170
26346
  }
26171
26347
  const rules = getCloudRules() ?? [];
26172
26348
  const age = Math.round((Date.now() - new Date(status.fetchedAt).getTime()) / 6e4);
26173
26349
  console.log(
26174
- import_chalk22.default.bold(`
26175
- Cloud policy rules`) + import_chalk22.default.gray(
26350
+ import_chalk23.default.bold(`
26351
+ Cloud policy rules`) + import_chalk23.default.gray(
26176
26352
  ` (${rules.length} rule${rules.length === 1 ? "" : "s"}, synced ${age}m ago)
26177
26353
  `
26178
26354
  )
26179
26355
  );
26180
26356
  if (rules.length === 0) {
26181
- console.log(import_chalk22.default.gray(" No rules defined in cloud policy.\n"));
26357
+ console.log(import_chalk23.default.gray(" No rules defined in cloud policy.\n"));
26182
26358
  return;
26183
26359
  }
26184
26360
  for (const rule of rules) {
26185
26361
  const r = rule;
26186
- const verdictColor = r.verdict === "block" ? import_chalk22.default.red : r.verdict === "allow" ? import_chalk22.default.green : import_chalk22.default.yellow;
26362
+ const verdictColor = r.verdict === "block" ? import_chalk23.default.red : r.verdict === "allow" ? import_chalk23.default.green : import_chalk23.default.yellow;
26187
26363
  console.log(
26188
26364
  ` ${verdictColor(
26189
26365
  String(r.verdict ?? "unknown").toUpperCase().padEnd(6)
26190
- )} ${import_chalk22.default.white(String(r.name ?? "(unnamed)"))}`
26366
+ )} ${import_chalk23.default.white(String(r.name ?? "(unnamed)"))}`
26191
26367
  );
26192
- if (r.reason) console.log(import_chalk22.default.gray(` ${String(r.reason)}`));
26368
+ if (r.reason) console.log(import_chalk23.default.gray(` ${String(r.reason)}`));
26193
26369
  }
26194
26370
  console.log("");
26195
26371
  });
26196
26372
  policy.command("status").description("Show current cloud policy cache status").action(() => {
26197
26373
  const s = getCloudSyncStatus();
26198
26374
  if (!s.cached) {
26199
- console.log(import_chalk22.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
26375
+ console.log(import_chalk23.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
26200
26376
  return;
26201
26377
  }
26202
26378
  const age = Math.round((Date.now() - new Date(s.fetchedAt).getTime()) / 6e4);
26203
26379
  console.log(`
26204
- Rules : ${import_chalk22.default.green(String(s.rules))} cloud rules loaded`);
26380
+ Rules : ${import_chalk23.default.green(String(s.rules))} cloud rules loaded`);
26205
26381
  console.log(
26206
- ` Synced : ${import_chalk22.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
26382
+ ` Synced : ${import_chalk23.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
26207
26383
  );
26208
26384
  if (s.workspaceId) {
26209
- console.log(` Workspace: ${import_chalk22.default.gray(s.workspaceId)}`);
26385
+ console.log(` Workspace: ${import_chalk23.default.gray(s.workspaceId)}`);
26210
26386
  }
26211
26387
  if (s.panicMode) {
26212
26388
  console.log(
26213
- ` ${import_chalk22.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk22.default.dim("(every review-verdict becomes block)")
26389
+ ` ${import_chalk23.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk23.default.dim("(every review-verdict becomes block)")
26214
26390
  );
26215
26391
  }
26216
26392
  if (s.shadowMode) {
26217
26393
  console.log(
26218
- ` ${import_chalk22.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk22.default.dim("(blocks become would-block log entries)")
26394
+ ` ${import_chalk23.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk23.default.dim("(blocks become would-block log entries)")
26219
26395
  );
26220
26396
  }
26221
26397
  if (s.syncIntervalHours) {
26222
26398
  console.log(
26223
- import_chalk22.default.gray(
26399
+ import_chalk23.default.gray(
26224
26400
  ` Polling : every ${s.syncIntervalHours} hour${s.syncIntervalHours === 1 ? "" : "s"}`
26225
26401
  )
26226
26402
  );
@@ -26230,7 +26406,7 @@ function registerSyncCommand(program2) {
26230
26406
  }
26231
26407
 
26232
26408
  // src/cli/commands/agents.ts
26233
- var import_chalk23 = __toESM(require("chalk"));
26409
+ var import_chalk24 = __toESM(require("chalk"));
26234
26410
  init_setup();
26235
26411
  var SETUP_FN = {
26236
26412
  claude: setupClaude,
@@ -26274,30 +26450,30 @@ function registerAgentsCommand(program2) {
26274
26450
  console.log(` ${"Agent".padEnd(14)}${"Installed".padEnd(11)}${"Wired".padEnd(8)}Mode`);
26275
26451
  console.log(" " + "\u2500".repeat(44));
26276
26452
  for (const s of statuses) {
26277
- const installed = s.installed ? import_chalk23.default.green("\u2713") : import_chalk23.default.gray("\u2717");
26278
- const wired = !s.installed ? import_chalk23.default.gray("\u2014") : s.wired ? import_chalk23.default.green("\u2713") : import_chalk23.default.yellow("\u2717");
26279
- const mode = s.mode ? import_chalk23.default.gray(s.mode) : import_chalk23.default.gray("\u2014");
26280
- const hint = s.installed && !s.wired ? import_chalk23.default.gray(` \u2190 node9 agents add ${s.name}`) : "";
26453
+ const installed = s.installed ? import_chalk24.default.green("\u2713") : import_chalk24.default.gray("\u2717");
26454
+ const wired = !s.installed ? import_chalk24.default.gray("\u2014") : s.wired ? import_chalk24.default.green("\u2713") : import_chalk24.default.yellow("\u2717");
26455
+ const mode = s.mode ? import_chalk24.default.gray(s.mode) : import_chalk24.default.gray("\u2014");
26456
+ const hint = s.installed && !s.wired ? import_chalk24.default.gray(` \u2190 node9 agents add ${s.name}`) : "";
26281
26457
  console.log(` ${s.label.padEnd(14)}${installed} ${wired} ${mode}${hint}`);
26282
26458
  }
26283
26459
  console.log("");
26284
26460
  if (!anyInstalled) {
26285
26461
  console.log(
26286
- import_chalk23.default.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + import_chalk23.default.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
26462
+ import_chalk24.default.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + import_chalk24.default.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
26287
26463
  );
26288
26464
  return;
26289
26465
  }
26290
26466
  const unwired = statuses.filter((s) => s.installed && !s.wired);
26291
26467
  if (unwired.length > 0) {
26292
26468
  console.log(
26293
- import_chalk23.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk23.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
26469
+ import_chalk24.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk24.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
26294
26470
  );
26295
26471
  }
26296
26472
  if (statuses.some((s) => s.name === "gemini" && s.installed)) {
26297
26473
  console.log(
26298
- import_chalk23.default.yellow(
26474
+ import_chalk24.default.yellow(
26299
26475
  " \u26A0\uFE0F Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18.\n"
26300
- ) + import_chalk23.default.gray(" Migrate to Antigravity: ") + import_chalk23.default.white("node9 agents add antigravity") + "\n"
26476
+ ) + import_chalk24.default.gray(" Migrate to Antigravity: ") + import_chalk24.default.white("node9 agents add antigravity") + "\n"
26301
26477
  );
26302
26478
  }
26303
26479
  });
@@ -26305,7 +26481,7 @@ function registerAgentsCommand(program2) {
26305
26481
  const name = resolveAgentName(agent);
26306
26482
  const fn = SETUP_FN[name];
26307
26483
  if (!fn) {
26308
- console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26484
+ console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26309
26485
  process.exit(1);
26310
26486
  }
26311
26487
  await fn();
@@ -26314,14 +26490,14 @@ function registerAgentsCommand(program2) {
26314
26490
  const name = resolveAgentName(agent);
26315
26491
  const fn = TEARDOWN_FN[name];
26316
26492
  if (!fn) {
26317
- console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26493
+ console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26318
26494
  process.exit(1);
26319
26495
  }
26320
- console.log(import_chalk23.default.cyan(`
26496
+ console.log(import_chalk24.default.cyan(`
26321
26497
  \u{1F6E1}\uFE0F Node9: removing from ${name}...
26322
26498
  `));
26323
26499
  fn();
26324
- console.log(import_chalk23.default.gray("\n Restart the agent for changes to take effect."));
26500
+ console.log(import_chalk24.default.gray("\n Restart the agent for changes to take effect."));
26325
26501
  });
26326
26502
  }
26327
26503
 
@@ -26329,22 +26505,22 @@ function registerAgentsCommand(program2) {
26329
26505
  init_scan();
26330
26506
 
26331
26507
  // src/cli/commands/posture.ts
26332
- var import_chalk25 = __toESM(require("chalk"));
26508
+ var import_chalk26 = __toESM(require("chalk"));
26333
26509
  init_posture();
26334
26510
 
26335
26511
  // src/posture/render.ts
26336
- var import_chalk24 = __toESM(require("chalk"));
26512
+ var import_chalk25 = __toESM(require("chalk"));
26337
26513
  init_score();
26338
26514
  var ICON = {
26339
- critical: import_chalk24.default.red("\u274C"),
26340
- high: import_chalk24.default.red("\u274C"),
26341
- medium: import_chalk24.default.yellow("\u26A0\uFE0F "),
26342
- advisory: import_chalk24.default.gray("\u26A0\uFE0F ")
26515
+ critical: import_chalk25.default.red("\u274C"),
26516
+ high: import_chalk25.default.red("\u274C"),
26517
+ medium: import_chalk25.default.yellow("\u26A0\uFE0F "),
26518
+ advisory: import_chalk25.default.gray("\u26A0\uFE0F ")
26343
26519
  };
26344
26520
  var TIER_LABEL = {
26345
- good: import_chalk24.default.green("Good"),
26346
- "at-risk": import_chalk24.default.yellow("At risk"),
26347
- critical: import_chalk24.default.red("Critical")
26521
+ good: import_chalk25.default.green("Good"),
26522
+ "at-risk": import_chalk25.default.yellow("At risk"),
26523
+ critical: import_chalk25.default.red("Critical")
26348
26524
  };
26349
26525
  function wrap(text, width) {
26350
26526
  const out = [];
@@ -26362,35 +26538,35 @@ function wrap(text, width) {
26362
26538
  }
26363
26539
  var LABEL_WIDTH = 14;
26364
26540
  function label(category) {
26365
- return import_chalk24.default.bold(category.padEnd(Math.max(LABEL_WIDTH, category.length + 1)));
26541
+ return import_chalk25.default.bold(category.padEnd(Math.max(LABEL_WIDTH, category.length + 1)));
26366
26542
  }
26367
26543
  function renderFinding(f, showWeight = false) {
26368
26544
  const lines = [];
26369
- const wt = showWeight && f.scoreWeight ? import_chalk24.default.cyan.bold(`+${f.scoreWeight} `) : "";
26545
+ const wt = showWeight && f.scoreWeight ? import_chalk25.default.cyan.bold(`+${f.scoreWeight} `) : "";
26370
26546
  lines.push(` ${ICON[f.severity]} ${label(f.category)}${wt}${f.title}`);
26371
26547
  const indent = " ".repeat(2 + 3 + LABEL_WIDTH);
26372
26548
  const width = 80 - indent.length;
26373
26549
  for (const s of [f.what, f.why, f.who]) {
26374
- if (s) for (const l of wrap(s, width)) lines.push(indent + import_chalk24.default.gray(l));
26550
+ if (s) for (const l of wrap(s, width)) lines.push(indent + import_chalk25.default.gray(l));
26375
26551
  }
26376
- for (const d of f.detail) lines.push(indent + import_chalk24.default.gray(d));
26552
+ for (const d of f.detail) lines.push(indent + import_chalk25.default.gray(d));
26377
26553
  if (f.fix) {
26378
26554
  let first = true;
26379
26555
  for (const seg of f.fix.split("\n")) {
26380
26556
  for (const l of wrap(seg, width - 2)) {
26381
- lines.push(indent + import_chalk24.default.cyan(first ? "\u2192 " + l : " " + l));
26557
+ lines.push(indent + import_chalk25.default.cyan(first ? "\u2192 " + l : " " + l));
26382
26558
  first = false;
26383
26559
  }
26384
26560
  }
26385
26561
  }
26386
26562
  const tradeoff = [
26387
- [f.gain, "gain: ", import_chalk24.default.green],
26388
- [f.cost, "cost: ", import_chalk24.default.yellow]
26563
+ [f.gain, "gain: ", import_chalk25.default.green],
26564
+ [f.cost, "cost: ", import_chalk25.default.yellow]
26389
26565
  ];
26390
26566
  for (const [text, lbl, color2] of tradeoff) {
26391
26567
  if (!text) continue;
26392
26568
  wrap(text, width - 6).forEach((l, i) => {
26393
- lines.push(indent + (i === 0 ? color2(lbl) : " ") + import_chalk24.default.gray(l));
26569
+ lines.push(indent + (i === 0 ? color2(lbl) : " ") + import_chalk25.default.gray(l));
26394
26570
  });
26395
26571
  }
26396
26572
  return lines;
@@ -26400,12 +26576,12 @@ function renderPosture(result) {
26400
26576
  const tier = TIER_LABEL[result.tier];
26401
26577
  lines.push("");
26402
26578
  lines.push(
26403
- import_chalk24.default.cyan.bold(`\u{1F6E1}\uFE0F Node9 Posture`) + import_chalk24.default.gray(` \u2014 ${result.agent}`) + ` ${import_chalk24.default.bold(`Score: ${result.score}/100`)} (${tier})`
26579
+ import_chalk25.default.cyan.bold(`\u{1F6E1}\uFE0F Node9 Posture`) + import_chalk25.default.gray(` \u2014 ${result.agent}`) + ` ${import_chalk25.default.bold(`Score: ${result.score}/100`)} (${tier})`
26404
26580
  );
26405
26581
  const headroom = openHeadroom(result.findings);
26406
26582
  if (headroom > 0) {
26407
26583
  lines.push(
26408
- " " + import_chalk24.default.gray(
26584
+ " " + import_chalk25.default.gray(
26409
26585
  `${headroom} pts of headroom below \u2014 each layer adds security at some cost to flexibility. You choose which to close.`
26410
26586
  )
26411
26587
  );
@@ -26413,21 +26589,21 @@ function renderPosture(result) {
26413
26589
  lines.push("");
26414
26590
  if (result.headline) {
26415
26591
  const indent = " ";
26416
- lines.push(` ${import_chalk24.default.red.bold("\u{1F525} Biggest risk")}`);
26417
- for (const l of wrap(result.headline.risk, 74)) lines.push(indent + import_chalk24.default.white(l));
26592
+ lines.push(` ${import_chalk25.default.red.bold("\u{1F525} Biggest risk")}`);
26593
+ for (const l of wrap(result.headline.risk, 74)) lines.push(indent + import_chalk25.default.white(l));
26418
26594
  const action = wrap(`Do this first: ${result.headline.action}`, 72);
26419
- action.forEach((l, i) => lines.push(indent + import_chalk24.default.cyan(i === 0 ? "\u2192 " + l : " " + l)));
26595
+ action.forEach((l, i) => lines.push(indent + import_chalk25.default.cyan(i === 0 ? "\u2192 " + l : " " + l)));
26420
26596
  lines.push("");
26421
26597
  }
26422
26598
  const covered = result.findings.filter((f) => f.coverage?.state === "covered");
26423
26599
  const open = result.findings.filter((f) => f.coverage?.state !== "covered");
26424
26600
  if (covered.length > 0) {
26425
- lines.push(" " + import_chalk24.default.green("\u{1F7E2} ON NOW \u2014 node9 is enforcing these (your floor)"));
26601
+ lines.push(" " + import_chalk25.default.green("\u{1F7E2} ON NOW \u2014 node9 is enforcing these (your floor)"));
26426
26602
  for (const f of covered) {
26427
26603
  const gated = f.coverage?.level === "review" ? "approval-gating" : "blocking";
26428
26604
  const via = f.coverage?.via ?? "node9";
26429
26605
  lines.push(
26430
- ` ${import_chalk24.default.green("\u2705")} ${label(f.category)}${import_chalk24.default.gray(`${via} is ${gated} this`)}`
26606
+ ` ${import_chalk25.default.green("\u2705")} ${label(f.category)}${import_chalk25.default.gray(`${via} is ${gated} this`)}`
26431
26607
  );
26432
26608
  }
26433
26609
  lines.push("");
@@ -26436,24 +26612,24 @@ function renderPosture(result) {
26436
26612
  const reduceOpen = open.filter((f) => f.owner !== "node9" && f.node9Reduces);
26437
26613
  const osOpen = open.filter((f) => f.owner !== "node9" && !f.node9Reduces);
26438
26614
  if (node9Open.length > 0) {
26439
- lines.push(" " + import_chalk24.default.cyan.bold("\u{1F527} node9 can fix these \u2014 run the command"));
26615
+ lines.push(" " + import_chalk25.default.cyan.bold("\u{1F527} node9 can fix these \u2014 run the command"));
26440
26616
  for (const f of node9Open) lines.push(...renderFinding(f, true));
26441
26617
  }
26442
26618
  if (reduceOpen.length > 0) {
26443
26619
  if (node9Open.length > 0) lines.push("");
26444
- lines.push(" " + import_chalk24.default.yellow.bold("\u{1F512} AVAILABLE \u2014 turn on to harden (each has a tradeoff)"));
26620
+ lines.push(" " + import_chalk25.default.yellow.bold("\u{1F512} AVAILABLE \u2014 turn on to harden (each has a tradeoff)"));
26445
26621
  for (const f of reduceOpen) lines.push(...renderFinding(f, true));
26446
26622
  }
26447
26623
  if (osOpen.length > 0) {
26448
26624
  if (node9Open.length > 0 || reduceOpen.length > 0) lines.push("");
26449
- lines.push(" " + import_chalk24.default.bold("\u{1F9F1} YOUR PART \u2014 node9 can't fix these (OS-level)"));
26625
+ lines.push(" " + import_chalk25.default.bold("\u{1F9F1} YOUR PART \u2014 node9 can't fix these (OS-level)"));
26450
26626
  for (const f of osOpen) lines.push(...renderFinding(f));
26451
26627
  }
26452
26628
  for (const cat of result.passedCategories) {
26453
- lines.push(` ${import_chalk24.default.green("\u2705")} ${label(cat)}${import_chalk24.default.gray("no issues found")}`);
26629
+ lines.push(` ${import_chalk25.default.green("\u2705")} ${label(cat)}${import_chalk25.default.gray("no issues found")}`);
26454
26630
  }
26455
26631
  for (const cat of result.erroredCategories) {
26456
- lines.push(` ${import_chalk24.default.gray("\u2022")} ${label(cat)}${import_chalk24.default.gray("could not be checked")}`);
26632
+ lines.push(` ${import_chalk25.default.gray("\u2022")} ${label(cat)}${import_chalk25.default.gray("could not be checked")}`);
26457
26633
  }
26458
26634
  lines.push("");
26459
26635
  const crit = open.filter((f) => f.severity === "critical").length;
@@ -26461,16 +26637,16 @@ function renderPosture(result) {
26461
26637
  const med = open.filter((f) => f.severity === "medium").length;
26462
26638
  const adv = open.filter((f) => f.severity === "advisory").length;
26463
26639
  const parts = [];
26464
- if (crit) parts.push(import_chalk24.default.red(`${crit} critical`));
26465
- if (high) parts.push(import_chalk24.default.red(`${high} high`));
26466
- if (med) parts.push(import_chalk24.default.yellow(`${med} medium`));
26467
- if (adv) parts.push(import_chalk24.default.gray(`${adv} advisory`));
26468
- const summary = parts.length ? parts.join(" \xB7 ") : import_chalk24.default.green("no findings");
26640
+ if (crit) parts.push(import_chalk25.default.red(`${crit} critical`));
26641
+ if (high) parts.push(import_chalk25.default.red(`${high} high`));
26642
+ if (med) parts.push(import_chalk25.default.yellow(`${med} medium`));
26643
+ if (adv) parts.push(import_chalk25.default.gray(`${adv} advisory`));
26644
+ const summary = parts.length ? parts.join(" \xB7 ") : import_chalk25.default.green("no findings");
26469
26645
  lines.push(` ${summary}`);
26470
26646
  lines.push("");
26471
- lines.push(" " + import_chalk24.default.bold("Track this across your fleet & keep it green:"));
26647
+ lines.push(" " + import_chalk25.default.bold("Track this across your fleet & keep it green:"));
26472
26648
  lines.push(
26473
- " " + import_chalk24.default.dim("\u2192 ") + import_chalk24.default.cyan.underline("https://node9.ai/auth/signup?ref=cli_posture")
26649
+ " " + import_chalk25.default.dim("\u2192 ") + import_chalk25.default.cyan.underline("https://node9.ai/auth/signup?ref=cli_posture")
26474
26650
  );
26475
26651
  lines.push("");
26476
26652
  return lines.join("\n");
@@ -26490,11 +26666,11 @@ function registerPostureCommand(program2) {
26490
26666
  if (opts.ship) {
26491
26667
  const creds = readCredentials();
26492
26668
  if (!creds) {
26493
- console.error(import_chalk25.default.gray(" Run `node9 login` to ship this to your dashboard."));
26669
+ console.error(import_chalk26.default.gray(" Run `node9 login` to ship this to your dashboard."));
26494
26670
  } else {
26495
26671
  const ok2 = await shipPosture(result, creds);
26496
26672
  console.error(
26497
- ok2 ? import_chalk25.default.gray(" \u2713 Shipped to your node9 dashboard.") : import_chalk25.default.gray(" Could not reach the dashboard \u2014 saved locally only.")
26673
+ ok2 ? import_chalk26.default.gray(" \u2713 Shipped to your node9 dashboard.") : import_chalk26.default.gray(" Could not reach the dashboard \u2014 saved locally only.")
26498
26674
  );
26499
26675
  }
26500
26676
  }
@@ -26503,7 +26679,7 @@ function registerPostureCommand(program2) {
26503
26679
  }
26504
26680
 
26505
26681
  // src/cli/commands/egress.ts
26506
- var import_chalk26 = __toESM(require("chalk"));
26682
+ var import_chalk27 = __toESM(require("chalk"));
26507
26683
  init_config();
26508
26684
  init_dist();
26509
26685
  function guard(fn) {
@@ -26511,7 +26687,7 @@ function guard(fn) {
26511
26687
  fn();
26512
26688
  return true;
26513
26689
  } catch (err2) {
26514
- console.error(import_chalk26.default.red(`
26690
+ console.error(import_chalk27.default.red(`
26515
26691
  \u2717 ${err2.message}
26516
26692
  `));
26517
26693
  process.exitCode = 1;
@@ -26526,19 +26702,19 @@ function addHost(list, host) {
26526
26702
  }
26527
26703
  function showStatus() {
26528
26704
  const e = getConfig().policy.egress;
26529
- const state = !e.enabled ? import_chalk26.default.red("OFF \u2014 your agent can reach any host") : e.mode === "block" ? import_chalk26.default.green("LOCKED (block) \u2014 unknown hosts are denied") : import_chalk26.default.yellow("WATCHING (review) \u2014 unknown hosts prompt you");
26530
- console.log(import_chalk26.default.cyan.bold("\n\u{1F310} Egress control"));
26705
+ const state = !e.enabled ? import_chalk27.default.red("OFF \u2014 your agent can reach any host") : e.mode === "block" ? import_chalk27.default.green("LOCKED (block) \u2014 unknown hosts are denied") : import_chalk27.default.yellow("WATCHING (review) \u2014 unknown hosts prompt you");
26706
+ console.log(import_chalk27.default.cyan.bold("\n\u{1F310} Egress control"));
26531
26707
  console.log(" State: " + state);
26532
26708
  console.log(
26533
- import_chalk26.default.gray(
26709
+ import_chalk27.default.gray(
26534
26710
  ` ${DEFAULT_EGRESS_ALLOWLIST.length} common dev/LLM hosts are always allowed (github, npm, pypi, anthropic, \u2026).`
26535
26711
  )
26536
26712
  );
26537
26713
  if (e.allow.length) console.log(" Your allow: " + e.allow.join(", "));
26538
26714
  if (e.deny.length) console.log(" Your deny: " + e.deny.join(", "));
26539
26715
  if (!e.enabled) {
26540
- console.log(import_chalk26.default.gray("\n Turn it on: node9 egress watch (prompt on unknown hosts)"));
26541
- console.log(import_chalk26.default.gray(" node9 egress lock (hard-block unknown hosts)"));
26716
+ console.log(import_chalk27.default.gray("\n Turn it on: node9 egress watch (prompt on unknown hosts)"));
26717
+ console.log(import_chalk27.default.gray(" node9 egress lock (hard-block unknown hosts)"));
26542
26718
  }
26543
26719
  console.log("");
26544
26720
  }
@@ -26546,43 +26722,43 @@ function registerEgressCommand(program2) {
26546
26722
  const egress = program2.command("egress").description("Control where your agent can send data (egress allowlist)");
26547
26723
  egress.command("watch").description("Prompt before the agent reaches an unknown host (review mode)").action(() => {
26548
26724
  if (!mutate({ enabled: true, mode: "review" })) return;
26549
- console.log(import_chalk26.default.green("\n\u2713 Egress is now watched (review mode)."));
26725
+ console.log(import_chalk27.default.green("\n\u2713 Egress is now watched (review mode)."));
26550
26726
  console.log(
26551
- import_chalk26.default.gray(" Routine hosts (LLM APIs, package registries, localhost) are allowed.")
26727
+ import_chalk27.default.gray(" Routine hosts (LLM APIs, package registries, localhost) are allowed.")
26552
26728
  );
26553
26729
  console.log(
26554
- import_chalk26.default.gray(" An unknown host will prompt you \u2014 run `node9 egress lock` to hard-block.\n")
26730
+ import_chalk27.default.gray(" An unknown host will prompt you \u2014 run `node9 egress lock` to hard-block.\n")
26555
26731
  );
26556
26732
  });
26557
26733
  egress.command("lock").description("Block the agent from reaching unknown hosts (block mode)").action(() => {
26558
26734
  if (!mutate({ enabled: true, mode: "block" })) return;
26559
- console.log(import_chalk26.default.green("\n\u2713 Egress is now locked (block mode)."));
26560
- console.log(import_chalk26.default.gray(" Routine hosts are still allowed; unknown hosts are denied."));
26561
- console.log(import_chalk26.default.gray(" Allow a specific host with `node9 egress allow <host>`.\n"));
26735
+ console.log(import_chalk27.default.green("\n\u2713 Egress is now locked (block mode)."));
26736
+ console.log(import_chalk27.default.gray(" Routine hosts are still allowed; unknown hosts are denied."));
26737
+ console.log(import_chalk27.default.gray(" Allow a specific host with `node9 egress allow <host>`.\n"));
26562
26738
  });
26563
26739
  egress.command("allow <host>").description("Allow an extra host (glob, e.g. *.mycorp.com)").action((host) => {
26564
26740
  if (!addHost("allow", host)) return;
26565
- console.log(import_chalk26.default.green(`
26741
+ console.log(import_chalk27.default.green(`
26566
26742
  \u2713 Allowed egress to ${host}.
26567
26743
  `));
26568
26744
  });
26569
26745
  egress.command("deny <host>").description("Block an extra host (deny always wins)").action((host) => {
26570
26746
  if (!addHost("deny", host)) return;
26571
- console.log(import_chalk26.default.green(`
26747
+ console.log(import_chalk27.default.green(`
26572
26748
  \u2713 Denied egress to ${host}.
26573
26749
  `));
26574
26750
  });
26575
26751
  egress.command("off").description("Turn egress control off").action(() => {
26576
26752
  if (!mutate({ enabled: false })) return;
26577
26753
  console.log(
26578
- import_chalk26.default.yellow("\n\u2713 Egress control is off \u2014 the agent can reach any host again.\n")
26754
+ import_chalk27.default.yellow("\n\u2713 Egress control is off \u2014 the agent can reach any host again.\n")
26579
26755
  );
26580
26756
  });
26581
26757
  egress.action(showStatus);
26582
26758
  }
26583
26759
 
26584
26760
  // src/cli/commands/jail.ts
26585
- var import_chalk27 = __toESM(require("chalk"));
26761
+ var import_chalk28 = __toESM(require("chalk"));
26586
26762
 
26587
26763
  // src/shields/jail.ts
26588
26764
  var import_fs55 = __toESM(require("fs"));
@@ -26677,20 +26853,20 @@ function registerJailCommand(program2) {
26677
26853
  regenerateUserJail(paths);
26678
26854
  appendConfigAudit({ event: "jail-add", path: p.trim(), verdict });
26679
26855
  } catch (err2) {
26680
- console.error(import_chalk27.default.red(`
26856
+ console.error(import_chalk28.default.red(`
26681
26857
  \u274C ${err2.message}
26682
26858
  `));
26683
26859
  process.exit(1);
26684
26860
  return;
26685
26861
  }
26686
- console.log(import_chalk27.default.green(`
26862
+ console.log(import_chalk28.default.green(`
26687
26863
  \u2705 Jailed ${p} (${verdict}).`));
26688
26864
  console.log(
26689
- import_chalk27.default.gray(
26865
+ import_chalk28.default.gray(
26690
26866
  ` AI reads of this path now ${verdict === "block" ? "BLOCK" : "require approval"}.`
26691
26867
  )
26692
26868
  );
26693
- console.log(import_chalk27.default.gray(` Preview: ${import_chalk27.default.cyan(`node9 explain bash "cat ${p}"`)}
26869
+ console.log(import_chalk28.default.gray(` Preview: ${import_chalk28.default.cyan(`node9 explain bash "cat ${p}"`)}
26694
26870
  `));
26695
26871
  });
26696
26872
  jail.command("remove <path>").description("Remove a user-added jail path (built-in paths are not removable)").action((p) => {
@@ -26698,17 +26874,17 @@ function registerJailCommand(program2) {
26698
26874
  try {
26699
26875
  result = removeJailPath(p);
26700
26876
  } catch (err2) {
26701
- console.error(import_chalk27.default.red(`
26877
+ console.error(import_chalk28.default.red(`
26702
26878
  \u274C ${err2.message}
26703
26879
  `));
26704
26880
  process.exit(1);
26705
26881
  return;
26706
26882
  }
26707
26883
  if (!result.removed) {
26708
- console.error(import_chalk27.default.yellow(`
26884
+ console.error(import_chalk28.default.yellow(`
26709
26885
  \u2139\uFE0F "${p}" is not a user-added jail path.
26710
26886
  `));
26711
- console.error(import_chalk27.default.gray(` Run ${import_chalk27.default.cyan("node9 jail list")} to see your paths.
26887
+ console.error(import_chalk28.default.gray(` Run ${import_chalk28.default.cyan("node9 jail list")} to see your paths.
26712
26888
  `));
26713
26889
  process.exit(1);
26714
26890
  return;
@@ -26717,39 +26893,39 @@ function registerJailCommand(program2) {
26717
26893
  regenerateUserJail(result.paths);
26718
26894
  appendConfigAudit({ event: "jail-remove", path: p.trim() });
26719
26895
  } catch (err2) {
26720
- console.error(import_chalk27.default.red(`
26896
+ console.error(import_chalk28.default.red(`
26721
26897
  \u274C ${err2.message}
26722
26898
  `));
26723
26899
  process.exit(1);
26724
26900
  return;
26725
26901
  }
26726
- console.log(import_chalk27.default.green(`
26902
+ console.log(import_chalk28.default.green(`
26727
26903
  \u2705 Removed ${p} from the jail.
26728
26904
  `));
26729
26905
  });
26730
26906
  jail.command("list").description("Show built-in + user-added jail paths").action(() => {
26731
- console.log(import_chalk27.default.bold("\n\u{1F512} Credential Jail\n"));
26732
- console.log(import_chalk27.default.gray(" Built-in (always on, not removable):"));
26733
- for (const b of BUILTIN_JAIL) console.log(` ${import_chalk27.default.gray("\u2022")} ${b}`);
26907
+ console.log(import_chalk28.default.bold("\n\u{1F512} Credential Jail\n"));
26908
+ console.log(import_chalk28.default.gray(" Built-in (always on, not removable):"));
26909
+ for (const b of BUILTIN_JAIL) console.log(` ${import_chalk28.default.gray("\u2022")} ${b}`);
26734
26910
  console.log("");
26735
26911
  let user;
26736
26912
  try {
26737
26913
  user = readJailPaths();
26738
26914
  } catch (err2) {
26739
- console.error(import_chalk27.default.red(` \u2717 ${err2.message}
26915
+ console.error(import_chalk28.default.red(` \u2717 ${err2.message}
26740
26916
  `));
26741
26917
  process.exit(1);
26742
26918
  return;
26743
26919
  }
26744
26920
  if (user.length === 0) {
26745
26921
  console.log(
26746
- import_chalk27.default.gray(" Your paths: (none) \u2014 add one with ") + import_chalk27.default.cyan("node9 jail add <path>")
26922
+ import_chalk28.default.gray(" Your paths: (none) \u2014 add one with ") + import_chalk28.default.cyan("node9 jail add <path>")
26747
26923
  );
26748
26924
  } else {
26749
- console.log(import_chalk27.default.gray(" Your paths (removable):"));
26925
+ console.log(import_chalk28.default.gray(" Your paths (removable):"));
26750
26926
  for (const u of user) {
26751
- const v = u.verdict === "block" ? import_chalk27.default.red("block ") : import_chalk27.default.yellow("review");
26752
- console.log(` ${v} ${import_chalk27.default.cyan(u.path)}`);
26927
+ const v = u.verdict === "block" ? import_chalk28.default.red("block ") : import_chalk28.default.yellow("review");
26928
+ console.log(` ${v} ${import_chalk28.default.cyan(u.path)}`);
26753
26929
  }
26754
26930
  }
26755
26931
  console.log("");
@@ -26757,7 +26933,7 @@ function registerJailCommand(program2) {
26757
26933
  }
26758
26934
 
26759
26935
  // src/cli/commands/sandbox.ts
26760
- var import_chalk28 = __toESM(require("chalk"));
26936
+ var import_chalk29 = __toESM(require("chalk"));
26761
26937
  var import_fs58 = __toESM(require("fs"));
26762
26938
  var import_path56 = __toESM(require("path"));
26763
26939
  var import_child_process13 = require("child_process");
@@ -26995,16 +27171,16 @@ function registerSandboxCommand(program2, version2) {
26995
27171
  const p = sandboxConfigPath();
26996
27172
  if (import_fs58.default.existsSync(p)) {
26997
27173
  console.log(
26998
- import_chalk28.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
27174
+ import_chalk29.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
26999
27175
  );
27000
27176
  return;
27001
27177
  }
27002
27178
  import_fs58.default.writeFileSync(p, scaffoldSandboxYaml(agent));
27003
27179
  console.log(
27004
- import_chalk28.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk28.default.dim(` (agent: ${agent})`)
27180
+ import_chalk29.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk29.default.dim(` (agent: ${agent})`)
27005
27181
  );
27006
27182
  console.log(
27007
- import_chalk28.default.dim(" Edit it (mounts / allow / expose), then: ") + import_chalk28.default.cyan("node9 sandbox run")
27183
+ import_chalk29.default.dim(" Edit it (mounts / allow / expose), then: ") + import_chalk29.default.cyan("node9 sandbox run")
27008
27184
  );
27009
27185
  });
27010
27186
  cmd.command("run [agent]").description("Build (if needed) + run the agent jailed. Extra args after -- go to the agent.").allowUnknownOption(true).allowExcessArguments(true).action((agentArg, _opts, command) => {
@@ -27014,7 +27190,7 @@ function registerSandboxCommand(program2, version2) {
27014
27190
  const engine = detectEngine(sandbox.runtime.engine);
27015
27191
  if (!engine.available) {
27016
27192
  console.error(
27017
- import_chalk28.default.red(` ${sandbox.runtime.engine} not found.`) + import_chalk28.default.dim(` Install it first \u2014 node9 sandbox needs a container runtime.`)
27193
+ import_chalk29.default.red(` ${sandbox.runtime.engine} not found.`) + import_chalk29.default.dim(` Install it first \u2014 node9 sandbox needs a container runtime.`)
27018
27194
  );
27019
27195
  process.exit(1);
27020
27196
  }
@@ -27027,11 +27203,11 @@ function registerSandboxCommand(program2, version2) {
27027
27203
  });
27028
27204
  if (compiled.rejected.length) {
27029
27205
  console.log(
27030
- import_chalk28.default.yellow(` \u26A0 ignoring invalid allow hosts: ${compiled.rejected.join(", ")}`)
27206
+ import_chalk29.default.yellow(` \u26A0 ignoring invalid allow hosts: ${compiled.rejected.join(", ")}`)
27031
27207
  );
27032
27208
  }
27033
27209
  if (compiled.denied.length) {
27034
- console.log(import_chalk28.default.dim(` (denied: ${compiled.denied.join(", ")})`));
27210
+ console.log(import_chalk29.default.dim(` (denied: ${compiled.denied.join(", ")})`));
27035
27211
  }
27036
27212
  const allowlistPath = writeAllowlist(cwd, compiled.allow);
27037
27213
  const dockerfile = renderDockerfile(sandbox, node9Version2);
@@ -27044,12 +27220,12 @@ function registerSandboxCommand(program2, version2) {
27044
27220
  const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
27045
27221
  const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
27046
27222
  if (needBuild) {
27047
- console.log(import_chalk28.default.dim(` building ${image} \u2026`));
27223
+ console.log(import_chalk29.default.dim(` building ${image} \u2026`));
27048
27224
  const b = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["build", "-t", image, buildDir], {
27049
27225
  stdio: "inherit"
27050
27226
  });
27051
27227
  if (b.status !== 0) {
27052
- console.error(import_chalk28.default.red(" build failed."));
27228
+ console.error(import_chalk29.default.red(" build failed."));
27053
27229
  process.exit(b.status ?? 1);
27054
27230
  }
27055
27231
  import_fs58.default.writeFileSync(hashFile, hash);
@@ -27067,15 +27243,15 @@ function registerSandboxCommand(program2, version2) {
27067
27243
  if (sandbox.node9.mountAgentCredentials) {
27068
27244
  const creds = agentCredentialsMount(sandbox.agent);
27069
27245
  if (import_fs58.default.existsSync(creds.hostPath)) {
27070
- console.log(import_chalk28.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
27246
+ console.log(import_chalk29.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
27071
27247
  } else {
27072
27248
  console.log(
27073
- import_chalk28.default.yellow(` \u26A0 ${creds.hostPath} not found \u2014 `) + import_chalk28.default.dim(`the agent must auth via an env key in env.pass.`)
27249
+ import_chalk29.default.yellow(` \u26A0 ${creds.hostPath} not found \u2014 `) + import_chalk29.default.dim(`the agent must auth via an env key in env.pass.`)
27074
27250
  );
27075
27251
  }
27076
27252
  }
27077
27253
  console.log(
27078
- import_chalk28.default.green(` \u{1F6E1}\uFE0F ${sandbox.agent} jailed \u2014 ${compiled.allow.length} hosts allowed
27254
+ import_chalk29.default.green(` \u{1F6E1}\uFE0F ${sandbox.agent} jailed \u2014 ${compiled.allow.length} hosts allowed
27079
27255
  `)
27080
27256
  );
27081
27257
  const r = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, runArgs, { stdio: "inherit" });
@@ -27084,7 +27260,7 @@ function registerSandboxCommand(program2, version2) {
27084
27260
  cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
27085
27261
  const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
27086
27262
  if (!import_fs58.default.existsSync(auditPath)) {
27087
- console.log(import_chalk28.default.dim(" no sandbox audit yet."));
27263
+ console.log(import_chalk29.default.dim(" no sandbox audit yet."));
27088
27264
  return;
27089
27265
  }
27090
27266
  (0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
@@ -27092,7 +27268,7 @@ function registerSandboxCommand(program2, version2) {
27092
27268
  cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
27093
27269
  const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
27094
27270
  if (!import_fs58.default.existsSync(auditPath)) {
27095
- console.log(import_chalk28.default.dim(" no sandbox audit yet."));
27271
+ console.log(import_chalk29.default.dim(" no sandbox audit yet."));
27096
27272
  return;
27097
27273
  }
27098
27274
  process.stdout.write(import_fs58.default.readFileSync(auditPath, "utf-8"));
@@ -27110,12 +27286,12 @@ function registerSandboxCommand(program2, version2) {
27110
27286
  });
27111
27287
  }
27112
27288
  import_fs58.default.rmSync(import_path56.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
27113
- console.log(import_chalk28.default.green(" \u2713 sandbox image + build + data removed."));
27289
+ console.log(import_chalk29.default.green(" \u2713 sandbox image + build + data removed."));
27114
27290
  });
27115
27291
  }
27116
27292
 
27117
27293
  // src/cli/commands/sessions.ts
27118
- var import_chalk29 = __toESM(require("chalk"));
27294
+ var import_chalk30 = __toESM(require("chalk"));
27119
27295
  var import_fs59 = __toESM(require("fs"));
27120
27296
  var import_path57 = __toESM(require("path"));
27121
27297
  var import_os50 = __toESM(require("os"));
@@ -27611,11 +27787,11 @@ function toolInputSummary(tool, input) {
27611
27787
  }
27612
27788
  function toolColor(tool) {
27613
27789
  const t = tool.toLowerCase();
27614
- if (t === "bash" || t === "execute_bash") return import_chalk29.default.red;
27615
- if (t === "write") return import_chalk29.default.green;
27616
- if (t === "edit" || t === "notebookedit") return import_chalk29.default.yellow;
27617
- if (t === "read") return import_chalk29.default.cyan;
27618
- return import_chalk29.default.gray;
27790
+ if (t === "bash" || t === "execute_bash") return import_chalk30.default.red;
27791
+ if (t === "write") return import_chalk30.default.green;
27792
+ if (t === "edit" || t === "notebookedit") return import_chalk30.default.yellow;
27793
+ if (t === "read") return import_chalk30.default.cyan;
27794
+ return import_chalk30.default.gray;
27619
27795
  }
27620
27796
  function barStr2(value, max, width) {
27621
27797
  if (max === 0 || width <= 0) return "\u2591".repeat(width);
@@ -27625,7 +27801,7 @@ function barStr2(value, max, width) {
27625
27801
  function colorBar2(value, max, width) {
27626
27802
  const s = barStr2(value, max, width);
27627
27803
  const filled = Math.max(1, Math.round(max > 0 ? value / max * width : 0));
27628
- return import_chalk29.default.cyan(s.slice(0, filled)) + import_chalk29.default.dim(s.slice(filled));
27804
+ return import_chalk30.default.cyan(s.slice(0, filled)) + import_chalk30.default.dim(s.slice(filled));
27629
27805
  }
27630
27806
  function renderSummary(summaries) {
27631
27807
  const totalTools = summaries.reduce((n, s) => n + s.toolCalls.length, 0);
@@ -27655,45 +27831,45 @@ function renderSummary(summaries) {
27655
27831
  }
27656
27832
  const topProjects = [...projCosts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
27657
27833
  const W = 20;
27658
- console.log(import_chalk29.default.dim(" " + "\u2500".repeat(70)));
27834
+ console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
27659
27835
  console.log(
27660
- " " + import_chalk29.default.bold.white(String(summaries.length).padEnd(4)) + import_chalk29.default.dim("sessions ") + import_chalk29.default.bold.yellow(fmtCost3(totalCost).padEnd(10)) + import_chalk29.default.dim("total ") + import_chalk29.default.bold.white(String(totalTools).padEnd(6)) + import_chalk29.default.dim("tool calls ") + import_chalk29.default.bold.white(String(totalFiles)) + import_chalk29.default.dim(" files modified") + (totalBlocked > 0 ? import_chalk29.default.dim(" ") + import_chalk29.default.red.bold(String(totalBlocked)) + import_chalk29.default.dim(" blocked by node9") : "")
27836
+ " " + import_chalk30.default.bold.white(String(summaries.length).padEnd(4)) + import_chalk30.default.dim("sessions ") + import_chalk30.default.bold.yellow(fmtCost3(totalCost).padEnd(10)) + import_chalk30.default.dim("total ") + import_chalk30.default.bold.white(String(totalTools).padEnd(6)) + import_chalk30.default.dim("tool calls ") + import_chalk30.default.bold.white(String(totalFiles)) + import_chalk30.default.dim(" files modified") + (totalBlocked > 0 ? import_chalk30.default.dim(" ") + import_chalk30.default.red.bold(String(totalBlocked)) + import_chalk30.default.dim(" blocked by node9") : "")
27661
27837
  );
27662
27838
  console.log(
27663
- " " + import_chalk29.default.dim("avg ") + import_chalk29.default.white(fmtCost3(avgCost).padEnd(10)) + import_chalk29.default.dim("/session ") + import_chalk29.default.green(String(snapshots)) + import_chalk29.default.dim(` of ${summaries.length} sessions had snapshots`)
27839
+ " " + import_chalk30.default.dim("avg ") + import_chalk30.default.white(fmtCost3(avgCost).padEnd(10)) + import_chalk30.default.dim("/session ") + import_chalk30.default.green(String(snapshots)) + import_chalk30.default.dim(` of ${summaries.length} sessions had snapshots`)
27664
27840
  );
27665
27841
  console.log("");
27666
- console.log(" " + import_chalk29.default.dim("Tool breakdown:"));
27842
+ console.log(" " + import_chalk30.default.dim("Tool breakdown:"));
27667
27843
  const maxGroup = Math.max(...Object.values(groups));
27668
27844
  for (const [label2, count] of Object.entries(groups)) {
27669
27845
  if (count === 0) continue;
27670
27846
  const pct = totalTools > 0 ? Math.round(count / totalTools * 100) : 0;
27671
27847
  console.log(
27672
- " " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk29.default.white(String(count).padStart(4)) + import_chalk29.default.dim(` (${String(pct)}%)`)
27848
+ " " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk30.default.white(String(count).padStart(4)) + import_chalk30.default.dim(` (${String(pct)}%)`)
27673
27849
  );
27674
27850
  }
27675
27851
  console.log("");
27676
27852
  if (topProjects.length > 1) {
27677
- console.log(" " + import_chalk29.default.dim("Cost by project:"));
27853
+ console.log(" " + import_chalk30.default.dim("Cost by project:"));
27678
27854
  const maxProjCost = topProjects[0][1];
27679
27855
  for (const [proj, cost] of topProjects) {
27680
27856
  console.log(
27681
- " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk29.default.yellow(fmtCost3(cost))
27857
+ " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk30.default.yellow(fmtCost3(cost))
27682
27858
  );
27683
27859
  }
27684
27860
  console.log("");
27685
27861
  }
27686
- console.log(import_chalk29.default.dim(" " + "\u2500".repeat(70)));
27862
+ console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
27687
27863
  console.log("");
27688
27864
  }
27689
27865
  function renderList(summaries, totalCost) {
27690
27866
  if (summaries.length === 0) {
27691
- console.log(import_chalk29.default.yellow(" No sessions found in the requested range.\n"));
27867
+ console.log(import_chalk30.default.yellow(" No sessions found in the requested range.\n"));
27692
27868
  return;
27693
27869
  }
27694
- const totalLabel = totalCost > 0 ? import_chalk29.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
27870
+ const totalLabel = totalCost > 0 ? import_chalk30.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
27695
27871
  console.log(
27696
- " " + import_chalk29.default.white(String(summaries.length)) + import_chalk29.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
27872
+ " " + import_chalk30.default.white(String(summaries.length)) + import_chalk30.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
27697
27873
  );
27698
27874
  console.log("");
27699
27875
  let lastGroup = "";
@@ -27701,51 +27877,51 @@ function renderList(summaries, totalCost) {
27701
27877
  const activeDate = fmtDate2(s.lastActiveTime);
27702
27878
  const group = activeDate + " " + s.projectLabel;
27703
27879
  if (group !== lastGroup) {
27704
- console.log(import_chalk29.default.dim(" \u2500\u2500\u2500 ") + import_chalk29.default.bold(activeDate) + import_chalk29.default.dim(" " + s.projectLabel));
27880
+ console.log(import_chalk30.default.dim(" \u2500\u2500\u2500 ") + import_chalk30.default.bold(activeDate) + import_chalk30.default.dim(" " + s.projectLabel));
27705
27881
  lastGroup = group;
27706
27882
  }
27707
27883
  const startDate = fmtDate2(s.startTime);
27708
- const dateRange = startDate !== activeDate ? import_chalk29.default.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
27709
- const timeStr = import_chalk29.default.dim(fmtTime(s.startTime));
27710
- const prompt = import_chalk29.default.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
27711
- const tools = s.toolCalls.length > 0 ? import_chalk29.default.dim(String(s.toolCalls.length).padStart(3) + " tools") : import_chalk29.default.dim(" 0 tools");
27712
- const cost = s.costUSD > 0 ? import_chalk29.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
27713
- const blocked = s.blockedCalls.length > 0 ? import_chalk29.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
27714
- const snap = s.hasSnapshot ? import_chalk29.default.green(" \u{1F4F8}") : "";
27715
- const agentBadge = import_chalk29.default[agentColorName(s.agent ?? "claude")](
27884
+ const dateRange = startDate !== activeDate ? import_chalk30.default.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
27885
+ const timeStr = import_chalk30.default.dim(fmtTime(s.startTime));
27886
+ const prompt = import_chalk30.default.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
27887
+ const tools = s.toolCalls.length > 0 ? import_chalk30.default.dim(String(s.toolCalls.length).padStart(3) + " tools") : import_chalk30.default.dim(" 0 tools");
27888
+ const cost = s.costUSD > 0 ? import_chalk30.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
27889
+ const blocked = s.blockedCalls.length > 0 ? import_chalk30.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
27890
+ const snap = s.hasSnapshot ? import_chalk30.default.green(" \u{1F4F8}") : "";
27891
+ const agentBadge = import_chalk30.default[agentColorName(s.agent ?? "claude")](
27716
27892
  " " + agentBadgeText(s.agent ?? "claude", 0)
27717
27893
  );
27718
- const sid = import_chalk29.default.dim(" " + s.sessionId.slice(0, 8));
27894
+ const sid = import_chalk30.default.dim(" " + s.sessionId.slice(0, 8));
27719
27895
  console.log(
27720
27896
  ` ${timeStr} ${prompt} ${tools}${cost}${blocked}${snap}${agentBadge}${sid}${dateRange}`
27721
27897
  );
27722
27898
  }
27723
27899
  console.log("");
27724
27900
  console.log(
27725
- import_chalk29.default.dim(" Run") + " " + import_chalk29.default.cyan("node9 sessions --detail <session-id>") + import_chalk29.default.dim(" for full tool trace.")
27901
+ import_chalk30.default.dim(" Run") + " " + import_chalk30.default.cyan("node9 sessions --detail <session-id>") + import_chalk30.default.dim(" for full tool trace.")
27726
27902
  );
27727
27903
  console.log("");
27728
27904
  }
27729
27905
  function renderDetail(s) {
27730
27906
  console.log("");
27731
- console.log(import_chalk29.default.bold(" Session ") + import_chalk29.default.dim(s.sessionId));
27907
+ console.log(import_chalk30.default.bold(" Session ") + import_chalk30.default.dim(s.sessionId));
27732
27908
  console.log(
27733
- import_chalk29.default.bold(" Prompt ") + import_chalk29.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
27909
+ import_chalk30.default.bold(" Prompt ") + import_chalk30.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
27734
27910
  );
27735
- console.log(import_chalk29.default.bold(" Project ") + import_chalk29.default.white(s.projectLabel));
27911
+ console.log(import_chalk30.default.bold(" Project ") + import_chalk30.default.white(s.projectLabel));
27736
27912
  if (s.agent) {
27737
- const agentLabel2 = import_chalk29.default[agentColorName(s.agent)](agentDisplayName(s.agent));
27738
- console.log(import_chalk29.default.bold(" Agent ") + agentLabel2);
27913
+ const agentLabel2 = import_chalk30.default[agentColorName(s.agent)](agentDisplayName(s.agent));
27914
+ console.log(import_chalk30.default.bold(" Agent ") + agentLabel2);
27739
27915
  }
27740
- console.log(import_chalk29.default.bold(" When ") + import_chalk29.default.white(fmtDateTime(s.startTime)));
27916
+ console.log(import_chalk30.default.bold(" When ") + import_chalk30.default.white(fmtDateTime(s.startTime)));
27741
27917
  if (s.costUSD > 0)
27742
- console.log(import_chalk29.default.bold(" Cost ") + import_chalk29.default.yellow("~" + fmtCost3(s.costUSD)));
27918
+ console.log(import_chalk30.default.bold(" Cost ") + import_chalk30.default.yellow("~" + fmtCost3(s.costUSD)));
27743
27919
  console.log(
27744
- import_chalk29.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk29.default.green("\u2713 taken") : import_chalk29.default.dim("none"))
27920
+ import_chalk30.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk30.default.green("\u2713 taken") : import_chalk30.default.dim("none"))
27745
27921
  );
27746
27922
  console.log("");
27747
27923
  if (s.toolCalls.length === 0 && s.blockedCalls.length === 0) {
27748
- console.log(import_chalk29.default.dim(" No tool calls recorded.\n"));
27924
+ console.log(import_chalk30.default.dim(" No tool calls recorded.\n"));
27749
27925
  return;
27750
27926
  }
27751
27927
  const timeline = [
@@ -27758,32 +27934,32 @@ function renderDetail(s) {
27758
27934
  });
27759
27935
  const headerParts = [`Tool calls (${s.toolCalls.length})`];
27760
27936
  if (s.blockedCalls.length > 0)
27761
- headerParts.push(import_chalk29.default.red(`${s.blockedCalls.length} blocked by node9`));
27762
- console.log(import_chalk29.default.bold(" " + headerParts.join(" \xB7 ")));
27937
+ headerParts.push(import_chalk30.default.red(`${s.blockedCalls.length} blocked by node9`));
27938
+ console.log(import_chalk30.default.bold(" " + headerParts.join(" \xB7 ")));
27763
27939
  console.log("");
27764
27940
  for (const entry of timeline) {
27765
27941
  if (entry.kind === "tool") {
27766
27942
  const tc = entry.tc;
27767
27943
  const colorFn = toolColor(tc.tool);
27768
27944
  const toolPad = colorFn(tc.tool.padEnd(16));
27769
- const detail = import_chalk29.default.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
27770
- const ts = tc.timestamp ? import_chalk29.default.dim(fmtTime(tc.timestamp) + " ") : " ";
27945
+ const detail = import_chalk30.default.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
27946
+ const ts = tc.timestamp ? import_chalk30.default.dim(fmtTime(tc.timestamp) + " ") : " ";
27771
27947
  console.log(` ${ts}${toolPad} ${detail}`);
27772
27948
  } else {
27773
27949
  const bc = entry.bc;
27774
- const ts = bc.timestamp ? import_chalk29.default.dim(fmtTime(bc.timestamp) + " ") : " ";
27775
- const label2 = import_chalk29.default.red("\u{1F6D1} BLOCKED".padEnd(16));
27776
- const toolName = import_chalk29.default.red(bc.tool.padEnd(10));
27777
- const argsSummary = bc.args ? import_chalk29.default.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : import_chalk29.default.dim("[args not logged]");
27778
- const reason = bc.checkedBy ? import_chalk29.default.dim(" \u2190 " + bc.checkedBy) : "";
27950
+ const ts = bc.timestamp ? import_chalk30.default.dim(fmtTime(bc.timestamp) + " ") : " ";
27951
+ const label2 = import_chalk30.default.red("\u{1F6D1} BLOCKED".padEnd(16));
27952
+ const toolName = import_chalk30.default.red(bc.tool.padEnd(10));
27953
+ const argsSummary = bc.args ? import_chalk30.default.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : import_chalk30.default.dim("[args not logged]");
27954
+ const reason = bc.checkedBy ? import_chalk30.default.dim(" \u2190 " + bc.checkedBy) : "";
27779
27955
  console.log(` ${ts}${label2} ${toolName} ${argsSummary}${reason}`);
27780
27956
  }
27781
27957
  }
27782
27958
  console.log("");
27783
27959
  if (s.modifiedFiles.length > 0) {
27784
- console.log(import_chalk29.default.bold(` Files modified (${s.modifiedFiles.length}):`));
27960
+ console.log(import_chalk30.default.bold(` Files modified (${s.modifiedFiles.length}):`));
27785
27961
  for (const f of s.modifiedFiles) {
27786
- console.log(" " + import_chalk29.default.yellow(f));
27962
+ console.log(" " + import_chalk30.default.yellow(f));
27787
27963
  }
27788
27964
  console.log("");
27789
27965
  }
@@ -27791,13 +27967,13 @@ function renderDetail(s) {
27791
27967
  function registerSessionsCommand(program2) {
27792
27968
  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) => {
27793
27969
  console.log("");
27794
- console.log(import_chalk29.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk29.default.dim(" \u2014 what your AI agent did"));
27970
+ console.log(import_chalk30.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk30.default.dim(" \u2014 what your AI agent did"));
27795
27971
  console.log("");
27796
27972
  const days = options.detail || options.all ? null : Math.max(1, parseInt(options.days, 10) || 7);
27797
27973
  const rangeLabel = options.detail ? "all time" : options.all ? "all time" : `last ${String(days)} days`;
27798
- console.log(import_chalk29.default.dim(" " + rangeLabel));
27974
+ console.log(import_chalk30.default.dim(" " + rangeLabel));
27799
27975
  console.log("");
27800
- process.stdout.write(import_chalk29.default.dim(" Loading\u2026"));
27976
+ process.stdout.write(import_chalk30.default.dim(" Loading\u2026"));
27801
27977
  const summaries = buildSessions(days);
27802
27978
  if (process.stdout.isTTY) {
27803
27979
  process.stdout.clearLine(0);
@@ -27810,8 +27986,8 @@ function registerSessionsCommand(program2) {
27810
27986
  (s) => s.sessionId === options.detail || s.sessionId.startsWith(options.detail)
27811
27987
  );
27812
27988
  if (!target) {
27813
- console.log(import_chalk29.default.red(` Session not found: ${options.detail}`));
27814
- console.log(import_chalk29.default.dim(" Run `node9 sessions` to list recent sessions.\n"));
27989
+ console.log(import_chalk30.default.red(` Session not found: ${options.detail}`));
27990
+ console.log(import_chalk30.default.dim(" Run `node9 sessions` to list recent sessions.\n"));
27815
27991
  return;
27816
27992
  }
27817
27993
  renderDetail(target);
@@ -27824,7 +28000,7 @@ function registerSessionsCommand(program2) {
27824
28000
  }
27825
28001
 
27826
28002
  // src/cli/commands/session-taint.ts
27827
- var import_chalk30 = __toESM(require("chalk"));
28003
+ var import_chalk31 = __toESM(require("chalk"));
27828
28004
  init_daemon();
27829
28005
  function resolveSessionId(records, query) {
27830
28006
  const exact = records.find((r) => r.sessionId === query);
@@ -27851,22 +28027,22 @@ function registerSessionTaintCommand(program2) {
27851
28027
  const records = await listSessionTaints();
27852
28028
  console.log("");
27853
28029
  if (records.length === 0) {
27854
- console.log(import_chalk30.default.dim(" No tainted sessions."));
27855
- console.log(import_chalk30.default.dim(" (Taint lives in the daemon \u2014 a stopped daemon has none.)") + "\n");
28030
+ console.log(import_chalk31.default.dim(" No tainted sessions."));
28031
+ console.log(import_chalk31.default.dim(" (Taint lives in the daemon \u2014 a stopped daemon has none.)") + "\n");
27856
28032
  return;
27857
28033
  }
27858
28034
  console.log(
27859
- " " + import_chalk30.default.bold(String(records.length)) + import_chalk30.default.dim(` tainted session${records.length !== 1 ? "s" : ""}`)
28035
+ " " + import_chalk31.default.bold(String(records.length)) + import_chalk31.default.dim(` tainted session${records.length !== 1 ? "s" : ""}`)
27860
28036
  );
27861
28037
  console.log("");
27862
28038
  for (const r of records) {
27863
28039
  console.log(
27864
- " " + import_chalk30.default.yellow(r.sessionId.slice(0, 8).padEnd(10)) + import_chalk30.default.red(r.source) + sourceGap(r.source) + import_chalk30.default.dim("clears in " + fmtRemaining(r.expiresAt))
28040
+ " " + import_chalk31.default.yellow(r.sessionId.slice(0, 8).padEnd(10)) + import_chalk31.default.red(r.source) + sourceGap(r.source) + import_chalk31.default.dim("clears in " + fmtRemaining(r.expiresAt))
27865
28041
  );
27866
28042
  }
27867
28043
  console.log("");
27868
28044
  console.log(
27869
- import_chalk30.default.dim(" Run ") + import_chalk30.default.cyan("node9 session-taint clear <id>") + import_chalk30.default.dim(" to release one, or ") + import_chalk30.default.cyan("--all") + import_chalk30.default.dim(" for every session.") + "\n"
28045
+ import_chalk31.default.dim(" Run ") + import_chalk31.default.cyan("node9 session-taint clear <id>") + import_chalk31.default.dim(" to release one, or ") + import_chalk31.default.cyan("--all") + import_chalk31.default.dim(" for every session.") + "\n"
27870
28046
  );
27871
28047
  });
27872
28048
  cmd.command("clear").description("Clear a session's taint so its next network/write action isn't held for review").argument("[sessionId]", "Session id to clear (the 8-char prefix from `list` is accepted)").option("--all", "Clear every session taint").action(async (sessionId, opts) => {
@@ -27874,32 +28050,32 @@ function registerSessionTaintCommand(program2) {
27874
28050
  if (opts.all) {
27875
28051
  const res2 = await clearSessionTaint({ all: true });
27876
28052
  if (res2.daemonUnavailable) {
27877
- console.log(import_chalk30.default.dim(" node9 daemon not running \u2014 no active taints to clear.") + "\n");
28053
+ console.log(import_chalk31.default.dim(" node9 daemon not running \u2014 no active taints to clear.") + "\n");
27878
28054
  return;
27879
28055
  }
27880
28056
  console.log(
27881
- import_chalk30.default.green(" \u2713 ") + `Cleared ${import_chalk30.default.bold(String(res2.cleared))} session taint${res2.cleared !== 1 ? "s" : ""}.
28057
+ import_chalk31.default.green(" \u2713 ") + `Cleared ${import_chalk31.default.bold(String(res2.cleared))} session taint${res2.cleared !== 1 ? "s" : ""}.
27882
28058
  `
27883
28059
  );
27884
28060
  return;
27885
28061
  }
27886
28062
  if (!sessionId) {
27887
- console.log(import_chalk30.default.red(" Provide a session id or --all."));
27888
- console.log(import_chalk30.default.dim(" Run `node9 session-taint list` to see tainted sessions.") + "\n");
28063
+ console.log(import_chalk31.default.red(" Provide a session id or --all."));
28064
+ console.log(import_chalk31.default.dim(" Run `node9 session-taint list` to see tainted sessions.") + "\n");
27889
28065
  return;
27890
28066
  }
27891
28067
  const records = await listSessionTaints();
27892
28068
  if (records.length === 0) {
27893
- console.log(import_chalk30.default.dim(" No tainted sessions \u2014 nothing to clear.") + "\n");
28069
+ console.log(import_chalk31.default.dim(" No tainted sessions \u2014 nothing to clear.") + "\n");
27894
28070
  return;
27895
28071
  }
27896
28072
  const resolved = resolveSessionId(records, sessionId);
27897
28073
  if ("error" in resolved) {
27898
28074
  if (resolved.error === "not-found") {
27899
- console.log(import_chalk30.default.red(` No tainted session matches "${sessionId}".`));
28075
+ console.log(import_chalk31.default.red(` No tainted session matches "${sessionId}".`));
27900
28076
  } else {
27901
- console.log(import_chalk30.default.red(` "${sessionId}" is ambiguous \u2014 matches:`));
27902
- for (const m of resolved.matches) console.log(import_chalk30.default.dim(" " + m));
28077
+ console.log(import_chalk31.default.red(` "${sessionId}" is ambiguous \u2014 matches:`));
28078
+ for (const m of resolved.matches) console.log(import_chalk31.default.dim(" " + m));
27903
28079
  }
27904
28080
  console.log("");
27905
28081
  return;
@@ -27907,18 +28083,18 @@ function registerSessionTaintCommand(program2) {
27907
28083
  const res = await clearSessionTaint({ sessionId: resolved.record.sessionId });
27908
28084
  if (res.cleared > 0) {
27909
28085
  console.log(
27910
- import_chalk30.default.green(" \u2713 ") + `Cleared taint for ${import_chalk30.default.yellow(resolved.record.sessionId.slice(0, 8))} ` + import_chalk30.default.dim(`(was flagged by ${resolved.record.source}).`) + "\n"
28086
+ import_chalk31.default.green(" \u2713 ") + `Cleared taint for ${import_chalk31.default.yellow(resolved.record.sessionId.slice(0, 8))} ` + import_chalk31.default.dim(`(was flagged by ${resolved.record.source}).`) + "\n"
27911
28087
  );
27912
28088
  } else {
27913
28089
  console.log(
27914
- import_chalk30.default.dim(` Session ${resolved.record.sessionId.slice(0, 8)} was already clear.`) + "\n"
28090
+ import_chalk31.default.dim(` Session ${resolved.record.sessionId.slice(0, 8)} was already clear.`) + "\n"
27915
28091
  );
27916
28092
  }
27917
28093
  });
27918
28094
  }
27919
28095
 
27920
28096
  // src/cli/commands/skill-pin.ts
27921
- var import_chalk31 = __toESM(require("chalk"));
28097
+ var import_chalk32 = __toESM(require("chalk"));
27922
28098
  var import_fs60 = __toESM(require("fs"));
27923
28099
  var import_os51 = __toESM(require("os"));
27924
28100
  var import_path58 = __toESM(require("path"));
@@ -27938,29 +28114,29 @@ function registerSkillPinCommand(program2) {
27938
28114
  const result = readSkillPinsSafe();
27939
28115
  if (!result.ok) {
27940
28116
  if (result.reason === "missing") {
27941
- console.log(import_chalk31.default.gray("\nNo skill roots are pinned yet."));
28117
+ console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet."));
27942
28118
  console.log(
27943
- import_chalk31.default.gray("Pins are created automatically on the first tool call of each session.\n")
28119
+ import_chalk32.default.gray("Pins are created automatically on the first tool call of each session.\n")
27944
28120
  );
27945
28121
  return;
27946
28122
  }
27947
- console.error(import_chalk31.default.red(`
28123
+ console.error(import_chalk32.default.red(`
27948
28124
  \u274C Pin file is corrupt: ${result.detail}`));
27949
- console.error(import_chalk31.default.yellow(" Run: node9 skill pin reset\n"));
28125
+ console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
27950
28126
  process.exit(1);
27951
28127
  }
27952
28128
  const entries = Object.entries(result.pins.roots);
27953
28129
  if (entries.length === 0) {
27954
- console.log(import_chalk31.default.gray("\nNo skill roots are pinned yet.\n"));
28130
+ console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet.\n"));
27955
28131
  return;
27956
28132
  }
27957
- console.log(import_chalk31.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
28133
+ console.log(import_chalk32.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
27958
28134
  for (const [key, entry] of entries) {
27959
- const missing = entry.exists ? "" : import_chalk31.default.yellow(" (not present at pin time)");
27960
- console.log(` ${import_chalk31.default.cyan(key)} ${import_chalk31.default.gray(entry.rootPath)}${missing}`);
28135
+ const missing = entry.exists ? "" : import_chalk32.default.yellow(" (not present at pin time)");
28136
+ console.log(` ${import_chalk32.default.cyan(key)} ${import_chalk32.default.gray(entry.rootPath)}${missing}`);
27961
28137
  console.log(` Files (${entry.fileCount})`);
27962
- console.log(` Hash: ${import_chalk31.default.gray(entry.contentHash.slice(0, 16))}...`);
27963
- console.log(` Pinned: ${import_chalk31.default.gray(entry.pinnedAt)}
28138
+ console.log(` Hash: ${import_chalk32.default.gray(entry.contentHash.slice(0, 16))}...`);
28139
+ console.log(` Pinned: ${import_chalk32.default.gray(entry.pinnedAt)}
27964
28140
  `);
27965
28141
  }
27966
28142
  });
@@ -27969,39 +28145,39 @@ function registerSkillPinCommand(program2) {
27969
28145
  try {
27970
28146
  pins = readSkillPins();
27971
28147
  } catch {
27972
- console.error(import_chalk31.default.red("\n\u274C Pin file is corrupt."));
27973
- console.error(import_chalk31.default.yellow(" Run: node9 skill pin reset\n"));
28148
+ console.error(import_chalk32.default.red("\n\u274C Pin file is corrupt."));
28149
+ console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
27974
28150
  process.exit(1);
27975
28151
  }
27976
28152
  if (!pins.roots[rootKey]) {
27977
- console.error(import_chalk31.default.red(`
28153
+ console.error(import_chalk32.default.red(`
27978
28154
  \u274C No pin found for root key "${rootKey}"
27979
28155
  `));
27980
- console.error(`Run ${import_chalk31.default.cyan("node9 skill pin list")} to see pinned roots.
28156
+ console.error(`Run ${import_chalk32.default.cyan("node9 skill pin list")} to see pinned roots.
27981
28157
  `);
27982
28158
  process.exit(1);
27983
28159
  }
27984
28160
  const rootPath = pins.roots[rootKey].rootPath;
27985
28161
  removePin2(rootKey);
27986
28162
  wipeSkillSessions();
27987
- console.log(import_chalk31.default.green(`
27988
- \u{1F513} Pin removed for ${import_chalk31.default.cyan(rootKey)}`));
27989
- console.log(import_chalk31.default.gray(` ${rootPath}`));
27990
- console.log(import_chalk31.default.gray(" Next session will re-pin with current state.\n"));
28163
+ console.log(import_chalk32.default.green(`
28164
+ \u{1F513} Pin removed for ${import_chalk32.default.cyan(rootKey)}`));
28165
+ console.log(import_chalk32.default.gray(` ${rootPath}`));
28166
+ console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
27991
28167
  });
27992
28168
  pinSubCmd.command("reset").description("Clear all skill pins and wipe session verification flags").action(() => {
27993
28169
  const result = readSkillPinsSafe();
27994
28170
  if (!result.ok && result.reason === "missing") {
27995
28171
  wipeSkillSessions();
27996
- console.log(import_chalk31.default.gray("\nNo pins to clear.\n"));
28172
+ console.log(import_chalk32.default.gray("\nNo pins to clear.\n"));
27997
28173
  return;
27998
28174
  }
27999
28175
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
28000
28176
  clearAllPins2();
28001
28177
  wipeSkillSessions();
28002
- console.log(import_chalk31.default.green(`
28178
+ console.log(import_chalk32.default.green(`
28003
28179
  \u{1F513} Cleared ${count} skill pin(s).`));
28004
- console.log(import_chalk31.default.gray(" Next session will re-pin with current state.\n"));
28180
+ console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
28005
28181
  });
28006
28182
  }
28007
28183
 
@@ -28009,7 +28185,7 @@ function registerSkillPinCommand(program2) {
28009
28185
  var import_fs61 = __toESM(require("fs"));
28010
28186
  var import_os52 = __toESM(require("os"));
28011
28187
  var import_path59 = __toESM(require("path"));
28012
- var import_chalk32 = __toESM(require("chalk"));
28188
+ var import_chalk33 = __toESM(require("chalk"));
28013
28189
  var DECISIONS_FILE2 = import_path59.default.join(import_os52.default.homedir(), ".node9", "decisions.json");
28014
28190
  function readDecisions() {
28015
28191
  try {
@@ -28038,55 +28214,55 @@ function registerDecisionsCommand(program2) {
28038
28214
  const decisions = readDecisions();
28039
28215
  const entries = Object.entries(decisions);
28040
28216
  if (entries.length === 0) {
28041
- console.log(import_chalk32.default.gray(" No persistent decisions stored."));
28217
+ console.log(import_chalk33.default.gray(" No persistent decisions stored."));
28042
28218
  console.log(
28043
- import_chalk32.default.gray(` File: ${DECISIONS_FILE2}
28044
- `) + import_chalk32.default.gray(' Decisions are written when you click "Always Allow" or')
28219
+ import_chalk33.default.gray(` File: ${DECISIONS_FILE2}
28220
+ `) + import_chalk33.default.gray(' Decisions are written when you click "Always Allow" or')
28045
28221
  );
28046
- console.log(import_chalk32.default.gray(' "Always Deny" in node9 tail or the native popup.'));
28222
+ console.log(import_chalk33.default.gray(' "Always Deny" in node9 tail or the native popup.'));
28047
28223
  return;
28048
28224
  }
28049
- console.log(import_chalk32.default.bold(`
28225
+ console.log(import_chalk33.default.bold(`
28050
28226
  Persistent decisions (${entries.length})
28051
28227
  `));
28052
28228
  const w = Math.max(...entries.map(([k]) => k.length));
28053
28229
  for (const [tool, verdict] of entries.sort()) {
28054
- const colored = verdict === "allow" ? import_chalk32.default.green(verdict) : import_chalk32.default.red(verdict);
28230
+ const colored = verdict === "allow" ? import_chalk33.default.green(verdict) : import_chalk33.default.red(verdict);
28055
28231
  console.log(` ${tool.padEnd(w)} ${colored}`);
28056
28232
  }
28057
28233
  console.log(
28058
- import_chalk32.default.gray(`
28234
+ import_chalk33.default.gray(`
28059
28235
  Stored in ${DECISIONS_FILE2}
28060
- `) + import_chalk32.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
28236
+ `) + import_chalk33.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
28061
28237
  );
28062
28238
  });
28063
28239
  cmd.command("clear <toolName>").description("Remove a persistent decision for one tool").action((toolName) => {
28064
28240
  const decisions = readDecisions();
28065
28241
  if (!(toolName in decisions)) {
28066
- console.log(import_chalk32.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
28242
+ console.log(import_chalk33.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
28067
28243
  process.exitCode = 1;
28068
28244
  return;
28069
28245
  }
28070
28246
  delete decisions[toolName];
28071
28247
  writeDecisions(decisions);
28072
- console.log(import_chalk32.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
28248
+ console.log(import_chalk33.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
28073
28249
  });
28074
28250
  cmd.command("clear-all").description("Remove every persistent decision (irreversible)").action(() => {
28075
28251
  const decisions = readDecisions();
28076
28252
  const count = Object.keys(decisions).length;
28077
28253
  if (count === 0) {
28078
- console.log(import_chalk32.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
28254
+ console.log(import_chalk33.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
28079
28255
  return;
28080
28256
  }
28081
28257
  writeDecisions({});
28082
28258
  console.log(
28083
- import_chalk32.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
28259
+ import_chalk33.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
28084
28260
  );
28085
28261
  });
28086
28262
  }
28087
28263
 
28088
28264
  // src/cli/commands/dlp.ts
28089
- var import_chalk33 = __toESM(require("chalk"));
28265
+ var import_chalk34 = __toESM(require("chalk"));
28090
28266
  var import_fs62 = __toESM(require("fs"));
28091
28267
  var import_path60 = __toESM(require("path"));
28092
28268
  var import_os53 = __toESM(require("os"));
@@ -28141,14 +28317,14 @@ function registerDlpCommand(program2) {
28141
28317
  cmd.command("resolve").description("Mark all current DLP findings as resolved").action(() => {
28142
28318
  const findings = loadDlpFindings();
28143
28319
  if (findings.length === 0) {
28144
- console.log(import_chalk33.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
28320
+ console.log(import_chalk34.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
28145
28321
  return;
28146
28322
  }
28147
28323
  const resolved = loadResolved();
28148
28324
  for (const e of findings) resolved.add(entryKey2(e));
28149
28325
  saveResolved(resolved);
28150
28326
  console.log(
28151
- import_chalk33.default.green(
28327
+ import_chalk34.default.green(
28152
28328
  `
28153
28329
  \u2705 ${findings.length} finding${findings.length !== 1 ? "s" : ""} marked as resolved.
28154
28330
  `
@@ -28162,54 +28338,54 @@ function registerDlpCommand(program2) {
28162
28338
  const resolvedCount = findings.length - open.length;
28163
28339
  console.log("");
28164
28340
  console.log(
28165
- import_chalk33.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk33.default.dim(" \u2014 secrets found in Claude response text")
28341
+ import_chalk34.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk34.default.dim(" \u2014 secrets found in Claude response text")
28166
28342
  );
28167
28343
  console.log("");
28168
28344
  if (open.length === 0) {
28169
28345
  if (resolvedCount > 0) {
28170
- console.log(import_chalk33.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
28346
+ console.log(import_chalk34.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
28171
28347
  } else {
28172
28348
  console.log(
28173
- import_chalk33.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
28349
+ import_chalk34.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
28174
28350
  );
28175
28351
  }
28176
28352
  console.log("");
28177
28353
  return;
28178
28354
  }
28179
28355
  console.log(
28180
- import_chalk33.default.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + import_chalk33.default.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
28356
+ import_chalk34.default.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + import_chalk34.default.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
28181
28357
  );
28182
28358
  console.log("");
28183
28359
  console.log(
28184
- import_chalk33.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
28360
+ import_chalk34.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
28185
28361
  );
28186
- console.log(import_chalk33.default.dim(" Rotate each affected key immediately.\n"));
28362
+ console.log(import_chalk34.default.dim(" Rotate each affected key immediately.\n"));
28187
28363
  for (const e of open) {
28188
28364
  console.log(
28189
- " " + import_chalk33.default.red("\u25CF") + " " + import_chalk33.default.white(e.dlpPattern ?? "Secret") + import_chalk33.default.dim(" " + fmtDate3(e.ts))
28365
+ " " + import_chalk34.default.red("\u25CF") + " " + import_chalk34.default.white(e.dlpPattern ?? "Secret") + import_chalk34.default.dim(" " + fmtDate3(e.ts))
28190
28366
  );
28191
28367
  if (e.dlpSample) {
28192
- console.log(" " + import_chalk33.default.dim("Sample: ") + import_chalk33.default.yellow(stripAnsi(e.dlpSample)));
28368
+ console.log(" " + import_chalk34.default.dim("Sample: ") + import_chalk34.default.yellow(stripAnsi(e.dlpSample)));
28193
28369
  }
28194
28370
  if (e.project) {
28195
- console.log(" " + import_chalk33.default.dim("Project: ") + import_chalk33.default.dim(stripAnsi(e.project)));
28371
+ console.log(" " + import_chalk34.default.dim("Project: ") + import_chalk34.default.dim(stripAnsi(e.project)));
28196
28372
  }
28197
28373
  console.log("");
28198
28374
  }
28199
- console.log(" " + import_chalk33.default.bold("Next steps:"));
28200
- console.log(" " + import_chalk33.default.cyan("1.") + " Rotate any exposed keys shown above");
28375
+ console.log(" " + import_chalk34.default.bold("Next steps:"));
28376
+ console.log(" " + import_chalk34.default.cyan("1.") + " Rotate any exposed keys shown above");
28201
28377
  console.log(
28202
- " " + import_chalk33.default.cyan("2.") + " Run " + import_chalk33.default.white("node9 dlp resolve") + " to acknowledge"
28378
+ " " + import_chalk34.default.cyan("2.") + " Run " + import_chalk34.default.white("node9 dlp resolve") + " to acknowledge"
28203
28379
  );
28204
28380
  console.log(
28205
- " " + import_chalk33.default.cyan("3.") + " Run " + import_chalk33.default.white("node9 report") + " for full audit history"
28381
+ " " + import_chalk34.default.cyan("3.") + " Run " + import_chalk34.default.white("node9 report") + " for full audit history"
28206
28382
  );
28207
28383
  console.log("");
28208
28384
  });
28209
28385
  }
28210
28386
 
28211
28387
  // src/cli/commands/mask.ts
28212
- var import_chalk34 = __toESM(require("chalk"));
28388
+ var import_chalk35 = __toESM(require("chalk"));
28213
28389
  var import_fs63 = __toESM(require("fs"));
28214
28390
  var import_path61 = __toESM(require("path"));
28215
28391
  var import_os54 = __toESM(require("os"));
@@ -28346,12 +28522,12 @@ function registerMaskCommand(program2) {
28346
28522
  }
28347
28523
  }) : allFiles;
28348
28524
  if (filtered.length === 0) {
28349
- console.log(import_chalk34.default.yellow(" No session files found."));
28525
+ console.log(import_chalk35.default.yellow(" No session files found."));
28350
28526
  return;
28351
28527
  }
28352
28528
  console.log("");
28353
28529
  if (dryRun) {
28354
- console.log(import_chalk34.default.dim(" Dry run \u2014 no files will be modified.\n"));
28530
+ console.log(import_chalk35.default.dim(" Dry run \u2014 no files will be modified.\n"));
28355
28531
  }
28356
28532
  let totalFiles = 0;
28357
28533
  let totalLines = 0;
@@ -28367,23 +28543,23 @@ function registerMaskCommand(program2) {
28367
28543
  });
28368
28544
  const verb = dryRun ? "Would redact" : "Redacted";
28369
28545
  console.log(
28370
- " " + import_chalk34.default.dim(shortPath.slice(0, 60).padEnd(62)) + import_chalk34.default.red(`${verb}: `) + import_chalk34.default.yellow(patterns.join(", ")) + import_chalk34.default.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
28546
+ " " + import_chalk35.default.dim(shortPath.slice(0, 60).padEnd(62)) + import_chalk35.default.red(`${verb}: `) + import_chalk35.default.yellow(patterns.join(", ")) + import_chalk35.default.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
28371
28547
  );
28372
28548
  }
28373
28549
  }
28374
28550
  console.log("");
28375
28551
  if (totalFiles === 0) {
28376
- console.log(import_chalk34.default.green(" No secrets found in session history."));
28552
+ console.log(import_chalk35.default.green(" No secrets found in session history."));
28377
28553
  } else {
28378
28554
  const verb = dryRun ? "would be modified" : "modified";
28379
28555
  console.log(
28380
- import_chalk34.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk34.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
28556
+ import_chalk35.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk35.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
28381
28557
  );
28382
- console.log(" Patterns: " + import_chalk34.default.yellow(totalPatterns.join(", ")));
28558
+ console.log(" Patterns: " + import_chalk35.default.yellow(totalPatterns.join(", ")));
28383
28559
  if (!dryRun) {
28384
28560
  console.log("");
28385
28561
  console.log(
28386
- import_chalk34.default.dim(
28562
+ import_chalk35.default.dim(
28387
28563
  " Note: secrets were already sent to the AI provider during the active session.\n This cleans your local disk only. Rotate any exposed keys."
28388
28564
  )
28389
28565
  );
@@ -28401,77 +28577,34 @@ var { version } = JSON.parse(
28401
28577
  var program = new import_commander.Command();
28402
28578
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
28403
28579
  program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
28404
- const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
28405
- const credPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "credentials.json");
28406
- if (!import_fs66.default.existsSync(import_path64.default.dirname(credPath)))
28407
- import_fs66.default.mkdirSync(import_path64.default.dirname(credPath), { recursive: true });
28408
- const profileName = options.profile || "default";
28409
- let existingCreds = {};
28410
- try {
28411
- if (import_fs66.default.existsSync(credPath)) {
28412
- const raw = JSON.parse(import_fs66.default.readFileSync(credPath, "utf-8"));
28413
- if (raw.apiKey) {
28414
- existingCreds = {
28415
- default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
28416
- };
28417
- } else {
28418
- existingCreds = raw;
28419
- }
28420
- }
28421
- } catch {
28422
- }
28423
- existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
28424
- import_fs66.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
28425
- let effectiveCloud = null;
28426
- if (profileName === "default") {
28427
- const configPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "config.json");
28428
- let config = {};
28429
- try {
28430
- if (import_fs66.default.existsSync(configPath))
28431
- config = JSON.parse(import_fs66.default.readFileSync(configPath, "utf-8"));
28432
- } catch {
28433
- }
28434
- if (!config.settings || typeof config.settings !== "object") config.settings = {};
28435
- const s = config.settings;
28436
- const approvers = s.approvers || {
28437
- native: true,
28438
- browser: true,
28439
- cloud: true,
28440
- terminal: true
28441
- };
28442
- if (options.local) {
28443
- approvers.cloud = false;
28444
- }
28445
- s.approvers = approvers;
28446
- if (!import_fs66.default.existsSync(import_path64.default.dirname(configPath)))
28447
- import_fs66.default.mkdirSync(import_path64.default.dirname(configPath), { recursive: true });
28448
- import_fs66.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
28449
- effectiveCloud = approvers.cloud === true;
28450
- }
28580
+ const { profileName, effectiveCloud } = writeCredentialsAndConfig(apiKey, {
28581
+ profileName: options.profile,
28582
+ isLocal: options.local
28583
+ });
28451
28584
  if (options.profile && profileName !== "default") {
28452
- console.log(import_chalk36.default.green(`\u2705 Profile "${profileName}" saved`));
28453
- console.log(import_chalk36.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
28585
+ console.log(import_chalk37.default.green(`\u2705 Profile "${profileName}" saved`));
28586
+ console.log(import_chalk37.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
28454
28587
  } else if (options.local || effectiveCloud === false) {
28455
- console.log(import_chalk36.default.green(`\u2705 Key saved \u2014 Privacy mode \u{1F6E1}\uFE0F`));
28456
- console.log(import_chalk36.default.gray(` All decisions stay on this machine. Nothing syncs to the cloud.`));
28588
+ console.log(import_chalk37.default.green(`\u2705 Key saved \u2014 Privacy mode \u{1F6E1}\uFE0F`));
28589
+ console.log(import_chalk37.default.gray(` All decisions stay on this machine. Nothing syncs to the cloud.`));
28457
28590
  if (!options.local) {
28458
28591
  console.log(
28459
- import_chalk36.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
28592
+ import_chalk37.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
28460
28593
  );
28461
28594
  console.log(
28462
- import_chalk36.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
28595
+ import_chalk37.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
28463
28596
  );
28464
28597
  }
28465
28598
  } else {
28466
- console.log(import_chalk36.default.green(`\u2705 Logged in \u2014 agent mode`));
28467
- console.log(import_chalk36.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
28599
+ console.log(import_chalk37.default.green(`\u2705 Logged in \u2014 agent mode`));
28600
+ console.log(import_chalk37.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
28468
28601
  }
28469
28602
  });
28470
28603
  program.command("signup").description("Create your node9 account / open the dashboard in your browser").option("--login", "Open the login page instead of signup").action((options) => {
28471
28604
  const route = options.login ? "auth/login" : "auth/signup";
28472
28605
  const url = `https://node9.ai/${route}?ref=cli_cmd`;
28473
28606
  console.log("");
28474
- console.log(" " + import_chalk36.default.dim("Opening ") + import_chalk36.default.cyan.underline(url));
28607
+ console.log(" " + import_chalk37.default.dim("Opening ") + import_chalk37.default.cyan.underline(url));
28475
28608
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
28476
28609
  try {
28477
28610
  const child = (0, import_child_process15.spawn)(opener, [url], {
@@ -28504,7 +28637,7 @@ program.command("addto", { hidden: true }).description("Integrate Node9 with an
28504
28637
  if (target === "hermes") return setupHermes();
28505
28638
  if (target === "hud") return setupHud();
28506
28639
  console.error(
28507
- import_chalk36.default.red(
28640
+ import_chalk37.default.red(
28508
28641
  `Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
28509
28642
  )
28510
28643
  );
@@ -28518,20 +28651,20 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
28518
28651
  "The agent to protect: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
28519
28652
  ).action(async (target) => {
28520
28653
  if (!target) {
28521
- console.log(import_chalk36.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
28522
- console.log(" Usage: " + import_chalk36.default.white("node9 setup <target>") + "\n");
28654
+ console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
28655
+ console.log(" Usage: " + import_chalk37.default.white("node9 setup <target>") + "\n");
28523
28656
  console.log(" Targets:");
28524
- console.log(" " + import_chalk36.default.green("claude") + " \u2014 Claude Code (hook mode)");
28525
- console.log(" " + import_chalk36.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
28526
- console.log(" " + import_chalk36.default.green("antigravity") + " \u2014 Antigravity / agy (hook mode)");
28527
- console.log(" " + import_chalk36.default.green("copilot") + " \u2014 GitHub Copilot CLI (hook mode)");
28528
- console.log(" " + import_chalk36.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
28529
- console.log(" " + import_chalk36.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
28530
- console.log(" " + import_chalk36.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
28531
- console.log(" " + import_chalk36.default.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
28532
- console.log(" " + import_chalk36.default.green("hermes") + " \u2014 Hermes Agent (hook mode)");
28657
+ console.log(" " + import_chalk37.default.green("claude") + " \u2014 Claude Code (hook mode)");
28658
+ console.log(" " + import_chalk37.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
28659
+ console.log(" " + import_chalk37.default.green("antigravity") + " \u2014 Antigravity / agy (hook mode)");
28660
+ console.log(" " + import_chalk37.default.green("copilot") + " \u2014 GitHub Copilot CLI (hook mode)");
28661
+ console.log(" " + import_chalk37.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
28662
+ console.log(" " + import_chalk37.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
28663
+ console.log(" " + import_chalk37.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
28664
+ console.log(" " + import_chalk37.default.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
28665
+ console.log(" " + import_chalk37.default.green("hermes") + " \u2014 Hermes Agent (hook mode)");
28533
28666
  process.stdout.write(
28534
- " " + import_chalk36.default.green("hud") + " \u2014 Claude Code security statusline\n"
28667
+ " " + import_chalk37.default.green("hud") + " \u2014 Claude Code security statusline\n"
28535
28668
  );
28536
28669
  console.log("");
28537
28670
  return;
@@ -28548,7 +28681,7 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
28548
28681
  if (t === "hermes") return setupHermes();
28549
28682
  if (t === "hud") return setupHud();
28550
28683
  console.error(
28551
- import_chalk36.default.red(
28684
+ import_chalk37.default.red(
28552
28685
  `Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
28553
28686
  )
28554
28687
  );
@@ -28559,32 +28692,32 @@ program.command("removefrom", { hidden: true }).description("Remove Node9 hooks
28559
28692
  const agent = resolveAgentTeardown(target);
28560
28693
  if (!agent) {
28561
28694
  console.error(
28562
- import_chalk36.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
28695
+ import_chalk37.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
28563
28696
  );
28564
28697
  process.exit(1);
28565
28698
  return;
28566
28699
  }
28567
- console.log(import_chalk36.default.cyan(`
28700
+ console.log(import_chalk37.default.cyan(`
28568
28701
  \u{1F6E1}\uFE0F Node9: removing hooks from ${agent.label}...
28569
28702
  `));
28570
28703
  try {
28571
28704
  agent.fn();
28572
28705
  } catch (err2) {
28573
- console.error(import_chalk36.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
28706
+ console.error(import_chalk37.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
28574
28707
  process.exit(1);
28575
28708
  }
28576
- console.log(import_chalk36.default.gray("\n Restart the agent for changes to take effect."));
28709
+ console.log(import_chalk37.default.gray("\n Restart the agent for changes to take effect."));
28577
28710
  });
28578
28711
  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) => {
28579
- console.log(import_chalk36.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
28580
- console.log(import_chalk36.default.bold("Stopping daemon..."));
28712
+ console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
28713
+ console.log(import_chalk37.default.bold("Stopping daemon..."));
28581
28714
  try {
28582
28715
  stopDaemon();
28583
- console.log(import_chalk36.default.green(" \u2705 Daemon stopped"));
28716
+ console.log(import_chalk37.default.green(" \u2705 Daemon stopped"));
28584
28717
  } catch {
28585
- console.log(import_chalk36.default.blue(" \u2139\uFE0F Daemon was not running"));
28718
+ console.log(import_chalk37.default.blue(" \u2139\uFE0F Daemon was not running"));
28586
28719
  }
28587
- console.log(import_chalk36.default.bold("\nRemoving hooks..."));
28720
+ console.log(import_chalk37.default.bold("\nRemoving hooks..."));
28588
28721
  let teardownFailed = false;
28589
28722
  for (const { label: label2, fn } of AGENT_TEARDOWNS) {
28590
28723
  try {
@@ -28592,7 +28725,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28592
28725
  } catch (err2) {
28593
28726
  teardownFailed = true;
28594
28727
  console.error(
28595
- import_chalk36.default.red(
28728
+ import_chalk37.default.red(
28596
28729
  ` \u26A0\uFE0F Failed to remove ${label2} hooks: ${err2 instanceof Error ? err2.message : String(err2)}`
28597
28730
  )
28598
28731
  );
@@ -28601,12 +28734,12 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28601
28734
  try {
28602
28735
  const residual = getAgentWiring().filter((a) => a.wireState === "wired");
28603
28736
  if (residual.length === 0) {
28604
- console.log(import_chalk36.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
28737
+ console.log(import_chalk37.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
28605
28738
  } else {
28606
28739
  teardownFailed = true;
28607
- console.error(import_chalk36.default.red(" \u26A0\uFE0F Still wired after teardown:"));
28740
+ console.error(import_chalk37.default.red(" \u26A0\uFE0F Still wired after teardown:"));
28608
28741
  for (const a of residual) {
28609
- console.error(import_chalk36.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
28742
+ console.error(import_chalk37.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
28610
28743
  }
28611
28744
  }
28612
28745
  } catch {
@@ -28622,28 +28755,28 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28622
28755
  import_fs66.default.rmSync(node9Dir, { recursive: true });
28623
28756
  if (import_fs66.default.existsSync(node9Dir)) {
28624
28757
  console.error(
28625
- import_chalk36.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
28758
+ import_chalk37.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
28626
28759
  );
28627
28760
  } else {
28628
- console.log(import_chalk36.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
28761
+ console.log(import_chalk37.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
28629
28762
  }
28630
28763
  } else {
28631
- console.log(import_chalk36.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
28764
+ console.log(import_chalk37.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
28632
28765
  }
28633
28766
  } else {
28634
- console.log(import_chalk36.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
28767
+ console.log(import_chalk37.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
28635
28768
  }
28636
28769
  } else {
28637
28770
  console.log(
28638
- import_chalk36.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
28771
+ import_chalk37.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
28639
28772
  );
28640
28773
  }
28641
28774
  if (teardownFailed) {
28642
- console.error(import_chalk36.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
28775
+ console.error(import_chalk37.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
28643
28776
  process.exit(1);
28644
28777
  }
28645
- console.log(import_chalk36.default.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g node9-ai"));
28646
- console.log(import_chalk36.default.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
28778
+ console.log(import_chalk37.default.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g node9-ai"));
28779
+ console.log(import_chalk37.default.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
28647
28780
  });
28648
28781
  registerDoctorCommand(program, version);
28649
28782
  program.command("explain").description(
@@ -28656,7 +28789,7 @@ program.command("explain").description(
28656
28789
  try {
28657
28790
  args = JSON.parse(trimmed);
28658
28791
  } catch {
28659
- console.error(import_chalk36.default.red(`
28792
+ console.error(import_chalk37.default.red(`
28660
28793
  \u274C Invalid JSON: ${trimmed}
28661
28794
  `));
28662
28795
  process.exit(1);
@@ -28667,67 +28800,68 @@ program.command("explain").description(
28667
28800
  }
28668
28801
  const result = await explainPolicy(tool, args);
28669
28802
  console.log("");
28670
- console.log(import_chalk36.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
28803
+ console.log(import_chalk37.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
28671
28804
  console.log("");
28672
- console.log(` ${import_chalk36.default.bold("Tool:")} ${import_chalk36.default.white(result.tool)}`);
28805
+ console.log(` ${import_chalk37.default.bold("Tool:")} ${import_chalk37.default.white(result.tool)}`);
28673
28806
  if (argsRaw) {
28674
28807
  const preview2 = argsRaw.length > 80 ? argsRaw.slice(0, 77) + "\u2026" : argsRaw;
28675
- console.log(` ${import_chalk36.default.bold("Input:")} ${import_chalk36.default.gray(preview2)}`);
28808
+ console.log(` ${import_chalk37.default.bold("Input:")} ${import_chalk37.default.gray(preview2)}`);
28676
28809
  }
28677
28810
  console.log("");
28678
- console.log(import_chalk36.default.bold("Config Sources (Waterfall):"));
28811
+ console.log(import_chalk37.default.bold("Config Sources (Waterfall):"));
28679
28812
  for (const tier of result.waterfall) {
28680
- const num3 = import_chalk36.default.gray(` ${tier.tier}.`);
28813
+ const num3 = import_chalk37.default.gray(` ${tier.tier}.`);
28681
28814
  const label2 = tier.label.padEnd(16);
28682
28815
  let statusStr;
28683
28816
  if (tier.tier === 1) {
28684
- statusStr = import_chalk36.default.gray(tier.note ?? "");
28817
+ statusStr = import_chalk37.default.gray(tier.note ?? "");
28685
28818
  } else if (tier.status === "active") {
28686
- const loc = tier.path ? import_chalk36.default.gray(tier.path) : "";
28687
- const note = tier.note ? import_chalk36.default.gray(`(${tier.note})`) : "";
28688
- statusStr = import_chalk36.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
28819
+ const loc = tier.path ? import_chalk37.default.gray(tier.path) : "";
28820
+ const note = tier.note ? import_chalk37.default.gray(`(${tier.note})`) : "";
28821
+ statusStr = import_chalk37.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
28689
28822
  } else {
28690
- statusStr = import_chalk36.default.gray("\u25CB " + (tier.note ?? "not found"));
28823
+ statusStr = import_chalk37.default.gray("\u25CB " + (tier.note ?? "not found"));
28691
28824
  }
28692
- console.log(`${num3} ${import_chalk36.default.white(label2)} ${statusStr}`);
28825
+ console.log(`${num3} ${import_chalk37.default.white(label2)} ${statusStr}`);
28693
28826
  }
28694
28827
  console.log("");
28695
- console.log(import_chalk36.default.bold("Policy Evaluation:"));
28828
+ console.log(import_chalk37.default.bold("Policy Evaluation:"));
28696
28829
  for (const step of result.steps) {
28697
28830
  const isFinal = step.isFinal;
28698
28831
  let icon;
28699
- if (step.outcome === "allow") icon = import_chalk36.default.green(" \u2705");
28700
- else if (step.outcome === "block") icon = import_chalk36.default.red(" \u{1F6D1}");
28701
- else if (step.outcome === "review") icon = import_chalk36.default.red(" \u{1F534}");
28702
- else if (step.outcome === "skip") icon = import_chalk36.default.gray(" \u2500 ");
28703
- else icon = import_chalk36.default.gray(" \u25CB ");
28832
+ if (step.outcome === "allow") icon = import_chalk37.default.green(" \u2705");
28833
+ else if (step.outcome === "block") icon = import_chalk37.default.red(" \u{1F6D1}");
28834
+ else if (step.outcome === "review") icon = import_chalk37.default.red(" \u{1F534}");
28835
+ else if (step.outcome === "skip") icon = import_chalk37.default.gray(" \u2500 ");
28836
+ else icon = import_chalk37.default.gray(" \u25CB ");
28704
28837
  const name = step.name.padEnd(18);
28705
- const nameStr = isFinal ? import_chalk36.default.white.bold(name) : import_chalk36.default.white(name);
28706
- const detail = isFinal ? import_chalk36.default.white(step.detail) : import_chalk36.default.gray(step.detail);
28707
- const arrow = isFinal ? import_chalk36.default.yellow(" \u2190 STOP") : "";
28838
+ const nameStr = isFinal ? import_chalk37.default.white.bold(name) : import_chalk37.default.white(name);
28839
+ const detail = isFinal ? import_chalk37.default.white(step.detail) : import_chalk37.default.gray(step.detail);
28840
+ const arrow = isFinal ? import_chalk37.default.yellow(" \u2190 STOP") : "";
28708
28841
  console.log(`${icon} ${nameStr} ${detail}${arrow}`);
28709
28842
  }
28710
28843
  console.log("");
28711
28844
  if (result.decision === "allow") {
28712
- console.log(import_chalk36.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk36.default.gray(" \u2014 no approval needed"));
28845
+ console.log(import_chalk37.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk37.default.gray(" \u2014 no approval needed"));
28713
28846
  } else if (result.decision === "block") {
28714
28847
  console.log(
28715
- import_chalk36.default.red.bold(" Decision: \u{1F6D1} BLOCK") + import_chalk36.default.gray(" \u2014 this action is blocked")
28848
+ import_chalk37.default.red.bold(" Decision: \u{1F6D1} BLOCK") + import_chalk37.default.gray(" \u2014 this action is blocked")
28716
28849
  );
28717
28850
  if (result.blockedByLabel) {
28718
- console.log(import_chalk36.default.gray(` Reason: ${result.blockedByLabel}`));
28851
+ console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
28719
28852
  }
28720
28853
  } else {
28721
28854
  console.log(
28722
- import_chalk36.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk36.default.gray(" \u2014 human approval required")
28855
+ import_chalk37.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk37.default.gray(" \u2014 human approval required")
28723
28856
  );
28724
28857
  if (result.blockedByLabel) {
28725
- console.log(import_chalk36.default.gray(` Reason: ${result.blockedByLabel}`));
28858
+ console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
28726
28859
  }
28727
28860
  }
28728
28861
  console.log("");
28729
28862
  });
28730
28863
  registerInitCommand(program);
28864
+ registerConnectCommand(program);
28731
28865
  registerAuditCommand(program);
28732
28866
  registerReportCommand(program);
28733
28867
  registerStatusCommand(program);
@@ -28737,7 +28871,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
28737
28871
  try {
28738
28872
  await startTail2(options);
28739
28873
  } catch (err2) {
28740
- console.error(import_chalk36.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28874
+ console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28741
28875
  process.exit(1);
28742
28876
  }
28743
28877
  });
@@ -28748,7 +28882,7 @@ program.command("monitor").description("Live interactive dashboard \u2014 activi
28748
28882
  const mod = await dynamicImport(`file://${dashboardPath}`);
28749
28883
  await mod.startMonitor();
28750
28884
  } catch (err2) {
28751
- console.error(import_chalk36.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28885
+ console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28752
28886
  process.exit(1);
28753
28887
  }
28754
28888
  });
@@ -28803,7 +28937,7 @@ program.command("pause").description("Temporarily disable Node9 protection for a
28803
28937
  const ms = parseDuration(options.duration);
28804
28938
  if (ms === null) {
28805
28939
  console.error(
28806
- import_chalk36.default.red(`
28940
+ import_chalk37.default.red(`
28807
28941
  \u274C Invalid duration: "${options.duration}". Use format like 15m, 1h, 30s.
28808
28942
  `)
28809
28943
  );
@@ -28811,20 +28945,20 @@ program.command("pause").description("Temporarily disable Node9 protection for a
28811
28945
  }
28812
28946
  pauseNode9(ms, options.duration);
28813
28947
  const expiresAt = new Date(Date.now() + ms).toLocaleTimeString();
28814
- console.log(import_chalk36.default.yellow(`
28948
+ console.log(import_chalk37.default.yellow(`
28815
28949
  \u23F8 Node9 paused until ${expiresAt}`));
28816
- console.log(import_chalk36.default.gray(` All tool calls will be allowed without review.`));
28817
- console.log(import_chalk36.default.gray(` Run "node9 resume" to re-enable early.
28950
+ console.log(import_chalk37.default.gray(` All tool calls will be allowed without review.`));
28951
+ console.log(import_chalk37.default.gray(` Run "node9 resume" to re-enable early.
28818
28952
  `));
28819
28953
  });
28820
28954
  program.command("resume").description("Re-enable Node9 protection immediately").action(() => {
28821
28955
  const { paused } = checkPause();
28822
28956
  if (!paused) {
28823
- console.log(import_chalk36.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
28957
+ console.log(import_chalk37.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
28824
28958
  return;
28825
28959
  }
28826
28960
  resumeNode9();
28827
- console.log(import_chalk36.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
28961
+ console.log(import_chalk37.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
28828
28962
  });
28829
28963
  var HOOK_BASED_AGENTS = {
28830
28964
  claude: "claude",
@@ -28840,15 +28974,15 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28840
28974
  if (HOOK_BASED_AGENTS[firstArg2] !== void 0) {
28841
28975
  const target = HOOK_BASED_AGENTS[firstArg2];
28842
28976
  console.error(
28843
- import_chalk36.default.yellow(`
28977
+ import_chalk37.default.yellow(`
28844
28978
  \u26A0\uFE0F Node9 proxy mode does not support "${target}" directly.`)
28845
28979
  );
28846
- console.error(import_chalk36.default.white(`
28980
+ console.error(import_chalk37.default.white(`
28847
28981
  "${target}" uses its own hook system. Use:`));
28848
28982
  console.error(
28849
- import_chalk36.default.green(` node9 addto ${target} `) + import_chalk36.default.gray("# one-time setup")
28983
+ import_chalk37.default.green(` node9 addto ${target} `) + import_chalk37.default.gray("# one-time setup")
28850
28984
  );
28851
- console.error(import_chalk36.default.green(` ${target} `) + import_chalk36.default.gray("# run normally"));
28985
+ console.error(import_chalk37.default.green(` ${target} `) + import_chalk37.default.gray("# run normally"));
28852
28986
  process.exit(1);
28853
28987
  }
28854
28988
  const runArgs = firstArg2 === "shell" ? commandArgs.slice(1) : commandArgs;
@@ -28865,7 +28999,7 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28865
28999
  }
28866
29000
  );
28867
29001
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && getConfig().settings.autoStartDaemon) {
28868
- console.error(import_chalk36.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
29002
+ console.error(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
28869
29003
  const daemonReady = await autoStartDaemonAndWait();
28870
29004
  if (daemonReady) result = await authorizeHeadless("shell", { command: fullCommand });
28871
29005
  }
@@ -28878,12 +29012,12 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28878
29012
  }
28879
29013
  if (!result.approved) {
28880
29014
  console.error(
28881
- import_chalk36.default.red(`
29015
+ import_chalk37.default.red(`
28882
29016
  \u274C Node9 Blocked: ${result.reason || "Dangerous command detected."}`)
28883
29017
  );
28884
29018
  process.exit(1);
28885
29019
  }
28886
- console.error(import_chalk36.default.green("\n\u2705 Approved \u2014 running command...\n"));
29020
+ console.error(import_chalk37.default.green("\n\u2705 Approved \u2014 running command...\n"));
28887
29021
  await runProxy(fullCommand);
28888
29022
  } else {
28889
29023
  program.help();