@chatpanel/gateway 0.1.1 → 0.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/gateway",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Local privacy gateway — redacts PII out of OpenAI/Anthropic API traffic before it reaches a model, then restores it in the reply. Point opencode, codex, aider, Claude Code, etc. at it.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/config.js CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { readFileSync, existsSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
+ import os from 'node:os';
10
11
 
11
12
  const DEFAULTS = {
12
13
  host: '127.0.0.1',
@@ -100,7 +101,9 @@ function deepMerge(base, over) {
100
101
  export function loadConfig(env = process.env) {
101
102
  let cfg = DEFAULTS;
102
103
 
103
- const path = env.CHATPANEL_GATEWAY_CONFIG || join(process.cwd(), 'gateway.config.json');
104
+ // Writable per-user location by default (NOT cwd — a login service runs with
105
+ // cwd "/", which is read-only). Same path persistConfig() writes to.
106
+ const path = env.CHATPANEL_GATEWAY_CONFIG || join(os.homedir(), '.chatpanel', 'gateway.config.json');
104
107
  if (existsSync(path)) {
105
108
  try {
106
109
  cfg = deepMerge(cfg, JSON.parse(readFileSync(path, 'utf8')));
@@ -2,15 +2,19 @@
2
2
  // configure it live over the localhost API (GET/POST /config). The gateway stays
3
3
  // authoritative — the extension is just a UI client.
4
4
 
5
- import { writeFileSync } from 'node:fs';
6
- import { join } from 'node:path';
5
+ import { writeFileSync, mkdirSync } from 'node:fs';
6
+ import { join, dirname } from 'node:path';
7
+ import os from 'node:os';
7
8
 
9
+ // Default to a writable per-user location, NOT process.cwd(): when the gateway
10
+ // runs as a login service its cwd is "/" (read-only → EROFS on save).
8
11
  export function configPath(env = process.env) {
9
- return env.CHATPANEL_GATEWAY_CONFIG || join(process.cwd(), 'gateway.config.json');
12
+ return env.CHATPANEL_GATEWAY_CONFIG || join(os.homedir(), '.chatpanel', 'gateway.config.json');
10
13
  }
11
14
 
12
15
  // Persist the user-editable subset (not derived runtime state).
13
16
  export function persistConfig(cfg, path = configPath()) {
17
+ mkdirSync(dirname(path), { recursive: true });
14
18
  const out = {
15
19
  host: cfg.host, port: cfg.port, backend: cfg.backend,
16
20
  bridge: cfg.bridge, upstreams: cfg.upstreams, redaction: cfg.redaction,
package/src/ner.js CHANGED
@@ -68,7 +68,10 @@ export function startNer(cfg) {
68
68
  });
69
69
 
70
70
  // Poll for readiness without blocking server start; wire detection when up.
71
+ // `stopped` MUST be declared before the async poller below references it (else a
72
+ // temporal-dead-zone ReferenceError crashes startup when autostart is on).
71
73
  const ac = new AbortController();
74
+ let stopped = false;
72
75
  (async () => {
73
76
  const deadline = Date.now() + 120_000; // generous: first run installs deps
74
77
  while (Date.now() < deadline && !stopped) {
@@ -88,7 +91,6 @@ export function startNer(cfg) {
88
91
  if (!stopped) console.log('[ner] not ready after 120s — continuing deterministic-only (run ./ner/run.sh manually to debug).');
89
92
  })();
90
93
 
91
- let stopped = false;
92
94
  const stop = () => {
93
95
  if (stopped) return;
94
96
  stopped = true;
package/src/server.js CHANGED
@@ -31,7 +31,7 @@ import * as openai from './openai.js';
31
31
  import * as responses from './responses.js';
32
32
  import * as anthropic from './anthropic.js';
33
33
 
34
- export const VERSION = '0.1.1';
34
+ export const VERSION = '0.1.3';
35
35
 
36
36
  const KNOWN_AGENTS = new Set(['codex', 'claude', 'opencode', 'pi', 'kiro', 'antigravity']);
37
37