@victor-software-house/pi-openai-proxy 0.2.0 → 0.2.2

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 CHANGED
@@ -231,7 +231,7 @@ pi install npm:@victor-software-house/pi-openai-proxy
231
231
 
232
232
  `/proxy` (or `/proxy config`) opens an interactive settings panel where you can configure the bind address, port, auth token, remote images, body size limit, and upstream timeout. Changes are saved to `~/.pi/agent/proxy-config.json` immediately. Restart the proxy to apply changes.
233
233
 
234
- ### Auto-start with pi
234
+ ### Auto-start with a pi session
235
235
 
236
236
  ```bash
237
237
  pi --proxy
@@ -239,7 +239,24 @@ pi --proxy
239
239
 
240
240
  The proxy starts automatically on session start and stops when the session ends. A status indicator in the footer shows the proxy URL and model count.
241
241
 
242
- The proxy can also run standalone (see [Installation](#installation) above). The extension detects externally running instances and shows their status without trying to manage them.
242
+ Note: the `--proxy` flag is registered by the extension at runtime and does not appear in `pi --help`.
243
+
244
+ ### Standalone (background) mode
245
+
246
+ For a proxy that outlives pi sessions, run the binary directly:
247
+
248
+ ```bash
249
+ # Foreground
250
+ pi-openai-proxy
251
+
252
+ # Background
253
+ pi-openai-proxy &
254
+
255
+ # With custom port
256
+ PI_PROXY_PORT=8080 pi-openai-proxy &
257
+ ```
258
+
259
+ The extension detects externally running instances and shows their status via `/proxy status` without trying to manage them.
243
260
 
244
261
  ## Architecture
245
262
 
@@ -359,10 +359,12 @@ export default function proxyExtension(pi: ExtensionAPI): void {
359
359
 
360
360
  async function showConfig(ctx: ExtensionContext): Promise<void> {
361
361
  config = loadConfig();
362
+ const authDisplay =
363
+ config.authToken.length > 0 ? `enabled (token: ${config.authToken})` : "disabled";
362
364
  const lines = [
363
365
  `host: ${config.host}`,
364
366
  `port: ${String(config.port)}`,
365
- `auth: ${config.authToken.length > 0 ? "enabled" : "disabled"}`,
367
+ `auth: ${authDisplay}`,
366
368
  `remote images: ${String(config.remoteImages)}`,
367
369
  `max body: ${String(config.maxBodySizeMb)} MB`,
368
370
  `upstream timeout: ${String(config.upstreamTimeoutSec)}s`,
@@ -391,6 +393,8 @@ export default function proxyExtension(pi: ExtensionAPI): void {
391
393
 
392
394
  // --- Settings panel ---
393
395
 
396
+ let lastGeneratedToken = "";
397
+
394
398
  function buildSettingItems(): SettingItem[] {
395
399
  return [
396
400
  {
@@ -410,7 +414,10 @@ export default function proxyExtension(pi: ExtensionAPI): void {
410
414
  {
411
415
  id: "authToken",
412
416
  label: "Proxy auth",
413
- description: "Require bearer token for all requests",
417
+ description:
418
+ config.authToken.length > 0
419
+ ? `Token: ${config.authToken.slice(0, 8)}... (use /proxy show to copy)`
420
+ : "Require bearer token for all requests",
414
421
  currentValue: config.authToken.length > 0 ? "enabled" : "disabled",
415
422
  values: ["disabled", "enabled"],
416
423
  },
@@ -447,17 +454,21 @@ export default function proxyExtension(pi: ExtensionAPI): void {
447
454
  config = { ...config, port: clampInt(Number.parseInt(value, 10), 1, 65535, config.port) };
448
455
  break;
449
456
  case "authToken":
450
- // Toggle: "enabled" keeps current token or sets placeholder; "disabled" clears
457
+ // Toggle: "enabled" keeps current token or generates one; "disabled" clears
451
458
  if (value === "disabled") {
452
459
  config = { ...config, authToken: "" };
453
460
  } else if (config.authToken.length === 0) {
454
461
  // Generate a random token on first enable
455
462
  const bytes = new Uint8Array(16);
456
463
  crypto.getRandomValues(bytes);
457
- const token = Array.from(bytes)
458
- .map((b) => b.toString(16).padStart(2, "0"))
459
- .join("");
460
- config = { ...config, authToken: token };
464
+ config = {
465
+ ...config,
466
+ authToken: Array.from(bytes)
467
+ .map((b) => b.toString(16).padStart(2, "0"))
468
+ .join(""),
469
+ };
470
+ // Stash token so the caller can notify the user
471
+ lastGeneratedToken = config.authToken;
461
472
  }
462
473
  break;
463
474
  case "remoteImages":
@@ -483,42 +494,51 @@ export default function proxyExtension(pi: ExtensionAPI): void {
483
494
 
484
495
  await ctx.ui.custom<void>(
485
496
  (tui, theme, _kb, done) => {
486
- const container = new Container();
487
- container.addChild(new Text(theme.fg("accent", theme.bold("Proxy Settings")), 1, 0));
488
- container.addChild(new Text(theme.fg("dim", getConfigPath()), 1, 0));
489
-
490
- const settingsList = new SettingsList(
491
- buildSettingItems(),
492
- 10,
493
- getSettingsListTheme(),
494
- (id, newValue) => {
495
- applySetting(id, newValue);
496
- // Rebuild items to reflect normalized values
497
- settingsList.setItems(buildSettingItems());
498
- tui.requestRender();
499
- },
500
- () => done(undefined),
501
- { enableSearch: true },
502
- );
497
+ function build(): { container: Container; settingsList: SettingsList } {
498
+ const container = new Container();
499
+ container.addChild(new Text(theme.fg("accent", theme.bold("Proxy Settings")), 1, 0));
500
+ container.addChild(new Text(theme.fg("dim", getConfigPath()), 1, 0));
501
+
502
+ const settingsList = new SettingsList(
503
+ buildSettingItems(),
504
+ 10,
505
+ getSettingsListTheme(),
506
+ (id, newValue) => {
507
+ lastGeneratedToken = "";
508
+ applySetting(id, newValue);
509
+ if (lastGeneratedToken.length > 0) {
510
+ ctx.ui.notify(`Auth token: ${lastGeneratedToken}`, "info");
511
+ }
512
+ current = build();
513
+ tui.requestRender();
514
+ },
515
+ () => done(undefined),
516
+ { enableSearch: true },
517
+ );
518
+
519
+ container.addChild(settingsList);
520
+ container.addChild(
521
+ new Text(
522
+ theme.fg("dim", "Esc: close | Arrow keys: navigate | Space: toggle | Restart proxy to apply"),
523
+ 1,
524
+ 0,
525
+ ),
526
+ );
527
+
528
+ return { container, settingsList };
529
+ }
503
530
 
504
- container.addChild(settingsList);
505
- container.addChild(
506
- new Text(
507
- theme.fg("dim", "Esc: close | Arrow keys: navigate | Space: toggle | Restart proxy to apply"),
508
- 1,
509
- 0,
510
- ),
511
- );
531
+ let current = build();
512
532
 
513
533
  return {
514
534
  render(width: number): string[] {
515
- return container.render(width);
535
+ return current.container.render(width);
516
536
  },
517
537
  invalidate(): void {
518
- container.invalidate();
538
+ current.container.invalidate();
519
539
  },
520
540
  handleInput(data: string): void {
521
- settingsList.handleInput?.(data);
541
+ current.settingsList.handleInput?.(data);
522
542
  tui.requestRender();
523
543
  },
524
544
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@victor-software-house/pi-openai-proxy",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Local OpenAI-compatible HTTP proxy built on pi's SDK",
5
5
  "license": "MIT",
6
6
  "author": "Victor Software House",