@node9/proxy 1.8.2 → 1.8.4

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
@@ -2872,9 +2872,7 @@ end run`;
2872
2872
  "--text",
2873
2873
  pangoMessage,
2874
2874
  "--ok-label",
2875
- locked ? "Waiting..." : "Allow \u21B5",
2876
- "--timeout",
2877
- "300"
2875
+ locked ? "Waiting..." : "Allow \u21B5"
2878
2876
  ];
2879
2877
  if (!locked) {
2880
2878
  argsList.push("--cancel-label", "Block \u238B");
@@ -5691,6 +5689,12 @@ function estimateToolCost(tool, args) {
5691
5689
  const newStr = a.new_string ?? "";
5692
5690
  return String(newStr).length / BYTES_PER_TOKEN / 1e6 * OUTPUT_PRICE_PER_1M;
5693
5691
  }
5692
+ if (t === "bash" || t === "shell" || t === "run_shell_command" || t === "terminal_execute") {
5693
+ const command = String(a.command ?? a.cmd ?? a.input ?? "");
5694
+ if (command.length > 0) {
5695
+ return command.length / BYTES_PER_TOKEN / 1e6 * OUTPUT_PRICE_PER_1M;
5696
+ }
5697
+ }
5694
5698
  return void 0;
5695
5699
  }
5696
5700
  function broadcast(event, data) {
@@ -6823,7 +6827,7 @@ async function ensureDaemon() {
6823
6827
  } catch {
6824
6828
  }
6825
6829
  console.log(import_chalk17.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon..."));
6826
- const child = (0, import_child_process13.spawn)(process.execPath, [process.argv[1], "daemon"], {
6830
+ const child = (0, import_child_process14.spawn)(process.execPath, [process.argv[1], "daemon"], {
6827
6831
  detached: true,
6828
6832
  stdio: "ignore",
6829
6833
  env: { ...process.env, NODE9_AUTO_STARTED: "1" }
@@ -6997,6 +7001,7 @@ async function startTail(options = {}) {
6997
7001
  return;
6998
7002
  }
6999
7003
  const connectionTime = Date.now();
7004
+ let initialReplayDone = false;
7000
7005
  const activityPending = /* @__PURE__ */ new Map();
7001
7006
  const orphanedResults = /* @__PURE__ */ new Map();
7002
7007
  let csrfToken = "";
@@ -7192,10 +7197,10 @@ async function startTail(options = {}) {
7192
7197
  try {
7193
7198
  const browserEnabled = getConfig().settings.approvers?.browser !== false;
7194
7199
  if (browserEnabled) {
7195
- if (process.platform === "darwin") (0, import_child_process13.execSync)(`open "${dashboardUrl}"`, { stdio: "ignore" });
7200
+ if (process.platform === "darwin") (0, import_child_process14.execSync)(`open "${dashboardUrl}"`, { stdio: "ignore" });
7196
7201
  else if (process.platform === "win32")
7197
- (0, import_child_process13.execSync)(`cmd /c start "" "${dashboardUrl}"`, { stdio: "ignore" });
7198
- else (0, import_child_process13.execSync)(`xdg-open "${dashboardUrl}"`, { stdio: "ignore" });
7202
+ (0, import_child_process14.execSync)(`cmd /c start "" "${dashboardUrl}"`, { stdio: "ignore" });
7203
+ else (0, import_child_process14.execSync)(`xdg-open "${dashboardUrl}"`, { stdio: "ignore" });
7199
7204
  const intToken = getInternalToken();
7200
7205
  fetch(`http://127.0.0.1:${port}/browser-opened`, {
7201
7206
  method: "POST",
@@ -7328,11 +7333,17 @@ async function startTail(options = {}) {
7328
7333
  return;
7329
7334
  }
