@node9/proxy 1.51.0 → 1.53.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
  }
@@ -16917,6 +16946,23 @@ function readCachedEtag() {
16917
16946
  return void 0;
16918
16947
  }
16919
16948
  }
16949
+ function readCachedSyncIntervalHours() {
16950
+ try {
16951
+ const raw = JSON.parse(import_fs32.default.readFileSync(rulesCacheFile(), "utf-8"));
16952
+ return typeof raw.syncIntervalHours === "number" ? raw.syncIntervalHours : void 0;
16953
+ } catch {
16954
+ return void 0;
16955
+ }
16956
+ }
16957
+ function pickSyncIntervalMs(cloudHours, localSettings) {
16958
+ if (typeof cloudHours === "number" && Number.isFinite(cloudHours)) {
16959
+ return resolveSyncIntervalMs({ cloudSyncIntervalHours: cloudHours });
16960
+ }
16961
+ return resolveSyncIntervalMs(localSettings);
16962
+ }
16963
+ function effectiveSyncIntervalMs() {
16964
+ return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
16965
+ }
16920
16966
  function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
16921
16967
  const parsed = new URL(apiUrl);
16922
16968
  const headers = {
@@ -17226,11 +17272,14 @@ function getCloudRules() {
17226
17272
  }
17227
17273
  }
17228
17274
  function startCloudSync() {
17229
- const intervalMs = resolveSyncIntervalMs(getConfig().settings);
17230
- const initial = setTimeout(() => void syncOnce(), 3e4);
17231
- initial.unref();
17232
- const recurring = setInterval(() => void syncOnce(), intervalMs);
17233
- recurring.unref();
17275
+ const scheduleNext = (ms) => {
17276
+ const t = setTimeout(() => {
17277
+ void syncOnce().catch(() => {
17278
+ }).finally(() => scheduleNext(effectiveSyncIntervalMs()));
17279
+ }, ms);
17280
+ t.unref();
17281
+ };
17282
+ scheduleNext(3e4);
17234
17283
  }
