@node9/proxy 1.52.0 → 1.54.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.
Files changed (3) hide show
  1. package/dist/cli.js +58 -20
  2. package/dist/cli.mjs +58 -20
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8640,10 +8640,27 @@ function claudeDesktopConfigPath(homeDir2 = import_os12.default.homedir()) {
8640
8640
  }
8641
8641
  return null;
8642
8642
  }
8643
- function binaryInPath(binary) {
8643
+ function opencodeConfigDir(home = import_os12.default.homedir()) {
8644
+ const xdg = process.env.XDG_CONFIG_HOME;
8645
+ const base = xdg && import_path15.default.isAbsolute(xdg) ? xdg : import_path15.default.join(home, ".config");
8646
+ return import_path15.default.join(base, "opencode");
8647
+ }
8648
+ function commonBinDirs(home) {
8649
+ return [
8650
+ import_path15.default.join(home, ".local", "bin"),
8651
+ import_path15.default.join(home, ".bun", "bin"),
8652
+ import_path15.default.join(home, ".npm-global", "bin"),
8653
+ "/usr/local/bin",
8654
+ "/opt/homebrew/bin"
8655
+ ];
8656
+ }
8657
+ function binaryInPath(binary, home = import_os12.default.homedir()) {
8644
8658
  const pathEnv = process.env.PATH ?? "";
8645
- for (const dir of pathEnv.split(import_path15.default.delimiter)) {
8646
- if (!dir) continue;
8659
+ const dirs = [...pathEnv.split(import_path15.default.delimiter), ...commonBinDirs(home)];
8660
+ const seen = /* @__PURE__ */ new Set();
8661
+ for (const dir of dirs) {
8662
+ if (!dir || seen.has(dir)) continue;
8663
+ seen.add(dir);
8647
8664
  try {
8648
8665
  import_fs13.default.accessSync(import_path15.default.join(dir, binary), import_fs13.default.constants.X_OK);
8649
8666
  return true;
@@ -8677,35 +8694,36 @@ function detectAgents(homeDir2 = import_os12.default.homedir()) {
8677
8694
  // creates ~/.gemini/settings.json on first run; agy does not touch
8678
8695
  // it (it uses antigravity-cli/settings.json) — that file is the
8679
8696
  // legacy-CLI discriminator.
8680
- gemini: exists2(import_path15.default.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8697
+ gemini: exists2(import_path15.default.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini", homeDir2),
8681
8698
  // agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
8682
8699
  // creates antigravity-ide/. PATH fallback covers installed-but-
8683
8700
  // never-launched (same class as opencode #186).
8684
- antigravity: exists2(import_path15.default.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(import_path15.default.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8701
+ antigravity: exists2(import_path15.default.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(import_path15.default.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy", homeDir2),
8685
8702
  // GitHub Copilot CLI creates ~/.copilot on first launch; PATH
8686
8703
  // fallback covers installed-but-never-launched (same as opencode #186).
8687
- copilot: exists2(import_path15.default.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8704
+ copilot: exists2(import_path15.default.join(homeDir2, ".copilot")) || binaryInPath("copilot", homeDir2),
8688
8705
  cursor: exists2(import_path15.default.join(homeDir2, ".cursor")),
8689
8706
  codex: exists2(import_path15.default.join(homeDir2, ".codex")),
8690
8707
  windsurf: exists2(import_path15.default.join(homeDir2, ".codeium", "windsurf")),
8691
8708
  vscode: exists2(import_path15.default.join(homeDir2, ".vscode")),
8692
8709
  claudeDesktop: desktopPath !== null && exists2(import_path15.default.dirname(desktopPath)),
8693
- // Opencode creates ~/.config/opencode lazily on first launch — fall back
8694
- // to a PATH lookup so installed-but-never-launched CLIs are still wired.
8695
- opencode: exists2(import_path15.default.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8710
+ // Opencode creates its config dir lazily on first launch — fall back to a
8711
+ // PATH lookup so installed-but-never-launched CLIs are still wired. Config
8712
+ // dir honors $XDG_CONFIG_HOME via opencodeConfigDir (#186, custom-XDG).
8713
+ opencode: exists2(opencodeConfigDir(homeDir2)) || binaryInPath("opencode", homeDir2),
8696
8714
  // Pi (https://pi.dev): config dir is ~/.pi/agent (CONFIG_DIR_NAME=".pi"
8697
8715
  // + agentDir, verified against opensources/pi-main/packages/coding-agent/
8698
8716
  // src/config.ts:449,475). The Bun-compiled binary path may create this
8699
8717
  // dir lazily on first launch — same class of bug as opencode's #186
8700
8718
  // (design R6) — so fall back to PATH lookup for installed-but-never-
8701
8719
  // launched pi.
8702
- pi: exists2(import_path15.default.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8720
+ pi: exists2(import_path15.default.join(homeDir2, ".pi", "agent")) || binaryInPath("pi", homeDir2),
8703
8721
  // Hermes Agent (https://github.com/NousResearch/hermes-agent): home dir
8704
8722
  // is $HERMES_HOME (default ~/.hermes) per hermes_constants.py:30. config.yaml
8705
8723
  // appears after `hermes setup` has run; the directory alone exists from
8706
8724
  // install time. PATH fallback covers the rare case where the user blew
8707
8725
  // away ~/.hermes but kept the binary.
8708
- hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8726
+ hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes", homeDir2)
8709
8727
  };
8710
8728
  }
8711
8729
  async function setupCursor() {
@@ -9358,7 +9376,7 @@ function node9Version() {
9358
9376
  async function setupOpencode() {
9359
9377
  seedMcpPinsIfMissing();
9360
9378
  const homeDir2 = import_os12.default.homedir();
9361
- const configDir = import_path15.default.join(homeDir2, ".config", "opencode");
9379
+ const configDir = opencodeConfigDir(homeDir2);
9362
9380
  const pluginsDir = import_path15.default.join(configDir, "plugins");
9363
9381
  const configPath = import_path15.default.join(configDir, "opencode.json");
9364
9382
  const pluginPath = import_path15.default.join(pluginsDir, OPENCODE_PLUGIN_NAME);
@@ -9426,7 +9444,7 @@ async function setupOpencode() {
9426
9444
  }
9427
9445
  function teardownOpencode() {
9428
9446
  const homeDir2 = import_os12.default.homedir();
9429
- const configDir = import_path15.default.join(homeDir2, ".config", "opencode");
9447
+ const configDir = opencodeConfigDir(homeDir2);
9430
9448
  const pluginsDir = import_path15.default.join(configDir, "plugins");
9431
9449
  const configPath = import_path15.default.join(configDir, "opencode.json");
9432
9450
  const pluginPath = import_path15.default.join(pluginsDir, OPENCODE_PLUGIN_NAME);
@@ -10068,8 +10086,8 @@ var init_agent_wiring = __esm({
10068
10086
  setupCommand: "node9 agents add opencode",
10069
10087
  hookFormat: "flat",
10070
10088
  hookEvents: [],
10071
- shimFile: (h) => import_path16.default.join(h, ".config", "opencode", "plugins", "node9.js"),
10072
- present: (h) => exists(import_path16.default.join(h, ".config", "opencode")) || exists(import_path16.default.join(h, ".config", "opencode", "plugins", "node9.js"))
10089
+ shimFile: (h) => import_path16.default.join(opencodeConfigDir(h), "plugins", "node9.js"),
10090
+ present: (h) => exists(opencodeConfigDir(h)) || exists(import_path16.default.join(opencodeConfigDir(h), "plugins", "node9.js"))
10073
10091
  },
10074
10092
  {
10075
10093
  id: "pi",
@@ -16946,6 +16964,23 @@ function readCachedEtag() {
16946
16964
  return void 0;
16947
16965
  }
16948
16966
  }
16967
+ function readCachedSyncIntervalHours() {
16968
+ try {
16969
+ const raw = JSON.parse(import_fs32.default.readFileSync(rulesCacheFile(), "utf-8"));
16970
+ return typeof raw.syncIntervalHours === "number" ? raw.syncIntervalHours : void 0;
16971
+ } catch {
16972
+ return void 0;
16973
+ }
16974
+ }
16975
+ function pickSyncIntervalMs(cloudHours, localSettings) {
16976
+ if (typeof cloudHours === "number" && Number.isFinite(cloudHours)) {
16977
+ return resolveSyncIntervalMs({ cloudSyncIntervalHours: cloudHours });
16978
+ }
16979
+ return resolveSyncIntervalMs(localSettings);
16980
+ }
16981
+ function effectiveSyncIntervalMs() {
16982
+ return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
16983
+ }
16949
16984
  function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
16950
16985
  const parsed = new URL(apiUrl);
16951
16986
  const headers = {
@@ -17255,11 +17290,14 @@ function getCloudRules() {
17255
17290
  }
17256
17291
  }
17257
17292
  function startCloudSync() {
17258
- const intervalMs = resolveSyncIntervalMs(getConfig().settings);
17259
- const initial = setTimeout(() => void syncOnce(), 3e4);
17260
- initial.unref();
17261
- const recurring = setInterval(() => void syncOnce(), intervalMs);
17262
- recurring.unref();
17293
+ const scheduleNext = (ms) => {
17294
+ const t = setTimeout(() => {
17295
+ void syncOnce().catch(() => {
17296
+ }).finally(() => scheduleNext(effectiveSyncIntervalMs()));
17297
+ }, ms);
17298
+ t.unref();
17299
+ };
17300
+ scheduleNext(3e4);
17263
17301
  }
17264
17302
  function startForensicBroadcast() {
17265
17303
  const tick = async () => {
package/dist/cli.mjs CHANGED
@@ -8622,10 +8622,27 @@ function claudeDesktopConfigPath(homeDir2 = os12.homedir()) {
8622
8622
  }
8623
8623
  return null;
8624
8624
  }
8625
- function binaryInPath(binary) {
8625
+ function opencodeConfigDir(home = os12.homedir()) {
8626
+ const xdg = process.env.XDG_CONFIG_HOME;
8627
+ const base = xdg && path15.isAbsolute(xdg) ? xdg : path15.join(home, ".config");
8628
+ return path15.join(base, "opencode");
8629
+ }
8630
+ function commonBinDirs(home) {
8631
+ return [
8632
+ path15.join(home, ".local", "bin"),
8633
+ path15.join(home, ".bun", "bin"),
8634
+ path15.join(home, ".npm-global", "bin"),
8635
+ "/usr/local/bin",
8636
+ "/opt/homebrew/bin"
8637
+ ];
8638
+ }
8639
+ function binaryInPath(binary, home = os12.homedir()) {
8626
8640
  const pathEnv = process.env.PATH ?? "";
8627
- for (const dir of pathEnv.split(path15.delimiter)) {
8628
- if (!dir) continue;
8641
+ const dirs = [...pathEnv.split(path15.delimiter), ...commonBinDirs(home)];
8642
+ const seen = /* @__PURE__ */ new Set();
8643
+ for (const dir of dirs) {
8644
+ if (!dir || seen.has(dir)) continue;
8645
+ seen.add(dir);
8629
8646
  try {
8630
8647
  fs13.accessSync(path15.join(dir, binary), fs13.constants.X_OK);
8631
8648
  return true;
@@ -8659,35 +8676,36 @@ function detectAgents(homeDir2 = os12.homedir()) {
8659
8676
  // creates ~/.gemini/settings.json on first run; agy does not touch
8660
8677
  // it (it uses antigravity-cli/settings.json) — that file is the
8661
8678
  // legacy-CLI discriminator.
8662
- gemini: exists2(path15.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini"),
8679
+ gemini: exists2(path15.join(homeDir2, ".gemini", "settings.json")) || binaryInPath("gemini", homeDir2),
8663
8680
  // agy creates ~/.gemini/antigravity-cli/ on first launch; the IDE
8664
8681
  // creates antigravity-ide/. PATH fallback covers installed-but-
8665
8682
  // never-launched (same class as opencode #186).
8666
- antigravity: exists2(path15.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(path15.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy"),
8683
+ antigravity: exists2(path15.join(homeDir2, ".gemini", "antigravity-cli")) || exists2(path15.join(homeDir2, ".gemini", "antigravity-ide")) || binaryInPath("agy", homeDir2),
8667
8684
  // GitHub Copilot CLI creates ~/.copilot on first launch; PATH
8668
8685
  // fallback covers installed-but-never-launched (same as opencode #186).
8669
- copilot: exists2(path15.join(homeDir2, ".copilot")) || binaryInPath("copilot"),
8686
+ copilot: exists2(path15.join(homeDir2, ".copilot")) || binaryInPath("copilot", homeDir2),
8670
8687
  cursor: exists2(path15.join(homeDir2, ".cursor")),
8671
8688
  codex: exists2(path15.join(homeDir2, ".codex")),
8672
8689
  windsurf: exists2(path15.join(homeDir2, ".codeium", "windsurf")),
8673
8690
  vscode: exists2(path15.join(homeDir2, ".vscode")),
8674
8691
  claudeDesktop: desktopPath !== null && exists2(path15.dirname(desktopPath)),
8675
- // Opencode creates ~/.config/opencode lazily on first launch — fall back
8676
- // to a PATH lookup so installed-but-never-launched CLIs are still wired.
8677
- opencode: exists2(path15.join(homeDir2, ".config", "opencode")) || binaryInPath("opencode"),
8692
+ // Opencode creates its config dir lazily on first launch — fall back to a
8693
+ // PATH lookup so installed-but-never-launched CLIs are still wired. Config
8694
+ // dir honors $XDG_CONFIG_HOME via opencodeConfigDir (#186, custom-XDG).
8695
+ opencode: exists2(opencodeConfigDir(homeDir2)) || binaryInPath("opencode", homeDir2),
8678
8696
  // Pi (https://pi.dev): config dir is ~/.pi/agent (CONFIG_DIR_NAME=".pi"
8679
8697
  // + agentDir, verified against opensources/pi-main/packages/coding-agent/
8680
8698
  // src/config.ts:449,475). The Bun-compiled binary path may create this
8681
8699
  // dir lazily on first launch — same class of bug as opencode's #186
8682
8700
  // (design R6) — so fall back to PATH lookup for installed-but-never-
8683
8701
  // launched pi.
8684
- pi: exists2(path15.join(homeDir2, ".pi", "agent")) || binaryInPath("pi"),
8702
+ pi: exists2(path15.join(homeDir2, ".pi", "agent")) || binaryInPath("pi", homeDir2),
8685
8703
  // Hermes Agent (https://github.com/NousResearch/hermes-agent): home dir
8686
8704
  // is $HERMES_HOME (default ~/.hermes) per hermes_constants.py:30. config.yaml
8687
8705
  // appears after `hermes setup` has run; the directory alone exists from
8688
8706
  // install time. PATH fallback covers the rare case where the user blew
8689
8707
  // away ~/.hermes but kept the binary.
8690
- hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes")
8708
+ hermes: exists2(hermesHomeDir(homeDir2)) || binaryInPath("hermes", homeDir2)
8691
8709
  };
8692
8710
  }
8693
8711
  async function setupCursor() {
@@ -9340,7 +9358,7 @@ function node9Version() {
9340
9358
  async function setupOpencode() {
9341
9359
  seedMcpPinsIfMissing();
9342
9360
  const homeDir2 = os12.homedir();
9343
- const configDir = path15.join(homeDir2, ".config", "opencode");
9361
+ const configDir = opencodeConfigDir(homeDir2);
9344
9362
  const pluginsDir = path15.join(configDir, "plugins");
9345
9363
  const configPath = path15.join(configDir, "opencode.json");
9346
9364
  const pluginPath = path15.join(pluginsDir, OPENCODE_PLUGIN_NAME);
@@ -9408,7 +9426,7 @@ async function setupOpencode() {
9408
9426
  }
9409
9427
  function teardownOpencode() {
9410
9428
  const homeDir2 = os12.homedir();
9411
- const configDir = path15.join(homeDir2, ".config", "opencode");
9429
+ const configDir = opencodeConfigDir(homeDir2);
9412
9430
  const pluginsDir = path15.join(configDir, "plugins");
9413
9431
  const configPath = path15.join(configDir, "opencode.json");
9414
9432
  const pluginPath = path15.join(pluginsDir, OPENCODE_PLUGIN_NAME);
@@ -10043,8 +10061,8 @@ var init_agent_wiring = __esm({
10043
10061
  setupCommand: "node9 agents add opencode",
10044
10062
  hookFormat: "flat",
10045
10063
  hookEvents: [],
10046
- shimFile: (h) => path16.join(h, ".config", "opencode", "plugins", "node9.js"),
10047
- present: (h) => exists(path16.join(h, ".config", "opencode")) || exists(path16.join(h, ".config", "opencode", "plugins", "node9.js"))
10064
+ shimFile: (h) => path16.join(opencodeConfigDir(h), "plugins", "node9.js"),
10065
+ present: (h) => exists(opencodeConfigDir(h)) || exists(path16.join(opencodeConfigDir(h), "plugins", "node9.js"))
10048
10066
  },
10049
10067
  {
10050
10068
  id: "pi",
@@ -16920,6 +16938,23 @@ function readCachedEtag() {
16920
16938
  return void 0;
16921
16939
  }
16922
16940
  }
16941
+ function readCachedSyncIntervalHours() {
16942
+ try {
16943
+ const raw = JSON.parse(fs33.readFileSync(rulesCacheFile(), "utf-8"));
16944
+ return typeof raw.syncIntervalHours === "number" ? raw.syncIntervalHours : void 0;
16945
+ } catch {
16946
+ return void 0;
16947
+ }
16948
+ }
16949
+ function pickSyncIntervalMs(cloudHours, localSettings) {
16950
+ if (typeof cloudHours === "number" && Number.isFinite(cloudHours)) {
16951
+ return resolveSyncIntervalMs({ cloudSyncIntervalHours: cloudHours });
16952
+ }
16953
+ return resolveSyncIntervalMs(localSettings);
16954
+ }
16955
+ function effectiveSyncIntervalMs() {
16956
+ return pickSyncIntervalMs(readCachedSyncIntervalHours(), getConfig().settings);
16957
+ }
16923
16958
  function fetchCloudPolicy(apiKey, apiUrl, ifNoneMatch) {
16924
16959
  const parsed = new URL(apiUrl);
16925
16960
  const headers = {
@@ -17229,11 +17264,14 @@ function getCloudRules() {
17229
17264
  }
17230
17265
  }
17231
17266
  function startCloudSync() {
17232
- const intervalMs = resolveSyncIntervalMs(getConfig().settings);
17233
- const initial = setTimeout(() => void syncOnce(), 3e4);
17234
- initial.unref();
17235
- const recurring = setInterval(() => void syncOnce(), intervalMs);
17236
- recurring.unref();
17267
+ const scheduleNext = (ms) => {
17268
+ const t = setTimeout(() => {
17269
+ void syncOnce().catch(() => {
17270
+ }).finally(() => scheduleNext(effectiveSyncIntervalMs()));
17271
+ }, ms);
17272
+ t.unref();
17273
+ };
17274
+ scheduleNext(3e4);
17237
17275
  }
17238
17276
  function startForensicBroadcast() {
17239
17277
  const tick = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "1.52.0",
3
+ "version": "1.54.0",
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",