anyray-connect 0.11.63 → 0.11.66

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 (73) hide show
  1. package/README.md +5 -4
  2. package/dist/assets/vscodeExtensionAsset.js +4 -4
  3. package/dist/assets/vscodeExtensionAsset.js.map +1 -1
  4. package/dist/cli.js +253 -54
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/desktop.js +2 -2
  7. package/dist/commands/desktop.js.map +1 -1
  8. package/dist/commands/doctor.js +74 -19
  9. package/dist/commands/doctor.js.map +1 -1
  10. package/dist/commands/fallbackProxy.js +60 -15
  11. package/dist/commands/fallbackProxy.js.map +1 -1
  12. package/dist/commands/hook.js +19 -0
  13. package/dist/commands/hook.js.map +1 -1
  14. package/dist/commands/managed.js +54 -9
  15. package/dist/commands/managed.js.map +1 -1
  16. package/dist/commands/mcpServer.js +131 -5
  17. package/dist/commands/mcpServer.js.map +1 -1
  18. package/dist/commands/shared.js +7 -5
  19. package/dist/commands/shared.js.map +1 -1
  20. package/dist/commands/status.js +20 -10
  21. package/dist/commands/status.js.map +1 -1
  22. package/dist/tools/claudeCodeHooks.js +21 -12
  23. package/dist/tools/claudeCodeHooks.js.map +1 -1
  24. package/dist/tools/claudeDesktop.js +70 -37
  25. package/dist/tools/claudeDesktop.js.map +1 -1
  26. package/dist/tools/claudeDesktopNative.js +14 -0
  27. package/dist/tools/claudeDesktopNative.js.map +1 -1
  28. package/dist/tools/copilotChat.js +113 -49
  29. package/dist/tools/copilotChat.js.map +1 -1
  30. package/dist/tools/copilotCli.js +436 -0
  31. package/dist/tools/copilotCli.js.map +1 -0
  32. package/dist/tools/cursor.js +23 -4
  33. package/dist/tools/cursor.js.map +1 -1
  34. package/dist/tools/index.js +2 -0
  35. package/dist/tools/index.js.map +1 -1
  36. package/dist/tools/jetbrainsCapability.js +2 -18
  37. package/dist/tools/jetbrainsCapability.js.map +1 -1
  38. package/dist/tools/sharedHooks.js +8 -3
  39. package/dist/tools/sharedHooks.js.map +1 -1
  40. package/dist/types.js.map +1 -1
  41. package/dist/util/cliInvocation.js +33 -0
  42. package/dist/util/cliInvocation.js.map +1 -0
  43. package/dist/util/connectHealth.js +44 -7
  44. package/dist/util/connectHealth.js.map +1 -1
  45. package/dist/util/connectHealthReport.js +14 -0
  46. package/dist/util/connectHealthReport.js.map +1 -1
  47. package/dist/util/devRefresh.js +27 -12
  48. package/dist/util/devRefresh.js.map +1 -1
  49. package/dist/util/devVerify.js +34 -1
  50. package/dist/util/devVerify.js.map +1 -1
  51. package/dist/util/localRead.js +95 -0
  52. package/dist/util/localRead.js.map +1 -0
  53. package/dist/util/localSearch.js +274 -0
  54. package/dist/util/localSearch.js.map +1 -0
  55. package/dist/util/loopback.js +25 -0
  56. package/dist/util/loopback.js.map +1 -0
  57. package/dist/util/persist.js +5 -3
  58. package/dist/util/persist.js.map +1 -1
  59. package/dist/util/profile.js +67 -12
  60. package/dist/util/profile.js.map +1 -1
  61. package/dist/util/profileTarget.js +24 -2
  62. package/dist/util/profileTarget.js.map +1 -1
  63. package/dist/util/proxyService.js +3 -12
  64. package/dist/util/proxyService.js.map +1 -1
  65. package/dist/util/refreshScheduler.js +307 -0
  66. package/dist/util/refreshScheduler.js.map +1 -0
  67. package/dist/util/seatState.js +22 -2
  68. package/dist/util/seatState.js.map +1 -1
  69. package/dist/util/versions.js +24 -0
  70. package/dist/util/versions.js.map +1 -0
  71. package/dist/util/vscodeState.js +62 -13
  72. package/dist/util/vscodeState.js.map +1 -1
  73. package/package.json +1 -1
package/README.md CHANGED
@@ -63,7 +63,7 @@ closed first-party traffic was routed.
63
63
  | **OpenCode** | **Automatic** for direct API providers and its Copilot provider. | **Automatic** for those routed lanes. | Restart OpenCode afterward. Built-in ChatGPT OAuth exposes no endpoint override; use Codex for that seat. |
