pennyrouter 0.2.35 → 0.3.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +47 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pennyrouter",
3
- "version": "0.2.35",
3
+ "version": "0.3.1",
4
4
  "description": "Install and manage PennyRouter local coding-agent integrations.",
5
5
  "homepage": "https://pennyrouter.com",
6
6
  "bugs": {
package/src/cli.js CHANGED
@@ -185,8 +185,18 @@ function parseArgs(argv) {
185
185
  else if (arg.startsWith("--harness=")) flags.harness = arg.slice("--harness=".length);
186
186
  else if (arg === "--app-url") flags.appUrl = rest[++i] || "";
187
187
  else if (arg.startsWith("--app-url=")) flags.appUrl = arg.slice("--app-url=".length);
188
- else if (arg === "--gateway-base-url") flags.gatewayBaseUrl = rest[++i] || "";
189
- else if (arg.startsWith("--gateway-base-url=")) flags.gatewayBaseUrl = arg.slice("--gateway-base-url=".length);
188
+ // A --gateway-base-url is a *private* gateway: an admin-run deployment that issues its own
189
+ // keys. Flag it so install can require the matching admin-issued key. --local/--prod are
190
+ // developer shortcuts against gateways that honor prod keys, so they do not set this.
191
+ else if (arg === "--gateway-base-url") { flags.gatewayBaseUrl = rest[++i] || ""; flags.privateGateway = true; }
192
+ else if (arg.startsWith("--gateway-base-url=")) {
193
+ flags.gatewayBaseUrl = arg.slice("--gateway-base-url=".length);
194
+ flags.privateGateway = true;
195
+ }
196
+ // Admin-issued key for a private gateway (see scripts/provision_local_key.py). Overrides the
197
+ // key returned by the browser claim, which is only valid against the hosted gateway.
198
+ else if (arg === "--private-key") flags.privateKey = rest[++i] || "";
199
+ else if (arg.startsWith("--private-key=")) flags.privateKey = arg.slice("--private-key=".length);
190
200
  // --local: point the installed harness at a locally-running gateway (default
191
201
  // http://localhost:8400), for developing/testing against your own gateway. Auth still goes
192
202
  // to prod (pennyrouter.com) so you get a real key; only the harness's serving URL is local.
@@ -608,7 +618,35 @@ export async function install(flags = {}) {
608
618
  const privateGateway = (await promptText(
609
619
  "PennyRouter gateway URL for this proxy (blank for hosted gateway): ",
610
620
  )).trim();
611
- if (privateGateway) gatewayBaseUrl = privateGateway;
621
+ if (privateGateway) {
622
+ gatewayBaseUrl = privateGateway;
623
+ flags.privateGateway = true;
624
+ }
625
+ }
626
+
627
+ // A private gateway has its own key store, so the hosted key from the browser claim is
628
+ // meaningless there. Require the admin-issued key and use it for every subsequent gateway
629
+ // call (credential storage, probing, harness config).
630
+ if (flags.privateGateway) {
631
+ let privateKey = (flags.privateKey || "").trim();
632
+ if (!privateKey && !flags.yes && input.isTTY && output.isTTY) {
633
+ console.log("");
634
+ console.log(`Private gateway: ${gatewayBaseUrl}`);
635
+ console.log("Your PennyRouter administrator issues keys for this gateway.");
636
+ privateKey = (await promptText("Paste your private gateway key (pr-...): ")).trim();
637
+ }
638
+ if (!privateKey) {
639
+ throw new Error(
640
+ `A private gateway (${gatewayBaseUrl}) needs its own key. `
641
+ + "Ask your PennyRouter administrator for one and pass `--private-key pr-...`.",
642
+ );
643
+ }
644
+ if (!privateKey.startsWith("pr-")) {
645
+ throw new Error(`That does not look like a PennyRouter key — expected it to start with "pr-".`);
646
+ }
647
+ claim.api_key = privateKey;
648
+ console.log(`Using private gateway key ${maskKey(privateKey)}.`);
649
+ console.log("");
612
650
  }
613
651
 
614
652
  for (const credential of funding.credentials) {
@@ -2067,7 +2105,7 @@ function printHelp() {
2067
2105
  console.log(`PennyRouter CLI
2068
2106
 
2069
2107
  Usage:
2070
- pennyrouter install [--harness ${SUPPORTED_HARNESS_IDS}] [--all] [--yes] [--dry-run] [--make-default|--penny-only] [--no-path-update] [--no-mcp] [--anthropic-auth|--no-anthropic-auth] [--anthropic-api-key KEY] [--openai-api-key KEY] [--openai-proxy-base-url URL --openai-proxy-api-key KEY] [--openrouter-api-key KEY] [--proxy-base-url URL --proxy-api-key KEY] [--local[=URL]|--prod] [--config PATH]
2108
+ pennyrouter install [--harness ${SUPPORTED_HARNESS_IDS}] [--all] [--yes] [--dry-run] [--make-default|--penny-only] [--no-path-update] [--no-mcp] [--anthropic-auth|--no-anthropic-auth] [--anthropic-api-key KEY] [--openai-api-key KEY] [--openai-proxy-base-url URL --openai-proxy-api-key KEY] [--openrouter-api-key KEY] [--proxy-base-url URL --proxy-api-key KEY] [--gateway-base-url URL --private-key pr-...] [--local[=URL]|--prod] [--config PATH]
2071
2109
  pennyrouter update [--harness ${SUPPORTED_HARNESS_IDS}] [--all] [--dry-run] [--penny-key pr-...] [--gateway-base-url URL|--local[=URL]|--prod] [--no-mcp]
2072
2110
  pennyrouter auth anthropic [--penny-key pr-...] [--token oauth-token] [--token-command CMD] [--gateway-base-url URL] [--forget]
2073
2111
  pennyrouter disable [--harness ${SUPPORTED_HARNESS_IDS}] [--all] [--yes]
@@ -2080,6 +2118,10 @@ When an interactive install selects an Anthropic or OpenAI-compatible proxy, it
2080
2118
  that can reach that proxy. Leave it blank for the hosted gateway, or enter a private/self-hosted
2081
2119
  gateway URL. Use --gateway-base-url (or --local for localhost:8400 development) for non-interactive installs.
2082
2120
 
2121
+ A private gateway keeps its own keys, so the key from the browser login does not work there. Whenever
2122
+ you point install at one — with --gateway-base-url or by entering a URL at that prompt — you must also
2123
+ supply the key your PennyRouter administrator issued you: paste it when asked, or pass --private-key pr-...
2124
+
2083
2125
  Install and update both register the Threads MCP server with Claude Code and Codex (--no-mcp to
2084
2126
  skip a run). Run "pennyrouter mcp install" if you skipped it or had to rename a conflicting
2085
2127
  server, "pennyrouter mcp status" to see whether it is wired up, and "pennyrouter mcp uninstall"
@@ -2110,6 +2152,7 @@ Examples:
2110
2152
  npx pennyrouter install --harness codex --openai-api-key <key>
2111
2153
  npx pennyrouter install --harness claude-code --proxy-base-url https://proxy.example.com --proxy-api-key <key>
2112
2154
  npx pennyrouter install --openrouter-api-key <key>
2155
+ npx pennyrouter install --gateway-base-url https://gateway.internal.example.com --private-key pr-...
2113
2156
  npx pennyrouter auth anthropic
2114
2157
  npx pennyrouter install --all
2115
2158
  npx pennyrouter install --harness windsurf,zed,codegpt,aider --yes