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.
- package/README.md +5 -4
- package/dist/assets/vscodeExtensionAsset.js +4 -4
- package/dist/assets/vscodeExtensionAsset.js.map +1 -1
- package/dist/cli.js +253 -54
- package/dist/cli.js.map +1 -1
- package/dist/commands/desktop.js +2 -2
- package/dist/commands/desktop.js.map +1 -1
- package/dist/commands/doctor.js +74 -19
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/fallbackProxy.js +60 -15
- package/dist/commands/fallbackProxy.js.map +1 -1
- package/dist/commands/hook.js +19 -0
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/managed.js +54 -9
- package/dist/commands/managed.js.map +1 -1
- package/dist/commands/mcpServer.js +131 -5
- package/dist/commands/mcpServer.js.map +1 -1
- package/dist/commands/shared.js +7 -5
- package/dist/commands/shared.js.map +1 -1
- package/dist/commands/status.js +20 -10
- package/dist/commands/status.js.map +1 -1
- package/dist/tools/claudeCodeHooks.js +21 -12
- package/dist/tools/claudeCodeHooks.js.map +1 -1
- package/dist/tools/claudeDesktop.js +70 -37
- package/dist/tools/claudeDesktop.js.map +1 -1
- package/dist/tools/claudeDesktopNative.js +14 -0
- package/dist/tools/claudeDesktopNative.js.map +1 -1
- package/dist/tools/copilotChat.js +113 -49
- package/dist/tools/copilotChat.js.map +1 -1
- package/dist/tools/copilotCli.js +436 -0
- package/dist/tools/copilotCli.js.map +1 -0
- package/dist/tools/cursor.js +23 -4
- package/dist/tools/cursor.js.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/jetbrainsCapability.js +2 -18
- package/dist/tools/jetbrainsCapability.js.map +1 -1
- package/dist/tools/sharedHooks.js +8 -3
- package/dist/tools/sharedHooks.js.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util/cliInvocation.js +33 -0
- package/dist/util/cliInvocation.js.map +1 -0
- package/dist/util/connectHealth.js +44 -7
- package/dist/util/connectHealth.js.map +1 -1
- package/dist/util/connectHealthReport.js +14 -0
- package/dist/util/connectHealthReport.js.map +1 -1
- package/dist/util/devRefresh.js +27 -12
- package/dist/util/devRefresh.js.map +1 -1
- package/dist/util/devVerify.js +34 -1
- package/dist/util/devVerify.js.map +1 -1
- package/dist/util/localRead.js +95 -0
- package/dist/util/localRead.js.map +1 -0
- package/dist/util/localSearch.js +274 -0
- package/dist/util/localSearch.js.map +1 -0
- package/dist/util/loopback.js +25 -0
- package/dist/util/loopback.js.map +1 -0
- package/dist/util/persist.js +5 -3
- package/dist/util/persist.js.map +1 -1
- package/dist/util/profile.js +67 -12
- package/dist/util/profile.js.map +1 -1
- package/dist/util/profileTarget.js +24 -2
- package/dist/util/profileTarget.js.map +1 -1
- package/dist/util/proxyService.js +3 -12
- package/dist/util/proxyService.js.map +1 -1
- package/dist/util/refreshScheduler.js +307 -0
- package/dist/util/refreshScheduler.js.map +1 -0
- package/dist/util/seatState.js +22 -2
- package/dist/util/seatState.js.map +1 -1
- package/dist/util/versions.js +24 -0
- package/dist/util/versions.js.map +1 -0
- package/dist/util/vscodeState.js +62 -13
- package/dist/util/vscodeState.js.map +1 -1
- 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
|
|
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
|
|
86
|
-
|
|
87
|
-
unverifiable
|
|
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.
|
|
8
|
-
export const BUNDLED_VSCODE_EXTENSION_SOURCE_SHA256 = "
|
|
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 = "
|
|
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 = "UEsDBBQAAAgIAJSA+Fz3AtGOCQMAALQJAAAWAAAAZXh0ZW5zaW9uLnZzaXhtYW5pZmVzdL1W224bNxB9tr+CYIA+RUvLQIDCXW0gKHYiVApUyPVjgBE5Wk1NkQSHK0v9+mJ3dbOStpEd5G2XM3MO58JD5u/XSytWGJm868ludiUFOu0NubInqzTv/CrfF5cX+QT0I5Q4Bkdz5CQediHX2VUdtF5axz25SCncKMV6gUvgbEk6evbzlGm/VAZXaH3AqFa87rQ+6vqq292G35gXAHQMMpWuxSkuLy7yMSYwkKD+uciHBl2itBEjcGUFJfYkus6fUymGpifBbSJsOivW3qA8ZHWVdbPuOykm1cwSLzDuXKVQLe4H4mBh8xmWWPQbk5j7KB6mYuAN5urY3gYg60ghkXd1ujccQGNPhoiMcYWy6BsjcB0saUpiC1lCwifYiKU3aFn4uDV0niKEgEYMfCDrk+BqdoDfeqdF9FW52O3pFwief2Ph53PSBFbYbUU6jb8I0a/IYBT9yTDL1dF+2wTuoeTieQznqllt7ANIWPpIyEV/+HYMekEOxQghOnJlro7sjf9HsBbj5s7WCE2hda6eLdZujesk1l1Pu9D9wqZp4ng/JA/EFdhpqgz5rM45u3UlubqzYCvsyS/drHv9rh5YdTbSOqGrp+MDBnQGnSbkPfBrAOuz9UOAfidn9kAVvX3y8bEZsxeAjrwGS3+j2Z2b1+XqYGbR9APVIZ7BfgPu7LRRVwl50B7dFizFCl8AOMW4Io2cjcg9cjb1VdQH0FqU+EapktKimjVS1KrBpz/U0jsfMfispHReYU44P2LiBDGh+cm8lD5Vs5/LOa1C8DGdRaqIuaqn8BW8jRidxfomIpjlyUi9gL+t8p2FlY9oxhAfjX9y3x7b85AH3iV0KZtE0uTKPeRdRJSquHy+7VydaGk+Io2OscCdiqjRcHD7eXqbpXXK1c681eJcHV+v+dBxAmvhcEscr9xDLDH930GWTdq5OsXKj4W29ekzY9ruu/kW95uA/y0TuyeLFBNIi5485BnaN032F3snRd+YiMy1Tj3vx/cwfdWNbdm+Jj0q7r9z5mqfaa5Onl7FP1BLAwQUAAAICACUgPhc36MN37wAAABlAQAAEwAAAFtDb250ZW50X1R5cGVzXS54bWx90DFuwzAMBdA9pxC4x3Q7FEFhO0PaG/QChEI7SiVKMBlDvX3hZAvqzvzvf4DdsaboFp41ZOnhpWnBsfh8DjL1cLNxf4DjsOu+fgqrqymK9nAxK++I6i+cSJtcWGqKY54TmTZ5nrCQ/6aJ8bVt39BnMRbb29oBQ/fBI92iuc9qLI/d5qrgTo/cOtUDlRKDJwtZ8EoLqZ9DMcAtnuW/gvW8Qa3akzSuhiVS2DSLhppIwsj6J64prhTvXxt2v1BLAwQUAAgICABLgPhcAAAAAAAAAAAAAAAAFgAAAGV4dGVuc2lvbi9wYWNrYWdlLmpzb251VNtu2zAMfc9XEH4ZsNVyk6675GlF12HF1qFDd3lYO0CRWJurIwkSnSYo8u+DZDlOh+7JNs8heXjzwwSgMHKJxRwKaTZebspVUFZjcRAhTcG1cvMlM04SA26thx9XcDrSMChPjsmaRNMacO1aUsSQfWrJeC83sLQa2wDWZ6C899I51HBqHbWWIXSLXbCBzY23Xd0MSZ8FsLe3pEi20EpTd7LGMlHBebsijR5OLs9FL26FPmRhh2Iqpse92XlaSY5lse+wN3WLlkKDfuxGz21JoQmpBRfn33qbR2cDsfWbYg4PEwCAgjcukWriRAIoOt9my4uG2YV5VdXETbcQyi6rPsnHr9XSGhsjij1XTR5VTlD0UylxzWhSOROAbRKCpiaDYVSRBziH4vdUTGfH4nAkK8lYW0+J/6vnn5wPGS+kasggfEbpDZk6+t0kv6Wk1EFRaQpc7WSIP6Fvx87yiYweY3c0xL63/i44qXAMqqSTC2qJaV9+Z9h3gVH/HDxGEKAInXPWM+o8uWTf7gqUiuNcyZqzFRreK9OaK5aeO/eBTJyyHpRZ893Tnipr2NOi431Rw5pdxC07bSRf5kUbE8BOY1o6o+2/e5SxJ4+qyPg2PW929fS3sKdk0VEbay+M1QgY0rdY5jnELZbqTtY4XwVa581ByEYoS2NLjQ6NRqMIA5Sl7Rge3b5IrsPcJKvmqXxQlj12MC6/alDdRTIHlXKdLcd9Zgy8C1SWtIxzBA5rKMuIwXURvKria/VcxIfgcF0M7r22ufOY7/Q/opy3ulP86EY0rt7vFT12811UHSqTD2b2Kv4hhowZHO9pOKcB75FISPCReCtmA5hF9b+d2ZsxKoc0lpdidrRnjJnSqCP2WhyKWVI/2U7+AlBLBwhgSlWamQIAAKQFAABQSwMEFAAICAgA/H74XAAAAAAAAAAAAAAAABUAAABleHRlbnNpb24vTElDRU5TRS50eHRdUUFu2zAQvPMVg5xSQEiLHHrojZFoi6hMGhQd10daoiMWMmmIdAP/vqDsJE1PBHd3ZnZmV1yjcZ310RJShtNlci9Dwn33BY/fHr+D+stkLoSs7XR0Mbrg4SIGO9n9BS+T8cn2BQ6TtQgHdIOZXmyBFGD8BSc7xeAR9sk47/wLDLpwupBwQBpcRAyH9GomC+N7mBhD50yyPfrQnY/WJ5Oy3sGNNuI+DRZ37Q1x92UW6a0ZifPIvbcWXl0awjlhsjFNrsscBZzvxnOfd3hrj+7obgoZPvuOJAWcoy3mPQscQ+8O+bWzrdN5P7o4FOhdpt6fky0Qc3EOsMg+voYJ0Y4j6cLJ2YjZ68d280xe/ZQDTbeIYq68DuH42YmL5HCevIuDnTF9QAyz4m/bpVzJ44cwjuE1W+uC7112FH8QogcLsw9/7OzlelYfkuuucc8HOH1c9daKgxlH7O0tMNvDeZh/7ExZPibjkzMjTmGa9f63+UCIrhlaudBbqhh4i7WSz7xiFe5oC97eFdhyXcuNxpYqRYXeQS5AxQ4/uagKsF9rxdoWUhG+WjecVQW4KJtNxcUSTxsNITUavuKaVdASWfBGxVmbyVZMlTUVmj7xhutdQRZci8y5kAoUa6o0LzcNVVhv1Fq2DFRUEFJwsVBcLNmKCf0ALiAk2DMTGm1NmyZLEbrRtVR5P5RyvVN8WWvUsqmYavHE0HD61LCrlNihbChfFajoii7ZjJK6Zorkset22NYsl7IeFaCl5lJkG6UUWtFSF9BS6XfolresAFW8zYEslFwVJMcpF3mEi4wT7MqSo8ani0g1/zcteydExWjDxbLN4GzxbfiB/AVQSwcIsoZ6jXkCAAAnBAAAUEsDBBQACAgIAJSA+FwAAAAAAAAAAAAAAAAbAAAAZXh0ZW5zaW9uL2Rpc3QvZXh0ZW5zaW9uLmpzxX3tdtu2tuD/+xQSx0sD3ML0R9O0pQtrEidp08ZJTuykp3V0bJqEJNQUoJKQHVfis9x/c9/rPMmsjS+ClJSkPWdmVldqCgSBzQ1gf+/NaFGxXqVKnqno6DYtexNFX13/xjIVZyVLFdONj11bzsZcsNelnLNS3et7c//AhKlXd8LdfMKqrORzJUvd7X5Lt5fpjFW6xyzs8bqUSqr7OXs1JlN/Y+5a42laBYPo5+8URYwoTI+XY1kiaBI9LnoKP0aMCLKcMJWoCzEiTCxmrEyvC5b092tckznTjxJBJDzOx0gNBjCPHPcUpZHU00erVdA2XohMcSkiDLMVTPXKnhz37hVSGPenKs7SokCMlHgwKPuUisEA4CgNHAjTY3VRtmFBks4VUqTEeLWScXOrxkclU4tS9FhtsOkAxvQYCcr6VCyKYjhRaKYQwzhZwkshtVr1GfyLLy9ZdSrzRcGGj5EgUc7G6aJQEVnepsWCJayLlEQQhjF5pCijx3OGHqNlTaJmGP8kdCYMmyUQdFkf3Sl0J8gyzRS/TRXT7zoTJGetlqmo8dFMjxWzD3NZqoo+gifNUE/pPUMl+33BS4ai2yqTOYswJpmivlXInCVZeT9XMsJk0b0zrvbmpZzxilWRGfQdjVJxX6b38SRV7C69P5FizCfx7UFEFOve/IndmzNxqahgd70zptBFtKhYGZFIsXQWkYgLxYTyFy/Sa1ZEJKpYVcHeGGFyqjHIKKVRIbO0mMoKdpJuuEiSg1G0Wu394+DwazRM3sfv8+UB+bLGyy/rnb1YsQqWk/wIQ+htafYf69MIDq2YRNhsjCg6UuX9ErahAfbtmxeIxarkM4T97rEnKJNFn9JoqtQ8iQaD9dYqgb3um2nQuX+qkIrhJUQ6Yxi6AUbgh34krao7WebmWk2hHUbd0wNWLC2zKVxN02o6jKJExbLkEy7qLFXZdOlepq7JL/DOsHuDd/bn8FEJ68Qr/RcxPFzWiaUR41LOngpVclYh28TsT4bjMS8UKxG6UESMMD2+1KAghf15F9TjdjAQccHERE2P95vr7+jhVw8Hg/7exfvF/v7+/i78ORjD/78ej+yiCYzjWTpvJjJ/MZkyeC/3TuFce/9Iy5vLi0e7v6a7f+zvfnu5O1oe7pOvDg6DrTBkya3keW+fzLYOxAKgWQP0/v6ngA6Hf+a2XL+La7vjLkZHZrddjIhw5+PI0UIJtJDFVcEzhvbJwwcY68GkX0+5fT0lxpkUiosF03OUVBJOZwyVMc8xSc2l3n9Hfb5a9dPVSuh15Hi1QiJO8xxxTFQ8X1RTtOR5wgl0T9Ia49odhprcNXSflPQC1kkfIU5/hGOX0ilDCh8B4HYaCZs5k3NeSLVbsVRFg4FuszRjN53zCKtpKe96gJOnZSlLFHFxmxY879levUzTnUWZGg6i3zKnz1CpJ5O0M+BgkNt1pJTuf3r4mcxZsTaJfe8fz169jM1m4eN7tLxlJdCq5IDYx9+WRcJJQwSTlMyYSvNUpckvSGACwyfS9TiFyaokB0b6SG9KS4aWtadJFdWzztOyYogNh1GEjyp/5KqGxQ4Gnf1W4cGgii2MlNKDwQApWmFLMGoYXdAfkYob6DGReuUCQo5JSX9BKnYvggmnKoYX6eIaqJNrby300LS7A5JSPhy2exBYQj+rwYtD+zJArgiRKxvklgazaRezhFcndi1ZnoQ0CbaegWcw4ME1StfAX61y/yCujRjx/cc4JrlkXVY75UV+OS9lxiro8LpzHwh+hMm5F8Q0EvO0vOMiGkZ7L/h1mZb3e4/m84Jnelv2zhZz4P17jzTr3buWUlWqTOfxb5UUUaJHuOPiy8No+DrWF/Fvkguk4telnJTp7Emq0uEwOknevw9aIhKZESMSdcbECdonr/UoGEV7TGURsZx/Q2fyVP05OvvVweFgcBHHMRvF7JaV90jZEyGoirNpWp7InD1SaN+fSHFMvzwcDESf0oPDr2s8GCANIq8eXVeyWCiGEbBah4CmHcgxuVV07x+Wb4waNPSe8YJVqPceffjm4XuMh+/f73Fy4hdHBai9VY4DJP198krRtLoXmaGN9Pu4UqlygnHzlGUE/X1/zCVN71KuegIx/3IyXvAcyNZggKQ+QYODbzA0tHh+/6CuyYdgYvp9XLI0h5eAqd0Uwk6hECPRQo2/iTTJdMy7EYyAJdj1ebD/7UML7HJesooJlfQP6iMDckCZhCe/IE5/HqsCSf0WVq7pHleVXJPQ1mYuqYyvuTjq3t4n11wkTxUq8bC01KZu4Socqq7JtV9Sve2GF2yUXIxIHMfhEl+Mkgu7zXczKQS8zWhEzloPXyv9Q4sugh6j5ZgXLBEkLSfV65KN+QcYWfEZkwt1WiVvVY3xppnMg5GYf4haD0e7u/es8gfOQfK/ihT2XxSOfcrq0YjcqEbTAY732tAnJOnxEu2TS1AeWKZ3ie63tAMkgszSD48X4zErk4cP/vNg//ABueMil3fVDzzXegtBJeGO56e0tOs+3E/sSpZxpjlBJBaza1ZGQ9MwHB4k0PFIoiX7wNWJodqVymFiPoyVPNNrjzCwuhrDf+SNCnijE83jal5wha7+4wrHczk3Dxw1mz3YnEYQEd3NKZrNaXea3ddCH9tFpbc0iChCyrkTV5goZVGw3P2+LmR2w/LWECXlHjfigo+8FmEmThtaOEzdPnW72UydSLIoi6RE0aIsIkwAefDLKHNkxqoqnegWexnh9k6va/JCeUmUrVae5n51cOjoz4HGl6OlTvfBa+pLlUTrJOflVvLuaer+7re7o+UDcvAw1MleK/qQPSDPFT3Y/0+4emsaThk9+IY9IN8resgekCeKHhzq++cgbNJljYNNMC9SNZblbDi0XNW3EEFZzMRtc4eJWyIp81RxOGwoJCkp08sNjfCXcOi5EMPhjSIpZbGQio/vh0NkCCymx/0DTHLKYjln4ukHBTpcEd5f1phU+sm74fBJqvQVKWCigrH5cIhm7SN5R48rps7N+UN3ZIZBX6cv9dmJXz79/tH583dPL5+/fPb85fPzX8iEnG6/eUn7B+TWsIPezNp0AG13oFmcKTQjCmONyKllCRzdgX7HCFCyu7ghO2C3sPTGGBJ2QcCKRuQu9uQGx3prIPvmWuafrlbT2B3wPkjeLbXkhL5RaBqbY6+fOHG0PpOzWSry5I7csjLnmUpOgFIvgvdxMM8amGctmHd3lZQF0Eorx0XEUs8ROWUdeGsyDsYG4C/x8pIGvPmOVgh/8cSoaEcVwt/dHWE+RgaOAn2vMEGfBGpecqF2b9h9NCIHX7EvO2DgoceX1lTsWy7QzMkDdT3mIi2Ke4AO2JejGAb6MUiTWHN7PkYVwrvZd6+Vo0oZvIPG/Yyeg6VMYHJnV/8DbAlpFu4uthwyJGdTegf8NpCSTxTSTQTUfzPKK72xSInJiR33Fk2HupclcWaGk2Bkv9q/+9V+VdMT6PfK0mAaktwGK797rAR9Q3K8WvVfKPQqXpQFXq36L+EaNrBTwjUstq1P6QSUJYR3T797rvByHIw/oaYTOQUUErhFDBQpujKSctKr+MRYTGWPCbAENvrqNFVGq6x67xeH+wcPevdyUfZgyB6vejtLM3x9RaJXcyb0ULtcRB6xuX0Lp7fVVgX5qaNDSFAs/r5ZsfjwUXXl1Zq6Yi2Dxp647S558dFRb7vPaQB3jFFvaOUDGj19+erpy/OInLCW6Iz2yW1D5THCVoqGXeikaLMb0D55EZdMGzW0DOZWzjDzq52lqmNLxGSR7+4sPcfgeb27A8LQUxaXqcjl7O3b508wwvUVKallj8as0UxVaJneWzdiXgEfQXgw0D/O7mfXsuDZCy5uEF63OJRsvKi4mMBeKdm8SDPWS3tCil0gHL2cVYoLZ3hYf0FFJGjkfasDIG6sQzsKcTcZrwHszbhpPVXizR2l77jsgn81TnnBcgB+vrgueDXtabBTkfdKVilZsp6ast68ZLdcLqrwfY56JcskKHa9TM7veyWbpVxUvVT1dpayvsK1g7+0e99ANQOIgItl1uugt+Ufilrj9u4Ulm48riLye9NYsozxuaoi8oHRQ/IsUPWsifDgITk4/Kbe2SO/hWZqLWIR/WeXi4rnrARWooflixlYpq8ZDLa/+61VHZvL+Ivd0XKfPAQjNDnT3dLd8f7ut6PlwwfQ9kPja7GC2edYabcbrlqmqp7FhLWLCcq04OuMQH1KPzDQ7oQUGVA91cjC8W1a8lSoUA3s/2ZsvP7mX4CDjxES4KZgmWI5SEsCQHnnITK8AaBa6/SEV+psmh5+9dD3Aw3fg7x91OAdrpm1K2/tjgMsfBSGYNSz7aM2T+C/hi8Rp9o/BtQRmLFXT3pOu/gRiZbRjlOx2fIGaN1kqhuKjkXuWTOis74FkBjTrbWjweuXqxXYdfm6uTUNzK0BXrOCM6F+YvctLH6G4T549C9g00pIcRyL0EZrzYW8Yy5M65rctNgQkcCIfoqncsZyXjZsqP/M230+Fyp96MwKB5vy1u/BYE/lwRbaOjpzG653veBF3uM5E4qre3v4S4D879ZYJ0kUO0PdH4pc7SxZrc10V5hwz+UKz+U+OC5nzOrFGl9brfqF53yrVRFX/A92fPDwy28erEO8EFU6Zh8lEYDkgNk3TB4seoUxfj38EtqbXeXY+IQpbShrHMuDQQG2sz6l7T5o04n8FHT0B4UCY0KDIm9kQ6UzqIE/14vpTc+FKLi4AWx2dA9jItiyUL+rRgD4EM9u9AZMybJk2aKs+C1wQ7ORHzz4pnaukGCwFBaaO+LtF7yy+k5h1ekMZKS8jrUk9KorCcVqNr86CgWFD/FdyRUzr57BHNscIx8Y0bs+YcQQkqQgrEN9E38GmlsNCU3CwwDmsoK2aNFgwANqGbaHbgMeUEt79PWWqmtc/8cVWeqmL795UDvR/oShjOSblhK2ZxZKI50VdVpZbxtc/NPMcDBAH+3lMbZabejX4potWjK0WmoFUmgh03zXCuh5hMl6U4I2v8PQ2pFj34RaCOYNySa/IB56jjTWybOmv2U2OHFjaoaH3DpUHgR42F7ZQI7NYQ763htGo73bgz2/oao902FPzhWf8T9YRB4r0wcUtL1MzuYFg9GriLxkXkSzUlRsH9O0Yeisgy6wJAYoWAWGXLVahcuoGWcKPhuWRwbsd8rIhF4IJUYu/FHRLR5m8kj78/vMe/3YR7x+YF8zrsQmqiH0IHrvwiOk8FA562PHdPhcYwDc9fjPeHDUYND/0TNG8ktjgET9R9oRw2IYrR8S69UK7sXuNwZFCvWfIwYu69VKX7mbsQudsCA1N9JyspgxoaqWgPGaoU19sLMCgIMb5iEwYNLARNxVstTe7w4ExI+UbBoeDFZ/b97dvHnfB8CkVcUrlergFzBURaOYi6xY5KxC1vrN4lIWzIN55Kye0HrkfEnNOM3OgDMJ4TT91lr5RmcA73/247BkNhTF7Wq9Im4hABD9ErYdri8hgOtSr56eyd5v3wxE/zVwgp5VI/oHuLDmm439BoO1yIugm9mD/qfbxodfPYT4B9q6B76cX5QPfXksZcFSgYlzj/Up3TAWbnYXLFeiiEVq4tGr/T4O5YDJ8Gi5HQd/augpBoNlM0si6tbjIU5bw4Q3knY/2KA//YuHs3skg5bcBjC2edr6mW31Czec7zFPy3TGFCvD5W1BFHRp8P4nT3OIzk3AtdAatCebu+v12QbjYLBsfiUb+4CFj/zathO4BdKWRNDczRUsT2erW3+Q2ejuR0spW2s+PmAPWqeLBl3gEPx9/RAY9TA4B50xOx41dtc7TeekdHYWwunFyMc8LcAzoRrQvctiDDcWwRkbDi9G2nYltWViDDzCTSVjEB2giZh1Hm+l2uNNVBtEDB32dAVTJTtLGArMUnyMFpr0BsRu0aZ02pymQerccMCVOrSqc9NPWLJqUahkZ9nuAJNbHcHhLfdX1RoGxScRZxwAEtQhgztYxrRB5Wo1Gzpy38HeajULmSzdhEL3sql+WT0iqT4Xpwa6MW2jQBN6g9kxcNHUX+b2yk2am0mbGT1Sxx6PxRrCQLsdau1VXxuYPNPSam7OCqbYtoU1qq8N0ygcrzpy/q5NL2qfbJpD3tdaNHuY9MjOQrnosqgxPTbnwOiTGd1vv6U9T0fZd9yPxy+yUZ/SxRHOvqAHgOSMUso7hxfu1a2xUtxsdOAFub0Mj/sEhjMMJ+DemyIiTR/PkgN69OVqhSbUNcNb/rSBEU+6jLjhwQE8C486pEwvfRj0qDN6POuwMkzGPiiTj9EkruSMIbT0TGQGjuj+Qr/5zLG/cfhz2N9P0FjvR9tC+geePelVOqVa6ywSS8mdS79KBLCPiWXgVTIx7B7Ua5bOAja4NC2Ju1XX5JIycksvljfsPokUm81ZmSpQ2ciMi2Qf4jqSw5rY+3J+OQ/vHLg7s/TDpZI3DJSh4EH2LYFY7QkrdQhI07fRnj77MeNlzNjlnIm0UPfmid3DNohjrVmJ7H5LN0//dPeFvjnW92Z+zrtajnu3zt99ebEYkROqLhYjWFzgiG5/WhHgpAlaGQzQ6cViRE/ax9l2nPZ9R3AwGnc8mMQEVwxN8Wo1/W68Wk2PZ6vV3WDQ9HhuINNd0ALOf4Dw1cq3rKM1sH6fhLNPj0/8jtcQT12o7mlNnmt1EC0jK3zuwghRYvRSE0u4pyP2SLpQU1laNTe5eszSkpW9nSULwkHBT/lh17rTnGYfJV0LEIRTecWfwE5OvDNex/S8DeysoaY9ZSk4XDSH8hCbQ22t41aLgTCT9/kX3k6MBwODYSTwsbJmPmNFYPG1zO+HcZaKjBWoY7IhgS3Q+HO989YgkeW9VPSktrn8wXIdBgzOrrkUlTPomimcnb5rLgQxnX1QkE9g5CHTHV7yjX5fhK1odM4+qCcMTBUl4RQs8xEEx1pXpCbjR9gGBpuhpbZDIg1GFedSMLxMv6BlnOthEISq9PePrkuW3sDu5V/QKtYJKPH1vWIvNGoJ9yj7V7ERzm0nIo5Uae/dBhw1hrZ8tXKvtWW14H0LllbshcxuEK5r8qQTh+RP79qJY3gwYMd0f3iaqmk84wIxcsi+xc4P8nMrYuqzHHNtBZ0I2u4BiV8Z1yYoPAx+OFZWgmWn9MpR+RHLTtlkWpTxDRctbe+dtbqYOxiH+QOa0ZVAAuBeYroAU3mCyhjcs7NUsfxck5iz9JblOOQymzokW5+sa+yxKQOnqjOCkai64fO5vsp5BaEScGmDiSISMdh60Sh03bjUsZYV7nm+LeLMWNWMZ9cgpfskKGHtlqTbJdSxlQ9FaSY06oe7gzU31nF7rqk2CFYxxGeK7P60amHVtybtPl7h9zvF6vvQ7a+u1ZYnQc38vh11MWYqm0JKR5PPsbTWzUTVltKFMfWO4pXD+C4tBYqcgbVn1znx5ENI5Z0s2uLMjxrV5tG1LNWJFEpH+pQkp3De0ziFdoSP5NBcsnzoGxNozPOnt5A+xivFBCtRpG9GJCdL7XkAknNk6GUQYtcanBx8tb+Pu16wnkBXAet7Wxb1zvINxOksZ0xNZZ5Er1+dnUfEcqzkOVhXCdD1NW7YoBATiO9JiySNzQUpwbHIMpXYrW8i6MphzMVYoiuPT5ispyHo7R73dpaF22hXmPSLWN64pTBozexbvGWoIA/YQ8OmHqEMt/tN6K8KZc6E3UTP9CZDD/aEhIcj+RkeCFtwnXAbWFLgZWdHNG9gh+uZEJIE3qHHBeg9GRwzzXSGhZaXPTLAP+mZQ1awtHRLWGEih3HJZvKWbdkCLlljpwmEBtrOjADR5P9tTA8MImbXWePVZ7FGEHt6O0tRXwVZqOQJa4OjAhsk+3KXNeq0vQF5NV4xerjb6NuGd38+3+5A5ueJ8FEw6xdUke4cX1AHQk121t0jRhcFkc2GWjcBC1oVNPe1i5g+3OAg3gawkrI3S8W9gVePEjkRCkz3UWSS06IosO1EUd24ZuzMABkETsma/C0MJn+tPSJwMv6E+OMc8GtIbNLjmGivsfMBdPXfbCp5xirctpb59njMRQ6s+5Hm/pDFJ3L2YTjc12kgBnIYXOrBkQRbhUpxoCfYJmd5bvOw1q3BQCBrOQVhNSImS7nTq8ak33kN1yMwsmNro+vecPv4X98EG8Yey/JpCpKizU0weC83uPw/cnpbiwvj2g2XUo98HhCMdLMS6ATOFK9W6Xf7q1X65zb+JkB6enqf8rjDkCIpePMfobIx0A+ba0hlL+iOzv0k4D6P9DDPnxidpdBrlMc8hyRJ7ZAp/gSEmpcXPFMmltEBqUeH4WhhrVE7qDLmVw0CXJn5s4Du7ea6i7Pe/DVNRANhxzfjfUEz8oShnAAM/qQSTWhJFBxdCHgEVeJFl7Z1snMviBzJsc1Rq0B6QFCK4IJDAmy5y22u7nMkjTXV5NbqH//i4rtVMym6ekSi5zE2q788uMWX8kdfymJX73sC/3+eJzCXIbNmMsLFfKGSvykkA8uvRp/6/0X2rPGsTfhs42bS17m5lfh1+m0kf67PBgK4fuvfSQI3jL6NCGpEBXTi30QUNRXi+CiFE7+R1JDUeDh3gtnX6AGc0pS0unzOcf2jE6xHSqPB+Ojalq7i/GefTjrvoOLR6+c6hB/i9btazFEQHt4rN6gMj9VfURmUVxTkFg2hz0Hm/7RgGsrcPQTxYFZvwFduEZfWsWyddG3RL9mv7XQbTXPamIiHTQSDPj97DCTyXWP2iTBeKoG8PsLJN+whJinkoLxgKDVCGhFhSkefG4PaZ+9SIb0RqgdPej7J101t1ZqprQAzWwaJUxN6aon/JT21OYZ778vhe7Hn/Q+39PgWsFiq6meupijSOeiRLVxh7mrzy1dYJyueQVeEscm/hoxFwOilJhGXuprJk1cvn44ivMzAVGexwEQYdnhpEFbXjSGwn1lT4KndfnlgCjw1prfB4HTN2Hd8yB7+RRZrFrSnV9dKEWBOtOa+066571TbI2tMCs/r/11T6xUyGVmX1CyQWSWd1YoKbHFzSwtvC7s0fMTA7dtt6xeXF/sjJ4CQCbrFJMPeamrexP7uZxBgatJQB4MJKjqBgr18m/Ey7xgvW9vfKKt//2gyzh8dW6c3FjJrFie/exHmD12WRFuxKKWHwyZkhH0IInyG/YMEsbjggj2G13vMxrKEJ/oQtBHEedmiILB/XYEQMxYm/X2c+JkOhizOlITSTQc6+shcH24UBHiRl0xgAKL5adP/BT3+nSFIMsNJ/yDpHxDBvIH2DyNa/AGxSEFeV0+nF7v6Kk4l+53ZbgSC3sw5jCKsc5Fr8ozR6GIhSiZyU8epZ6nbKCK/sTAOAybVx7ZBaxDYArhopAy8/NeQGlDDBrWDATIIpTpv3l8f4sFgK3KbsABhisv4O78Z9PoMQwvBM4Zr8sOncf2MrWH6twDTpMG02dtC0EMiBT0gpaBfEq5nYJpqKnqsnD+8FEMTOiWFETyVERhcHJXy0liiMPlJj+Io+lOhKTrCMdNXkM4c+DlSER6goSFY7cBGI/Z6xyB5zNqPuPvNM829diwXeffJRztrNnRvhknVgXTGZ+xch2e1Eihgq7zf2+M26NJ3w0PY24ke1+Tyx7x6x9kdYrEOxh12eCDCjozbDvpwkGILGG2cwQN965brN0AEUsFehMmvrJWDNWou+/9jZ/CPyyZ56v3eZ3Xb2SO5cLt0Y3wstoYef0Y3wf8rW8feVQ+uKYhzrrG+SqLI7vOrneVaJa0ohasocXPXkHl45YsmWQhq8pZmRVpVJoEjrwwXXNYkE4FlKojtMYcWB1XMxNrGxUt7dIW50/ZYu/5NqS7/fAtP4LFpRggKerSIq51JBnMEt/37Nmef/Ng6B51TMmwFPILRImV075//9b/f7w3TMpknkF2X7o4hYa/+53/9996ELITuoO+i8Db+53/9N7p4X70/G/3nEOsxdKf3B+bBcYhiyJRgtljjD2k1xSiqdKB8hImg0uyqDQdIgjwbL+Z5qhjSVRO4UN84ZfBa9yVSU51X43HFlP1hzbUhYV+r3tUMHF1E+KhVIFFigUogqq4HAcXd/xpF4cjSr7UMV7npvuwOb0u+3bD7CklsrBsY+wfW0zxKXCdXmAgkL8pRCNdRC666gcs32jDnzoASQph8aR/kCizazUvcOUwCMkS06M2GmgI5i4WntDVAlfMJHO5oCsYzLwsePMQ1+Zl9mrhtJA4XqVJpNgUtqdciEaOrBESJytRmYnkgScjQ7m9O2zgs96NDQJUxVkvCMLl6vzj8+ulDvYEhQVb//HpnCUkSOm8YpYzA+TL99jodr2ryq69YNGSdhxJGJiIUbbbyRHf2f0XMLoQx8rMuUWGbiQoY0dyjzctacXX4qxZAEskQIz80/UDDd2WQ4NbPWlNWsGawZGu09+pCL0M6Rz9bNQtOByzHRrYwvFruLMMNz9yGd8LI+nZXuE52lj8jdqFGuL4Kp6mvks07GqLJ/ta1KQakXVrSbhL2LkYQFhvHsXRiwAiKpTm1851zVTRZliBBpk0QHF83oL5F0Yx/sNbRXRMS2XOxZr20ZNqiAZUHHj3fte09iDxKFb8uWEAkKhP/Z3yk2gSOC1o5SDXeMno8ESgDgd1T/yNWVMzmmWUC+QewCzrU/KUFcKXKRQZxa9biZKCuendcTXWmPAg97mT5d1BlKqoiVakBu6BZXdoyhlqYNMGXpBUWX1lC4UXLwibl5Q3aK3rcf8dQhTXEQSk4G4YTLGcGKDLBwI8ZuFp91RMIsxXQsrTRqb+izJ+mgJEal2wFXXXwoT0mwWOT9gOwIQozsl4S11FCBtvPAES7f4joq5BQNWtv0ArECOxFOQwOxiIbQUurZmm1idMK7UJgu8q5j9OE895agiD1xWMcoht+ZEjqalhZsLHDpIdM768JBLHwPJm4ZftEoP+kG/fdOZ6TWNuyh0OduYfhXw3btdeG2uTtrANc6zBmZUJi/SE8wDpr/gxMR6f2oIFZx5+Div6Myov9ESYF1QlvUDVBW9UqfFQMCydeJc1N4AkVuZAjXAtzO47j0pNIUZNKs7K/aTLJQhfnUnMVb9yzI/rfXUihMhoRFAYCOu/8HpKUIx0KY5/HpXdJgw7r4LSh0tKH7wRRrVBJIUvLRIGjoKml10LAz0Axh3E15WMIzBBqjXQSCaa6ku4TrkNElpLKDmsjEkrOmgUESpFICBuj4Bd2BzU1evAMjDOPigItQEmWX1BXd7UkqbUVkZLayy/SxkBkbYvKsmwAPb04GBkKEcSUyi9oenE4Co4rvJWFDapi3DJd/tOxugACTHTfmkjV0pLRp7JbVJPUEmaldFJX1FrGijKH4SybslkaRhUF+SqtPjUcGfIL+5PpiaXnh2tcvBM7B9YrXQrYVBcvtbECDgFOWNL/hRmrxC9M9/y8KsamsrAgUlcWFkSntgaYiFpic1fDhxrogeICP5OSQb2UCzHCUKS47JT3cCV/Ab+jo8aneJrOkXk5SY8vZMczAq/YVJ4eF6k6NT2toCD0jrO+P9exHF5AtJwMItfKP5fOtLm73hxy2+YImjUqwn6k3JgCVddQZVFXjxcfzVTdVk1+bVcpb5FSrkrS1rIJLhxpPX6jJrx91Ex0jkvSqO4rxWYbvEXvznpQtqtXpGKyABZqyz3lUssllsX2zPNe9vI1WnyU4ZqfcujbIMJFNj03KtDKK9BHLbgbnttKSwx5saaSOu/A7J6NKSiaHZ9obqy6KSg6utRqX6X3F3cdfsZxPBcb3XxY89826DYvSAu97eybtUXoLKsVdHnVm/FKl1viqrJhFHlTGKQlGBokwI83JnPIvVF7btuxruvWIEZICDBZ18Zknyra1KErfK38XevuSCJy3yhiQT1GfQZsWJ1JVBJhuNxbv+VdqKDhJz0oJL8L+FlMphBkJ5ybGILpjAHHIA8KoMLEsOI4qBOo7U3KWYTYML4QoyDkRW4MsbZpD9KfRFnX5DdXJBzw4Qp40U0JvbralgOAG2uH2+7D+IKPWlkZDBqELoOFj8rVCrELebE/GlGBa/I3Y15bZlIYRUKWSFcU0z4YIvFSTbnm2cY1TNWRbpDirWg8u1SY1kJOqKx956N2r6NCTo6yaSom7OmMK8VMFP99rCMSbdMR1GTIT3SvF5ZG6LoHJ9NUPRdQ8kSHUVI9YWu0WLu7jkqWFuaJNJsyx0COSjYuWTU1NRSQfa9231jHTCJMNoxtKgbWOa/msmLu+XYff7P24yLl9HoorQbpfO/34WKcznhxb3/YAhX1FZCtDWAB/7I1g/2GsRvBol3eLOZvgjljNWUCcXqM+Gq1aUgre0KlCKiIdGxrl32ia/OBkE0dQe4WUNOwrG3NlDW4fIFqnrd8wuaUJxH4m+CWluq+BqGe5yDJW5/tfVzM4ooVLFOwHexaLm+ZyGWZQDnSPBHE4DZxSCauwEqD6KZqtIV0Xspbnn90w+kykK3y0+2TgayG1w6i2HBYECb9bjcBv7UXtNCTvTGRCD5k/GJkBt9UnspviXaZEM1quNUBr3aWBashngESSg3D4YbPWGzBHY8pN34E6WHPgRGZUPjk4PAb9iU0vlqooBVCToDqKz5Pug5qzd8jkjOV8iKJHr1+DnU9wQAxHvOs9/7D4697pVwo7cIOJY7r+54dSvcBZrErRWGqRELA1Ty95gVXnFWJZ7dcTMD1yWfphGnAdfFqm0pUmgq+n7mZatwq9HExcopH2Uat3btt5F6FoMMtLW5cNdju7E3u6/p0MM7jdsMnkP8LlMs8MQzUfp9BG4IsOGEgerMm33P1w+LaP1Ytrr08a16gWRQpetrd3NPR4B9bhP31RfjEYXtjQ1KQDU8iHNuy0NvPWz9tZ1gYMnYftwbXUk/8Ur5mpRZwpKh8HMValFLce7MQvXbd8F46SbmIfZhMuvEgkormQ8OtkwDikBdokPPBoF99HFL1TC5EjqLzKetpvRuEss4ymdXV8PcKKSas7KW3KS/ApOdALWgOFoc2tS1Yi8wWPpLU5iJpvRwKgxQ6hbxNVWx+L8+TOWT2zikEwm4IkHtuNYhN1KBnTp2p2ukEh2Gcs+vFBF3B8U5MR2p5pv5Fd5YG77VXCygIbDbU3gZoZURnVOdm68zpvQA92M5h8D//ZFCN10nE/1S9e9aoJXpL92TZGFa3mF9hATI6r70da04NE8/o3JduIBM6j62lx+Y5yybnmly6rOd8WCQV0GdvIMpASDztmv+qRCp0atKiri23KF7pc1yRVopzKxEquJF84rFtQ5vsaPj7ujM23Nk0auuJLcOGqdXw49wm9oYTNH02zLJtgI/MtyE9G9pPfPM2INYe3ALPZ0+wBcj1ZHDf9Nq2tGDr9t8A1ucMuQWaDUnnTdtGeNae2ADQ541qbS2w808NOe5QU2Aq5/Zu/MaWavOmch0+nUS+hFtNmsTbFgnZlHL3hvJYio0im45fm7t8OXzEt8l2g4Hv1ZQM7P0Bwb2X5JweL0uw1cL9cxfSZOKth0Ztar0rBKe8TnVf4xRMNnWyDNp2tH6BcyMInhtrFAZTk823a0L13rSUG1+YwVbOR3Pyxtmdzy23Bt+syO3LQgeIfB7L0qSZa9X1DFTXc1uRAfu3PcNQwh6weIu4VjxMvfXJcM1VYNUwzT60Xh8Z7rFRuweanSo545n330w5mNPvI1dCb4FaBbHHG9d+9om1H3/W2vtepPMKlgGCTAxcf2fp3Dye76EK9+xb6frRjm05Ma20vPBObytXuf57s7FM1urYZVR61uiXehYsNRgyNkLnp+q53Fu6s7zbWPpvOIyEFCyqexD1vtapnUo8HEa7JpHxExoRbIiXDN2RS9wUum8t3rSTXX7n8jab0kneXhrc03JHYy70d5JLckJL+BKDZrUk4NRW8/vThChk4Cfhl9c2v9DvlMP0Hnryis6t6XzilMC5Xvg3VMCRm3g9942R287pcWSORsRF7xwP32hVBpo1YYHGTxAXHW2ZAMmAYXCyaQTTK4kiHIQ1TRj93XgUWsRiMlThS128GZFJKIied0va9ThDF+cjfLGvdeL5JtOtHvuMXtgeGmbddkNfud9HdulvgsW+GQzObGTYR5Bwg3Fy5h2LN9gX/bkBejaPvem3KSM1VvTGkFe/5ezvIMzCtoBN+iNQhCT8xpHwG6vLq+a7gxu2oKWa8SOHKXTmd+DwDMzmc+MlqVuItUW8zIsZa6/DsMamb22F4n4MgLcVK9HFlrczY+n3aw0eeLHh0yzBsm0cya3WGR4lZ3j0OXjRYPkN4pGByUuqnUUtKQX84PXRb+gl6Ugv0zgQmTvyM9ncH4Thrky8uWsj0Q6H5teaPLlV7P2T8udmALqy4udJj5vHWhPzPlfyI+6bKRNGrOZzQhz5TRpKDAJiGLj0EocqUwhN8hLCGVr2CY2HE7kQyhgkXODRR4wR5f9bY4QOpdhoErR2k/VvzQ5FN6yjYgj8sf7Y/qRLzISJWputGPz/vgXDF4fOYBXMvtTubVuqIGdUy3vx9b28eavADmXMFE/cZ6ez5mvLW/rEs1SkE6irUjVfUG5V/4/gwxuPJpBJ05RlInnT27XZry033ckP7bJNjZCvjeWnZmakmq/VkEK1k/Taj6nwMYG7nxkL/GHBNN8X8jotQIzut0sX204/mGx//ZmyRStHsIm9hFCGCkpnm9pLsPEdGOA+yFtfEdT7MvxiKG2u3ZSCWKZOwu+JyniigX1nQiOpNwDqEsluP8BHRznkwBTmZKaEe+rejObqd4dz9Q9w0pojqKsr4ztZ3lTzNGMfufVMFjkr2x0CUEwpZztdTcYb63apNvokoE/goQjQJ2kzO2tw3wHde4PCyrHNojZvffTRneH6bXhy/eOZ+uAxRpcWKP2Rdf1ijD5t8NSQRvuRAIT9a+R+KZfB+0AgcvCTtFcD7rZbyKY1aXUL2muI+bLvmxgqz/zH0T4Bto3Czhlh5GncunuelhOmYjMuUCX7dTHrr+/NIGTZhZY1i65xxuzbnin45h24+DKGSXO+LZiVB7P9gIUqYwRiRMxn/FwB93ieZjfphGlKb/0Km79eutUS2nwvw47Vm6aaTtvhmsoizoMhSFM8Hz59m6nN2QIOcveVgIUKvg3B4tR/dPZ1qrNFeaWa0vTxb1WEMW6HqdcQduY+J/ioqSJXsaxkNuDsHQY6dc7Q0nyh0GAXVaSA4kZuG+jvdsbVVN4Fjr9Tp3RDX0oLEn7JcG2VnsIHFFsfO0RP47clt4E6FWT/QegkSamf0ODJeHXA8y1Ygfx3hZeFnJjCTCwOPTM2dDV1PglYw7+hkujzyJ2/mqT4CLKVtD8YoKxaIspwAXXn9HcGGNAo+IqBeZKMGdJNIP9unDnf0v4U/Golm0CFoXJN1n5thKsS+W8h5/hjAwXhAIGXDl4S0kNbLv3t41g8O6DelvyHVOQFK9Fyqi/eljxYSV0cED4GB8nve823HMIYDFNi9u2bF2csLbPpa4jYqlAV/75g5T02ad/2Izatb626UlM3UGpq6ce2+3FCTskluSULHBx7t4915Cd6R+5Y0M+R7aab9dcr5o1aDN2a5a2J/mJE0nx8c8vD7z5jWLdB6tra5zLzDabOhzGWrXP1c1oKLibuTHnBF0J14KuF8HU3dsfK7gd74t4bPXDPxo8RMHyJXvkR6dhaTta2CfnUQc86X/BwQFqvUCCdR97b3f4gjo4jgftORGtNqSltFwOZXBS5lv5vWcnH99qwJwXbhWp/7q03f3fno0qCjjutPUeaCoSXNVRfnsl8UQDTAJtrRZfwvZDbVDGSM3dZ46P/+D9QSwcIjFNh81IuAAC6hwAAUEsBAj8DFAAACAgAlID4XPcC0Y4JAwAAtAkAABYAAAAAAAAAAAAAALSBAAAAAGV4dGVuc2lvbi52c2l4bWFuaWZlc3RQSwECPwMUAAAICACUgPhc36MN37wAAABlAQAAEwAAAAAAAAAAAAAAtIE9AwAAW0NvbnRlbnRfVHlwZXNdLnhtbFBLAQI/AxQACAgIAEuA+FxgSlWamQIAAKQFAAAWAAAAAAAAAAAAAACkgSoEAABleHRlbnNpb24vcGFja2FnZS5qc29uUEsBAj8DFAAICAgA/H74XLKGeo15AgAAJwQAABUAAAAAAAAAAAAAAKSBBwcAAGV4dGVuc2lvbi9MSUNFTlNFLnR4dFBLAQI/AxQACAgIAJSA+FyMU2HzUi4AALqHAAAbAAAAAAAAAAAAAACkgcMJAABleHRlbnNpb24vZGlzdC9leHRlbnNpb24uanNQSwUGAAAAAAUABQBVAQAAXjgAAAAA";
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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} —
|
|
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
|
|
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
|
-
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
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
|
|
592
|
-
|
|
593
|
-
const
|
|
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
|
-
//
|
|
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 <
|
|
599
|
-
health = await
|
|
600
|
-
if (!health)
|
|
601
|
-
await new Promise((r) => setTimeout(r,
|
|
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(
|
|
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("
|
|
608
|
-
info(dim(
|
|
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
|
|
1247
|
-
//
|
|
1248
|
-
// tools on a dead 127.0.0.1 port), so a plain
|
|
1249
|
-
//
|
|
1250
|
-
// that pass it keep working.
|
|
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
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
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
|
|
1269
|
-
// expiry beside it: a later helper
|
|
1270
|
-
// operator-supplied identity with the
|
|
1271
|
-
|
|
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 (
|
|
1314
|
-
applyTarget = await
|
|
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
|
-
|
|
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
|
|
1368
|
-
// but a previous run left it installed — covers
|
|
1369
|
-
// a
|
|
1370
|
-
//
|
|
1371
|
-
//
|
|
1372
|
-
if (!
|
|
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
|
|
1375
|
-
heading("Local
|
|
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
|
|
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.");
|