64
64
  | **VS Code Copilot Chat** | **Automatic** on VS Code 1.121+ — Connect installs and configures an explicit Anyray chat provider through VS Code's supported language-model-provider API. | **Automatic** for gateway API-key mode. Copilot-seat/native automatic reporting requires Copilot Business or Enterprise plus the official GitHub connector; the current Anyray connector does not cover Individual plans. | The developer selects an “Anyray · …” chat model. Native Copilot Chat and inline completions remain GitHub traffic. VS Code profiles scope extensions: Connect installs into every profile registered at apply time (config is shared); a profile created later needs a re-run or the official **Apply Extension to all Profiles** action. |
65
65
  | **JetBrains AI Assistant** | **Automatic** on IDE 2025.3.2+ with enabled JetBrains AI 253.30387.147+ — registers pinned Claude and Codex ACP launchers in `~/.jetbrains/acp.json`. | **Automatic** on those ACP carriers; native Copilot reporting requires Copilot Business or Enterprise plus the official GitHub connector. | Connect proves both versions from local JetBrains metadata before writing. Native JetBrains AI and Copilot traffic is untouched. A carrier may request its normal provider sign-in on first launch. |
66
- | **Claude Desktop** | **Automatic** on Windows and on macOS for verified Claude Desktop builds (a scheduled release probe extends the list per Desktop release). Both routing and the retrieval MCP server are applied through one adapter; other macOS builds use the in-app flow. | **Automatic** for routed third-party Gateway traffic, including the supported macOS subscription-helper lane. | On verified macOS builds, subscription selection uses the developer's Claude Code credential: the local helper reads it from the login Keychain on demand; setup never reads it, and the helper never persists or logs it. Windows remains API-billed and fails closed when subscription is selected. The first-party Desktop lane stays direct. Desktop has no supported pre-transcript tool-result replacement hook, so source-side trim is unavailable. Machine-level Windows policy takes priority. |
66
+ | **Claude Desktop** | **Automatic** on Windows and on macOS builds whose config seam Connect verifies locally at apply time (version floor + app-bundle byte-check, so a routine Desktop update stays automatic). Both routing and the retrieval MCP server are applied through one adapter; unverifiable macOS builds use the in-app flow. | **Automatic** for routed third-party Gateway traffic, including the supported macOS subscription-helper lane. | On verified macOS builds, subscription selection uses the developer's Claude Code credential: the local helper reads it from the login Keychain on demand; setup never reads it, and the helper never persists or logs it. Windows remains API-billed and fails closed when subscription is selected. The first-party Desktop lane stays direct. Desktop has no supported pre-transcript tool-result replacement hook, so source-side trim is unavailable. Machine-level Windows policy takes priority. |
67
67
  | **Devin Desktop** | **Automatic registry write only** for pinned Claude and Codex ACP agents; route activation is not automatic. | **Automatic** once requests use those carriers; the official enterprise consumption connector covers native Devin usage. | Devin requires its documented one-time vendor UI agent-enable action and an app restart. Native Devin traffic is not redirected. |
68
68
  | **Shell / SDK env** | **Automatic** — writes a managed, idempotent shell-profile block. | **Automatic** on the gateway request path. | Subscription seats are not applicable to generic SDK traffic. |
69
69
 
