@amenophis1er/foreman 0.1.10 → 0.1.12

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
@@ -230,7 +230,7 @@ result.
230
230
  ```sh
231
231
  npm ci && npm run setup # dependencies, then the dashboard build
232
232
  npm start # serves http://localhost:4177
233
- npm test # 364 tests, node:test
233
+ npm test # 365 tests, node:test
234
234
  npm run typecheck # server and dashboard
235
235
  npm run dev # API + Vite together
236
236
  scripts/dev-restart.sh # restarts the server only when nothing would be lost
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amenophis1er/foreman",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Autonomous mission runner on the Claude Agent SDK: a director plans, delegates to workers, verifies, and reports — from one dashboard, your phone, or the CLI.",
5
5
  "keywords": [
6
6
  "claude",
@@ -364,3 +364,19 @@ test('a role provider carries the role’s model, so every alias resolves on its
364
364
  assert.equal(withRoleModel(bare, '').model, undefined);
365
365
  assert.equal(withRoleModel(bare, undefined), bare, 'no change returns the same object');
366
366
  });
367
+
368
+
369
+ test('agents do not inherit the server\'s own environment: PORT and FOREMAN_* are dropped', async () => {
370
+ const saved = { PORT: process.env.PORT, FOREMAN_HOME: process.env.FOREMAN_HOME, FOREMAN_BIND: process.env.FOREMAN_BIND };
371
+ process.env.PORT = '4177'; process.env.FOREMAN_HOME = '/tmp/fh'; process.env.FOREMAN_BIND = 'all';
372
+ try {
373
+ const p = await resolveProvider({ kind: 'claude-code' }, '/tmp/foreman-test-root');
374
+ const env = providerEnv(p).env ?? {};
375
+ assert.equal(env.PORT, undefined, 'a dev server a worker starts must not bind the dashboard port');
376
+ assert.equal(env.FOREMAN_HOME, undefined);
377
+ assert.equal(env.FOREMAN_BIND, undefined);
378
+ assert.ok(env.PATH, 'the rest of the environment survives');
379
+ } finally {
380
+ for (const [k, v] of Object.entries(saved)) { if (v === undefined) delete process.env[k]; else process.env[k] = v; }
381
+ }
382
+ });
package/src/provider.ts CHANGED
@@ -427,8 +427,22 @@ export interface AgentEnv {
427
427
  * programming error rather than a user error, and the failure mode it guards
428
428
  * against is a leaked token, so it fails loudly instead of degrading.
429
429
  */
430
+ /**
431
+ * The server's own knobs, which an agent must not inherit. `PORT` is the one
432
+ * that bit: the service sets it for the dashboard, an agent's dev server
433
+ * honoured it, bound Foreman's port on a wildcard address and shadowed the
434
+ * dashboard on localhost until it exited. The rest are Foreman's operating
435
+ * settings — none of them means anything to a project's own tooling, and a
436
+ * worker reading `FOREMAN_HOME` would only find somewhere it should not be.
437
+ */
438
+ const SERVER_ONLY_VARS = [
439
+ 'PORT', 'FOREMAN_SERVICES_PORT', 'FOREMAN_HOME', 'FOREMAN_BIND', 'FOREMAN_BROWSER',
440
+ 'FOREMAN_AUTH_MODE', 'FOREMAN_CLAUDE_CONFIG_DIR', 'FOREMAN_CLAUDE_EXECUTABLE', 'FOREMAN_NO_TELEGRAM', 'FOREMAN_LOG',
441
+ ];
442
+
430
443
  export function providerEnv(p: ResolvedProvider, gatewayUrl?: string): AgentEnv {
431
444
  const env: Record<string, string | undefined> = { ...process.env };
445
+ for (const v of SERVER_ONLY_VARS) delete env[v];
432
446
  env.CLAUDE_CONFIG_DIR = p.configDir;
433
447
 
434
448
  if (p.wire === 'anthropic-native') {