7330
7335
  if (event === "activity") {
7336
+ const isReplayEvent = data.status && data.status !== "pending";
7337
+ if (isReplayEvent && !initialReplayDone) {
7338
+ renderResult(data, data);
7339
+ return;
7340
+ }
7331
7341
  if (!options.history && data.ts > 0 && data.ts < connectionTime) return;
7332
- if (data.status && data.status !== "pending") {
7342
+ if (isReplayEvent) {
7333
7343
  renderResult(data, data);
7334
7344
  return;
7335
7345
  }
7346
+ if (!initialReplayDone) initialReplayDone = true;
7336
7347
  const orphaned = orphanedResults.get(data.id);
7337
7348
  if (orphaned) {
7338
7349
  orphanedResults.delete(data.id);
@@ -7371,7 +7382,7 @@ async function startTail(options = {}) {
7371
7382
  process.exit(1);
7372
7383
  });
7373
7384
  }
7374
- var import_http2, import_chalk17, import_fs25, import_os21, import_path28, import_readline5, import_child_process13, PID_FILE, ICONS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, DIVIDER;
7385
+ var import_http2, import_chalk17, import_fs25, import_os21, import_path28, import_readline5, import_child_process14, PID_FILE, ICONS, RESET2, BOLD2, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, DIVIDER;
7375
7386
  var init_tail = __esm({
7376
7387
  "src/tui/tail.ts"() {
7377
7388
  "use strict";
@@ -7381,7 +7392,7 @@ var init_tail = __esm({
7381
7392
  import_os21 = __toESM(require("os"));
7382
7393
  import_path28 = __toESM(require("path"));
7383
7394
  import_readline5 = __toESM(require("readline"));
7384
- import_child_process13 = require("child_process");
7395
+ import_child_process14 = require("child_process");
7385
7396
  init_daemon2();
7386
7397
  init_daemon();
7387
7398
  init_core();
@@ -7716,6 +7727,24 @@ function renderContextLine(stdin) {
7716
7727
  async function main() {
7717
7728
  try {
7718
7729
  const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
7730
+ if (import_fs26.default.existsSync(import_path29.default.join(import_os22.default.homedir(), ".node9", "hud-debug"))) {
7731
+ try {
7732
+ const logPath = import_path29.default.join(import_os22.default.homedir(), ".node9", "hud-debug.log");
7733
+ const MAX_LOG_SIZE = 10 * 1024 * 1024;
7734
+ let size = 0;
7735
+ try {
7736
+ size = import_fs26.default.statSync(logPath).size;
7737
+ } catch {
7738
+ }
7739
+ if (size < MAX_LOG_SIZE) {
7740
+ import_fs26.default.appendFileSync(
7741
+ logPath,
7742
+ JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
7743
+ );
7744
+ }
7745
+ } catch {
7746
+ }
7747
+ }
7719
7748
  if (!daemonStatus2) {
7720
7749
  renderOffline();
7721
7750
  return;
@@ -7832,7 +7861,7 @@ function isNode9Hook(cmd) {
7832
7861
  function teardownClaude() {
7833
7862
  const homeDir2 = import_os10.default.homedir();
7834
7863
  const hooksPath = import_path14.default.join(homeDir2, ".claude", "settings.json");
7835
- const mcpPath = import_path14.default.join(homeDir2, ".claude.json");
7864
+ const mcpPath = import_path14.default.join(homeDir2, ".claude", ".mcp.json");
7836
7865
  let changed = false;
7837
7866
  const settings = readJson(hooksPath);
7838
7867
  if (settings?.hooks) {
@@ -7858,11 +7887,12 @@ function teardownClaude() {
7858
7887
  let mcpChanged = false;
7859
7888
  if (removeNode9McpServer(claudeConfig.mcpServers)) {
7860
7889
  mcpChanged = true;
7861
- console.log(import_chalk.default.green(" \u2705 Removed node9 MCP server entry from ~/.claude.json"));
7890
+ console.log(import_chalk.default.green(" \u2705 Removed node9 MCP server entry from ~/.claude/.mcp.json"));
7862
7891
  }
7863
7892
  for (const [name, server] of Object.entries(claudeConfig.mcpServers)) {
7864
- if (server.command === "node9" && Array.isArray(server.args) && server.args.length > 0) {
7865
- const [originalCmd, ...originalArgs] = server.args;
7893
+ const args = server.args;
7894
+ if (server.command === "node9" && Array.isArray(args) && args[0] === "mcp" && args[1] === "--upstream" && typeof args[2] === "string") {
7895
+ const [originalCmd, ...originalArgs] = args[2].split(" ");
7866
7896
  claudeConfig.mcpServers[name] = {
7867
7897
  ...server,
7868
7898
  command: originalCmd,
@@ -7870,16 +7900,11 @@ function teardownClaude() {
7870
7900
  };
7871
7901
  mcpChanged = true;
7872
7902
  } else if (server.command === "node9") {
7873
- console.warn(
7874
- import_chalk.default.yellow(
7875
- ` \u26A0\uFE0F Cannot unwrap MCP server "${name}" in ~/.claude.json \u2014 args is empty. Remove it manually.`
7876
- )
7877
- );
7878
7903
  }
7879
7904
  }
7880
7905
  if (mcpChanged) {
7881
7906
  writeJson(mcpPath, claudeConfig);
7882
- console.log(import_chalk.default.green(" \u2705 Unwrapped MCP servers in ~/.claude.json"));
7907
+ console.log(import_chalk.default.green(" \u2705 Unwrapped MCP servers in ~/.claude/.mcp.json"));
7883
7908
  }
7884
7909
  }
7885
7910
  }
@@ -7908,8 +7933,9 @@ function teardownGemini() {
7908
7933
  console.log(import_chalk.default.green(" \u2705 Removed node9 MCP server entry from ~/.gemini/settings.json"));
7909
7934
  }
7910
7935
  for (const [name, server] of Object.entries(settings.mcpServers)) {
7911
- if (server.command === "node9" && Array.isArray(server.args) && server.args.length > 0) {
7912
- const [originalCmd, ...originalArgs] = server.args;
7936
+ const args = server.args;
7937
+ if (server.command === "node9" && Array.isArray(args) && args[0] === "mcp" && args[1] === "--upstream" && typeof args[2] === "string") {
7938
+ const [originalCmd, ...originalArgs] = args[2].split(" ");
7913
7939
  settings.mcpServers[name] = {
7914
7940
  ...server,
7915
7941
  command: originalCmd,
@@ -7940,8 +7966,9 @@ function teardownCursor() {
7940
7966
  console.log(import_chalk.default.green(" \u2705 Removed node9 MCP server entry from ~/.cursor/mcp.json"));
7941
7967
  }
7942
7968
  for (const [name, server] of Object.entries(mcpConfig.mcpServers)) {
7943
- if (server.command === "node9" && Array.isArray(server.args) && server.args.length > 0) {
7944
- const [originalCmd, ...originalArgs] = server.args;
7969
+ const args = server.args;
7970
+ if (server.command === "node9" && Array.isArray(args) && args[0] === "mcp" && args[1] === "--upstream" && typeof args[2] === "string") {
7971
+ const [originalCmd, ...originalArgs] = args[2].split(" ");
7945
7972
  mcpConfig.mcpServers[name] = {
7946
7973
  ...server,
7947
7974
  command: originalCmd,
@@ -7959,7 +7986,7 @@ function teardownCursor() {
7959
7986
  }
7960
7987
  async function setupClaude() {
7961
7988
  const homeDir2 = import_os10.default.homedir();
7962
- const mcpPath = import_path14.default.join(homeDir2, ".claude.json");
7989
+ const mcpPath = import_path14.default.join(homeDir2, ".claude", ".mcp.json");
7963
7990
  const hooksPath = import_path14.default.join(homeDir2, ".claude", "settings.json");
7964
7991
  const claudeConfig = readJson(mcpPath) ?? {};
7965
7992
  const settings = readJson(hooksPath) ?? {};
@@ -7974,7 +8001,7 @@ async function setupClaude() {
7974
8001
  if (!settings.hooks.PreToolUse) settings.hooks.PreToolUse = [];
7975
8002
  settings.hooks.PreToolUse.push({
7976
8003
  matcher: ".*",
7977
- hooks: [{ type: "command", command: fullPathCommand("check"), timeout: 60 }]
8004
+ hooks: [{ type: "command", command: fullPathCommand("check"), timeout: 600 }]
7978
8005
  });
7979
8006
  console.log(import_chalk.default.green(" \u2705 PreToolUse hook added \u2192 node9 check"));
7980
8007
  hooksChanged = true;
@@ -8000,6 +8027,15 @@ async function setupClaude() {
8000
8027
  console.log(import_chalk.default.green(" \u2705 node9 MCP server added \u2192 node9 mcp-server"));
8001
8028
  anythingChanged = true;
8002
8029
  }
8030
+ const hudCommand = fullPathCommand("hud");
8031
+ const statusLineObj = { type: "command", command: hudCommand };
8032
+ const existingStatusLine = settings.statusLine;
8033
+ const existingStatusCommand = typeof existingStatusLine === "object" ? existingStatusLine?.command : existingStatusLine;
8034
+ if (existingStatusCommand !== hudCommand) {
8035
+ settings.statusLine = statusLineObj;
8036
+ hooksChanged = true;
8037
+ anythingChanged = true;
8038
+ }
8003
8039
  if (hooksChanged) {
8004
8040
  writeJson(hooksPath, settings);
8005
8041
  console.log("");
@@ -8007,20 +8043,24 @@ async function setupClaude() {
8007
8043
  const serversToWrap = [];
8008
8044
  for (const [name, server] of Object.entries(servers)) {
8009
8045
  if (!server.command || server.command === "node9") continue;
8010
- const parts = [server.command, ...server.args ?? []];
8011
- serversToWrap.push({ name, originalCmd: parts.join(" "), parts });
8046
+ const upstream = [server.command, ...server.args ?? []].join(" ");
8047
+ serversToWrap.push({ name, upstream });
8012
8048
  }
8013
8049
  if (serversToWrap.length > 0) {
8014
8050
  console.log(import_chalk.default.bold("The following existing entries will be modified:\n"));
8015
8051
  console.log(import_chalk.default.white(` ${mcpPath}`));
8016
- for (const { name, originalCmd } of serversToWrap) {
8017
- console.log(import_chalk.default.gray(` \u2022 ${name}: "${originalCmd}" \u2192 node9 ${originalCmd}`));
8052
+ for (const { name, upstream } of serversToWrap) {
8053
+ console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8018
8054
  }
8019
8055
  console.log("");
8020
8056
  const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8021
8057
  if (proceed) {
8022
- for (const { name, parts } of serversToWrap) {
8023
- servers[name] = { ...servers[name], command: "node9", args: parts };
8058
+ for (const { name, upstream } of serversToWrap) {
8059
+ servers[name] = {
8060
+ ...servers[name],
8061
+ command: "node9",
8062
+ args: ["mcp", "--upstream", upstream]
8063
+ };
8024
8064
  }
8025
8065
  claudeConfig.mcpServers = servers;
8026
8066
  writeJson(mcpPath, claudeConfig);
@@ -8100,20 +8140,24 @@ async function setupGemini() {
8100
8140
  const serversToWrap = [];
8101
8141
  for (const [name, server] of Object.entries(servers)) {
8102
8142
  if (!server.command || server.command === "node9") continue;
8103
- const parts = [server.command, ...server.args ?? []];
8104
- serversToWrap.push({ name, originalCmd: parts.join(" "), parts });
8143
+ const upstream = [server.command, ...server.args ?? []].join(" ");
8144
+ serversToWrap.push({ name, upstream });
8105
8145
  }
8106
8146
  if (serversToWrap.length > 0) {
8107
8147
  console.log(import_chalk.default.bold("The following existing entries will be modified:\n"));
8108
8148
  console.log(import_chalk.default.white(` ${settingsPath} (mcpServers)`));
8109
- for (const { name, originalCmd } of serversToWrap) {
8110
- console.log(import_chalk.default.gray(` \u2022 ${name}: "${originalCmd}" \u2192 node9 ${originalCmd}`));
8149
+ for (const { name, upstream } of serversToWrap) {
8150
+ console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8111
8151
  }
8112
8152
  console.log("");
8113
8153
  const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8114
8154
  if (proceed) {
8115
- for (const { name, parts } of serversToWrap) {
8116
- servers[name] = { ...servers[name], command: "node9", args: parts };
8155
+ for (const { name, upstream } of serversToWrap) {
8156
+ servers[name] = {
8157
+ ...servers[name],
8158
+ command: "node9",
8159
+ args: ["mcp", "--upstream", upstream]
8160
+ };
8117
8161
  }
8118
8162
  settings.mcpServers = servers;
8119
8163
  writeJson(settingsPath, settings);
@@ -8172,20 +8216,24 @@ async function setupCursor() {
8172
8216
  const serversToWrap = [];
8173
8217
  for (const [name, server] of Object.entries(servers)) {
8174
8218
  if (!server.command || server.command === "node9") continue;
8175
- const parts = [server.command, ...server.args ?? []];
8176
- serversToWrap.push({ name, originalCmd: parts.join(" "), parts });
8219
+ const upstream = [server.command, ...server.args ?? []].join(" ");
8220
+ serversToWrap.push({ name, upstream });
8177
8221
  }
8178
8222
  if (serversToWrap.length > 0) {
8179
8223
  console.log(import_chalk.default.bold("The following existing entries will be modified:\n"));
8180
8224
  console.log(import_chalk.default.white(` ${mcpPath}`));
8181
- for (const { name, originalCmd } of serversToWrap) {
8182
- console.log(import_chalk.default.gray(` \u2022 ${name}: "${originalCmd}" \u2192 node9 ${originalCmd}`));
8225
+ for (const { name, upstream } of serversToWrap) {
8226
+ console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8183
8227
  }
8184
8228
  console.log("");
8185
8229
  const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8186
8230
  if (proceed) {
8187
- for (const { name, parts } of serversToWrap) {
8188
- servers[name] = { ...servers[name], command: "node9", args: parts };
8231
+ for (const { name, upstream } of serversToWrap) {
8232
+ servers[name] = {
8233
+ ...servers[name],
8234
+ command: "node9",
8235
+ args: ["mcp", "--upstream", upstream]
8236
+ };
8189
8237
  }
8190
8238
  mcpConfig.mcpServers = servers;
8191
8239
  writeJson(mcpPath, mcpConfig);
@@ -8248,20 +8296,24 @@ async function setupCodex() {
8248
8296
  const serversToWrap = [];
8249
8297
  for (const [name, server] of Object.entries(servers)) {
8250
8298
  if (!server.command || server.command === "node9") continue;
8251
- const parts = [server.command, ...server.args ?? []];
8252
- serversToWrap.push({ name, originalCmd: parts.join(" "), parts });
8299
+ const upstream = [server.command, ...server.args ?? []].join(" ");
8300
+ serversToWrap.push({ name, upstream });
8253
8301
  }
8254
8302
  if (serversToWrap.length > 0) {
8255
8303
  console.log(import_chalk.default.bold("The following existing entries will be modified:\n"));
8256
8304
  console.log(import_chalk.default.white(` ${configPath}`));
8257
- for (const { name, originalCmd } of serversToWrap) {
8258
- console.log(import_chalk.default.gray(` \u2022 ${name}: "${originalCmd}" \u2192 node9 ${originalCmd}`));
8305
+ for (const { name, upstream } of serversToWrap) {
8306
+ console.log(import_chalk.default.gray(` \u2022 ${name}: "${upstream}" \u2192 node9 mcp --upstream "${upstream}"`));
8259
8307
  }
8260
8308
  console.log("");
8261
8309
  const proceed = await (0, import_prompts.confirm)({ message: "Wrap these MCP servers?", default: true });
8262
8310
  if (proceed) {
8263
- for (const { name, parts } of serversToWrap) {
8264
- servers[name] = { ...servers[name], command: "node9", args: parts };
8311
+ for (const { name, upstream } of serversToWrap) {
8312
+ servers[name] = {
8313
+ ...servers[name],
8314
+ command: "node9",
8315
+ args: ["mcp", "--upstream", upstream]
8316
+ };
8265
8317
  }
8266
8318
  config.mcp_servers = servers;
8267
8319
  writeToml(configPath, config);
@@ -8450,18 +8502,20 @@ async function runProxy(targetCommand) {
8450
8502
  const cmd = commandParts[0];
8451
8503
  const args = commandParts.slice(1);
8452
8504
  let executable = cmd;
8505
+ let useShell = false;
8453
8506
  try {
8454
8507
  const { stdout } = await (0, import_execa.execa)("which", [cmd]);
8455
8508
  if (stdout) executable = stdout.trim();
8456
8509
  } catch {
8510
+ useShell = true;
8457
8511
  }
8458
8512
  console.error(import_chalk4.default.green(`\u{1F680} Node9 Proxy Active: Monitoring [${targetCommand}]`));
8459
- const child = (0, import_child_process6.spawn)(executable, args, {
8513
+ const spawnEnv = { ...process.env, FORCE_COLOR: "1" };
8514
+ const child = useShell ? (0, import_child_process6.spawn)("/bin/bash", ["-c", targetCommand], {
8460
8515
  stdio: ["pipe", "pipe", "inherit"],
8461
- // We control STDIN and STDOUT
8462
8516
  shell: false,
8463
- env: { ...process.env, FORCE_COLOR: "1" }
8464
- });
8517
+ env: spawnEnv
8518
+ }) : (0, import_child_process6.spawn)(executable, args, { stdio: ["pipe", "pipe", "inherit"], shell: false, env: spawnEnv });
8465
8519
  const agentIn = import_readline.default.createInterface({ input: process.stdin, terminal: false });
8466
8520
  agentIn.on("line", async (line) => {
8467
8521
  let message;
@@ -8570,6 +8624,7 @@ async function autoStartDaemonAndWait() {
8570
8624
  // src/cli/commands/check.ts
8571
8625
  var import_chalk5 = __toESM(require("chalk"));
8572
8626
  var import_fs18 = __toESM(require("fs"));
8627
+ var import_child_process9 = require("child_process");
8573
8628
  var import_path20 = __toESM(require("path"));
8574
8629
  var import_os14 = __toESM(require("os"));
8575
8630
  init_orchestrator();
@@ -8953,6 +9008,37 @@ RAW: ${raw}
8953
9008
  process.exit(0);
8954
9009
  }
8955
9010
  const config = getConfig(payload.cwd || void 0);
9011
+ if (config.settings.autoStartDaemon && !isDaemonRunning() && !process.env.NODE9_NO_AUTO_DAEMON) {
9012
+ try {
9013
+ const scriptPath = process.argv[1];
9014
+ if (typeof scriptPath !== "string" || !import_path20.default.isAbsolute(scriptPath))
9015
+ throw new Error("node9: argv[1] is not an absolute path");
9016
+ const resolvedScript = import_fs18.default.realpathSync(scriptPath);
9017
+ const expectedCli = import_fs18.default.realpathSync(import_path20.default.resolve(__dirname, "../../cli.js"));
9018
+ if (resolvedScript !== expectedCli)
9019
+ throw new Error(
9020
+ "node9: daemon spawn aborted \u2014 argv[1] does not resolve to the node9 CLI"
9021
+ );
9022
+ const safeEnv = { ...process.env };
9023
+ for (const key of [
9024
+ "NODE_OPTIONS",
9025
+ "LD_PRELOAD",
9026
+ "LD_LIBRARY_PATH",
9027
+ "DYLD_INSERT_LIBRARIES",
9028
+ "NODE_PATH",
9029
+ "ELECTRON_RUN_AS_NODE"
9030
+ ]) {
9031
+ delete safeEnv[key];
9032
+ }
9033
+ const d = (0, import_child_process9.spawn)(process.execPath, [scriptPath, "daemon"], {
9034
+ detached: true,
9035
+ stdio: "ignore",
9036
+ env: { ...safeEnv, NODE9_AUTO_STARTED: "1", NODE9_BROWSER_OPENED: "1" }
9037
+ });
9038
+ d.unref();
9039
+ } catch {
9040
+ }
9041
+ }
8956
9042
  if (process.env.NODE9_DEBUG === "1" || config.settings.enableHookLogDebug) {
8957
9043
  const logPath = import_path20.default.join(import_os14.default.homedir(), ".node9", "hook-debug.log");
8958
9044
  if (!import_fs18.default.existsSync(import_path20.default.dirname(logPath)))
@@ -9621,7 +9707,7 @@ var import_chalk7 = __toESM(require("chalk"));
9621
9707
  var import_fs20 = __toESM(require("fs"));
9622
9708
  var import_path22 = __toESM(require("path"));
9623
9709
  var import_os16 = __toESM(require("os"));
9624
- var import_child_process9 = require("child_process");
9710
+ var import_child_process10 = require("child_process");
9625
9711
  init_daemon();
9626
9712
  function registerDoctorCommand(program2, version2) {
9627
9713
  program2.command("doctor").description("Check that Node9 is installed and configured correctly").action(() => {
@@ -9647,7 +9733,7 @@ function registerDoctorCommand(program2, version2) {
9647
9733
  `));
9648
9734
  section("Binary");
9649
9735
  try {
9650
- const which = (0, import_child_process9.execSync)("which node9", { encoding: "utf-8", timeout: 3e3 }).trim();
9736
+ const which = (0, import_child_process10.execSync)("which node9", { encoding: "utf-8", timeout: 3e3 }).trim();
9651
9737
  pass(`node9 found at ${which}`);
9652
9738
  } catch {
9653
9739
  warn(
@@ -9665,7 +9751,7 @@ function registerDoctorCommand(program2, version2) {
9665
9751
  );
9666
9752
  }
9667
9753
  try {
9668
- const gitVersion = (0, import_child_process9.execSync)("git --version", { encoding: "utf-8", timeout: 3e3 }).trim();
9754
+ const gitVersion = (0, import_child_process10.execSync)("git --version", { encoding: "utf-8", timeout: 3e3 }).trim();
9669
9755
  pass(gitVersion);
9670
9756
  } catch {
9671
9757
  warn(
@@ -9862,7 +9948,7 @@ function registerAuditCommand(program2) {
9862
9948
 
9863
9949
  // src/cli/commands/daemon-cmd.ts
9864
9950
  var import_chalk9 = __toESM(require("chalk"));
9865
- var import_child_process10 = require("child_process");
9951
+ var import_child_process11 = require("child_process");
9866
9952
  init_daemon2();
9867
9953
  init_daemon();
9868
9954
  function registerDaemonCommand(program2) {
@@ -9895,7 +9981,7 @@ function registerDaemonCommand(program2) {
9895
9981
  console.log(import_chalk9.default.green(`\u{1F310} Opened browser: http://${DAEMON_HOST}:${DAEMON_PORT}/`));
9896
9982
  process.exit(0);
9897
9983
  }
9898
- const child = (0, import_child_process10.spawn)(process.execPath, [process.argv[1], "daemon"], {
9984
+ const child = (0, import_child_process11.spawn)(process.execPath, [process.argv[1], "daemon"], {
9899
9985
  detached: true,
9900
9986
  stdio: "ignore"
9901
9987
  });
@@ -9910,7 +9996,7 @@ function registerDaemonCommand(program2) {
9910
9996
  process.exit(0);
9911
9997
  }
9912
9998
  if (options.background) {
9913
- const child = (0, import_child_process10.spawn)(process.execPath, [process.argv[1], "daemon"], {
9999
+ const child = (0, import_child_process11.spawn)(process.execPath, [process.argv[1], "daemon"], {
9914
10000
  detached: true,
9915
10001
  stdio: "ignore"
9916
10002
  });
@@ -10498,7 +10584,7 @@ function registerUndoCommand(program2) {
10498
10584
 
10499
10585
  // src/cli/commands/watch.ts
10500
10586
  var import_chalk14 = __toESM(require("chalk"));
10501
- var import_child_process11 = require("child_process");
10587
+ var import_child_process12 = require("child_process");
10502
10588
  init_daemon();
10503
10589
  function registerWatchCommand(program2) {
10504
10590
  program2.command("watch").description("Run a command under Node9 watch mode (daemon stays alive for the session)").argument("<command>", "Command to run").argument("[args...]", "Arguments for the command").action(async (cmd, args) => {
@@ -10515,7 +10601,7 @@ function registerWatchCommand(program2) {
10515
10601
  }
10516
10602
  } catch {
10517
10603
  console.error(import_chalk14.default.dim("\u{1F6E1}\uFE0F Starting Node9 daemon (watch mode)..."));
10518
- const child = (0, import_child_process11.spawn)(process.execPath, [process.argv[1], "daemon"], {
10604
+ const child = (0, import_child_process12.spawn)(process.execPath, [process.argv[1], "daemon"], {
10519
10605
  detached: true,
10520
10606
  stdio: "ignore",
10521
10607
  env: { ...process.env, NODE9_AUTO_STARTED: "1", NODE9_WATCH_MODE: "1" }
@@ -10545,7 +10631,7 @@ function registerWatchCommand(program2) {
10545
10631
  "\n Tip: run `node9 tail` in another terminal to review and approve AI actions.\n"
10546
10632
  )
10547
10633
  );
10548
- const result = (0, import_child_process11.spawnSync)(cmd, args, {
10634
+ const result = (0, import_child_process12.spawnSync)(cmd, args, {
10549
10635
  stdio: "inherit",
10550
10636
  env: { ...process.env, NODE9_WATCH_MODE: "1" }
10551
10637
  });
@@ -10560,7 +10646,7 @@ function registerWatchCommand(program2) {
10560
10646
  // src/mcp-gateway/index.ts
10561
10647
  var import_readline3 = __toESM(require("readline"));
10562
10648
  var import_chalk15 = __toESM(require("chalk"));
10563
- var import_child_process12 = require("child_process");
10649
+ var import_child_process13 = require("child_process");
10564
10650
  var import_execa3 = require("execa");
10565
10651
  init_orchestrator();
10566
10652
  init_provenance();
@@ -10648,7 +10734,7 @@ async function runMcpGateway(upstreamCommand) {
10648
10734
  const safeEnv = Object.fromEntries(
10649
10735
  Object.entries(process.env).filter(([k]) => !UPSTREAM_INJECTOR_VARS.has(k))
10650
10736
  );
10651
- const child = (0, import_child_process12.spawn)(executable, cmdArgs, {
10737
+ const child = (0, import_child_process13.spawn)(executable, cmdArgs, {
10652
10738
  stdio: ["pipe", "pipe", "inherit"],
10653
10739
  // control stdin/stdout; inherit stderr
10654
10740
  shell: false,
@@ -10731,8 +10817,11 @@ async function runMcpGateway(upstreamCommand) {
10731
10817
  return;
10732
10818
  } finally {
10733
10819
  authPending = false;
10734
- agentIn.resume();
10735
- if (deferredStdinEnd) child.stdin.end();
10820
+ if (deferredStdinEnd) {
10821
+ child.stdin.end();
10822
+ } else {
10823
+ agentIn.resume();
10824
+ }
10736
10825
  if (deferredExitCode !== null) process.exit(deferredExitCode);
10737
10826
  }
10738
10827
  return;
@@ -11467,7 +11556,43 @@ registerMcpGatewayCommand(program);
11467
11556
  registerMcpServerCommand(program);
11468
11557
  registerCheckCommand(program);
11469
11558
  registerLogCommand(program);
11470
- program.command("hud").description("Render node9 security statusline (spawned by Claude Code statusLine)").action(async () => {
11559
+ program.command("hud").description("Render node9 security statusline (spawned by Claude Code statusLine)").addHelpText(
11560
+ "after",
11561
+ `
11562
+ Outputs up to 3 lines to stdout, then exits:
11563
+
11564
+ Line 1 \u2014 Security state (always shown):
11565
+ \u{1F6E1} node9 | <mode> [shields] | \u2705 allowed \u{1F6D1} blocked \u{1F6A8} dlp ~$cost
11566
+ Shows "offline" if the node9 daemon is not running.
11567
+
11568
+ Line 2 \u2014 Claude context & rate limits (shown when available):
11569
+ <model> \u2502 ctx \u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591 61% \u2502 5h \u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591 40% (2h 10m left)
11570
+ Only appears when Claude Code passes context_window / rate_limits data via stdin.
11571
+
11572
+ Line 3 \u2014 Environment counts (shown when non-zero):
11573
+ 2 CLAUDE.md | 5 rules | 4 MCPs | 3 hooks
11574
+ Counts CLAUDE.md files, rules/, MCP servers, and hook entries across user + project scope.
11575
+ Disable with: { "settings": { "hud": { "showEnvironmentCounts": false } } } in node9.config.json
11576
+
11577
+ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
11578
+ Run "node9 addto claude" to register it as the statusLine.`
11579
+ ).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
11580
+ if (subcommand === "debug") {
11581
+ const flagFile = import_path30.default.join(import_os23.default.homedir(), ".node9", "hud-debug");
11582
+ if (state === "on") {
11583
+ import_fs27.default.mkdirSync(import_path30.default.dirname(flagFile), { recursive: true });
11584
+ import_fs27.default.writeFileSync(flagFile, "");
11585
+ console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
11586
+ console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
11587
+ } else if (state === "off") {
11588
+ if (import_fs27.default.existsSync(flagFile)) import_fs27.default.unlinkSync(flagFile);
11589
+ console.log("HUD debug logging disabled.");
11590
+ } else {
11591
+ console.error("Usage: node9 hud debug on|off");
11592
+ process.exit(1);
11593
+ }
11594
+ return;
11595
+ }
11471
11596
  const { main: main2 } = await Promise.resolve().then(() => (init_hud(), hud_exports));
11472
11597
  await main2();
11473
11598
  });