@@ -82,9 +82,10 @@ distinguished automatically; a scheduled repo probe (`connect/scripts/probe-curs
82
82
  checks each latest Cursor build still ships the managed cell names, and the UI remains the fallback
83
83
  when the override disappears.
84
84
  Claude Desktop similarly publishes its third-party inference UI, not a managed contract for the
85
- local config-library files. The macOS write is limited to builds verified by a scheduled
86
- per-release probe, is journaled, and fails closed to the supported UI on every other or
87
- unverifiable version.
85
+ local config-library files. The macOS write is gated by a local seam check — the installed app
86
+ bundle must still ship the known config-library shape (a scheduled probe also watches new
87
+ releases for drift) — is journaled, and fails closed to the supported UI on every unverifiable
88
+ version.
88
89
  On Windows, Connect writes Claude's per-user policy and installs a key-free credential helper.
89
90
  Restart Claude after first setup. Later enrolled-key renewals need no policy update or restart.
90
91
  That Windows helper resolves only the personal Anyray gateway key; Windows has no supported
@@ -4,9 +4,9 @@
4
4
  * source so both npm/npx runtimes and Bun's single-file executable carry the
5
5
  * same installable extension without a Marketplace dependency.
6
6
  */
7
- export const BUNDLED_VSCODE_EXTENSION_VERSION = "0.1.14";
8
- export const BUNDLED_VSCODE_EXTENSION_SOURCE_SHA256 = "e071cfb1406ac5a6eca7cea3edef94f2d270a89f720e8a525bc8642eff5e0b51";
7
+ export const BUNDLED_VSCODE_EXTENSION_VERSION = "0.1.15";
8
+ export const BUNDLED_VSCODE_EXTENSION_SOURCE_SHA256 = "b113ea0cb02542cf383077de7b6ad69b0ebbaff0ab7e28f82d2efa3b3ab4fb1b";
9
9
  export const BUNDLED_VSCODE_EXTENSION_DIST_SHA256 = "95eefccd0762153769ad73b23e28924dc866d1d84c057832968e7b96fc9b8112";
10
- export const BUNDLED_VSCODE_EXTENSION_SHA256 = "82ca213b3da54a0f6e168e65887b978a4d3e122a3fb3ebe486f64d9d79ce5f6f";
11
- export const BUNDLED_VSCODE_EXTENSION_BASE64 = "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";
10
+ export const BUNDLED_VSCODE_EXTENSION_SHA256 = "af7bde1fff8e6ad4cb390d6db27ff3799cae5aea7491bde714e41d31c4644a1a";
11
+ export const BUNDLED_VSCODE_EXTENSION_BASE64 = "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";
12
12
  //# sourceMappingURL=vscodeExtensionAsset.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vscodeExtensionAsset.js","sourceRoot":"","sources":["../../src/assets/vscodeExtensionAsset.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,QAAQ,CAAC;AACzD,MAAM,CAAC,MAAM,sCAAsC,GACjD,kEAAkE,CAAC;AACrE,MAAM,CAAC,MAAM,oCAAoC,GAC/C,kEAAkE,CAAC;AACrE,MAAM,CAAC,MAAM,+BAA+B,GAC1C,kEAAkE,CAAC;AACrE,MAAM,CAAC,MAAM,+BAA+B,GAC1C,8vmBAA8vmB,CAAC"}
1
+ {"version":3,"file":"vscodeExtensionAsset.js","sourceRoot":"","sources":["../../src/assets/vscodeExtensionAsset.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,QAAQ,CAAC;AACzD,MAAM,CAAC,MAAM,sCAAsC,GACjD,kEAAkE,CAAC;AACrE,MAAM,CAAC,MAAM,oCAAoC,GAC/C,kEAAkE,CAAC;AACrE,MAAM,CAAC,MAAM,+BAA+B,GAC1C,kEAAkE,CAAC;AACrE,MAAM,CAAC,MAAM,+BAA+B,GAC1C,8wmBAA8wmB,CAAC"}
package/dist/cli.js CHANGED
@@ -11,8 +11,10 @@
11
11
  */
12
12
  import { isPersonalClientKey, isInsecureRemoteOrigin, normalizeOrigin, resolveOrigin, resolveTarget, withLocalProxy, } from "./target.js";
13
13
  import { pickFallbackPort, installProxyService, uninstallProxyService, probeHealth, } from "./util/proxyService.js";
14
+ import { installRefreshScheduler, uninstallRefreshScheduler, } from "./util/refreshScheduler.js";
14
15
  import { clearBundle, clearQueue } from "./util/fallbackStore.js";
15
16
  import { runFallbackProxy } from "./commands/fallbackProxy.js";
17
+ import { loopbackEngaged } from "./util/loopback.js";
16
18
  import { runCursorWatch } from "./commands/cursorWatch.js";
17
19
  import { runManaged } from "./commands/managed.js";
18
20
  import { runPrintKey } from "./commands/printKey.js";
@@ -165,6 +167,11 @@ ${bold("Options")}
165
167
  when the gateway is back. Off by default; a plain apply
166
168
  points tools straight at the gateway and removes the proxy
167
169
  if an earlier run installed it.
170
+ --no-key-refresh Turn OFF the default-on seamless key refresh for
171
+ subscription Claude Code + Codex. Normally a small loopback
172
+ daemon fills a freshly re-minted key on each request so a
173
+ long session never 401s on an expired key mid-flight; this
174
+ forces the legacy lane that bakes the key once at launch.
168
175
  --revert Undo a previous run: unpick every tool config we wrote and
169
176
  clear the stored enrollment. Reconnecting needs --sso (or a
170
177
  fresh --enroll link). Cannot be combined with --sso or
@@ -276,6 +283,9 @@ export const parseArgs = (argv) => {
276
283
  case "--no-fallback":
277
284
  args.noFallback = true;
278
285
  break;
286
+ case "--no-key-refresh":
287
+ args.noKeyRefresh = true;
288
+ break;
279
289
  case "--revert":
280
290
  args.revert = true;
281
291
  break;
@@ -430,7 +440,14 @@ export const persistApplyProfile = async (previous, next, enrolledPrivateKeyPem,
430
440
  throw error;
431
441
  }
432
442
  };
433
- export const runApply = async (adapters, target, opts, revert) => {
443
+ export const runApply = async (adapters, target, opts, revert,
444
+ /**
445
+ * Adapter ids the developer named themselves (`--tools`, or the wizard's
446
+ * checklist). Passed through as `ApplyOptions.explicit` so an adapter that
447
+ * changes where inference is billed can require consent. Omitted by the
448
+ * background lanes (refresh, drift repair), which carry none.
449
+ */
450
+ explicitIds) => {
434
451
  let changes = 0;
435
452
  const manual = [];
436
453
  const results = [];
@@ -444,7 +461,10 @@ export const runApply = async (adapters, target, opts, revert) => {
444
461
  try {
445
462
  const result = revert
446
463
  ? await adapter.revert(opts)
447
- : await adapter.apply(target, opts);
464
+ : await adapter.apply(target, {
465
+ ...opts,
466
+ explicit: explicitIds?.has(adapter.id) === true,
467
+ });
448
468
  for (const m of result.messages)
449
469
  info(` ${m}`);
450
470
  // Partially automatic adapters can write config and still return `manual`
@@ -458,6 +478,12 @@ export const runApply = async (adapters, target, opts, revert) => {
458
478
  manual.push(adapter.title);
459
479
  warn(" manual step required (see above)");
460
480
  }
481
+ else if (result.status === "held") {
482
+ // Deliberately not routed, and nothing for the developer to do — must
483
+ // stay out of `manual`, which drives the "Action required" heading and
484
+ // its acknowledgement prompt.
485
+ note(" left on its own plan (no change)");
486
+ }
461
487
  else {
462
488
  note(` ${result.status}`);
463
489
  }
@@ -483,9 +509,19 @@ export const manualStepsNotice = (titles) => {
483
509
  return [
484
510
  `${which} a remaining app action — Connect may already have written its automatic config.`,
485
511
  `Review and complete the steps shown above for: ${titles.join(", ")}.`,
486
- "Then restart or reload the app as instructed; use `anyray-connect status` for the available route checks.",
512
+ "Then restart or reload the app as instructed; use `npx anyray-connect status` for the available route checks.",
487
513
  ];
488
514
  };
515
+ /**
516
+ * May the wizard put this tool in its prefilled selection?
517
+ *
518
+ * Everything except the tools that move where inference is billed. Enter is the
519
+ * path of least resistance, and `prompt` returns the default on a blank line —
520
+ * so anything prefilled here is something a developer configures by not
521
+ * answering. That is fine for a route change and wrong for a billing change,
522
+ * which the adapter must be named to get (see `ToolAdapter.changesBilling`).
523
+ */
524
+ export const wizardSuggests = (adapter) => adapter.changesBilling !== true;
489
525
  /**
490
526
  * Interactive wizard — guided first-run setup on a TTY. Detects installed
491
527
  * tools, lets the dev pick which to configure, confirms the gateway URL, name,
@@ -502,18 +538,25 @@ const runWizard = async (args, profile) => {
502
538
  // Tool selection: show what's installed, let the dev narrow it down.
503
539
  if (!args.tools || args.tools.length === 0) {
504
540
  heading("Tools detected");
505
- const installed = [];
541
+ // Billing-switching tools are listed with their consequence but kept OUT of
542
+ // the prefilled default: pressing Enter accepts a suggestion, which is not
543
+ // a decision about where someone's inference is billed. Naming one is.
544
+ const suggested = [];
506
545
  for (const adapter of REGISTRY) {
507
546
  const detected = await adapter.detect();
508
- if (detected.installed) {
509
- installed.push(adapter.id);
547
+ if (!detected.installed) {
548
+ note(` ${adapter.title} — not installed`);
549
+ continue;
550
+ }
551
+ if (wizardSuggests(adapter)) {
552
+ suggested.push(adapter.id);
510
553
  ok(` ${adapter.title} ${dim(`(${adapter.id})`)}`);
511
554
  }
512
555
  else {
513
- note(` ${adapter.title} — not installed`);
556
+ note(` ${adapter.title} ${dim(`(${adapter.id})`)} routing this moves its spend off your subscription onto the org API bill; add it by name to opt in`);
514
557
  }
515
558
  }
516
- const pick = await prompt("? Tools to configure (comma-separated, blank = all detected)", installed.join(",") || undefined);
559
+ const pick = await prompt("? Tools to configure (comma-separated, blank = all suggested)", suggested.join(",") || undefined);
517
560
  const chosen = (pick ?? "")
518
561
  .split(",")
519
562
  .map((s) => s.trim())
@@ -581,33 +624,116 @@ const runVerify = async (target, toolIds) => {
581
624
  info(dim(` ${line}`));
582
625
  };
583
626
  /**
584
- * Bring up the local fallback proxy and return the target the tools should point
585
- * at the local daemon when it comes up healthy, else the direct gateway (with
586
- * a warning). The caller commits gateway/clientKey/port to `~/.anyray` before
587
- * invoking this function, so the daemon can read a complete enrollment profile
588
- * as soon as it starts. Best-effort: a setup failure never aborts the apply
589
- * (tools still work while the gateway is up).
627
+ * Install + health-check the loopback daemon, then return the target the tools
628
+ * should be pointed at. On health-check success the tools point at the loopback
629
+ * (`viaLocalProxy`); if it never binds we **degrade to the direct gateway
630
+ * target** so the worst case is exactly today's static-key lane — pointing tools
631
+ * at a dead 127.0.0.1 port is never an option. Shared by both modes: the daemon
632
+ * itself picks refresh-only vs fallback from the persisted profile, so this only
633
+ * varies the user-facing copy.
590
634
  */
591
- const setupFallbackProxy = async (target, port) => {
592
- heading("Local fallback proxy");
593
- const svc = await installProxyService();
635
+ export const setupLoopbackProxy = async (target, port, mode, deps = {}) => {
636
+ const install = deps.install ?? installProxyService;
637
+ const probe = deps.probe ?? probeHealth;
638
+ const pollDelayMs = deps.pollDelayMs ?? 300;
639
+ const isFallback = mode === "fallback";
640
+ heading(isFallback ? "Local fallback proxy" : "Seamless key refresh");
641
+ const svc = await install();
594
642
  for (const m of svc.messages)
595
643
  info(` ${m}`);
596
- // The service may take a moment to bind poll its health endpoint.
644
+ // A freshly-installed supervisor may take a moment to bind, so poll. But
645
+ // retries only make sense when the install SUCCEEDED — if it failed (no
646
+ // daemon supervisor on this OS, e.g. Windows Task Scheduler users, or a
647
+ // `systemctl enable` error), a single probe still catches a daemon a prior
648
+ // run left running, and otherwise we degrade immediately instead of blocking
649
+ // the apply ~3s on a port nothing will ever bind.
650
+ const attempts = svc.ok ? 10 : 1;
597
651
  let health = null;
598
- for (let i = 0; i < 10 && !health; i++) {
599
- health = await probeHealth(port);
600
- if (!health)
601
- await new Promise((r) => setTimeout(r, 300));
652
+ for (let i = 0; i < attempts && !health; i++) {
653
+ health = await probe(port);
654
+ if (!health && i < attempts - 1)
655
+ await new Promise((r) => setTimeout(r, pollDelayMs));
602
656
  }
603
657
  if (health) {
604
- ok(` Running on 127.0.0.1:${port} → ${target.origin} — tools fail over to the provider automatically.`);
658
+ ok(isFallback
659
+ ? ` Running on 127.0.0.1:${port} → ${target.origin} — tools fail over to the provider automatically.`
660
+ : ` Running on 127.0.0.1:${port} → ${target.origin} — your key refreshes automatically, no restart needed.`);
605
661
  return withLocalProxy(target, port);
606
662
  }
607
- warn(" Fallback proxy did not come up — pointing tools directly at the gateway for now.");
608
- info(dim(" It will retry on the next run; check the service logs if it persists."));
663
+ warn(` ${isFallback ? "Fallback proxy" : "Key-refresh proxy"} did not come up — pointing tools directly at the gateway for now.`);
664
+ info(dim(svc.ok
665
+ ? // Install succeeded but the port never bound — a transient miss the
666
+ // next run retries against the same supervisor.
667
+ " It will retry on the next run; check the service logs if it persists."
668
+ : // No supervised daemon on this platform (svc.messages said why).
669
+ // Refresh-only seats still get the scheduled ~30-min re-mint; the
670
+ // fallback lane has no non-daemon equivalent.
671
+ isFallback
672
+ ? " Local fallback isn't available on this platform."
673
+ : " Your key still refreshes on a schedule — no daemon needed here."));
609
674
  return target;
610
675
  };
676
+ /**
677
+ * Reconcile the per-user refresh scheduler with what this apply wants — the
678
+ * universal ~30-min re-mint that keeps EVERY tool's short-TTL key fresh, not
679
+ * just the CC/Codex traffic behind the loopback daemon.
680
+ *
681
+ * - `want` → (re)install it. Installed even alongside the daemon
682
+ * (belt-and-suspenders — it rescues the seat if the daemon dies), but only
683
+ * ANNOUNCED when it's the seat's PRIMARY refresh (`announcePrimary`, i.e. no
684
+ * daemon), so the daemon path's own output isn't echoed.
685
+ * - `!want && !scopedRevert && wasEnabled` → tear down a scheduler a prior run
686
+ * installed and clear the persisted flag. A SCOPED revert (`--tools x
687
+ * --revert`) leaves it: the tools it did not name still depend on the refresh.
688
+ *
689
+ * Runs AFTER the adapters settled the tool config + profile, so a launchd
690
+ * `RunAtLoad` / Task Scheduler `/Run` fired at install time sees consistent
691
+ * state. Best-effort: a scheduling failure only costs the user a manual re-run,
692
+ * so it never aborts the apply. Deps are injectable so the wiring is testable
693
+ * without standing up real launchd/systemd/Task Scheduler units.
694
+ */
695
+ export const reconcileRefreshScheduler = async (opts, deps = {}) => {
696
+ if (opts.dryRun)
697
+ return;
698
+ const install = deps.install ?? installRefreshScheduler;
699
+ const uninstall = deps.uninstall ?? uninstallRefreshScheduler;
700
+ if (opts.want) {
701
+ const svc = await install();
702
+ if (opts.announcePrimary) {
703
+ heading("Automatic key refresh");
704
+ for (const m of svc.messages)
705
+ info(` ${m}`);
706
+ if (svc.ok)
707
+ ok(" Your gateway key now re-mints every ~30 min — no tool will 401 on a stale key mid-session.");
708
+ }
709
+ // The flag was persisted `true` optimistically before this reconcile ran.
710
+ // If the OS refused the unit (no supervisor here, a launchd/systemctl
711
+ // error), correct it to false so `doctor` doesn't forever report an
712
+ // enabled-but-not-installed scheduler. Re-read so we don't clobber fields
713
+ // the adapters just wrote.
714
+ if (!svc.ok) {
715
+ await saveProfile({
716
+ ...(await loadProfile()),
717
+ refreshSchedulerEnabled: false,
718
+ });
719
+ }
720
+ return;
721
+ }
722
+ if (!opts.scopedRevert && opts.wasEnabled) {
723
+ heading("Automatic key refresh");
724
+ const svc = await uninstall();
725
+ for (const m of svc.messages)
726
+ info(` ${m}`);
727
+ // Re-read: a full --revert already rewrote the profile on disk, so spreading
728
+ // the pre-run snapshot would resurrect stale fields. loadProfile() reflects
729
+ // what is actually persisted now.
730
+ await saveProfile({
731
+ ...(await loadProfile()),
732
+ refreshSchedulerEnabled: false,
733
+ });
734
+ ok(" Removed the automatic key-refresh schedule.");
735
+ }
736
+ };
611
737
  const SUBCOMMANDS = new Set(["login", "wizard", "status", "doctor", "sync"]);
612
738
  export const run = async (argv) => {
613
739
  // Hidden hook entrypoint: Claude Code invokes `anyray-connect __anyray-hook`
@@ -766,7 +892,7 @@ export const run = async (argv) => {
766
892
  }
767
893
  catch (error) {
768
894
  fail(error.message);
769
- info("\nRun `anyray-connect --help` for usage.");
895
+ info("\nRun `npx anyray-connect --help` for usage.");
770
896
  return 1;
771
897
  }
772
898
  if (parsed.help) {
@@ -796,7 +922,7 @@ const runApplyCommand = async (argv, forceWizard) => {
796
922
  }
797
923
  catch (error) {
798
924
  fail(error.message);
799
- info("\nRun `anyray-connect --help` for usage.");
925
+ info("\nRun `npx anyray-connect --help` for usage.");
800
926
  return 1;
801
927
  }
802
928
  if (args.help) {
@@ -1243,19 +1369,73 @@ const runApplyCommand = async (argv, forceWizard) => {
1243
1369
  return 1;
1244
1370
  }
1245
1371
  }
1246
- // Local fallback proxy: OFF by default — opt in with --fallback. The loopback
1247
- // daemon proved unreliable in the field (it could crash mid-session and strand
1248
- // tools on a dead 127.0.0.1 port), so a plain apply now routes tools straight
1249
- // at the gateway. --no-fallback stays accepted and always wins, so scripts
1250
- // that pass it keep working. A machine an earlier release auto-installed the
1251
- // proxy on gets it torn down below.
1372
+ // Local fallback proxy: OFF by default — opt in with --fallback. The provider-
1373
+ // direct fallback leg proved unreliable in the field (the fat daemon could
1374
+ // crash mid-session and strand tools on a dead 127.0.0.1 port), so a plain
1375
+ // apply never enables it. --no-fallback stays accepted and always wins, so
1376
+ // scripts that pass it keep working.
1252
1377
  const wantFallback = !args.revert && args.fallback === true && args.noFallback !== true;
1378
+ // Seamless key refresh: ON by default for subscription/passthrough Claude Code
1379
+ // + Codex — the only tools whose traffic actually traverses the loopback (see
1380
+ // the daemon's ProxyMode). They bake a short-TTL client key as a STATIC header
1381
+ // read once at launch, so without the daemon a long session 401s the moment
1382
+ // the key lapses mid-flight, curable only by a re-run + a tool relaunch. Here
1383
+ // the daemon runs in the crash-minimal refresh-only mode (fallbackEnabled is
1384
+ // false) — that tiny surface is what lets it default on where the full
1385
+ // fallback leg cannot. --no-key-refresh forces the legacy direct static-key
1386
+ // lane. Other tools (native Cursor, the Copilot extension, ACP launchers)
1387
+ // rebuild their own target and bypass the loopback, so they are unaffected
1388
+ // either way — see the scope boundary in commands/fallbackProxy.ts.
1389
+ const keyRefreshSeatSelected = (adapters.some((a) => a.id === "claude-code") &&
1390
+ effectiveSubscription(target, "anthropic")) ||
1391
+ (adapters.some((a) => a.id === "codex") &&
1392
+ effectiveSubscription(target, "openai"));
1393
+ const wantKeyRefresh = !args.revert && args.noKeyRefresh !== true && keyRefreshSeatSelected;
1394
+ // Either flag engages the loopback daemon; --fallback additionally turns it
1395
+ // into the provider-direct fallback (the daemon derives its mode from
1396
+ // fallbackEnabled at boot, so fallback wins when both are set).
1397
+ const wantLoopback = wantFallback || wantKeyRefresh;
1398
+ // A scoped apply (`--tools x`) that doesn't itself engage the loopback must
1399
+ // not tear down the DEFAULT-ON key-refresh lane the tools it did NOT name
1400
+ // still depend on — the apply-side mirror of the scoped-revert credential rule
1401
+ // below. Without this, `anyray-connect --tools cursor` after a full connect
1402
+ // would uninstall the refresh daemon and drop Claude Code / Codex back to the
1403
+ // 401-prone static-key lane. Scope is deliberately the refresh-only lane only:
1404
+ // the opt-in --fallback machinery is NOT preserved here, so the upgrade
1405
+ // cleanup that disables a proxy an earlier release auto-enabled still runs
1406
+ // (re-opt-in with --fallback). An explicit --no-key-refresh still wins, and a
1407
+ // full, unscoped apply falls through to the normal want-driven teardown below.
1408
+ const scopedApply = !args.revert && (args.tools?.length ?? 0) > 0;
1409
+ const preserveKeyRefresh = scopedApply &&
1410
+ args.noKeyRefresh !== true &&
1411
+ Boolean(profile.keyRefreshEnabled);
1412
+ const preserveLoopback = preserveKeyRefresh;
1413
+ // The refresh SCHEDULER is the universal trigger: a per-user launchd/systemd/
1414
+ // Task Scheduler task that runs `__anyray-refresh` every ~30 min to re-mint
1415
+ // the short-TTL ark_ key for EVERY configured tool. The loopback daemon above
1416
+ // only covers
1417
+ // CC/Codex (their traffic traverses it); Cursor/Copilot/Claude-Desktop/
1418
+ // shell-env read a static key from their own config with no daemon or hook to
1419
+ // renew it, so they 401 mid-session when it lapses — the exact bug this fixes.
1420
+ // Installed for every ENROLLED seat (an env-key seat has no cert to refresh),
1421
+ // gated by the same --no-key-refresh opt-out the daemon lane uses. It coexists
1422
+ // with the daemon: the shared refresh-state throttle stops the two triggers
1423
+ // double-minting, and if the daemon is ever down the scheduler's refresh
1424
+ // degrades those seats' tools to gateway-direct with a fresh key.
1425
+ const usingEnvironmentKey = Boolean(envClientKey && target.clientKey === envClientKey && !enrolledCert);
1426
+ const hasRefreshableCert = !usingEnvironmentKey && Boolean(enrolledCert ?? profile.enrolledCert);
1427
+ const wantRefreshScheduler = !args.revert && args.noKeyRefresh !== true && hasRefreshableCert;
1253
1428
  let applyTarget = target;
1254
1429
  const resolvedFallbackEnabled = wantFallback;
1255
- // Only hold a port when the proxy is wanted; otherwise clear it so the
1256
- // persisted profile and the teardown below agree the proxy is gone.
1257
- let resolvedFallbackPort = wantFallback ? profile.fallbackPort : undefined;
1258
- if (wantFallback && !args.dryRun) {
1430
+ const resolvedKeyRefreshEnabled = wantKeyRefresh || preserveKeyRefresh;
1431
+ const loopbackMode = resolvedFallbackEnabled
1432
+ ? "fallback"
1433
+ : "refresh-only";
1434
+ // Hold the port when the loopback is wanted now, or preserved for the tools
1435
+ // this scoped apply didn't name; otherwise clear it so the persisted profile
1436
+ // and the teardown below agree the daemon is gone.
1437
+ let resolvedFallbackPort = wantLoopback || preserveLoopback ? profile.fallbackPort : undefined;
1438
+ if (wantLoopback && !args.dryRun) {
1259
1439
  resolvedFallbackPort = profile.fallbackPort ?? (await pickFallbackPort());
1260
1440
  }
1261
1441
  // ACP agents and Claude Desktop's credential helper intentionally persist no
@@ -1265,10 +1445,10 @@ const runApplyCommand = async (argv, forceWizard) => {
1265
1445
  // while no tool configuration has changed yet.
1266
1446
  if (!args.revert && !args.dryRun) {
1267
1447
  // An explicit pre-minted environment key is a complete, non-refreshable
1268
- // credential source. Never retain a possibly unrelated enrollment cert or
1269
- // expiry beside it: a later helper refresh could otherwise replace the
1270
- // operator-supplied identity with the old certificate's identity.
1271
- const usingEnvironmentKey = Boolean(envClientKey && target.clientKey === envClientKey && !enrolledCert);
1448
+ // credential source (see `usingEnvironmentKey` above). Never retain a
1449
+ // possibly unrelated enrollment cert or expiry beside it: a later helper
1450
+ // refresh could otherwise replace the operator-supplied identity with the
1451
+ // old certificate's identity.
1272
1452
  const nextProfile = {
1273
1453
  ...profile,
1274
1454
  gateway: target.origin,
@@ -1300,6 +1480,8 @@ const runApplyCommand = async (argv, forceWizard) => {
1300
1480
  authMode: target.authMode,
1301
1481
  byoUpstream: target.byoUpstream,
1302
1482
  fallbackEnabled: resolvedFallbackEnabled,
1483
+ keyRefreshEnabled: resolvedKeyRefreshEnabled,
1484
+ refreshSchedulerEnabled: wantRefreshScheduler,
1303
1485
  fallbackPort: resolvedFallbackPort,
1304
1486
  };
1305
1487
  try {
@@ -1310,8 +1492,8 @@ const runApplyCommand = async (argv, forceWizard) => {
1310
1492
  return 1;
1311
1493
  }
1312
1494
  }
1313
- if (wantFallback && !args.dryRun) {
1314
- applyTarget = await setupFallbackProxy(target, resolvedFallbackPort);
1495
+ if (wantLoopback && !args.dryRun) {
1496
+ applyTarget = await setupLoopbackProxy(target, resolvedFallbackPort, loopbackMode);
1315
1497
  }
1316
1498
  // Drop the enrollment credential FIRST, before a single config is unpicked —
1317
1499
  // see util/persist `clearEnrollment` for why a revert that leaves it behind
@@ -1356,7 +1538,9 @@ const runApplyCommand = async (argv, forceWizard) => {
1356
1538
  note("\nKeeping the stored enrollment — the tools you did not name still need it.");
1357
1539
  note("Run --revert with no --tools to remove it.");
1358
1540
  }
1359
- const { changes, manual, results } = await runApply(adapters, applyTarget, opts, args.revert);
1541
+ // A named `--tools` list (the wizard writes its checklist here too) is the
1542
+ // developer choosing these adapters by hand; the default sweep names none.
1543
+ const { changes, manual, results } = await runApply(adapters, applyTarget, opts, args.revert, new Set(args.tools ?? []));
1360
1544
  // Keep the managed-tool record in step: apply records landed tools, revert
1361
1545
  // removes them, a full revert clears the record. Drift repair (`doctor
1362
1546
  // --repair`, the detached refresh) only ever re-applies recorded ids, so
@@ -1364,15 +1548,16 @@ const runApplyCommand = async (argv, forceWizard) => {
1364
1548
  if (!args.dryRun) {
1365
1549
  await recordManagedTools(results, args.revert, fullRevert).catch(() => undefined);
1366
1550
  }
1367
- // Tear down the fallback daemon + its at-rest state whenever it is not wanted
1368
- // but a previous run left it installed — covers both an explicit --revert and
1369
- // a plain apply now that the proxy is off by default (an earlier release
1370
- // auto-installed it). Runs AFTER the adapters above re-pointed tools straight
1371
- // at the gateway, so uninstalling the loopback service strands nothing.
1372
- if (!wantFallback &&
1551
+ // Tear down the loopback daemon + its at-rest state whenever NEITHER layer is
1552
+ // wanted but a previous run left it installed — covers an explicit --revert,
1553
+ // --no-key-refresh, or a subscription→api-key switch that no longer needs the
1554
+ // refresh lane. Runs AFTER the adapters above re-pointed tools straight at the
1555
+ // gateway, so uninstalling the loopback service strands nothing.
1556
+ if (!wantLoopback &&
1557
+ !preserveLoopback &&
1373
1558
  !args.dryRun &&
1374
- (profile.fallbackEnabled || profile.fallbackPort)) {
1375
- heading("Local fallback proxy");
1559
+ (loopbackEngaged(profile) || profile.fallbackPort)) {
1560
+ heading("Local loopback proxy");
1376
1561
  const svc = await uninstallProxyService(profile.fallbackPort);
1377
1562
  for (const m of svc.messages)
1378
1563
  info(` ${m}`);
@@ -1384,10 +1569,24 @@ const runApplyCommand = async (argv, forceWizard) => {
1384
1569
  await saveProfile({
1385
1570
  ...(await loadProfile()),
1386
1571
  fallbackEnabled: false,
1572
+ keyRefreshEnabled: false,
1387
1573
  fallbackPort: undefined,
1388
1574
  });
1389
- ok(" Removed the local fallback proxy.");
1390
- }
1575
+ ok(" Removed the local loopback proxy.");
1576
+ }
1577
+ // Reconcile the universal refresh scheduler: (re)install it for an enrolled
1578
+ // seat, or tear down one a prior run left when the seat no longer wants it (a
1579
+ // full revert dropped the enrollment, or --no-key-refresh opted out). A SCOPED
1580
+ // revert (`--tools x --revert`) leaves it — the tools it did not name still
1581
+ // depend on the refresh. Independent of the daemon teardown above: a
1582
+ // Cursor-only seat has the scheduler but never had a daemon.
1583
+ await reconcileRefreshScheduler({
1584
+ want: wantRefreshScheduler,
1585
+ announcePrimary: !wantLoopback,
1586
+ scopedRevert: Boolean(args.revert) && !fullRevert,
1587
+ dryRun: Boolean(args.dryRun),
1588
+ wasEnabled: Boolean(profile.refreshSchedulerEnabled),
1589
+ });
1391
1590
  heading("Summary");
1392
1591
  if (args.dryRun) {
1393
1592
  note("Dry run complete — re-run without --dry-run to apply.");