pennyrouter 0.2.9 → 0.2.10
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/LICENSE +21 -21
- package/README.md +225 -225
- package/bin/penny.js +9 -9
- package/bin/pennyrouter.js +7 -7
- package/package.json +30 -30
- package/src/cli.js +1774 -1727
- package/src/harnesses/aider.js +48 -48
- package/src/harnesses/claude-code.js +322 -318
- package/src/harnesses/claude-code.test.js +57 -57
- package/src/harnesses/cline.js +77 -77
- package/src/harnesses/codegpt.js +76 -76
- package/src/harnesses/codex.js +180 -180
- package/src/harnesses/codex.test.js +119 -119
- package/src/harnesses/opencode.js +151 -151
- package/src/harnesses/shared.js +51 -51
- package/src/harnesses/windsurf.js +57 -57
- package/src/harnesses/zed.js +61 -61
- package/src/launch.js +487 -487
- package/src/launch.test.js +170 -153
- package/src/mcp.js +228 -0
- package/src/mcp.test.js +182 -0
- package/src/session.js +157 -157
- package/src/session.test.js +44 -44
- package/src/state.js +103 -103
- package/src/statusline.js +202 -202
- package/src/statusline.test.js +72 -72
- package/src/thread-session.js +204 -0
- package/src/thread-session.test.js +140 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 PennyRouter
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PennyRouter
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
# PennyRouter CLI
|
|
2
|
-
|
|
3
|
-
Official local installer for [PennyRouter](https://pennyrouter.com) coding-agent integrations.
|
|
4
|
-
|
|
5
|
-
PennyRouter is a model gateway for coding tools. This CLI handles the local setup work that
|
|
6
|
-
agents should not do by hand: browser authorization, API-key handoff, config edits, backups,
|
|
7
|
-
status checks, and uninstall metadata.
|
|
8
|
-
|
|
9
|
-
## Usage
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npx pennyrouter install
|
|
13
|
-
npx pennyrouter install --make-default
|
|
14
|
-
npx pennyrouter update
|
|
15
|
-
npx pennyrouter auth anthropic
|
|
16
|
-
npx pennyrouter install --harness claude-code,cline,opencode,codex,windsurf,zed,codegpt,aider
|
|
17
|
-
npx pennyrouter disable
|
|
18
|
-
npx pennyrouter enable
|
|
19
|
-
npx pennyrouter uninstall
|
|
20
|
-
npx pennyrouter status
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Installation opens a browser and requires login to the PennyRouter account that should own
|
|
24
|
-
the new machine key. CLI installs no longer create anonymous ghost accounts.
|
|
25
|
-
|
|
26
|
-
With no `--harness` flag, the interactive installer shows Claude Code and Codex. Detected
|
|
27
|
-
tools start checked. The additional legacy integrations remain available through an explicit
|
|
28
|
-
`--harness <id>` selection or `--all`.
|
|
29
|
-
|
|
30
|
-
When Claude Code is selected, the installer offers Claude subscription authorization. If it is
|
|
31
|
-
declined or unavailable, installation requires an Anthropic API key or OpenRouter key. Codex
|
|
32
|
-
uses an existing ChatGPT login; without one, installation requires an OpenAI API key or
|
|
33
|
-
OpenRouter key. PennyRouter-funded provider keys are never an installed-harness fallback.
|
|
34
|
-
|
|
35
|
-
## Explicit Penny Commands
|
|
36
|
-
|
|
37
|
-
On macOS and Linux, a normal install adds a small `penny` launcher under `~/.local/bin`.
|
|
38
|
-
On Windows it installs `penny.cmd` under `%LOCALAPPDATA%\\PennyRouter\\bin` and adds that
|
|
39
|
-
directory to the user PATH:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
penny claude
|
|
43
|
-
penny codex
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Arguments are passed through to the native harness, so commands such as `penny claude --resume`
|
|
47
|
-
and `penny codex resume --last` work normally. By default, bare `claude` and `codex` remain
|
|
48
|
-
completely native; their normal configuration files are not redirected. Choose the installer's
|
|
49
|
-
"make PennyRouter the default" option, or pass `--make-default`, to retain the original global
|
|
50
|
-
routing behavior.
|
|
51
|
-
|
|
52
|
-
Existing PennyRouter installs preserve their current bare-command behavior during upgrade unless
|
|
53
|
-
the user explicitly changes it. Close running Claude Code or Codex sessions only when adding or
|
|
54
|
-
removing global bare-command routing. A Penny-only install does not require closing native sessions.
|
|
55
|
-
|
|
56
|
-
The launcher uses a private config, a Claude settings overlay, and a secret-free Codex profile.
|
|
57
|
-
The installer adds one marked PATH block to zsh or bash startup files on macOS/Linux, or a single
|
|
58
|
-
user-PATH entry on Windows, when needed; `--no-path-update` skips that edit. Open a new terminal
|
|
59
|
-
after a PATH update.
|
|
60
|
-
|
|
61
|
-
In Claude Code sessions launched with `penny claude`, `/penny help` is an alias for the existing
|
|
62
|
-
`@penny help` syntax. Both forms remain supported. Codex continues to use `@penny` because Codex
|
|
63
|
-
does not currently expose equivalent project-independent custom slash commands.
|
|
64
|
-
|
|
65
|
-
When Codex is already signed in with ChatGPT, the installer preserves that Codex-managed
|
|
66
|
-
login and configures PennyRouter as an OpenAI-authenticated Responses proxy. Codex continues
|
|
67
|
-
to own and refresh the OpenAI credentials; PennyRouter stores only its existing `pr-` account
|
|
68
|
-
key in the managed provider block. API-key Codex installs use the user's encrypted OpenAI or
|
|
69
|
-
OpenRouter key.
|
|
70
|
-
|
|
71
|
-
To point Codex directly at a PennyRouter gateway running on localhost port 8400:
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
npx pennyrouter@latest install --harness codex --local
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Restart Codex after installation. Without `--local`, browser authorization supplies the normal
|
|
78
|
-
hosted gateway URL.
|
|
79
|
-
|
|
80
|
-
Before configuring Claude Code, the installer sends a small compatibility request exercising the
|
|
81
|
-
modern beta/context-management request shape. If that check fails, Claude routing is not enabled;
|
|
82
|
-
the gateway must be redeployed or fixed before retrying. This check is about PennyRouter's gateway
|
|
83
|
-
compatibility, not a demand that the user upgrade a Claude Code version that already emits a
|
|
84
|
-
supported request shape.
|
|
85
|
-
|
|
86
|
-
## Updating
|
|
87
|
-
|
|
88
|
-
To pick up a new CLI version without repeating the install interview:
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
npx pennyrouter update
|
|
92
|
-
npx pennyrouter update --dry-run
|
|
93
|
-
npx pennyrouter update --harness claude-code
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
`update` refreshes only the files generated from the CLI's own constants: the managed `penny`
|
|
97
|
-
runtime and launcher, the `/penny` Claude skill, the Claude settings overlay and statusline, the
|
|
98
|
-
Codex provider profile, and the model labels and context-window settings in managed tool configs.
|
|
99
|
-
Older installs are migrated forward, so retired model labels are replaced with the current ones.
|
|
100
|
-
|
|
101
|
-
It never touches credentials and never re-runs browser authorization. Upstream provider tokens
|
|
102
|
-
(Claude subscription, Anthropic, OpenAI, OpenRouter) are held encrypted at the gateway, and the
|
|
103
|
-
existing `pr-` account key and gateway URL are read back from the local config, so the command is
|
|
104
|
-
non-interactive and prompts for nothing.
|
|
105
|
-
|
|
106
|
-
Per-tool choices are preserved rather than re-asked. Bare-command routing is read from the
|
|
107
|
-
uninstall manifest, so a Penny-only install keeps bare `claude` and `codex` fully native and an
|
|
108
|
-
install that opted into global routing keeps it. Subscription auth mode is likewise carried
|
|
109
|
-
forward. Use `install` instead when the intent is to change those choices.
|
|
110
|
-
|
|
111
|
-
Because the managed tool config is rewritten only for tools whose bare command already routes
|
|
112
|
-
through PennyRouter, a Penny-only install leaves files such as `~/.claude/settings.json`
|
|
113
|
-
untouched and needs no session shutdown. Updating a tool that owns global routing requires
|
|
114
|
-
closing its running sessions, or passing `--allow-running-harnesses`. Unrelated keys and user
|
|
115
|
-
settings inside managed config files are preserved, and re-running `update` is idempotent.
|
|
116
|
-
|
|
117
|
-
Restart Claude Code or Codex afterwards to pick up the refreshed configuration.
|
|
118
|
-
|
|
119
|
-
## Supported Tools
|
|
120
|
-
|
|
121
|
-
- Claude Code
|
|
122
|
-
- Cline (manual setup instructions; no VS Code settings mutation)
|
|
123
|
-
- Codex
|
|
124
|
-
- opencode
|
|
125
|
-
- Windsurf
|
|
126
|
-
- Zed
|
|
127
|
-
- JetBrains CodeGPT (manual setup instructions; no XML mutation)
|
|
128
|
-
- Aider
|
|
129
|
-
|
|
130
|
-
## Penny Models
|
|
131
|
-
|
|
132
|
-
Tools that expose a model picker (e.g. Claude Code `/model`) get four curated choices. The three
|
|
133
|
-
named-model choices PIN the trunk to that exact model — you pick the model, PennyRouter still cuts
|
|
134
|
-
the bill via its side machinery (cache/compaction/swallowed background calls) without switching the
|
|
135
|
-
model you chose. "Penny Custom" is the dynamic option: PennyRouter cost-routes each turn.
|
|
136
|
-
|
|
137
|
-
- Opus 5 (PennyRouter): pins `anthropic/claude-opus-5`
|
|
138
|
-
- Sonnet 5 (PennyRouter): pins `anthropic/claude-sonnet-5`
|
|
139
|
-
- Haiku 4.5 (PennyRouter): pins `anthropic/claude-haiku-4-5-20251001`
|
|
140
|
-
- Fable 5 (PennyRouter): pins `anthropic/claude-fable-5`
|
|
141
|
-
- Penny Custom: `pennyrouter/auto` — dynamic routing on the bundle/profile saved in the user's account
|
|
142
|
-
|
|
143
|
-
## Claude Subscription Auth
|
|
144
|
-
|
|
145
|
-
When installing PennyRouter for Claude Code, the interactive installer offers to route
|
|
146
|
-
Anthropic-native Claude turns through the user's own Claude subscription token. To force this
|
|
147
|
-
in non-interactive installs:
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
npx pennyrouter install --harness claude-code --anthropic-auth --token <token>
|
|
151
|
-
npx pennyrouter install --harness claude-code --anthropic-api-key <key>
|
|
152
|
-
npx pennyrouter install --harness codex --openai-api-key <key>
|
|
153
|
-
npx pennyrouter install --openrouter-api-key <key>
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
If Claude Code is already logged in to a Claude subscription, use Claude Code's token setup
|
|
157
|
-
flow:
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
claude setup-token
|
|
161
|
-
ANTHROPIC_AUTH_TOKEN=<token> npx pennyrouter auth anthropic
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
Other token sources are supported:
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
npx pennyrouter auth anthropic --token <token>
|
|
168
|
-
npx pennyrouter auth anthropic --token-command '<command that prints the token>'
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
If the separate Anthropic `ant` CLI is installed and logged in, PennyRouter can use it as a
|
|
172
|
-
convenience fallback:
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
ant auth login
|
|
176
|
-
npx pennyrouter auth anthropic
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
The command stores the Anthropic token encrypted at the gateway. Claude Code keeps only the
|
|
180
|
-
PennyRouter `pr-` bearer in its settings; the gateway retrieves and forwards the stored token
|
|
181
|
-
with the required OAuth beta header and does not deduct PennyRouter credit for successfully
|
|
182
|
-
served Anthropic-subscription calls.
|
|
183
|
-
|
|
184
|
-
On a transient subscription 429/529, the gateway retries the same subscription once. If it
|
|
185
|
-
still fails, it can fall back only to credentials owned by that user: Anthropic API then
|
|
186
|
-
OpenRouter for Claude, or OpenAI API then OpenRouter for Codex. If no such credential is
|
|
187
|
-
configured, the provider error is returned; PennyRouter never changes the payer to itself.
|
|
188
|
-
|
|
189
|
-
PennyRouter also sets `disableClaudeAiConnectors: true` while its custom gateway is installed.
|
|
190
|
-
Claude Code cannot load claude.ai organization connectors when gateway authentication takes
|
|
191
|
-
precedence, and otherwise displays a persistent warning about that state. Making the disablement
|
|
192
|
-
explicit suppresses the warning; locally configured MCP servers are unaffected. Reinstall keeps
|
|
193
|
-
the original user value, and disable or uninstall restores it unless the user changed it later.
|
|
194
|
-
|
|
195
|
-
If the stored token expires during a long-running session, refresh the token source and rerun
|
|
196
|
-
`npx pennyrouter auth anthropic`.
|
|
197
|
-
|
|
198
|
-
## Agent Flow
|
|
199
|
-
|
|
200
|
-
Users can ask a coding agent to follow:
|
|
201
|
-
|
|
202
|
-
```text
|
|
203
|
-
https://pennyrouter.com/install
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
That machine-readable page tells the agent to invoke this CLI instead of editing config files
|
|
207
|
-
directly.
|
|
208
|
-
|
|
209
|
-
## What It Changes
|
|
210
|
-
|
|
211
|
-
The CLI installs its managed launcher under `~/.local`, writes only selected local tool
|
|
212
|
-
configuration or per-command overlay files, saves backups under the local PennyRouter state
|
|
213
|
-
directory, and records an uninstall manifest.
|
|
214
|
-
|
|
215
|
-
`disable` temporarily removes PennyRouter from selected tools while retaining a local
|
|
216
|
-
PennyRouter-managed snapshot for `enable`.
|
|
217
|
-
|
|
218
|
-
`update` rewrites those same managed files for the installed version without re-authorizing,
|
|
219
|
-
and without changing bare-command routing or stored credentials.
|
|
220
|
-
|
|
221
|
-
It does not delete PennyRouter accounts, credits, or remote API keys.
|
|
222
|
-
|
|
223
|
-
## License
|
|
224
|
-
|
|
225
|
-
MIT
|
|
1
|
+
# PennyRouter CLI
|
|
2
|
+
|
|
3
|
+
Official local installer for [PennyRouter](https://pennyrouter.com) coding-agent integrations.
|
|
4
|
+
|
|
5
|
+
PennyRouter is a model gateway for coding tools. This CLI handles the local setup work that
|
|
6
|
+
agents should not do by hand: browser authorization, API-key handoff, config edits, backups,
|
|
7
|
+
status checks, and uninstall metadata.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx pennyrouter install
|
|
13
|
+
npx pennyrouter install --make-default
|
|
14
|
+
npx pennyrouter update
|
|
15
|
+
npx pennyrouter auth anthropic
|
|
16
|
+
npx pennyrouter install --harness claude-code,cline,opencode,codex,windsurf,zed,codegpt,aider
|
|
17
|
+
npx pennyrouter disable
|
|
18
|
+
npx pennyrouter enable
|
|
19
|
+
npx pennyrouter uninstall
|
|
20
|
+
npx pennyrouter status
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Installation opens a browser and requires login to the PennyRouter account that should own
|
|
24
|
+
the new machine key. CLI installs no longer create anonymous ghost accounts.
|
|
25
|
+
|
|
26
|
+
With no `--harness` flag, the interactive installer shows Claude Code and Codex. Detected
|
|
27
|
+
tools start checked. The additional legacy integrations remain available through an explicit
|
|
28
|
+
`--harness <id>` selection or `--all`.
|
|
29
|
+
|
|
30
|
+
When Claude Code is selected, the installer offers Claude subscription authorization. If it is
|
|
31
|
+
declined or unavailable, installation requires an Anthropic API key or OpenRouter key. Codex
|
|
32
|
+
uses an existing ChatGPT login; without one, installation requires an OpenAI API key or
|
|
33
|
+
OpenRouter key. PennyRouter-funded provider keys are never an installed-harness fallback.
|
|
34
|
+
|
|
35
|
+
## Explicit Penny Commands
|
|
36
|
+
|
|
37
|
+
On macOS and Linux, a normal install adds a small `penny` launcher under `~/.local/bin`.
|
|
38
|
+
On Windows it installs `penny.cmd` under `%LOCALAPPDATA%\\PennyRouter\\bin` and adds that
|
|
39
|
+
directory to the user PATH:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
penny claude
|
|
43
|
+
penny codex
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Arguments are passed through to the native harness, so commands such as `penny claude --resume`
|
|
47
|
+
and `penny codex resume --last` work normally. By default, bare `claude` and `codex` remain
|
|
48
|
+
completely native; their normal configuration files are not redirected. Choose the installer's
|
|
49
|
+
"make PennyRouter the default" option, or pass `--make-default`, to retain the original global
|
|
50
|
+
routing behavior.
|
|
51
|
+
|
|
52
|
+
Existing PennyRouter installs preserve their current bare-command behavior during upgrade unless
|
|
53
|
+
the user explicitly changes it. Close running Claude Code or Codex sessions only when adding or
|
|
54
|
+
removing global bare-command routing. A Penny-only install does not require closing native sessions.
|
|
55
|
+
|
|
56
|
+
The launcher uses a private config, a Claude settings overlay, and a secret-free Codex profile.
|
|
57
|
+
The installer adds one marked PATH block to zsh or bash startup files on macOS/Linux, or a single
|
|
58
|
+
user-PATH entry on Windows, when needed; `--no-path-update` skips that edit. Open a new terminal
|
|
59
|
+
after a PATH update.
|
|
60
|
+
|
|
61
|
+
In Claude Code sessions launched with `penny claude`, `/penny help` is an alias for the existing
|
|
62
|
+
`@penny help` syntax. Both forms remain supported. Codex continues to use `@penny` because Codex
|
|
63
|
+
does not currently expose equivalent project-independent custom slash commands.
|
|
64
|
+
|
|
65
|
+
When Codex is already signed in with ChatGPT, the installer preserves that Codex-managed
|
|
66
|
+
login and configures PennyRouter as an OpenAI-authenticated Responses proxy. Codex continues
|
|
67
|
+
to own and refresh the OpenAI credentials; PennyRouter stores only its existing `pr-` account
|
|
68
|
+
key in the managed provider block. API-key Codex installs use the user's encrypted OpenAI or
|
|
69
|
+
OpenRouter key.
|
|
70
|
+
|
|
71
|
+
To point Codex directly at a PennyRouter gateway running on localhost port 8400:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx pennyrouter@latest install --harness codex --local
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Restart Codex after installation. Without `--local`, browser authorization supplies the normal
|
|
78
|
+
hosted gateway URL.
|
|
79
|
+
|
|
80
|
+
Before configuring Claude Code, the installer sends a small compatibility request exercising the
|
|
81
|
+
modern beta/context-management request shape. If that check fails, Claude routing is not enabled;
|
|
82
|
+
the gateway must be redeployed or fixed before retrying. This check is about PennyRouter's gateway
|
|
83
|
+
compatibility, not a demand that the user upgrade a Claude Code version that already emits a
|
|
84
|
+
supported request shape.
|
|
85
|
+
|
|
86
|
+
## Updating
|
|
87
|
+
|
|
88
|
+
To pick up a new CLI version without repeating the install interview:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx pennyrouter update
|
|
92
|
+
npx pennyrouter update --dry-run
|
|
93
|
+
npx pennyrouter update --harness claude-code
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`update` refreshes only the files generated from the CLI's own constants: the managed `penny`
|
|
97
|
+
runtime and launcher, the `/penny` Claude skill, the Claude settings overlay and statusline, the
|
|
98
|
+
Codex provider profile, and the model labels and context-window settings in managed tool configs.
|
|
99
|
+
Older installs are migrated forward, so retired model labels are replaced with the current ones.
|
|
100
|
+
|
|
101
|
+
It never touches credentials and never re-runs browser authorization. Upstream provider tokens
|
|
102
|
+
(Claude subscription, Anthropic, OpenAI, OpenRouter) are held encrypted at the gateway, and the
|
|
103
|
+
existing `pr-` account key and gateway URL are read back from the local config, so the command is
|
|
104
|
+
non-interactive and prompts for nothing.
|
|
105
|
+
|
|
106
|
+
Per-tool choices are preserved rather than re-asked. Bare-command routing is read from the
|
|
107
|
+
uninstall manifest, so a Penny-only install keeps bare `claude` and `codex` fully native and an
|
|
108
|
+
install that opted into global routing keeps it. Subscription auth mode is likewise carried
|
|
109
|
+
forward. Use `install` instead when the intent is to change those choices.
|
|
110
|
+
|
|
111
|
+
Because the managed tool config is rewritten only for tools whose bare command already routes
|
|
112
|
+
through PennyRouter, a Penny-only install leaves files such as `~/.claude/settings.json`
|
|
113
|
+
untouched and needs no session shutdown. Updating a tool that owns global routing requires
|
|
114
|
+
closing its running sessions, or passing `--allow-running-harnesses`. Unrelated keys and user
|
|
115
|
+
settings inside managed config files are preserved, and re-running `update` is idempotent.
|
|
116
|
+
|
|
117
|
+
Restart Claude Code or Codex afterwards to pick up the refreshed configuration.
|
|
118
|
+
|
|
119
|
+
## Supported Tools
|
|
120
|
+
|
|
121
|
+
- Claude Code
|
|
122
|
+
- Cline (manual setup instructions; no VS Code settings mutation)
|
|
123
|
+
- Codex
|
|
124
|
+
- opencode
|
|
125
|
+
- Windsurf
|
|
126
|
+
- Zed
|
|
127
|
+
- JetBrains CodeGPT (manual setup instructions; no XML mutation)
|
|
128
|
+
- Aider
|
|
129
|
+
|
|
130
|
+
## Penny Models
|
|
131
|
+
|
|
132
|
+
Tools that expose a model picker (e.g. Claude Code `/model`) get four curated choices. The three
|
|
133
|
+
named-model choices PIN the trunk to that exact model — you pick the model, PennyRouter still cuts
|
|
134
|
+
the bill via its side machinery (cache/compaction/swallowed background calls) without switching the
|
|
135
|
+
model you chose. "Penny Custom" is the dynamic option: PennyRouter cost-routes each turn.
|
|
136
|
+
|
|
137
|
+
- Opus 5 (PennyRouter): pins `anthropic/claude-opus-5`
|
|
138
|
+
- Sonnet 5 (PennyRouter): pins `anthropic/claude-sonnet-5`
|
|
139
|
+
- Haiku 4.5 (PennyRouter): pins `anthropic/claude-haiku-4-5-20251001`
|
|
140
|
+
- Fable 5 (PennyRouter): pins `anthropic/claude-fable-5`
|
|
141
|
+
- Penny Custom: `pennyrouter/auto` — dynamic routing on the bundle/profile saved in the user's account
|
|
142
|
+
|
|
143
|
+
## Claude Subscription Auth
|
|
144
|
+
|
|
145
|
+
When installing PennyRouter for Claude Code, the interactive installer offers to route
|
|
146
|
+
Anthropic-native Claude turns through the user's own Claude subscription token. To force this
|
|
147
|
+
in non-interactive installs:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npx pennyrouter install --harness claude-code --anthropic-auth --token <token>
|
|
151
|
+
npx pennyrouter install --harness claude-code --anthropic-api-key <key>
|
|
152
|
+
npx pennyrouter install --harness codex --openai-api-key <key>
|
|
153
|
+
npx pennyrouter install --openrouter-api-key <key>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
If Claude Code is already logged in to a Claude subscription, use Claude Code's token setup
|
|
157
|
+
flow:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
claude setup-token
|
|
161
|
+
ANTHROPIC_AUTH_TOKEN=<token> npx pennyrouter auth anthropic
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Other token sources are supported:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npx pennyrouter auth anthropic --token <token>
|
|
168
|
+
npx pennyrouter auth anthropic --token-command '<command that prints the token>'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
If the separate Anthropic `ant` CLI is installed and logged in, PennyRouter can use it as a
|
|
172
|
+
convenience fallback:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
ant auth login
|
|
176
|
+
npx pennyrouter auth anthropic
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The command stores the Anthropic token encrypted at the gateway. Claude Code keeps only the
|
|
180
|
+
PennyRouter `pr-` bearer in its settings; the gateway retrieves and forwards the stored token
|
|
181
|
+
with the required OAuth beta header and does not deduct PennyRouter credit for successfully
|
|
182
|
+
served Anthropic-subscription calls.
|
|
183
|
+
|
|
184
|
+
On a transient subscription 429/529, the gateway retries the same subscription once. If it
|
|
185
|
+
still fails, it can fall back only to credentials owned by that user: Anthropic API then
|
|
186
|
+
OpenRouter for Claude, or OpenAI API then OpenRouter for Codex. If no such credential is
|
|
187
|
+
configured, the provider error is returned; PennyRouter never changes the payer to itself.
|
|
188
|
+
|
|
189
|
+
PennyRouter also sets `disableClaudeAiConnectors: true` while its custom gateway is installed.
|
|
190
|
+
Claude Code cannot load claude.ai organization connectors when gateway authentication takes
|
|
191
|
+
precedence, and otherwise displays a persistent warning about that state. Making the disablement
|
|
192
|
+
explicit suppresses the warning; locally configured MCP servers are unaffected. Reinstall keeps
|
|
193
|
+
the original user value, and disable or uninstall restores it unless the user changed it later.
|
|
194
|
+
|
|
195
|
+
If the stored token expires during a long-running session, refresh the token source and rerun
|
|
196
|
+
`npx pennyrouter auth anthropic`.
|
|
197
|
+
|
|
198
|
+
## Agent Flow
|
|
199
|
+
|
|
200
|
+
Users can ask a coding agent to follow:
|
|
201
|
+
|
|
202
|
+
```text
|
|
203
|
+
https://pennyrouter.com/install
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
That machine-readable page tells the agent to invoke this CLI instead of editing config files
|
|
207
|
+
directly.
|
|
208
|
+
|
|
209
|
+
## What It Changes
|
|
210
|
+
|
|
211
|
+
The CLI installs its managed launcher under `~/.local`, writes only selected local tool
|
|
212
|
+
configuration or per-command overlay files, saves backups under the local PennyRouter state
|
|
213
|
+
directory, and records an uninstall manifest.
|
|
214
|
+
|
|
215
|
+
`disable` temporarily removes PennyRouter from selected tools while retaining a local
|
|
216
|
+
PennyRouter-managed snapshot for `enable`.
|
|
217
|
+
|
|
218
|
+
`update` rewrites those same managed files for the installed version without re-authorizing,
|
|
219
|
+
and without changing bare-command routing or stored credentials.
|
|
220
|
+
|
|
221
|
+
It does not delete PennyRouter accounts, credits, or remote API keys.
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|
package/bin/penny.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { runPenny } from "../src/launch.js";
|
|
3
|
-
|
|
4
|
-
runPenny().then((code) => {
|
|
5
|
-
process.exitCode = code;
|
|
6
|
-
}).catch((error) => {
|
|
7
|
-
console.error(error?.message || String(error));
|
|
8
|
-
process.exitCode = 1;
|
|
9
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runPenny } from "../src/launch.js";
|
|
3
|
+
|
|
4
|
+
runPenny().then((code) => {
|
|
5
|
+
process.exitCode = code;
|
|
6
|
+
}).catch((error) => {
|
|
7
|
+
console.error(error?.message || String(error));
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
});
|
package/bin/pennyrouter.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { main } from "../src/cli.js";
|
|
3
|
-
|
|
4
|
-
main().catch((error) => {
|
|
5
|
-
console.error(error?.message || String(error));
|
|
6
|
-
process.exitCode = 1;
|
|
7
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { main } from "../src/cli.js";
|
|
3
|
+
|
|
4
|
+
main().catch((error) => {
|
|
5
|
+
console.error(error?.message || String(error));
|
|
6
|
+
process.exitCode = 1;
|
|
7
|
+
});
|
package/package.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pennyrouter",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Install and manage PennyRouter local coding-agent integrations.",
|
|
5
|
-
"homepage": "https://pennyrouter.com",
|
|
6
|
-
"bugs": {
|
|
7
|
-
"url": "https://github.com/jduke99/pennyrouter-cli/issues"
|
|
8
|
-
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/jduke99/pennyrouter-cli.git"
|
|
12
|
-
},
|
|
13
|
-
"type": "module",
|
|
14
|
-
"bin": {
|
|
15
|
-
"pennyrouter": "bin/pennyrouter.js"
|
|
16
|
-
},
|
|
17
|
-
"engines": {
|
|
18
|
-
"node": ">=18"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"bin",
|
|
22
|
-
"src",
|
|
23
|
-
"README.md"
|
|
24
|
-
],
|
|
25
|
-
"scripts": {
|
|
26
|
-
"start": "node ./bin/pennyrouter.js",
|
|
27
|
-
"check": "node --check ./bin/pennyrouter.js && node --check ./bin/penny.js && find src -name '*.js' -print0 | xargs -0 -n1 node --check && node src/session.test.js && node src/statusline.test.js && node src/harnesses/claude-code.test.js && node src/harnesses/codex.test.js && node src/launch.test.js"
|
|
28
|
-
},
|
|
29
|
-
"license": "MIT"
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pennyrouter",
|
|
3
|
+
"version": "0.2.10",
|
|
4
|
+
"description": "Install and manage PennyRouter local coding-agent integrations.",
|
|
5
|
+
"homepage": "https://pennyrouter.com",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/jduke99/pennyrouter-cli/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/jduke99/pennyrouter-cli.git"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"bin": {
|
|
15
|
+
"pennyrouter": "bin/pennyrouter.js"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"bin",
|
|
22
|
+
"src",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"start": "node ./bin/pennyrouter.js",
|
|
27
|
+
"check": "node --check ./bin/pennyrouter.js && node --check ./bin/penny.js && find src -name '*.js' -print0 | xargs -0 -n1 node --check && node src/session.test.js && node src/statusline.test.js && node src/harnesses/claude-code.test.js && node src/harnesses/codex.test.js && node src/launch.test.js && node src/thread-session.test.js && node src/mcp.test.js"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT"
|
|
30
|
+
}
|