@node9/proxy 1.50.0 → 1.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -240,8 +240,8 @@ function sanitizeConfig(raw) {
240
240
  }
241
241
  }
242
242
  const lines = result.error.issues.map((issue) => {
243
- const path65 = issue.path.length > 0 ? issue.path.join(".") : "root";
244
- return ` \u2022 ${path65}: ${issue.message}`;
243
+ const path66 = issue.path.length > 0 ? issue.path.join(".") : "root";
244
+ return ` \u2022 ${path66}: ${issue.message}`;
245
245
  });
246
246
  return {
247
247
  sanitized,
@@ -1362,9 +1362,9 @@ function matchesPattern(text, patterns) {
1362
1362
  const withoutDotSlash = text.replace(/^\.\//, "");
1363
1363
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
1364
1364
  }
1365
- function getNestedValue(obj, path65) {
1365
+ function getNestedValue(obj, path66) {
1366
1366
  if (!obj || typeof obj !== "object") return null;
1367
- const segments = path65.split(".");
1367
+ const segments = path66.split(".");
1368
1368
  for (const seg of segments) {
1369
1369
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
1370
1370
  }
@@ -4243,12 +4243,28 @@ function applyManagedEgress(local, managed, locked) {
4243
4243
  }
4244
4244
  return next;
4245
4245
  }
4246
- var MODE_ORDER, EGRESS_MODE_ORDER;
4246
+ function applyManagedDlp(local, managed, locked) {
4247
+ const next = { ...local };
4248
+ if (typeof managed.enabled === "boolean") {
4249
+ next.enabled = locked.includes("dlpEnabled") ? managed.enabled : local.enabled || managed.enabled;
4250
+ }
4251
+ if (typeof managed.pii === "string") {
4252
+ next.pii = resolveByOrder(
4253
+ DLP_PII_ORDER,
4254
+ local.pii ?? "off",
4255
+ managed.pii,
4256
+ locked.includes("dlpPii")
4257
+ );
4258
+ }
4259
+ return next;
4260
+ }
4261
+ var MODE_ORDER, EGRESS_MODE_ORDER, DLP_PII_ORDER;
4247
4262
  var init_managed = __esm({
4248
4263
  "src/config/managed.ts"() {
4249
4264
  "use strict";
4250
4265
  MODE_ORDER = ["observe", "audit", "standard", "strict"];
4251
4266
  EGRESS_MODE_ORDER = ["off", "review", "block"];
4267
+ DLP_PII_ORDER = ["off", "block"];
4252
4268
  }
4253
4269
  });
4254
4270
 
@@ -4281,11 +4297,11 @@ function getGlobalSettings() {
4281
4297
  };
4282
4298
  }
4283
4299
  function getCredentials() {
4284
- const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
4300
+ const DEFAULT_API_URL3 = "https://api.node9.ai/api/v1/intercept";
4285
4301
  if (process.env.NODE9_API_KEY) {
4286
4302
  return {
4287
4303
  apiKey: process.env.NODE9_API_KEY,
4288
- apiUrl: process.env.NODE9_API_URL || DEFAULT_API_URL2
4304
+ apiUrl: process.env.NODE9_API_URL || DEFAULT_API_URL3
4289
4305
  };
4290
4306
  }
4291
4307
  try {
@@ -4297,13 +4313,13 @@ function getCredentials() {
4297
4313
  if (profile?.apiKey) {
4298
4314
  return {
4299
4315
  apiKey: profile.apiKey,
4300
- apiUrl: profile.apiUrl || DEFAULT_API_URL2
4316
+ apiUrl: profile.apiUrl || DEFAULT_API_URL3
4301
4317
  };
4302
4318
  }
4303
4319
  if (creds.apiKey) {
4304
4320
  return {
4305
4321
  apiKey: creds.apiKey,
4306
- apiUrl: creds.apiUrl || DEFAULT_API_URL2
4322
+ apiUrl: creds.apiUrl || DEFAULT_API_URL3
4307
4323
  };
4308
4324
  }
4309
4325
  }
@@ -4482,6 +4498,16 @@ function getConfig(cwd) {
4482
4498
  locked
4483
4499
  );
4484
4500
  }
4501
+ if (mc.dlp && typeof mc.dlp === "object") {
4502
+ mergedPolicy.dlp = applyManagedDlp(
4503
+ mergedPolicy.dlp,
4504
+ {
4505
+ enabled: typeof mc.dlp.enabled === "boolean" ? mc.dlp.enabled : void 0,
4506
+ pii: typeof mc.dlp.pii === "string" ? mc.dlp.pii : void 0
4507
+ },
4508
+ locked
4509
+ );
4510
+ }
4485
4511
  }
4486
4512
  if (raw.panicMode === true) {
4487
4513
  mergedSettings.panicMode = true;
@@ -7761,6 +7787,35 @@ var init_setup_pi_shim = __esm({
7761
7787
  });
7762
7788
 
7763
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
+ }
7764
7819
  function hasNode9McpServer(servers) {
7765
7820
  const entry = servers["node9"];
7766
7821
  return !!entry && entry.command === "node9" && Array.isArray(entry.args) && entry.args[0] === "mcp-server";
@@ -8081,7 +8136,7 @@ async function setupClaude() {
8081
8136
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8082
8137
  }
8083
8138
  console.log("");
8084
- 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 });
8085
8140
  if (proceed) {
8086
8141
  for (const { name, upstream } of serversToWrap) {
8087
8142
  servers[name] = {
@@ -8186,7 +8241,7 @@ async function setupGemini() {
8186
8241
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8187
8242
  }
8188
8243
  console.log("");
8189
- 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 });
8190
8245
  if (proceed) {
8191
8246
  for (const { name, upstream } of serversToWrap) {
8192
8247
  servers[name] = {
@@ -8312,7 +8367,7 @@ async function setupAntigravity() {
8312
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)."
8313
8368
  )
8314
8369
  );
8315
- const clean = await (0, import_prompts.confirm)({
8370
+ const clean = await confirm({
8316
8371
  message: "Remove the legacy Gemini CLI hooks?",
8317
8372
  default: false
8318
8373
  });
@@ -8334,7 +8389,7 @@ async function setupAntigravity() {
8334
8389
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8335
8390
  }
8336
8391
  console.log("");
8337
- 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 });
8338
8393
  if (proceed) {
8339
8394
  for (const { name, upstream } of serversToWrap) {
8340
8395
  servers[name] = {
@@ -8479,7 +8534,7 @@ async function setupCopilot() {
8479
8534
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8480
8535
  }
8481
8536
  console.log("");
8482
- 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 });
8483
8538
  if (proceed) {
8484
8539
  for (const { name, upstream } of serversToWrap) {
8485
8540
  servers[name] = {
@@ -8680,7 +8735,7 @@ async function setupCursor() {
8680
8735
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8681
8736
  }
8682
8737
  console.log("");
8683
- 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 });
8684
8739
  if (proceed) {
8685
8740
  for (const { name, upstream } of serversToWrap) {
8686
8741
  servers[name] = {
@@ -8831,7 +8886,7 @@ async function setupCodex() {
8831
8886
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8832
8887
  }
8833
8888
  console.log("");
8834
- 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 });
8835
8890
  if (proceed) {
8836
8891
  for (const { name, upstream } of serversToWrap) {
8837
8892
  servers[name] = {
@@ -9008,7 +9063,7 @@ async function setupWindsurf() {
9008
9063
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
9009
9064
  }
9010
9065
  console.log("");
9011
- 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 });
9012
9067
  if (proceed) {
9013
9068
  for (const { name, upstream } of serversToWrap) {
9014
9069
  servers[name] = {
@@ -9112,7 +9167,7 @@ async function setupVSCode() {
9112
9167
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
9113
9168
  }
9114
9169
  console.log("");
9115
- 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 });
9116
9171
  if (proceed) {
9117
9172
  for (const { name, upstream } of serversToWrap) {
9118
9173
  servers[name] = {
@@ -9212,7 +9267,7 @@ async function setupClaudeDesktop() {
9212
9267
  console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
9213
9268
  }
9214
9269
  console.log("");
9215
- 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 });
9216
9271
  if (proceed) {
9217
9272
  for (const { name, upstream } of serversToWrap) {
9218
9273
  servers[name] = {
@@ -16854,7 +16909,7 @@ function readCredentials() {
16854
16909
  if (process.env.NODE9_API_KEY) {
16855
16910
  return {
16856
16911
  apiKey: process.env.NODE9_API_KEY,
16857
- apiUrl: process.env.NODE9_API_URL ?? DEFAULT_API_URL
16912
+ apiUrl: process.env.NODE9_API_URL ?? DEFAULT_API_URL2
16858
16913
  };
16859
16914
  }
16860
16915
  try {
@@ -16873,11 +16928,11 @@ function readCredentials() {
16873
16928
  // Anything else is taken as-is so users can override the full
16874
16929
  // URL via NODE9_API_URL or a non-standard apiUrl.
16875
16930
  /\/intercept$/.test(profile.apiUrl) ? profile.apiUrl + "/policies/sync" : profile.apiUrl
16876
- ) : DEFAULT_API_URL
16931
+ ) : DEFAULT_API_URL2
16877
16932
  };
16878
16933
  }
16879
16934
  if (typeof creds.apiKey === "string" && creds.apiKey.length > 0) {
16880
- return { apiKey: creds.apiKey, apiUrl: DEFAULT_API_URL };
16935
+ return { apiKey: creds.apiKey, apiUrl: DEFAULT_API_URL2 };
16881
16936
  }
16882
16937
  } catch {
16883
16938
  }
@@ -16961,7 +17016,13 @@ function extractManagedConfig(body) {
16961
17016
  if (typeof mc.egress.mode === "string") e.mode = mc.egress.mode;
16962
17017
  if (e.enabled !== void 0 || e.mode !== void 0) out.egress = e;
16963
17018
  }
16964
- return out.mode !== void 0 || out.egress !== void 0 ? out : void 0;
17019
+ if (mc.dlp && typeof mc.dlp === "object") {
17020
+ const d = {};
17021
+ if (typeof mc.dlp.enabled === "boolean") d.enabled = mc.dlp.enabled;
17022
+ if (typeof mc.dlp.pii === "string") d.pii = mc.dlp.pii;
17023
+ if (d.enabled !== void 0 || d.pii !== void 0) out.dlp = d;
17024
+ }
17025
+ return out.mode !== void 0 || out.egress !== void 0 || out.dlp !== void 0 ? out : void 0;
16965
17026
  }
16966
17027
  function writeCache2(cache) {
16967
17028
  const dir = import_path31.default.dirname(rulesCacheFile());
@@ -17219,7 +17280,7 @@ function startForensicBroadcast() {
17219
17280
  const recurring = setInterval(() => void tick(), FORENSIC_BROADCAST_INTERVAL_MS);
17220
17281
  recurring.unref();
17221
17282
  }
17222
- var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17283
+ var import_fs32, import_https4, import_os29, import_path31, FINDING_TO_SIGNAL3, rulesCacheFile, DEFAULT_API_URL2, DEFAULT_INTERVAL_HOURS, MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS, FORENSIC_BROADCAST_INTERVAL_MS, FORENSIC_INITIAL_DELAY_MS, forensicBroadcastOffsets;
17223
17284
  var init_sync = __esm({
17224
17285
  "src/daemon/sync.ts"() {
17225
17286
  "use strict";
@@ -17251,7 +17312,7 @@ var init_sync = __esm({
17251
17312
  "long-output-redacted": "longOutputRedactions"
17252
17313
  };
17253
17314
  rulesCacheFile = () => import_path31.default.join(import_os29.default.homedir(), ".node9", "rules-cache.json");
17254
- DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept/policies/sync";
17315
+ DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept/policies/sync";
17255
17316
  DEFAULT_INTERVAL_HOURS = 5;
17256
17317
  MIN_INTERVAL_SECONDS = 15;
17257
17318
  MAX_INTERVAL_SECONDS = 24 * 60 * 60;
@@ -19053,10 +19114,10 @@ function readSessionUsage() {
19053
19114
  }
19054
19115
  }
19055
19116
  function formatContextStat(stat) {
19056
- const pctColor = stat.fillPct >= 80 ? import_chalk35.default.red : stat.fillPct >= 50 ? import_chalk35.default.yellow : import_chalk35.default.cyan;
19117
+ const pctColor = stat.fillPct >= 80 ? import_chalk36.default.red : stat.fillPct >= 50 ? import_chalk36.default.yellow : import_chalk36.default.cyan;
19057
19118
  const k = (n) => `${Math.round(n / 1e3)}k`;
19058
19119
  const modelShort = stat.model.replace(/@.*$/, "").replace(/-\d{8}$/, "").replace(/^claude-/, "");
19059
- return import_chalk35.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk35.default.dim(
19120
+ return import_chalk36.default.dim("ctx: ") + pctColor(`${stat.fillPct}%`) + import_chalk36.default.dim(
19060
19121
  ` (${k(stat.inputTokens)}/${k(getModelContextLimit(stat.model))} out ${k(stat.outputTokens)} \xB7 ${modelShort})`
19061
19122
  );
19062
19123
  }
@@ -19079,11 +19140,11 @@ function agentLabel(agent, mcpServer, sessionId) {
19079
19140
  const tag = sessionTag(sessionId);
19080
19141
  const tagSuffix = tag ? `\xB7${tag}` : "";
19081
19142
  if (!agent || agent === "Terminal") {
19082
- return mcpServer ? import_chalk35.default.dim(`[\u2192 ${mcpServer}] `) : "";
19143
+ return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
19083
19144
  }
19084
19145
  const short = agent === "Claude Code" ? "Claude" : agent === "Gemini CLI" ? "Gemini" : agent === "Unknown Agent" ? "" : agent.split(" ")[0];
19085
- if (!short) return mcpServer ? import_chalk35.default.dim(`[\u2192 ${mcpServer}] `) : "";
19086
- return mcpServer ? import_chalk35.default.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : import_chalk35.default.dim(`[${short}${tagSuffix}] `);
19146
+ if (!short) return mcpServer ? import_chalk36.default.dim(`[\u2192 ${mcpServer}] `) : "";
19147
+ return mcpServer ? import_chalk36.default.dim(`[${short}${tagSuffix} \u2192 ${mcpServer}] `) : import_chalk36.default.dim(`[${short}${tagSuffix}] `);
19087
19148
  }
19088
19149
  function formatBase(activity) {
19089
19150
  const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
@@ -19091,20 +19152,20 @@ function formatBase(activity) {
19091
19152
  const toolName = activity.tool.slice(0, 16).padEnd(16);
19092
19153
  const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os55.default.homedir(), "~");
19093
19154
  const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
19094
- return `${import_chalk35.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk35.default.white.bold(toolName)} ${import_chalk35.default.dim(argsPreview)}`;
19155
+ return `${import_chalk36.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk36.default.white.bold(toolName)} ${import_chalk36.default.dim(argsPreview)}`;
19095
19156
  }
19096
19157
  function renderResult(activity, result) {
19097
19158
  const base = formatBase(activity);
19098
19159
  let status;
19099
19160
  if (result.status === "allow") {
19100
- status = import_chalk35.default.green("\u2713 ALLOW");
19161
+ status = import_chalk36.default.green("\u2713 ALLOW");
19101
19162
  } else if (result.status === "dlp") {
19102
- status = import_chalk35.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
19163
+ status = import_chalk36.default.bgRed.white.bold(" \u{1F6E1}\uFE0F DLP ");
19103
19164
  } else {
19104
- status = import_chalk35.default.red("\u2717 BLOCK");
19165
+ status = import_chalk36.default.red("\u2717 BLOCK");
19105
19166
  }
19106
19167
  const cost = result.costEstimate ?? activity.costEstimate;
19107
- const costSuffix = cost == null ? "" : import_chalk35.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
19168
+ const costSuffix = cost == null ? "" : import_chalk36.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
19108
19169
  if (process.stdout.isTTY) {
19109
19170
  if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
19110
19171
  import_readline6.default.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
@@ -19121,7 +19182,7 @@ function renderResult(activity, result) {
19121
19182
  }
19122
19183
  function renderPending(activity) {
19123
19184
  if (!process.stdout.isTTY) return;
19124
- const line = `${formatBase(activity)} ${import_chalk35.default.yellow("\u25CF \u2026")}`;
19185
+ const line = `${formatBase(activity)} ${import_chalk36.default.yellow("\u25CF \u2026")}`;
19125
19186
  pendingShownForId = activity.id;
19126
19187
  pendingWrappedLines = wrappedLineCount(line);
19127
19188
  process.stdout.write(`${line}\r`);
@@ -19133,7 +19194,7 @@ async function ensureDaemon() {
19133
19194
  const { port } = JSON.parse(import_fs64.default.readFileSync(PID_FILE, "utf-8"));
19134
19195
  pidPort = port;
19135
19196
  } catch {
19136
- console.error(import_chalk35.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
19197
+ console.error(import_chalk36.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
19137
19198
  }
19138
19199
  }
19139
19200
  const checkPort = pidPort ?? DAEMON_PORT;
@@ -19144,7 +19205,7 @@ async function ensureDaemon() {
19144
19205
  if (res.ok) return checkPort;
19145
19206
  } catch {
19146
19207
  }
19147
- console.log(import_chalk35.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
19208
+ console.log(import_chalk36.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
19148
19209
  const child = (0, import_child_process14.spawn)(process.execPath, [process.argv[1], "daemon"], {
19149
19210
  detached: true,
19150
19211
  stdio: "ignore",
@@ -19161,7 +19222,7 @@ async function ensureDaemon() {
19161
19222
  } catch {
19162
19223
  }
19163
19224
  }
19164
- console.error(import_chalk35.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
19225
+ console.error(import_chalk36.default.red("\u274C Daemon failed to start. Try: node9 daemon start"));
19165
19226
  process.exit(1);
19166
19227
  }
19167
19228
  function postDecisionHttp(id, decision, authToken, port, opts) {
@@ -19171,7 +19232,7 @@ function postDecisionHttp(id, decision, authToken, port, opts) {
19171
19232
  if (opts?.trustDuration) bodyObj.trustDuration = opts.trustDuration;
19172
19233
  if (opts?.reason) bodyObj.reason = opts.reason;
19173
19234
  const body = JSON.stringify(bodyObj);
19174
- const req = import_http4.default.request(
19235
+ const req = import_http5.default.request(
19175
19236
  {
19176
19237
  hostname: "127.0.0.1",
19177
19238
  port,
@@ -19230,7 +19291,7 @@ function buildCardLines(req, localCount = 0) {
19230
19291
  const severityIcon = isBlock ? `${RED}\u{1F6D1}` : `${YELLOW}\u26A0 `;
19231
19292
  const rawDesc = req.riskMetadata?.ruleDescription ?? "";
19232
19293
  const description = rawDesc ? cleanReason(rawDesc) : "";
19233
- const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk35.default.dim(`(${req.agent})`)}` : "";
19294
+ const agentSuffix = req.agent && req.agent !== "Terminal" ? ` ${RESET2}${import_chalk36.default.dim(`(${req.agent})`)}` : "";
19234
19295
  const lines = [
19235
19296
  ``,
19236
19297
  `${BOLD2}${CYAN}\u2554\u2550\u2550 Node9 Approval Required \u2550\u2550\u2557${RESET2}`,
@@ -19299,7 +19360,7 @@ function approverStatusLine() {
19299
19360
  const a = readApproversFromDisk();
19300
19361
  const fmt = (label2, key) => {
19301
19362
  const on = a[key] !== false;
19302
- return `[${key[0]}]${label2.slice(1)} ${on ? import_chalk35.default.green("\u2713") : import_chalk35.default.dim("\u2717")}`;
19363
+ return `[${key[0]}]${label2.slice(1)} ${on ? import_chalk36.default.green("\u2713") : import_chalk36.default.dim("\u2717")}`;
19303
19364
  };
19304
19365
  return `${fmt("native", "native")} ${fmt("cloud", "cloud")} ${fmt("terminal", "terminal")}`;
19305
19366
  }
@@ -19322,7 +19383,7 @@ async function startTail(options = {}) {
19322
19383
  const port = await ensureDaemon();
19323
19384
  if (options.clear) {
19324
19385
  const result = await new Promise((resolve) => {
19325
- const req2 = import_http4.default.request(
19386
+ const req2 = import_http5.default.request(
19326
19387
  { method: "POST", hostname: "127.0.0.1", port, path: "/events/clear" },
19327
19388
  (res) => {
19328
19389
  const status = res.statusCode ?? 0;
@@ -19344,7 +19405,7 @@ async function startTail(options = {}) {
19344
19405
  req2.end();
19345
19406
  });
19346
19407
  if (result.ok) {
19347
- console.log(import_chalk35.default.green("\u2713 Flight Recorder buffer cleared."));
19408
+ console.log(import_chalk36.default.green("\u2713 Flight Recorder buffer cleared."));
19348
19409
  } else if (result.code === "ECONNREFUSED") {
19349
19410
  throw new Error("Daemon is not running. Start it with: node9 daemon start");
19350
19411
  } else if (result.code === "ETIMEDOUT") {
@@ -19390,7 +19451,7 @@ async function startTail(options = {}) {
19390
19451
  const channel = name === "n" ? "native" : name === "c" ? "cloud" : name === "t" ? "terminal" : null;
19391
19452
  if (channel) {
19392
19453
  toggleApprover(channel);
19393
- console.log(import_chalk35.default.dim(` Approvers: ${approverStatusLine()}`));
19454
+ console.log(import_chalk36.default.dim(` Approvers: ${approverStatusLine()}`));
19394
19455
  }
19395
19456
  };
19396
19457
  process.stdin.on("keypress", idleKeypressHandler);
@@ -19456,7 +19517,7 @@ async function startTail(options = {}) {
19456
19517
  localAllowCounts.get(req2.toolName) ?? 0
19457
19518
  )
19458
19519
  );
19459
- const decisionStamp = action === "always-allow" ? import_chalk35.default.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? import_chalk35.default.cyan("\u23F1 TRUST 30m") : action === "allow" ? import_chalk35.default.green("\u2713 ALLOWED") : action === "redirect" ? import_chalk35.default.yellow("\u21A9 REDIRECT AI") : import_chalk35.default.red("\u2717 DENIED");
19520
+ const decisionStamp = action === "always-allow" ? import_chalk36.default.yellow("\u2605 ALWAYS ALLOW") : action === "trust" ? import_chalk36.default.cyan("\u23F1 TRUST 30m") : action === "allow" ? import_chalk36.default.green("\u2713 ALLOWED") : action === "redirect" ? import_chalk36.default.yellow("\u21A9 REDIRECT AI") : import_chalk36.default.red("\u2717 DENIED");
19460
19521
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${decisionStamp} ${GRAY}(terminal)${RESET2}`, ``);
19461
19522
  for (const line of stampedLines) process.stdout.write(line + "\n");
19462
19523
  process.stdout.write(SHOW_CURSOR);
@@ -19507,7 +19568,7 @@ async function startTail(options = {}) {
19507
19568
  );
19508
19569
  const stampedLines = buildCardLines(req2, priorCount);
19509
19570
  if (externalDecision) {
19510
- const source = externalDecision === "allow" ? import_chalk35.default.green("\u2713 ALLOWED") : import_chalk35.default.red("\u2717 DENIED");
19571
+ const source = externalDecision === "allow" ? import_chalk36.default.green("\u2713 ALLOWED") : import_chalk36.default.red("\u2717 DENIED");
19511
19572
  stampedLines.push(` ${BOLD2}\u2192${RESET2} ${source} ${GRAY}(external)${RESET2}`, ``);
19512
19573
  }
19513
19574
  for (const line of stampedLines) process.stdout.write(line + "\n");
@@ -19555,25 +19616,25 @@ async function startTail(options = {}) {
19555
19616
  if (unackedDlp > 0) {
19556
19617
  console.log("");
19557
19618
  console.log(
19558
- import_chalk35.default.bgRed.white.bold(
19619
+ import_chalk36.default.bgRed.white.bold(
19559
19620
  ` \u26A0\uFE0F DLP ALERT: ${unackedDlp} secret${unackedDlp !== 1 ? "s" : ""} found in Claude response text \u2014 run: node9 dlp `
19560
19621
  )
19561
19622
  );
19562
19623
  }
19563
19624
  } catch {
19564
19625
  }
19565
- console.log(import_chalk35.default.cyan.bold(`
19626
+ console.log(import_chalk36.default.cyan.bold(`
19566
19627
  \u{1F6F0}\uFE0F Node9 tail`));
19567
19628
  if (canApprove) {
19568
- console.log(import_chalk35.default.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
19569
- console.log(import_chalk35.default.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
19629
+ console.log(import_chalk36.default.dim("Card: [\u21B5/y] Allow [n] Deny [a] Always [t] Trust 30m"));
19630
+ console.log(import_chalk36.default.dim(`Approvers (toggle): ${approverStatusLine()} [q] quit`));
19570
19631
  }
19571
19632
  const ctxStat = readSessionUsage();
19572
19633
  if (ctxStat) console.log(" " + formatContextStat(ctxStat));
19573
19634
  if (options.history) {
19574
- console.log(import_chalk35.default.dim("Showing history + live events.\n"));
19635
+ console.log(import_chalk36.default.dim("Showing history + live events.\n"));
19575
19636
  } else {
19576
- console.log(import_chalk35.default.dim("Showing live events only. Use --history to include past.\n"));
19637
+ console.log(import_chalk36.default.dim("Showing live events only. Use --history to include past.\n"));
19577
19638
  }
19578
19639
  process.on("SIGINT", () => {
19579
19640
  exitIdleMode();
@@ -19583,7 +19644,7 @@ async function startTail(options = {}) {
19583
19644
  import_readline6.default.clearLine(process.stdout, 0);
19584
19645
  import_readline6.default.cursorTo(process.stdout, 0);
19585
19646
  }
19586
- console.log(import_chalk35.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
19647
+ console.log(import_chalk36.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
19587
19648
  process.exit(0);
19588
19649
  });
19589
19650
  const STALL_THRESHOLD_MS = 6e4;
@@ -19595,7 +19656,7 @@ async function startTail(options = {}) {
19595
19656
  if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
19596
19657
  console.log("");
19597
19658
  console.log(
19598
- import_chalk35.default.yellow(
19659
+ import_chalk36.default.yellow(
19599
19660
  "\u26A0\uFE0F Tail appears stalled \u2014 hooks are firing but no events are arriving. Try: node9 daemon restart"
19600
19661
  )
19601
19662
  );
@@ -19605,14 +19666,14 @@ async function startTail(options = {}) {
19605
19666
  }, STALL_THRESHOLD_MS / 2);
19606
19667
  stallWatchdog.unref();
19607
19668
  const sseUrl = `http://127.0.0.1:${port}/events?capabilities=input`;
19608
- const req = import_http4.default.get(
19669
+ const req = import_http5.default.get(
19609
19670
  sseUrl,
19610
19671
  {
19611
19672
  headers: authToken ? { "X-Node9-Internal": authToken } : {}
19612
19673
  },
19613
19674
  (res) => {
19614
19675
  if (res.statusCode !== 200) {
19615
- console.error(import_chalk35.default.red(`Failed to connect: HTTP ${res.statusCode}`));
19676
+ console.error(import_chalk36.default.red(`Failed to connect: HTTP ${res.statusCode}`));
19616
19677
  process.exit(1);
19617
19678
  }
19618
19679
  if (canApprove) enterIdleMode();
@@ -19643,7 +19704,7 @@ async function startTail(options = {}) {
19643
19704
  import_readline6.default.clearLine(process.stdout, 0);
19644
19705
  import_readline6.default.cursorTo(process.stdout, 0);
19645
19706
  }
19646
- console.log(import_chalk35.default.red("\n\u274C Daemon disconnected."));
19707
+ console.log(import_chalk36.default.red("\n\u274C Daemon disconnected."));
19647
19708
  process.exit(1);
19648
19709
  });
19649
19710
  }
@@ -19656,7 +19717,7 @@ async function startTail(options = {}) {
19656
19717
  const parsed = JSON.parse(rawData);
19657
19718
  const msg = parsed.message ?? "Flight recorder is down \u2014 run: node9 daemon restart";
19658
19719
  console.log("");
19659
- console.log(import_chalk35.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
19720
+ console.log(import_chalk36.default.bgRed.white.bold(` \u26A0\uFE0F ${msg} `));
19660
19721
  } catch {
19661
19722
  }
19662
19723
  return;
@@ -19741,9 +19802,9 @@ async function startTail(options = {}) {
19741
19802
  const rawSummary = data.argsSummary ?? data.tool;
19742
19803
  const summary = shortenPathSummary(rawSummary);
19743
19804
  const fileCount = data.fileCount ?? 0;
19744
- const files = fileCount > 0 ? import_chalk35.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
19805
+ const files = fileCount > 0 ? import_chalk36.default.dim(` \xB7 ${fileCount} file${fileCount === 1 ? "" : "s"}`) : "";
19745
19806
  process.stdout.write(
19746
- `${import_chalk35.default.dim(time)} ${import_chalk35.default.cyan("\u{1F4F8} snapshot")} ${import_chalk35.default.dim(hash)} ${summary}${files}
19807
+ `${import_chalk36.default.dim(time)} ${import_chalk36.default.cyan("\u{1F4F8} snapshot")} ${import_chalk36.default.dim(hash)} ${summary}${files}
19747
19808
  `
19748
19809
  );
19749
19810
  return;
@@ -19760,28 +19821,28 @@ async function startTail(options = {}) {
19760
19821
  if (event === "execution-result") {
19761
19822
  const exec = data;
19762
19823
  const time = new Date(Date.now()).toLocaleTimeString([], { hour12: false });
19763
- const arrow = exec.isError ? import_chalk35.default.red(" \u21B3 \u2717") : import_chalk35.default.green(" \u21B3 \u2713");
19824
+ const arrow = exec.isError ? import_chalk36.default.red(" \u21B3 \u2717") : import_chalk36.default.green(" \u21B3 \u2713");
19764
19825
  const label2 = agentLabel(exec.agent, exec.mcpServer);
19765
19826
  const tool = (exec.tool ?? "").slice(0, 16);
19766
- const duration = typeof exec.durationMs === "number" ? import_chalk35.default.dim(` (${exec.durationMs}ms)`) : "";
19827
+ const duration = typeof exec.durationMs === "number" ? import_chalk36.default.dim(` (${exec.durationMs}ms)`) : "";
19767
19828
  console.log(
19768
- `${import_chalk35.default.gray(time)} ${arrow} ${label2}${import_chalk35.default.dim(tool)}${import_chalk35.default.dim(" completed")}${duration}`
19829
+ `${import_chalk36.default.gray(time)} ${arrow} ${label2}${import_chalk36.default.dim(tool)}${import_chalk36.default.dim(" completed")}${duration}`
19769
19830
  );
19770
19831
  }
19771
19832
  }
19772
19833
  req.on("error", (err2) => {
19773
19834
  const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
19774
- console.error(import_chalk35.default.red(`
19835
+ console.error(import_chalk36.default.red(`
19775
19836
  \u274C ${msg}`));
19776
19837
  process.exit(1);
19777
19838
  });
19778
19839
  }
19779
- var import_http4, import_chalk35, import_fs64, import_os55, import_path62, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
19840
+ var import_http5, import_chalk36, import_fs64, import_os55, import_path62, import_readline6, import_child_process14, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
19780
19841
  var init_tail = __esm({
19781
19842
  "src/tui/tail.ts"() {
19782
19843
  "use strict";
19783
- import_http4 = __toESM(require("http"));
19784
- import_chalk35 = __toESM(require("chalk"));
19844
+ import_http5 = __toESM(require("http"));
19845
+ import_chalk36 = __toESM(require("chalk"));
19785
19846
  import_fs64 = __toESM(require("fs"));
19786
19847
  import_os55 = __toESM(require("os"));
19787
19848
  import_path62 = __toESM(require("path"));
@@ -19854,7 +19915,7 @@ function queryDaemon() {
19854
19915
  return new Promise((resolve) => {
19855
19916
  const timeout = setTimeout(() => resolve(null), 50);
19856
19917
  try {
19857
- const req = import_http5.default.get(
19918
+ const req = import_http6.default.get(
19858
19919
  `http://${DAEMON_HOST}:${DAEMON_PORT}/status`,
19859
19920
  { timeout: 50 },
19860
19921
  (res) => {
@@ -20182,14 +20243,14 @@ async function main() {
20182
20243
  renderOffline();
20183
20244
  }
20184
20245
  }
20185
- var import_fs65, import_path63, import_os56, import_http5, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
20246
+ var import_fs65, import_path63, import_os56, import_http6, RESET3, BOLD3, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
20186
20247
  var init_hud = __esm({
20187
20248
  "src/cli/hud.ts"() {
20188
20249
  "use strict";
20189
20250
  import_fs65 = __toESM(require("fs"));
20190
20251
  import_path63 = __toESM(require("path"));
20191
20252
  import_os56 = __toESM(require("os"));
20192
- import_http5 = __toESM(require("http"));
20253
+ import_http6 = __toESM(require("http"));
20193
20254
  init_daemon();
20194
20255
  RESET3 = "\x1B[0m";
20195
20256
  BOLD3 = "\x1B[1m";
@@ -20246,8 +20307,69 @@ function agentTeardownTargets() {
20246
20307
 
20247
20308
  // src/cli.ts
20248
20309
  init_agent_wiring();
20310
+
20311
+ // src/credentials.ts
20312
+ var fs15 = __toESM(require("fs"));
20313
+ var os14 = __toESM(require("os"));
20314
+ var path17 = __toESM(require("path"));
20315
+ var DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
20316
+ function writeCredentialsAndConfig(apiKey, opts = {}) {
20317
+ const profileName = opts.profileName || "default";
20318
+ const home = opts.homeDir ?? os14.homedir();
20319
+ const credPath = path17.join(home, ".node9", "credentials.json");
20320
+ if (!fs15.existsSync(path17.dirname(credPath))) {
20321
+ fs15.mkdirSync(path17.dirname(credPath), { recursive: true });
20322
+ }
20323
+ let existingCreds = {};
20324
+ try {
20325
+ if (fs15.existsSync(credPath)) {
20326
+ const raw = JSON.parse(fs15.readFileSync(credPath, "utf-8"));
20327
+ existingCreds = raw.apiKey ? { default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL } } : raw;
20328
+ }
20329
+ } catch {
20330
+ }
20331
+ existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL };
20332
+ fs15.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), {
20333
+ mode: 384
20334
+ });
20335
+ let effectiveCloud = null;
20336
+ if (profileName === "default") {
20337
+ const configPath = path17.join(home, ".node9", "config.json");
20338
+ let config = {};
20339
+ try {
20340
+ if (fs15.existsSync(configPath)) {
20341
+ config = JSON.parse(fs15.readFileSync(configPath, "utf-8"));
20342
+ }
20343
+ } catch {
20344
+ }
20345
+ if (!config.settings || typeof config.settings !== "object") {
20346
+ config.settings = {};
20347
+ }
20348
+ const s = config.settings;
20349
+ const approvers = s.approvers || {
20350
+ native: true,
20351
+ browser: true,
20352
+ cloud: true,
20353
+ terminal: true
20354
+ };
20355
+ if (opts.isLocal) {
20356
+ approvers.cloud = false;
20357
+ }
20358
+ s.approvers = approvers;
20359
+ if (!fs15.existsSync(path17.dirname(configPath))) {
20360
+ fs15.mkdirSync(path17.dirname(configPath), { recursive: true });
20361
+ }
20362
+ fs15.writeFileSync(configPath, JSON.stringify(config, null, 2), {
20363
+ mode: 384
20364
+ });
20365
+ effectiveCloud = approvers.cloud === true;
20366
+ }
20367
+ return { profileName, effectiveCloud };
20368
+ }
20369
+
20370
+ // src/cli.ts
20249
20371
  init_daemon2();
20250
- var import_chalk36 = __toESM(require("chalk"));
20372
+ var import_chalk37 = __toESM(require("chalk"));
20251
20373
  var import_fs66 = __toESM(require("fs"));
20252
20374
  var import_path64 = __toESM(require("path"));
20253
20375
  var import_os57 = __toESM(require("os"));
@@ -24122,18 +24244,7 @@ function registerInitCommand(program2) {
24122
24244
  console.log("");
24123
24245
  for (const agent of found) {
24124
24246
  console.log(import_chalk16.default.bold(`Wiring ${agent}...`));
24125
- if (agent === "claude") await setupClaude();
24126
- else if (agent === "gemini") await setupGemini();
24127
- else if (agent === "antigravity") await setupAntigravity();
24128
- else if (agent === "copilot") await setupCopilot();
24129
- else if (agent === "cursor") await setupCursor();
24130
- else if (agent === "codex") await setupCodex();
24131
- else if (agent === "windsurf") await setupWindsurf();
24132
- else if (agent === "vscode") await setupVSCode();
24133
- else if (agent === "claudeDesktop") await setupClaudeDesktop();
24134
- else if (agent === "opencode") await setupOpencode();
24135
- else if (agent === "pi") await setupPi();
24136
- else if (agent === "hermes") setupHermes();
24247
+ await setupAgent(agent);
24137
24248
  console.log("");
24138
24249
  }
24139
24250
  if ((process.platform === "darwin" || process.platform === "linux") && process.stdout.isTTY) {
@@ -24196,13 +24307,110 @@ function registerInitCommand(program2) {
24196
24307
  );
24197
24308
  }
24198
24309
 
24310
+ // src/cli/commands/connect.ts
24311
+ var import_http4 = __toESM(require("http"));
24312
+ var import_https7 = __toESM(require("https"));
24313
+ var import_url3 = require("url");
24314
+ var import_chalk17 = __toESM(require("chalk"));
24315
+ init_setup();
24316
+ init_sync();
24317
+ var DEFAULT_CONNECT_URL = "https://api.node9.ai/api/v1/cli/connect";
24318
+ function resolveConnectUrl(apiUrl) {
24319
+ if (apiUrl) return apiUrl;
24320
+ const base = process.env.NODE9_API_URL;
24321
+ if (base) return base.replace(/\/intercept\/?$/, "") + "/cli/connect";
24322
+ return DEFAULT_CONNECT_URL;
24323
+ }
24324
+ function postConnect(url, token) {
24325
+ return new Promise((resolve, reject) => {
24326
+ const body = JSON.stringify({ token });
24327
+ const u = new import_url3.URL(url);
24328
+ const lib = u.protocol === "http:" ? import_http4.default : import_https7.default;
24329
+ const req = lib.request(
24330
+ {
24331
+ method: "POST",
24332
+ hostname: u.hostname,
24333
+ port: u.port || (u.protocol === "http:" ? 80 : 443),
24334
+ path: u.pathname + u.search,
24335
+ headers: {
24336
+ "Content-Type": "application/json",
24337
+ "Content-Length": Buffer.byteLength(body)
24338
+ },
24339
+ timeout: 15e3
24340
+ },
24341
+ (res) => {
24342
+ let data = "";
24343
+ res.on("data", (c) => data += c);
24344
+ res.on("end", () => {
24345
+ const code = res.statusCode ?? 0;
24346
+ if (code >= 200 && code < 300) {
24347
+ try {
24348
+ resolve(JSON.parse(data));
24349
+ } catch {
24350
+ reject(new Error("Unexpected response from the server."));
24351
+ }
24352
+ } else if (code === 400 || code === 401) {
24353
+ reject(
24354
+ new Error(
24355
+ "This connect link expired or was already used \u2014 generate a new one in the dashboard."
24356
+ )
24357
+ );
24358
+ } else {
24359
+ reject(new Error(`Connect failed (HTTP ${code}).`));
24360
+ }
24361
+ });
24362
+ }
24363
+ );
24364
+ req.on("error", (e) => reject(e));
24365
+ req.on("timeout", () => {
24366
+ req.destroy();
24367
+ reject(new Error("Connection timed out."));
24368
+ });
24369
+ req.write(body);
24370
+ req.end();
24371
+ });
24372
+ }
24373
+ function registerConnectCommand(program2) {
24374
+ program2.command("connect").argument("<token>", "A connect token from the dashboard").option("--profile <name>", 'Save as a named profile (default: "default")').option("--api-url <url>", "Override the connect endpoint (self-host / dev)").description("Connect this machine to a node9 workspace using a dashboard token").action(async (token, options) => {
24375
+ let resp;
24376
+ try {
24377
+ resp = await postConnect(resolveConnectUrl(options.apiUrl), token);
24378
+ } catch (e) {
24379
+ console.error(import_chalk17.default.red(`\u2717 ${e instanceof Error ? e.message : "Connect failed."}`));
24380
+ process.exitCode = 1;
24381
+ return;
24382
+ }
24383
+ writeCredentialsAndConfig(resp.apiKey, { profileName: options.profile });
24384
+ process.env.NODE9_NONINTERACTIVE = "1";
24385
+ let wired = [];
24386
+ try {
24387
+ wired = await setupDetectedAgents();
24388
+ } catch {
24389
+ }
24390
+ if (!isTestingMode()) {
24391
+ try {
24392
+ await runCloudSync();
24393
+ } catch {
24394
+ }
24395
+ }
24396
+ console.log(import_chalk17.default.green(`\u2705 Connected to ${resp.workspaceName}`));
24397
+ if (wired.length) {
24398
+ console.log(import_chalk17.default.gray(` Wired: ${wired.join(", ")}`));
24399
+ } else {
24400
+ console.log(
24401
+ import_chalk17.default.gray(" No agents detected yet \u2014 run `node9 init` after installing one.")
24402
+ );
24403
+ }
24404
+ });
24405
+ }
24406
+
24199
24407
  // src/cli/commands/undo.ts
24200
24408
  var import_path50 = __toESM(require("path"));
24201
- var import_chalk18 = __toESM(require("chalk"));
24409
+ var import_chalk19 = __toESM(require("chalk"));
24202
24410
 
24203
24411
  // src/tui/undo-navigator.ts
24204
24412
  var import_readline3 = __toESM(require("readline"));
24205
- var import_chalk17 = __toESM(require("chalk"));
24413
+ var import_chalk18 = __toESM(require("chalk"));
24206
24414
  var RESET = "\x1B[0m";
24207
24415
  var BOLD = "\x1B[1m";
24208
24416
  var CLEAR_SCREEN = "\x1B[2J\x1B[H";
@@ -24220,15 +24428,15 @@ function renderDiff(raw) {
24220
24428
  );
24221
24429
  for (const line of lines) {
24222
24430
  if (line.startsWith("+++") || line.startsWith("---")) {
24223
- process.stdout.write(import_chalk17.default.bold(line) + "\n");
24431
+ process.stdout.write(import_chalk18.default.bold(line) + "\n");
24224
24432
  } else if (line.startsWith("+")) {
24225
- process.stdout.write(import_chalk17.default.green(line) + "\n");
24433
+ process.stdout.write(import_chalk18.default.green(line) + "\n");
24226
24434
  } else if (line.startsWith("-")) {
24227
- process.stdout.write(import_chalk17.default.red(line) + "\n");
24435
+ process.stdout.write(import_chalk18.default.red(line) + "\n");
24228
24436
  } else if (line.startsWith("@@")) {
24229
- process.stdout.write(import_chalk17.default.cyan(line) + "\n");
24437
+ process.stdout.write(import_chalk18.default.cyan(line) + "\n");
24230
24438
  } else {
24231
- process.stdout.write(import_chalk17.default.gray(line) + "\n");
24439
+ process.stdout.write(import_chalk18.default.gray(line) + "\n");
24232
24440
  }
24233
24441
  }
24234
24442
  }
@@ -24247,23 +24455,23 @@ function render(entries, idx) {
24247
24455
  const step = idx + 1;
24248
24456
  process.stdout.write(CLEAR_SCREEN);
24249
24457
  process.stdout.write(
24250
- import_chalk17.default.magenta.bold(`\u23EA Node9 Undo`) + import_chalk17.default.gray(` \u2500\u2500 step ${step} of ${total}`) + (entry.files?.length ? import_chalk17.default.gray(
24458
+ import_chalk18.default.magenta.bold(`\u23EA Node9 Undo`) + import_chalk18.default.gray(` \u2500\u2500 step ${step} of ${total}`) + (entry.files?.length ? import_chalk18.default.gray(
24251
24459
  ` \u2500\u2500 ${entry.files.slice(0, 2).join(", ")}${entry.files.length > 2 ? ` +${entry.files.length - 2} more` : ""}`
24252
24460
  ) : "") + "\n\n"
24253
24461
  );
24254
24462
  process.stdout.write(
24255
- ` ${BOLD}Tool:${RESET} ${import_chalk17.default.cyan(entry.tool)}` + (entry.argsSummary ? import_chalk17.default.gray(" \u2192 " + entry.argsSummary) : "") + "\n"
24463
+ ` ${BOLD}Tool:${RESET} ${import_chalk18.default.cyan(entry.tool)}` + (entry.argsSummary ? import_chalk18.default.gray(" \u2192 " + entry.argsSummary) : "") + "\n"
24256
24464
  );
24257
- process.stdout.write(` ${BOLD}When:${RESET} ${import_chalk17.default.gray(formatAge(entry.timestamp))}
24465
+ process.stdout.write(` ${BOLD}When:${RESET} ${import_chalk18.default.gray(formatAge(entry.timestamp))}
24258
24466
  `);
24259
- process.stdout.write(` ${BOLD}Dir: ${RESET} ${import_chalk17.default.gray(entry.cwd)}
24467
+ process.stdout.write(` ${BOLD}Dir: ${RESET} ${import_chalk18.default.gray(entry.cwd)}
24260
24468
  `);
24261
24469
  if (entry.files && entry.files.length > 0) {
24262
- process.stdout.write(` ${BOLD}Files:${RESET} ${import_chalk17.default.gray(entry.files.join(", "))}
24470
+ process.stdout.write(` ${BOLD}Files:${RESET} ${import_chalk18.default.gray(entry.files.join(", "))}
24263
24471
  `);
24264
24472
  }
24265
24473
  if (idx < total - 1 && isSessionBoundary(entries, idx + 1)) {
24266
- process.stdout.write(import_chalk17.default.gray("\n \u2500\u2500 session boundary above \u2500\u2500\n"));
24474
+ process.stdout.write(import_chalk18.default.gray("\n \u2500\u2500 session boundary above \u2500\u2500\n"));
24267
24475
  }
24268
24476
  process.stdout.write("\n");
24269
24477
  const diff = entry.diff ?? computeUndoDiff(entry.hash, entry.cwd);
@@ -24271,12 +24479,12 @@ function render(entries, idx) {
24271
24479
  renderDiff(diff);
24272
24480
  } else {
24273
24481
  process.stdout.write(
24274
- import_chalk17.default.gray(" (no diff \u2014 working tree may already match this snapshot)\n")
24482
+ import_chalk18.default.gray(" (no diff \u2014 working tree may already match this snapshot)\n")
24275
24483
  );
24276
24484
  }
24277
24485
  process.stdout.write("\n");
24278
24486
  process.stdout.write(
24279
- import_chalk17.default.gray(" ") + (idx < total - 1 ? import_chalk17.default.white("[\u2190] older") : import_chalk17.default.gray("[\u2190] older")) + import_chalk17.default.gray(" ") + (idx > 0 ? import_chalk17.default.white("[\u2192] newer") : import_chalk17.default.gray("[\u2192] newer")) + import_chalk17.default.gray(" ") + import_chalk17.default.green("[\u21B5] restore here") + import_chalk17.default.gray(" ") + import_chalk17.default.yellow("[s] session start") + import_chalk17.default.gray(" ") + import_chalk17.default.gray("[q] quit") + "\n"
24487
+ import_chalk18.default.gray(" ") + (idx < total - 1 ? import_chalk18.default.white("[\u2190] older") : import_chalk18.default.gray("[\u2190] older")) + import_chalk18.default.gray(" ") + (idx > 0 ? import_chalk18.default.white("[\u2192] newer") : import_chalk18.default.gray("[\u2192] newer")) + import_chalk18.default.gray(" ") + import_chalk18.default.green("[\u21B5] restore here") + import_chalk18.default.gray(" ") + import_chalk18.default.yellow("[s] session start") + import_chalk18.default.gray(" ") + import_chalk18.default.gray("[q] quit") + "\n"
24280
24488
  );
24281
24489
  }
24282
24490
  async function runUndoNavigator(entries) {
@@ -24330,19 +24538,19 @@ async function runUndoNavigator(entries) {
24330
24538
  cleanup();
24331
24539
  process.stdout.write(CLEAR_SCREEN);
24332
24540
  const entry = display[idx];
24333
- process.stdout.write(import_chalk17.default.magenta.bold("\n\u23EA Restoring snapshot...\n\n"));
24541
+ process.stdout.write(import_chalk18.default.magenta.bold("\n\u23EA Restoring snapshot...\n\n"));
24334
24542
  if (applyUndo(entry.hash, entry.cwd)) {
24335
- process.stdout.write(import_chalk17.default.green("\u2705 Reverted successfully.\n\n"));
24543
+ process.stdout.write(import_chalk18.default.green("\u2705 Reverted successfully.\n\n"));
24336
24544
  resolve({ restored: true });
24337
24545
  } else {
24338
- process.stdout.write(import_chalk17.default.red("\u274C Undo failed.\n\n"));
24546
+ process.stdout.write(import_chalk18.default.red("\u274C Undo failed.\n\n"));
24339
24547
  resolve({ restored: false });
24340
24548
  }
24341
24549
  } else if (name === "q" || key?.ctrl && name === "c") {
24342
24550
  done = true;
24343
24551
  cleanup();
24344
24552
  process.stdout.write(CLEAR_SCREEN);
24345
- process.stdout.write(import_chalk17.default.gray("\nCancelled.\n\n"));
24553
+ process.stdout.write(import_chalk18.default.gray("\nCancelled.\n\n"));
24346
24554
  resolve({ restored: false });
24347
24555
  }
24348
24556
  };
@@ -24378,39 +24586,39 @@ function registerUndoCommand(program2) {
24378
24586
  if (history.length === 0) {
24379
24587
  if (!options.all && allHistory.length > 0) {
24380
24588
  console.log(
24381
- import_chalk18.default.yellow(
24589
+ import_chalk19.default.yellow(
24382
24590
  `
24383
24591
  \u2139\uFE0F No snapshots found for the current directory (${process.cwd()}).
24384
- Run ${import_chalk18.default.cyan("node9 undo --all")} to see snapshots from all projects.
24592
+ Run ${import_chalk19.default.cyan("node9 undo --all")} to see snapshots from all projects.
24385
24593
  `
24386
24594
  )
24387
24595
  );
24388
24596
  } else {
24389
- console.log(import_chalk18.default.yellow("\n\u2139\uFE0F No undo snapshots found.\n"));
24597
+ console.log(import_chalk19.default.yellow("\n\u2139\uFE0F No undo snapshots found.\n"));
24390
24598
  }
24391
24599
  return;
24392
24600
  }
24393
24601
  if (options.list) {
24394
- console.log(import_chalk18.default.magenta.bold("\n\u23EA Snapshot History\n"));
24602
+ console.log(import_chalk19.default.magenta.bold("\n\u23EA Snapshot History\n"));
24395
24603
  console.log(
24396
- import_chalk18.default.gray(
24604
+ import_chalk19.default.gray(
24397
24605
  ` ${"#".padEnd(3)} ${"File / Command".padEnd(30)} ${"Tool".padEnd(8)} ${"When".padEnd(10)} Dir`
24398
24606
  )
24399
24607
  );
24400
- console.log(import_chalk18.default.gray(" " + "\u2500".repeat(80)));
24608
+ console.log(import_chalk19.default.gray(" " + "\u2500".repeat(80)));
24401
24609
  const display = [...history].reverse();
24402
24610
  let prevTs = null;
24403
24611
  for (let i = 0; i < display.length; i++) {
24404
24612
  const e = display[i];
24405
24613
  const isGap = prevTs !== null && prevTs - e.timestamp > 6e4;
24406
- if (isGap) console.log(import_chalk18.default.gray(" \u2500\u2500 earlier \u2500\u2500"));
24614
+ if (isGap) console.log(import_chalk19.default.gray(" \u2500\u2500 earlier \u2500\u2500"));
24407
24615
  const label2 = (e.argsSummary || e.files?.[0] || "\u2014").slice(0, 30).padEnd(30);
24408
24616
  const tool = e.tool.slice(0, 8).padEnd(8);
24409
24617
  const when = formatAge2(e.timestamp).padEnd(10);
24410
24618
  const dir = e.cwd.length > 30 ? "\u2026" + e.cwd.slice(-29) : e.cwd;
24411
24619
  console.log(
24412
- import_chalk18.default.white(
24413
- ` ${String(i + 1).padEnd(3)} ${label2} ${import_chalk18.default.cyan(tool)} ${import_chalk18.default.gray(when)} ${import_chalk18.default.gray(dir)}`
24620
+ import_chalk19.default.white(
24621
+ ` ${String(i + 1).padEnd(3)} ${label2} ${import_chalk19.default.cyan(tool)} ${import_chalk19.default.gray(when)} ${import_chalk19.default.gray(dir)}`
24414
24622
  )
24415
24623
  );
24416
24624
  prevTs = e.timestamp;
@@ -24423,7 +24631,7 @@ function registerUndoCommand(program2) {
24423
24631
  const idx = history.length - steps;
24424
24632
  if (idx < 0) {
24425
24633
  console.log(
24426
- import_chalk18.default.yellow(
24634
+ import_chalk19.default.yellow(
24427
24635
  `
24428
24636
  \u2139\uFE0F Only ${history.length} snapshot(s) available, cannot go back ${steps}.
24429
24637
  `
@@ -24434,47 +24642,47 @@ function registerUndoCommand(program2) {
24434
24642
  const snapshot = history[idx];
24435
24643
  const ageStr = formatAge2(snapshot.timestamp);
24436
24644
  console.log(
24437
- import_chalk18.default.magenta.bold(`
24645
+ import_chalk19.default.magenta.bold(`
24438
24646
  \u23EA Node9 Undo${steps > 1 ? ` (${steps} steps back)` : ""}`)
24439
24647
  );
24440
24648
  console.log(
24441
- import_chalk18.default.white(
24442
- ` Tool: ${import_chalk18.default.cyan(snapshot.tool)}${snapshot.argsSummary ? import_chalk18.default.gray(" \u2192 " + snapshot.argsSummary) : ""}`
24649
+ import_chalk19.default.white(
24650
+ ` Tool: ${import_chalk19.default.cyan(snapshot.tool)}${snapshot.argsSummary ? import_chalk19.default.gray(" \u2192 " + snapshot.argsSummary) : ""}`
24443
24651
  )
24444
24652
  );
24445
- console.log(import_chalk18.default.white(` When: ${import_chalk18.default.gray(ageStr)}`));
24446
- console.log(import_chalk18.default.white(` Dir: ${import_chalk18.default.gray(snapshot.cwd)}`));
24653
+ console.log(import_chalk19.default.white(` When: ${import_chalk19.default.gray(ageStr)}`));
24654
+ console.log(import_chalk19.default.white(` Dir: ${import_chalk19.default.gray(snapshot.cwd)}`));
24447
24655
  if (steps > 1)
24448
24656
  console.log(
24449
- import_chalk18.default.yellow(` Note: This will also undo the ${steps - 1} action(s) after it.`)
24657
+ import_chalk19.default.yellow(` Note: This will also undo the ${steps - 1} action(s) after it.`)
24450
24658
  );
24451
24659
  console.log("");
24452
24660
  const diff = snapshot.diff ?? computeUndoDiff(snapshot.hash, snapshot.cwd);
24453
24661
  if (diff) {
24454
24662
  const lines = diff.split("\n").filter((l) => !l.startsWith("diff --git") && !l.startsWith("index "));
24455
24663
  for (const line of lines) {
24456
- if (line.startsWith("+++") || line.startsWith("---")) console.log(import_chalk18.default.bold(line));
24457
- else if (line.startsWith("+")) console.log(import_chalk18.default.green(line));
24458
- else if (line.startsWith("-")) console.log(import_chalk18.default.red(line));
24459
- else if (line.startsWith("@@")) console.log(import_chalk18.default.cyan(line));
24460
- else console.log(import_chalk18.default.gray(line));
24664
+ if (line.startsWith("+++") || line.startsWith("---")) console.log(import_chalk19.default.bold(line));
24665
+ else if (line.startsWith("+")) console.log(import_chalk19.default.green(line));
24666
+ else if (line.startsWith("-")) console.log(import_chalk19.default.red(line));
24667
+ else if (line.startsWith("@@")) console.log(import_chalk19.default.cyan(line));
24668
+ else console.log(import_chalk19.default.gray(line));
24461
24669
  }
24462
24670
  console.log("");
24463
24671
  } else {
24464
24672
  console.log(
24465
- import_chalk18.default.gray(" (no diff available \u2014 working tree may already match snapshot)\n")
24673
+ import_chalk19.default.gray(" (no diff available \u2014 working tree may already match snapshot)\n")
24466
24674
  );
24467
24675
  }
24468
24676
  const { confirm: confirm3 } = await import("@inquirer/prompts");
24469
24677
  const proceed = await confirm3({ message: `Revert to this snapshot?`, default: false });
24470
24678
  if (proceed) {
24471
24679
  if (applyUndo(snapshot.hash, snapshot.cwd)) {
24472
- console.log(import_chalk18.default.green("\n\u2705 Reverted successfully.\n"));
24680
+ console.log(import_chalk19.default.green("\n\u2705 Reverted successfully.\n"));
24473
24681
  } else {
24474
- console.error(import_chalk18.default.red("\n\u274C Undo failed. Ensure you are in a Git repository.\n"));
24682
+ console.error(import_chalk19.default.red("\n\u274C Undo failed. Ensure you are in a Git repository.\n"));
24475
24683
  }
24476
24684
  } else {
24477
- console.log(import_chalk18.default.gray("\nCancelled.\n"));
24685
+ console.log(import_chalk19.default.gray("\nCancelled.\n"));
24478
24686
  }
24479
24687
  return;
24480
24688
  }
@@ -24484,7 +24692,7 @@ function registerUndoCommand(program2) {
24484
24692
 
24485
24693
  // src/mcp-gateway/index.ts
24486
24694
  var import_readline4 = __toESM(require("readline"));
24487
- var import_chalk19 = __toESM(require("chalk"));
24695
+ var import_chalk20 = __toESM(require("chalk"));
24488
24696
  var import_child_process10 = require("child_process");
24489
24697
  var import_execa3 = require("execa");
24490
24698
  init_orchestrator();
@@ -24620,13 +24828,13 @@ async function runMcpGateway(upstreamCommand) {
24620
24828
  const prov = checkProvenance(executable);
24621
24829
  if (prov.trustLevel === "suspect") {
24622
24830
  console.error(
24623
- import_chalk19.default.red(
24831
+ import_chalk20.default.red(
24624
24832
  `\u26A0\uFE0F Node9: Upstream MCP server binary is suspect \u2014 ${prov.reason} (${prov.resolvedPath})`
24625
24833
  )
24626
24834
  );
24627
- console.error(import_chalk19.default.red(" Verify this binary is trusted before proceeding."));
24835
+ console.error(import_chalk20.default.red(" Verify this binary is trusted before proceeding."));
24628
24836
  }
24629
- console.error(import_chalk19.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
24837
+ console.error(import_chalk20.default.green(`\u{1F680} Node9 MCP Gateway: Monitoring [${upstreamCommand}]`));
24630
24838
  const UPSTREAM_INJECTOR_VARS = /* @__PURE__ */ new Set([
24631
24839
  "NODE_OPTIONS",
24632
24840
  "NODE_PATH",
@@ -24739,10 +24947,10 @@ async function runMcpGateway(upstreamCommand) {
24739
24947
  mcpServer
24740
24948
  });
24741
24949
  if (!result.approved) {
24742
- console.error(import_chalk19.default.red(`
24950
+ console.error(import_chalk20.default.red(`
24743
24951
  \u{1F6D1} Node9 MCP Gateway: Action Blocked`));
24744
- console.error(import_chalk19.default.gray(` Tool: ${toolName}`));
24745
- console.error(import_chalk19.default.gray(` Reason: ${result.reason ?? "Security Policy"}
24952
+ console.error(import_chalk20.default.gray(` Tool: ${toolName}`));
24953
+ console.error(import_chalk20.default.gray(` Reason: ${result.reason ?? "Security Policy"}
24746
24954
  `));
24747
24955
  const blockedByLabel = result.blockedByLabel ?? result.reason ?? "Security Policy";
24748
24956
  const isHumanDecision = blockedByLabel.toLowerCase().includes("user") || blockedByLabel.toLowerCase().includes("daemon") || blockedByLabel.toLowerCase().includes("decision");
@@ -24855,7 +25063,7 @@ async function runMcpGateway(upstreamCommand) {
24855
25063
  updatePin(serverKey, upstreamCommand, currentHash, toolNames);
24856
25064
  pinState = "validated";
24857
25065
  console.error(
24858
- import_chalk19.default.green(
25066
+ import_chalk20.default.green(
24859
25067
  `\u{1F512} Node9: Pinned ${toolNames.length} tool definition(s) for this MCP server`
24860
25068
  )
24861
25069
  );
@@ -24868,11 +25076,11 @@ async function runMcpGateway(upstreamCommand) {
24868
25076
  } else if (pinStatus === "corrupt") {
24869
25077
  pinState = "quarantined";
24870
25078
  console.error(
24871
- import_chalk19.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
25079
+ import_chalk20.default.red("\n\u{1F6A8} Node9: MCP pin file is corrupt or unreadable \u2014 session quarantined!")
24872
25080
  );
24873
- console.error(import_chalk19.default.red(" Tool calls are blocked until the pin file is repaired."));
25081
+ console.error(import_chalk20.default.red(" Tool calls are blocked until the pin file is repaired."));
24874
25082
  console.error(
24875
- import_chalk19.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
25083
+ import_chalk20.default.yellow(` Run: node9 mcp pin reset (to clear and re-pin on next connect)
24876
25084
  `)
24877
25085
  );
24878
25086
  const errorResponse = {
@@ -24889,13 +25097,13 @@ async function runMcpGateway(upstreamCommand) {
24889
25097
  } else {
24890
25098
  pinState = "quarantined";
24891
25099
  console.error(
24892
- import_chalk19.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
25100
+ import_chalk20.default.red("\n\u{1F6A8} Node9: MCP tool definitions have changed since last verified!")
24893
25101
  );
24894
25102
  console.error(
24895
- import_chalk19.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
25103
+ import_chalk20.default.red(" This could indicate a supply chain attack (tool poisoning / rug pull).")
24896
25104
  );
24897
- console.error(import_chalk19.default.red(" Session quarantined \u2014 all tool calls blocked."));
24898
- console.error(import_chalk19.default.yellow(` Run: node9 mcp pin update ${serverKey}
25105
+ console.error(import_chalk20.default.red(" Session quarantined \u2014 all tool calls blocked."));
25106
+ console.error(import_chalk20.default.yellow(` Run: node9 mcp pin update ${serverKey}
24899
25107
  `));
24900
25108
  reportPinMismatchToCloud(serverKey, clientName);
24901
25109
  const errorResponse = {
@@ -24939,7 +25147,7 @@ async function runMcpGateway(upstreamCommand) {
24939
25147
  const toolName = callId !== void 0 ? pendingCallNames.get(callId) ?? "unknown" : "unknown";
24940
25148
  if (callId !== void 0) pendingCallNames.delete(callId);
24941
25149
  console.error(
24942
- import_chalk19.default.yellow(
25150
+ import_chalk20.default.yellow(
24943
25151
  `\u26A1 Node9: Large MCP response from '${toolName}' (${(line.length / 1024).toFixed(0)}KB) \u2014 context window enlarged`
24944
25152
  )
24945
25153
  );
@@ -25906,7 +26114,7 @@ function registerMcpServerCommand(program2) {
25906
26114
  }
25907
26115
 
25908
26116
  // src/cli/commands/trust.ts
25909
- var import_chalk20 = __toESM(require("chalk"));
26117
+ var import_chalk21 = __toESM(require("chalk"));
25910
26118
  init_trusted_hosts();
25911
26119
  function isValidHost(host) {
25912
26120
  return /^(\*\.)?[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(host);
@@ -25917,51 +26125,51 @@ function registerTrustCommand(program2) {
25917
26125
  const normalized = normalizeHost(host.trim());
25918
26126
  if (!isValidHost(normalized)) {
25919
26127
  console.error(
25920
- import_chalk20.default.red(`
26128
+ import_chalk21.default.red(`
25921
26129
  \u274C Invalid host: "${host}"
25922
- `) + import_chalk20.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
26130
+ `) + import_chalk21.default.gray(" Use an FQDN like api.mycompany.com or *.mycompany.com\n")
25923
26131
  );
25924
26132
  process.exit(1);
25925
26133
  }
25926
26134
  addTrustedHost(normalized);
25927
- console.log(import_chalk20.default.green(`
26135
+ console.log(import_chalk21.default.green(`
25928
26136
  \u2705 ${normalized} added to trusted hosts.`));
25929
26137
  console.log(
25930
- import_chalk20.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
26138
+ import_chalk21.default.gray(" Pipe-chain blocks to this host: critical \u2192 review, high \u2192 allow\n")
25931
26139
  );
25932
26140
  });
25933
26141
  trustCmd.command("remove <host>").description("Remove a trusted host").action((host) => {
25934
26142
  const normalized = normalizeHost(host.trim());
25935
26143
  const removed = removeTrustedHost(normalized);
25936
26144
  if (!removed) {
25937
- console.error(import_chalk20.default.yellow(`
26145
+ console.error(import_chalk21.default.yellow(`
25938
26146
  \u26A0\uFE0F "${normalized}" is not in the trusted hosts list.
25939
26147
  `));
25940
26148
  process.exit(1);
25941
26149
  }
25942
- console.log(import_chalk20.default.green(`
26150
+ console.log(import_chalk21.default.green(`
25943
26151
  \u2705 ${normalized} removed from trusted hosts.
25944
26152
  `));
25945
26153
  });
25946
26154
  trustCmd.command("list").description("Show all trusted hosts").action(() => {
25947
26155
  const hosts = readTrustedHosts();
25948
26156
  if (hosts.length === 0) {
25949
- console.log(import_chalk20.default.gray("\n No trusted hosts configured.\n"));
25950
- console.log(` Add one: ${import_chalk20.default.cyan("node9 trust add api.mycompany.com")}
26157
+ console.log(import_chalk21.default.gray("\n No trusted hosts configured.\n"));
26158
+ console.log(` Add one: ${import_chalk21.default.cyan("node9 trust add api.mycompany.com")}
25951
26159
  `);
25952
26160
  return;
25953
26161
  }
25954
- console.log(import_chalk20.default.bold("\n\u{1F513} Trusted Hosts\n"));
26162
+ console.log(import_chalk21.default.bold("\n\u{1F513} Trusted Hosts\n"));
25955
26163
  for (const entry of hosts) {
25956
26164
  const date = new Date(entry.addedAt).toLocaleDateString();
25957
- console.log(` ${import_chalk20.default.cyan(entry.host.padEnd(40))} ${import_chalk20.default.gray(`added ${date}`)}`);
26165
+ console.log(` ${import_chalk21.default.cyan(entry.host.padEnd(40))} ${import_chalk21.default.gray(`added ${date}`)}`);
25958
26166
  }
25959
26167
  console.log("");
25960
26168
  });
25961
26169
  }
25962
26170
 
25963
26171
  // src/cli/commands/mcp-pin.ts
25964
- var import_chalk21 = __toESM(require("chalk"));
26172
+ var import_chalk22 = __toESM(require("chalk"));
25965
26173
  init_mcp_pin();
25966
26174
  var import_fs54 = __toESM(require("fs"));
25967
26175
  function registerMcpPinCommand(program2) {
@@ -25982,14 +26190,14 @@ function registerMcpPinCommand(program2) {
25982
26190
  }
25983
26191
  }
25984
26192
  if (repoCorrupt) {
25985
- console.error(import_chalk21.default.red(`
26193
+ console.error(import_chalk22.default.red(`
25986
26194
  \u274C Repo pin file at ${found.path} is corrupt or unreadable.`));
25987
26195
  process.exit(1);
25988
26196
  }
25989
26197
  if (!homeResult.ok && homeResult.reason === "corrupt") {
25990
- console.error(import_chalk21.default.red(`
26198
+ console.error(import_chalk22.default.red(`
25991
26199
  \u274C Home pin file is corrupt: ${homeResult.detail}`));
25992
- console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
26200
+ console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
25993
26201
  process.exit(1);
25994
26202
  }
25995
26203
  const homeEntries = homeResult.ok ? homeResult.pins.servers : {};
@@ -26001,25 +26209,25 @@ function registerMcpPinCommand(program2) {
26001
26209
  merged.set(key, { entry, source: "repo" });
26002
26210
  }
26003
26211
  if (merged.size === 0) {
26004
- console.log(import_chalk21.default.gray("\nNo MCP servers are pinned yet."));
26212
+ console.log(import_chalk22.default.gray("\nNo MCP servers are pinned yet."));
26005
26213
  console.log(
26006
- import_chalk21.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
26214
+ import_chalk22.default.gray("Pins are created automatically when the MCP gateway first connects.\n")
26007
26215
  );
26008
26216
  return;
26009
26217
  }
26010
- console.log(import_chalk21.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
26218
+ console.log(import_chalk22.default.bold("\n\u{1F512} Pinned MCP Servers\n"));
26011
26219
  const showSource = found.source === "repo";
26012
26220
  for (const [key, { entry, source }] of merged) {
26013
- const tag = showSource ? ` ${import_chalk21.default.yellow(`[${source}]`)}` : "";
26014
- console.log(` ${import_chalk21.default.cyan(key)}${tag} ${import_chalk21.default.gray(entry.label)}`);
26015
- console.log(` Tools (${entry.toolCount}): ${import_chalk21.default.white(entry.toolNames.join(", "))}`);
26016
- console.log(` Hash: ${import_chalk21.default.gray(entry.toolsHash.slice(0, 16))}...`);
26017
- console.log(` Pinned: ${import_chalk21.default.gray(entry.pinnedAt)}`);
26221
+ const tag = showSource ? ` ${import_chalk22.default.yellow(`[${source}]`)}` : "";
26222
+ console.log(` ${import_chalk22.default.cyan(key)}${tag} ${import_chalk22.default.gray(entry.label)}`);
26223
+ console.log(` Tools (${entry.toolCount}): ${import_chalk22.default.white(entry.toolNames.join(", "))}`);
26224
+ console.log(` Hash: ${import_chalk22.default.gray(entry.toolsHash.slice(0, 16))}...`);
26225
+ console.log(` Pinned: ${import_chalk22.default.gray(entry.pinnedAt)}`);
26018
26226
  console.log("");
26019
26227
  }
26020
26228
  if (showSource) {
26021
- console.log(import_chalk21.default.gray(` [repo] entries come from ${found.path}`));
26022
- console.log(import_chalk21.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
26229
+ console.log(import_chalk22.default.gray(` [repo] entries come from ${found.path}`));
26230
+ console.log(import_chalk22.default.gray(" [home] entries come from ~/.node9/mcp-pins.json\n"));
26023
26231
  }
26024
26232
  });
26025
26233
  pinSubCmd.command("promote <serverKey>").description(
@@ -26029,22 +26237,22 @@ function registerMcpPinCommand(program2) {
26029
26237
  const { repoPath, created } = promotePin(serverKey, process.cwd());
26030
26238
  if (created) {
26031
26239
  console.log(
26032
- import_chalk21.default.green(
26240
+ import_chalk22.default.green(
26033
26241
  `
26034
- \u2705 Created ${repoPath} with the promoted pin for ${import_chalk21.default.cyan(serverKey)}.`
26242
+ \u2705 Created ${repoPath} with the promoted pin for ${import_chalk22.default.cyan(serverKey)}.`
26035
26243
  )
26036
26244
  );
26037
26245
  } else {
26038
- console.log(import_chalk21.default.green(`
26039
- \u2705 Promoted ${import_chalk21.default.cyan(serverKey)} into ${repoPath}.`));
26246
+ console.log(import_chalk22.default.green(`
26247
+ \u2705 Promoted ${import_chalk22.default.cyan(serverKey)} into ${repoPath}.`));
26040
26248
  }
26041
- console.log(import_chalk21.default.gray(" Review the change and commit it:"));
26042
- console.log(import_chalk21.default.cyan(` git add ${repoPath}`));
26043
- console.log(import_chalk21.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
26249
+ console.log(import_chalk22.default.gray(" Review the change and commit it:"));
26250
+ console.log(import_chalk22.default.cyan(` git add ${repoPath}`));
26251
+ console.log(import_chalk22.default.cyan(` git commit -m "pin ${serverKey} (node9)"`));
26044
26252
  console.log("");
26045
26253
  } catch (err2) {
26046
26254
  const msg = err2 instanceof Error ? err2.message : String(err2);
26047
- console.error(import_chalk21.default.red(`
26255
+ console.error(import_chalk22.default.red(`
26048
26256
  \u274C ${msg}
26049
26257
  `));
26050
26258
  process.exit(1);
@@ -26057,138 +26265,138 @@ function registerMcpPinCommand(program2) {
26057
26265
  try {
26058
26266
  pins = readMcpPins();
26059
26267
  } catch {
26060
- console.error(import_chalk21.default.red("\n\u274C Pin file is corrupt."));
26061
- console.error(import_chalk21.default.yellow(" Run: node9 mcp pin reset\n"));
26268
+ console.error(import_chalk22.default.red("\n\u274C Pin file is corrupt."));
26269
+ console.error(import_chalk22.default.yellow(" Run: node9 mcp pin reset\n"));
26062
26270
  process.exit(1);
26063
26271
  }
26064
26272
  if (!pins.servers[serverKey]) {
26065
- console.error(import_chalk21.default.red(`
26273
+ console.error(import_chalk22.default.red(`
26066
26274
  \u274C No pin found for server key "${serverKey}"
26067
26275
  `));
26068
- console.error(`Run ${import_chalk21.default.cyan("node9 mcp pin list")} to see pinned servers.
26276
+ console.error(`Run ${import_chalk22.default.cyan("node9 mcp pin list")} to see pinned servers.
26069
26277
  `);
26070
26278
  process.exit(1);
26071
26279
  }
26072
26280
  const label2 = pins.servers[serverKey].label;
26073
26281
  removePin(serverKey);
26074
- console.log(import_chalk21.default.green(`
26075
- \u{1F513} Pin removed for ${import_chalk21.default.cyan(serverKey)}`));
26076
- console.log(import_chalk21.default.gray(` Server: ${label2}`));
26077
- console.log(import_chalk21.default.gray(" Next connection will re-pin with current tool definitions.\n"));
26282
+ console.log(import_chalk22.default.green(`
26283
+ \u{1F513} Pin removed for ${import_chalk22.default.cyan(serverKey)}`));
26284
+ console.log(import_chalk22.default.gray(` Server: ${label2}`));
26285
+ console.log(import_chalk22.default.gray(" Next connection will re-pin with current tool definitions.\n"));
26078
26286
  });
26079
26287
  pinSubCmd.command("reset").description("Clear all MCP pins (next connection to each server will re-pin)").action(() => {
26080
26288
  const result = readMcpPinsSafe();
26081
26289
  if (!result.ok && result.reason === "missing") {
26082
- console.log(import_chalk21.default.gray("\nNo pins to clear.\n"));
26290
+ console.log(import_chalk22.default.gray("\nNo pins to clear.\n"));
26083
26291
  return;
26084
26292
  }
26085
26293
  const count = result.ok ? Object.keys(result.pins.servers).length : "?";
26086
26294
  clearAllPins();
26087
- console.log(import_chalk21.default.green(`
26295
+ console.log(import_chalk22.default.green(`
26088
26296
  \u{1F513} Cleared ${count} MCP pin(s).`));
26089
- console.log(import_chalk21.default.gray(" Next connection to each server will re-pin.\n"));
26297
+ console.log(import_chalk22.default.gray(" Next connection to each server will re-pin.\n"));
26090
26298
  });
26091
26299
  }
26092
26300
 
26093
26301
  // src/cli/commands/sync.ts
26094
- var import_chalk22 = __toESM(require("chalk"));
26302
+ var import_chalk23 = __toESM(require("chalk"));
26095
26303
  init_sync();
26096
26304
  function registerSyncCommand(program2) {
26097
26305
  const policy = program2.command("policy").description("Manage cloud policy rules");
26098
26306
  policy.command("push").description("Push this machine's effective policy to the node9 dashboard").action(async () => {
26099
- process.stdout.write(import_chalk22.default.cyan("Pushing policy to the dashboard\u2026"));
26307
+ process.stdout.write(import_chalk23.default.cyan("Pushing policy to the dashboard\u2026"));
26100
26308
  const result = await runPolicyPush();
26101
26309
  process.stdout.write("\n");
26102
26310
  if (!result.ok) {
26103
- console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
26311
+ console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
26104
26312
  process.exit(1);
26105
26313
  }
26106
- console.log(import_chalk22.default.green("\u2713 Policy mirrored to the dashboard"));
26107
- console.log(import_chalk22.default.gray(" See it under Security Policy \u2192 Machines"));
26314
+ console.log(import_chalk23.default.green("\u2713 Policy mirrored to the dashboard"));
26315
+ console.log(import_chalk23.default.gray(" See it under Security Policy \u2192 Machines"));
26108
26316
  });
26109
26317
  policy.command("sync").description("Sync cloud policy rules to local cache (~/.node9/rules-cache.json)").action(async () => {
26110
- process.stdout.write(import_chalk22.default.cyan("Syncing cloud policy rules\u2026"));
26318
+ process.stdout.write(import_chalk23.default.cyan("Syncing cloud policy rules\u2026"));
26111
26319
  const result = await runCloudSync();
26112
26320
  process.stdout.write("\n");
26113
26321
  if (!result.ok) {
26114
- console.error(import_chalk22.default.red(`\u2717 ${result.reason}`));
26322
+ console.error(import_chalk23.default.red(`\u2717 ${result.reason}`));
26115
26323
  process.exit(1);
26116
26324
  }
26117
26325
  if (result.unchanged) {
26118
26326
  console.log(
26119
- import_chalk22.default.green(
26327
+ import_chalk23.default.green(
26120
26328
  `\u2713 Already up to date \u2014 ${result.rules} rule${result.rules === 1 ? "" : "s"} cached`
26121
26329
  )
26122
26330
  );
26123
- console.log(import_chalk22.default.gray(` Cached at: ${result.fetchedAt}`));
26124
- console.log(import_chalk22.default.gray(` Server returned 304 (no changes since last sync)`));
26331
+ console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
26332
+ console.log(import_chalk23.default.gray(` Server returned 304 (no changes since last sync)`));
26125
26333
  } else {
26126
26334
  console.log(
26127
- import_chalk22.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
26335
+ import_chalk23.default.green(`\u2713 Synced ${result.rules} rule${result.rules === 1 ? "" : "s"} from cloud`)
26128
26336
  );
26129
- console.log(import_chalk22.default.gray(` Cached at: ${result.fetchedAt}`));
26130
- console.log(import_chalk22.default.gray(` File: ~/.node9/rules-cache.json`));
26337
+ console.log(import_chalk23.default.gray(` Cached at: ${result.fetchedAt}`));
26338
+ console.log(import_chalk23.default.gray(` File: ~/.node9/rules-cache.json`));
26131
26339
  }
26132
26340
  });
26133
26341
  policy.command("show").description("List all cloud policy rules in the local cache").action(() => {
26134
26342
  const status = getCloudSyncStatus();
26135
26343
  if (!status.cached) {
26136
- console.log(import_chalk22.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
26344
+ console.log(import_chalk23.default.yellow("\n No cloud rules cached \u2014 run: node9 policy sync\n"));
26137
26345
  return;
26138
26346
  }
26139
26347
  const rules = getCloudRules() ?? [];
26140
26348
  const age = Math.round((Date.now() - new Date(status.fetchedAt).getTime()) / 6e4);
26141
26349
  console.log(
26142
- import_chalk22.default.bold(`
26143
- Cloud policy rules`) + import_chalk22.default.gray(
26350
+ import_chalk23.default.bold(`
26351
+ Cloud policy rules`) + import_chalk23.default.gray(
26144
26352
  ` (${rules.length} rule${rules.length === 1 ? "" : "s"}, synced ${age}m ago)
26145
26353
  `
26146
26354
  )
26147
26355
  );
26148
26356
  if (rules.length === 0) {
26149
- console.log(import_chalk22.default.gray(" No rules defined in cloud policy.\n"));
26357
+ console.log(import_chalk23.default.gray(" No rules defined in cloud policy.\n"));
26150
26358
  return;
26151
26359
  }
26152
26360
  for (const rule of rules) {
26153
26361
  const r = rule;
26154
- const verdictColor = r.verdict === "block" ? import_chalk22.default.red : r.verdict === "allow" ? import_chalk22.default.green : import_chalk22.default.yellow;
26362
+ const verdictColor = r.verdict === "block" ? import_chalk23.default.red : r.verdict === "allow" ? import_chalk23.default.green : import_chalk23.default.yellow;
26155
26363
  console.log(
26156
26364
  ` ${verdictColor(
26157
26365
  String(r.verdict ?? "unknown").toUpperCase().padEnd(6)
26158
- )} ${import_chalk22.default.white(String(r.name ?? "(unnamed)"))}`
26366
+ )} ${import_chalk23.default.white(String(r.name ?? "(unnamed)"))}`
26159
26367
  );
26160
- if (r.reason) console.log(import_chalk22.default.gray(` ${String(r.reason)}`));
26368
+ if (r.reason) console.log(import_chalk23.default.gray(` ${String(r.reason)}`));
26161
26369
  }
26162
26370
  console.log("");
26163
26371
  });
26164
26372
  policy.command("status").description("Show current cloud policy cache status").action(() => {
26165
26373
  const s = getCloudSyncStatus();
26166
26374
  if (!s.cached) {
26167
- console.log(import_chalk22.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
26375
+ console.log(import_chalk23.default.yellow("\n No cache yet \u2014 run: node9 policy sync\n"));
26168
26376
  return;
26169
26377
  }
26170
26378
  const age = Math.round((Date.now() - new Date(s.fetchedAt).getTime()) / 6e4);
26171
26379
  console.log(`
26172
- Rules : ${import_chalk22.default.green(String(s.rules))} cloud rules loaded`);
26380
+ Rules : ${import_chalk23.default.green(String(s.rules))} cloud rules loaded`);
26173
26381
  console.log(
26174
- ` Synced : ${import_chalk22.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
26382
+ ` Synced : ${import_chalk23.default.gray(`${age} minute${age === 1 ? "" : "s"} ago`)} (${s.fetchedAt})`
26175
26383
  );
26176
26384
  if (s.workspaceId) {
26177
- console.log(` Workspace: ${import_chalk22.default.gray(s.workspaceId)}`);
26385
+ console.log(` Workspace: ${import_chalk23.default.gray(s.workspaceId)}`);
26178
26386
  }
26179
26387
  if (s.panicMode) {
26180
26388
  console.log(
26181
- ` ${import_chalk22.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk22.default.dim("(every review-verdict becomes block)")
26389
+ ` ${import_chalk23.default.red.bold("\u{1F6A8} Panic mode : ON")} ` + import_chalk23.default.dim("(every review-verdict becomes block)")
26182
26390
  );
26183
26391
  }
26184
26392
  if (s.shadowMode) {
26185
26393
  console.log(
26186
- ` ${import_chalk22.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk22.default.dim("(blocks become would-block log entries)")
26394
+ ` ${import_chalk23.default.yellow.bold("\u{1F441} Shadow mode : ON")} ` + import_chalk23.default.dim("(blocks become would-block log entries)")
26187
26395
  );
26188
26396
  }
26189
26397
  if (s.syncIntervalHours) {
26190
26398
  console.log(
26191
- import_chalk22.default.gray(
26399
+ import_chalk23.default.gray(
26192
26400
  ` Polling : every ${s.syncIntervalHours} hour${s.syncIntervalHours === 1 ? "" : "s"}`
26193
26401
  )
26194
26402
  );
@@ -26198,7 +26406,7 @@ function registerSyncCommand(program2) {
26198
26406
  }
26199
26407
 
26200
26408
  // src/cli/commands/agents.ts
26201
- var import_chalk23 = __toESM(require("chalk"));
26409
+ var import_chalk24 = __toESM(require("chalk"));
26202
26410
  init_setup();
26203
26411
  var SETUP_FN = {
26204
26412
  claude: setupClaude,
@@ -26242,30 +26450,30 @@ function registerAgentsCommand(program2) {
26242
26450
  console.log(` ${"Agent".padEnd(14)}${"Installed".padEnd(11)}${"Wired".padEnd(8)}Mode`);
26243
26451
  console.log(" " + "\u2500".repeat(44));
26244
26452
  for (const s of statuses) {
26245
- const installed = s.installed ? import_chalk23.default.green("\u2713") : import_chalk23.default.gray("\u2717");
26246
- const wired = !s.installed ? import_chalk23.default.gray("\u2014") : s.wired ? import_chalk23.default.green("\u2713") : import_chalk23.default.yellow("\u2717");
26247
- const mode = s.mode ? import_chalk23.default.gray(s.mode) : import_chalk23.default.gray("\u2014");
26248
- const hint = s.installed && !s.wired ? import_chalk23.default.gray(` \u2190 node9 agents add ${s.name}`) : "";
26453
+ const installed = s.installed ? import_chalk24.default.green("\u2713") : import_chalk24.default.gray("\u2717");
26454
+ const wired = !s.installed ? import_chalk24.default.gray("\u2014") : s.wired ? import_chalk24.default.green("\u2713") : import_chalk24.default.yellow("\u2717");
26455
+ const mode = s.mode ? import_chalk24.default.gray(s.mode) : import_chalk24.default.gray("\u2014");
26456
+ const hint = s.installed && !s.wired ? import_chalk24.default.gray(` \u2190 node9 agents add ${s.name}`) : "";
26249
26457
  console.log(` ${s.label.padEnd(14)}${installed} ${wired} ${mode}${hint}`);
26250
26458
  }
26251
26459
  console.log("");
26252
26460
  if (!anyInstalled) {
26253
26461
  console.log(
26254
- import_chalk23.default.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + import_chalk23.default.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
26462
+ import_chalk24.default.gray(" No AI agents detected. Install Claude Code, Gemini CLI, Cursor,\n") + import_chalk24.default.gray(" Windsurf, VSCode, or Codex then run: node9 agents list\n")
26255
26463
  );
26256
26464
  return;
26257
26465
  }
26258
26466
  const unwired = statuses.filter((s) => s.installed && !s.wired);
26259
26467
  if (unwired.length > 0) {
26260
26468
  console.log(
26261
- import_chalk23.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk23.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
26469
+ import_chalk24.default.yellow(` ${unwired.length} agent(s) not yet wired. Run: `) + import_chalk24.default.white(`node9 agents add ${unwired[0].name}`) + "\n"
26262
26470
  );
26263
26471
  }
26264
26472
  if (statuses.some((s) => s.name === "gemini" && s.installed)) {
26265
26473
  console.log(
26266
- import_chalk23.default.yellow(
26474
+ import_chalk24.default.yellow(
26267
26475
  " \u26A0\uFE0F Gemini CLI stops serving AI Pro/Ultra and free tiers on 2026-06-18.\n"
26268
- ) + import_chalk23.default.gray(" Migrate to Antigravity: ") + import_chalk23.default.white("node9 agents add antigravity") + "\n"
26476
+ ) + import_chalk24.default.gray(" Migrate to Antigravity: ") + import_chalk24.default.white("node9 agents add antigravity") + "\n"
26269
26477
  );
26270
26478
  }
26271
26479
  });
@@ -26273,7 +26481,7 @@ function registerAgentsCommand(program2) {
26273
26481
  const name = resolveAgentName(agent);
26274
26482
  const fn = SETUP_FN[name];
26275
26483
  if (!fn) {
26276
- console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26484
+ console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26277
26485
  process.exit(1);
26278
26486
  }
26279
26487
  await fn();
@@ -26282,14 +26490,14 @@ function registerAgentsCommand(program2) {
26282
26490
  const name = resolveAgentName(agent);
26283
26491
  const fn = TEARDOWN_FN[name];
26284
26492
  if (!fn) {
26285
- console.error(import_chalk23.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26493
+ console.error(import_chalk24.default.red(`Unknown agent: "${agent}". Supported: ${AGENT_NAMES.join(", ")}`));
26286
26494
  process.exit(1);
26287
26495
  }
26288
- console.log(import_chalk23.default.cyan(`
26496
+ console.log(import_chalk24.default.cyan(`
26289
26497
  \u{1F6E1}\uFE0F Node9: removing from ${name}...
26290
26498
  `));
26291
26499
  fn();
26292
- console.log(import_chalk23.default.gray("\n Restart the agent for changes to take effect."));
26500
+ console.log(import_chalk24.default.gray("\n Restart the agent for changes to take effect."));
26293
26501
  });
26294
26502
  }
26295
26503
 
@@ -26297,22 +26505,22 @@ function registerAgentsCommand(program2) {
26297
26505
  init_scan();
26298
26506
 
26299
26507
  // src/cli/commands/posture.ts
26300
- var import_chalk25 = __toESM(require("chalk"));
26508
+ var import_chalk26 = __toESM(require("chalk"));
26301
26509
  init_posture();
26302
26510
 
26303
26511
  // src/posture/render.ts
26304
- var import_chalk24 = __toESM(require("chalk"));
26512
+ var import_chalk25 = __toESM(require("chalk"));
26305
26513
  init_score();
26306
26514
  var ICON = {
26307
- critical: import_chalk24.default.red("\u274C"),
26308
- high: import_chalk24.default.red("\u274C"),
26309
- medium: import_chalk24.default.yellow("\u26A0\uFE0F "),
26310
- advisory: import_chalk24.default.gray("\u26A0\uFE0F ")
26515
+ critical: import_chalk25.default.red("\u274C"),
26516
+ high: import_chalk25.default.red("\u274C"),
26517
+ medium: import_chalk25.default.yellow("\u26A0\uFE0F "),
26518
+ advisory: import_chalk25.default.gray("\u26A0\uFE0F ")
26311
26519
  };
26312
26520
  var TIER_LABEL = {
26313
- good: import_chalk24.default.green("Good"),
26314
- "at-risk": import_chalk24.default.yellow("At risk"),
26315
- critical: import_chalk24.default.red("Critical")
26521
+ good: import_chalk25.default.green("Good"),
26522
+ "at-risk": import_chalk25.default.yellow("At risk"),
26523
+ critical: import_chalk25.default.red("Critical")
26316
26524
  };
26317
26525
  function wrap(text, width) {
26318
26526
  const out = [];
@@ -26330,35 +26538,35 @@ function wrap(text, width) {
26330
26538
  }
26331
26539
  var LABEL_WIDTH = 14;
26332
26540
  function label(category) {
26333
- return import_chalk24.default.bold(category.padEnd(Math.max(LABEL_WIDTH, category.length + 1)));
26541
+ return import_chalk25.default.bold(category.padEnd(Math.max(LABEL_WIDTH, category.length + 1)));
26334
26542
  }
26335
26543
  function renderFinding(f, showWeight = false) {
26336
26544
  const lines = [];
26337
- const wt = showWeight && f.scoreWeight ? import_chalk24.default.cyan.bold(`+${f.scoreWeight} `) : "";
26545
+ const wt = showWeight && f.scoreWeight ? import_chalk25.default.cyan.bold(`+${f.scoreWeight} `) : "";
26338
26546
  lines.push(` ${ICON[f.severity]} ${label(f.category)}${wt}${f.title}`);
26339
26547
  const indent = " ".repeat(2 + 3 + LABEL_WIDTH);
26340
26548
  const width = 80 - indent.length;
26341
26549
  for (const s of [f.what, f.why, f.who]) {
26342
- if (s) for (const l of wrap(s, width)) lines.push(indent + import_chalk24.default.gray(l));
26550
+ if (s) for (const l of wrap(s, width)) lines.push(indent + import_chalk25.default.gray(l));
26343
26551
  }
26344
- for (const d of f.detail) lines.push(indent + import_chalk24.default.gray(d));
26552
+ for (const d of f.detail) lines.push(indent + import_chalk25.default.gray(d));
26345
26553
  if (f.fix) {
26346
26554
  let first = true;
26347
26555
  for (const seg of f.fix.split("\n")) {
26348
26556
  for (const l of wrap(seg, width - 2)) {
26349
- lines.push(indent + import_chalk24.default.cyan(first ? "\u2192 " + l : " " + l));
26557
+ lines.push(indent + import_chalk25.default.cyan(first ? "\u2192 " + l : " " + l));
26350
26558
  first = false;
26351
26559
  }
26352
26560
  }
26353
26561
  }
26354
26562
  const tradeoff = [
26355
- [f.gain, "gain: ", import_chalk24.default.green],
26356
- [f.cost, "cost: ", import_chalk24.default.yellow]
26563
+ [f.gain, "gain: ", import_chalk25.default.green],
26564
+ [f.cost, "cost: ", import_chalk25.default.yellow]
26357
26565
  ];
26358
26566
  for (const [text, lbl, color2] of tradeoff) {
26359
26567
  if (!text) continue;
26360
26568
  wrap(text, width - 6).forEach((l, i) => {
26361
- lines.push(indent + (i === 0 ? color2(lbl) : " ") + import_chalk24.default.gray(l));
26569
+ lines.push(indent + (i === 0 ? color2(lbl) : " ") + import_chalk25.default.gray(l));
26362
26570
  });
26363
26571
  }
26364
26572
  return lines;
@@ -26368,12 +26576,12 @@ function renderPosture(result) {
26368
26576
  const tier = TIER_LABEL[result.tier];
26369
26577
  lines.push("");
26370
26578
  lines.push(
26371
- import_chalk24.default.cyan.bold(`\u{1F6E1}\uFE0F Node9 Posture`) + import_chalk24.default.gray(` \u2014 ${result.agent}`) + ` ${import_chalk24.default.bold(`Score: ${result.score}/100`)} (${tier})`
26579
+ import_chalk25.default.cyan.bold(`\u{1F6E1}\uFE0F Node9 Posture`) + import_chalk25.default.gray(` \u2014 ${result.agent}`) + ` ${import_chalk25.default.bold(`Score: ${result.score}/100`)} (${tier})`
26372
26580
  );
26373
26581
  const headroom = openHeadroom(result.findings);
26374
26582
  if (headroom > 0) {
26375
26583
  lines.push(
26376
- " " + import_chalk24.default.gray(
26584
+ " " + import_chalk25.default.gray(
26377
26585
  `${headroom} pts of headroom below \u2014 each layer adds security at some cost to flexibility. You choose which to close.`
26378
26586
  )
26379
26587
  );
@@ -26381,21 +26589,21 @@ function renderPosture(result) {
26381
26589
  lines.push("");
26382
26590
  if (result.headline) {
26383
26591
  const indent = " ";
26384
- lines.push(` ${import_chalk24.default.red.bold("\u{1F525} Biggest risk")}`);
26385
- for (const l of wrap(result.headline.risk, 74)) lines.push(indent + import_chalk24.default.white(l));
26592
+ lines.push(` ${import_chalk25.default.red.bold("\u{1F525} Biggest risk")}`);
26593
+ for (const l of wrap(result.headline.risk, 74)) lines.push(indent + import_chalk25.default.white(l));
26386
26594
  const action = wrap(`Do this first: ${result.headline.action}`, 72);
26387
- action.forEach((l, i) => lines.push(indent + import_chalk24.default.cyan(i === 0 ? "\u2192 " + l : " " + l)));
26595
+ action.forEach((l, i) => lines.push(indent + import_chalk25.default.cyan(i === 0 ? "\u2192 " + l : " " + l)));
26388
26596
  lines.push("");
26389
26597
  }
26390
26598
  const covered = result.findings.filter((f) => f.coverage?.state === "covered");
26391
26599
  const open = result.findings.filter((f) => f.coverage?.state !== "covered");
26392
26600
  if (covered.length > 0) {
26393
- lines.push(" " + import_chalk24.default.green("\u{1F7E2} ON NOW \u2014 node9 is enforcing these (your floor)"));
26601
+ lines.push(" " + import_chalk25.default.green("\u{1F7E2} ON NOW \u2014 node9 is enforcing these (your floor)"));
26394
26602
  for (const f of covered) {
26395
26603
  const gated = f.coverage?.level === "review" ? "approval-gating" : "blocking";
26396
26604
  const via = f.coverage?.via ?? "node9";
26397
26605
  lines.push(
26398
- ` ${import_chalk24.default.green("\u2705")} ${label(f.category)}${import_chalk24.default.gray(`${via} is ${gated} this`)}`
26606
+ ` ${import_chalk25.default.green("\u2705")} ${label(f.category)}${import_chalk25.default.gray(`${via} is ${gated} this`)}`
26399
26607
  );
26400
26608
  }
26401
26609
  lines.push("");
@@ -26404,24 +26612,24 @@ function renderPosture(result) {
26404
26612
  const reduceOpen = open.filter((f) => f.owner !== "node9" && f.node9Reduces);
26405
26613
  const osOpen = open.filter((f) => f.owner !== "node9" && !f.node9Reduces);
26406
26614
  if (node9Open.length > 0) {
26407
- lines.push(" " + import_chalk24.default.cyan.bold("\u{1F527} node9 can fix these \u2014 run the command"));
26615
+ lines.push(" " + import_chalk25.default.cyan.bold("\u{1F527} node9 can fix these \u2014 run the command"));
26408
26616
  for (const f of node9Open) lines.push(...renderFinding(f, true));
26409
26617
  }
26410
26618
  if (reduceOpen.length > 0) {
26411
26619
  if (node9Open.length > 0) lines.push("");
26412
- lines.push(" " + import_chalk24.default.yellow.bold("\u{1F512} AVAILABLE \u2014 turn on to harden (each has a tradeoff)"));
26620
+ lines.push(" " + import_chalk25.default.yellow.bold("\u{1F512} AVAILABLE \u2014 turn on to harden (each has a tradeoff)"));
26413
26621
  for (const f of reduceOpen) lines.push(...renderFinding(f, true));
26414
26622
  }
26415
26623
  if (osOpen.length > 0) {
26416
26624
  if (node9Open.length > 0 || reduceOpen.length > 0) lines.push("");
26417
- lines.push(" " + import_chalk24.default.bold("\u{1F9F1} YOUR PART \u2014 node9 can't fix these (OS-level)"));
26625
+ lines.push(" " + import_chalk25.default.bold("\u{1F9F1} YOUR PART \u2014 node9 can't fix these (OS-level)"));
26418
26626
  for (const f of osOpen) lines.push(...renderFinding(f));
26419
26627
  }
26420
26628
  for (const cat of result.passedCategories) {
26421
- lines.push(` ${import_chalk24.default.green("\u2705")} ${label(cat)}${import_chalk24.default.gray("no issues found")}`);
26629
+ lines.push(` ${import_chalk25.default.green("\u2705")} ${label(cat)}${import_chalk25.default.gray("no issues found")}`);
26422
26630
  }
26423
26631
  for (const cat of result.erroredCategories) {
26424
- lines.push(` ${import_chalk24.default.gray("\u2022")} ${label(cat)}${import_chalk24.default.gray("could not be checked")}`);
26632
+ lines.push(` ${import_chalk25.default.gray("\u2022")} ${label(cat)}${import_chalk25.default.gray("could not be checked")}`);
26425
26633
  }
26426
26634
  lines.push("");
26427
26635
  const crit = open.filter((f) => f.severity === "critical").length;
@@ -26429,16 +26637,16 @@ function renderPosture(result) {
26429
26637
  const med = open.filter((f) => f.severity === "medium").length;
26430
26638
  const adv = open.filter((f) => f.severity === "advisory").length;
26431
26639
  const parts = [];
26432
- if (crit) parts.push(import_chalk24.default.red(`${crit} critical`));
26433
- if (high) parts.push(import_chalk24.default.red(`${high} high`));
26434
- if (med) parts.push(import_chalk24.default.yellow(`${med} medium`));
26435
- if (adv) parts.push(import_chalk24.default.gray(`${adv} advisory`));
26436
- const summary = parts.length ? parts.join(" \xB7 ") : import_chalk24.default.green("no findings");
26640
+ if (crit) parts.push(import_chalk25.default.red(`${crit} critical`));
26641
+ if (high) parts.push(import_chalk25.default.red(`${high} high`));
26642
+ if (med) parts.push(import_chalk25.default.yellow(`${med} medium`));
26643
+ if (adv) parts.push(import_chalk25.default.gray(`${adv} advisory`));
26644
+ const summary = parts.length ? parts.join(" \xB7 ") : import_chalk25.default.green("no findings");
26437
26645
  lines.push(` ${summary}`);
26438
26646
  lines.push("");
26439
- lines.push(" " + import_chalk24.default.bold("Track this across your fleet & keep it green:"));
26647
+ lines.push(" " + import_chalk25.default.bold("Track this across your fleet & keep it green:"));
26440
26648
  lines.push(
26441
- " " + import_chalk24.default.dim("\u2192 ") + import_chalk24.default.cyan.underline("https://node9.ai/auth/signup?ref=cli_posture")
26649
+ " " + import_chalk25.default.dim("\u2192 ") + import_chalk25.default.cyan.underline("https://node9.ai/auth/signup?ref=cli_posture")
26442
26650
  );
26443
26651
  lines.push("");
26444
26652
  return lines.join("\n");
@@ -26458,11 +26666,11 @@ function registerPostureCommand(program2) {
26458
26666
  if (opts.ship) {
26459
26667
  const creds = readCredentials();
26460
26668
  if (!creds) {
26461
- console.error(import_chalk25.default.gray(" Run `node9 login` to ship this to your dashboard."));
26669
+ console.error(import_chalk26.default.gray(" Run `node9 login` to ship this to your dashboard."));
26462
26670
  } else {
26463
26671
  const ok2 = await shipPosture(result, creds);
26464
26672
  console.error(
26465
- ok2 ? import_chalk25.default.gray(" \u2713 Shipped to your node9 dashboard.") : import_chalk25.default.gray(" Could not reach the dashboard \u2014 saved locally only.")
26673
+ ok2 ? import_chalk26.default.gray(" \u2713 Shipped to your node9 dashboard.") : import_chalk26.default.gray(" Could not reach the dashboard \u2014 saved locally only.")
26466
26674
  );
26467
26675
  }
26468
26676
  }
@@ -26471,7 +26679,7 @@ function registerPostureCommand(program2) {
26471
26679
  }
26472
26680
 
26473
26681
  // src/cli/commands/egress.ts
26474
- var import_chalk26 = __toESM(require("chalk"));
26682
+ var import_chalk27 = __toESM(require("chalk"));
26475
26683
  init_config();
26476
26684
  init_dist();
26477
26685
  function guard(fn) {
@@ -26479,7 +26687,7 @@ function guard(fn) {
26479
26687
  fn();
26480
26688
  return true;
26481
26689
  } catch (err2) {
26482
- console.error(import_chalk26.default.red(`
26690
+ console.error(import_chalk27.default.red(`
26483
26691
  \u2717 ${err2.message}
26484
26692
  `));
26485
26693
  process.exitCode = 1;
@@ -26494,19 +26702,19 @@ function addHost(list, host) {
26494
26702
  }
26495
26703
  function showStatus() {
26496
26704
  const e = getConfig().policy.egress;
26497
- 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");
26498
- console.log(import_chalk26.default.cyan.bold("\n\u{1F310} Egress control"));
26705
+ const state = !e.enabled ? import_chalk27.default.red("OFF \u2014 your agent can reach any host") : e.mode === "block" ? import_chalk27.default.green("LOCKED (block) \u2014 unknown hosts are denied") : import_chalk27.default.yellow("WATCHING (review) \u2014 unknown hosts prompt you");
26706
+ console.log(import_chalk27.default.cyan.bold("\n\u{1F310} Egress control"));
26499
26707
  console.log(" State: " + state);
26500
26708
  console.log(
26501
- import_chalk26.default.gray(
26709
+ import_chalk27.default.gray(
26502
26710
  ` ${DEFAULT_EGRESS_ALLOWLIST.length} common dev/LLM hosts are always allowed (github, npm, pypi, anthropic, \u2026).`
26503
26711
  )
26504
26712
  );
26505
26713
  if (e.allow.length) console.log(" Your allow: " + e.allow.join(", "));
26506
26714
  if (e.deny.length) console.log(" Your deny: " + e.deny.join(", "));
26507
26715
  if (!e.enabled) {
26508
- console.log(import_chalk26.default.gray("\n Turn it on: node9 egress watch (prompt on unknown hosts)"));
26509
- console.log(import_chalk26.default.gray(" node9 egress lock (hard-block unknown hosts)"));
26716
+ console.log(import_chalk27.default.gray("\n Turn it on: node9 egress watch (prompt on unknown hosts)"));
26717
+ console.log(import_chalk27.default.gray(" node9 egress lock (hard-block unknown hosts)"));
26510
26718
  }
26511
26719
  console.log("");
26512
26720
  }
@@ -26514,43 +26722,43 @@ function registerEgressCommand(program2) {
26514
26722
  const egress = program2.command("egress").description("Control where your agent can send data (egress allowlist)");
26515
26723
  egress.command("watch").description("Prompt before the agent reaches an unknown host (review mode)").action(() => {
26516
26724
  if (!mutate({ enabled: true, mode: "review" })) return;
26517
- console.log(import_chalk26.default.green("\n\u2713 Egress is now watched (review mode)."));
26725
+ console.log(import_chalk27.default.green("\n\u2713 Egress is now watched (review mode)."));
26518
26726
  console.log(
26519
- import_chalk26.default.gray(" Routine hosts (LLM APIs, package registries, localhost) are allowed.")
26727
+ import_chalk27.default.gray(" Routine hosts (LLM APIs, package registries, localhost) are allowed.")
26520
26728
  );
26521
26729
  console.log(
26522
- import_chalk26.default.gray(" An unknown host will prompt you \u2014 run `node9 egress lock` to hard-block.\n")
26730
+ import_chalk27.default.gray(" An unknown host will prompt you \u2014 run `node9 egress lock` to hard-block.\n")
26523
26731
  );
26524
26732
  });
26525
26733
  egress.command("lock").description("Block the agent from reaching unknown hosts (block mode)").action(() => {
26526
26734
  if (!mutate({ enabled: true, mode: "block" })) return;
26527
- console.log(import_chalk26.default.green("\n\u2713 Egress is now locked (block mode)."));
26528
- console.log(import_chalk26.default.gray(" Routine hosts are still allowed; unknown hosts are denied."));
26529
- console.log(import_chalk26.default.gray(" Allow a specific host with `node9 egress allow <host>`.\n"));
26735
+ console.log(import_chalk27.default.green("\n\u2713 Egress is now locked (block mode)."));
26736
+ console.log(import_chalk27.default.gray(" Routine hosts are still allowed; unknown hosts are denied."));
26737
+ console.log(import_chalk27.default.gray(" Allow a specific host with `node9 egress allow <host>`.\n"));
26530
26738
  });
26531
26739
  egress.command("allow <host>").description("Allow an extra host (glob, e.g. *.mycorp.com)").action((host) => {
26532
26740
  if (!addHost("allow", host)) return;
26533
- console.log(import_chalk26.default.green(`
26741
+ console.log(import_chalk27.default.green(`
26534
26742
  \u2713 Allowed egress to ${host}.
26535
26743
  `));
26536
26744
  });
26537
26745
  egress.command("deny <host>").description("Block an extra host (deny always wins)").action((host) => {
26538
26746
  if (!addHost("deny", host)) return;
26539
- console.log(import_chalk26.default.green(`
26747
+ console.log(import_chalk27.default.green(`
26540
26748
  \u2713 Denied egress to ${host}.
26541
26749
  `));
26542
26750
  });
26543
26751
  egress.command("off").description("Turn egress control off").action(() => {
26544
26752
  if (!mutate({ enabled: false })) return;
26545
26753
  console.log(
26546
- import_chalk26.default.yellow("\n\u2713 Egress control is off \u2014 the agent can reach any host again.\n")
26754
+ import_chalk27.default.yellow("\n\u2713 Egress control is off \u2014 the agent can reach any host again.\n")
26547
26755
  );
26548
26756
  });
26549
26757
  egress.action(showStatus);
26550
26758
  }
26551
26759
 
26552
26760
  // src/cli/commands/jail.ts
26553
- var import_chalk27 = __toESM(require("chalk"));
26761
+ var import_chalk28 = __toESM(require("chalk"));
26554
26762
 
26555
26763
  // src/shields/jail.ts
26556
26764
  var import_fs55 = __toESM(require("fs"));
@@ -26645,20 +26853,20 @@ function registerJailCommand(program2) {
26645
26853
  regenerateUserJail(paths);
26646
26854
  appendConfigAudit({ event: "jail-add", path: p.trim(), verdict });
26647
26855
  } catch (err2) {
26648
- console.error(import_chalk27.default.red(`
26856
+ console.error(import_chalk28.default.red(`
26649
26857
  \u274C ${err2.message}
26650
26858
  `));
26651
26859
  process.exit(1);
26652
26860
  return;
26653
26861
  }
26654
- console.log(import_chalk27.default.green(`
26862
+ console.log(import_chalk28.default.green(`
26655
26863
  \u2705 Jailed ${p} (${verdict}).`));
26656
26864
  console.log(
26657
- import_chalk27.default.gray(
26865
+ import_chalk28.default.gray(
26658
26866
  ` AI reads of this path now ${verdict === "block" ? "BLOCK" : "require approval"}.`
26659
26867
  )
26660
26868
  );
26661
- console.log(import_chalk27.default.gray(` Preview: ${import_chalk27.default.cyan(`node9 explain bash "cat ${p}"`)}
26869
+ console.log(import_chalk28.default.gray(` Preview: ${import_chalk28.default.cyan(`node9 explain bash "cat ${p}"`)}
26662
26870
  `));
26663
26871
  });
26664
26872
  jail.command("remove <path>").description("Remove a user-added jail path (built-in paths are not removable)").action((p) => {
@@ -26666,17 +26874,17 @@ function registerJailCommand(program2) {
26666
26874
  try {
26667
26875
  result = removeJailPath(p);
26668
26876
  } catch (err2) {
26669
- console.error(import_chalk27.default.red(`
26877
+ console.error(import_chalk28.default.red(`
26670
26878
  \u274C ${err2.message}
26671
26879
  `));
26672
26880
  process.exit(1);
26673
26881
  return;
26674
26882
  }
26675
26883
  if (!result.removed) {
26676
- console.error(import_chalk27.default.yellow(`
26884
+ console.error(import_chalk28.default.yellow(`
26677
26885
  \u2139\uFE0F "${p}" is not a user-added jail path.
26678
26886
  `));
26679
- console.error(import_chalk27.default.gray(` Run ${import_chalk27.default.cyan("node9 jail list")} to see your paths.
26887
+ console.error(import_chalk28.default.gray(` Run ${import_chalk28.default.cyan("node9 jail list")} to see your paths.
26680
26888
  `));
26681
26889
  process.exit(1);
26682
26890
  return;
@@ -26685,39 +26893,39 @@ function registerJailCommand(program2) {
26685
26893
  regenerateUserJail(result.paths);
26686
26894
  appendConfigAudit({ event: "jail-remove", path: p.trim() });
26687
26895
  } catch (err2) {
26688
- console.error(import_chalk27.default.red(`
26896
+ console.error(import_chalk28.default.red(`
26689
26897
  \u274C ${err2.message}
26690
26898
  `));
26691
26899
  process.exit(1);
26692
26900
  return;
26693
26901
  }
26694
- console.log(import_chalk27.default.green(`
26902
+ console.log(import_chalk28.default.green(`
26695
26903
  \u2705 Removed ${p} from the jail.
26696
26904
  `));
26697
26905
  });
26698
26906
  jail.command("list").description("Show built-in + user-added jail paths").action(() => {
26699
- console.log(import_chalk27.default.bold("\n\u{1F512} Credential Jail\n"));
26700
- console.log(import_chalk27.default.gray(" Built-in (always on, not removable):"));
26701
- for (const b of BUILTIN_JAIL) console.log(` ${import_chalk27.default.gray("\u2022")} ${b}`);
26907
+ console.log(import_chalk28.default.bold("\n\u{1F512} Credential Jail\n"));
26908
+ console.log(import_chalk28.default.gray(" Built-in (always on, not removable):"));
26909
+ for (const b of BUILTIN_JAIL) console.log(` ${import_chalk28.default.gray("\u2022")} ${b}`);
26702
26910
  console.log("");
26703
26911
  let user;
26704
26912
  try {
26705
26913
  user = readJailPaths();
26706
26914
  } catch (err2) {
26707
- console.error(import_chalk27.default.red(` \u2717 ${err2.message}
26915
+ console.error(import_chalk28.default.red(` \u2717 ${err2.message}
26708
26916
  `));
26709
26917
  process.exit(1);
26710
26918
  return;
26711
26919
  }
26712
26920
  if (user.length === 0) {
26713
26921
  console.log(
26714
- import_chalk27.default.gray(" Your paths: (none) \u2014 add one with ") + import_chalk27.default.cyan("node9 jail add <path>")
26922
+ import_chalk28.default.gray(" Your paths: (none) \u2014 add one with ") + import_chalk28.default.cyan("node9 jail add <path>")
26715
26923
  );
26716
26924
  } else {
26717
- console.log(import_chalk27.default.gray(" Your paths (removable):"));
26925
+ console.log(import_chalk28.default.gray(" Your paths (removable):"));
26718
26926
  for (const u of user) {
26719
- const v = u.verdict === "block" ? import_chalk27.default.red("block ") : import_chalk27.default.yellow("review");
26720
- console.log(` ${v} ${import_chalk27.default.cyan(u.path)}`);
26927
+ const v = u.verdict === "block" ? import_chalk28.default.red("block ") : import_chalk28.default.yellow("review");
26928
+ console.log(` ${v} ${import_chalk28.default.cyan(u.path)}`);
26721
26929
  }
26722
26930
  }
26723
26931
  console.log("");
@@ -26725,7 +26933,7 @@ function registerJailCommand(program2) {
26725
26933
  }
26726
26934
 
26727
26935
  // src/cli/commands/sandbox.ts
26728
- var import_chalk28 = __toESM(require("chalk"));
26936
+ var import_chalk29 = __toESM(require("chalk"));
26729
26937
  var import_fs58 = __toESM(require("fs"));
26730
26938
  var import_path56 = __toESM(require("path"));
26731
26939
  var import_child_process13 = require("child_process");
@@ -26963,16 +27171,16 @@ function registerSandboxCommand(program2, version2) {
26963
27171
  const p = sandboxConfigPath();
26964
27172
  if (import_fs58.default.existsSync(p)) {
26965
27173
  console.log(
26966
- import_chalk28.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
27174
+ import_chalk29.default.yellow(` ${SANDBOX_CONFIG_FILE} already exists \u2014 leaving it untouched.`)
26967
27175
  );
26968
27176
  return;
26969
27177
  }
26970
27178
  import_fs58.default.writeFileSync(p, scaffoldSandboxYaml(agent));
26971
27179
  console.log(
26972
- import_chalk28.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk28.default.dim(` (agent: ${agent})`)
27180
+ import_chalk29.default.green(` \u2713 wrote ${SANDBOX_CONFIG_FILE}`) + import_chalk29.default.dim(` (agent: ${agent})`)
26973
27181
  );
26974
27182
  console.log(
26975
- import_chalk28.default.dim(" Edit it (mounts / allow / expose), then: ") + import_chalk28.default.cyan("node9 sandbox run")
27183
+ import_chalk29.default.dim(" Edit it (mounts / allow / expose), then: ") + import_chalk29.default.cyan("node9 sandbox run")
26976
27184
  );
26977
27185
  });
26978
27186
  cmd.command("run [agent]").description("Build (if needed) + run the agent jailed. Extra args after -- go to the agent.").allowUnknownOption(true).allowExcessArguments(true).action((agentArg, _opts, command) => {
@@ -26982,7 +27190,7 @@ function registerSandboxCommand(program2, version2) {
26982
27190
  const engine = detectEngine(sandbox.runtime.engine);
26983
27191
  if (!engine.available) {
26984
27192
  console.error(
26985
- import_chalk28.default.red(` ${sandbox.runtime.engine} not found.`) + import_chalk28.default.dim(` Install it first \u2014 node9 sandbox needs a container runtime.`)
27193
+ import_chalk29.default.red(` ${sandbox.runtime.engine} not found.`) + import_chalk29.default.dim(` Install it first \u2014 node9 sandbox needs a container runtime.`)
26986
27194
  );
26987
27195
  process.exit(1);
26988
27196
  }
@@ -26995,11 +27203,11 @@ function registerSandboxCommand(program2, version2) {
26995
27203
  });
26996
27204
  if (compiled.rejected.length) {
26997
27205
  console.log(
26998
- import_chalk28.default.yellow(` \u26A0 ignoring invalid allow hosts: ${compiled.rejected.join(", ")}`)
27206
+ import_chalk29.default.yellow(` \u26A0 ignoring invalid allow hosts: ${compiled.rejected.join(", ")}`)
26999
27207
  );
27000
27208
  }
27001
27209
  if (compiled.denied.length) {
27002
- console.log(import_chalk28.default.dim(` (denied: ${compiled.denied.join(", ")})`));
27210
+ console.log(import_chalk29.default.dim(` (denied: ${compiled.denied.join(", ")})`));
27003
27211
  }
27004
27212
  const allowlistPath = writeAllowlist(cwd, compiled.allow);
27005
27213
  const dockerfile = renderDockerfile(sandbox, node9Version2);
@@ -27012,12 +27220,12 @@ function registerSandboxCommand(program2, version2) {
27012
27220
  const imageExists = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
27013
27221
  const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash;
27014
27222
  if (needBuild) {
27015
- console.log(import_chalk28.default.dim(` building ${image} \u2026`));
27223
+ console.log(import_chalk29.default.dim(` building ${image} \u2026`));
27016
27224
  const b = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, ["build", "-t", image, buildDir], {
27017
27225
  stdio: "inherit"
27018
27226
  });
27019
27227
  if (b.status !== 0) {
27020
- console.error(import_chalk28.default.red(" build failed."));
27228
+ console.error(import_chalk29.default.red(" build failed."));
27021
27229
  process.exit(b.status ?? 1);
27022
27230
  }
27023
27231
  import_fs58.default.writeFileSync(hashFile, hash);
@@ -27035,15 +27243,15 @@ function registerSandboxCommand(program2, version2) {
27035
27243
  if (sandbox.node9.mountAgentCredentials) {
27036
27244
  const creds = agentCredentialsMount(sandbox.agent);
27037
27245
  if (import_fs58.default.existsSync(creds.hostPath)) {
27038
- console.log(import_chalk28.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
27246
+ console.log(import_chalk29.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
27039
27247
  } else {
27040
27248
  console.log(
27041
- import_chalk28.default.yellow(` \u26A0 ${creds.hostPath} not found \u2014 `) + import_chalk28.default.dim(`the agent must auth via an env key in env.pass.`)
27249
+ import_chalk29.default.yellow(` \u26A0 ${creds.hostPath} not found \u2014 `) + import_chalk29.default.dim(`the agent must auth via an env key in env.pass.`)
27042
27250
  );
27043
27251
  }
27044
27252
  }
27045
27253
  console.log(
27046
- import_chalk28.default.green(` \u{1F6E1}\uFE0F ${sandbox.agent} jailed \u2014 ${compiled.allow.length} hosts allowed
27254
+ import_chalk29.default.green(` \u{1F6E1}\uFE0F ${sandbox.agent} jailed \u2014 ${compiled.allow.length} hosts allowed
27047
27255
  `)
27048
27256
  );
27049
27257
  const r = (0, import_child_process13.spawnSync)(sandbox.runtime.engine, runArgs, { stdio: "inherit" });
@@ -27052,7 +27260,7 @@ function registerSandboxCommand(program2, version2) {
27052
27260
  cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
27053
27261
  const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
27054
27262
  if (!import_fs58.default.existsSync(auditPath)) {
27055
- console.log(import_chalk28.default.dim(" no sandbox audit yet."));
27263
+ console.log(import_chalk29.default.dim(" no sandbox audit yet."));
27056
27264
  return;
27057
27265
  }
27058
27266
  (0, import_child_process13.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
@@ -27060,7 +27268,7 @@ function registerSandboxCommand(program2, version2) {
27060
27268
  cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
27061
27269
  const auditPath = import_path56.default.join(sandboxDataDir(), "audit.log");
27062
27270
  if (!import_fs58.default.existsSync(auditPath)) {
27063
- console.log(import_chalk28.default.dim(" no sandbox audit yet."));
27271
+ console.log(import_chalk29.default.dim(" no sandbox audit yet."));
27064
27272
  return;
27065
27273
  }
27066
27274
  process.stdout.write(import_fs58.default.readFileSync(auditPath, "utf-8"));
@@ -27078,12 +27286,12 @@ function registerSandboxCommand(program2, version2) {
27078
27286
  });
27079
27287
  }
27080
27288
  import_fs58.default.rmSync(import_path56.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
27081
- console.log(import_chalk28.default.green(" \u2713 sandbox image + build + data removed."));
27289
+ console.log(import_chalk29.default.green(" \u2713 sandbox image + build + data removed."));
27082
27290
  });
27083
27291
  }
27084
27292
 
27085
27293
  // src/cli/commands/sessions.ts
27086
- var import_chalk29 = __toESM(require("chalk"));
27294
+ var import_chalk30 = __toESM(require("chalk"));
27087
27295
  var import_fs59 = __toESM(require("fs"));
27088
27296
  var import_path57 = __toESM(require("path"));
27089
27297
  var import_os50 = __toESM(require("os"));
@@ -27579,11 +27787,11 @@ function toolInputSummary(tool, input) {
27579
27787
  }
27580
27788
  function toolColor(tool) {
27581
27789
  const t = tool.toLowerCase();
27582
- if (t === "bash" || t === "execute_bash") return import_chalk29.default.red;
27583
- if (t === "write") return import_chalk29.default.green;
27584
- if (t === "edit" || t === "notebookedit") return import_chalk29.default.yellow;
27585
- if (t === "read") return import_chalk29.default.cyan;
27586
- return import_chalk29.default.gray;
27790
+ if (t === "bash" || t === "execute_bash") return import_chalk30.default.red;
27791
+ if (t === "write") return import_chalk30.default.green;
27792
+ if (t === "edit" || t === "notebookedit") return import_chalk30.default.yellow;
27793
+ if (t === "read") return import_chalk30.default.cyan;
27794
+ return import_chalk30.default.gray;
27587
27795
  }
27588
27796
  function barStr2(value, max, width) {
27589
27797
  if (max === 0 || width <= 0) return "\u2591".repeat(width);
@@ -27593,7 +27801,7 @@ function barStr2(value, max, width) {
27593
27801
  function colorBar2(value, max, width) {
27594
27802
  const s = barStr2(value, max, width);
27595
27803
  const filled = Math.max(1, Math.round(max > 0 ? value / max * width : 0));
27596
- return import_chalk29.default.cyan(s.slice(0, filled)) + import_chalk29.default.dim(s.slice(filled));
27804
+ return import_chalk30.default.cyan(s.slice(0, filled)) + import_chalk30.default.dim(s.slice(filled));
27597
27805
  }
27598
27806
  function renderSummary(summaries) {
27599
27807
  const totalTools = summaries.reduce((n, s) => n + s.toolCalls.length, 0);
@@ -27623,45 +27831,45 @@ function renderSummary(summaries) {
27623
27831
  }
27624
27832
  const topProjects = [...projCosts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
27625
27833
  const W = 20;
27626
- console.log(import_chalk29.default.dim(" " + "\u2500".repeat(70)));
27834
+ console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
27627
27835
  console.log(
27628
- " " + import_chalk29.default.bold.white(String(summaries.length).padEnd(4)) + import_chalk29.default.dim("sessions ") + import_chalk29.default.bold.yellow(fmtCost3(totalCost).padEnd(10)) + import_chalk29.default.dim("total ") + import_chalk29.default.bold.white(String(totalTools).padEnd(6)) + import_chalk29.default.dim("tool calls ") + import_chalk29.default.bold.white(String(totalFiles)) + import_chalk29.default.dim(" files modified") + (totalBlocked > 0 ? import_chalk29.default.dim(" ") + import_chalk29.default.red.bold(String(totalBlocked)) + import_chalk29.default.dim(" blocked by node9") : "")
27836
+ " " + import_chalk30.default.bold.white(String(summaries.length).padEnd(4)) + import_chalk30.default.dim("sessions ") + import_chalk30.default.bold.yellow(fmtCost3(totalCost).padEnd(10)) + import_chalk30.default.dim("total ") + import_chalk30.default.bold.white(String(totalTools).padEnd(6)) + import_chalk30.default.dim("tool calls ") + import_chalk30.default.bold.white(String(totalFiles)) + import_chalk30.default.dim(" files modified") + (totalBlocked > 0 ? import_chalk30.default.dim(" ") + import_chalk30.default.red.bold(String(totalBlocked)) + import_chalk30.default.dim(" blocked by node9") : "")
27629
27837
  );
27630
27838
  console.log(
27631
- " " + import_chalk29.default.dim("avg ") + import_chalk29.default.white(fmtCost3(avgCost).padEnd(10)) + import_chalk29.default.dim("/session ") + import_chalk29.default.green(String(snapshots)) + import_chalk29.default.dim(` of ${summaries.length} sessions had snapshots`)
27839
+ " " + import_chalk30.default.dim("avg ") + import_chalk30.default.white(fmtCost3(avgCost).padEnd(10)) + import_chalk30.default.dim("/session ") + import_chalk30.default.green(String(snapshots)) + import_chalk30.default.dim(` of ${summaries.length} sessions had snapshots`)
27632
27840
  );
27633
27841
  console.log("");
27634
- console.log(" " + import_chalk29.default.dim("Tool breakdown:"));
27842
+ console.log(" " + import_chalk30.default.dim("Tool breakdown:"));
27635
27843
  const maxGroup = Math.max(...Object.values(groups));
27636
27844
  for (const [label2, count] of Object.entries(groups)) {
27637
27845
  if (count === 0) continue;
27638
27846
  const pct = totalTools > 0 ? Math.round(count / totalTools * 100) : 0;
27639
27847
  console.log(
27640
- " " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk29.default.white(String(count).padStart(4)) + import_chalk29.default.dim(` (${String(pct)}%)`)
27848
+ " " + label2.padEnd(6) + " " + colorBar2(count, maxGroup, W) + " " + import_chalk30.default.white(String(count).padStart(4)) + import_chalk30.default.dim(` (${String(pct)}%)`)
27641
27849
  );
27642
27850
  }
27643
27851
  console.log("");
27644
27852
  if (topProjects.length > 1) {
27645
- console.log(" " + import_chalk29.default.dim("Cost by project:"));
27853
+ console.log(" " + import_chalk30.default.dim("Cost by project:"));
27646
27854
  const maxProjCost = topProjects[0][1];
27647
27855
  for (const [proj, cost] of topProjects) {
27648
27856
  console.log(
27649
- " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk29.default.yellow(fmtCost3(cost))
27857
+ " " + proj.slice(0, 28).padEnd(28) + " " + colorBar2(cost, maxProjCost, W) + " " + import_chalk30.default.yellow(fmtCost3(cost))
27650
27858
  );
27651
27859
  }
27652
27860
  console.log("");
27653
27861
  }
27654
- console.log(import_chalk29.default.dim(" " + "\u2500".repeat(70)));
27862
+ console.log(import_chalk30.default.dim(" " + "\u2500".repeat(70)));
27655
27863
  console.log("");
27656
27864
  }
27657
27865
  function renderList(summaries, totalCost) {
27658
27866
  if (summaries.length === 0) {
27659
- console.log(import_chalk29.default.yellow(" No sessions found in the requested range.\n"));
27867
+ console.log(import_chalk30.default.yellow(" No sessions found in the requested range.\n"));
27660
27868
  return;
27661
27869
  }
27662
- const totalLabel = totalCost > 0 ? import_chalk29.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
27870
+ const totalLabel = totalCost > 0 ? import_chalk30.default.dim(" ~" + fmtCost3(totalCost) + " total") : "";
27663
27871
  console.log(
27664
- " " + import_chalk29.default.white(String(summaries.length)) + import_chalk29.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
27872
+ " " + import_chalk30.default.white(String(summaries.length)) + import_chalk30.default.dim(` session${summaries.length !== 1 ? "s" : ""}`) + totalLabel
27665
27873
  );
27666
27874
  console.log("");
27667
27875
  let lastGroup = "";
@@ -27669,51 +27877,51 @@ function renderList(summaries, totalCost) {
27669
27877
  const activeDate = fmtDate2(s.lastActiveTime);
27670
27878
  const group = activeDate + " " + s.projectLabel;
27671
27879
  if (group !== lastGroup) {
27672
- console.log(import_chalk29.default.dim(" \u2500\u2500\u2500 ") + import_chalk29.default.bold(activeDate) + import_chalk29.default.dim(" " + s.projectLabel));
27880
+ console.log(import_chalk30.default.dim(" \u2500\u2500\u2500 ") + import_chalk30.default.bold(activeDate) + import_chalk30.default.dim(" " + s.projectLabel));
27673
27881
  lastGroup = group;
27674
27882
  }
27675
27883
  const startDate = fmtDate2(s.startTime);
27676
- const dateRange = startDate !== activeDate ? import_chalk29.default.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
27677
- const timeStr = import_chalk29.default.dim(fmtTime(s.startTime));
27678
- const prompt = import_chalk29.default.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
27679
- const tools = s.toolCalls.length > 0 ? import_chalk29.default.dim(String(s.toolCalls.length).padStart(3) + " tools") : import_chalk29.default.dim(" 0 tools");
27680
- const cost = s.costUSD > 0 ? import_chalk29.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
27681
- const blocked = s.blockedCalls.length > 0 ? import_chalk29.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
27682
- const snap = s.hasSnapshot ? import_chalk29.default.green(" \u{1F4F8}") : "";
27683
- const agentBadge = import_chalk29.default[agentColorName(s.agent ?? "claude")](
27884
+ const dateRange = startDate !== activeDate ? import_chalk30.default.dim(" (" + startDate + " \u2192 " + activeDate + ")") : "";
27885
+ const timeStr = import_chalk30.default.dim(fmtTime(s.startTime));
27886
+ const prompt = import_chalk30.default.white(truncate(s.firstPrompt.replace(/\n/g, " "), 50).padEnd(50));
27887
+ const tools = s.toolCalls.length > 0 ? import_chalk30.default.dim(String(s.toolCalls.length).padStart(3) + " tools") : import_chalk30.default.dim(" 0 tools");
27888
+ const cost = s.costUSD > 0 ? import_chalk30.default.dim(" " + fmtCost3(s.costUSD).padEnd(8)) : " ";
27889
+ const blocked = s.blockedCalls.length > 0 ? import_chalk30.default.red(" \u{1F6D1} " + String(s.blockedCalls.length)) : "";
27890
+ const snap = s.hasSnapshot ? import_chalk30.default.green(" \u{1F4F8}") : "";
27891
+ const agentBadge = import_chalk30.default[agentColorName(s.agent ?? "claude")](
27684
27892
  " " + agentBadgeText(s.agent ?? "claude", 0)
27685
27893
  );
27686
- const sid = import_chalk29.default.dim(" " + s.sessionId.slice(0, 8));
27894
+ const sid = import_chalk30.default.dim(" " + s.sessionId.slice(0, 8));
27687
27895
  console.log(
27688
27896
  ` ${timeStr} ${prompt} ${tools}${cost}${blocked}${snap}${agentBadge}${sid}${dateRange}`
27689
27897
  );
27690
27898
  }
27691
27899
  console.log("");
27692
27900
  console.log(
27693
- import_chalk29.default.dim(" Run") + " " + import_chalk29.default.cyan("node9 sessions --detail <session-id>") + import_chalk29.default.dim(" for full tool trace.")
27901
+ import_chalk30.default.dim(" Run") + " " + import_chalk30.default.cyan("node9 sessions --detail <session-id>") + import_chalk30.default.dim(" for full tool trace.")
27694
27902
  );
27695
27903
  console.log("");
27696
27904
  }
27697
27905
  function renderDetail(s) {
27698
27906
  console.log("");
27699
- console.log(import_chalk29.default.bold(" Session ") + import_chalk29.default.dim(s.sessionId));
27907
+ console.log(import_chalk30.default.bold(" Session ") + import_chalk30.default.dim(s.sessionId));
27700
27908
  console.log(
27701
- import_chalk29.default.bold(" Prompt ") + import_chalk29.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
27909
+ import_chalk30.default.bold(" Prompt ") + import_chalk30.default.white(s.firstPrompt.replace(/\n/g, " ").slice(0, 120))
27702
27910
  );
27703
- console.log(import_chalk29.default.bold(" Project ") + import_chalk29.default.white(s.projectLabel));
27911
+ console.log(import_chalk30.default.bold(" Project ") + import_chalk30.default.white(s.projectLabel));
27704
27912
  if (s.agent) {
27705
- const agentLabel2 = import_chalk29.default[agentColorName(s.agent)](agentDisplayName(s.agent));
27706
- console.log(import_chalk29.default.bold(" Agent ") + agentLabel2);
27913
+ const agentLabel2 = import_chalk30.default[agentColorName(s.agent)](agentDisplayName(s.agent));
27914
+ console.log(import_chalk30.default.bold(" Agent ") + agentLabel2);
27707
27915
  }
27708
- console.log(import_chalk29.default.bold(" When ") + import_chalk29.default.white(fmtDateTime(s.startTime)));
27916
+ console.log(import_chalk30.default.bold(" When ") + import_chalk30.default.white(fmtDateTime(s.startTime)));
27709
27917
  if (s.costUSD > 0)
27710
- console.log(import_chalk29.default.bold(" Cost ") + import_chalk29.default.yellow("~" + fmtCost3(s.costUSD)));
27918
+ console.log(import_chalk30.default.bold(" Cost ") + import_chalk30.default.yellow("~" + fmtCost3(s.costUSD)));
27711
27919
  console.log(
27712
- import_chalk29.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk29.default.green("\u2713 taken") : import_chalk29.default.dim("none"))
27920
+ import_chalk30.default.bold(" Snapshot ") + (s.hasSnapshot ? import_chalk30.default.green("\u2713 taken") : import_chalk30.default.dim("none"))
27713
27921
  );
27714
27922
  console.log("");
27715
27923
  if (s.toolCalls.length === 0 && s.blockedCalls.length === 0) {
27716
- console.log(import_chalk29.default.dim(" No tool calls recorded.\n"));
27924
+ console.log(import_chalk30.default.dim(" No tool calls recorded.\n"));
27717
27925
  return;
27718
27926
  }
27719
27927
  const timeline = [
@@ -27726,32 +27934,32 @@ function renderDetail(s) {
27726
27934
  });
27727
27935
  const headerParts = [`Tool calls (${s.toolCalls.length})`];
27728
27936
  if (s.blockedCalls.length > 0)
27729
- headerParts.push(import_chalk29.default.red(`${s.blockedCalls.length} blocked by node9`));
27730
- console.log(import_chalk29.default.bold(" " + headerParts.join(" \xB7 ")));
27937
+ headerParts.push(import_chalk30.default.red(`${s.blockedCalls.length} blocked by node9`));
27938
+ console.log(import_chalk30.default.bold(" " + headerParts.join(" \xB7 ")));
27731
27939
  console.log("");
27732
27940
  for (const entry of timeline) {
27733
27941
  if (entry.kind === "tool") {
27734
27942
  const tc = entry.tc;
27735
27943
  const colorFn = toolColor(tc.tool);
27736
27944
  const toolPad = colorFn(tc.tool.padEnd(16));
27737
- const detail = import_chalk29.default.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
27738
- const ts = tc.timestamp ? import_chalk29.default.dim(fmtTime(tc.timestamp) + " ") : " ";
27945
+ const detail = import_chalk30.default.gray(truncate(toolInputSummary(tc.tool, tc.input), 70));
27946
+ const ts = tc.timestamp ? import_chalk30.default.dim(fmtTime(tc.timestamp) + " ") : " ";
27739
27947
  console.log(` ${ts}${toolPad} ${detail}`);
27740
27948
  } else {
27741
27949
  const bc = entry.bc;
27742
- const ts = bc.timestamp ? import_chalk29.default.dim(fmtTime(bc.timestamp) + " ") : " ";
27743
- const label2 = import_chalk29.default.red("\u{1F6D1} BLOCKED".padEnd(16));
27744
- const toolName = import_chalk29.default.red(bc.tool.padEnd(10));
27745
- const argsSummary = bc.args ? import_chalk29.default.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : import_chalk29.default.dim("[args not logged]");
27746
- const reason = bc.checkedBy ? import_chalk29.default.dim(" \u2190 " + bc.checkedBy) : "";
27950
+ const ts = bc.timestamp ? import_chalk30.default.dim(fmtTime(bc.timestamp) + " ") : " ";
27951
+ const label2 = import_chalk30.default.red("\u{1F6D1} BLOCKED".padEnd(16));
27952
+ const toolName = import_chalk30.default.red(bc.tool.padEnd(10));
27953
+ const argsSummary = bc.args ? import_chalk30.default.gray(truncate(toolInputSummary(bc.tool, bc.args), 40)) : import_chalk30.default.dim("[args not logged]");
27954
+ const reason = bc.checkedBy ? import_chalk30.default.dim(" \u2190 " + bc.checkedBy) : "";
27747
27955
  console.log(` ${ts}${label2} ${toolName} ${argsSummary}${reason}`);
27748
27956
  }
27749
27957
  }
27750
27958
  console.log("");
27751
27959
  if (s.modifiedFiles.length > 0) {
27752
- console.log(import_chalk29.default.bold(` Files modified (${s.modifiedFiles.length}):`));
27960
+ console.log(import_chalk30.default.bold(` Files modified (${s.modifiedFiles.length}):`));
27753
27961
  for (const f of s.modifiedFiles) {
27754
- console.log(" " + import_chalk29.default.yellow(f));
27962
+ console.log(" " + import_chalk30.default.yellow(f));
27755
27963
  }
27756
27964
  console.log("");
27757
27965
  }
@@ -27759,13 +27967,13 @@ function renderDetail(s) {
27759
27967
  function registerSessionsCommand(program2) {
27760
27968
  program2.command("sessions").description("Show what your AI agent did \u2014 sessions, tool calls, cost, and file changes").option("--all", "Show all sessions (default: last 7 days)").option("--days <n>", "Show last N days of sessions", "7").option("--detail <sessionId>", "Show full tool trace for a session").action((options) => {
27761
27969
  console.log("");
27762
- console.log(import_chalk29.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk29.default.dim(" \u2014 what your AI agent did"));
27970
+ console.log(import_chalk30.default.cyan.bold("\u{1F4CB} node9 sessions") + import_chalk30.default.dim(" \u2014 what your AI agent did"));
27763
27971
  console.log("");
27764
27972
  const days = options.detail || options.all ? null : Math.max(1, parseInt(options.days, 10) || 7);
27765
27973
  const rangeLabel = options.detail ? "all time" : options.all ? "all time" : `last ${String(days)} days`;
27766
- console.log(import_chalk29.default.dim(" " + rangeLabel));
27974
+ console.log(import_chalk30.default.dim(" " + rangeLabel));
27767
27975
  console.log("");
27768
- process.stdout.write(import_chalk29.default.dim(" Loading\u2026"));
27976
+ process.stdout.write(import_chalk30.default.dim(" Loading\u2026"));
27769
27977
  const summaries = buildSessions(days);
27770
27978
  if (process.stdout.isTTY) {
27771
27979
  process.stdout.clearLine(0);
@@ -27778,8 +27986,8 @@ function registerSessionsCommand(program2) {
27778
27986
  (s) => s.sessionId === options.detail || s.sessionId.startsWith(options.detail)
27779
27987
  );
27780
27988
  if (!target) {
27781
- console.log(import_chalk29.default.red(` Session not found: ${options.detail}`));
27782
- console.log(import_chalk29.default.dim(" Run `node9 sessions` to list recent sessions.\n"));
27989
+ console.log(import_chalk30.default.red(` Session not found: ${options.detail}`));
27990
+ console.log(import_chalk30.default.dim(" Run `node9 sessions` to list recent sessions.\n"));
27783
27991
  return;
27784
27992
  }
27785
27993
  renderDetail(target);
@@ -27792,7 +28000,7 @@ function registerSessionsCommand(program2) {
27792
28000
  }
27793
28001
 
27794
28002
  // src/cli/commands/session-taint.ts
27795
- var import_chalk30 = __toESM(require("chalk"));
28003
+ var import_chalk31 = __toESM(require("chalk"));
27796
28004
  init_daemon();
27797
28005
  function resolveSessionId(records, query) {
27798
28006
  const exact = records.find((r) => r.sessionId === query);
@@ -27819,22 +28027,22 @@ function registerSessionTaintCommand(program2) {
27819
28027
  const records = await listSessionTaints();
27820
28028
  console.log("");
27821
28029
  if (records.length === 0) {
27822
- console.log(import_chalk30.default.dim(" No tainted sessions."));
27823
- console.log(import_chalk30.default.dim(" (Taint lives in the daemon \u2014 a stopped daemon has none.)") + "\n");
28030
+ console.log(import_chalk31.default.dim(" No tainted sessions."));
28031
+ console.log(import_chalk31.default.dim(" (Taint lives in the daemon \u2014 a stopped daemon has none.)") + "\n");
27824
28032
  return;
27825
28033
  }
27826
28034
  console.log(
27827
- " " + import_chalk30.default.bold(String(records.length)) + import_chalk30.default.dim(` tainted session${records.length !== 1 ? "s" : ""}`)
28035
+ " " + import_chalk31.default.bold(String(records.length)) + import_chalk31.default.dim(` tainted session${records.length !== 1 ? "s" : ""}`)
27828
28036
  );
27829
28037
  console.log("");
27830
28038
  for (const r of records) {
27831
28039
  console.log(
27832
- " " + import_chalk30.default.yellow(r.sessionId.slice(0, 8).padEnd(10)) + import_chalk30.default.red(r.source) + sourceGap(r.source) + import_chalk30.default.dim("clears in " + fmtRemaining(r.expiresAt))
28040
+ " " + import_chalk31.default.yellow(r.sessionId.slice(0, 8).padEnd(10)) + import_chalk31.default.red(r.source) + sourceGap(r.source) + import_chalk31.default.dim("clears in " + fmtRemaining(r.expiresAt))
27833
28041
  );
27834
28042
  }
27835
28043
  console.log("");
27836
28044
  console.log(
27837
- import_chalk30.default.dim(" Run ") + import_chalk30.default.cyan("node9 session-taint clear <id>") + import_chalk30.default.dim(" to release one, or ") + import_chalk30.default.cyan("--all") + import_chalk30.default.dim(" for every session.") + "\n"
28045
+ import_chalk31.default.dim(" Run ") + import_chalk31.default.cyan("node9 session-taint clear <id>") + import_chalk31.default.dim(" to release one, or ") + import_chalk31.default.cyan("--all") + import_chalk31.default.dim(" for every session.") + "\n"
27838
28046
  );
27839
28047
  });
27840
28048
  cmd.command("clear").description("Clear a session's taint so its next network/write action isn't held for review").argument("[sessionId]", "Session id to clear (the 8-char prefix from `list` is accepted)").option("--all", "Clear every session taint").action(async (sessionId, opts) => {
@@ -27842,32 +28050,32 @@ function registerSessionTaintCommand(program2) {
27842
28050
  if (opts.all) {
27843
28051
  const res2 = await clearSessionTaint({ all: true });
27844
28052
  if (res2.daemonUnavailable) {
27845
- console.log(import_chalk30.default.dim(" node9 daemon not running \u2014 no active taints to clear.") + "\n");
28053
+ console.log(import_chalk31.default.dim(" node9 daemon not running \u2014 no active taints to clear.") + "\n");
27846
28054
  return;
27847
28055
  }
27848
28056
  console.log(
27849
- import_chalk30.default.green(" \u2713 ") + `Cleared ${import_chalk30.default.bold(String(res2.cleared))} session taint${res2.cleared !== 1 ? "s" : ""}.
28057
+ import_chalk31.default.green(" \u2713 ") + `Cleared ${import_chalk31.default.bold(String(res2.cleared))} session taint${res2.cleared !== 1 ? "s" : ""}.
27850
28058
  `
27851
28059
  );
27852
28060
  return;
27853
28061
  }
27854
28062
  if (!sessionId) {
27855
- console.log(import_chalk30.default.red(" Provide a session id or --all."));
27856
- console.log(import_chalk30.default.dim(" Run `node9 session-taint list` to see tainted sessions.") + "\n");
28063
+ console.log(import_chalk31.default.red(" Provide a session id or --all."));
28064
+ console.log(import_chalk31.default.dim(" Run `node9 session-taint list` to see tainted sessions.") + "\n");
27857
28065
  return;
27858
28066
  }
27859
28067
  const records = await listSessionTaints();
27860
28068
  if (records.length === 0) {
27861
- console.log(import_chalk30.default.dim(" No tainted sessions \u2014 nothing to clear.") + "\n");
28069
+ console.log(import_chalk31.default.dim(" No tainted sessions \u2014 nothing to clear.") + "\n");
27862
28070
  return;
27863
28071
  }
27864
28072
  const resolved = resolveSessionId(records, sessionId);
27865
28073
  if ("error" in resolved) {
27866
28074
  if (resolved.error === "not-found") {
27867
- console.log(import_chalk30.default.red(` No tainted session matches "${sessionId}".`));
28075
+ console.log(import_chalk31.default.red(` No tainted session matches "${sessionId}".`));
27868
28076
  } else {
27869
- console.log(import_chalk30.default.red(` "${sessionId}" is ambiguous \u2014 matches:`));
27870
- for (const m of resolved.matches) console.log(import_chalk30.default.dim(" " + m));
28077
+ console.log(import_chalk31.default.red(` "${sessionId}" is ambiguous \u2014 matches:`));
28078
+ for (const m of resolved.matches) console.log(import_chalk31.default.dim(" " + m));
27871
28079
  }
27872
28080
  console.log("");
27873
28081
  return;
@@ -27875,18 +28083,18 @@ function registerSessionTaintCommand(program2) {
27875
28083
  const res = await clearSessionTaint({ sessionId: resolved.record.sessionId });
27876
28084
  if (res.cleared > 0) {
27877
28085
  console.log(
27878
- import_chalk30.default.green(" \u2713 ") + `Cleared taint for ${import_chalk30.default.yellow(resolved.record.sessionId.slice(0, 8))} ` + import_chalk30.default.dim(`(was flagged by ${resolved.record.source}).`) + "\n"
28086
+ import_chalk31.default.green(" \u2713 ") + `Cleared taint for ${import_chalk31.default.yellow(resolved.record.sessionId.slice(0, 8))} ` + import_chalk31.default.dim(`(was flagged by ${resolved.record.source}).`) + "\n"
27879
28087
  );
27880
28088
  } else {
27881
28089
  console.log(
27882
- import_chalk30.default.dim(` Session ${resolved.record.sessionId.slice(0, 8)} was already clear.`) + "\n"
28090
+ import_chalk31.default.dim(` Session ${resolved.record.sessionId.slice(0, 8)} was already clear.`) + "\n"
27883
28091
  );
27884
28092
  }
27885
28093
  });
27886
28094
  }
27887
28095
 
27888
28096
  // src/cli/commands/skill-pin.ts
27889
- var import_chalk31 = __toESM(require("chalk"));
28097
+ var import_chalk32 = __toESM(require("chalk"));
27890
28098
  var import_fs60 = __toESM(require("fs"));
27891
28099
  var import_os51 = __toESM(require("os"));
27892
28100
  var import_path58 = __toESM(require("path"));
@@ -27906,29 +28114,29 @@ function registerSkillPinCommand(program2) {
27906
28114
  const result = readSkillPinsSafe();
27907
28115
  if (!result.ok) {
27908
28116
  if (result.reason === "missing") {
27909
- console.log(import_chalk31.default.gray("\nNo skill roots are pinned yet."));
28117
+ console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet."));
27910
28118
  console.log(
27911
- import_chalk31.default.gray("Pins are created automatically on the first tool call of each session.\n")
28119
+ import_chalk32.default.gray("Pins are created automatically on the first tool call of each session.\n")
27912
28120
  );
27913
28121
  return;
27914
28122
  }
27915
- console.error(import_chalk31.default.red(`
28123
+ console.error(import_chalk32.default.red(`
27916
28124
  \u274C Pin file is corrupt: ${result.detail}`));
27917
- console.error(import_chalk31.default.yellow(" Run: node9 skill pin reset\n"));
28125
+ console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
27918
28126
  process.exit(1);
27919
28127
  }
27920
28128
  const entries = Object.entries(result.pins.roots);
27921
28129
  if (entries.length === 0) {
27922
- console.log(import_chalk31.default.gray("\nNo skill roots are pinned yet.\n"));
28130
+ console.log(import_chalk32.default.gray("\nNo skill roots are pinned yet.\n"));
27923
28131
  return;
27924
28132
  }
27925
- console.log(import_chalk31.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
28133
+ console.log(import_chalk32.default.bold("\n\u{1F512} Pinned Skill Roots\n"));
27926
28134
  for (const [key, entry] of entries) {
27927
- const missing = entry.exists ? "" : import_chalk31.default.yellow(" (not present at pin time)");
27928
- console.log(` ${import_chalk31.default.cyan(key)} ${import_chalk31.default.gray(entry.rootPath)}${missing}`);
28135
+ const missing = entry.exists ? "" : import_chalk32.default.yellow(" (not present at pin time)");
28136
+ console.log(` ${import_chalk32.default.cyan(key)} ${import_chalk32.default.gray(entry.rootPath)}${missing}`);
27929
28137
  console.log(` Files (${entry.fileCount})`);
27930
- console.log(` Hash: ${import_chalk31.default.gray(entry.contentHash.slice(0, 16))}...`);
27931
- console.log(` Pinned: ${import_chalk31.default.gray(entry.pinnedAt)}
28138
+ console.log(` Hash: ${import_chalk32.default.gray(entry.contentHash.slice(0, 16))}...`);
28139
+ console.log(` Pinned: ${import_chalk32.default.gray(entry.pinnedAt)}
27932
28140
  `);
27933
28141
  }
27934
28142
  });
@@ -27937,39 +28145,39 @@ function registerSkillPinCommand(program2) {
27937
28145
  try {
27938
28146
  pins = readSkillPins();
27939
28147
  } catch {
27940
- console.error(import_chalk31.default.red("\n\u274C Pin file is corrupt."));
27941
- console.error(import_chalk31.default.yellow(" Run: node9 skill pin reset\n"));
28148
+ console.error(import_chalk32.default.red("\n\u274C Pin file is corrupt."));
28149
+ console.error(import_chalk32.default.yellow(" Run: node9 skill pin reset\n"));
27942
28150
  process.exit(1);
27943
28151
  }
27944
28152
  if (!pins.roots[rootKey]) {
27945
- console.error(import_chalk31.default.red(`
28153
+ console.error(import_chalk32.default.red(`
27946
28154
  \u274C No pin found for root key "${rootKey}"
27947
28155
  `));
27948
- console.error(`Run ${import_chalk31.default.cyan("node9 skill pin list")} to see pinned roots.
28156
+ console.error(`Run ${import_chalk32.default.cyan("node9 skill pin list")} to see pinned roots.
27949
28157
  `);
27950
28158
  process.exit(1);
27951
28159
  }
27952
28160
  const rootPath = pins.roots[rootKey].rootPath;
27953
28161
  removePin2(rootKey);
27954
28162
  wipeSkillSessions();
27955
- console.log(import_chalk31.default.green(`
27956
- \u{1F513} Pin removed for ${import_chalk31.default.cyan(rootKey)}`));
27957
- console.log(import_chalk31.default.gray(` ${rootPath}`));
27958
- console.log(import_chalk31.default.gray(" Next session will re-pin with current state.\n"));
28163
+ console.log(import_chalk32.default.green(`
28164
+ \u{1F513} Pin removed for ${import_chalk32.default.cyan(rootKey)}`));
28165
+ console.log(import_chalk32.default.gray(` ${rootPath}`));
28166
+ console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
27959
28167
  });
27960
28168
  pinSubCmd.command("reset").description("Clear all skill pins and wipe session verification flags").action(() => {
27961
28169
  const result = readSkillPinsSafe();
27962
28170
  if (!result.ok && result.reason === "missing") {
27963
28171
  wipeSkillSessions();
27964
- console.log(import_chalk31.default.gray("\nNo pins to clear.\n"));
28172
+ console.log(import_chalk32.default.gray("\nNo pins to clear.\n"));
27965
28173
  return;
27966
28174
  }
27967
28175
  const count = result.ok ? Object.keys(result.pins.roots).length : "?";
27968
28176
  clearAllPins2();
27969
28177
  wipeSkillSessions();
27970
- console.log(import_chalk31.default.green(`
28178
+ console.log(import_chalk32.default.green(`
27971
28179
  \u{1F513} Cleared ${count} skill pin(s).`));
27972
- console.log(import_chalk31.default.gray(" Next session will re-pin with current state.\n"));
28180
+ console.log(import_chalk32.default.gray(" Next session will re-pin with current state.\n"));
27973
28181
  });
27974
28182
  }
27975
28183
 
@@ -27977,7 +28185,7 @@ function registerSkillPinCommand(program2) {
27977
28185
  var import_fs61 = __toESM(require("fs"));
27978
28186
  var import_os52 = __toESM(require("os"));
27979
28187
  var import_path59 = __toESM(require("path"));
27980
- var import_chalk32 = __toESM(require("chalk"));
28188
+ var import_chalk33 = __toESM(require("chalk"));
27981
28189
  var DECISIONS_FILE2 = import_path59.default.join(import_os52.default.homedir(), ".node9", "decisions.json");
27982
28190
  function readDecisions() {
27983
28191
  try {
@@ -28006,55 +28214,55 @@ function registerDecisionsCommand(program2) {
28006
28214
  const decisions = readDecisions();
28007
28215
  const entries = Object.entries(decisions);
28008
28216
  if (entries.length === 0) {
28009
- console.log(import_chalk32.default.gray(" No persistent decisions stored."));
28217
+ console.log(import_chalk33.default.gray(" No persistent decisions stored."));
28010
28218
  console.log(
28011
- import_chalk32.default.gray(` File: ${DECISIONS_FILE2}
28012
- `) + import_chalk32.default.gray(' Decisions are written when you click "Always Allow" or')
28219
+ import_chalk33.default.gray(` File: ${DECISIONS_FILE2}
28220
+ `) + import_chalk33.default.gray(' Decisions are written when you click "Always Allow" or')
28013
28221
  );
28014
- console.log(import_chalk32.default.gray(' "Always Deny" in node9 tail or the native popup.'));
28222
+ console.log(import_chalk33.default.gray(' "Always Deny" in node9 tail or the native popup.'));
28015
28223
  return;
28016
28224
  }
28017
- console.log(import_chalk32.default.bold(`
28225
+ console.log(import_chalk33.default.bold(`
28018
28226
  Persistent decisions (${entries.length})
28019
28227
  `));
28020
28228
  const w = Math.max(...entries.map(([k]) => k.length));
28021
28229
  for (const [tool, verdict] of entries.sort()) {
28022
- const colored = verdict === "allow" ? import_chalk32.default.green(verdict) : import_chalk32.default.red(verdict);
28230
+ const colored = verdict === "allow" ? import_chalk33.default.green(verdict) : import_chalk33.default.red(verdict);
28023
28231
  console.log(` ${tool.padEnd(w)} ${colored}`);
28024
28232
  }
28025
28233
  console.log(
28026
- import_chalk32.default.gray(`
28234
+ import_chalk33.default.gray(`
28027
28235
  Stored in ${DECISIONS_FILE2}
28028
- `) + import_chalk32.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
28236
+ `) + import_chalk33.default.gray(" Run `node9 decisions clear <tool>` to remove an entry.")
28029
28237
  );
28030
28238
  });
28031
28239
  cmd.command("clear <toolName>").description("Remove a persistent decision for one tool").action((toolName) => {
28032
28240
  const decisions = readDecisions();
28033
28241
  if (!(toolName in decisions)) {
28034
- console.log(import_chalk32.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
28242
+ console.log(import_chalk33.default.yellow(` No persistent decision for "${toolName}". Nothing to clear.`));
28035
28243
  process.exitCode = 1;
28036
28244
  return;
28037
28245
  }
28038
28246
  delete decisions[toolName];
28039
28247
  writeDecisions(decisions);
28040
- console.log(import_chalk32.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
28248
+ console.log(import_chalk33.default.green(` \u2713 Cleared persistent decision for "${toolName}".`));
28041
28249
  });
28042
28250
  cmd.command("clear-all").description("Remove every persistent decision (irreversible)").action(() => {
28043
28251
  const decisions = readDecisions();
28044
28252
  const count = Object.keys(decisions).length;
28045
28253
  if (count === 0) {
28046
- console.log(import_chalk32.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
28254
+ console.log(import_chalk33.default.gray(" Nothing to clear \u2014 no persistent decisions stored."));
28047
28255
  return;
28048
28256
  }
28049
28257
  writeDecisions({});
28050
28258
  console.log(
28051
- import_chalk32.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
28259
+ import_chalk33.default.green(` \u2713 Cleared ${count} persistent decision${count === 1 ? "" : "s"}.`)
28052
28260
  );
28053
28261
  });
28054
28262
  }
28055
28263
 
28056
28264
  // src/cli/commands/dlp.ts
28057
- var import_chalk33 = __toESM(require("chalk"));
28265
+ var import_chalk34 = __toESM(require("chalk"));
28058
28266
  var import_fs62 = __toESM(require("fs"));
28059
28267
  var import_path60 = __toESM(require("path"));
28060
28268
  var import_os53 = __toESM(require("os"));
@@ -28109,14 +28317,14 @@ function registerDlpCommand(program2) {
28109
28317
  cmd.command("resolve").description("Mark all current DLP findings as resolved").action(() => {
28110
28318
  const findings = loadDlpFindings();
28111
28319
  if (findings.length === 0) {
28112
- console.log(import_chalk33.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
28320
+ console.log(import_chalk34.default.green("\n \u2705 No response-DLP findings to resolve.\n"));
28113
28321
  return;
28114
28322
  }
28115
28323
  const resolved = loadResolved();
28116
28324
  for (const e of findings) resolved.add(entryKey2(e));
28117
28325
  saveResolved(resolved);
28118
28326
  console.log(
28119
- import_chalk33.default.green(
28327
+ import_chalk34.default.green(
28120
28328
  `
28121
28329
  \u2705 ${findings.length} finding${findings.length !== 1 ? "s" : ""} marked as resolved.
28122
28330
  `
@@ -28130,54 +28338,54 @@ function registerDlpCommand(program2) {
28130
28338
  const resolvedCount = findings.length - open.length;
28131
28339
  console.log("");
28132
28340
  console.log(
28133
- import_chalk33.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk33.default.dim(" \u2014 secrets found in Claude response text")
28341
+ import_chalk34.default.bold.cyan("\u{1F510} node9 dlp") + import_chalk34.default.dim(" \u2014 secrets found in Claude response text")
28134
28342
  );
28135
28343
  console.log("");
28136
28344
  if (open.length === 0) {
28137
28345
  if (resolvedCount > 0) {
28138
- console.log(import_chalk33.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
28346
+ console.log(import_chalk34.default.green(` \u2705 No open findings \xB7 ${resolvedCount} previously resolved`));
28139
28347
  } else {
28140
28348
  console.log(
28141
- import_chalk33.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
28349
+ import_chalk34.default.green(" \u2705 No findings \u2014 Claude has not leaked secrets in response text")
28142
28350
  );
28143
28351
  }
28144
28352
  console.log("");
28145
28353
  return;
28146
28354
  }
28147
28355
  console.log(
28148
- import_chalk33.default.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + import_chalk33.default.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
28356
+ import_chalk34.default.bgRed.white.bold(` \u26A0\uFE0F ${open.length} open finding${open.length !== 1 ? "s" : ""} `) + import_chalk34.default.dim(resolvedCount > 0 ? ` (${resolvedCount} resolved)` : "")
28149
28357
  );
28150
28358
  console.log("");
28151
28359
  console.log(
28152
- import_chalk33.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
28360
+ import_chalk34.default.dim(" These secrets were included in Claude's response text \u2014 NOT blocked.")
28153
28361
  );
28154
- console.log(import_chalk33.default.dim(" Rotate each affected key immediately.\n"));
28362
+ console.log(import_chalk34.default.dim(" Rotate each affected key immediately.\n"));
28155
28363
  for (const e of open) {
28156
28364
  console.log(
28157
- " " + import_chalk33.default.red("\u25CF") + " " + import_chalk33.default.white(e.dlpPattern ?? "Secret") + import_chalk33.default.dim(" " + fmtDate3(e.ts))
28365
+ " " + import_chalk34.default.red("\u25CF") + " " + import_chalk34.default.white(e.dlpPattern ?? "Secret") + import_chalk34.default.dim(" " + fmtDate3(e.ts))
28158
28366
  );
28159
28367
  if (e.dlpSample) {
28160
- console.log(" " + import_chalk33.default.dim("Sample: ") + import_chalk33.default.yellow(stripAnsi(e.dlpSample)));
28368
+ console.log(" " + import_chalk34.default.dim("Sample: ") + import_chalk34.default.yellow(stripAnsi(e.dlpSample)));
28161
28369
  }
28162
28370
  if (e.project) {
28163
- console.log(" " + import_chalk33.default.dim("Project: ") + import_chalk33.default.dim(stripAnsi(e.project)));
28371
+ console.log(" " + import_chalk34.default.dim("Project: ") + import_chalk34.default.dim(stripAnsi(e.project)));
28164
28372
  }
28165
28373
  console.log("");
28166
28374
  }
28167
- console.log(" " + import_chalk33.default.bold("Next steps:"));
28168
- console.log(" " + import_chalk33.default.cyan("1.") + " Rotate any exposed keys shown above");
28375
+ console.log(" " + import_chalk34.default.bold("Next steps:"));
28376
+ console.log(" " + import_chalk34.default.cyan("1.") + " Rotate any exposed keys shown above");
28169
28377
  console.log(
28170
- " " + import_chalk33.default.cyan("2.") + " Run " + import_chalk33.default.white("node9 dlp resolve") + " to acknowledge"
28378
+ " " + import_chalk34.default.cyan("2.") + " Run " + import_chalk34.default.white("node9 dlp resolve") + " to acknowledge"
28171
28379
  );
28172
28380
  console.log(
28173
- " " + import_chalk33.default.cyan("3.") + " Run " + import_chalk33.default.white("node9 report") + " for full audit history"
28381
+ " " + import_chalk34.default.cyan("3.") + " Run " + import_chalk34.default.white("node9 report") + " for full audit history"
28174
28382
  );
28175
28383
  console.log("");
28176
28384
  });
28177
28385
  }
28178
28386
 
28179
28387
  // src/cli/commands/mask.ts
28180
- var import_chalk34 = __toESM(require("chalk"));
28388
+ var import_chalk35 = __toESM(require("chalk"));
28181
28389
  var import_fs63 = __toESM(require("fs"));
28182
28390
  var import_path61 = __toESM(require("path"));
28183
28391
  var import_os54 = __toESM(require("os"));
@@ -28314,12 +28522,12 @@ function registerMaskCommand(program2) {
28314
28522
  }
28315
28523
  }) : allFiles;
28316
28524
  if (filtered.length === 0) {
28317
- console.log(import_chalk34.default.yellow(" No session files found."));
28525
+ console.log(import_chalk35.default.yellow(" No session files found."));
28318
28526
  return;
28319
28527
  }
28320
28528
  console.log("");
28321
28529
  if (dryRun) {
28322
- console.log(import_chalk34.default.dim(" Dry run \u2014 no files will be modified.\n"));
28530
+ console.log(import_chalk35.default.dim(" Dry run \u2014 no files will be modified.\n"));
28323
28531
  }
28324
28532
  let totalFiles = 0;
28325
28533
  let totalLines = 0;
@@ -28335,23 +28543,23 @@ function registerMaskCommand(program2) {
28335
28543
  });
28336
28544
  const verb = dryRun ? "Would redact" : "Redacted";
28337
28545
  console.log(
28338
- " " + import_chalk34.default.dim(shortPath.slice(0, 60).padEnd(62)) + import_chalk34.default.red(`${verb}: `) + import_chalk34.default.yellow(patterns.join(", ")) + import_chalk34.default.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
28546
+ " " + import_chalk35.default.dim(shortPath.slice(0, 60).padEnd(62)) + import_chalk35.default.red(`${verb}: `) + import_chalk35.default.yellow(patterns.join(", ")) + import_chalk35.default.dim(` (${redactedLines} line${redactedLines !== 1 ? "s" : ""})`)
28339
28547
  );
28340
28548
  }
28341
28549
  }
28342
28550
  console.log("");
28343
28551
  if (totalFiles === 0) {
28344
- console.log(import_chalk34.default.green(" No secrets found in session history."));
28552
+ console.log(import_chalk35.default.green(" No secrets found in session history."));
28345
28553
  } else {
28346
28554
  const verb = dryRun ? "would be modified" : "modified";
28347
28555
  console.log(
28348
- import_chalk34.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk34.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
28556
+ import_chalk35.default.bold(` ${totalFiles} file${totalFiles !== 1 ? "s" : ""} ${verb}`) + import_chalk35.default.dim(`, ${totalLines} line${totalLines !== 1 ? "s" : ""} redacted`)
28349
28557
  );
28350
- console.log(" Patterns: " + import_chalk34.default.yellow(totalPatterns.join(", ")));
28558
+ console.log(" Patterns: " + import_chalk35.default.yellow(totalPatterns.join(", ")));
28351
28559
  if (!dryRun) {
28352
28560
  console.log("");
28353
28561
  console.log(
28354
- import_chalk34.default.dim(
28562
+ import_chalk35.default.dim(
28355
28563
  " Note: secrets were already sent to the AI provider during the active session.\n This cleans your local disk only. Rotate any exposed keys."
28356
28564
  )
28357
28565
  );
@@ -28369,77 +28577,34 @@ var { version } = JSON.parse(
28369
28577
  var program = new import_commander.Command();
28370
28578
  program.name("node9").description("The Sudo Command for AI Agents").version(version);
28371
28579
  program.command("login").argument("<apiKey>").option("--local", "Save key for audit/logging only \u2014 local config still controls all decisions").option("--profile <name>", 'Save as a named profile (default: "default")').action((apiKey, options) => {
28372
- const DEFAULT_API_URL2 = "https://api.node9.ai/api/v1/intercept";
28373
- const credPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "credentials.json");
28374
- if (!import_fs66.default.existsSync(import_path64.default.dirname(credPath)))
28375
- import_fs66.default.mkdirSync(import_path64.default.dirname(credPath), { recursive: true });
28376
- const profileName = options.profile || "default";
28377
- let existingCreds = {};
28378
- try {
28379
- if (import_fs66.default.existsSync(credPath)) {
28380
- const raw = JSON.parse(import_fs66.default.readFileSync(credPath, "utf-8"));
28381
- if (raw.apiKey) {
28382
- existingCreds = {
28383
- default: { apiKey: raw.apiKey, apiUrl: raw.apiUrl || DEFAULT_API_URL2 }
28384
- };
28385
- } else {
28386
- existingCreds = raw;
28387
- }
28388
- }
28389
- } catch {
28390
- }
28391
- existingCreds[profileName] = { apiKey, apiUrl: DEFAULT_API_URL2 };
28392
- import_fs66.default.writeFileSync(credPath, JSON.stringify(existingCreds, null, 2), { mode: 384 });
28393
- let effectiveCloud = null;
28394
- if (profileName === "default") {
28395
- const configPath = import_path64.default.join(import_os57.default.homedir(), ".node9", "config.json");
28396
- let config = {};
28397
- try {
28398
- if (import_fs66.default.existsSync(configPath))
28399
- config = JSON.parse(import_fs66.default.readFileSync(configPath, "utf-8"));
28400
- } catch {
28401
- }
28402
- if (!config.settings || typeof config.settings !== "object") config.settings = {};
28403
- const s = config.settings;
28404
- const approvers = s.approvers || {
28405
- native: true,
28406
- browser: true,
28407
- cloud: true,
28408
- terminal: true
28409
- };
28410
- if (options.local) {
28411
- approvers.cloud = false;
28412
- }
28413
- s.approvers = approvers;
28414
- if (!import_fs66.default.existsSync(import_path64.default.dirname(configPath)))
28415
- import_fs66.default.mkdirSync(import_path64.default.dirname(configPath), { recursive: true });
28416
- import_fs66.default.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
28417
- effectiveCloud = approvers.cloud === true;
28418
- }
28580
+ const { profileName, effectiveCloud } = writeCredentialsAndConfig(apiKey, {
28581
+ profileName: options.profile,
28582
+ isLocal: options.local
28583
+ });
28419
28584
  if (options.profile && profileName !== "default") {
28420
- console.log(import_chalk36.default.green(`\u2705 Profile "${profileName}" saved`));
28421
- console.log(import_chalk36.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
28585
+ console.log(import_chalk37.default.green(`\u2705 Profile "${profileName}" saved`));
28586
+ console.log(import_chalk37.default.gray(` Switch to it per-session: NODE9_PROFILE=${profileName} claude`));
28422
28587
  } else if (options.local || effectiveCloud === false) {
28423
- console.log(import_chalk36.default.green(`\u2705 Key saved \u2014 Privacy mode \u{1F6E1}\uFE0F`));
28424
- console.log(import_chalk36.default.gray(` All decisions stay on this machine. Nothing syncs to the cloud.`));
28588
+ console.log(import_chalk37.default.green(`\u2705 Key saved \u2014 Privacy mode \u{1F6E1}\uFE0F`));
28589
+ console.log(import_chalk37.default.gray(` All decisions stay on this machine. Nothing syncs to the cloud.`));
28425
28590
  if (!options.local) {
28426
28591
  console.log(
28427
- import_chalk36.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
28592
+ import_chalk37.default.yellow(` Your config has cloud approvals OFF (settings.approvers.cloud).`)
28428
28593
  );
28429
28594
  console.log(
28430
- import_chalk36.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
28595
+ import_chalk37.default.gray(` To enable team policy + dashboard sync: set it to true, or re-init.`)
28431
28596
  );
28432
28597
  }
28433
28598
  } else {
28434
- console.log(import_chalk36.default.green(`\u2705 Logged in \u2014 agent mode`));
28435
- console.log(import_chalk36.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
28599
+ console.log(import_chalk37.default.green(`\u2705 Logged in \u2014 agent mode`));
28600
+ console.log(import_chalk37.default.gray(` Team policy enforced for all calls via Node9 cloud.`));
28436
28601
  }
28437
28602
  });
28438
28603
  program.command("signup").description("Create your node9 account / open the dashboard in your browser").option("--login", "Open the login page instead of signup").action((options) => {
28439
28604
  const route = options.login ? "auth/login" : "auth/signup";
28440
28605
  const url = `https://node9.ai/${route}?ref=cli_cmd`;
28441
28606
  console.log("");
28442
- console.log(" " + import_chalk36.default.dim("Opening ") + import_chalk36.default.cyan.underline(url));
28607
+ console.log(" " + import_chalk37.default.dim("Opening ") + import_chalk37.default.cyan.underline(url));
28443
28608
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
28444
28609
  try {
28445
28610
  const child = (0, import_child_process15.spawn)(opener, [url], {
@@ -28472,7 +28637,7 @@ program.command("addto", { hidden: true }).description("Integrate Node9 with an
28472
28637
  if (target === "hermes") return setupHermes();
28473
28638
  if (target === "hud") return setupHud();
28474
28639
  console.error(
28475
- import_chalk36.default.red(
28640
+ import_chalk37.default.red(
28476
28641
  `Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
28477
28642
  )
28478
28643
  );
@@ -28486,20 +28651,20 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
28486
28651
  "The agent to protect: claude | antigravity | copilot | gemini | cursor | codex | windsurf | vscode | hud"
28487
28652
  ).action(async (target) => {
28488
28653
  if (!target) {
28489
- console.log(import_chalk36.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
28490
- console.log(" Usage: " + import_chalk36.default.white("node9 setup <target>") + "\n");
28654
+ console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Setup \u2014 integrate with your AI agent\n"));
28655
+ console.log(" Usage: " + import_chalk37.default.white("node9 setup <target>") + "\n");
28491
28656
  console.log(" Targets:");
28492
- console.log(" " + import_chalk36.default.green("claude") + " \u2014 Claude Code (hook mode)");
28493
- console.log(" " + import_chalk36.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
28494
- console.log(" " + import_chalk36.default.green("antigravity") + " \u2014 Antigravity / agy (hook mode)");
28495
- console.log(" " + import_chalk36.default.green("copilot") + " \u2014 GitHub Copilot CLI (hook mode)");
28496
- console.log(" " + import_chalk36.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
28497
- console.log(" " + import_chalk36.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
28498
- console.log(" " + import_chalk36.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
28499
- console.log(" " + import_chalk36.default.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
28500
- console.log(" " + import_chalk36.default.green("hermes") + " \u2014 Hermes Agent (hook mode)");
28657
+ console.log(" " + import_chalk37.default.green("claude") + " \u2014 Claude Code (hook mode)");
28658
+ console.log(" " + import_chalk37.default.green("gemini") + " \u2014 Gemini CLI (hook mode)");
28659
+ console.log(" " + import_chalk37.default.green("antigravity") + " \u2014 Antigravity / agy (hook mode)");
28660
+ console.log(" " + import_chalk37.default.green("copilot") + " \u2014 GitHub Copilot CLI (hook mode)");
28661
+ console.log(" " + import_chalk37.default.green("cursor") + " \u2014 Cursor (MCP proxy)");
28662
+ console.log(" " + import_chalk37.default.green("codex") + " \u2014 OpenAI Codex CLI (MCP proxy)");
28663
+ console.log(" " + import_chalk37.default.green("windsurf") + " \u2014 Windsurf (MCP proxy)");
28664
+ console.log(" " + import_chalk37.default.green("vscode") + " \u2014 VSCode / Copilot (MCP proxy)");
28665
+ console.log(" " + import_chalk37.default.green("hermes") + " \u2014 Hermes Agent (hook mode)");
28501
28666
  process.stdout.write(
28502
- " " + import_chalk36.default.green("hud") + " \u2014 Claude Code security statusline\n"
28667
+ " " + import_chalk37.default.green("hud") + " \u2014 Claude Code security statusline\n"
28503
28668
  );
28504
28669
  console.log("");
28505
28670
  return;
@@ -28516,7 +28681,7 @@ program.command("setup", { hidden: true }).description('Alias for "addto" \u2014
28516
28681
  if (t === "hermes") return setupHermes();
28517
28682
  if (t === "hud") return setupHud();
28518
28683
  console.error(
28519
- import_chalk36.default.red(
28684
+ import_chalk37.default.red(
28520
28685
  `Unknown target: "${target}". Supported: claude, antigravity, copilot, gemini, cursor, codex, windsurf, vscode, hermes, hud`
28521
28686
  )
28522
28687
  );
@@ -28527,32 +28692,32 @@ program.command("removefrom", { hidden: true }).description("Remove Node9 hooks
28527
28692
  const agent = resolveAgentTeardown(target);
28528
28693
  if (!agent) {
28529
28694
  console.error(
28530
- import_chalk36.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
28695
+ import_chalk37.default.red(`Unknown target: "${target}". Supported: ${agentTeardownTargets().join(", ")}`)
28531
28696
  );
28532
28697
  process.exit(1);
28533
28698
  return;
28534
28699
  }
28535
- console.log(import_chalk36.default.cyan(`
28700
+ console.log(import_chalk37.default.cyan(`
28536
28701
  \u{1F6E1}\uFE0F Node9: removing hooks from ${agent.label}...
28537
28702
  `));
28538
28703
  try {
28539
28704
  agent.fn();
28540
28705
  } catch (err2) {
28541
- console.error(import_chalk36.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
28706
+ console.error(import_chalk37.default.red(` \u26A0\uFE0F Failed: ${err2 instanceof Error ? err2.message : String(err2)}`));
28542
28707
  process.exit(1);
28543
28708
  }
28544
- console.log(import_chalk36.default.gray("\n Restart the agent for changes to take effect."));
28709
+ console.log(import_chalk37.default.gray("\n Restart the agent for changes to take effect."));
28545
28710
  });
28546
28711
  program.command("uninstall").description("Remove all Node9 hooks and optionally delete config files").option("--purge", "Also delete ~/.node9/ directory (config, audit log, credentials)").action(async (options) => {
28547
- console.log(import_chalk36.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
28548
- console.log(import_chalk36.default.bold("Stopping daemon..."));
28712
+ console.log(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
28713
+ console.log(import_chalk37.default.bold("Stopping daemon..."));
28549
28714
  try {
28550
28715
  stopDaemon();
28551
- console.log(import_chalk36.default.green(" \u2705 Daemon stopped"));
28716
+ console.log(import_chalk37.default.green(" \u2705 Daemon stopped"));
28552
28717
  } catch {
28553
- console.log(import_chalk36.default.blue(" \u2139\uFE0F Daemon was not running"));
28718
+ console.log(import_chalk37.default.blue(" \u2139\uFE0F Daemon was not running"));
28554
28719
  }
28555
- console.log(import_chalk36.default.bold("\nRemoving hooks..."));
28720
+ console.log(import_chalk37.default.bold("\nRemoving hooks..."));
28556
28721
  let teardownFailed = false;
28557
28722
  for (const { label: label2, fn } of AGENT_TEARDOWNS) {
28558
28723
  try {
@@ -28560,7 +28725,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28560
28725
  } catch (err2) {
28561
28726
  teardownFailed = true;
28562
28727
  console.error(
28563
- import_chalk36.default.red(
28728
+ import_chalk37.default.red(
28564
28729
  ` \u26A0\uFE0F Failed to remove ${label2} hooks: ${err2 instanceof Error ? err2.message : String(err2)}`
28565
28730
  )
28566
28731
  );
@@ -28569,12 +28734,12 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28569
28734
  try {
28570
28735
  const residual = getAgentWiring().filter((a) => a.wireState === "wired");
28571
28736
  if (residual.length === 0) {
28572
- console.log(import_chalk36.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
28737
+ console.log(import_chalk37.default.green(" \u2705 Verified \u2014 no node9 hooks or plugin shims remain"));
28573
28738
  } else {
28574
28739
  teardownFailed = true;
28575
- console.error(import_chalk36.default.red(" \u26A0\uFE0F Still wired after teardown:"));
28740
+ console.error(import_chalk37.default.red(" \u26A0\uFE0F Still wired after teardown:"));
28576
28741
  for (const a of residual) {
28577
- console.error(import_chalk36.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
28742
+ console.error(import_chalk37.default.red(` \u2022 ${a.label} \u2014 ${a.settingsPath}`));
28578
28743
  }
28579
28744
  }
28580
28745
  } catch {
@@ -28590,28 +28755,28 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
28590
28755
  import_fs66.default.rmSync(node9Dir, { recursive: true });
28591
28756
  if (import_fs66.default.existsSync(node9Dir)) {
28592
28757
  console.error(
28593
- import_chalk36.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
28758
+ import_chalk37.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
28594
28759
  );
28595
28760
  } else {
28596
- console.log(import_chalk36.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
28761
+ console.log(import_chalk37.default.green("\n \u2705 Deleted ~/.node9/ (config, audit log, credentials)"));
28597
28762
  }
28598
28763
  } else {
28599
- console.log(import_chalk36.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
28764
+ console.log(import_chalk37.default.yellow("\n Skipped \u2014 ~/.node9/ was not deleted."));
28600
28765
  }
28601
28766
  } else {
28602
- console.log(import_chalk36.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
28767
+ console.log(import_chalk37.default.blue("\n \u2139\uFE0F ~/.node9/ not found \u2014 nothing to delete"));
28603
28768
  }
28604
28769
  } else {
28605
28770
  console.log(
28606
- import_chalk36.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
28771
+ import_chalk37.default.gray("\n ~/.node9/ kept \u2014 run with --purge to delete config and audit log")
28607
28772
  );
28608
28773
  }
28609
28774
  if (teardownFailed) {
28610
- console.error(import_chalk36.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
28775
+ console.error(import_chalk37.default.red("\n \u26A0\uFE0F Some hooks could not be removed \u2014 see errors above."));
28611
28776
  process.exit(1);
28612
28777
  }
28613
- console.log(import_chalk36.default.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g node9-ai"));
28614
- console.log(import_chalk36.default.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
28778
+ console.log(import_chalk37.default.green.bold("\n\u{1F6E1}\uFE0F Node9 removed. Run: npm uninstall -g node9-ai"));
28779
+ console.log(import_chalk37.default.gray(" Restart any open AI agent sessions for changes to take effect.\n"));
28615
28780
  });
28616
28781
  registerDoctorCommand(program, version);
28617
28782
  program.command("explain").description(
@@ -28624,7 +28789,7 @@ program.command("explain").description(
28624
28789
  try {
28625
28790
  args = JSON.parse(trimmed);
28626
28791
  } catch {
28627
- console.error(import_chalk36.default.red(`
28792
+ console.error(import_chalk37.default.red(`
28628
28793
  \u274C Invalid JSON: ${trimmed}
28629
28794
  `));
28630
28795
  process.exit(1);
@@ -28635,67 +28800,68 @@ program.command("explain").description(
28635
28800
  }
28636
28801
  const result = await explainPolicy(tool, args);
28637
28802
  console.log("");
28638
- console.log(import_chalk36.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
28803
+ console.log(import_chalk37.default.cyan.bold("\u{1F6E1}\uFE0F Node9 Explain"));
28639
28804
  console.log("");
28640
- console.log(` ${import_chalk36.default.bold("Tool:")} ${import_chalk36.default.white(result.tool)}`);
28805
+ console.log(` ${import_chalk37.default.bold("Tool:")} ${import_chalk37.default.white(result.tool)}`);
28641
28806
  if (argsRaw) {
28642
28807
  const preview2 = argsRaw.length > 80 ? argsRaw.slice(0, 77) + "\u2026" : argsRaw;
28643
- console.log(` ${import_chalk36.default.bold("Input:")} ${import_chalk36.default.gray(preview2)}`);
28808
+ console.log(` ${import_chalk37.default.bold("Input:")} ${import_chalk37.default.gray(preview2)}`);
28644
28809
  }
28645
28810
  console.log("");
28646
- console.log(import_chalk36.default.bold("Config Sources (Waterfall):"));
28811
+ console.log(import_chalk37.default.bold("Config Sources (Waterfall):"));
28647
28812
  for (const tier of result.waterfall) {
28648
- const num3 = import_chalk36.default.gray(` ${tier.tier}.`);
28813
+ const num3 = import_chalk37.default.gray(` ${tier.tier}.`);
28649
28814
  const label2 = tier.label.padEnd(16);
28650
28815
  let statusStr;
28651
28816
  if (tier.tier === 1) {
28652
- statusStr = import_chalk36.default.gray(tier.note ?? "");
28817
+ statusStr = import_chalk37.default.gray(tier.note ?? "");
28653
28818
  } else if (tier.status === "active") {
28654
- const loc = tier.path ? import_chalk36.default.gray(tier.path) : "";
28655
- const note = tier.note ? import_chalk36.default.gray(`(${tier.note})`) : "";
28656
- statusStr = import_chalk36.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
28819
+ const loc = tier.path ? import_chalk37.default.gray(tier.path) : "";
28820
+ const note = tier.note ? import_chalk37.default.gray(`(${tier.note})`) : "";
28821
+ statusStr = import_chalk37.default.green("\u2713 active") + (loc ? " " + loc : "") + (note ? " " + note : "");
28657
28822
  } else {
28658
- statusStr = import_chalk36.default.gray("\u25CB " + (tier.note ?? "not found"));
28823
+ statusStr = import_chalk37.default.gray("\u25CB " + (tier.note ?? "not found"));
28659
28824
  }
28660
- console.log(`${num3} ${import_chalk36.default.white(label2)} ${statusStr}`);
28825
+ console.log(`${num3} ${import_chalk37.default.white(label2)} ${statusStr}`);
28661
28826
  }
28662
28827
  console.log("");
28663
- console.log(import_chalk36.default.bold("Policy Evaluation:"));
28828
+ console.log(import_chalk37.default.bold("Policy Evaluation:"));
28664
28829
  for (const step of result.steps) {
28665
28830
  const isFinal = step.isFinal;
28666
28831
  let icon;
28667
- if (step.outcome === "allow") icon = import_chalk36.default.green(" \u2705");
28668
- else if (step.outcome === "block") icon = import_chalk36.default.red(" \u{1F6D1}");
28669
- else if (step.outcome === "review") icon = import_chalk36.default.red(" \u{1F534}");
28670
- else if (step.outcome === "skip") icon = import_chalk36.default.gray(" \u2500 ");
28671
- else icon = import_chalk36.default.gray(" \u25CB ");
28832
+ if (step.outcome === "allow") icon = import_chalk37.default.green(" \u2705");
28833
+ else if (step.outcome === "block") icon = import_chalk37.default.red(" \u{1F6D1}");
28834
+ else if (step.outcome === "review") icon = import_chalk37.default.red(" \u{1F534}");
28835
+ else if (step.outcome === "skip") icon = import_chalk37.default.gray(" \u2500 ");
28836
+ else icon = import_chalk37.default.gray(" \u25CB ");
28672
28837
  const name = step.name.padEnd(18);
28673
- const nameStr = isFinal ? import_chalk36.default.white.bold(name) : import_chalk36.default.white(name);
28674
- const detail = isFinal ? import_chalk36.default.white(step.detail) : import_chalk36.default.gray(step.detail);
28675
- const arrow = isFinal ? import_chalk36.default.yellow(" \u2190 STOP") : "";
28838
+ const nameStr = isFinal ? import_chalk37.default.white.bold(name) : import_chalk37.default.white(name);
28839
+ const detail = isFinal ? import_chalk37.default.white(step.detail) : import_chalk37.default.gray(step.detail);
28840
+ const arrow = isFinal ? import_chalk37.default.yellow(" \u2190 STOP") : "";
28676
28841
  console.log(`${icon} ${nameStr} ${detail}${arrow}`);
28677
28842
  }
28678
28843
  console.log("");
28679
28844
  if (result.decision === "allow") {
28680
- console.log(import_chalk36.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk36.default.gray(" \u2014 no approval needed"));
28845
+ console.log(import_chalk37.default.green.bold(" Decision: \u2705 ALLOW") + import_chalk37.default.gray(" \u2014 no approval needed"));
28681
28846
  } else if (result.decision === "block") {
28682
28847
  console.log(
28683
- import_chalk36.default.red.bold(" Decision: \u{1F6D1} BLOCK") + import_chalk36.default.gray(" \u2014 this action is blocked")
28848
+ import_chalk37.default.red.bold(" Decision: \u{1F6D1} BLOCK") + import_chalk37.default.gray(" \u2014 this action is blocked")
28684
28849
  );
28685
28850
  if (result.blockedByLabel) {
28686
- console.log(import_chalk36.default.gray(` Reason: ${result.blockedByLabel}`));
28851
+ console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
28687
28852
  }
28688
28853
  } else {
28689
28854
  console.log(
28690
- import_chalk36.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk36.default.gray(" \u2014 human approval required")
28855
+ import_chalk37.default.red.bold(" Decision: \u{1F534} REVIEW") + import_chalk37.default.gray(" \u2014 human approval required")
28691
28856
  );
28692
28857
  if (result.blockedByLabel) {
28693
- console.log(import_chalk36.default.gray(` Reason: ${result.blockedByLabel}`));
28858
+ console.log(import_chalk37.default.gray(` Reason: ${result.blockedByLabel}`));
28694
28859
  }
28695
28860
  }
28696
28861
  console.log("");
28697
28862
  });
28698
28863
  registerInitCommand(program);
28864
+ registerConnectCommand(program);
28699
28865
  registerAuditCommand(program);
28700
28866
  registerReportCommand(program);
28701
28867
  registerStatusCommand(program);
@@ -28705,7 +28871,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
28705
28871
  try {
28706
28872
  await startTail2(options);
28707
28873
  } catch (err2) {
28708
- console.error(import_chalk36.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28874
+ console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28709
28875
  process.exit(1);
28710
28876
  }
28711
28877
  });
@@ -28716,7 +28882,7 @@ program.command("monitor").description("Live interactive dashboard \u2014 activi
28716
28882
  const mod = await dynamicImport(`file://${dashboardPath}`);
28717
28883
  await mod.startMonitor();
28718
28884
  } catch (err2) {
28719
- console.error(import_chalk36.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28885
+ console.error(import_chalk37.default.red(`\u274C ${err2 instanceof Error ? err2.message : String(err2)}`));
28720
28886
  process.exit(1);
28721
28887
  }
28722
28888
  });
@@ -28771,7 +28937,7 @@ program.command("pause").description("Temporarily disable Node9 protection for a
28771
28937
  const ms = parseDuration(options.duration);
28772
28938
  if (ms === null) {
28773
28939
  console.error(
28774
- import_chalk36.default.red(`
28940
+ import_chalk37.default.red(`
28775
28941
  \u274C Invalid duration: "${options.duration}". Use format like 15m, 1h, 30s.
28776
28942
  `)
28777
28943
  );
@@ -28779,20 +28945,20 @@ program.command("pause").description("Temporarily disable Node9 protection for a
28779
28945
  }
28780
28946
  pauseNode9(ms, options.duration);
28781
28947
  const expiresAt = new Date(Date.now() + ms).toLocaleTimeString();
28782
- console.log(import_chalk36.default.yellow(`
28948
+ console.log(import_chalk37.default.yellow(`
28783
28949
  \u23F8 Node9 paused until ${expiresAt}`));
28784
- console.log(import_chalk36.default.gray(` All tool calls will be allowed without review.`));
28785
- console.log(import_chalk36.default.gray(` Run "node9 resume" to re-enable early.
28950
+ console.log(import_chalk37.default.gray(` All tool calls will be allowed without review.`));
28951
+ console.log(import_chalk37.default.gray(` Run "node9 resume" to re-enable early.
28786
28952
  `));
28787
28953
  });
28788
28954
  program.command("resume").description("Re-enable Node9 protection immediately").action(() => {
28789
28955
  const { paused } = checkPause();
28790
28956
  if (!paused) {
28791
- console.log(import_chalk36.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
28957
+ console.log(import_chalk37.default.gray("\nNode9 is already active \u2014 nothing to resume.\n"));
28792
28958
  return;
28793
28959
  }
28794
28960
  resumeNode9();
28795
- console.log(import_chalk36.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
28961
+ console.log(import_chalk37.default.green("\n\u25B6 Node9 resumed \u2014 protection is active.\n"));
28796
28962
  });
28797
28963
  var HOOK_BASED_AGENTS = {
28798
28964
  claude: "claude",
@@ -28808,15 +28974,15 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28808
28974
  if (HOOK_BASED_AGENTS[firstArg2] !== void 0) {
28809
28975
  const target = HOOK_BASED_AGENTS[firstArg2];
28810
28976
  console.error(
28811
- import_chalk36.default.yellow(`
28977
+ import_chalk37.default.yellow(`
28812
28978
  \u26A0\uFE0F Node9 proxy mode does not support "${target}" directly.`)
28813
28979
  );
28814
- console.error(import_chalk36.default.white(`
28980
+ console.error(import_chalk37.default.white(`
28815
28981
  "${target}" uses its own hook system. Use:`));
28816
28982
  console.error(
28817
- import_chalk36.default.green(` node9 addto ${target} `) + import_chalk36.default.gray("# one-time setup")
28983
+ import_chalk37.default.green(` node9 addto ${target} `) + import_chalk37.default.gray("# one-time setup")
28818
28984
  );
28819
- console.error(import_chalk36.default.green(` ${target} `) + import_chalk36.default.gray("# run normally"));
28985
+ console.error(import_chalk37.default.green(` ${target} `) + import_chalk37.default.gray("# run normally"));
28820
28986
  process.exit(1);
28821
28987
  }
28822
28988
  const runArgs = firstArg2 === "shell" ? commandArgs.slice(1) : commandArgs;
@@ -28833,7 +28999,7 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28833
28999
  }
28834
29000
  );
28835
29001
  if (result.noApprovalMechanism && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON && getConfig().settings.autoStartDaemon) {
28836
- console.error(import_chalk36.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
29002
+ console.error(import_chalk37.default.cyan("\n\u{1F6E1}\uFE0F Node9: Starting approval daemon automatically..."));
28837
29003
  const daemonReady = await autoStartDaemonAndWait();
28838
29004
  if (daemonReady) result = await authorizeHeadless("shell", { command: fullCommand });
28839
29005
  }
@@ -28846,12 +29012,12 @@ program.argument("[command...]", "The agent command to run (e.g., gemini)").acti
28846
29012
  }
28847
29013
  if (!result.approved) {
28848
29014
  console.error(
28849
- import_chalk36.default.red(`
29015
+ import_chalk37.default.red(`
28850
29016
  \u274C Node9 Blocked: ${result.reason || "Dangerous command detected."}`)
28851
29017
  );
28852
29018
  process.exit(1);
28853
29019
  }
28854
- console.error(import_chalk36.default.green("\n\u2705 Approved \u2014 running command...\n"));
29020
+ console.error(import_chalk37.default.green("\n\u2705 Approved \u2014 running command...\n"));
28855
29021
  await runProxy(fullCommand);
28856
29022
  } else {
28857
29023
  program.help();