17235
17284
  function startForensicBroadcast() {
17236
17285
  const tick = async () => {
@@ -17251,7 +17300,7 @@ function startForensicBroadcast() {
17251
17300
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
17252
17301
  recurring.unref();
17253
17302
  }
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;
17303
+ 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
17304
  var init_sync = __esm({
17256
17305
  "src/daemon/sync.ts"() {
17257
17306
  "use strict";
@@ -17283,7 +17332,7 @@ var init_sync = __esm({
17283
17332
  "long-output-redacted": "longOutputRedactions"
17284
17333
  };
17285
17334
  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";
17335
+ DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept/policies/sync";
17287
17336
  DEFAULT_INTERVAL_HOURS = 5;
17288
17337
  MIN_INTERVAL_SECONDS = 15;
17289
17338
  MAX_INTERVAL_SECONDS = 24 * 60 * 60;
@@ -19085,10 +19134,10 @@ function readSessionUsage() {
19085
19134
  }
19086
19135
  }
19087
19136
  function formatContextStat(stat) {
19088
- const pctColor = stat.fillPct >= 80 ? import_chalk35.default.red : stat.fillPct >= 50 ? import_chalk35.default.yellow : import_chalk35.default.cyan;
19137
+ const pctColor = stat.fillPct >= 80 ? import_chalk36.default.red : stat.fillPct >= 50 ? import_chalk36.default.yellow : import_chalk36.default.cyan;
19089
19138
  const k = (n) => `${Math.round(n / 1e3)}k`;
19090
19139
  const modelShort = stat.model.replace(/@.*$/, "").replace(/-\d{8}$/, "").replace(/^claude-/, "");
19091
- return import_chalk35.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk35.default.dim(
19140
+ return import_chalk36.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk36.default.dim(
19092
19141
  ` (${k(stat.inputTokens)}/${k(getModelContextLimit(stat.model))} out ${k(stat.outputTokens)} \xB7 ${modelShort})`
19093
19142
  );
19094
19143
  }
@@ -19111,11 +19160,11 @@ function agentLabel(agent, mcpServer, sessionId) {
19111
19160
  const tag = sessionTag(sessionId);
19112
19161
  const tagSuffix = tag ? `\xB7${tag}` : "";
19113
19162
  if (!agent || agent === "Terminal") {
19114
- return mcpServer ? import_chalk35.default.dim(`[\u2192 ${mcpServer}] `) : "";
19163
+ return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
19115
19164
  }
19116
19165
  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}] `);
19166
+ if (!short) return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
19167
+ return mcpServer ? import_chalk36.default.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : import_chalk36.default.dim(`[${short}${tagSuffix}] `);
19119
19168
  }
19120
19169
  function formatBase(activity) {
19121
19170
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
@@ -19123,20 +19172,20 @@ function formatBase(activity) {
19123
19172
  const toolName = activity.tool.slice(0, 16).padEnd(16);
19124
19173
  const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os55.default.homedir(), "~");
19125
19174
  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)}`;
19175
+ 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
19176
  }
19128
19177
  function renderResult(activity, result) {
19129
19178
  const base = formatBase(activity);
19130
19179
  let status;
19131
19180
  if (result.status === "allow") {
19132
- status = import_chalk35.default.green("\u2713 ALLOW");
19181
+ status = import_chalk36.default.green("\u2713 ALLOW");
19133
19182
  } else if (result.status === "dlp") {
19134
- status = import_chalk35.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
19183
+ status = import_chalk36.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
19135
19184
  } else {
19136
- status = import_chalk35.default.red("\u2717 BLOCK");
19185
+ status = import_chalk36.default.red("\u2717 BLOCK");
19137
19186
  }
19138
19187
  const cost = result.costEstimate ?? activity.costEstimate;
19139
- const costSuffix = cost == null ? "" : import_chalk35.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
19188
+ const costSuffix = cost == null ? "" : import_chalk36.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
19140
19189
  if (process.stdout.isTTY) {
19141
19190
  if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
19142
19191
  import_readline6.default.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
@@ -19153,7 +19202,7 @@ function renderResult(activity, result) {
19153
19202
  }
19154
19203
  function renderPending(activity) {
19155
19204
  if (!process.stdout.isTTY) return;
19156
- const line = `${formatBase(activity)} ${import_chalk35.default.yellow("\u25CF \u2026")}`;
19205
+ const line = `${formatBase(activity)} ${import_chalk36.default.yellow("\u25CF \u2026")}`;
19157
19206
  pendingShownForId = activity.id;
19158
19207
  pendingWrappedLines = wrappedLineCount(line);
19159
19208
  process.stdout.write(`${line}\r`);
@@ -19165,7 +19214,7 @@ async function ensureDaemon() {
19165
19214
  const { port } = JSON.parse(import_fs64.default.readFileSync(PID_FILE, "utf-8"));
19166
19215
  pidPort = port;
19167
19216
  } catch {
19168
- console.error(import_chalk35.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
19217
+ console.error(import_chalk36.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
19169
19218
  }
19170
19219
  }
19171
19220
  const checkPort = pidPort ?? DAEMON_PORT;
@@ -19176,7 +19225,7 @@ async function ensureDaemon() {
19176
19225
  if (res.ok) return checkPort;
19177
19226
  } catch {
19178
19227
  }
19179
- console.log(import_chalk35.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
19228
+ console.log(import_chalk36.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
19180
19229
  const child = (0, import_child_process14.spawn)(process.execPath, [process.argv[1], "daemon"], {
19181
19230
  detached: true,
19182
19231
  stdio: "ignore",
@@ -19193,7 +19242,7 @@ async function ensureDaemon() {
19193
19242
  } catch {
19194
19243
  }
19195
19244
  }
19196
- console.error(import_chalk35.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
19245
+ console.error(import_chalk36.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
19197
19246
  process.exit(1);
19198
19247
  }
19199
19248
  function postDecisionHttp(id, decision, authToken, port, opts) {
@@ -19203,7 +19252,7 @@ function postDecisionHttp(id, decision, authToken, port, opts) {
19203
19252
  if (opts?.trustDuration) bodyObj.trustDuration = opts.trustDuration;
19204
19253
  if (opts?.reason) bodyObj.reason = opts.reason;
19205
19254
  const body = JSON.stringify(bodyObj);
19206
- const req = import_http4.default.request(
19255
+ const req = import_http5.default.request(
19207
19256
  {
19208
19257
  hostname: "127.0.0.1",
19209
19258
  port,
@@ -19262,7 +19311,7 @@ function buildCardLines(req, localCount = 0) {
19262
19311
  const severityIcon = isBlock ? `${RED}\u{1F6D1}` : `${YELLOW}\u26A0 `;
19263
19312
  const rawDesc = req.riskMetadata?.ruleDescription ?? "";
19264
19313
  const description = rawDesc ? cleanReason(rawDesc) : "";
19265
- const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk35.default.dim(`(${req.agent})`)}` : "";
19314
+ const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk36.default.dim(`(${req.agent})`)}` : "";
19266
19315
  const lines = [
19267
19316
  ``,
19268
19317
  `${BOLD2}${CYAN}\u2554\u2550\u2550 Node9 Approval Required \u2550\u2550\u2557${RESET2}`,
@@ -19331,7 +19380,7 @@ function approverStatusLine() {
19331
19380
  const a = readApproversFromDisk();
19332
19381
  const fmt = (label2, key) => {
19333
19382
  const on = a[key] !== false;
19334
- return `[${key[0]}]${label2.slice(1)} ${on ? import_chalk35.default.green("\u2713") : import_chalk35.default.dim("\u2717")}`;
19383
+ return `[${key[0]}]${label2.slice(1)} ${on ? import_chalk36.default.green("\u2713") : import_chalk36.default.dim("\u2717")}`;
19335
19384
  };
19336
19385
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
19337
19386
  }
@@ -19354,7 +19403,7 @@ async function startTail(options = {}) {
19354
19403
  const port = await ensureDaemon();
19355
19404
  if (options.clear) {
19356
19405
  const result = await new Promise((resolve) => {
19357
- const req2 = import_http4.default.request(
19406
+ const req2 = import_http5.default.request(
19358
19407
  { method: "POST", hostname: "127.0.0.1", port, path: "/events/clear" },
19359
19408
  (res) => {
19360
19409
  const status = res.statusCode ?? 0;
@@ -19376,7 +19425,7 @@ async function startTail(options = {}) {
19376
19425
  req2.end();
19377
19426
  });
19378
19427
  if (result.ok) {
19379
- console.log(import_chalk35.default.green("\u2713 Flight Recorder buffer cleared."));
19428
+ console.log(import_chalk36.default.green("\u2713 Flight Recorder buffer cleared."));
19380
19429
  } else if (result.code === "ECONNREFUSED") {
19381
19430
  throw new Error("Daemon is not running. Start it with: node9 daemon start");
19382
19431
  } else if (result.code === "ETIMEDOUT") {
@@ -19422,7 +19471,7 @@ async function startTail(options = {}) {
19422
19471
  const channel = name === "n" ? "native" : name === "c" ? "cloud" : name === "t" ? "terminal" : null;
19423
19472
  if (channel) {
19424
19473
  toggleApprover(channel);
19425
- console.log(import_chalk35.default.dim(` Approvers: ${approverStatusLine()}`));
19474
+ console.log(import_chalk36.default.dim(` Approvers: ${approverStatusLine()}`));
19426
19475
  }
19427
19476
  };
19428
19477
  process.stdin.on("keypress", idleKeypressHandler);
@@ -19488,7 +19537,7 @@ async function startTail(options = {}) {
19488
19537
  localAllowCounts.get(req2.toolName) ?? 0
19489
19538
  )
19490
19539
  );
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");
19540
+ 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
19541
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${decisionStamp} ${GRAY}(terminal)${RESET2}`, ``);
19493
19542
  for (const line of stampedLines) process.stdout.write(line + "\n");
19494
19543
  process.stdout.write(SHOW_CURSOR);
@@ -19539,7 +19588,7 @@ async function startTail(options = {}) {
19539
19588
  );
19540
19589
  const stampedLines = buildCardLines(req2, priorCount);
19541
19590
  if (externalDecision) {
19542
- const source = externalDecision === "allow" ? import_chalk35.default.green("\u2713 ALLOWED") : import_chalk35.default.red("\u2717 DENIED");
19591
+ const source = externalDecision === "allow" ? import_chalk36.default.green("\u2713 ALLOWED") : import_chalk36.default.red("\u2717 DENIED");
19543
19592
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${source} ${GRAY}(external)${RESET2}`, ``);
19544
19593
  }
19545
19594
  for (const line of stampedLines) process.stdout.write(line + "\n");
@@ -19587,25 +19636,25 @@ async function startTail(options = {}) {
19587
19636
  if (unackedDlp > 0) {
19588
19637
  console.log("");
19589
19638
  console.log(
19590
- import_chalk35.default.bgRed.white.bold(
19639
+ import_chalk36.default.bgRed.white.bold(
19591
19640
  ` \u26A0\uFE0F DLP ALERT: ${unackedDlp} secret${unackedDlp !== 1 ? "s" : ""} found in Claude response text \u2014 run: node9 dlp `
19592
19641
  )
19593
19642
  );
19594
19643
  }
19595
19644
  } catch {
19596
19645
  }
19597
- console.log(import_chalk35.default.cyan.bold(`
19646
+ console.log(import_chalk36.default.cyan.bold(`
19598
19647
  \u{1F6F0}\uFE0F Node9 tail`));
19599
19648
  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`));
19649
+ console.log(import_chalk36.default.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
19650
+ console.log(import_chalk36.default.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
19602
19651
  }
19603
19652
  const ctxStat = readSessionUsage();
19604
19653
  if (ctxStat) console.log(" " + formatContextStat(ctxStat));
19605
19654
  if (options.history) {
19606
- console.log(import_chalk35.default.dim("Showing history + live events.\n"));
19655
+ console.log(import_chalk36.default.dim("Showing history + live events.\n"));
19607
19656
  } else {
19608
- console.log(import_chalk35.default.dim("Showing live events only. Use --history to include past.\n"));
19657
+ console.log(import_chalk36.default.dim("Showing live events only. Use --history to include past.\n"));
19609
19658
  }
19610
19659
  process.on("SIGINT", () => {
19611
19660
  exitIdleMode();
@@ -19615,7 +19664,7 @@ async function startTail(options = {}) {
19615
19664
  import_readline6.default.clearLine(process.stdout, 0);
19616
19665
  import_readline6.default.cursorTo(process.stdout, 0);
19617
19666
  }
19618
- console.log(import_chalk35.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
19667
+ console.log(import_chalk36.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
19619
19668
  process.exit(0);
19620
19669
  });
19621
19670
  const STALL_THRESHOLD_MS = 6e4;
@@ -19627,7 +19676,7 @@ async function startTail(options = {}) {
19627
19676
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
19628
19677
  console.log("");
19629
19678
  console.log(
19630
- import_chalk35.default.yellow(
19679
+ import_chalk36.default.yellow(
19631
19680
  "\u26A0\uFE0F Tail appears stalled \u2014 hooks are firing but no events are arriving. Try: node9 daemon restart"
19632
19681
  )
19633
19682
  );
@@ -19637,14 +19686,14 @@ async function startTail(options = {}) {
19637
19686
  }, STALL_THRESHOLD_MS / 2);
19638
19687
  stallWatchdog.unref();
19639
19688
  const sseUrl = `http://127.0.0.1:${port}/events?capabilities=input`;
19640
- const req = import_http4.default.get(
19689
+ const req = import_http5.default.get(
19641
19690
  sseUrl,
19642
19691
  {
19643
19692
  headers: authToken ? { "X-Node9-Internal": authToken } : {}
19644
19693
  },
19645
19694
  (res) => {
19646
19695
  if (res.statusCode !== 200) {
19647
- console.error(import_chalk35.default.red(`Failed to connect: HTTP ${res.statusCode}`));
19696
+ console.error(import_chalk36.default.red(`Failed to connect: HTTP ${res.statusCode}`));
19648
19697
  process.exit(1);
19649
19698
  }
19650
19699
  if (canApprove) enterIdleMode();
@@ -19675,7 +19724,7 @@ async function startTail(options = {}) {
19675
19724
  import_readline6.default.clearLine(process.stdout, 0);
19676
19725
  import_readline6.default.cursorTo(process.stdout, 0);
19677
19726
  }
19678
- console.log(import_chalk35.default.red("\n\u274C Daemon disconnected."));
19727
+ console.log(import_chalk36.default.red("\n\u274C Daemon disconnected."));
19679
19728
  process.exit(1);
19680
19729
  });
19681
19730
  }
@@ -19688,7 +19737,7 @@ async function startTail(options = {}) {
19688
19737
  const parsed = JSON.parse(rawData);
19689
19738
  const msg = parsed.message ?? "Flight recorder is down \u2014 run: node9 daemon restart";
19690
19739
  console.log("");
19691
- console.log(import_chalk35.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
19740
+ console.log(import_chalk36.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
19692
19741
  } catch {
19693
19742
  }
19694
19743
  return;
@@ -19773,9 +19822,9 @@ async function startTail(options = {}) {
19773
19822
  const rawSummary = data.argsSummary ?? data.tool;
19774
19823
  const summary = shortenPathSummary(rawSummary);
19775
19824
  const fileCount = data.fileCount ?? 0;
19776
- const files = fileCount > 0 ? import_chalk35.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
19825
+ const files = fileCount > 0 ? import_chalk36.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
19777
19826
  process.stdout.write(
19778
- `${import_chalk35.default.dim(time)} ${import_chalk35.default.cyan("\u{1F4F8} snapshot")} ${import_chalk35.default.dim(hash)} ${summary}${files}
19827
+ `${import_chalk36.default.dim(time)} ${import_chalk36.default.cyan("\u{1F4F8} snapshot")} ${import_chalk36.default.dim(hash)} ${summary}${files}
19779
19828
  `
19780
19829
  );
19781
19830
  return;
@@ -19792,28 +19841,28 @@ async function startTail(options = {}) {
19792
19841
  if (event === "execution-result") {
19793
19842
  const exec = data;
19794
19843
  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");
19844
+ const arrow = exec.isError ? import_chalk36.default.red(" \u21B3 \u2717") : import_chalk36.default.green(" \u21B3 \u2713");
19796
19845
  const label2 = agentLabel(exec.agent, exec.mcpServer);
19797
19846
  const tool = (exec.tool ?? "").slice(0, 16);
19798
- const duration = typeof exec.durationMs === "number" ? import_chalk35.default.dim(` (${exec.durationMs}ms)`) : "";
19847
+ const duration = typeof exec.durationMs === "number" ? import_chalk36.default.dim(` (${exec.durationMs}ms)`) : "";
19799
19848
  console.log(
19800
- `${import_chalk35.default.gray(time)} ${arrow} ${label2}${import_chalk35.default.dim(tool)}${import_chalk35.default.dim(" completed")}${duration}`
19849
+ `${import_chalk36.default.gray(time)} ${arrow} ${label2}${import_chalk36.default.dim(tool)}${import_chalk36.default.dim(" completed")}${duration}`
19801
19850
  );
19802
19851
  }
19803
19852
  }
19804
19853
  req.on("error", (err2) => {
19805
19854
  const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
19806
- console.error(import_chalk35.default.red(`
19855
+ console.error(import_chalk36.default.red(`
19807
19856
  \u274C ${msg}`));
19808
19857
  process.exit(1);
19809
19858
  });
19810
19859
  }
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;
19860
+ 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
19861
  var init_tail = __esm({
19813
19862
  "src/tui/tail.ts"() {
19814
19863
  "use strict";
19815
- import_http4 = __toESM(require("http"));
19816
- import_chalk35 = __toESM(require("chalk"));
19864
+ import_http5 = __toESM(require("http"));
19865
+ import_chalk36 = __toESM(require("chalk"));
19817
19866
  import_fs64 = __toESM(require("fs"));
19818
19867
  import_os55 = __toESM(require("os"));
19819
19868
  import_path62 = __toESM(require("path"));
@@ -19886,7 +19935,7 @@ function queryDaemon() {
19886
19935
  return new Promise((resolve) => {
19887
19936
  const timeout = setTimeout(() => resolve(null), 50);
19888
19937
  try {
19889
- const req = import_http5.default.get(
19938
+ const req = import_http6.default.get(
19890
19939
  `http://${DAEMON_HOST}:${DAEMON_PORT}/status`,
19891
19940
  { timeout: 50 },
19892
19941
  (res) => {
@@ -20214,14 +20263,14 @@ async function main() {
20214
20263
  renderOffline();
20215
20264
  }
20216
20265
  }
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;
20266
+ 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
20267
  var init_hud = __esm({
20219
20268
  "src/cli/hud.ts"() {
20220
20269
  "use strict";
20221
20270
  import_fs65 = __toESM(require("fs"));
20222
20271
  import_path63 = __toESM(require("path"));
20223
20272
  import_os56 = __toESM(require("os"));
20224
- import_http5 = __toESM(require("http"));
20273
+ import_http6 = __toESM(require("http"));
20225
20274
  init_daemon();
20226
20275
  RESET3 = "\x1B[0m";
20227
20276
  BOLD3 = "\x1B[1m";
@@ -20278,8 +20327,69 @@ function agentTeardownTargets() {
20278
20327
 
20279
20328
  // src/cli.ts
20280
20329
  init_agent_wiring();
20330
+
20331
+ // src/credentials.ts
20332
+ var fs15 = __toESM(require("fs"));
20333
+ var os14 = __toESM(require("os"));
20334
+ var path17 = __toESM(require("path"));
20335
+ var DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
20336
+ function writeCredentialsAndConfig(apiKey, opts = {}) {
20337
+ const profileName = opts.profileName || "default";
20338
+ const home = opts.homeDir ?? os14.homedir();
20339
+ const credPath = path17.join(home, ".node9", "credentials.json");
20340
+ if (!fs15.existsSync(path17.dirname(credPath))) {
20341
+ fs15.mkdirSync(path17.dirname(credPath), { recursive: true });
20342
+ }
20343
+ let existingCreds = {};
20344
+ try {
20345
+ if (fs15.existsSync(credPath)) {
20346
+ const raw = JSON.parse(fs15.readFileSync(credPath, "utf-8"));
20347
+ existingCreds = raw.apiKey ? { default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL } } : raw;
20348
+ }
20349
+ } catch {
20350
+ }
20351
+ existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL };
20352
+ fs15.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), {
20353
+ mode: 384
20354
+ });
20355
+ let effectiveCloud = null;
20356
+ if (profileName === "default") {
20357
+ const configPath = path17.join(home, ".node9", "config.json");
20358
+ let config = {};
20359
+ try {
20360
+ if (fs15.existsSync(configPath)) {
20361
+ config = JSON.parse(fs15.readFileSync(configPath, "utf-8"));
20362
+ }
20363
+ } catch {
20364
+ }
20365
+ if (!config.settings || typeof config.settings !== "object") {
20366
+ config.settings = {};
20367
+ }
20368
+ const s = config.settings;
20369
+ const approvers = s.approvers || {
20370
+ native: true,
20371
+ browser: true,
20372
+ cloud: true,
20373
+ terminal: true
20374
+ };
20375
+ if (opts.isLocal) {
20376
+ approvers.cloud = false;
20377
+ }
20378
+ s.approvers = approvers;
20379
+ if (!fs15.existsSync(path17.dirname(configPath))) {
20380
+ fs15.mkdirSync(path17.dirname(configPath), { recursive: true });
20381
+ }
20382
+ fs15.writeFileSync(configPath, JSON.stringify(config, null, 2), {
20383
+ mode: 384
20384
+ });
20385
+ effectiveCloud = approvers.cloud === true;
20386
+ }
20387
+ return { profileName, effectiveCloud };
20388
+ }
20389
+
20390
+ // src/cli.ts
20281
20391
  init_daemon2();
20282
- var import_chalk36 = __toESM(require("chalk"));
20392
+ var import_chalk37 = __toESM(require("chalk"));
20283
20393
  var import_fs66 = __toESM(require("fs"));
20284
20394
  var import_path64 = __toESM(require("path"));
20285
20395
  var import_os57 = __toESM(require("os"));
@@ -24154,18 +24264,7 @@ function registerInitCommand(program2) {
24154
24264
  console.log("");
24155
24265
  for (const agent of found) {
24156
24266
  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();
24267
+ await setupAgent(agent);
24169
24268
  console.log("");
24170
24269
  }
24171
24270
  if ((process.platform === "darwin" || process.platform === "linux") && process.stdout.isTTY) {
@@ -24228,13 +24327,110 @@ function registerInitCommand(program2) {
24228
24327
  );
24229
24328
  }
24230
24329
 
24330
+ // src/cli/commands/connect.ts
24331
+ var import_http4 = __toESM(require("http"));
24332
+ var import_https7 = __toESM(require("https"));
24333
+ var import_url3 = require("url");
24334
+ var import_chalk17 = __toESM(require("chalk"));
24335
+ init_setup();
24336
+ init_sync();
24337
+ var DEFAULT_CONNECT_URL = "https://api.node9.ai/api/v1/cli/connect";
24338
+ function resolveConnectUrl(apiUrl) {
24339
+ if (apiUrl) return apiUrl;
24340
+ const base = process.env.NODE9_API_URL;
24341
+ if (base) return base.replace(/\/intercept\/?$/, "") + "/cli/connect";
24342
+ return DEFAULT_CONNECT_URL;
24343
+ }
24344
+ function postConnect(url, token) {
24345
+ return new Promise((resolve, reject) => {
24346
+ const body = JSON.stringify({ token });
24347
+ const u = new import_url3.URL(url);
24348
+ const lib = u.protocol === "http:" ? import_http4.default : import_https7.default;
24349
+ const req = lib.request(
24350
+ {
24351
+ method: "POST",
24352
+ hostname: u.hostname,
24353
+ port: u.port || (u.protocol === "http:" ? 80 : 443),
24354
+ path: u.pathname + u.search,
24355
+ headers: {
24356
+ "Content-Type": "application/json",
24357
+ "Content-Length": Buffer.byteLength(body)
24358
+ },
24359
+ timeout: 15e3
24360
+ },
24361
+ (res) => {
24362
+ let data = "";
24363
+ res.on("data", (c) => data += c);
24364
+ res.on("end", () => {
24365
+ const code = res.statusCode ?? 0;
24366
+ if (code >= 200 && code < 300) {
24367
+ try {
24368
+ resolve(JSON.parse(data));
24369
+ } catch {
24370
+ reject(new Error("Unexpected response from the server."));
24371
+ }
24372
+ } else if (code === 400 || code === 401) {
24373
+ reject(
24374
+ new Error(
24375
+ "This connect link expired or was already used \u2014 generate a new one in the dashboard."
24376
+ )
24377
+ );
24378
+ } else {
24379
+ reject(new Error(`Connect failed (HTTP ${code}).`));
24380
+ }
24381
+ });
24382
+ }
24383
+ );
24384
+ req.on("error", (e) => reject(e));
24385
+ req.on("timeout", () => {
24386
+ req.destroy();
24387
+ reject(new Error("Connection timed out."));
24388
+ });
24389
+ req.write(body);
24390
+ req.end();
24391
+ });
24392
+ }
24393
+ function registerConnectCommand(program2) {
24394
+ 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) => {
24395
+ let resp;
24396
+ try {
24397
+ resp = await postConnect(resolveConnectUrl(options.apiUrl), token);
24398
+ } catch (e) {
24399
+ console.error(import_chalk17.default.red(`\u2717 ${e instanceof Error ? e.message : "Connect failed."}`));
24400
+ process.exitCode = 1;
24401
+ return;
24402
+ }
24403
+ writeCredentialsAndConfig(resp.apiKey, { profileName: options.profile });
24404
+ process.env.NODE9_NONINTERACTIVE = "1";
24405
+ let wired = [];
24406
+ try {
24407
+ wired = await setupDetectedAgents();
24408
+ } catch {
24409
+ }
24410
+ if (!isTestingMode()) {
24411
+ try {
24412
+ await runCloudSync();
24413
+ } catch {
24414
+ }
24415
+ }
24416
+ console.log(import_chalk17.default.green(`\u2705 Connected to ${resp.workspaceName}`));
24417
+ if (wired.length) {
24418
+ console.log(import_chalk17.default.gray(` Wired: ${wired.join(", ")}`));
24419
+ } else {
24420
+ console.log(
24421
+ import_chalk17.default.gray(" No agents detected yet \u2014 run `node9 init` after installing one.")
24422
+ );
24423
+ }
24424
+ });
24425
+ }
24426
+
24231
24427
  // src/cli/commands/undo.ts
24232
24428
  var import_path50 = __toESM(require("path"));
24233
- var import_chalk18 = __toESM(require("chalk"));
24429
+ var import_chalk19 = __toESM(require("chalk"));
24234
24430
 
24235
24431
  // src/tui/undo-navigator.ts
24236
24432
  var import_readline3 = __toESM(require("readline"));
24237
- var import_chalk17 = __toESM(require("chalk"));
24433
+ var import_chalk18 = __toESM(require("chalk"));
24238
24434
  var RESET = "\x1B[0m";
24239
24435
  var BOLD = "\x1B[1m";
24240
24436
  var CLEAR_SCREEN = "\x1B[2J\x1B[H";
@@ -24252,15 +24448,15 @@ function renderDiff(raw) {
24252
24448
  );
24253
24449
  for (const line of lines) {
24254
24450
  if (line.startsWith("+++") || line.startsWith("---")) {
24255
- process.stdout.write(import_chalk17.default.bold(line) + "\n");
24451
+ process.stdout.write(import_chalk18.default.bold(line) + "\n");
24256
24452
  } else if (line.startsWith("+")) {
24257
- process.stdout.write(import_chalk17.default.green(line) + "\n");
24453
+ process.stdout.write(import_chalk18.default.green(line) + "\n");
24258
24454
  } else if (line.startsWith("-")) {
24259
- process.stdout.write(import_chalk17.default.red(line) + "\n");
24455
+ process.stdout.write(import_chalk18.default.red(line) + "\n");
24260
24456
  } else if (line.startsWith("@@")) {
24261
- process.stdout.write(import_chalk17.default.cyan(line) + "\n");
24457
+ process.stdout.write(import_chalk18.default.cyan(line) + "\n");
24262
24458
  } else {
24263
- process.stdout.write(import_chalk17.default.gray(line) + "\n");
24459
+ process.stdout.write(import_chalk18.default.gray(line) + "\n");
24264
24460
  }
24265
24461
  }
24266
24462
  }
@@ -24279,23 +24475,23 @@ function render(entries, idx) {
24279
24475
  const step = idx + 1;
24280
24476
  process.stdout.write(CLEAR_SCREEN);
24281
24477
  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(
24478
+ 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
24479
  ` \u2500\u2500 ${entry.files.slice(0, 2).join(", ")}${entry.files.length > 2 ? ` +${entry.files.length - 2} more` : ""}`
24284
24480
  ) : "") + "\n\n"
24285
24481
  );
24286
24482
  process.stdout.write(
24287
- ` ${BOLD}Tool:${RESET} ${import_chalk17.default.cyan(entry.tool)}` + (entry.argsSummary ? import_chalk17.default.gray(" \u2192 " + entry.argsSummary) : "") + "\n"
24483
+ ` ${BOLD}Tool:${RESET} ${import_chalk18.default.cyan(entry.tool)}` + (entry.argsSummary ? import_chalk18.default.gray(" \u2192 " + entry.argsSummary) : "") + "\n"
24288
24484
  );
24289
- process.stdout.write(` ${BOLD}When:${RESET} ${import_chalk17.default.gray(formatAge(entry.timestamp))}
24485
+ process.stdout.write(` ${BOLD}When:${RESET} ${import_chalk18.default.gray(formatAge(entry.timestamp))}
24290
24486
  `);
24291
- process.stdout.write(` ${BOLD}Dir: ${RESET} ${import_chalk17.default.gray(entry.cwd)}
24487
+ process.stdout.write(` ${BOLD}Dir: ${RESET} ${import_chalk18.default.gray(entry.cwd)}
24292
24488
  `);
24293
24489
  if (entry.files && entry.files.length > 0) {
24294
- process.stdout.write(` ${BOLD}Files:${RESET} ${import_chalk17.default.gray(entry.files.join(", "))}
24490
+ process.stdout.write(` ${BOLD}Files:${RESET} ${import_chalk18.default.gray(entry.files.join(", "))}
24295
24491
  `);
24296
24492
  }
24297
24493
  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"));
24494
+ process.stdout.write(import_chalk18.default.gray("\n \u2500\u2500 session boundary above \u2500\u2500\n"));
24299
24495
  }
24300
24496
  process.stdout.write("\n");
24301
24497
  const diff = entry.diff ?? computeUndoDiff(entry.hash, entry.cwd);
@@ -24303,12 +24499,12 @@ function render(entries, idx) {
24303
24499
  renderDiff(diff);
24304
24500
  } else {
24305
24501
  process.stdout.write(
24306
- import_chalk17.default.gray(" (no diff \u2014 working tree may already match this snapshot)\n")
24502
+ import_chalk18.default.gray(" (no diff \u2014 working tree may already match this snapshot)\n")
24307
24503
  );
24308
24504
  }
24309
24505
  process.stdout.write("\n");
24310
24506
  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"
24507
+ 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
24508
  );
24313
24509
  }
24314
24510
  async function runUndoNavigator(entries) {
@@ -24362,19 +24558,19 @@ async function runUndoNavigator(entries) {
24362
24558
  cleanup();
24363
24559
  process.stdout.write(CLEAR_SCREEN);
24364
24560
  const entry = display[idx];
24365
- process.stdout.write(import_chalk17.default.magenta.bold("\n\u23EA Restoring snapshot...\n\n"));
24561
+ process.stdout.write(import_chalk18.default.magenta.bold("\n\u23EA Restoring snapshot...\n\n"));
24366
24562
  if (applyUndo(entry.hash, entry.cwd)) {
24367
- process.stdout.write(import_chalk17.default.green("\u2705 Reverted successfully.\n\n"));
24563
+ process.stdout.write(import_chalk18.default.green("\u2705 Reverted successfully.\n\n"));
24368
24564
  resolve({ restored: true });
24369
24565
  } else {
24370
- process.stdout.write(import_chalk17.default.red("\u274C Undo failed.\n\n"));
24566
+ process.stdout.write(import_chalk18.default.red("\u274C Undo failed.\n\n"));
24371
24567
  resolve({ restored: false });
24372
24568
  }
24373
24569
  } else if (name === "q" || key?.ctrl && name === "c") {
24374
24570
  done = true;
24375
24571
  cleanup();
24376
24572
  process.stdout.write(CLEAR_SCREEN);
24377
- process.stdout.write(import_chalk17.default.gray("\nCancelled.\n\n"));
24573
+ process.stdout.write(import_chalk18.default.gray("\nCancelled.\n\n"));
24378
24574
  resolve({ restored: false });
24379
24575
  }
24380
24576
  };
@@ -24410,39 +24606,39 @@ function registerUndoCommand(program2) {
24410
24606
  if (history.length === 0) {
24411
24607
  if (!options.all && allHistory.length > 0) {
24412
24608
  console.log(
24413
- import_chalk18.default.yellow(
24609
+ import_chalk19.default.yellow(
24414
24610
  `
24415
24611
  \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.
24612
+ Run ${import_chalk19.default.cyan("node9 undo --all")} to see snapshots from all projects.
24417
24613
  `
24418
24614
  )
24419
24615
  );
24420
24616
  } else {
24421
- console.log(import_chalk18.default.yellow("\n\u2139\uFE0F No undo snapshots found.\n"));
24617
+ console.log(import_chalk19.default.yellow("\n\u2139\uFE0F No undo snapshots found.\n"));
24422
24618
  }
24423
24619
  return;
24424
24620
  }
24425
24621
  if (options.list) {
24426
- console.log(import_chalk18.default.magenta.bold("\n\u23EA Snapshot History\n"));
24622
+ console.log(import_chalk19.default.magenta.bold("\n\u23EA Snapshot History\n"));
24427
24623
  console.log(
24428
- import_chalk18.default.gray(
24624
+ import_chalk19.default.gray(
24429
24625
  ` ${"#".padEnd(3)} ${"File / Command".padEnd(30)} ${"Tool".padEnd(8)} ${"When".padEnd(10)} Dir`
24430
24626
  )
24431
24627
  );
24432
- console.log(import_chalk18.default.gray(" " + "\u2500".repeat(80)));
24628
+ console.log(import_chalk19.default.gray(" " + "\u2500".repeat(80)));
24433
24629
  const display = [...history].reverse();
24434
24630
  let prevTs = null;
24435
24631
  for (let i = 0; i < display.length; i++) {
24436
24632
  const e = display[i];
24437
24633
  const isGap = prevTs !== null && prevTs - e.timestamp > 6e4;
24438
- if (isGap) console.log(import_chalk18.default.gray(" \u2500\u2500 earlier \u2500\u2500"));
24634
+ if (isGap) console.log(import_chalk19.default.gray(" \u2500\u2500 earlier \u2500\u2500"));
24439
24635
  const label2 = (e.argsSummary || e.files?.[0] || "\u2014").slice(0, 30).padEnd(30);
24440
24636
  const tool = e.tool.slice(0, 8).padEnd(8);
24441
24637
  const when = formatAge2(e.timestamp).padEnd(10);
24442
24638
  const dir = e.cwd.length > 30 ? "\u2026" + e.cwd.slice(-29) : e.cwd;
24443
24639
  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)}`
24640
+ import_chalk19.default.white(
24641
+ ` ${String(i + 1).padEnd(3)} ${label2} ${import_chalk19.default.cyan(tool)} ${import_chalk19.default.gray(when)} ${import_chalk19.default.gray(dir)}`
24446
24642
  )
24447
24643
  );
24448
24644
  prevTs = e.timestamp;
@@ -24455,7 +24651,7 @@ function registerUndoCommand(program2) {
24455
24651
  const idx = history.length - steps;
24456
24652
  if (idx < 0) {
24457
24653
  console.log(
24458
- import_chalk18.default.yellow(
24654
+ import_chalk19.default.yellow(
24459
24655
  `
24460
24656
  \u2139\uFE0F Only ${history.length} snapshot(s) available, cannot go back ${steps}.
24461
24657
  `
@@ -24466,47 +24662,47 @@ function registerUndoCommand(program2) {
24466
24662
  const snapshot = history[idx];
24467
24663
  const ageStr = formatAge2(snapshot.timestamp);
24468
24664
  console.log(
24469
- import_chalk18.default.magenta.bold(`
24665
+ import_chalk19.default.magenta.bold(`
24470
24666
  \u23EA Node9 Undo${steps > 1 ? ` (${steps} steps back)` : ""}`)
24471
24667
  );
24472
24668
  console.log(
24473
- import_chalk18.default.white(
24474
- ` Tool: ${import_chalk18.default.cyan(snapshot.tool)}${snapshot.argsSummary ? import_chalk18.default.gray(" \u2192 " + snapshot.argsSummary) : ""}`
24669
+ import_chalk19.default.white(
24670
+ ` Tool: ${import_chalk19.default.cyan(snapshot.tool)}${snapshot.argsSummary ? import_chalk19.default.gray(" \u2192 " + snapshot.argsSummary) : ""}`
24475
24671
  )
24476
24672
  );
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)}`));
24673
+ console.log(import_chalk19.default.white(` When: ${import_chalk19.default.gray(ageStr)}`));
24674
+ console.log(import_chalk19.default.white(` Dir: ${import_chalk19.default.gray(snapshot.cwd)}`));
24479
24675
  if (steps > 1)
24480
24676
  console.log(
24481
- import_chalk18.default.yellow(` Note: This will also undo the ${steps - 1} action(s) after it.`)
24677
+ import_chalk19.default.yellow(` Note: This will also undo the ${steps - 1} action(s) after it.`)
24482
24678
  );
24483
24679
  console.log("");
24484
24680
  const diff = snapshot.diff ?? computeUndoDiff(snapshot.hash, snapshot.cwd);
24485
24681
  if (diff) {
24486
24682
  const lines = diff.split("\n").filter((l) => !l.startsWith("diff --git") && !l.startsWith("index "));
24487
24683
  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));
24684
+ if (line.startsWith("+++") || line.startsWith("---")) console.log(import_chalk19.default.bold(line));
24685
+ else if (line.startsWith("+")) console.log(import_chalk19.default.green(line));
24686
+ else if (line.startsWith("-")) console.log(import_chalk19.default.red(line));
24687
+ else if (line.startsWith("@@")) console.log(import_chalk19.default.cyan(line));
24688
+ else console.log(import_chalk19.default.gray(line));
24493
24689
  }
24494
24690
  console.log("");
24495
24691
  } else {
24496
24692
  console.log(
24497
- import_chalk18.default.gray(" (no diff available \u2014 working tree may already match snapshot)\n")
24693
+ import_chalk19.default.gray(" (no diff available \u2014 working tree may already match snapshot)\n")
24498
24694
  );
24499
24695
  }
24500
24696
  const { confirm: confirm3 } = await import("@inquirer/prompts");
24501
24697
  const proceed = await confirm3({ message: `Revert to this snapshot?`, default: false });
24502
24698
  if (proceed) {
24503
24699
  if (applyUndo(snapshot.hash, snapshot.cwd)) {
24504
- console.log(import_chalk18.default.green("\n\u2705 Reverted successfully.\n"));
24700
+ console.log(import_chalk19.default.green("\n\u2705 Reverted successfully.\n"));
24505
24701
  } else {
24506
- console.error(import_chalk18.default.red("\n\u274C Undo failed. Ensure you are in a Git repository.\n"));
24702
+ console.error(import_chalk19.default.red("\n\u274C Undo failed. Ensure you are in a Git repository.\n"));
24507
24703
  }
24508
24704
  } else {
24509
- console.log(import_chalk18.default.gray("\nCancelled.\n"));
24705
+ console.log(import_chalk19.default.gray("\nCancelled.\n"));
24510
24706
  }
24511
24707
  return;
24512
24708
  }
@@ -24516,7 +24712,7 @@ function registerUndoCommand(program2) {
24516
24712
 
24517
24713
  // src/mcp-gateway/index.ts
24518
24714
  var import_readline4 = __toESM(require("readline"));
24519
- var import_chalk19 = __toESM(require("chalk"));
24715
+ var import_chalk20 = __toESM(require("chalk"));
24520
24716
  var import_child_process10 = require("child_process");
24521
24717
  var import_execa3 = require("execa");
24522
24718
  init_orchestrator();
@@ -24652,13 +24848,13 @@ async function runMcpGateway(upstreamCommand) {
24652
24848
  const prov = checkProvenance(executable);
24653
24849
  if (prov.trustLevel === "suspect") {
24654
24850
  console.error(
24655
- import_chalk19.default.red(
24851
+ import_chalk20.default.red(
24656
24852
  `\u26A0\uFE0F Node9: Upstream MCP server binary is suspect \u2014 ${prov.reason} (${prov.resolvedPath})`
24657
24853
  )
24658
24854
  );
24659
- console.error(import_chalk19.default.red(" Verify this binary is trusted before proceeding."));
24855
+ console.error(import_chalk20.default.red(" Verify this binary is trusted before proceeding."));
24660
24856
  }
24661
- console.error(import_chalk19.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
24857
+ console.error(import_chalk20.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
24662
24858
  const UPSTREAM_INJECTOR_VARS = /* @__PURE__ */ new Set([
24663
24859
  "NODE_OPTIONS",
24664
24860
  "NODE_PATH",
@@ -24771,10 +24967,10 @@ async function runMcpGateway(upstreamCommand) {
24771
24967
  mcpServer
24772
24968
  });
24773
24969
  if (!result.approved) {
24774
- console.error(import_chalk19.default.red(`
24970
+ console.error(import_chalk20.default.red(`
24775
24971
  \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"}
24972
+ console.error(import_chalk20.default.gray(` Tool: ${toolName}`));
24973
+ console.error(import_chalk20.default.gray(` Reason: ${result.reason ?? "Security Policy"}
24778
24974
  `));
24779
24975
  const blockedByLabel = result.blockedByLabel ?? result.reason ?? "Security Policy";
24780
24976
  const isHumanDecision = blockedByLabel.toLowerCase().includes("user") || blockedByLabel.toLowerCase().includes("daemon") || blockedByLabel.toLowerCase().includes("decision");
@@ -24887,7 +25083,7 @@ async function runMcpGateway(upstreamCommand) {
24887
25083
  updatePin(serverKey, upstreamCommand, currentHash, toolNames);
24888
25084
  pinState = "validated";
24889
25085
  console.error(
24890
- import_chalk19.default.green(
25086
+ import_chalk20.default.green(
24891
25087
  `\u{1F512} Node9: Pinned ${toolNames.length} tool definition(s) for this MCP server`
24892
25088
  )
24893
25089
  );
@@ -24900,11 +25096,11 @@ async function runMcpGateway(upstreamCommand) {
24900
25096
  } else if (pinStatus === "corrupt") {
24901
25097
  pinState = "quarantined";
24902
25098
  console.error(
24903
- import_chalk19.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
25099
+ import_chalk20.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
24904
25100
  );
24905
- console.error(import_chalk19.default.red(" Tool calls are blocked until the pin file is repaired."));
25101
+ console.error(import_chalk20.default.red(" Tool calls are blocked until the pin file is repaired."));
24906
25102
  console.error(
24907
- import_chalk19.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
25103
+ import_chalk20.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
24908
25104
  `)
24909
25105
  );
24910
25106
  const errorResponse = {
@@ -24921,13 +25117,13 @@ async function runMcpGateway(upstreamCommand) {
24921
25117
  } else {
24922
25118
  pinState = "quarantined";
24923
25119
  console.error(
24924
- import_chalk19.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
25120
+ import_chalk20.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
24925
25121
  );
24926
25122
  console.error(
24927
- import_chalk19.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
25123
+ import_chalk20.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
24928
25124
  );
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}
25125
+ console.error(import_chalk20.default.red(" Session quarantined \u2014 all tool calls blocked."));
25126
+ console.error(import_chalk20.default.yellow(` Run: node9 mcp pin update ${serverKey}
24931
25127
  `));
24932
25128
  reportPinMismatchToCloud(serverKey, clientName);
24933
25129
  const errorResponse = {
@@ -24971,7 +25167,7 @@ async function runMcpGateway(upstreamCommand) {
24971
25167
  const toolName = callId !== void 0 ? pendingCallNames.get(callId) ?? "unknown" : "unknown";
24972
25168
  if (callId !== void 0) pendingCallNames.delete(callId);
24973
25169
  console.error(
24974
- import_chalk19.default.yellow(
25170
+ import_chalk20.default.yellow(
24975
25171
  `\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
24976
25172
  )
24977
25173
  );
@@ -25938,7 +26134,7 @@ function registerMcpServerCommand(program2) {
25938
26134
  }
25939
26135
 
25940
26136
  // src/cli/commands/trust.ts
25941
- var import_chalk20 = __toESM(require("chalk"));
26137
+ var import_chalk21 = __toESM(require("chalk"));
25942
26138
  init_trusted_hosts();
25943
26139
  function isValidHost(host) {
25944
26140
  return /^(\*\.)?[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(host);
@@ -25949,51 +26145,51 @@ function registerTrustCommand(program2) {
25949
26145
  const normalized = normalizeHost(host.trim());
25950
26146
  if (!isValidHost(normalized)) {
25951
26147
  console.error(
25952
- import_chalk20.default.red(`
26148
+ import_chalk21.default.red(`
25953
26149
  \u274C Invalid host: "${host}"
25954
- `) + import_chalk20.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
26150
+ `) + import_chalk21.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
25955
26151
  );
25956
26152
  process.exit(1);
25957
26153
  }
25958
26154
  addTrustedHost(normalized);
25959
- console.log(import_chalk20.default.green(`
26155
+ console.log(import_chalk21.default.green(`
25960
26156
  \u2705 ${normalized} added to trusted hosts.`));
25961
26157
  console.log(
25962
- import_chalk20.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
26158
+ import_chalk21.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
25963
26159
  );
25964
26160
  });
25965
26161
  trustCmd.command("remove <host>").description("Remove a trusted host").action((host) => {
25966
26162
  const normalized = normalizeHost(host.trim());
25967
26163
  const removed = removeTrustedHost(normalized);
25968
26164
  if (!removed) {
25969
- console.error(import_chalk20.default.yellow(`
26165
+ console.error(import_chalk21.default.yellow(`
25970
26166
  \u26A0\uFE0F "${normalized}" is not in the trusted hosts list.
25971
26167
  `));
25972
26168
  process.exit(1);
25973
26169
  }
25974
- console.log(import_chalk20.default.green(`
26170
+ console.log(import_chalk21.default.green(`
25975
26171
  \u2705 ${normalized} removed from trusted hosts.
25976
26172
  `));
25977
26173
  });
25978
26174
  trustCmd.command("list").description("Show all trusted hosts").action(() => {
25979
26175
  const hosts = readTrustedHosts();
25980
26176
  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")}
26177
+ console.log(import_chalk21.default.gray("\n No trusted hosts configured.\n"));
26178
+ console.log(` Add one: ${import_chalk21.default.cyan("node9 trust add api.mycompany.com")}
25983
26179
  `);
25984
26180
  return;
25985
26181
  }
25986
- console.log(import_chalk20.default.bold("\n\u{1F513} Trusted Hosts\n"));
26182
+ console.log(import_chalk21.default.bold("\n\u{1F513} Trusted Hosts\n"));
25987
26183
  for (const entry of hosts) {
25988
26184
  const date = new Date(entry.addedAt).toLocaleDateString();
25989
- console.log(` ${import_chalk20.default.cyan(entry.host.padEnd(40))} ${import_chalk20.default.gray(`added ${date}`)}`);
26185
+ console.log(` ${import_chalk21.default.cyan(entry.host.padEnd(40))} ${import_chalk21.default.gray(`added ${date}`)}`);
25990
26186
  }
25991
26187
  console.log("");
25992
26188
  });
25993
26189
  }
25994
26190
 
25995
26191
  // src/cli/commands/mcp-pin.ts
25996
- var import_chalk21 = __toESM(require("chalk"));
26192
+ var import_chalk22 = __toESM(require("chalk"));
25997
26193
  init_mcp_pin();
25998
26194
  var import_fs54 = __toESM(require("fs"));
25999
26195
  function registerMcpPinCommand(program2) {
@@ -26014,14 +26210,14 @@ function registerMcpPinCommand(program2) {
26014
26210
  }
26015
26211
  }
26016
26212
  if (repoCorrupt) {
26017
- console.error(import_chalk21.default.red(`
26213
+ console.error(import_chalk22.default.red(`
26018
26214
  \u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
26019
26215
  process.exit(1);
26020
26216
  }
26021
26217
  if (!homeResult.ok && homeResult.reason === "corrupt") {
26022
- console.error(import_chalk21.default.red(`
26218
+ console.error(import_chalk22.default.red(`
26023
26219
  \u274C Home pin file is corrupt: ${homeResult.detail}`));
26024
- console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
26220
+ console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
26025
26221
  process.exit(1);
26026
26222
  }
26027
26223
  const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
@@ -26033,25 +26229,25 @@ function registerMcpPinCommand(program2) {
26033
26229
  merged.set(key, { entry, source: "repo" });
26034
26230
  }
26035
26231
  if (merged.size === 0) {
26036
- console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
26232
+ console.log(import_chalk22.default.gray("\nNo MCP servers are pinned yet."));
26037
26233
  console.log(
26038
- import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
26234
+ import_chalk22.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
26039
26235
  );
26040
26236
  return;
26041
26237
  }
26042
- console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
26238
+ console.log(import_chalk22.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
26043
26239
  const showSource = found.source === "repo";
26044
26240
  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)}`);
26241
+ const tag = showSource ? ` ${import_chalk22.default.yellow(`[${source}]`)}` : "";
26242
+ console.log(` ${import_chalk22.default.cyan(key)}${tag} ${import_chalk22.default.gray(entry.label)}`);
26243
+ console.log(` Tools (${entry.toolCount}): ${import_chalk22.default.white(entry.toolNames.join(", "))}`);
26244
+ console.log(` Hash: ${import_chalk22.default.gray(entry.toolsHash.slice(0, 16))}...`);
26245
+ console.log(` Pinned: ${import_chalk22.default.gray(entry.pinnedAt)}`);
26050
26246
  console.log("");
26051
26247
  }
26052
26248
  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"));
26249
+ console.log(import_chalk22.default.gray(` [repo] entries come from ${found.path}`));
26250
+ console.log(import_chalk22.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
26055
26251
  }
26056
26252
  });
26057
26253
  pinSubCmd.command("promote <serverKey>").description(
@@ -26061,22 +26257,22 @@ function registerMcpPinCommand(program2) {
26061
26257
  const { repoPath, created } = promotePin(serverKey, process.cwd());
26062
26258
  if (created) {
26063
26259
  console.log(
26064
- import_chalk21.default.green(
26260
+ import_chalk22.default.green(
26065
26261
  `
26066
- \u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
26262
+ \u2705 Created ${repoPath} with the promoted pin for ${import_chalk22.default.cyan(serverKey)}.`
26067
26263
  )
26068
26264
  );
26069
26265
  } else {
26070
- console.log(import_chalk21.default.green(`
26071
- \u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
26266
+ console.log(import_chalk22.default.green(`
26267
+ \u2705 Promoted ${import_chalk22.default.cyan(serverKey)} into ${repoPath}.`));
26072
26268
  }
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)"`));
26269
+ console.log(import_chalk22.default.gray(" Review the change and commit it:"));
26270
+ console.log(import_chalk22.default.cyan(` git add ${repoPath}`));
26271
+ console.log(import_chalk22.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
26076
26272
  console.log("");
26077
26273
  } catch (err2) {
26078
26274
  const msg = err2 instanceof Error ? err2.message : String(err2);
26079
- console.error(import_chalk21.default.red(`
26275
+ console.error(import_chalk22.default.red(`
26080
26276
  \u274C ${msg}
26081
26277
  `));
26082
26278
  process.exit(1);
@@ -26089,138 +26285,138 @@ function registerMcpPinCommand(program2) {
26089
26285
  try {
26090
26286
  pins = readMcpPins();
26091
26287
  } 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"));
26288
+ console.error(import_chalk22.default.red("\n\u274C Pin file is corrupt."));
26289
+ console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
26094
26290
  process.exit(1);
26095
26291
  }
26096
26292
  if (!pins.servers[serverKey]) {
26097
- console.error(import_chalk21.default.red(`
26293
+ console.error(import_chalk22.default.red(`
26098
26294
  \u274C No pin found for server key "${serverKey}"
26099
26295
  `));
26100
- console.error(`Run ${import_chalk21.default.cyan("node9 mcp pin list")} to see pinned servers.
26296
+ console.error(`Run ${import_chalk22.default.cyan("node9 mcp pin list")} to see pinned servers.
26101
26297
  `);
26102
26298
  process.exit(1);
26103
26299
  }
26104
26300
  const label2 = pins.servers[serverKey].label;
26105
26301
  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"));
26302
+ console.log(import_chalk22.default.green(`
26303
+ \u{1F513} Pin removed for ${import_chalk22.default.cyan(serverKey)}`));
26304
+ console.log(import_chalk22.default.gray(` Server: ${label2}`));
26305
+ console.log(import_chalk22.default.gray(" Next connection will re-pin with current tool definitions.\n"));
26110
26306
  });
26111
26307
  pinSubCmd.command("reset").description("Clear all MCP pins (next connection to each server will re-pin)").action(() => {
26112
26308
  const result = readMcpPinsSafe();
26113
26309
  if (!result.ok && result.reason === "missing") {
26114
- console.log(import_chalk21.default.gray("\nNo pins to clear.\n"));
26310
+ console.log(import_chalk22.default.gray("\nNo pins to clear.\n"));
26115
26311
  return;
26116
26312
  }
26117
26313
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
26118
26314
  clearAllPins();
26119
- console.log(import_chalk21.default.green(`
26315
+ console.log(import_chalk22.default.green(`
26120
26316
  \u{1F513} Cleared ${count} MCP pin(s).`));
26121
- console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
26317
+ console.log(import_chalk22.default.gray(" Next connection to each server will re-pin.\n"));
26122
26318
  });
26123
26319
  }
26124
26320
 
26125
26321
  // src/cli/commands/sync.ts
26126
- var import_chalk22 = __toESM(require("chalk"));
26322
+ var import_chalk23 = __toESM(require("chalk"));
26127
26323
  init_sync();
26128
26324
  function registerSyncCommand(program2) {
26129
26325
  const policy = program2.command("policy").description("Manage cloud policy rules");
26130
26326
  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"));
26327
+ process.stdout.write(import_chalk23.default.cyan("Pushing policy to the dashboard\u2026"));
26132
26328
  const result = await runPolicyPush();
26133
26329
  process.stdout.write("\n");
26134
26330
  if (!result.ok) {
26135
- console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
26331
+ console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
26136
26332
  process.exit(1);
26137
26333
  }
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"));
26334
+ console.log(import_chalk23.default.green("\u2713 Policy mirrored to the dashboard"));
26335
+ console.log(import_chalk23.default.gray(" See it under Security Policy \u2192 Machines"));
26140
26336
  });
26141
26337
  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"));
26338
+ process.stdout.write(import_chalk23.default.cyan("Syncing cloud policy rules\u2026"));
26143
26339
  const result = await runCloudSync();
26144
26340
  process.stdout.write("\n");
26145
26341
  if (!result.ok) {
26146
- console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
26342
+ console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
26147
26343
  process.exit(1);
26148
26344
  }
26149
26345
  if (result.unchanged) {
26150
26346
  console.log(
26151
- import_chalk22.default.green(
26347
+ import_chalk23.default.green(
26152
26348
  `\u2713 Already up to date \u2014 ${result.rules} rule${result.rules === 1 ? "" : "s"} cached`
26153
26349
  )
26154
26350
  );
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)`));
26351
+ console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
26352
+ console.log(import_chalk23.default.gray(` Server returned 304 (no changes since last sync)`));
26157
26353
  } else {
26158
26354
  console.log(
26159
- import_chalk22.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
26355
+ import_chalk23.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
26160
26356
  );
26161
- console.log(import_chalk22.default.gray(` Cached at: ${result.fetchedAt}`));
26162
- console.log(import_chalk22.default.gray(` File: ~/.node9/rules-cache.json`));
26357
+ console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
26358
+ console.log(import_chalk23.default.gray(` File: ~/.node9/rules-cache.json`));
26163
26359
  }
26164
26360
  });
26165
26361
  policy.command("show").description("List all cloud policy rules in the local cache").action(() => {
26166
26362
  const status = getCloudSyncStatus();
26167
26363
  if (!status.cached) {
26168
- console.log(import_chalk22.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
26364
+ console.log(import_chalk23.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
26169
26365
  return;
26170
26366
  }
26171
26367
  const rules = getCloudRules() ?? [];
26172
26368
  const age = Math.round((Date.now() - new Date(status.fetchedAt).getTime()) / 6e4);
26173
26369
  console.log(
26174
- import_chalk22.default.bold(`
26175
- Cloud policy rules`) + import_chalk22.default.gray(
26370
+ import_chalk23.default.bold(`
26371
+ Cloud policy rules`) + import_chalk23.default.gray(
26176
26372
  ` (${rules.length} rule${rules.length === 1 ? "" : "s"}, synced ${age}m ago)
26177
26373
  `
26178
26374
  )
26179
26375
  );
26180
26376
  if (rules.length === 0) {
26181
- console.log(import_chalk22.default.gray(" No rules defined in cloud policy.\n"));
26377
+ console.log(import_chalk23.default.gray(" No rules defined in cloud policy.\n"));
26182
26378
  return;
26183
26379
  }
26184
26380
  for (const rule of rules) {
26185
26381
  const r = rule;
26186
- const verdictColor = r.verdict === "block" ? import_chalk22.default.red : r.verdict === "allow" ? import_chalk22.default.green : import_chalk22.default.yellow;
26382
+ const verdictColor = r.verdict === "block" ? import_chalk23.default.red : r.verdict === "allow" ? import_chalk23.default.green : import_chalk23.default.yellow;
26187
26383
  console.log(
26188
26384
  ` ${verdictColor(
26189
26385
  String(r.verdict ?? "unknown").toUpperCase().padEnd(6)
26190
- )} ${import_chalk22.default.white(String(r.name ?? "(unnamed)"))}`
26386
+ )} ${import_chalk23.default.white(String(r.name ?? "(unnamed)"))}`
26191
26387
  );
26192
- if (r.reason) console.log(import_chalk22.default.gray(` ${String(r.reason)}`));
26388
+ if (r.reason) console.log(import_chalk23.default.gray(` ${String(r.reason)}`));
26193
26389
  }
26194
26390
  console.log("");
26195
26391
  });
26196
26392
  policy.command("status").description("Show current cloud policy cache status").action(() => {
26197
26393
  const s = getCloudSyncStatus();
26198
26394
  if (!s.cached) {
26199
- console.log(import_chalk22.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
26395
+ console.log(import_chalk23.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
26200
26396
  return;
26201
26397
  }
26202
26398
  const age = Math.round((Date.now() - new Date(s.fetchedAt).getTime()) / 6e4);
26203
26399
  console.log(`
26204
- Rules : ${import_chalk22.default.green(String(s.rules))} cloud rules loaded`);
26400
+ Rules : ${import_chalk23.default.green(String(s.rules))} cloud rules loaded`);
26205
26401
  console.log(
26206
- ` Synced : ${import_chalk22.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
26402
+ ` Synced : ${import_chalk23.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
26207
26403
  );
26208
26404
  if (s.workspaceId) {
26209
- console.log(` Workspace: ${import_chalk22.default.gray(s.workspaceId)}`);
26405
+ console.log(` Workspace: ${import_chalk23.default.gray(s.workspaceId)}`);
26210
26406
  }
26211
26407
  if (s.panicMode) {
26212
26408
  console.log(
26213
- ` ${import_chalk22.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk22.default.dim("(every review-verdict becomes block)")
26409
+ ` ${import_chalk23.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk23.default.dim("(every review-verdict becomes block)")
26214
26410
  );
26215
26411
  }
26216
26412
  if (s.shadowMode) {
26217
26413
  console.log(
26218
- ` ${import_chalk22.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk22.default.dim("(blocks become would-block log entries)")
26414
+ ` ${import_chalk23.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk23.default.dim("(blocks become would-block log entries)")
26219
26415
  );
26220
26416
  }
26221
26417
  if (s.syncIntervalHours) {
26222
26418
  console.log(
26223
- import_chalk22.default.gray(
26419
+ import_chalk23.default.gray(
26224
26420
  ` Polling : every ${s.syncIntervalHours} hour${s.syncIntervalHours === 1 ? "" : "s"}`
26225
26421
  )
26226
26422
  );
@@ -26230,7 +26426,7 @@ function registerSyncCommand(program2) {
26230
26426
  }
26231
26427
 
26232
26428
  // src/cli/commands/agents.ts
26233
- var import_chalk23 = __toESM(require("chalk"));
26429
+ var import_chalk24 = __toESM(require("chalk"));
26234
26430
  init_setup();
26235
26431
  var SETUP_FN = {
26236
26432
  claude: setupClaude,
@@ -26274,30 +26470,30 @@ function registerAgentsCommand(program2) {
26274
26470
  console.log(` ${"Agent".padEnd(14)}${"Installed".padEnd(11)}${"Wired".padEnd(8)}Mode`);
26275
26471
  console.log(" " + "\u2500".repeat(44));
26276
26472
  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}`) : "";
26473
+ const installed = s.installed ? import_chalk24.default.green("\u2713") : import_chalk24.default.gray("\u2717");
26474
+ const wired = !s.installed ? import_chalk24.default.gray("\u2014") : s.wired ? import_chalk24.default.green("\u2713") : import_chalk24.default.yellow("\u2717");
26475
+ const mode = s.mode ? import_chalk24.default.gray(s.mode) : import_chalk24.default.gray("\u2014");
26476
+ const hint = s.installed && !s.wired ? import_chalk24.default.gray(` \u2190 node9 agents add ${s.name}`) : "";
26281
26477
  console.log(` ${s.label.padEnd(14)}${installed} ${wired} ${mode}${hint}`);
26282
26478
  }
26283
26479
  console.log("");
26284
26480
  if (!anyInstalled) {
26285
26481
  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")
26482
+ 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
26483
  );
26288
26484
  return;
26289
26485
  }
26290
26486
  const unwired = statuses.filter((s) => s.installed && !s.wired);
26291
26487
  if (unwired.length > 0) {
26292
26488
  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"
26489
+ import_chalk24.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk24.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
26294
26490
  );
26295
26491
  }
26296
26492
  if (statuses.some((s) => s.name === "gemini" && s.installed)) {
26297
26493
  console.log(
26298
- import_chalk23.default.yellow(
26494
+ import_chalk24.default.yellow(
26299
26495
  " \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"
26496
+ ) + import_chalk24.default.gray(" Migrate to Antigravity: ") + import_chalk24.default.white("node9 agents add antigravity") + "\n"
26301
26497
  );
26302
26498
  }
26303
26499
  });
@@ -26305,7 +26501,7 @@ function registerAgentsCommand(program2) {
26305
26501
  const name = resolveAgentName(agent);
26306
26502
  const fn = SETUP_FN[name];
26307
26503
  if (!fn) {
26308
- console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26504
+ console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26309
26505
  process.exit(1);
26310
26506
  }
26311
26507
  await fn();
@@ -26314,14 +26510,14 @@ function registerAgentsCommand(program2) {
26314
26510
  const name = resolveAgentName(agent);
26315
26511
  const fn = TEARDOWN_FN[name];
26316
26512
  if (!fn) {
26317
- console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26513
+ console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26318
26514
  process.exit(1);
26319
26515
  }
26320
- console.log(import_chalk23.default.cyan(`
26516
+ console.log(import_chalk24.default.cyan(`
26321
26517
  \u{1F6E1}\uFE0F Node9: removing from ${name}...
26322
26518
  `));
26323
26519
  fn();
26324
- console.log(import_chalk23.default.gray("\n Restart the agent for changes to take effect."));
26520
+ console.log(import_chalk24.default.gray("\n Restart the agent for changes to take effect."));
26325
26521
  });
26326
26522
  }
26327
26523
 
@@ -26329,22 +26525,22 @@ function registerAgentsCommand(program2) {
26329
26525
  init_scan();
26330
26526
 
26331
26527
  // src/cli/commands/posture.ts
26332
- var import_chalk25 = __toESM(require("chalk"));
26528
+ var import_chalk26 = __toESM(require("chalk"));
26333
26529
  init_posture();
26334
26530
 
26335
26531
  // src/posture/render.ts
26336
- var import_chalk24 = __toESM(require("chalk"));
26532
+ var import_chalk25 = __toESM(require("chalk"));
26337
26533
  init_score();
26338
26534
  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 ")
26535
+ critical: import_chalk25.default.red("\u274C"),
26536
+ high: import_chalk25.default.red("\u274C"),
26537
+ medium: import_chalk25.default.yellow("\u26A0\uFE0F "),
26538
+ advisory: import_chalk25.default.gray("\u26A0\uFE0F ")
26343
26539
  };
26344
26540
  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")
26541
+ good: import_chalk25.default.green("Good"),
26542
+ "at-risk": import_chalk25.default.yellow("At risk"),
26543
+ critical: import_chalk25.default.red("Critical")
26348
26544
  };
26349
26545
  function wrap(text, width) {
26350
26546
  const out = [];
@@ -26362,35 +26558,35 @@ function wrap(text, width) {
26362
26558
  }
26363
26559
  var LABEL_WIDTH = 14;
26364
26560
  function label(category) {
26365
- return import_chalk24.default.bold(category.padEnd(Math.max(LABEL_WIDTH, category.length + 1)));
26561
+ return import_chalk25.default.bold(category.padEnd(Math.max(LABEL_WIDTH, category.length + 1)));
26366
26562
  }
26367
26563
  function renderFinding(f, showWeight = false) {
26368
26564
  const lines = [];
26369
- const wt = showWeight && f.scoreWeight ? import_chalk24.default.cyan.bold(`+${f.scoreWeight} `) : "";
26565
+ const wt = showWeight && f.scoreWeight ? import_chalk25.default.cyan.bold(`+${f.scoreWeight} `) : "";
26370
26566
  lines.push(` ${ICON[f.severity]} ${label(f.category)}${wt}${f.title}`);
26371
26567
  const indent = " ".repeat(2 + 3 + LABEL_WIDTH);
26372
26568
  const width = 80 - indent.length;
26373
26569
  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));
26570
+ if (s) for (const l of wrap(s, width)) lines.push(indent + import_chalk25.default.gray(l));
26375
26571
  }
26376
- for (const d of f.detail) lines.push(indent + import_chalk24.default.gray(d));
26572
+ for (const d of f.detail) lines.push(indent + import_chalk25.default.gray(d));
26377
26573
  if (f.fix) {
26378
26574
  let first = true;
26379
26575
  for (const seg of f.fix.split("\n")) {
26380
26576
  for (const l of wrap(seg, width - 2)) {
26381
- lines.push(indent + import_chalk24.default.cyan(first ? "\u2192 " + l : " " + l));
26577
+ lines.push(indent + import_chalk25.default.cyan(first ? "\u2192 " + l : " " + l));
26382
26578
  first = false;
26383
26579
  }
26384
26580
  }
26385
26581
  }
26386
26582
  const tradeoff = [
26387
- [f.gain, "gain: ", import_chalk24.default.green],
26388
- [f.cost, "cost: ", import_chalk24.default.yellow]
26583
+ [f.gain, "gain: ", import_chalk25.default.green],
26584
+ [f.cost, "cost: ", import_chalk25.default.yellow]
26389
26585
  ];
26390
26586
  for (const [text, lbl, color2] of tradeoff) {
26391
26587
  if (!text) continue;
26392
26588
  wrap(text, width - 6).forEach((l, i) => {
26393
- lines.push(indent + (i === 0 ? color2(lbl) : " ") + import_chalk24.default.gray(l));
26589
+ lines.push(indent + (i === 0 ? color2(lbl) : " ") + import_chalk25.default.gray(l));
26394
26590
  });
26395
26591
  }
26396
26592
  return lines;
@@ -26400,12 +26596,12 @@ function renderPosture(result) {
26400
26596
  const tier = TIER_LABEL[result.tier];
26401
26597
  lines.push("");
26402
26598
  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})`
26599
+ 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
26600
  );
26405
26601
  const headroom = openHeadroom(result.findings);
26406
26602
  if (headroom > 0) {
26407
26603
  lines.push(
26408
- " " + import_chalk24.default.gray(
26604
+ " " + import_chalk25.default.gray(
26409
26605
  `${headroom} pts of headroom below \u2014 each layer adds security at some cost to flexibility. You choose which to close.`
26410
26606
  )
26411
26607
  );
@@ -26413,21 +26609,21 @@ function renderPosture(result) {
26413
26609
  lines.push("");
26414
26610
  if (result.headline) {
26415
26611
  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));
26612
+ lines.push(` ${import_chalk25.default.red.bold("\u{1F525} Biggest risk")}`);
26613
+ for (const l of wrap(result.headline.risk, 74)) lines.push(indent + import_chalk25.default.white(l));
26418
26614
  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)));
26615
+ action.forEach((l, i) => lines.push(indent + import_chalk25.default.cyan(i === 0 ? "\u2192 " + l : " " + l)));
26420
26616
  lines.push("");
26421
26617
  }
26422
26618
  const covered = result.findings.filter((f) => f.coverage?.state === "covered");
26423
26619
  const open = result.findings.filter((f) => f.coverage?.state !== "covered");
26424
26620
  if (covered.length > 0) {
26425
- lines.push(" " + import_chalk24.default.green("\u{1F7E2} ON NOW \u2014 node9 is enforcing these (your floor)"));
26621
+ lines.push(" " + import_chalk25.default.green("\u{1F7E2} ON NOW \u2014 node9 is enforcing these (your floor)"));
26426
26622
  for (const f of covered) {
26427
26623
  const gated = f.coverage?.level === "review" ? "approval-gating" : "blocking";
26428
26624
  const via = f.coverage?.via ?? "node9";
26429
26625
  lines.push(
26430
- ` ${import_chalk24.default.green("\u2705")} ${label(f.category)}${import_chalk24.default.gray(`${via} is ${gated} this`)}`
26626
+ ` ${import_chalk25.default.green("\u2705")} ${label(f.category)}${import_chalk25.default.gray(`${via} is ${gated} this`)}`
26431
26627
  );
26432
26628
  }
26433
26629
  lines.push("");
@@ -26436,24 +26632,24 @@ function renderPosture(result) {
26436
26632
  const reduceOpen = open.filter((f) => f.owner !== "node9" && f.node9Reduces);
26437
26633
  const osOpen = open.filter((f) => f.owner !== "node9" && !f.node9Reduces);
26438
26634
  if (node9Open.length > 0) {
26439
- lines.push(" " + import_chalk24.default.cyan.bold("\u{1F527} node9 can fix these \u2014 run the command"));
26635
+ lines.push(" " + import_chalk25.default.cyan.bold("\u{1F527} node9 can fix these \u2014 run the command"));
26440
26636
  for (const f of node9Open) lines.push(...renderFinding(f, true));
26441
26637
  }
26442
26638
  if (reduceOpen.length > 0) {
26443
26639
  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)"));
26640
+ lines.push(" " + import_chalk25.default.yellow.bold("\u{1F512} AVAILABLE \u2014 turn on to harden (each has a tradeoff)"));
26445
26641
  for (const f of reduceOpen) lines.push(...renderFinding(f, true));
26446
26642
  }
26447
26643
  if (osOpen.length > 0) {
26448
26644
  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)"));
26645
+ lines.push(" " + import_chalk25.default.bold("\u{1F9F1} YOUR PART \u2014 node9 can't fix these (OS-level)"));
26450
26646
  for (const f of osOpen) lines.push(...renderFinding(f));
26451
26647
  }
26452
26648
  for (const cat of result.passedCategories) {
26453
- lines.push(` ${import_chalk24.default.green("\u2705")} ${label(cat)}${import_chalk24.default.gray("no issues found")}`);
26649
+ lines.push(` ${import_chalk25.default.green("\u2705")} ${label(cat)}${import_chalk25.default.gray("no issues found")}`);
26454
26650
  }
26455
26651
  for (const cat of result.erroredCategories) {
26456
- lines.push(` ${import_chalk24.default.gray("\u2022")} ${label(cat)}${import_chalk24.default.gray("could not be checked")}`);
26652
+ lines.push(` ${import_chalk25.default.gray("\u2022")} ${label(cat)}${import_chalk25.default.gray("could not be checked")}`);
26457
26653
  }
26458
26654
  lines.push("");
26459
26655
  const crit = open.filter((f) => f.severity === "critical").length;
@@ -26461,16 +26657,16 @@ function renderPosture(result) {
26461
26657
  const med = open.filter((f) => f.severity === "medium").length;
26462
26658
  const adv = open.filter((f) => f.severity === "advisory").length;
26463
26659
  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");
26660
+ if (crit) parts.push(import_chalk25.default.red(`${crit} critical`));
26661
+ if (high) parts.push(import_chalk25.default.red(`${high} high`));
26662
+ if (med) parts.push(import_chalk25.default.yellow(`${med} medium`));
26663
+ if (adv) parts.push(import_chalk25.default.gray(`${adv} advisory`));
26664
+ const summary = parts.length ? parts.join(" \xB7 ") : import_chalk25.default.green("no findings");
26469
26665
  lines.push(` ${summary}`);
26470
26666
  lines.push("");
26471
- lines.push(" " + import_chalk24.default.bold("Track this across your fleet & keep it green:"));
26667
+ lines.push(" " + import_chalk25.default.bold("Track this across your fleet & keep it green:"));
26472
26668
  lines.push(
26473
- " " + import_chalk24.default.dim("\u2192 ") + import_chalk24.default.cyan.underline("https://node9.ai/auth/signup?ref=cli_posture")
26669
+ " " + import_chalk25.default.dim("\u2192 ") + import_chalk25.default.cyan.underline("https://node9.ai/auth/signup?ref=cli_posture")
26474
26670
  );
26475
26671
  lines.push("");
26476
26672
  return lines.join("\n");
@@ -26490,11 +26686,11 @@ function registerPostureCommand(program2) {
26490
26686
  if (opts.ship) {
26491
26687
  const creds = readCredentials();
26492
26688
  if (!creds) {
26493
- console.error(import_chalk25.default.gray(" Run `node9 login` to ship this to your dashboard."));
26689
+ console.error(import_chalk26.default.gray(" Run `node9 login` to ship this to your dashboard."));
26494
26690
  } else {
26495
26691
  const ok2 = await shipPosture(result, creds);
26496
26692
  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.")
26693
+ 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
26694
  );
26499
26695
  }
26500
26696
  }
@@ -26503,7 +26699,7 @@ function registerPostureCommand(program2) {
26503
26699
  }
26504
26700
 
26505
26701
  // src/cli/commands/egress.ts
26506
- var import_chalk26 = __toESM(require("chalk"));
26702
+ var import_chalk27 = __toESM(require("chalk"));
26507
26703
  init_config();
26508
26704
  init_dist();
26509
26705
  function guard(fn) {
@@ -26511,7 +26707,7 @@ function guard(fn) {
26511
26707
  fn();
26512
26708
  return true;
26513
26709
  } catch (err2) {
26514
- console.error(import_chalk26.default.red(`
26710
+ console.error(import_chalk27.default.red(`
26515
26711
  \u2717 ${err2.message}
26516
26712
  `));
26517
26713
  process.exitCode = 1;
@@ -26526,19 +26722,19 @@ function addHost(list, host) {
26526
26722
  }
26527
26723
  function showStatus() {
26528
26724
  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"));
26725
+ 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");
26726
+ console.log(import_chalk27.default.cyan.bold("\n\u{1F310} Egress control"));
26531
26727
  console.log(" State: " + state);
26532
26728
  console.log(
26533
- import_chalk26.default.gray(
26729
+ import_chalk27.default.gray(
26534
26730
  ` ${DEFAULT_EGRESS_ALLOWLIST.length} common dev/LLM hosts are always allowed (github, npm, pypi, anthropic, \u2026).`
26535
26731
  )
26536
26732
  );
26537
26733
  if (e.allow.length) console.log(" Your allow: " + e.allow.join(", "));
26538
26734
  if (e.deny.length) console.log(" Your deny: " + e.deny.join(", "));
26539
26735
  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)"));
26736
+ console.log(import_chalk27.default.gray("\n Turn it on: node9 egress watch (prompt on unknown hosts)"));
26737
+ console.log(import_chalk27.default.gray(" node9 egress lock (hard-block unknown hosts)"));
26542
26738
  }
26543
26739
  console.log("");
26544
26740
  }
@@ -26546,43 +26742,43 @@ function registerEgressCommand(program2) {
26546
26742
  const egress = program2.command("egress").description("Control where your agent can send data (egress allowlist)");
26547
26743
  egress.command("watch").description("Prompt before the agent reaches an unknown host (review mode)").action(() => {
26548
26744
  if (!mutate({ enabled: true, mode: "review" })) return;
26549
- console.log(import_chalk26.default.green("\n\u2713 Egress is now watched (review mode)."));
26745
+ console.log(import_chalk27.default.green("\n\u2713 Egress is now watched (review mode)."));
26550
26746
  console.log(
26551
- import_chalk26.default.gray(" Routine hosts (LLM APIs, package registries, localhost) are allowed.")
26747
+ import_chalk27.default.gray(" Routine hosts (LLM APIs, package registries, localhost) are allowed.")
26552
26748
  );
26553
26749
  console.log(
26554
- import_chalk26.default.gray(" An unknown host will prompt you \u2014 run `node9 egress lock` to hard-block.\n")
26750
+ import_chalk27.default.gray(" An unknown host will prompt you \u2014 run `node9 egress lock` to hard-block.\n")
26555
26751
  );
26556
26752
  });
26557
26753
  egress.command("lock").description("Block the agent from reaching unknown hosts (block mode)").action(() => {
26558
26754
  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"));
26755
+ console.log(import_chalk27.default.green("\n\u2713 Egress is now locked (block mode)."));
26756
+ console.log(import_chalk27.default.gray(" Routine hosts are still allowed; unknown hosts are denied."));
26757
+ console.log(import_chalk27.default.gray(" Allow a specific host with `node9 egress allow <host>`.\n"));
26562
26758
  });
26563
26759
  egress.command("allow <host>").description("Allow an extra host (glob, e.g. *.mycorp.com)").action((host) => {
26564
26760
  if (!addHost("allow", host)) return;
26565
- console.log(import_chalk26.default.green(`
26761
+ console.log(import_chalk27.default.green(`
26566
26762
  \u2713 Allowed egress to ${host}.
26567
26763
  `));
26568
26764
  });
26569
26765
  egress.command("deny <host>").description("Block an extra host (deny always wins)").action((host) => {
26570
26766
  if (!addHost("deny", host)) return;
26571
- console.log(import_chalk26.default.green(`
26767
+ console.log(import_chalk27.default.green(`
26572
26768
  \u2713 Denied egress to ${host}.
26573
26769
  `));
26574
26770
  });
26575
26771
  egress.command("off").description("Turn egress control off").action(() => {
26576
26772
  if (!mutate({ enabled: false })) return;
26577
26773
  console.log(
26578
- import_chalk26.default.yellow("\n\u2713 Egress control is off \u2014 the agent can reach any host again.\n")
26774
+ import_chalk27.default.yellow("\n\u2713 Egress control is off \u2014 the agent can reach any host again.\n")
26579
26775
  );
26580
26776
  });
26581
26777
  egress.action(showStatus);
26582
26778
  }
26583
26779
 
26584
26780
  // src/cli/commands/jail.ts
26585
- var import_chalk27 = __toESM(require("chalk"));
26781
+ var import_chalk28 = __toESM(require("chalk"));
26586
26782
 
26587
26783
  // src/shields/jail.ts
26588
26784
  var import_fs55 = __toESM(require("fs"));
@@ -26677,20 +26873,20 @@ function registerJailCommand(program2) {
26677
26873
  regenerateUserJail(paths);
26678
26874
  appendConfigAudit({ event: "jail-add", path: p.trim(), verdict });
26679
26875
  } catch (err2) {
26680
- console.error(import_chalk27.default.red(`
26876
+ console.error(import_chalk28.default.red(`
26681
26877
  \u274C ${err2.message}
26682
26878
  `));
26683
26879
  process.exit(1);
26684
26880
  return;
26685
26881
  }
26686
- console.log(import_chalk27.default.green(`
26882
+ console.log(import_chalk28.default.green(`
26687
26883
  \u2705 Jailed ${p} (${verdict}).`));
26688
26884
  console.log(
26689
- import_chalk27.default.gray(
26885
+ import_chalk28.default.gray(
26690
26886
  ` AI reads of this path now ${verdict === "block" ? "BLOCK" : "require approval"}.`
26691
26887
  )
26692
26888
  );
26693
- console.log(import_chalk27.default.gray(` Preview: ${import_chalk27.default.cyan(`node9 explain bash "cat ${p}"`)}
26889
+ console.log(import_chalk28.default.gray(` Preview: ${import_chalk28.default.cyan(`node9 explain bash "cat ${p}"`)}
26694
26890
  `));
26695
26891
  });
26696
26892
  jail.command("remove <path>").description("Remove a user-added jail path (built-in paths are not removable)").action((p) => {
@@ -26698,17 +26894,17 @@ function registerJailCommand(program2) {
26698
26894
  try {
26699
26895
  result = removeJailPath(p);
26700
26896
  } catch (err2) {
26701
- console.error(import_chalk27.default.red(`
26897
+ console.error(import_chalk28.default.red(`
26702
26898
  \u274C ${err2.message}
26703
26899
  `));
26704
26900
  process.exit(1);
26705
26901
  return;
26706
26902
  }
26707
26903
  if (!result.removed) {
26708
- console.error(import_chalk27.default.yellow(`
26904
+ console.error(import_chalk28.default.yellow(`
26709
26905
  \u2139\uFE0F "${p}" is not a user-added jail path.
26710
26906
  `));
26711
- console.error(import_chalk27.default.gray(` Run ${import_chalk27.default.cyan("node9 jail list")} to see your paths.
26907
+ console.error(import_chalk28.default.gray(` Run ${import_chalk28.default.cyan("node9 jail list")} to see your paths.
26712
26908
  `));
26713
26909
  process.exit(1);
26714
26910
  return;
@@ -26717,39 +26913,39 @@ function registerJailCommand(program2) {
26717
26913
  regenerateUserJail(result.paths);
26718
26914
  appendConfigAudit({ event: "jail-remove", path: p.trim() });
26719
26915
  } catch (err2) {
26720
- console.error(import_chalk27.default.red(`
26916
+ console.error(import_chalk28.default.red(`
26721
26917
  \u274C ${err2.message}
26722
26918
  `));
26723
26919
  process.exit(1);
26724
26920
  return;
26725
26921
  }
26726
- console.log(import_chalk27.default.green(`
26922
+ console.log(import_chalk28.default.green(`
26727
26923
  \u2705 Removed ${p} from the jail.
26728
26924
  `));
26729
26925
  });
26730
26926
  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}`);
26927
+ console.log(import_chalk28.default.bold("\n\u{1F512} Credential Jail\n"));
26928
+ console.log(import_chalk28.default.gray(" Built-in (always on, not removable):"));
26929
+ for (const b of BUILTIN_JAIL) console.log(` ${import_chalk28.default.gray("\u2022")} ${b}`);
26734
26930
  console.log("");
26735
26931
  let user;
26736
26932
  try {
26737
26933
  user = readJailPaths();
26738
26934
  } catch (err2) {
26739
- console.error(import_chalk27.default.red(` \u2717 ${err2.message}
26935
+ console.error(import_chalk28.default.red(` \u2717 ${err2.message}
26740
26936
  `));
26741
26937
  process.exit(1);
26742
26938
  return;
26743
26939
  }
26744
26940
  if (user.length === 0) {
26745
26941
  console.log(
26746
- import_chalk27.default.gray(" Your paths: (none) \u2014 add one with ") + import_chalk27.default.cyan("node9 jail add <path>")
26942
+ import_chalk28.default.gray(" Your paths: (none) \u2014 add one with ") + import_chalk28.default.cyan("node9 jail add <path>")
26747
26943
  );
26748
26944
  } else {
26749
- console.log(import_chalk27.default.gray(" Your paths (removable):"));
26945
+ console.log(import_chalk28.default.gray(" Your paths (removable):"));
26750
26946
  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)}`);
26947
+ const v = u.verdict === "block" ? import_chalk28.default.red("block ") : import_chalk28.default.yellow("review");
26948
+ console.log(` ${v} ${import_chalk28.default.cyan(u.path)}`);
26753
26949
  }
26754
26950
  }
26755
26951
  console.log("");
@@ -26757,7 +26953,7 @@ function registerJailCommand(program2) {
26757
26953
  }
26758
26954
 
26759
26955
  // src/cli/commands/sandbox.ts
26760
- var import_chalk28 = __toESM(require("chalk"));
26956
+ var import_chalk29 = __toESM(require("chalk"));
26761
26957
  var import_fs58 = __toESM(require("fs"));
26762
26958
  var import_path56 = __toESM(require("path"));
26763
26959
  var import_child_process13 = require("child_process");
@@ -26995,16 +27191,16 @@ function registerSandboxCommand(program2, version2) {
26995
27191
  const p = sandboxConfigPath();
26996
27192
  if (import_fs58.default.existsSync(p)) {
26997
27193
  console.log(
26998
- import_chalk28.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
27194
+ import_chalk29.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
26999
27195
  );
27000
27196
  return;
27001
27197
  }
27002
27198
  import_fs58.default.writeFileSync(p, scaffoldSandboxYaml(agent));
27003
27199
  console.log(
27004
- import_chalk28.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk28.default.dim(` (agent: ${agent})`)
27200
+ import_chalk29.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk29.default.dim(` (agent: ${agent})`)
27005
27201
  );
27006
27202
  console.log(
27007
- import_chalk28.default.dim(" Edit it (mounts / allow / expose), then: ") + import_chalk28.default.cyan("node9 sandbox run")
27203
+ import_chalk29.default.dim(" Edit it (mounts / allow / expose), then: ") + import_chalk29.default.cyan("node9 sandbox run")
27008
27204
  );
27009
27205
  });
27010
27206
  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 +27210,7 @@ function registerSandboxCommand(program2, version2) {
27014
27210
  const engine = detectEngine(sandbox.runtime.engine);
27015
27211
  if (!engine.available) {
27016
27212
  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.`)
27213
+ import_chalk29.default.red(` ${sandbox.runtime.engine} not found.`) + import_chalk29.default.dim(` Install it first \u2014 node9 sandbox needs a container runtime.`)
27018
27214
  );
27019
27215
  process.exit(1);
27020
27216
  }
@@ -27027,11 +27223,11 @@ function registerSandboxCommand(program2, version2) {
27027
27223
  });
27028
27224
  if (compiled.rejected.length) {
27029
27225
  console.log(
27030
- import_chalk28.default.yellow(` \u26A0 ignoring invalid allow hosts: ${compiled.rejected.join(", ")}`)
27226
+ import_chalk29.default.yellow(` \u26A0 ignoring invalid allow hosts: ${compiled.rejected.join(", ")}`)
27031
27227
  );
27032
27228
  }
27033
27229
  if (compiled.denied.length) {
27034
- console.log(import_chalk28.default.dim(` (denied: ${compiled.denied.join(", ")})`));
27230
+ console.log(import_chalk29.default.dim(` (denied: ${compiled.denied.join(", ")})`));
27035
27231
  }
27036
27232
  const allowlistPath = writeAllowlist(cwd, compiled.allow);
27037
27233
  const dockerfile = renderDockerfile(sandbox, node9Version2);
@@ -27044,12 +27240,12 @@ function registerSandboxCommand(program2, version2) {
27044
27240
  const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
27045
27241
  const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
27046
27242
  if (needBuild) {
27047
- console.log(import_chalk28.default.dim(` building ${image} \u2026`));
27243
+ console.log(import_chalk29.default.dim(` building ${image} \u2026`));
27048
27244
  const b = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["build", "-t", image, buildDir], {
27049
27245
  stdio: "inherit"
27050
27246
  });
27051
27247
  if (b.status !== 0) {
27052
- console.error(import_chalk28.default.red(" build failed."));
27248
+ console.error(import_chalk29.default.red(" build failed."));
27053
27249
  process.exit(b.status ?? 1);
27054
27250
  }
27055
27251
  import_fs58.default.writeFileSync(hashFile, hash);
@@ -27067,15 +27263,15 @@ function registerSandboxCommand(program2, version2) {
27067
27263
  if (sandbox.node9.mountAgentCredentials) {
27068
27264
  const creds = agentCredentialsMount(sandbox.agent);
27069
27265
  if (import_fs58.default.existsSync(creds.hostPath)) {
27070
- console.log(import_chalk28.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
27266
+ console.log(import_chalk29.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
27071
27267
  } else {
27072
27268
  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.`)
27269
+ 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
27270
  );
27075
27271
  }
27076
27272
  }
27077
27273
  console.log(
27078
- import_chalk28.default.green(` \u{1F6E1}\uFE0F ${sandbox.agent} jailed \u2014 ${compiled.allow.length} hosts allowed
27274
+ import_chalk29.default.green(` \u{1F6E1}\uFE0F ${sandbox.agent} jailed \u2014 ${compiled.allow.length} hosts allowed
27079
27275
  `)
27080
27276
  );
27081
27277
  const r = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, runArgs, { stdio: "inherit" });
@@ -27084,7 +27280,7 @@ function registerSandboxCommand(program2, version2) {
27084
27280
  cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
27085
27281
  const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
27086
27282
  if (!import_fs58.default.existsSync(auditPath)) {
27087
- console.log(import_chalk28.default.dim(" no sandbox audit yet."));
27283
+ console.log(import_chalk29.default.dim(" no sandbox audit yet."));
27088
27284
  return;
27089
27285
  }
27090
27286
  (0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
@@ -27092,7 +27288,7 @@ function registerSandboxCommand(program2, version2) {
27092
27288
  cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
27093
27289
  const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
27094
27290
  if (!import_fs58.default.existsSync(auditPath)) {
27095
- console.log(import_chalk28.default.dim(" no sandbox audit yet."));
27291
+ console.log(import_chalk29.default.dim(" no sandbox audit yet."));
27096
27292
  return;
27097
27293
  }
27098
27294
  process.stdout.write(import_fs58.default.readFileSync(auditPath, "utf-8"));
@@ -27110,12 +27306,12 @@ function registerSandboxCommand(program2, version2) {
27110
27306
  });
27111
27307
  }
27112
27308
  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."));
27309
+ console.log(import_chalk29.default.green(" \u2713 sandbox image + build + data removed."));
27114
27310
  });
27115
27311
  }
27116
27312
 
27117
27313
  // src/cli/commands/sessions.ts
27118
- var import_chalk29 = __toESM(require("chalk"));
27314
+ var import_chalk30 = __toESM(require("chalk"));
27119
27315
  var import_fs59 = __toESM(require("fs"));
27120
27316
  var import_path57 = __toESM(require("path"));
27121
27317
  var import_os50 = __toESM(require("os"));
@@ -27611,11 +27807,11 @@ function toolInputSummary(tool, input) {
27611
27807
  }
27612
27808
  function toolColor(tool) {
27613
27809
  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;
27810
+ if (t === "bash" || t === "execute_bash") return import_chalk30.default.red;
27811
+ if (t === "write") return import_chalk30.default.green;
27812
+ if (t === "edit" || t === "notebookedit") return import_chalk30.default.yellow;
27813
+ if (t === "read") return import_chalk30.default.cyan;
27814
+ return import_chalk30.default.gray;
27619
27815
  }
27620
27816
  function barStr2(value, max, width) {
27621
27817
  if (max === 0 || width <= 0) return "\u2591".repeat(width);
@@ -27625,7 +27821,7 @@ function barStr2(value, max, width) {
27625
27821
  function colorBar2(value, max, width) {
27626
27822
  const s = barStr2(value, max, width);
27627
27823
  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));
27824
+ return import_chalk30.default.cyan(s.slice(0, filled)) + import_chalk30.default.dim(s.slice(filled));
27629
27825
  }
27630
27826
  function renderSummary(summaries) {
27631
27827
  const totalTools = summaries.reduce((n, s) => n + s.toolCalls.length, 0);
@@ -27655,45 +27851,45 @@ function renderSummary(summaries) {
27655
27851
  }
27656
27852
  const topProjects = [...projCosts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
27657
27853
  const W = 20;
27658
- console.log(import_chalk29.default.dim(" " + "\u2500".repeat(70)));
27854
+ console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
27659
27855
  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") : "")
27856
+ " " + 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
27857
  );
27662
27858
  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`)
27859
+ " " + 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
27860
  );
27665
27861
  console.log("");
27666
- console.log(" " + import_chalk29.default.dim("Tool breakdown:"));
27862
+ console.log(" " + import_chalk30.default.dim("Tool breakdown:"));
27667
27863
  const maxGroup = Math.max(...Object.values(groups));
27668
27864
  for (const [label2, count] of Object.entries(groups)) {
27669
27865
  if (count === 0) continue;
27670
27866
  const pct = totalTools > 0 ? Math.round(count / totalTools * 100) : 0;
27671
27867
  console.log(
27672
- " " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk29.default.white(String(count).padStart(4)) + import_chalk29.default.dim(` (${String(pct)}%)`)
27868
+ " " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk30.default.white(String(count).padStart(4)) + import_chalk30.default.dim(` (${String(pct)}%)`)
27673
27869
  );
27674
27870
  }
27675
27871
  console.log("");
27676
27872
  if (topProjects.length > 1) {
27677
- console.log(" " + import_chalk29.default.dim("Cost by project:"));
27873
+ console.log(" " + import_chalk30.default.dim("Cost by project:"));
27678
27874
  const maxProjCost = topProjects[0][1];
27679
27875
  for (const [proj, cost] of topProjects) {
27680
27876
  console.log(
27681
- " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk29.default.yellow(fmtCost3(cost))
27877
+ " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk30.default.yellow(fmtCost3(cost))
27682
27878
  );
27683
27879
  }
27684
27880
  console.log("");
27685
27881
  }
27686
- console.log(import_chalk29.default.dim(" " + "\u2500".repeat(70)));
27882
+ console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
27687
27883
  console.log("");
27688
27884
  }
27689
27885
  function renderList(summaries, totalCost) {
27690
27886
  if (summaries.length === 0) {
27691
- console.log(import_chalk29.default.yellow(" No sessions found in the requested range.\n"));
27887
+ console.log(import_chalk30.default.yellow(" No sessions found in the requested range.\n"));
27692
27888
  return;
27693
27889
  }
27694
- const totalLabel = totalCost > 0 ? import_chalk29.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
27890
+ const totalLabel = totalCost > 0 ? import_chalk30.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
27695
27891
  console.log(
27696
- " " + import_chalk29.default.white(String(summaries.length)) + import_chalk29.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
27892
+ " " + import_chalk30.default.white(String(summaries.length)) + import_chalk30.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
27697
27893
  );
27698
27894
  console.log("");
27699
27895
  let lastGroup = "";
@@ -27701,51 +27897,51 @@ function renderList(summaries, totalCost) {
27701
27897
  const activeDate = fmtDate2(s.lastActiveTime);
27702
27898
  const group = activeDate + " " + s.projectLabel;
27703
27899
  if (group !== lastGroup) {
27704
- console.log(import_chalk29.default.dim(" \u2500\u2500\u2500 ") + import_chalk29.default.bold(activeDate) + import_chalk29.default.dim(" " + s.projectLabel));
27900
+ console.log(import_chalk30.default.dim(" \u2500\u2500\u2500 ") + import_chalk30.default.bold(activeDate) + import_chalk30.default.dim(" " + s.projectLabel));
27705
27901
  lastGroup = group;
27706
27902
  }
27707
27903
  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")](
27904
+ const dateRange = startDate !== activeDate ? import_chalk30.default.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
27905
+ const timeStr = import_chalk30.default.dim(fmtTime(s.startTime));
27906
+ const prompt = import_chalk30.default.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
27907
+ const tools = s.toolCalls.length > 0 ? import_chalk30.default.dim(String(s.toolCalls.length).padStart(3) + " tools") : import_chalk30.default.dim(" 0 tools");
27908
+ const cost = s.costUSD > 0 ? import_chalk30.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
27909
+ const blocked = s.blockedCalls.length > 0 ? import_chalk30.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
27910
+ const snap = s.hasSnapshot ? import_chalk30.default.green(" \u{1F4F8}") : "";
27911
+ const agentBadge = import_chalk30.default[agentColorName(s.agent ?? "claude")](
27716
27912
  " " + agentBadgeText(s.agent ?? "claude", 0)
27717
27913
  );
27718
- const sid = import_chalk29.default.dim(" " + s.sessionId.slice(0, 8));
27914
+ const sid = import_chalk30.default.dim(" " + s.sessionId.slice(0, 8));
27719
27915
  console.log(
27720
27916
  ` ${timeStr} ${prompt} ${tools}${cost}${blocked}${snap}${agentBadge}${sid}${dateRange}`
27721
27917
  );
27722
27918
  }
27723
27919
  console.log("");
27724
27920
  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.")
27921
+ import_chalk30.default.dim(" Run") + " " + import_chalk30.default.cyan("node9 sessions --detail <session-id>") + import_chalk30.default.dim(" for full tool trace.")
27726
27922
  );
27727
27923
  console.log("");
27728
27924
  }
27729
27925
  function renderDetail(s) {
27730
27926
  console.log("");
27731
- console.log(import_chalk29.default.bold(" Session ") + import_chalk29.default.dim(s.sessionId));
27927
+ console.log(import_chalk30.default.bold(" Session ") + import_chalk30.default.dim(s.sessionId));
27732
27928
  console.log(
27733
- import_chalk29.default.bold(" Prompt ") + import_chalk29.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
27929
+ import_chalk30.default.bold(" Prompt ") + import_chalk30.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
27734
27930
  );
27735
- console.log(import_chalk29.default.bold(" Project ") + import_chalk29.default.white(s.projectLabel));
27931
+ console.log(import_chalk30.default.bold(" Project ") + import_chalk30.default.white(s.projectLabel));
27736
27932
  if (s.agent) {
27737
- const agentLabel2 = import_chalk29.default[agentColorName(s.agent)](agentDisplayName(s.agent));
27738
- console.log(import_chalk29.default.bold(" Agent ") + agentLabel2);
27933
+ const agentLabel2 = import_chalk30.default[agentColorName(s.agent)](agentDisplayName(s.agent));
27934
+ console.log(import_chalk30.default.bold(" Agent ") + agentLabel2);
27739
27935
  }
27740
- console.log(import_chalk29.default.bold(" When ") + import_chalk29.default.white(fmtDateTime(s.startTime)));
27936
+ console.log(import_chalk30.default.bold(" When ") + import_chalk30.default.white(fmtDateTime(s.startTime)));
27741
27937
  if (s.costUSD > 0)
27742
- console.log(import_chalk29.default.bold(" Cost ") + import_chalk29.default.yellow("~" + fmtCost3(s.costUSD)));
27938
+ console.log(import_chalk30.default.bold(" Cost ") + import_chalk30.default.yellow("~" + fmtCost3(s.costUSD)));
27743
27939
  console.log(
27744
- import_chalk29.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk29.default.green("\u2713 taken") : import_chalk29.default.dim("none"))
27940
+ import_chalk30.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk30.default.green("\u2713 taken") : import_chalk30.default.dim("none"))
27745
27941
  );
27746
27942
  console.log("");
27747
27943
  if (s.toolCalls.length === 0 && s.blockedCalls.length === 0) {
27748
- console.log(import_chalk29.default.dim(" No tool calls recorded.\n"));
27944
+ console.log(import_chalk30.default.dim(" No tool calls recorded.\n"));
27749
27945
  return;
27750
27946
  }
27751
27947
  const timeline = [
@@ -27758,32 +27954,32 @@ function renderDetail(s) {
27758
27954
  });
27759
27955
  const headerParts = [`Tool calls (${s.toolCalls.length})`];
27760
27956
  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 ")));
27957
+ headerParts.push(import_chalk30.default.red(`${s.blockedCalls.length} blocked by node9`));
27958
+ console.log(import_chalk30.default.bold(" " + headerParts.join(" \xB7 ")));
27763
27959
  console.log("");
27764
27960
  for (const entry of timeline) {
27765
27961
  if (entry.kind === "tool") {
27766
27962
  const tc = entry.tc;
27767
27963
  const colorFn = toolColor(tc.tool);
27768
27964
  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) + " ") : " ";
27965
+ const detail = import_chalk30.default.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
27966
+ const ts = tc.timestamp ? import_chalk30.default.dim(fmtTime(tc.timestamp) + " ") : " ";
27771
27967
  console.log(` ${ts}${toolPad} ${detail}`);
27772
27968
  } else {
27773
27969
  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) : "";
27970
+ const ts = bc.timestamp ? import_chalk30.default.dim(fmtTime(bc.timestamp) + " ") : " ";
27971
+ const label2 = import_chalk30.default.red("\u{1F6D1} BLOCKED".padEnd(16));
27972
+ const toolName = import_chalk30.default.red(bc.tool.padEnd(10));
27973
+ const argsSummary = bc.args ? import_chalk30.default.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : import_chalk30.default.dim("[args not logged]");
27974
+ const reason = bc.checkedBy ? import_chalk30.default.dim(" \u2190 " + bc.checkedBy) : "";
27779
27975
  console.log(` ${ts}${label2} ${toolName} ${argsSummary}${reason}`);
27780
27976
  }
27781
27977
  }
27782
27978
  console.log("");
27783
27979
  if (s.modifiedFiles.length > 0) {
27784
- console.log(import_chalk29.default.bold(` Files modified (${s.modifiedFiles.length}):`));
27980
+ console.log(import_chalk30.default.bold(` Files modified (${s.modifiedFiles.length}):`));
27785
27981
  for (const f of s.modifiedFiles) {
27786
- console.log(" " + import_chalk29.default.yellow(f));
27982
+ console.log(" " + import_chalk30.default.yellow(f));
27787
27983
  }
27788
27984
  console.log("");
27789
27985
  }
@@ -27791,13 +27987,13 @@ function renderDetail(s) {
27791
27987
  function registerSessionsCommand(program2) {
27792
27988
  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
27989
  console.log("");
27794
- console.log(import_chalk29.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk29.default.dim(" \u2014 what your AI agent did"));
27990
+ console.log(import_chalk30.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk30.default.dim(" \u2014 what your AI agent did"));
27795
27991
  console.log("");
27796
27992
  const days = options.detail || options.all ? null : Math.max(1, parseInt(options.days, 10) || 7);
27797
27993
  const rangeLabel = options.detail ? "all time" : options.all ? "all time" : `last ${String(days)} days`;
27798
- console.log(import_chalk29.default.dim(" " + rangeLabel));
27994
+ console.log(import_chalk30.default.dim(" " + rangeLabel));
27799
27995
  console.log("");
27800
- process.stdout.write(import_chalk29.default.dim(" Loading\u2026"));
27996
+ process.stdout.write(import_chalk30.default.dim(" Loading\u2026"));
27801
27997
  const summaries = buildSessions(days);
27802
27998
  if (process.stdout.isTTY) {
27803
27999
  process.stdout.clearLine(0);
@@ -27810,8 +28006,8 @@ function registerSessionsCommand(program2) {
27810
28006
  (s) => s.sessionId === options.detail || s.sessionId.startsWith(options.detail)
27811
28007
  );
27812
28008
  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"));
28009
+ console.log(import_chalk30.default.red(` Session not found: ${options.detail}`));
28010
+ console.log(import_chalk30.default.dim(" Run `node9 sessions` to list recent sessions.\n"));
27815
28011
  return;
27816
28012
  }
27817
28013
  renderDetail(target);
@@ -27824,7 +28020,7 @@ function registerSessionsCommand(program2) {
27824
28020
  }
27825
28021
 
27826
28022
  // src/cli/commands/session-taint.ts
27827
- var import_chalk30 = __toESM(require("chalk"));
28023
+ var import_chalk31 = __toESM(require("chalk"));
27828
28024
  init_daemon();
27829
28025
  function resolveSessionId(records, query) {
27830
28026
  const exact = records.find((r) => r.sessionId === query);
@@ -27851,22 +28047,22 @@ function registerSessionTaintCommand(program2) {
27851
28047
  const records = await listSessionTaints();
27852
28048
  console.log("");
27853
28049
  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");
28050
+ console.log(import_chalk31.default.dim(" No tainted sessions."));
28051
+ console.log(import_chalk31.default.dim(" (Taint lives in the daemon \u2014 a stopped daemon has none.)") + "\n");
27856
28052
  return;
27857
28053
  }
27858
28054
  console.log(
27859
- " " + import_chalk30.default.bold(String(records.length)) + import_chalk30.default.dim(` tainted session${records.length !== 1 ? "s" : ""}`)
28055
+ " " + import_chalk31.default.bold(String(records.length)) + import_chalk31.default.dim(` tainted session${records.length !== 1 ? "s" : ""}`)
27860
28056
  );
27861
28057
  console.log("");
27862
28058
  for (const r of records) {
27863
28059
  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))
28060
+ " " + 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
28061
  );
27866
28062
  }
27867
28063
  console.log("");
27868
28064
  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"
28065
+ 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
28066
  );
27871
28067
  });
27872
28068
  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 +28070,32 @@ function registerSessionTaintCommand(program2) {
27874
28070
  if (opts.all) {
27875
28071
  const res2 = await clearSessionTaint({ all: true });
27876
28072
  if (res2.daemonUnavailable) {
27877
- console.log(import_chalk30.default.dim(" node9 daemon not running \u2014 no active taints to clear.") + "\n");
28073
+ console.log(import_chalk31.default.dim(" node9 daemon not running \u2014 no active taints to clear.") + "\n");
27878
28074
  return;
27879
28075
  }
27880
28076
  console.log(
27881
- import_chalk30.default.green(" \u2713 ") + `Cleared ${import_chalk30.default.bold(String(res2.cleared))} session taint${res2.cleared !== 1 ? "s" : ""}.
28077
+ import_chalk31.default.green(" \u2713 ") + `Cleared ${import_chalk31.default.bold(String(res2.cleared))} session taint${res2.cleared !== 1 ? "s" : ""}.
27882
28078
  `
27883
28079
  );
27884
28080
  return;
27885
28081
  }
27886
28082
  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");
28083
+ console.log(import_chalk31.default.red(" Provide a session id or --all."));
28084
+ console.log(import_chalk31.default.dim(" Run `node9 session-taint list` to see tainted sessions.") + "\n");
27889
28085
  return;
27890
28086
  }
27891
28087
  const records = await listSessionTaints();
27892
28088
  if (records.length === 0) {
27893
- console.log(import_chalk30.default.dim(" No tainted sessions \u2014 nothing to clear.") + "\n");
28089
+ console.log(import_chalk31.default.dim(" No tainted sessions \u2014 nothing to clear.") + "\n");
27894
28090
  return;
27895
28091
  }
27896
28092
  const resolved = resolveSessionId(records, sessionId);
27897
28093
  if ("error" in resolved) {
27898
28094
  if (resolved.error === "not-found") {
27899
- console.log(import_chalk30.default.red(` No tainted session matches "${sessionId}".`));
28095
+ console.log(import_chalk31.default.red(` No tainted session matches "${sessionId}".`));
27900
28096
  } 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));
28097
+ console.log(import_chalk31.default.red(` "${sessionId}" is ambiguous \u2014 matches:`));
28098
+ for (const m of resolved.matches) console.log(import_chalk31.default.dim(" " + m));
27903
28099
  }
27904
28100
  console.log("");
27905
28101
  return;
@@ -27907,18 +28103,18 @@ function registerSessionTaintCommand(program2) {
27907
28103
  const res = await clearSessionTaint({ sessionId: resolved.record.sessionId });
27908
28104
  if (res.cleared > 0) {
27909
28105
  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"
28106
+ 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
28107
  );
27912
28108
  } else {
27913
28109
  console.log(
27914
- import_chalk30.default.dim(` Session ${resolved.record.sessionId.slice(0, 8)} was already clear.`) + "\n"
28110
+ import_chalk31.default.dim(` Session ${resolved.record.sessionId.slice(0, 8)} was already clear.`) + "\n"
27915
28111
  );
27916
28112
  }
27917
28113
  });
27918
28114
  }
27919
28115
 
27920
28116
  // src/cli/commands/skill-pin.ts
27921
- var import_chalk31 = __toESM(require("chalk"));
28117
+ var import_chalk32 = __toESM(require("chalk"));
27922
28118
  var import_fs60 = __toESM(require("fs"));
27923
28119
  var import_os51 = __toESM(require("os"));
27924
28120
  var import_path58 = __toESM(require("path"));
@@ -27938,29 +28134,29 @@ function registerSkillPinCommand(program2) {
27938
28134
  const result = readSkillPinsSafe();
27939
28135
  if (!result.ok) {
27940
28136
  if (result.reason === "missing") {
27941
- console.log(import_chalk31.default.gray("\nNo skill roots are pinned yet."));
28137
+ console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet."));
27942
28138
  console.log(
27943
- import_chalk31.default.gray("Pins are created automatically on the first tool call of each session.\n")
28139
+ import_chalk32.default.gray("Pins are created automatically on the first tool call of each session.\n")
27944
28140
  );
27945
28141
  return;
27946
28142
  }
27947
- console.error(import_chalk31.default.red(`
28143
+ console.error(import_chalk32.default.red(`
27948
28144
  \u274C Pin file is corrupt: ${result.detail}`));
27949
- console.error(import_chalk31.default.yellow(" Run: node9 skill pin reset\n"));
28145
+ console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
27950
28146
  process.exit(1);
27951
28147
  }
27952
28148
  const entries = Object.entries(result.pins.roots);
27953
28149
  if (entries.length === 0) {
27954
- console.log(import_chalk31.default.gray("\nNo skill roots are pinned yet.\n"));
28150
+ console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet.\n"));
27955
28151
  return;
27956
28152
  }
27957
- console.log(import_chalk31.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
28153
+ console.log(import_chalk32.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
27958
28154
  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}`);
28155
+ const missing = entry.exists ? "" : import_chalk32.default.yellow(" (not present at pin time)");
28156
+ console.log(` ${import_chalk32.default.cyan(key)} ${import_chalk32.default.gray(entry.rootPath)}${missing}`);
27961
28157
  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)}
28158
+ console.log(` Hash: ${import_chalk32.default.gray(entry.contentHash.slice(0, 16))}...`);
28159
+ console.log(` Pinned: ${import_chalk32.default.gray(entry.pinnedAt)}
27964
28160
  `);
27965
28161
  }
27966
28162
  });
@@ -27969,39 +28165,39 @@ function registerSkillPinCommand(program2) {
27969
28165
  try {
27970
28166
  pins = readSkillPins();
27971
28167
  } 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"));
28168
+ console.error(import_chalk32.default.red("\n\u274C Pin file is corrupt."));
28169
+ console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
27974
28170
  process.exit(1);
27975
28171
  }
27976
28172
  if (!pins.roots[rootKey]) {
27977
- console.error(import_chalk31.default.red(`
28173
+ console.error(import_chalk32.default.red(`
27978
28174
  \u274C No pin found for root key "${rootKey}"
27979
28175
  `));
27980
- console.error(`Run ${import_chalk31.default.cyan("node9 skill pin list")} to see pinned roots.
28176
+ console.error(`Run ${import_chalk32.default.cyan("node9 skill pin list")} to see pinned roots.
27981
28177
  `);
27982
28178
  process.exit(1);
27983
28179
  }
27984
28180
  const rootPath = pins.roots[rootKey].rootPath;
27985
28181
  removePin2(rootKey);
27986
28182
  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"));
28183
+ console.log(import_chalk32.default.green(`
28184
+ \u{1F513} Pin removed for ${import_chalk32.default.cyan(rootKey)}`));
28185
+ console.log(import_chalk32.default.gray(` ${rootPath}`));
28186
+ console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
27991
28187
  });
27992
28188
  pinSubCmd.command("reset").description("Clear all skill pins and wipe session verification flags").action(() => {
27993
28189
  const result = readSkillPinsSafe();
27994
28190
  if (!result.ok && result.reason === "missing") {
27995
28191
  wipeSkillSessions();
27996
- console.log(import_chalk31.default.gray("\nNo pins to clear.\n"));
28192
+ console.log(import_chalk32.default.gray("\nNo pins to clear.\n"));
27997
28193
  return;
27998
28194
  }
27999
28195
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
28000
28196
  clearAllPins2();
28001
28197
  wipeSkillSessions();
28002
- console.log(import_chalk31.default.green(`
28198
+ console.log(import_chalk32.default.green(`
28003
28199
  \u{1F513} Cleared ${count} skill pin(s).`));
28004
- console.log(import_chalk31.default.gray(" Next session will re-pin with current state.\n"));
28200
+ console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
28005
28201
  });
28006
28202
  }
28007
28203
 
@@ -28009,7 +28205,7 @@ function registerSkillPinCommand(program2) {
28009
28205
  var import_fs61 = __toESM(require("fs"));
28010
28206
  var import_os52 = __toESM(require("os"));
28011
28207
  var import_path59 = __toESM(require("path"));
28012
- var import_chalk32 = __toESM(require("chalk"));
28208
+ var import_chalk33 = __toESM(require("chalk"));
28013
28209
  var DECISIONS_FILE2 = import_path59.default.join(import_os52.default.homedir(), ".node9", "decisions.json");
28014
28210
  function readDecisions() {
28015
28211
  try {
@@ -28038,55 +28234,55 @@ function registerDecisionsCommand(program2) {
28038
28234
  const decisions = readDecisions();
28039
28235
  const entries = Object.entries(decisions);
28040
28236
  if (entries.length === 0) {
28041
- console.log(import_chalk32.default.gray(" No persistent decisions stored."));
28237
+ console.log(import_chalk33.default.gray(" No persistent decisions stored."));
28042
28238
  console.log(
28043
- import_chalk32.default.gray(` File: ${DECISIONS_FILE2}
28044
- `) + import_chalk32.default.gray(' Decisions are written when you click "Always Allow" or')
28239
+ import_chalk33.default.gray(` File: ${DECISIONS_FILE2}
28240
+ `) + import_chalk33.default.gray(' Decisions are written when you click "Always Allow" or')
28045
28241
  );
28046
- console.log(import_chalk32.default.gray(' "Always Deny" in node9 tail or the native popup.'));
28242
+ console.log(import_chalk33.default.gray(' "Always Deny" in node9 tail or the native popup.'));
28047
28243
  return;
28048
28244
  }
28049
- console.log(import_chalk32.default.bold(`
28245
+ console.log(import_chalk33.default.bold(`
28050
28246
  Persistent decisions (${entries.length})
28051
28247
  `));
28052
28248
  const w = Math.max(...entries.map(([k]) => k.length));
28053
28249
  for (const [tool, verdict] of entries.sort()) {
28054
- const colored = verdict === "allow" ? import_chalk32.default.green(verdict) : import_chalk32.default.red(verdict);
28250
+ const colored = verdict === "allow" ? import_chalk33.default.green(verdict) : import_chalk33.default.red(verdict);
28055
28251
  console.log(` ${tool.padEnd(w)} ${colored}`);
28056
28252
  }
28057
28253
  console.log(
28058
- import_chalk32.default.gray(`
28254
+ import_chalk33.default.gray(`
28059
28255
  Stored in ${DECISIONS_FILE2}
28060
- `) + import_chalk32.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
28256
+ `) + import_chalk33.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
28061
28257
  );
28062
28258
  });
28063
28259
  cmd.command("clear <toolName>").description("Remove a persistent decision for one tool").action((toolName) => {
28064
28260
  const decisions = readDecisions();
28065
28261
  if (!(toolName in decisions)) {
28066
- console.log(import_chalk32.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
28262
+ console.log(import_chalk33.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
28067
28263
  process.exitCode = 1;
28068
28264
  return;
28069
28265
  }
28070
28266
  delete decisions[toolName];
28071
28267
  writeDecisions(decisions);
28072
- console.log(import_chalk32.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
28268
+ console.log(import_chalk33.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
28073
28269
  });
28074
28270
  cmd.command("clear-all").description("Remove every persistent decision (irreversible)").action(() => {
28075
28271
  const decisions = readDecisions();
28076
28272
  const count = Object.keys(decisions).length;
28077
28273
  if (count === 0) {
28078
- console.log(import_chalk32.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
28274
+ console.log(import_chalk33.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
28079
28275
  return;
28080
28276
  }
28081
28277
  writeDecisions({});
28082
28278
  console.log(
28083
- import_chalk32.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
28279
+ import_chalk33.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
28084
28280
  );
28085
28281
  });
28086
28282
  }
28087
28283
 
28088
28284
  // src/cli/commands/dlp.ts
28089
- var import_chalk33 = __toESM(require("chalk"));
28285
+ var import_chalk34 = __toESM(require("chalk"));
28090
28286
  var import_fs62 = __toESM(require("fs"));
28091
28287
  var import_path60 = __toESM(require("path"));
28092
28288
  var import_os53 = __toESM(require("os"));
@@ -28141,14 +28337,14 @@ function registerDlpCommand(program2) {
28141
28337
  cmd.command("resolve").description("Mark all current DLP findings as resolved").action(() => {
28142
28338
  const findings = loadDlpFindings();
28143
28339
  if (findings.length === 0) {
28144
- console.log(import_chalk33.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
28340
+ console.log(import_chalk34.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
28145
28341
  return;
28146
28342
  }
28147
28343
  const resolved = loadResolved();
28148
28344
  for (const e of findings) resolved.add(entryKey2(e));
28149
28345
  saveResolved(resolved);
28150
28346
  console.log(
28151
- import_chalk33.default.green(
28347
+ import_chalk34.default.green(
28152
28348
  `
28153
28349
  \u2705 ${findings.length} finding${findings.length !== 1 ? "s" : ""} marked as resolved.
28154
28350
  `
@@ -28162,54 +28358,54 @@ function registerDlpCommand(program2) {
28162
28358
  const resolvedCount = findings.length - open.length;
28163
28359
  console.log("");
28164
28360
  console.log(
28165
- import_chalk33.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk33.default.dim(" \u2014 secrets found in Claude response text")
28361
+ import_chalk34.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk34.default.dim(" \u2014 secrets found in Claude response text")
28166
28362
  );
28167
28363
  console.log("");
28168
28364
  if (open.length === 0) {
28169
28365
  if (resolvedCount > 0) {
28170
- console.log(import_chalk33.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
28366
+ console.log(import_chalk34.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
28171
28367
  } else {
28172
28368
  console.log(
28173
- import_chalk33.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
28369
+ import_chalk34.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
28174
28370
  );
28175
28371
  }
28176
28372
  console.log("");
28177
28373
  return;
28178
28374
  }
28179
28375
  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)` : "")
28376
+ 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
28377
  );
28182
28378
  console.log("");
28183
28379
  console.log(
28184
- import_chalk33.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
28380
+ import_chalk34.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
28185
28381
  );
28186
- console.log(import_chalk33.default.dim(" Rotate each affected key immediately.\n"));
28382
+ console.log(import_chalk34.default.dim(" Rotate each affected key immediately.\n"));
28187
28383
  for (const e of open) {
28188
28384
  console.log(
28189
- " " + import_chalk33.default.red("\u25CF") + " " + import_chalk33.default.white(e.dlpPattern ?? "Secret") + import_chalk33.default.dim(" " + fmtDate3(e.ts))
28385
+ " " + import_chalk34.default.red("\u25CF") + " " + import_chalk34.default.white(e.dlpPattern ?? "Secret") + import_chalk34.default.dim(" " + fmtDate3(e.ts))
28190
28386
  );
28191
28387
  if (e.dlpSample) {
28192
- console.log(" " + import_chalk33.default.dim("Sample: ") + import_chalk33.default.yellow(stripAnsi(e.dlpSample)));
28388
+ console.log(" " + import_chalk34.default.dim("Sample: ") + import_chalk34.default.yellow(stripAnsi(e.dlpSample)));
28193
28389
  }
28194
28390
  if (e.project) {
28195
- console.log(" " + import_chalk33.default.dim("Project: ") + import_chalk33.default.dim(stripAnsi(e.project)));
28391
+ console.log(" " + import_chalk34.default.dim("Project: ") + import_chalk34.default.dim(stripAnsi(e.project)));
28196
28392
  }
28197
28393
  console.log("");
28198
28394
  }
28199
- console.log(" " + import_chalk33.default.bold("Next steps:"));
28200
- console.log(" " + import_chalk33.default.cyan("1.") + " Rotate any exposed keys shown above");
28395
+ console.log(" " + import_chalk34.default.bold("Next steps:"));
28396
+ console.log(" " + import_chalk34.default.cyan("1.") + " Rotate any exposed keys shown above");
28201
28397
  console.log(
28202
- " " + import_chalk33.default.cyan("2.") + " Run " + import_chalk33.default.white("node9 dlp resolve") + " to acknowledge"
28398
+ " " + import_chalk34.default.cyan("2.") + " Run " + import_chalk34.default.white("node9 dlp resolve") + " to acknowledge"
28203
28399
  );
28204
28400
  console.log(
28205
- " " + import_chalk33.default.cyan("3.") + " Run " + import_chalk33.default.white("node9 report") + " for full audit history"
28401
+ " " + import_chalk34.default.cyan("3.") + " Run " + import_chalk34.default.white("node9 report") + " for full audit history"
28206
28402
  );
28207
28403
  console.log("");
28208
28404
  });
28209
28405
  }
28210
28406
 
28211
28407
  // src/cli/commands/mask.ts
28212
- var import_chalk34 = __toESM(require("chalk"));
28408
+ var import_chalk35 = __toESM(require("chalk"));
28213
28409
  var import_fs63 = __toESM(require("fs"));
28214
28410
  var import_path61 = __toESM(require("path"));
28215
28411
  var import_os54 = __toESM(require("os"));
@@ -28346,12 +28542,12 @@ function registerMaskCommand(program2) {
28346
28542
  }
28347
28543
  }) : allFiles;
28348
28544
  if (filtered.length === 0) {
28349
- console.log(import_chalk34.default.yellow(" No session files found."));
28545
+ console.log(import_chalk35.default.yellow(" No session files found."));
28350
28546
  return;
28351
28547
  }
28352
28548
  console.log("");
28353
28549
  if (dryRun) {
28354
- console.log(import_chalk34.default.dim(" Dry run \u2014 no files will be modified.\n"));
28550
+ console.log(import_chalk35.default.dim(" Dry run \u2014 no files will be modified.\n"));
28355
28551
  }
28356
28552
  let totalFiles = 0;
28357
28553
  let totalLines = 0;
@@ -28367,23 +28563,23 @@ function registerMaskCommand(program2) {
28367
28563
  });
28368
28564
  const verb = dryRun ? "Would redact" : "Redacted";
28369
28565
  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" : ""})`)
28566
+ " " + 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
28567
  );
28372
28568
  }
28373
28569
  }
28374
28570
  console.log("");
28375
28571
  if (totalFiles === 0) {
28376
- console.log(import_chalk34.default.green(" No secrets found in session history."));
28572
+ console.log(import_chalk35.default.green(" No secrets found in session history."));
28377
28573
  } else {
28378
28574
  const verb = dryRun ? "would be modified" : "modified";
28379
28575
  console.log(
28380
- import_chalk34.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk34.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
28576
+ import_chalk35.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk35.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
28381
28577
  );
28382
- console.log(" Patterns: " + import_chalk34.default.yellow(totalPatterns.join(", ")));
28578
+ console.log(" Patterns: " + import_chalk35.default.yellow(totalPatterns.join(", ")));
28383
28579
  if (!dryRun) {
28384
28580
  console.log("");
28385
28581
  console.log(
28386
- import_chalk34.default.dim(
28582
+ import_chalk35.default.dim(
28387
28583
  " 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
28584
  )
28389
28585
  );
@@ -28401,77 +28597,34 @@ var { version } = JSON.parse(
28401
28597
  var program = new import_commander.Command();
28402
28598
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
28403
28599
  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
- }
28600
+ const { profileName, effectiveCloud } = writeCredentialsAndConfig(apiKey, {
28601
+ profileName: options.profile,
28602
+ isLocal: options.local
28603
+ });
28451
28604
  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`));
28605
+ console.log(import_chalk37.default.green(`\u2705 Profile "${profileName}" saved`));
28606
+ console.log(import_chalk37.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
28454
28607
  } 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.`));
28608
+ console.log(import_chalk37.default.green(`\u2705 Key saved \u2014 Privacy mode \u{1F6E1}\uFE0F`));
28609
+ console.log(import_chalk37.default.gray(` All decisions stay on this machine. Nothing syncs to the cloud.`));
28457
28610
  if (!options.local) {
28458
28611
  console.log(
28459
- import_chalk36.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
28612
+ import_chalk37.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
28460
28613
  );
28461
28614
  console.log(
28462
- import_chalk36.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
28615
+ import_chalk37.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
28463
28616
  );
28464
28617
  }
28465
28618
  } 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.`));
28619
+ console.log(import_chalk37.default.green(`\u2705 Logged in \u2014 agent mode`));
28620
+ console.log(import_chalk37.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
28468
28621
  }
28469
28622
  });
28470
28623
  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
28624
  const route = options.login ? "auth/login" : "auth/signup";
28472
28625
  const url = `https://node9.ai/${route}?ref=cli_cmd`;
28473
28626
  console.log("");
28474
- console.log(" " + import_chalk36.default.dim("Opening ") + import_chalk36.default.cyan.underline(url));
28627
+ console.log(" " + import_chalk37.default.dim("Opening ") + import_chalk37.default.cyan.underline(url));
28475
28628
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
28476
28629
  try {
28477
28630
  const child = (0, import_child_process15.spawn)(opener, [url], {
@@ -28504,7 +28657,7 @@ program.command("addto", { hidden: true }).description("Integrate Node9 with an
28504
28657
  if (target === "hermes") return setupHermes();
28505
28658
  if (target === "hud") return setupHud();
28506
28659
  console.error(
28507
- import_chalk36.default.red(
28660
+ import_chalk37.default.red(
28508
28661
  `Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
28509
28662
  )
28510
28663
  );
@@ -28518,20 +28671,20 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
28518
28671
  "The agent to protect: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
28519
28672
  ).action(async (target) => {
28520
28673
  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");
28674
+ console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
28675
+ console.log(" Usage: " + import_chalk37.default.white("node9 setup <target>") + "\n");
28523
28676
  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)");
28677
+ console.log(" " + import_chalk37.default.green("claude") + " \u2014 Claude Code (hook mode)");
28678
+ console.log(" " + import_chalk37.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
28679
+ console.log(" " + import_chalk37.default.green("antigravity") + " \u2014 Antigravity / agy (hook mode)");
28680
+ console.log(" " + import_chalk37.default.green("copilot") + " \u2014 GitHub Copilot CLI (hook mode)");
28681
+ console.log(" " + import_chalk37.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
28682
+ console.log(" " + import_chalk37.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
28683
+ console.log(" " + import_chalk37.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
28684
+ console.log(" " + import_chalk37.default.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
28685
+ console.log(" " + import_chalk37.default.green("hermes") + " \u2014 Hermes Agent (hook mode)");
28533
28686
  process.stdout.write(
28534
- " " + import_chalk36.default.green("hud") + " \u2014 Claude Code security statusline\n"
28687
+ " " + import_chalk37.default.green("hud") + " \u2014 Claude Code security statusline\n"
28535
28688
  );
28536
28689
  console.log("");
28537
28690
  return;
@@ -28548,7 +28701,7 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
28548
28701
  if (t === "hermes") return setupHermes();
28549
28702
  if (t === "hud") return setupHud();
28550
28703
  console.error(
28551
- import_chalk36.default.red(
28704
+ import_chalk37.default.red(
28552
28705
  `Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
28553
28706
  )
28554
28707
  );
@@ -28559,32 +28712,32 @@ program.command("removefrom", { hidden: true }).description("Remove Node9 hooks
28559
28712
  const agent = resolveAgentTeardown(target);
28560
28713
  if (!agent) {
28561
28714
  console.error(
28562
- import_chalk36.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
28715
+ import_chalk37.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
28563
28716
  );
28564
28717
  process.exit(1);
28565
28718
  return;
28566
28719
  }
28567
- console.log(import_chalk36.default.cyan(`
28720
+ console.log(import_chalk37.default.cyan(`
28568
28721
  \u{1F6E1}\uFE0F Node9: removing hooks from ${agent.label}...
28569
28722
  `));
28570
28723
  try {
28571
28724
  agent.fn();
28572
28725
  } catch (err2) {
28573
- console.error(import_chalk36.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
28726
+ console.error(import_chalk37.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
28574
28727
  process.exit(1);
28575
28728
  }
28576
- console.log(import_chalk36.default.gray("\n Restart the agent for changes to take effect."));
28729
+ console.log(import_chalk37.default.gray("\n Restart the agent for changes to take effect."));
28577
28730
  });
28578
28731
  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..."));
28732
+ console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
28733
+ console.log(import_chalk37.default.bold("Stopping daemon..."));
28581
28734
  try {
28582
28735
  stopDaemon();
28583
- console.log(import_chalk36.default.green(" \u2705 Daemon stopped"));
28736
+ console.log(import_chalk37.default.green(" \u2705 Daemon stopped"));
28584
28737
  } catch {
28585
- console.log(import_chalk36.default.blue(" \u2139\uFE0F Daemon was not running"));
28738
+ console.log(import_chalk37.default.blue(" \u2139\uFE0F Daemon was not running"));
28586
28739
  }
28587
- console.log(import_chalk36.default.bold("\nRemoving hooks..."));
28740
+ console.log(import_chalk37.default.bold("\nRemoving hooks..."));
28588
28741
  let teardownFailed = false;
28589
28742
  for (const { label: label2, fn } of AGENT_TEARDOWNS) {
28590
28743
  try {
@@ -28592,7 +28745,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28592
28745
  } catch (err2) {
28593
28746
  teardownFailed = true;
28594
28747
  console.error(
28595
- import_chalk36.default.red(
28748
+ import_chalk37.default.red(
28596
28749
  ` \u26A0\uFE0F Failed to remove ${label2} hooks: ${err2 instanceof Error ? err2.message : String(err2)}`
28597
28750
  )
28598
28751
  );
@@ -28601,12 +28754,12 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28601
28754
  try {
28602
28755
  const residual = getAgentWiring().filter((a) => a.wireState === "wired");
28603
28756
  if (residual.length === 0) {
28604
- console.log(import_chalk36.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
28757
+ console.log(import_chalk37.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
28605
28758
  } else {
28606
28759
  teardownFailed = true;
28607
- console.error(import_chalk36.default.red(" \u26A0\uFE0F Still wired after teardown:"));
28760
+ console.error(import_chalk37.default.red(" \u26A0\uFE0F Still wired after teardown:"));
28608
28761
  for (const a of residual) {
28609
- console.error(import_chalk36.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
28762
+ console.error(import_chalk37.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
28610
28763
  }
28611
28764
  }
28612
28765
  } catch {
@@ -28622,28 +28775,28 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28622
28775
  import_fs66.default.rmSync(node9Dir, { recursive: true });
28623
28776
  if (import_fs66.default.existsSync(node9Dir)) {
28624
28777
  console.error(
28625
- import_chalk36.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
28778
+ import_chalk37.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
28626
28779
  );
28627
28780
  } else {
28628
- console.log(import_chalk36.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
28781
+ console.log(import_chalk37.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
28629
28782
  }
28630
28783
  } else {
28631
- console.log(import_chalk36.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
28784
+ console.log(import_chalk37.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
28632
28785
  }
28633
28786
  } else {
28634
- console.log(import_chalk36.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
28787
+ console.log(import_chalk37.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
28635
28788
  }
28636
28789
  } else {
28637
28790
  console.log(
28638
- import_chalk36.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
28791
+ import_chalk37.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
28639
28792
  );
28640
28793
  }
28641
28794
  if (teardownFailed) {
28642
- console.error(import_chalk36.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
28795
+ console.error(import_chalk37.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
28643
28796
  process.exit(1);
28644
28797
  }
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"));
28798
+ console.log(import_chalk37.default.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g node9-ai"));
28799
+ console.log(import_chalk37.default.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
28647
28800
  });
28648
28801
  registerDoctorCommand(program, version);
28649
28802
  program.command("explain").description(
@@ -28656,7 +28809,7 @@ program.command("explain").description(
28656
28809
  try {
28657
28810
  args = JSON.parse(trimmed);
28658
28811
  } catch {
28659
- console.error(import_chalk36.default.red(`
28812
+ console.error(import_chalk37.default.red(`
28660
28813
  \u274C Invalid JSON: ${trimmed}
28661
28814
  `));
28662
28815
  process.exit(1);
@@ -28667,67 +28820,68 @@ program.command("explain").description(
28667
28820
  }
28668
28821
  const result = await explainPolicy(tool, args);
28669
28822
  console.log("");
28670
- console.log(import_chalk36.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
28823
+ console.log(import_chalk37.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
28671
28824
  console.log("");
28672
- console.log(` ${import_chalk36.default.bold("Tool:")} ${import_chalk36.default.white(result.tool)}`);
28825
+ console.log(` ${import_chalk37.default.bold("Tool:")} ${import_chalk37.default.white(result.tool)}`);
28673
28826
  if (argsRaw) {
28674
28827
  const preview2 = argsRaw.length > 80 ? argsRaw.slice(0, 77) + "\u2026" : argsRaw;
28675
- console.log(` ${import_chalk36.default.bold("Input:")} ${import_chalk36.default.gray(preview2)}`);
28828
+ console.log(` ${import_chalk37.default.bold("Input:")} ${import_chalk37.default.gray(preview2)}`);
28676
28829
  }
28677
28830
  console.log("");
28678
- console.log(import_chalk36.default.bold("Config Sources (Waterfall):"));
28831
+ console.log(import_chalk37.default.bold("Config Sources (Waterfall):"));
28679
28832
  for (const tier of result.waterfall) {
28680
- const num3 = import_chalk36.default.gray(` ${tier.tier}.`);
28833
+ const num3 = import_chalk37.default.gray(` ${tier.tier}.`);
28681
28834
  const label2 = tier.label.padEnd(16);
28682
28835
  let statusStr;
28683
28836
  if (tier.tier === 1) {
28684
- statusStr = import_chalk36.default.gray(tier.note ?? "");
28837
+ statusStr = import_chalk37.default.gray(tier.note ?? "");
28685
28838
  } 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 : "");
28839
+ const loc = tier.path ? import_chalk37.default.gray(tier.path) : "";
28840
+ const note = tier.note ? import_chalk37.default.gray(`(${tier.note})`) : "";
28841
+ statusStr = import_chalk37.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
28689
28842
  } else {
28690
- statusStr = import_chalk36.default.gray("\u25CB " + (tier.note ?? "not found"));
28843
+ statusStr = import_chalk37.default.gray("\u25CB " + (tier.note ?? "not found"));
28691
28844
  }
28692
- console.log(`${num3} ${import_chalk36.default.white(label2)} ${statusStr}`);
28845
+ console.log(`${num3} ${import_chalk37.default.white(label2)} ${statusStr}`);
28693
28846
  }
28694
28847
  console.log("");
28695
- console.log(import_chalk36.default.bold("Policy Evaluation:"));
28848
+ console.log(import_chalk37.default.bold("Policy Evaluation:"));
28696
28849
  for (const step of result.steps) {
28697
28850
  const isFinal = step.isFinal;
28698
28851
  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 ");
28852
+ if (step.outcome === "allow") icon = import_chalk37.default.green(" \u2705");
28853
+ else if (step.outcome === "block") icon = import_chalk37.default.red(" \u{1F6D1}");
28854
+ else if (step.outcome === "review") icon = import_chalk37.default.red(" \u{1F534}");
28855
+ else if (step.outcome === "skip") icon = import_chalk37.default.gray(" \u2500 ");
28856
+ else icon = import_chalk37.default.gray(" \u25CB ");
28704
28857
  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") : "";
28858
+ const nameStr = isFinal ? import_chalk37.default.white.bold(name) : import_chalk37.default.white(name);
28859
+ const detail = isFinal ? import_chalk37.default.white(step.detail) : import_chalk37.default.gray(step.detail);
28860
+ const arrow = isFinal ? import_chalk37.default.yellow(" \u2190 STOP") : "";
28708
28861
  console.log(`${icon} ${nameStr} ${detail}${arrow}`);
28709
28862
  }
28710
28863
  console.log("");
28711
28864
  if (result.decision === "allow") {
28712
- console.log(import_chalk36.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk36.default.gray(" \u2014 no approval needed"));
28865
+ console.log(import_chalk37.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk37.default.gray(" \u2014 no approval needed"));
28713
28866
  } else if (result.decision === "block") {
28714
28867
  console.log(
28715
- import_chalk36.default.red.bold(" Decision: \u{1F6D1} BLOCK") + import_chalk36.default.gray(" \u2014 this action is blocked")
28868
+ import_chalk37.default.red.bold(" Decision: \u{1F6D1} BLOCK") + import_chalk37.default.gray(" \u2014 this action is blocked")
28716
28869
  );
28717
28870
  if (result.blockedByLabel) {
28718
- console.log(import_chalk36.default.gray(` Reason: ${result.blockedByLabel}`));
28871
+ console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
28719
28872
  }
28720
28873
  } else {
28721
28874
  console.log(
28722
- import_chalk36.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk36.default.gray(" \u2014 human approval required")
28875
+ import_chalk37.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk37.default.gray(" \u2014 human approval required")
28723
28876
  );
28724
28877
  if (result.blockedByLabel) {
28725
- console.log(import_chalk36.default.gray(` Reason: ${result.blockedByLabel}`));
28878
+ console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
28726
28879
  }
28727
28880
  }
28728
28881
  console.log("");
28729
28882
  });
28730
28883
  registerInitCommand(program);
28884
+ registerConnectCommand(program);
28731
28885
  registerAuditCommand(program);
28732
28886
  registerReportCommand(program);
28733
28887
  registerStatusCommand(program);
@@ -28737,7 +28891,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
28737
28891
  try {
28738
28892
  await startTail2(options);
28739
28893
  } catch (err2) {
28740
- console.error(import_chalk36.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28894
+ console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28741
28895
  process.exit(1);
28742
28896
  }
28743
28897
  });
@@ -28748,7 +28902,7 @@ program.command("monitor").description("Live interactive dashboard \u2014 activi
28748
28902
  const mod = await dynamicImport(`file://${dashboardPath}`);
28749
28903
  await mod.startMonitor();
28750
28904
  } catch (err2) {
28751
- console.error(import_chalk36.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28905
+ console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28752
28906
  process.exit(1);
28753
28907
  }
28754
28908
  });
@@ -28803,7 +28957,7 @@ program.command("pause").description("Temporarily disable Node9 protection for a
28803
28957
  const ms = parseDuration(options.duration);
28804
28958
  if (ms === null) {
28805
28959
  console.error(
28806
- import_chalk36.default.red(`
28960
+ import_chalk37.default.red(`
28807
28961
  \u274C Invalid duration: "${options.duration}". Use format like 15m, 1h, 30s.
28808
28962
  `)
28809
28963
  );
@@ -28811,20 +28965,20 @@ program.command("pause").description("Temporarily disable Node9 protection for a
28811
28965
  }
28812
28966
  pauseNode9(ms, options.duration);
28813
28967
  const expiresAt = new Date(Date.now() + ms).toLocaleTimeString();
28814
- console.log(import_chalk36.default.yellow(`
28968
+ console.log(import_chalk37.default.yellow(`
28815
28969
  \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.
28970
+ console.log(import_chalk37.default.gray(` All tool calls will be allowed without review.`));
28971
+ console.log(import_chalk37.default.gray(` Run "node9 resume" to re-enable early.
28818
28972
  `));
28819
28973
  });
28820
28974
  program.command("resume").description("Re-enable Node9 protection immediately").action(() => {
28821
28975
  const { paused } = checkPause();
28822
28976
  if (!paused) {
28823
- console.log(import_chalk36.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
28977
+ console.log(import_chalk37.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
28824
28978
  return;
28825
28979
  }
28826
28980
  resumeNode9();
28827
- console.log(import_chalk36.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
28981
+ console.log(import_chalk37.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
28828
28982
  });
28829
28983
  var HOOK_BASED_AGENTS = {
28830
28984
  claude: "claude",
@@ -28840,15 +28994,15 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28840
28994
  if (HOOK_BASED_AGENTS[firstArg2] !== void 0) {
28841
28995
  const target = HOOK_BASED_AGENTS[firstArg2];
28842
28996
  console.error(
28843
- import_chalk36.default.yellow(`
28997
+ import_chalk37.default.yellow(`
28844
28998
  \u26A0\uFE0F Node9 proxy mode does not support "${target}" directly.`)
28845
28999
  );
28846
- console.error(import_chalk36.default.white(`
29000
+ console.error(import_chalk37.default.white(`
28847
29001
  "${target}" uses its own hook system. Use:`));
28848
29002
  console.error(
28849
- import_chalk36.default.green(` node9 addto ${target} `) + import_chalk36.default.gray("# one-time setup")
29003
+ import_chalk37.default.green(` node9 addto ${target} `) + import_chalk37.default.gray("# one-time setup")
28850
29004
  );
28851
- console.error(import_chalk36.default.green(` ${target} `) + import_chalk36.default.gray("# run normally"));
29005
+ console.error(import_chalk37.default.green(` ${target} `) + import_chalk37.default.gray("# run normally"));
28852
29006
  process.exit(1);
28853
29007
  }
28854
29008
  const runArgs = firstArg2 === "shell" ? commandArgs.slice(1) : commandArgs;
@@ -28865,7 +29019,7 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28865
29019
  }
28866
29020
  );
28867
29021
  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..."));
29022
+ console.error(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
28869
29023
  const daemonReady = await autoStartDaemonAndWait();
28870
29024
  if (daemonReady) result = await authorizeHeadless("shell", { command: fullCommand });
28871
29025
  }
@@ -28878,12 +29032,12 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28878
29032
  }
28879
29033
  if (!result.approved) {
28880
29034
  console.error(
28881
- import_chalk36.default.red(`
29035
+ import_chalk37.default.red(`
28882
29036
  \u274C Node9 Blocked: ${result.reason || "Dangerous command detected."}`)
28883
29037
  );
28884
29038
  process.exit(1);
28885
29039
  }
28886
- console.error(import_chalk36.default.green("\n\u2705 Approved \u2014 running command...\n"));
29040
+ console.error(import_chalk37.default.green("\n\u2705 Approved \u2014 running command...\n"));
28887
29041
  await runProxy(fullCommand);
28888
29042
  } else {
28889
29043
  program.help();