kiro-spec-engine 1.45.1 → 1.45.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/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.45.2] - 2026-02-13
11
+
12
+ ### Fixed
13
+ - **AgentSpawner auth fallback**: Added `~/.codex/auth.json` fallback when `CODEX_API_KEY` env var is not set, supporting users who configured auth via `codex auth`
14
+ - **AgentSpawner codex command**: Added `codexCommand` config option (e.g. `"npx @openai/codex"`) for users without global Codex CLI install
15
+ - **OrchestratorConfig**: Added `codexCommand` to known config keys and defaults
16
+
10
17
  ## [1.45.1] - 2026-02-12
11
18
 
12
19
  ### Fixed
@@ -13,6 +13,9 @@
13
13
 
14
14
  const { EventEmitter } = require('events');
15
15
  const { spawn } = require('child_process');
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const os = require('os');
16
19
 
17
20
  class AgentSpawner extends EventEmitter {
18
21
  /**
@@ -45,12 +48,16 @@ class AgentSpawner extends EventEmitter {
45
48
  async spawn(specName) {
46
49
  const config = await this._orchestratorConfig.getConfig();
47
50
 
48
- // Validate API key availability (Req 1.2)
51
+ // Resolve API key: env var → ~/.codex/auth.json fallback
49
52
  const apiKeyEnvVar = config.apiKeyEnvVar || 'CODEX_API_KEY';
50
- if (!process.env[apiKeyEnvVar]) {
53
+ let apiKey = process.env[apiKeyEnvVar];
54
+ if (!apiKey) {
55
+ apiKey = this._readCodexAuthFile();
56
+ }
57
+ if (!apiKey) {
51
58
  throw new Error(
52
- `Environment variable ${apiKeyEnvVar} is not set. ` +
53
- 'Cannot start Codex CLI without authentication.'
59
+ `Cannot find API key. Set environment variable ${apiKeyEnvVar}, ` +
60
+ 'or configure Codex CLI auth via `codex auth` (~/.codex/auth.json).'
54
61
  );
55
62
  }
56
63
 
@@ -72,13 +79,17 @@ class AgentSpawner extends EventEmitter {
72
79
  prompt,
73
80
  ];
74
81
 
82
+ // Resolve codex command: config → auto-detect
83
+ const { command, prependArgs } = this._resolveCodexCommand(config);
84
+
75
85
  // Spawn the child process (Req 1.1, 1.2)
76
- const env = { ...process.env, [apiKeyEnvVar]: process.env[apiKeyEnvVar] };
77
- const child = spawn('codex', args, {
86
+ const env = { ...process.env, [apiKeyEnvVar]: apiKey };
87
+ const child = spawn(command, [...prependArgs, ...args], {
78
88
  cwd: this._workspaceRoot,
79
89
  env,
80
90
  stdio: ['ignore', 'pipe', 'pipe'],
81
91
  windowsHide: true,
92
+ shell: command === 'npx',
82
93
  });
83
94
 
84
95
  const now = new Date().toISOString();
@@ -373,6 +384,49 @@ class AgentSpawner extends EventEmitter {
373
384
  );
374
385
  }
375
386
  }
387
+
388
+ /**
389
+ * Read API key from Codex CLI's native auth file (~/.codex/auth.json).
390
+ * Returns the key string or null if not found.
391
+ *
392
+ * @returns {string|null}
393
+ * @private
394
+ */
395
+ _readCodexAuthFile() {
396
+ try {
397
+ const authPath = path.join(os.homedir(), '.codex', 'auth.json');
398
+ if (!fs.existsSync(authPath)) {
399
+ return null;
400
+ }
401
+ const auth = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
402
+ return auth.OPENAI_API_KEY || auth.CODEX_API_KEY || null;
403
+ } catch (_err) {
404
+ return null;
405
+ }
406
+ }
407
+
408
+ /**
409
+ * Resolve the codex command and any prepended arguments.
410
+ *
411
+ * Priority:
412
+ * 1. config.codexCommand (user-specified, e.g. "npx @openai/codex" or "codex")
413
+ * 2. "codex" (default — assumes global install)
414
+ *
415
+ * When codexCommand contains spaces (e.g. "npx @openai/codex"),
416
+ * the first token becomes the command and the rest become prependArgs.
417
+ *
418
+ * @param {object} config
419
+ * @returns {{ command: string, prependArgs: string[] }}
420
+ * @private
421
+ */
422
+ _resolveCodexCommand(config) {
423
+ const raw = config.codexCommand || 'codex';
424
+ const parts = raw.trim().split(/\s+/);
425
+ return {
426
+ command: parts[0],
427
+ prependArgs: parts.slice(1),
428
+ };
429
+ }
376
430
  }
377
431
 
378
432
  module.exports = { AgentSpawner };
@@ -27,6 +27,7 @@ const KNOWN_KEYS = new Set([
27
27
  'apiKeyEnvVar',
28
28
  'bootstrapTemplate',
29
29
  'codexArgs',
30
+ 'codexCommand',
30
31
  ]);
31
32
 
32
33
  /** @type {import('./orchestrator-config').OrchestratorConfigData} */
@@ -38,6 +39,7 @@ const DEFAULT_CONFIG = Object.freeze({
38
39
  apiKeyEnvVar: 'CODEX_API_KEY',
39
40
  bootstrapTemplate: null,
40
41
  codexArgs: [],
42
+ codexCommand: null,
41
43
  });
42
44
 
43
45
  class OrchestratorConfig {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiro-spec-engine",
3
- "version": "1.45.1",
3
+ "version": "1.45.2",
4
4
  "description": "kiro-spec-engine (kse) - A CLI tool and npm package for spec-driven development with AI coding assistants. NOT the Kiro IDE desktop application.",
5
5
  "main": "index.js",
6
6
  "bin": {