github-router 0.3.33 → 0.3.35

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.
@@ -3613,6 +3613,32 @@ var import_subprotocol = /* @__PURE__ */ __toESM(require_subprotocol(), 1);
3613
3613
  var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
3614
3614
  var import_websocket_server = /* @__PURE__ */ __toESM(require_websocket_server(), 1);
3615
3615
 
3616
+ //#endregion
3617
+ //#region src/lib/browser-mcp/bridge-paths.ts
3618
+ /**
3619
+ * Filesystem path where the browser bridge writes its discovery file
3620
+ * (`{pid, port, token, startedAt}`) and where the install-check reads
3621
+ * it from. Used by `src/browser-bridge/index.ts` (writer) AND by
3622
+ * `src/lib/browser-mcp/install-check.ts` (reader).
3623
+ *
3624
+ * MUST be a single computation. Historically the bridge special-cased
3625
+ * win32 to `%LOCALAPPDATA%\github-router` while the install-check used
3626
+ * `~/.local/share/github-router` (the canonical `PATHS.APP_DIR` from
3627
+ * `src/lib/paths.ts`, which has no win32 branch). On Windows the
3628
+ * writer and reader never met, so the install-check returned
3629
+ * `bridge_not_running` even with a healthy bridge. Centralized here so
3630
+ * the regression test in `tests/browser-bridge-discovery-path.test.ts`
3631
+ * can pin the round-trip.
3632
+ *
3633
+ * Mirrors `PATHS.APP_DIR` from `src/lib/paths.ts` (XDG-style on every
3634
+ * platform). The bridge bundle pulls this file in via tsdown's
3635
+ * relative-import bundling; no runtime dependency on `src/lib/paths.ts`
3636
+ * is introduced.
3637
+ */
3638
+ function discoveryPath() {
3639
+ return path.join(homedir(), ".local", "share", "github-router", "browser-mcp", "bridge.json");
3640
+ }
3641
+
3616
3642
  //#endregion
3617
3643
  //#region src/browser-bridge/index.ts
