delimit-cli 4.7.2 → 4.7.4

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.
@@ -172,6 +172,31 @@ function loadOrCreateHmacKey() {
172
172
  return key;
173
173
  }
174
174
 
175
+
176
+ function getNextModelInChain(currentModel) {
177
+ const homedir = os.homedir();
178
+ const modelsPath = path.join(homedir, '.delimit', 'models.json');
179
+ if (!fs.existsSync(modelsPath)) return null;
180
+
181
+ try {
182
+ const models = JSON.parse(fs.readFileSync(modelsPath, 'utf-8'));
183
+ // Normalize currentModel (it might be a path)
184
+ const base = path.basename(currentModel).toLowerCase();
185
+
186
+ // Find which chain contains the current model
187
+ // Using 'default' chain for prototype
188
+ const chain = models.fallbacks?.default || [];
189
+ const idx = chain.findIndex(m => m.toLowerCase() === base);
190
+ if (idx !== -1 && idx < chain.length - 1) {
191
+ return chain[idx + 1];
192
+ }
193
+ } catch {
194
+ return null;
195
+ }
196
+ return null;
197
+ }
198
+
199
+
175
200
  function signAttestation(bundle) {
176
201
  const key = loadOrCreateHmacKey();
177
202
  return crypto.createHmac('sha256', key).update(canonicalize(bundle)).digest('hex');
@@ -251,6 +276,8 @@ function suggestHandoff(rawCmd) {
251
276
  aider: ['claude', 'codex', 'gemini'],
252
277
  codex: ['claude', 'gemini', 'cursor'],
253
278
  gemini: ['claude', 'codex', 'cursor'],
279
+ antigravity: ['claude', 'codex', 'gemini'],
280
+ agy: ['claude', 'codex', 'gemini'],
254
281
  };
255
282
  const key = Object.keys(fallbacks).find(k => base.includes(k));
256
283
  if (!key) return null;
@@ -309,6 +336,7 @@ async function runWrap(rawCmd, options = {}) {
309
336
  attest = true,
310
337
  cwd = process.cwd(),
311
338
  maxTimeSeconds = 0, // LED-1052: 0 disables kill switch
339
+ autoPhoenix = false, // LED-3013: automatic model switching
312
340
  } = options;
313
341
 
314
342
  const repoRoot = getRepoRoot(cwd);
@@ -333,20 +361,48 @@ async function runWrap(rawCmd, options = {}) {
333
361
  const beforeDirty = isGitRepo ? getDirtyFiles(repoRoot) : [];
334
362
  const startedAt = new Date().toISOString();
335
363
 
336
- // Execute the wrapped command
337
- // The wrapped command runs in the user's shell so `claude -p "..."` / `cursor edit` / etc. work natively.
338
- // LED-1052: if maxTimeSeconds > 0, use async spawnWithKillSwitch; otherwise spawnSync for back-compat.
364
+ // Execute the wrapped command (with Auto-Phoenix retry loop)
339
365
  let wrappedExit;
340
366
  let killedByTimeout = false;
341
367
  let killSignal = null;
342
- if (maxTimeSeconds > 0) {
343
- const res = await spawnWithKillSwitch(rawCmd[0], rawCmd.slice(1), { cwd: repoRoot, shell: false }, maxTimeSeconds);
344
- wrappedExit = res.status;
345
- killedByTimeout = res.killed_by_timeout;
346
- killSignal = res.signal || null;
347
- } else {
348
- const child = spawnSync(rawCmd[0], rawCmd.slice(1), { cwd: repoRoot, stdio: 'inherit', shell: false });
349
- wrappedExit = child.status ?? 1;
368
+ let currentCmd = [...rawCmd];
369
+ let attempts = 0;
370
+ const maxAttempts = autoPhoenix ? 3 : 1;
371
+ const chalk = require('chalk');
372
+
373
+ while (attempts < maxAttempts) {
374
+ attempts++;
375
+ if (attempts > 1) {
376
+ console.log(chalk.blue(`\n Auto-Phoenix: Retrying with next model (Attempt ${attempts}/${maxAttempts})...`));
377
+ }
378
+
379
+ if (maxTimeSeconds > 0) {
380
+ const res = await spawnWithKillSwitch(currentCmd[0], currentCmd.slice(1), { cwd: repoRoot, shell: false }, maxTimeSeconds);
381
+ wrappedExit = res.status;
382
+ killedByTimeout = res.killed_by_timeout;
383
+ killSignal = res.signal || null;
384
+ } else {
385
+ const child = spawnSync(currentCmd[0], currentCmd.slice(1), { cwd: repoRoot, stdio: 'inherit', shell: false });
386
+ wrappedExit = child.status ?? 1;
387
+ }
388
+
389
+ if (wrappedExit === 0) break;
390
+ if (!autoPhoenix) break;
391
+
392
+ // Migration logic
393
+ const nextModel = getNextModelInChain(currentCmd[0]);
394
+ if (!nextModel) break;
395
+
396
+ console.log(chalk.yellow(`\n ⚠ Task failed (exit ${wrappedExit}). Auto-Phoenix initiating migration...`));
397
+
398
+ // 1. Capture Soul
399
+ runDelimitCLI(['soul-capture', '--active-task', `Auto-Phoenix migration: ${currentCmd.join(' ')}`], repoRoot);
400
+
401
+ // 2. Update command for next iteration
402
+ console.log(chalk.green(` ✓ Migrating session to ${chalk.bold(nextModel)}...`));
403
+ currentCmd[0] = nextModel;
404
+ // In prototype, we don't automatically add --revive because we don't know the CLI arg schema of nextModel
405
+ // but we've logged the soul capture which the next agent can find.
350
406
  }
351
407
  const completedAt = new Date().toISOString();
352
408
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "delimit-cli",
3
3
  "mcpName": "io.github.delimit-ai/delimit-mcp-server",
4
- "version": "4.7.2",
4
+ "version": "4.7.4",
5
5
  "description": "Unify Claude Code, Codex, Cursor, and Gemini CLI with persistent context, governance, and multi-model debate.",
6
6
  "main": "index.js",
7
7
  "files": [
package/server.json CHANGED
@@ -7,13 +7,13 @@
7
7
  "url": "https://github.com/delimit-ai/delimit-mcp-server",
8
8
  "source": "github"
9
9
  },
10
- "version": "4.5.13",
10
+ "version": "4.7.3",
11
11
  "websiteUrl": "https://delimit.ai",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "identifier": "delimit-cli",
16
- "version": "4.5.13",
16
+ "version": "4.7.3",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }