@node9/proxy 1.35.1 → 1.35.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +127 -214
  2. package/dist/cli.mjs +127 -214
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8154,7 +8154,7 @@ function binaryInPath(binary) {
8154
8154
  return false;
8155
8155
  }
8156
8156
  function detectAgents(homeDir2 = import_os12.default.homedir()) {
8157
- const exists = (p) => {
8157
+ const exists2 = (p) => {
8158
8158
  try {
8159
8159
  return import_fs13.default.existsSync(p);
8160
8160
  } catch (err2) {
@@ -8168,7 +8168,7 @@ function detectAgents(homeDir2 = import_os12.default.homedir()) {
8168
8168
  };
8169
8169
  const desktopPath = claudeDesktopConfigPath(homeDir2);
8170
8170
  return {
8171
- claude: exists(import_path15.default.join(homeDir2, ".claude")) || exists(import_path15.default.join(homeDir2, ".claude.json")),
8171
+ claude: exists2(import_path15.default.join(homeDir2, ".claude")) || exists2(import_path15.default.join(homeDir2, ".claude.json")),
8172
8172
  // Antigravity (agy) shares the ~/.gemini root, so a bare
8173
8173
  // `exists(~/.gemini)` would report the (EOL'd) Gemini CLI as
8174
8174
  // installed on every agy machine — and `node9 init` would then
@@ -8178,35 +8178,35 @@ function detectAgents(homeDir2 = import_os12.default.homedir()) {
8178
8178
  // creates ~/.gemini/settings.json on first run; agy does not touch
8179
8179
  // it (it uses antigravity-cli/settings.json) — that file is the
8180
8180
  // legacy-CLI discriminator.
8181
- gemini: exists(import_path15.default.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8181
+ gemini: exists2(import_path15.default.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8182
8182
  // agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
8183
8183
  // creates antigravity-ide/. PATH fallback covers installed-but-
8184
8184
  // never-launched (same class as opencode #186).
8185
- antigravity: exists(import_path15.default.join(homeDir2, ".gemini", "antigravity-cli")) || exists(import_path15.default.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8185
+ antigravity: exists2(import_path15.default.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(import_path15.default.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8186
8186
  // GitHub Copilot CLI creates ~/.copilot on first launch; PATH
8187
8187
  // fallback covers installed-but-never-launched (same as opencode #186).
8188
- copilot: exists(import_path15.default.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8189
- cursor: exists(import_path15.default.join(homeDir2, ".cursor")),
8190
- codex: exists(import_path15.default.join(homeDir2, ".codex")),
8191
- windsurf: exists(import_path15.default.join(homeDir2, ".codeium", "windsurf")),
8192
- vscode: exists(import_path15.default.join(homeDir2, ".vscode")),
8193
- claudeDesktop: desktopPath !== null && exists(import_path15.default.dirname(desktopPath)),
8188
+ copilot: exists2(import_path15.default.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8189
+ cursor: exists2(import_path15.default.join(homeDir2, ".cursor")),
8190
+ codex: exists2(import_path15.default.join(homeDir2, ".codex")),
8191
+ windsurf: exists2(import_path15.default.join(homeDir2, ".codeium", "windsurf")),
8192
+ vscode: exists2(import_path15.default.join(homeDir2, ".vscode")),
8193
+ claudeDesktop: desktopPath !== null && exists2(import_path15.default.dirname(desktopPath)),
8194
8194
  // Opencode creates ~/.config/opencode lazily on first launch — fall back
8195
8195
  // to a PATH lookup so installed-but-never-launched CLIs are still wired.
8196
- opencode: exists(import_path15.default.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8196
+ opencode: exists2(import_path15.default.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8197
8197
  // Pi (https://pi.dev): config dir is ~/.pi/agent (CONFIG_DIR_NAME=".pi"
8198
8198
  // + agentDir, verified against opensources/pi-main/packages/coding-agent/
8199
8199
  // src/config.ts:449,475). The Bun-compiled binary path may create this
8200
8200
  // dir lazily on first launch — same class of bug as opencode's #186
8201
8201
  // (design R6) — so fall back to PATH lookup for installed-but-never-
8202
8202
  // launched pi.
8203
- pi: exists(import_path15.default.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8203
+ pi: exists2(import_path15.default.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8204
8204
  // Hermes Agent (https://github.com/NousResearch/hermes-agent): home dir
8205
8205
  // is $HERMES_HOME (default ~/.hermes) per hermes_constants.py:30. config.yaml
8206
8206
  // appears after `hermes setup` has run; the directory alone exists from
8207
8207
  // install time. PATH fallback covers the rare case where the user blew
8208
8208
  // away ~/.hermes but kept the binary.
8209
- hermes: exists(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8209
+ hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8210
8210
  };
8211
8211
  }
8212
8212
  async function setupCursor() {
@@ -19983,118 +19983,151 @@ function matchersHaveNode9Hook(matchers) {
19983
19983
  function flatHaveNode9Hook(entries) {
19984
19984
  return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
19985
19985
  }
19986
- function jsonWire(filePath, read) {
19987
- const parsed = readJson2(filePath);
19988
- if (parsed === null) return "absent";
19989
- if (parsed === "invalid") return "invalid";
19990
- return read(parsed) ? "wired" : "unwired";
19991
- }
19992
- function hermesWire(home) {
19993
- const configPath = hermesConfigPath(home);
19994
- if (!import_fs38.default.existsSync(configPath)) return "absent";
19986
+ function readHookRoot(filePath, format) {
19987
+ if (!import_fs38.default.existsSync(filePath)) return "absent";
19995
19988
  let raw;
19996
19989
  try {
19997
- raw = import_fs38.default.readFileSync(configPath, "utf-8");
19990
+ raw = import_fs38.default.readFileSync(filePath, "utf-8");
19998
19991
  } catch {
19999
19992
  return "absent";
20000
19993
  }
20001
19994
  try {
20002
- const cfg = yaml2.parse(raw);
20003
- const pre = (cfg?.hooks?.pre_tool_call ?? []).some(
20004
- (e) => typeof e?.command === "string" && isNode9Hook(e.command)
20005
- );
20006
- return pre ? "wired" : "unwired";
19995
+ const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
19996
+ return parsed?.hooks ?? {};
20007
19997
  } catch {
20008
19998
  return "invalid";
20009
19999
  }
20010
20000
  }
20001
+ function eventWired(root, ev, format) {
20002
+ const arr = root[ev.key];
20003
+ if (format === "matcher") return matchersHaveNode9Hook(arr);
20004
+ return flatHaveNode9Hook(arr);
20005
+ }
20006
+ function readMcp(filePath) {
20007
+ const parsed = readJson2(filePath);
20008
+ if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
20009
+ const servers = parsed.mcpServers ?? {};
20010
+ const entries = Object.entries(servers);
20011
+ const present = entries.some(([, s]) => s?.command === "node9");
20012
+ const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
20013
+ return { wrapped, present };
20014
+ }
20015
+ var exists = (p) => {
20016
+ try {
20017
+ return import_fs38.default.existsSync(p);
20018
+ } catch {
20019
+ return false;
20020
+ }
20021
+ };
20022
+ var ck = (key) => ({ key, kind: "check" });
20023
+ var lg = (key) => ({ key, kind: "log" });
20024
+ var DEFAULT_LABEL_PAD = 11;
20025
+ var hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
20011
20026
  var AGENT_SPECS = [
20012
20027
  {
20013
20028
  id: "claude",
20014
20029
  label: "Claude Code",
20015
- hookLabel: "PreToolUse hook",
20016
20030
  setupCommand: "node9 setup claude",
20017
- settingsPath: (h) => import_path39.default.join(h, ".claude", "settings.json"),
20018
- wireState: (h) => jsonWire(
20019
- import_path39.default.join(h, ".claude", "settings.json"),
20020
- (p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
20021
- )
20031
+ hookFile: (h) => import_path39.default.join(h, ".claude", "settings.json"),
20032
+ hookFormat: "matcher",
20033
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
20034
+ mcpFile: (h) => import_path39.default.join(h, ".claude.json"),
20035
+ present: (h) => exists(import_path39.default.join(h, ".claude", "settings.json")) || exists(import_path39.default.join(h, ".claude.json"))
20022
20036
  },
20023
20037
  {
20024
20038
  id: "gemini",
20025
20039
  label: "Gemini CLI",
20026
- hookLabel: "BeforeTool hook",
20027
20040
  setupCommand: "node9 setup gemini",
20028
- settingsPath: (h) => import_path39.default.join(h, ".gemini", "settings.json"),
20029
- wireState: (h) => jsonWire(
20030
- import_path39.default.join(h, ".gemini", "settings.json"),
20031
- (p) => matchersHaveNode9Hook(p.hooks?.BeforeTool)
20032
- )
20041
+ hookFile: (h) => import_path39.default.join(h, ".gemini", "settings.json"),
20042
+ hookFormat: "matcher",
20043
+ hookEvents: [ck("BeforeTool"), lg("AfterTool")],
20044
+ mcpFile: (h) => import_path39.default.join(h, ".gemini", "settings.json"),
20045
+ present: (h) => exists(import_path39.default.join(h, ".gemini", "settings.json"))
20033
20046
  },
20034
20047
  {
20035
20048
  id: "codex",
20036
20049
  label: "Codex",
20037
- hookLabel: "PreToolUse hook",
20038
20050
  setupCommand: "node9 setup codex",
20039
- settingsPath: (h) => import_path39.default.join(h, ".codex", "hooks.json"),
20040
- wireState: (h) => jsonWire(
20041
- import_path39.default.join(h, ".codex", "hooks.json"),
20042
- (p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
20043
- )
20051
+ hookFile: (h) => import_path39.default.join(h, ".codex", "hooks.json"),
20052
+ hookFormat: "matcher",
20053
+ hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
20054
+ present: (h) => exists(import_path39.default.join(h, ".codex"))
20044
20055
  },
20045
20056
  {
20046
20057
  id: "antigravity",
20047
20058
  label: "Antigravity",
20048
- hookLabel: "PreToolUse hook",
20049
20059
  setupCommand: "node9 setup antigravity",
20050
- settingsPath: (h) => import_path39.default.join(h, ".gemini", "config", "hooks.json"),
20051
- wireState: (h) => jsonWire(
20052
- import_path39.default.join(h, ".gemini", "config", "hooks.json"),
20053
- (p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
20054
- )
20060
+ hookFile: (h) => import_path39.default.join(h, ".gemini", "config", "hooks.json"),
20061
+ hookFormat: "matcher",
20062
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
20063
+ mcpFile: (h) => import_path39.default.join(h, ".gemini", "config", "mcp_config.json"),
20064
+ present: (h) => exists(import_path39.default.join(h, ".gemini", "config", "hooks.json")) || exists(import_path39.default.join(h, ".gemini", "antigravity-cli")) || exists(import_path39.default.join(h, ".gemini", "antigravity-ide"))
20055
20065
  },
20056
20066
  {
20057
20067
  id: "copilot",
20058
20068
  label: "GitHub Copilot",
20059
- hookLabel: "PreToolUse hook",
20060
20069
  setupCommand: "node9 setup copilot",
20061
- settingsPath: (h) => import_path39.default.join(h, ".copilot", "hooks", "node9.json"),
20062
- wireState: (h) => jsonWire(
20063
- import_path39.default.join(h, ".copilot", "hooks", "node9.json"),
20064
- (p) => flatHaveNode9Hook(p.hooks?.PreToolUse)
20065
- )
20070
+ hookFile: (h) => import_path39.default.join(h, ".copilot", "hooks", "node9.json"),
20071
+ hookFormat: "flat",
20072
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
20073
+ mcpFile: (h) => import_path39.default.join(h, ".copilot", "mcp-config.json"),
20074
+ present: (h) => exists(import_path39.default.join(h, ".copilot"))
20066
20075
  },
20067
20076
  {
20068
20077
  id: "cursor",
20069
20078
  label: "Cursor",
20070
- hookLabel: "preToolUse hook",
20071
20079
  setupCommand: "node9 setup cursor",
20072
- settingsPath: (h) => import_path39.default.join(h, ".cursor", "hooks.json"),
20073
- wireState: (h) => jsonWire(
20074
- import_path39.default.join(h, ".cursor", "hooks.json"),
20075
- (p) => flatHaveNode9Hook(p.hooks?.preToolUse)
20076
- )
20080
+ // MCP-only no hook file (see note above).
20081
+ hookFormat: "flat",
20082
+ hookEvents: [],
20083
+ mcpFile: (h) => import_path39.default.join(h, ".cursor", "mcp.json"),
20084
+ present: (h) => exists(import_path39.default.join(h, ".cursor", "mcp.json"))
20077
20085
  },
20078
20086
  {
20079
20087
  id: "hermes",
20080
20088
  label: "Hermes Agent",
20081
- hookLabel: "pre_tool_call hook",
20082
20089
  setupCommand: "node9 setup hermes",
20083
- settingsPath: (h) => hermesConfigPath(h),
20084
- wireState: (h) => hermesWire(h)
20090
+ hookFile: (h) => hermesConfigPath(h),
20091
+ hookFormat: "yaml",
20092
+ hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
20093
+ labelPad: 14,
20094
+ // 'post_tool_call' is wider than the default
20095
+ present: (h) => exists(hermesConfigPath(h))
20085
20096
  }
20086
20097
  ];
20087
20098
  function getAgentWiring(home = import_os34.default.homedir()) {
20088
20099
  const detected = detectAgents(home);
20089
- return AGENT_SPECS.map((spec) => ({
20090
- id: spec.id,
20091
- label: spec.label,
20092
- hookLabel: spec.hookLabel,
20093
- setupCommand: spec.setupCommand,
20094
- settingsPath: spec.settingsPath(home),
20095
- installed: detected[spec.id],
20096
- wireState: spec.wireState(home)
20097
- }));
20100
+ return AGENT_SPECS.map((spec) => {
20101
+ const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
20102
+ const primary = spec.hookEvents[0];
20103
+ const rootPresent = root !== "absent" && root !== "invalid";
20104
+ const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
20105
+ const hooks = spec.hookEvents.map((ev) => ({
20106
+ label: hookLabelOf(ev, pad),
20107
+ wired: rootPresent && eventWired(root, ev, spec.hookFormat)
20108
+ }));
20109
+ let wireState;
20110
+ if (root === "absent") wireState = "absent";
20111
+ else if (root === "invalid") wireState = "invalid";
20112
+ else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
20113
+ const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home)) : null;
20114
+ const anyHookWired = hooks.some((h) => h.wired);
20115
+ return {
20116
+ id: spec.id,
20117
+ label: spec.label,
20118
+ setupCommand: spec.setupCommand,
20119
+ installed: detected[spec.id],
20120
+ present: spec.present(home),
20121
+ hooks,
20122
+ wireState,
20123
+ hookLabel: primary ? `${primary.key} hook` : "MCP proxy",
20124
+ settingsPath: spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "",
20125
+ configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
20126
+ mcpServers: mcp ? mcp.wrapped : null,
20127
+ mcpProtected: mcp ? mcp.present : false,
20128
+ isProtected: anyHookWired || (mcp?.present ?? false)
20129
+ };
20130
+ });
20098
20131
  }
20099
20132
 
20100
20133
  // src/cli/commands/doctor.ts
@@ -20184,12 +20217,13 @@ function registerDoctorCommand(program2, version2) {
20184
20217
  section("Agent Hooks");
20185
20218
  const notConfigured = [];
20186
20219
  for (const a of getAgentWiring(homeDir2)) {
20187
- if (a.wireState === "wired") {
20188
- pass(`${a.label} \u2014 ${a.hookLabel} active`);
20189
- } else if (a.wireState === "unwired") {
20190
- fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
20220
+ const anyHookWired = a.hooks.some((h) => h.wired);
20221
+ if (a.isProtected) {
20222
+ pass(`${a.label} \u2014 ${anyHookWired ? `${a.hookLabel} active` : "MCP proxy active"}`);
20191
20223
  } else if (a.wireState === "invalid") {
20192
20224
  fail(`${a.label} \u2014 settings file is invalid JSON`, a.settingsPath);
20225
+ } else if (a.wireState === "unwired") {
20226
+ fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
20193
20227
  } else {
20194
20228
  notConfigured.push(a.label);
20195
20229
  }
@@ -21493,50 +21527,8 @@ var import_chalk15 = __toESM(require("chalk"));
21493
21527
  var import_fs42 = __toESM(require("fs"));
21494
21528
  var import_path43 = __toESM(require("path"));
21495
21529
  var import_os38 = __toESM(require("os"));
21496
- var yaml3 = __toESM(require("yaml"));
21497
21530
  init_core();
21498
21531
  init_daemon();
21499
- init_setup();
21500
- function readHermesHooks(configPath) {
21501
- if (!import_fs42.default.existsSync(configPath)) return null;
21502
- let raw;
21503
- try {
21504
- raw = import_fs42.default.readFileSync(configPath, "utf-8");
21505
- } catch {
21506
- return null;
21507
- }
21508
- try {
21509
- const cfg = yaml3.parse(raw);
21510
- const has = (event) => (cfg?.hooks?.[event] ?? []).some(
21511
- (e) => typeof e?.command === "string" && isNode9Hook(e.command)
21512
- );
21513
- return { pre: has("pre_tool_call"), post: has("post_tool_call") };
21514
- } catch {
21515
- console.error(
21516
- import_chalk15.default.yellow(
21517
- ` \u26A0\uFE0F Hermes config.yaml at ${configPath} is not valid YAML \u2014 showing as unwired.`
21518
- )
21519
- );
21520
- return { pre: false, post: false };
21521
- }
21522
- }
21523
- function readJson3(filePath) {
21524
- try {
21525
- if (import_fs42.default.existsSync(filePath)) return JSON.parse(import_fs42.default.readFileSync(filePath, "utf-8"));
21526
- } catch {
21527
- }
21528
- return null;
21529
- }
21530
- function matchersHaveNode9Hook2(matchers) {
21531
- return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
21532
- }
21533
- function flatHaveNode9Hook2(entries) {
21534
- return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
21535
- }
21536
- function wrappedMcpServers(servers) {
21537
- if (!servers) return [];
21538
- return Object.entries(servers).filter(([, s]) => s.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
21539
- }
21540
21532
  function printAgentSection(label, hookPairs, wrapped) {
21541
21533
  console.log(import_chalk15.default.bold(` ${label}`));
21542
21534
  for (const { name, present } of hookPairs) {
@@ -21603,102 +21595,23 @@ function registerStatusCommand(program2) {
21603
21595
  ` Sandbox: ${import_chalk15.default.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
21604
21596
  );
21605
21597
  }
21606
- const homeDir2 = import_os38.default.homedir();
21607
- const claudeSettings = readJson3(
21608
- import_path43.default.join(homeDir2, ".claude", "settings.json")
21609
- );
21610
- const claudeConfig = readJson3(import_path43.default.join(homeDir2, ".claude.json"));
21611
- const geminiSettings = readJson3(
21612
- import_path43.default.join(homeDir2, ".gemini", "settings.json")
21613
- );
21614
- const cursorConfig = readJson3(import_path43.default.join(homeDir2, ".cursor", "mcp.json"));
21615
- const antigravityHooks = readJson3(
21616
- import_path43.default.join(homeDir2, ".gemini", "config", "hooks.json")
21617
- );
21618
- const antigravityMcp = readJson3(
21619
- import_path43.default.join(homeDir2, ".gemini", "config", "mcp_config.json")
21620
- );
21621
- const antigravityPresent = antigravityHooks !== null || import_fs42.default.existsSync(import_path43.default.join(homeDir2, ".gemini", "antigravity-cli")) || import_fs42.default.existsSync(import_path43.default.join(homeDir2, ".gemini", "antigravity-ide"));
21622
- const copilotHooks = readJson3(
21623
- import_path43.default.join(homeDir2, ".copilot", "hooks", "node9.json")
21624
- );
21625
- const copilotMcp = readJson3(
21626
- import_path43.default.join(homeDir2, ".copilot", "mcp-config.json")
21627
- );
21628
- const copilotPresent = import_fs42.default.existsSync(import_path43.default.join(homeDir2, ".copilot"));
21629
- const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
21630
- const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
21631
- if (agentFound) {
21598
+ const wiring = getAgentWiring(import_os38.default.homedir()).filter((a) => a.present);
21599
+ if (wiring.length > 0) {
21632
21600
  console.log("");
21633
21601
  console.log(import_chalk15.default.bold(" Agent Wiring:"));
21634
21602
  console.log("");
21635
- if (claudeSettings || claudeConfig) {
21636
- const preHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PreToolUse);
21637
- const postHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PostToolUse);
21638
- printAgentSection(
21639
- "Claude Code",
21640
- [
21641
- { name: "PreToolUse (node9 check)", present: preHook },
21642
- { name: "PostToolUse (node9 log)", present: postHook }
21643
- ],
21644
- wrappedMcpServers(claudeConfig?.mcpServers)
21645
- );
21646
- console.log("");
21647
- }
21648
- if (geminiSettings) {
21649
- const beforeHook = matchersHaveNode9Hook2(geminiSettings.hooks?.BeforeTool);
21650
- const afterHook = matchersHaveNode9Hook2(geminiSettings.hooks?.AfterTool);
21651
- printAgentSection(
21652
- "Gemini CLI",
21653
- [
21654
- { name: "BeforeTool (node9 check)", present: beforeHook },
21655
- { name: "AfterTool (node9 log)", present: afterHook }
21656
- ],
21657
- wrappedMcpServers(geminiSettings.mcpServers)
21658
- );
21659
- console.log("");
21660
- }
21661
- if (antigravityPresent) {
21662
- const preHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PreToolUse);
21663
- const postHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PostToolUse);
21664
- printAgentSection(
21665
- "Antigravity",
21666
- [
21667
- { name: "PreToolUse (node9 check)", present: preHook },
21668
- { name: "PostToolUse (node9 log)", present: postHook }
21669
- ],
21670
- wrappedMcpServers(antigravityMcp?.mcpServers)
21671
- );
21672
- console.log("");
21673
- }
21674
- if (copilotPresent) {
21675
- const preHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PreToolUse);
21676
- const postHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PostToolUse);
21677
- const promptHook = flatHaveNode9Hook2(copilotHooks?.hooks?.UserPromptSubmit);
21678
- printAgentSection(
21679
- "GitHub Copilot",
21680
- [
21681
- { name: "PreToolUse (node9 check)", present: preHook },
21682
- { name: "PostToolUse (node9 log)", present: postHook },
21683
- { name: "UserPromptSubmit (node9 check)", present: promptHook }
21684
- ],
21685
- wrappedMcpServers(copilotMcp?.mcpServers)
21686
- );
21687
- console.log("");
21688
- }
21689
- if (cursorConfig) {
21690
- printAgentSection("Cursor", [], wrappedMcpServers(cursorConfig.mcpServers));
21691
- console.log("");
21692
- }
21693
- if (hermesHooks) {
21603
+ for (const a of wiring) {
21604
+ if (a.wireState === "invalid") {
21605
+ console.error(
21606
+ import_chalk15.default.yellow(
21607
+ ` \u26A0\uFE0F ${a.label} config at ${a.settingsPath} is not valid ${a.configFormat} \u2014 showing as unwired.`
21608
+ )
21609
+ );
21610
+ }
21694
21611
  printAgentSection(
21695
- "Hermes Agent",
21696
- [
21697
- { name: "pre_tool_call (node9 check)", present: hermesHooks.pre },
21698
- { name: "post_tool_call (node9 log)", present: hermesHooks.post }
21699
- ],
21700
- null
21701
- // Hermes has no MCP surface
21612
+ a.label,
21613
+ a.hooks.map((h) => ({ name: h.label, present: h.wired })),
21614
+ a.mcpServers
21702
21615
  );
21703
21616
  console.log("");
21704
21617
  }
package/dist/cli.mjs CHANGED
@@ -8136,7 +8136,7 @@ function binaryInPath(binary) {
8136
8136
  return false;
8137
8137
  }
8138
8138
  function detectAgents(homeDir2 = os12.homedir()) {
8139
- const exists = (p) => {
8139
+ const exists2 = (p) => {
8140
8140
  try {
8141
8141
  return fs13.existsSync(p);
8142
8142
  } catch (err2) {
@@ -8150,7 +8150,7 @@ function detectAgents(homeDir2 = os12.homedir()) {
8150
8150
  };
8151
8151
  const desktopPath = claudeDesktopConfigPath(homeDir2);
8152
8152
  return {
8153
- claude: exists(path15.join(homeDir2, ".claude")) || exists(path15.join(homeDir2, ".claude.json")),
8153
+ claude: exists2(path15.join(homeDir2, ".claude")) || exists2(path15.join(homeDir2, ".claude.json")),
8154
8154
  // Antigravity (agy) shares the ~/.gemini root, so a bare
8155
8155
  // `exists(~/.gemini)` would report the (EOL'd) Gemini CLI as
8156
8156
  // installed on every agy machine — and `node9 init` would then
@@ -8160,35 +8160,35 @@ function detectAgents(homeDir2 = os12.homedir()) {
8160
8160
  // creates ~/.gemini/settings.json on first run; agy does not touch
8161
8161
  // it (it uses antigravity-cli/settings.json) — that file is the
8162
8162
  // legacy-CLI discriminator.
8163
- gemini: exists(path15.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8163
+ gemini: exists2(path15.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8164
8164
  // agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
8165
8165
  // creates antigravity-ide/. PATH fallback covers installed-but-
8166
8166
  // never-launched (same class as opencode #186).
8167
- antigravity: exists(path15.join(homeDir2, ".gemini", "antigravity-cli")) || exists(path15.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8167
+ antigravity: exists2(path15.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(path15.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8168
8168
  // GitHub Copilot CLI creates ~/.copilot on first launch; PATH
8169
8169
  // fallback covers installed-but-never-launched (same as opencode #186).
8170
- copilot: exists(path15.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8171
- cursor: exists(path15.join(homeDir2, ".cursor")),
8172
- codex: exists(path15.join(homeDir2, ".codex")),
8173
- windsurf: exists(path15.join(homeDir2, ".codeium", "windsurf")),
8174
- vscode: exists(path15.join(homeDir2, ".vscode")),
8175
- claudeDesktop: desktopPath !== null && exists(path15.dirname(desktopPath)),
8170
+ copilot: exists2(path15.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8171
+ cursor: exists2(path15.join(homeDir2, ".cursor")),
8172
+ codex: exists2(path15.join(homeDir2, ".codex")),
8173
+ windsurf: exists2(path15.join(homeDir2, ".codeium", "windsurf")),
8174
+ vscode: exists2(path15.join(homeDir2, ".vscode")),
8175
+ claudeDesktop: desktopPath !== null && exists2(path15.dirname(desktopPath)),
8176
8176
  // Opencode creates ~/.config/opencode lazily on first launch — fall back
8177
8177
  // to a PATH lookup so installed-but-never-launched CLIs are still wired.
8178
- opencode: exists(path15.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8178
+ opencode: exists2(path15.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8179
8179
  // Pi (https://pi.dev): config dir is ~/.pi/agent (CONFIG_DIR_NAME=".pi"
8180
8180
  // + agentDir, verified against opensources/pi-main/packages/coding-agent/
8181
8181
  // src/config.ts:449,475). The Bun-compiled binary path may create this
8182
8182
  // dir lazily on first launch — same class of bug as opencode's #186
8183
8183
  // (design R6) — so fall back to PATH lookup for installed-but-never-
8184
8184
  // launched pi.
8185
- pi: exists(path15.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8185
+ pi: exists2(path15.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8186
8186
  // Hermes Agent (https://github.com/NousResearch/hermes-agent): home dir
8187
8187
  // is $HERMES_HOME (default ~/.hermes) per hermes_constants.py:30. config.yaml
8188
8188
  // appears after `hermes setup` has run; the directory alone exists from
8189
8189
  // install time. PATH fallback covers the rare case where the user blew
8190
8190
  // away ~/.hermes but kept the binary.
8191
- hermes: exists(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8191
+ hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8192
8192
  };
8193
8193
  }
8194
8194
  async function setupCursor() {
@@ -19955,118 +19955,151 @@ function matchersHaveNode9Hook(matchers) {
19955
19955
  function flatHaveNode9Hook(entries) {
19956
19956
  return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
19957
19957
  }
19958
- function jsonWire(filePath, read) {
19959
- const parsed = readJson2(filePath);
19960
- if (parsed === null) return "absent";
19961
- if (parsed === "invalid") return "invalid";
19962
- return read(parsed) ? "wired" : "unwired";
19963
- }
19964
- function hermesWire(home) {
19965
- const configPath = hermesConfigPath(home);
19966
- if (!fs38.existsSync(configPath)) return "absent";
19958
+ function readHookRoot(filePath, format) {
19959
+ if (!fs38.existsSync(filePath)) return "absent";
19967
19960
  let raw;
19968
19961
  try {
19969
- raw = fs38.readFileSync(configPath, "utf-8");
19962
+ raw = fs38.readFileSync(filePath, "utf-8");
19970
19963
  } catch {
19971
19964
  return "absent";
19972
19965
  }
19973
19966
  try {
19974
- const cfg = yaml2.parse(raw);
19975
- const pre = (cfg?.hooks?.pre_tool_call ?? []).some(
19976
- (e) => typeof e?.command === "string" && isNode9Hook(e.command)
19977
- );
19978
- return pre ? "wired" : "unwired";
19967
+ const parsed = format === "yaml" ? yaml2.parse(raw) : JSON.parse(raw);
19968
+ return parsed?.hooks ?? {};
19979
19969
  } catch {
19980
19970
  return "invalid";
19981
19971
  }
19982
19972
  }
19973
+ function eventWired(root, ev, format) {
19974
+ const arr = root[ev.key];
19975
+ if (format === "matcher") return matchersHaveNode9Hook(arr);
19976
+ return flatHaveNode9Hook(arr);
19977
+ }
19978
+ function readMcp(filePath) {
19979
+ const parsed = readJson2(filePath);
19980
+ if (parsed === null || parsed === "invalid") return { wrapped: [], present: false };
19981
+ const servers = parsed.mcpServers ?? {};
19982
+ const entries = Object.entries(servers);
19983
+ const present = entries.some(([, s]) => s?.command === "node9");
19984
+ const wrapped = entries.filter(([, s]) => s?.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
19985
+ return { wrapped, present };
19986
+ }
19987
+ var exists = (p) => {
19988
+ try {
19989
+ return fs38.existsSync(p);
19990
+ } catch {
19991
+ return false;
19992
+ }
19993
+ };
19994
+ var ck = (key) => ({ key, kind: "check" });
19995
+ var lg = (key) => ({ key, kind: "log" });
19996
+ var DEFAULT_LABEL_PAD = 11;
19997
+ var hookLabelOf = (ev, pad) => `${ev.key.padEnd(pad)} (node9 ${ev.kind})`;
19983
19998
  var AGENT_SPECS = [
19984
19999
  {
19985
20000
  id: "claude",
19986
20001
  label: "Claude Code",
19987
- hookLabel: "PreToolUse hook",
19988
20002
  setupCommand: "node9 setup claude",
19989
- settingsPath: (h) => path39.join(h, ".claude", "settings.json"),
19990
- wireState: (h) => jsonWire(
19991
- path39.join(h, ".claude", "settings.json"),
19992
- (p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
19993
- )
20003
+ hookFile: (h) => path39.join(h, ".claude", "settings.json"),
20004
+ hookFormat: "matcher",
20005
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
20006
+ mcpFile: (h) => path39.join(h, ".claude.json"),
20007
+ present: (h) => exists(path39.join(h, ".claude", "settings.json")) || exists(path39.join(h, ".claude.json"))
19994
20008
  },
19995
20009
  {
19996
20010
  id: "gemini",
19997
20011
  label: "Gemini CLI",
19998
- hookLabel: "BeforeTool hook",
19999
20012
  setupCommand: "node9 setup gemini",
20000
- settingsPath: (h) => path39.join(h, ".gemini", "settings.json"),
20001
- wireState: (h) => jsonWire(
20002
- path39.join(h, ".gemini", "settings.json"),
20003
- (p) => matchersHaveNode9Hook(p.hooks?.BeforeTool)
20004
- )
20013
+ hookFile: (h) => path39.join(h, ".gemini", "settings.json"),
20014
+ hookFormat: "matcher",
20015
+ hookEvents: [ck("BeforeTool"), lg("AfterTool")],
20016
+ mcpFile: (h) => path39.join(h, ".gemini", "settings.json"),
20017
+ present: (h) => exists(path39.join(h, ".gemini", "settings.json"))
20005
20018
  },
20006
20019
  {
20007
20020
  id: "codex",
20008
20021
  label: "Codex",
20009
- hookLabel: "PreToolUse hook",
20010
20022
  setupCommand: "node9 setup codex",
20011
- settingsPath: (h) => path39.join(h, ".codex", "hooks.json"),
20012
- wireState: (h) => jsonWire(
20013
- path39.join(h, ".codex", "hooks.json"),
20014
- (p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
20015
- )
20023
+ hookFile: (h) => path39.join(h, ".codex", "hooks.json"),
20024
+ hookFormat: "matcher",
20025
+ hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
20026
+ present: (h) => exists(path39.join(h, ".codex"))
20016
20027
  },
20017
20028
  {
20018
20029
  id: "antigravity",
20019
20030
  label: "Antigravity",
20020
- hookLabel: "PreToolUse hook",
20021
20031
  setupCommand: "node9 setup antigravity",
20022
- settingsPath: (h) => path39.join(h, ".gemini", "config", "hooks.json"),
20023
- wireState: (h) => jsonWire(
20024
- path39.join(h, ".gemini", "config", "hooks.json"),
20025
- (p) => matchersHaveNode9Hook(p.hooks?.PreToolUse)
20026
- )
20032
+ hookFile: (h) => path39.join(h, ".gemini", "config", "hooks.json"),
20033
+ hookFormat: "matcher",
20034
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
20035
+ mcpFile: (h) => path39.join(h, ".gemini", "config", "mcp_config.json"),
20036
+ present: (h) => exists(path39.join(h, ".gemini", "config", "hooks.json")) || exists(path39.join(h, ".gemini", "antigravity-cli")) || exists(path39.join(h, ".gemini", "antigravity-ide"))
20027
20037
  },
20028
20038
  {
20029
20039
  id: "copilot",
20030
20040
  label: "GitHub Copilot",
20031
- hookLabel: "PreToolUse hook",
20032
20041
  setupCommand: "node9 setup copilot",
20033
- settingsPath: (h) => path39.join(h, ".copilot", "hooks", "node9.json"),
20034
- wireState: (h) => jsonWire(
20035
- path39.join(h, ".copilot", "hooks", "node9.json"),
20036
- (p) => flatHaveNode9Hook(p.hooks?.PreToolUse)
20037
- )
20042
+ hookFile: (h) => path39.join(h, ".copilot", "hooks", "node9.json"),
20043
+ hookFormat: "flat",
20044
+ hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
20045
+ mcpFile: (h) => path39.join(h, ".copilot", "mcp-config.json"),
20046
+ present: (h) => exists(path39.join(h, ".copilot"))
20038
20047
  },
20039
20048
  {
20040
20049
  id: "cursor",
20041
20050
  label: "Cursor",
20042
- hookLabel: "preToolUse hook",
20043
20051
  setupCommand: "node9 setup cursor",
20044
- settingsPath: (h) => path39.join(h, ".cursor", "hooks.json"),
20045
- wireState: (h) => jsonWire(
20046
- path39.join(h, ".cursor", "hooks.json"),
20047
- (p) => flatHaveNode9Hook(p.hooks?.preToolUse)
20048
- )
20052
+ // MCP-only no hook file (see note above).
20053
+ hookFormat: "flat",
20054
+ hookEvents: [],
20055
+ mcpFile: (h) => path39.join(h, ".cursor", "mcp.json"),
20056
+ present: (h) => exists(path39.join(h, ".cursor", "mcp.json"))
20049
20057
  },
20050
20058
  {
20051
20059
  id: "hermes",
20052
20060
  label: "Hermes Agent",
20053
- hookLabel: "pre_tool_call hook",
20054
20061
  setupCommand: "node9 setup hermes",
20055
- settingsPath: (h) => hermesConfigPath(h),
20056
- wireState: (h) => hermesWire(h)
20062
+ hookFile: (h) => hermesConfigPath(h),
20063
+ hookFormat: "yaml",
20064
+ hookEvents: [ck("pre_tool_call"), lg("post_tool_call")],
20065
+ labelPad: 14,
20066
+ // 'post_tool_call' is wider than the default
20067
+ present: (h) => exists(hermesConfigPath(h))
20057
20068
  }
20058
20069
  ];
20059
20070
  function getAgentWiring(home = os34.homedir()) {
20060
20071
  const detected = detectAgents(home);
20061
- return AGENT_SPECS.map((spec) => ({
20062
- id: spec.id,
20063
- label: spec.label,
20064
- hookLabel: spec.hookLabel,
20065
- setupCommand: spec.setupCommand,
20066
- settingsPath: spec.settingsPath(home),
20067
- installed: detected[spec.id],
20068
- wireState: spec.wireState(home)
20069
- }));
20072
+ return AGENT_SPECS.map((spec) => {
20073
+ const root = spec.hookFile ? readHookRoot(spec.hookFile(home), spec.hookFormat) : "absent";
20074
+ const primary = spec.hookEvents[0];
20075
+ const rootPresent = root !== "absent" && root !== "invalid";
20076
+ const pad = spec.labelPad ?? DEFAULT_LABEL_PAD;
20077
+ const hooks = spec.hookEvents.map((ev) => ({
20078
+ label: hookLabelOf(ev, pad),
20079
+ wired: rootPresent && eventWired(root, ev, spec.hookFormat)
20080
+ }));
20081
+ let wireState;
20082
+ if (root === "absent") wireState = "absent";
20083
+ else if (root === "invalid") wireState = "invalid";
20084
+ else wireState = primary && eventWired(root, primary, spec.hookFormat) ? "wired" : "unwired";
20085
+ const mcp = spec.mcpFile ? readMcp(spec.mcpFile(home)) : null;
20086
+ const anyHookWired = hooks.some((h) => h.wired);
20087
+ return {
20088
+ id: spec.id,
20089
+ label: spec.label,
20090
+ setupCommand: spec.setupCommand,
20091
+ installed: detected[spec.id],
20092
+ present: spec.present(home),
20093
+ hooks,
20094
+ wireState,
20095
+ hookLabel: primary ? `${primary.key} hook` : "MCP proxy",
20096
+ settingsPath: spec.hookFile ? spec.hookFile(home) : spec.mcpFile ? spec.mcpFile(home) : "",
20097
+ configFormat: spec.hookFormat === "yaml" ? "YAML" : "JSON",
20098
+ mcpServers: mcp ? mcp.wrapped : null,
20099
+ mcpProtected: mcp ? mcp.present : false,
20100
+ isProtected: anyHookWired || (mcp?.present ?? false)
20101
+ };
20102
+ });
20070
20103
  }
20071
20104
 
20072
20105
  // src/cli/commands/doctor.ts
@@ -20156,12 +20189,13 @@ function registerDoctorCommand(program2, version2) {
20156
20189
  section("Agent Hooks");
20157
20190
  const notConfigured = [];
20158
20191
  for (const a of getAgentWiring(homeDir2)) {
20159
- if (a.wireState === "wired") {
20160
- pass(`${a.label} \u2014 ${a.hookLabel} active`);
20161
- } else if (a.wireState === "unwired") {
20162
- fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
20192
+ const anyHookWired = a.hooks.some((h) => h.wired);
20193
+ if (a.isProtected) {
20194
+ pass(`${a.label} \u2014 ${anyHookWired ? `${a.hookLabel} active` : "MCP proxy active"}`);
20163
20195
  } else if (a.wireState === "invalid") {
20164
20196
  fail(`${a.label} \u2014 settings file is invalid JSON`, a.settingsPath);
20197
+ } else if (a.wireState === "unwired") {
20198
+ fail(`${a.label} \u2014 settings found but node9 hook missing`, `Run: ${a.setupCommand}`);
20165
20199
  } else {
20166
20200
  notConfigured.push(a.label);
20167
20201
  }
@@ -21463,52 +21497,10 @@ function registerDaemonCommand(program2) {
21463
21497
  // src/cli/commands/status.ts
21464
21498
  init_core();
21465
21499
  init_daemon();
21466
- init_setup();
21467
21500
  import chalk15 from "chalk";
21468
21501
  import fs42 from "fs";
21469
21502
  import path43 from "path";
21470
21503
  import os38 from "os";
21471
- import * as yaml3 from "yaml";
21472
- function readHermesHooks(configPath) {
21473
- if (!fs42.existsSync(configPath)) return null;
21474
- let raw;
21475
- try {
21476
- raw = fs42.readFileSync(configPath, "utf-8");
21477
- } catch {
21478
- return null;
21479
- }
21480
- try {
21481
- const cfg = yaml3.parse(raw);
21482
- const has = (event) => (cfg?.hooks?.[event] ?? []).some(
21483
- (e) => typeof e?.command === "string" && isNode9Hook(e.command)
21484
- );
21485
- return { pre: has("pre_tool_call"), post: has("post_tool_call") };
21486
- } catch {
21487
- console.error(
21488
- chalk15.yellow(
21489
- ` \u26A0\uFE0F Hermes config.yaml at ${configPath} is not valid YAML \u2014 showing as unwired.`
21490
- )
21491
- );
21492
- return { pre: false, post: false };
21493
- }
21494
- }
21495
- function readJson3(filePath) {
21496
- try {
21497
- if (fs42.existsSync(filePath)) return JSON.parse(fs42.readFileSync(filePath, "utf-8"));
21498
- } catch {
21499
- }
21500
- return null;
21501
- }
21502
- function matchersHaveNode9Hook2(matchers) {
21503
- return (matchers ?? []).some((m) => (m.hooks ?? []).some((h) => isNode9Hook(h.command)));
21504
- }
21505
- function flatHaveNode9Hook2(entries) {
21506
- return (Array.isArray(entries) ? entries : []).some((h) => isNode9Hook(h.command));
21507
- }
21508
- function wrappedMcpServers(servers) {
21509
- if (!servers) return [];
21510
- return Object.entries(servers).filter(([, s]) => s.command === "node9" && Array.isArray(s.args) && s.args.length > 0).map(([name, s]) => `${name} \u2192 ${s.args.join(" ")}`);
21511
- }
21512
21504
  function printAgentSection(label, hookPairs, wrapped) {
21513
21505
  console.log(chalk15.bold(` ${label}`));
21514
21506
  for (const { name, present } of hookPairs) {
@@ -21575,102 +21567,23 @@ function registerStatusCommand(program2) {
21575
21567
  ` Sandbox: ${chalk15.green(`${mergedConfig.policy.sandboxPaths.length} safe zones active`)}`
21576
21568
  );
21577
21569
  }
21578
- const homeDir2 = os38.homedir();
21579
- const claudeSettings = readJson3(
21580
- path43.join(homeDir2, ".claude", "settings.json")
21581
- );
21582
- const claudeConfig = readJson3(path43.join(homeDir2, ".claude.json"));
21583
- const geminiSettings = readJson3(
21584
- path43.join(homeDir2, ".gemini", "settings.json")
21585
- );
21586
- const cursorConfig = readJson3(path43.join(homeDir2, ".cursor", "mcp.json"));
21587
- const antigravityHooks = readJson3(
21588
- path43.join(homeDir2, ".gemini", "config", "hooks.json")
21589
- );
21590
- const antigravityMcp = readJson3(
21591
- path43.join(homeDir2, ".gemini", "config", "mcp_config.json")
21592
- );
21593
- const antigravityPresent = antigravityHooks !== null || fs42.existsSync(path43.join(homeDir2, ".gemini", "antigravity-cli")) || fs42.existsSync(path43.join(homeDir2, ".gemini", "antigravity-ide"));
21594
- const copilotHooks = readJson3(
21595
- path43.join(homeDir2, ".copilot", "hooks", "node9.json")
21596
- );
21597
- const copilotMcp = readJson3(
21598
- path43.join(homeDir2, ".copilot", "mcp-config.json")
21599
- );
21600
- const copilotPresent = fs42.existsSync(path43.join(homeDir2, ".copilot"));
21601
- const hermesHooks = readHermesHooks(hermesConfigPath(homeDir2));
21602
- const agentFound = claudeSettings || claudeConfig || geminiSettings || cursorConfig || antigravityPresent || copilotPresent || hermesHooks;
21603
- if (agentFound) {
21570
+ const wiring = getAgentWiring(os38.homedir()).filter((a) => a.present);
21571
+ if (wiring.length > 0) {
21604
21572
  console.log("");
21605
21573
  console.log(chalk15.bold(" Agent Wiring:"));
21606
21574
  console.log("");
21607
- if (claudeSettings || claudeConfig) {
21608
- const preHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PreToolUse);
21609
- const postHook = matchersHaveNode9Hook2(claudeSettings?.hooks?.PostToolUse);
21610
- printAgentSection(
21611
- "Claude Code",
21612
- [
21613
- { name: "PreToolUse (node9 check)", present: preHook },
21614
- { name: "PostToolUse (node9 log)", present: postHook }
21615
- ],
21616
- wrappedMcpServers(claudeConfig?.mcpServers)
21617
- );
21618
- console.log("");
21619
- }
21620
- if (geminiSettings) {
21621
- const beforeHook = matchersHaveNode9Hook2(geminiSettings.hooks?.BeforeTool);
21622
- const afterHook = matchersHaveNode9Hook2(geminiSettings.hooks?.AfterTool);
21623
- printAgentSection(
21624
- "Gemini CLI",
21625
- [
21626
- { name: "BeforeTool (node9 check)", present: beforeHook },
21627
- { name: "AfterTool (node9 log)", present: afterHook }
21628
- ],
21629
- wrappedMcpServers(geminiSettings.mcpServers)
21630
- );
21631
- console.log("");
21632
- }
21633
- if (antigravityPresent) {
21634
- const preHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PreToolUse);
21635
- const postHook = matchersHaveNode9Hook2(antigravityHooks?.hooks?.PostToolUse);
21636
- printAgentSection(
21637
- "Antigravity",
21638
- [
21639
- { name: "PreToolUse (node9 check)", present: preHook },
21640
- { name: "PostToolUse (node9 log)", present: postHook }
21641
- ],
21642
- wrappedMcpServers(antigravityMcp?.mcpServers)
21643
- );
21644
- console.log("");
21645
- }
21646
- if (copilotPresent) {
21647
- const preHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PreToolUse);
21648
- const postHook = flatHaveNode9Hook2(copilotHooks?.hooks?.PostToolUse);
21649
- const promptHook = flatHaveNode9Hook2(copilotHooks?.hooks?.UserPromptSubmit);
21650
- printAgentSection(
21651
- "GitHub Copilot",
21652
- [
21653
- { name: "PreToolUse (node9 check)", present: preHook },
21654
- { name: "PostToolUse (node9 log)", present: postHook },
21655
- { name: "UserPromptSubmit (node9 check)", present: promptHook }
21656
- ],
21657
- wrappedMcpServers(copilotMcp?.mcpServers)
21658
- );
21659
- console.log("");
21660
- }
21661
- if (cursorConfig) {
21662
- printAgentSection("Cursor", [], wrappedMcpServers(cursorConfig.mcpServers));
21663
- console.log("");
21664
- }
21665
- if (hermesHooks) {
21575
+ for (const a of wiring) {
21576
+ if (a.wireState === "invalid") {
21577
+ console.error(
21578
+ chalk15.yellow(
21579
+ ` \u26A0\uFE0F ${a.label} config at ${a.settingsPath} is not valid ${a.configFormat} \u2014 showing as unwired.`
21580
+ )
21581
+ );
21582
+ }
21666
21583
  printAgentSection(
21667
- "Hermes Agent",
21668
- [
21669
- { name: "pre_tool_call (node9 check)", present: hermesHooks.pre },
21670
- { name: "post_tool_call (node9 log)", present: hermesHooks.post }
21671
- ],
21672
- null
21673
- // Hermes has no MCP surface
21584
+ a.label,
21585
+ a.hooks.map((h) => ({ name: h.label, present: h.wired })),
21586
+ a.mcpServers
21674
21587
  );
21675
21588
  console.log("");
21676
21589
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "1.35.1",
3
+ "version": "1.35.2",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",