3618
3644
  try {
@@ -3620,17 +3646,6 @@ try {
3620
3646
  } catch {}
3621
3647
  const HEARTBEAT_MS = 5e3;
3622
3648
  const HEARTBEAT_MISS_LIMIT = 3;
3623
- function appDir() {
3624
- if (platform() === "win32") {
3625
- const local = process$1.env.LOCALAPPDATA;
3626
- if (local) return path.join(local, "github-router");
3627
- return path.join(homedir(), "AppData", "Local", "github-router");
3628
- }
3629
- return path.join(homedir(), ".local", "share", "github-router");
3630
- }
3631
- function discoveryPath() {
3632
- return path.join(appDir(), "browser-mcp", "bridge.json");
3633
- }
3634
3649
  function writeDiscoveryFile(payload) {
3635
3650
  const file = discoveryPath();
3636
3651
  mkdirSync(path.dirname(file), { recursive: true });
package/dist/main.js CHANGED
@@ -929,31 +929,15 @@ async function autoUpdateClaude(latestVersion) {
929
929
  //#endregion
930
930
  //#region src/lib/port.ts
931
931
  const DEFAULT_PORT = 8787;
932
- /**
933
- * Default model for `github-router claude`. The Anthropic-published dashed
934
- * slug (`claude-opus-4-7`) — NOT the Copilot-internal slug
935
- * (`claude-opus-4.7-1m-internal`) — because Claude Code 2.1.126's `/model`
936
- * UI is backed by a hardcoded registry of Anthropic slugs, and an
937
- * unrecognized slug causes the menu to highlight "Opus 4" with a
938
- * "Newer version available" hint instead of "Opus 4.7 (1M context)".
939
- *
940
- * The proxy's `resolveModel` (`src/lib/utils.ts`) translates this to
941
- * Copilot's `claude-opus-4.7-1m-internal` (enterprise) or
942
- * `claude-opus-4.7` (Pro+/Business/Max) at request time via the
943
- * family-preference + version-match branch — round-trip covered by
944
- * `tests/lib-utils.test.ts:154`.
945
- *
946
- * `DEFAULT_CLAUDE_MODEL_FALLBACKS` covers major.minor regressions only;
947
- * 1M↔200K downgrade is handled inside the resolver, so we don't need
948
- * separate `-1m` entries here.
949
- */
950
- const DEFAULT_CLAUDE_MODEL = "claude-opus-4-7";
951
932
  const DEFAULT_CLAUDE_MODEL_FALLBACKS = ["claude-opus-4-6", "claude-opus-4-5"];
952
933
  /**
953
934
  * Cap-aware default picker for `ANTHROPIC_MODEL` on the implicit-default
954
- * path. Returns `claude-opus-4-7[1m]` when the live Copilot catalog
955
- * contains a `*-opus-4.7-1m*` variant (enterprise tier), else
956
- * `DEFAULT_CLAUDE_MODEL` (the bare slug).
935
+ * path. Returns `claude-opus-${family}[1m]` when the live Copilot catalog
936
+ * contains an `opus-${family}-1m*` variant (enterprise tier), else the
937
+ * bare `claude-opus-${family}` slug. `family` defaults to `"4.7"` so the
938
+ * no-arg call preserves the original behavior; explicit values like
939
+ * `"4.6"` or `"4.8"` are used to honor the `github-router claude
940
+ * -m <version>` family shorthand.
957
941
  *
958
942
  * The `[1m]` literal-bracket suffix is Claude Code's local 1M-context
959
943
  * unlock — cc-backup `src/utils/context.ts:35-40` matches `/\[1m\]/i`
@@ -980,12 +964,21 @@ const DEFAULT_CLAUDE_MODEL_FALLBACKS = ["claude-opus-4-6", "claude-opus-4-5"];
980
964
  * can't tell the difference between "no catalog yet" and "no 1M
981
965
  * variant" — defaulting safe-side preserves the pre-change behavior).
982
966
  */
983
- function pickClaudeDefault() {
984
- if (state.models?.data.some((m) => /opus-4[.-]7-1m(?:$|-)/i.test(m.id)) ?? false) {
985
- consola.info(`Catalog contains opus-4.7-1m variant; defaulting ANTHROPIC_MODEL to "${DEFAULT_CLAUDE_MODEL}[1m]" so Claude Code accounts for 1M context locally. Set CLAUDE_CODE_DISABLE_1M_CONTEXT=1 to opt out (HIPAA), or pass --model ${DEFAULT_CLAUDE_MODEL} to pin 200K.`);
986
- return `${DEFAULT_CLAUDE_MODEL}[1m]`;
967
+ const DEFAULT_OPUS_FAMILY = "4.7";
968
+ function pickClaudeDefault(opusFamily = DEFAULT_OPUS_FAMILY) {
969
+ const dotted = opusFamily.replace(/-/g, ".");
970
+ const bareSlug = `claude-opus-${dotted.replace(/\./g, "-")}`;
971
+ const versionPattern = dotted.replace(/\./g, "[.-]");
972
+ const oneMRegex = new RegExp(`opus-${versionPattern}-1m(?:$|-)`, "i");
973
+ const familyRegex = new RegExp(`opus-${versionPattern}(?:$|[-.])`, "i");
974
+ const models = state.models?.data ?? [];
975
+ const has1m = models.some((m) => oneMRegex.test(m.id));
976
+ if (opusFamily !== DEFAULT_OPUS_FAMILY && state.models && models.length > 0 && !models.some((m) => familyRegex.test(m.id))) consola.warn(`Requested Opus family "${dotted}" not found in Copilot catalog; using "${bareSlug}" anyway (resolveModel may not find a backend for it).`);
977
+ if (has1m) {
978
+ consola.info(`Catalog contains opus-${dotted}-1m variant; defaulting ANTHROPIC_MODEL to "${bareSlug}[1m]" so Claude Code accounts for 1M context locally. Set CLAUDE_CODE_DISABLE_1M_CONTEXT=1 to opt out (HIPAA), or pass --model ${bareSlug} to pin 200K.`);
979
+ return `${bareSlug}[1m]`;
987
980
  }
988
- return DEFAULT_CLAUDE_MODEL;
981
+ return bareSlug;
989
982
  }
990
983
  /**
991
984
  * Default model for `github-router codex`. `gpt-5.5` is the new flagship
@@ -2587,6 +2580,32 @@ function hasSupportedBrowserInstalled() {
2587
2580
  return detectSupportedBrowsers().length > 0;
2588
2581
  }
2589
2582
 
2583
+ //#endregion
2584
+ //#region src/lib/browser-mcp/bridge-paths.ts
2585
+ /**
2586
+ * Filesystem path where the browser bridge writes its discovery file
2587
+ * (`{pid, port, token, startedAt}`) and where the install-check reads
2588
+ * it from. Used by `src/browser-bridge/index.ts` (writer) AND by
2589
+ * `src/lib/browser-mcp/install-check.ts` (reader).
2590
+ *
2591
+ * MUST be a single computation. Historically the bridge special-cased
2592
+ * win32 to `%LOCALAPPDATA%\github-router` while the install-check used
2593
+ * `~/.local/share/github-router` (the canonical `PATHS.APP_DIR` from
2594
+ * `src/lib/paths.ts`, which has no win32 branch). On Windows the
2595
+ * writer and reader never met, so the install-check returned
2596
+ * `bridge_not_running` even with a healthy bridge. Centralized here so
2597
+ * the regression test in `tests/browser-bridge-discovery-path.test.ts`
2598
+ * can pin the round-trip.
2599
+ *
2600
+ * Mirrors `PATHS.APP_DIR` from `src/lib/paths.ts` (XDG-style on every
2601
+ * platform). The bridge bundle pulls this file in via tsdown's
2602
+ * relative-import bundling; no runtime dependency on `src/lib/paths.ts`
2603
+ * is introduced.
2604
+ */
2605
+ function discoveryPath() {
2606
+ return path.join(homedir(), ".local", "share", "github-router", "browser-mcp", "bridge.json");
2607
+ }
2608
+
2590
2609
  //#endregion
2591
2610
  //#region src/lib/browser-mcp/native-host-installer.ts
2592
2611
  const NMH_HOST_ID = "com.githubrouter.browser";
@@ -2815,9 +2834,6 @@ function installNativeHostForAll(browsers) {
2815
2834
 
2816
2835
  //#endregion
2817
2836
  //#region src/lib/browser-mcp/install-check.ts
2818
- function discoveryPath() {
2819
- return path.join(PATHS.APP_DIR, "browser-mcp", "bridge.json");
2820
- }
2821
2837
  function readBridgeDiscovery() {
2822
2838
  try {
2823
2839
  const raw = readFileSync(discoveryPath(), "utf8");
@@ -10879,7 +10895,7 @@ function initProxyFromEnv() {
10879
10895
  //#endregion
10880
10896
  //#region package.json
10881
10897
  var name = "github-router";
10882
- var version = "0.3.33";
10898
+ var version = "0.3.35";
10883
10899
 
10884
10900
  //#endregion
10885
10901
  //#region src/lib/approval.ts
@@ -13000,7 +13016,7 @@ const claude = defineCommand({
13000
13016
  model: {
13001
13017
  alias: "m",
13002
13018
  type: "string",
13003
- description: "Override the default model for Claude Code"
13019
+ description: "Override the default model for Claude Code. Accepts a full slug (e.g. claude-opus-4-7) or an Opus family shorthand (e.g. 4.7, 4.8, 4.6) which expands to the best variant for that family — adding the [1m] suffix when a 1M-context backend is in the catalog."
13004
13020
  },
13005
13021
  "codex-mcp": {
13006
13022
  type: "boolean",
@@ -13079,7 +13095,8 @@ const claude = defineCommand({
13079
13095
  }
13080
13096
  enableFileLogging();
13081
13097
  const usingDefault = !args.model;
13082
- let chosenSlug = args.model ?? pickClaudeDefault();
13098
+ const opusFamilyShorthand = args.model?.match(/^(\d+\.\d+)$/)?.[1];
13099
+ let chosenSlug = opusFamilyShorthand ? pickClaudeDefault(opusFamilyShorthand) : args.model ?? pickClaudeDefault();
13083
13100
  let resolvedSlug = resolveModel(chosenSlug);
13084
13101
  if (usingDefault && state.models) {
13085
13102
  const inCache = (slug) => state.models?.data.some((m) => m.id === resolveModel(slug)) ?? false;