fixo-cli 1.0.2 → 1.0.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.
Files changed (82) hide show
  1. package/dist/agent/agent-client.d.ts +3 -0
  2. package/dist/agent/agent-client.d.ts.map +1 -1
  3. package/dist/agent/agent-client.js +63 -9
  4. package/dist/agent/agent-client.js.map +1 -1
  5. package/dist/agent/command-parser.d.ts +37 -0
  6. package/dist/agent/command-parser.d.ts.map +1 -1
  7. package/dist/agent/command-parser.js +297 -1
  8. package/dist/agent/command-parser.js.map +1 -1
  9. package/dist/agent/conversation.d.ts +18 -1
  10. package/dist/agent/conversation.d.ts.map +1 -1
  11. package/dist/agent/conversation.js +31 -2
  12. package/dist/agent/conversation.js.map +1 -1
  13. package/dist/agent/duration.d.ts +24 -0
  14. package/dist/agent/duration.d.ts.map +1 -0
  15. package/dist/agent/duration.js +42 -0
  16. package/dist/agent/duration.js.map +1 -0
  17. package/dist/agent/file-writing-rules.d.ts +19 -0
  18. package/dist/agent/file-writing-rules.d.ts.map +1 -0
  19. package/dist/agent/file-writing-rules.js +31 -0
  20. package/dist/agent/file-writing-rules.js.map +1 -0
  21. package/dist/agent/parser-adapter.d.ts.map +1 -1
  22. package/dist/agent/parser-adapter.js +57 -5
  23. package/dist/agent/parser-adapter.js.map +1 -1
  24. package/dist/agent/provider-cooldown.d.ts.map +1 -1
  25. package/dist/agent/provider-cooldown.js +3 -2
  26. package/dist/agent/provider-cooldown.js.map +1 -1
  27. package/dist/agent/providers-manager.d.ts +6 -0
  28. package/dist/agent/providers-manager.d.ts.map +1 -1
  29. package/dist/agent/providers-manager.js +20 -0
  30. package/dist/agent/providers-manager.js.map +1 -1
  31. package/dist/agent/single-agent.d.ts +25 -0
  32. package/dist/agent/single-agent.d.ts.map +1 -1
  33. package/dist/agent/single-agent.js +136 -27
  34. package/dist/agent/single-agent.js.map +1 -1
  35. package/dist/agent/telemetry.d.ts.map +1 -1
  36. package/dist/agent/telemetry.js +4 -1
  37. package/dist/agent/telemetry.js.map +1 -1
  38. package/dist/agent/tool-executor.d.ts +5 -0
  39. package/dist/agent/tool-executor.d.ts.map +1 -1
  40. package/dist/agent/tool-executor.js +17 -4
  41. package/dist/agent/tool-executor.js.map +1 -1
  42. package/dist/agent/worker-agent.d.ts +8 -0
  43. package/dist/agent/worker-agent.d.ts.map +1 -1
  44. package/dist/agent/worker-agent.js +25 -3
  45. package/dist/agent/worker-agent.js.map +1 -1
  46. package/dist/config.d.ts +11 -1
  47. package/dist/config.d.ts.map +1 -1
  48. package/dist/config.js +2 -1
  49. package/dist/config.js.map +1 -1
  50. package/dist/index.js +5 -1
  51. package/dist/index.js.map +1 -1
  52. package/dist/project-memory.d.ts +1 -2
  53. package/dist/project-memory.d.ts.map +1 -1
  54. package/dist/project-memory.js +13 -1
  55. package/dist/project-memory.js.map +1 -1
  56. package/dist/runtime/loop-mitigation.d.ts +48 -0
  57. package/dist/runtime/loop-mitigation.d.ts.map +1 -0
  58. package/dist/runtime/loop-mitigation.js +79 -0
  59. package/dist/runtime/loop-mitigation.js.map +1 -0
  60. package/dist/runtime/session-snapshots.d.ts +52 -2
  61. package/dist/runtime/session-snapshots.d.ts.map +1 -1
  62. package/dist/runtime/session-snapshots.js +76 -1
  63. package/dist/runtime/session-snapshots.js.map +1 -1
  64. package/dist/setup-wizard.d.ts +1 -0
  65. package/dist/setup-wizard.d.ts.map +1 -1
  66. package/dist/setup-wizard.js +42 -1
  67. package/dist/setup-wizard.js.map +1 -1
  68. package/dist/ui/prompt.d.ts.map +1 -1
  69. package/dist/ui/prompt.js +195 -10
  70. package/dist/ui/prompt.js.map +1 -1
  71. package/dist/ui/render-primitives.d.ts +20 -0
  72. package/dist/ui/render-primitives.d.ts.map +1 -1
  73. package/dist/ui/render-primitives.js +41 -0
  74. package/dist/ui/render-primitives.js.map +1 -1
  75. package/dist/ui/session-header.d.ts +13 -0
  76. package/dist/ui/session-header.d.ts.map +1 -1
  77. package/dist/ui/session-header.js +6 -0
  78. package/dist/ui/session-header.js.map +1 -1
  79. package/package.json +6 -2
  80. package/scripts/check-vendor-wasm.js +44 -0
  81. package/vendor/tree-sitter-bash.wasm +0 -0
  82. package/vendor/tree-sitter.wasm +0 -0
@@ -51,7 +51,7 @@ export function snapshotPath(cwd, id) {
51
51
  return path.join(dirForCwd(cwd), `${id}.json`);
52
52
  }
53
53
  export function saveSnapshot(input, now = new Date()) {
54
- const id = makeSnapshotId(now);
54
+ const id = input.id ?? makeSnapshotId(now);
55
55
  const file = snapshotPath(input.cwd, id);
56
56
  const dir = path.dirname(file);
57
57
  try {
@@ -73,6 +73,7 @@ export function saveSnapshot(input, now = new Date()) {
73
73
  mode: input.mode,
74
74
  selectedFiles: input.selectedFiles,
75
75
  summary: input.summary,
76
+ label: input.label,
76
77
  fixedInstructions: input.fixedInstructions,
77
78
  todo,
78
79
  };
@@ -154,6 +155,7 @@ export function listSnapshots(cwd) {
154
155
  tokens: typeof obj.tokens === 'number' ? obj.tokens : 0,
155
156
  items,
156
157
  summary: typeof obj.summary === 'string' ? obj.summary : undefined,
158
+ label: typeof obj.label === 'string' ? obj.label : undefined,
157
159
  });
158
160
  }
159
161
  catch {
@@ -163,4 +165,77 @@ export function listSnapshots(cwd) {
163
165
  out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
164
166
  return out;
165
167
  }
168
+ /* ──────────────────────── rename ──────────────────────── */
169
+ /**
170
+ * Maximum label length. Long enough for "clinic-website-accessibility-audit"
171
+ * but short enough to fit in a session header pill on a 100-col terminal.
172
+ */
173
+ export const MAX_LABEL_LENGTH = 64;
174
+ /**
175
+ * Returns true if the label is safe to store, render, and search.
176
+ *
177
+ * Rules:
178
+ * - 1..MAX_LABEL_LENGTH characters
179
+ * - letters, digits, dash, underscore, dot, and spaces only
180
+ * - no path separators (`/`, `\`) so a label can never affect
181
+ * where the snapshot file lives on disk
182
+ * - no shell metacharacters (backtick, `$`, `;`, `|`, `&`, `<`, `>`)
183
+ * so a future render path that interpolates the label cannot be
184
+ * hijacked
185
+ *
186
+ * The validator is conservative on purpose — labels are user-facing,
187
+ * not creative writing. The file id stays as the durable identifier.
188
+ */
189
+ export function isValidSessionLabel(label) {
190
+ if (typeof label !== 'string')
191
+ return false;
192
+ const trimmed = label.trim();
193
+ if (trimmed.length === 0 || trimmed.length > MAX_LABEL_LENGTH)
194
+ return false;
195
+ // Allow Unicode letters/digits + space + dash + underscore + dot.
196
+ return /^[\p{L}\p{N}._\- ]+$/u.test(trimmed);
197
+ }
198
+ /**
199
+ * Atomically rewrite the `label` field of an existing snapshot.
200
+ * The on-disk file basename (the snapshot id) is **never** renamed —
201
+ * existing `/resume <id>` invocations keep working after a relabel.
202
+ *
203
+ * Pass `label: undefined` to clear an existing label.
204
+ */
205
+ export function renameSnapshot(cwd, id, label) {
206
+ if (label !== undefined && !isValidSessionLabel(label)) {
207
+ return {
208
+ ok: false,
209
+ id,
210
+ error: `invalid label: must be 1..${MAX_LABEL_LENGTH} chars, letters/digits/space/dash/underscore/dot only`,
211
+ };
212
+ }
213
+ const loaded = loadSnapshot(cwd, id);
214
+ if (!loaded.ok || !loaded.snapshot) {
215
+ return { ok: false, id, error: loaded.error ?? 'snapshot not found' };
216
+ }
217
+ const updated = {
218
+ ...loaded.snapshot,
219
+ label: label?.trim() || undefined,
220
+ };
221
+ const file = snapshotPath(cwd, id);
222
+ const tmp = `${file}.tmp`;
223
+ try {
224
+ fs.writeFileSync(tmp, JSON.stringify(updated, null, 2), {
225
+ encoding: 'utf-8',
226
+ mode: 0o600,
227
+ });
228
+ fs.renameSync(tmp, file);
229
+ }
230
+ catch (err) {
231
+ try {
232
+ fs.unlinkSync(tmp);
233
+ }
234
+ catch {
235
+ /* ignore tmp cleanup failure */
236
+ }
237
+ return { ok: false, id, error: err.message };
238
+ }
239
+ return { ok: true, id, label: updated.label };
240
+ }
166
241
  //# sourceMappingURL=session-snapshots.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-snapshots.js","sourceRoot":"","sources":["../../src/runtime/session-snapshots.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-snapshots.js","sourceRoot":"","sources":["../../src/runtime/session-snapshots.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import type { FreeLLMConfig } from './config.js';
3
3
  * Runs the interactive first-run setup wizard for FixO CLI.
4
4
  * Links the CLI terminal to the FreeLLMAPI SaaS cloud by prompting
5
5
  * for the master API key, destination URL, and saving it to the configuration.
6
+ * Also offers to configure individual provider API keys for direct access.
6
7
  */
7
8
  export declare function runSetupWizard(): Promise<FreeLLMConfig>;
8
9
  //# sourceMappingURL=setup-wizard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../src/setup-wizard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,aAAa,CAAC,CA0E7D"}
1
+ {"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../src/setup-wizard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;;;GAKG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,aAAa,CAAC,CAuH7D"}
@@ -4,6 +4,7 @@ import { getDefaultConfig, saveConfig, DEFAULT_API_URL } from './config.js';
4
4
  * Runs the interactive first-run setup wizard for FixO CLI.
5
5
  * Links the CLI terminal to the FreeLLMAPI SaaS cloud by prompting
6
6
  * for the master API key, destination URL, and saving it to the configuration.
7
+ * Also offers to configure individual provider API keys for direct access.
7
8
  */
8
9
  export async function runSetupWizard() {
9
10
  p.intro('🚀 Welcome to FixO CLI Setup');
@@ -67,7 +68,47 @@ export async function runSetupWizard() {
67
68
  config.apiUrl = apiUrl;
68
69
  config._firstRunComplete = true;
69
70
  saveConfig(config);
70
- p.outro('✓ Configuration saved to ~/.fixocli/config.json');
71
+ p.outro('✓ FreeLLMAPI configuration saved to ~/.fixocli/config.json');
72
+ // ──── Optional: Configure individual provider API keys ────
73
+ const configureProviders = await p.confirm({
74
+ message: 'Would you like to add API keys for individual AI providers? (You can also do this later via /providers add)',
75
+ initialValue: false,
76
+ });
77
+ if (configureProviders) {
78
+ // Dynamic import to avoid any module-load-time side effects
79
+ const { ProvidersManager, PROVIDER_REGISTRY } = await import('./agent/providers-manager.js');
80
+ const selectedProviders = await p.multiselect({
81
+ message: 'Select providers to configure (you can add more later via /providers add):',
82
+ options: PROVIDER_REGISTRY.map(def => ({
83
+ value: def.name,
84
+ label: def.displayName,
85
+ hint: def.docsUrl,
86
+ })),
87
+ required: false,
88
+ });
89
+ if (!p.isCancel(selectedProviders) && selectedProviders.length > 0) {
90
+ let configuredCount = 0;
91
+ for (const name of selectedProviders) {
92
+ const def = PROVIDER_REGISTRY.find(d => d.name === name);
93
+ const apiKey = await p.password({
94
+ message: `Enter API key for ${def.displayName}:`,
95
+ validate: (val) => {
96
+ if (!val.trim())
97
+ return 'API key is required';
98
+ return;
99
+ },
100
+ });
101
+ if (!p.isCancel(apiKey) && apiKey) {
102
+ ProvidersManager.add(name, apiKey);
103
+ configuredCount++;
104
+ console.log(` ✓ ${def.displayName} key saved`);
105
+ }
106
+ }
107
+ if (configuredCount > 0) {
108
+ p.outro(`✓ ${configuredCount} provider key(s) saved to ~/.fixocli/providers.json`);
109
+ }
110
+ }
111
+ }
71
112
  return config;
72
113
  }
73
114
  //# sourceMappingURL=setup-wizard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../src/setup-wizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE5E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,CAAC,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC;;;;;;;;qEAQuD,CAAC,CAAC;IAErE,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC;QAClC,OAAO,EAAE,yCAAyC;QAClD,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,6BAA6B,EAAE;YAChE,EAAE,KAAK,EAAE,0BAA0B,EAAE,KAAK,EAAE,qDAAqD,EAAE;YACnG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,qBAAqB,EAAE;SAClD;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,GAAG,YAAsB,CAAC;IACpC,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC;YAC7B,OAAO,EAAE,4CAA4C;YACrD,WAAW,EAAE,kCAAkC;YAC/C,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;gBAChB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;oBAAE,OAAO,iBAAiB,CAAC;gBAC1C,OAAO;YACT,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC;QAC/B,OAAO,EAAE,gCAAgC;QACzC,WAAW,EAAE,wBAAwB;QACrC,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;YAChB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;gBAChB,OAAO,qBAAqB,CAAC;YAC/B,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC1C,OAAO,uCAAuC,CAAC;YACjD,CAAC;YACD,OAAO;QACT,CAAC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,CAAC,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,MAAM,CAAC,kBAAkB,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IAC/C,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAEhC,UAAU,CAAC,MAAM,CAAC,CAAC;IAEnB,CAAC,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAE3D,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../src/setup-wizard.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/ui/prompt.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AA2DlD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA4+DrE"}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/ui/prompt.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AA2DlD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAkrErE"}
package/dist/ui/prompt.js CHANGED
@@ -45,6 +45,7 @@ export async function startREPL(options) {
45
45
  await mcpBridgeManager.initialize(cwd);
46
46
  const { randomUUID } = await import('node:crypto');
47
47
  let currentSessionId = randomUUID();
48
+ let currentSessionLabel;
48
49
  let sessionModifiedFiles = [];
49
50
  let currentMode = 'BUILD';
50
51
  let currentModel = projectConfig?.model ?? config.defaultModel ?? 'auto';
@@ -76,6 +77,8 @@ export async function startREPL(options) {
76
77
  conversation.setContextLimit(currentModel);
77
78
  currentMode = snap.mode;
78
79
  selectedFiles = [...snap.selectedFiles];
80
+ currentSessionId = snap.id;
81
+ currentSessionLabel = snap.label;
79
82
  console.log(`\n${c.green}✓ Resumed session${c.reset} ${c.dim}${snap.id}${c.reset}`);
80
83
  console.log(` ${c.dim}messages=${snap.conversation.length} tokens=${snap.tokens} model=${snap.model} mode=${snap.mode}${c.reset}`);
81
84
  if (snap.summary) {
@@ -88,6 +91,8 @@ export async function startREPL(options) {
88
91
  }
89
92
  }
90
93
  let isPrompting = false;
94
+ let isTaskRunning = false;
95
+ let currentRunningAgent = null;
91
96
  let activeSuggestionsCount = 0;
92
97
  let currentMatches = [];
93
98
  let highlightedIndex = 0;
@@ -181,7 +186,10 @@ export async function startREPL(options) {
181
186
  mode: modeForState,
182
187
  routing: 'auto',
183
188
  model: currentModel,
184
- branch: currentBranch || 'detached',
189
+ // Show '(detached HEAD)' instead of bare 'detached' so the
190
+ // status bar is unambiguous — the previous label read as "the
191
+ // CLI is detached from the API server" to several users.
192
+ branch: currentBranch || '(detached HEAD)',
185
193
  contextPercent,
186
194
  providersCount,
187
195
  transport: 'freellmapi',
@@ -273,12 +281,48 @@ export async function startREPL(options) {
273
281
  }
274
282
  };
275
283
  process.on('exit', exitCleanup);
276
- // ──── Graceful exit handlers ────
284
+ // ──── Double-Ctrl+C (and task-abort) handler ────
285
+ const SIGINT_RESET_MS = 2000;
286
+ let sigintCount = 0;
287
+ let lastSigintTime = 0;
288
+ let sigintResetTimer = null;
277
289
  const sigintHandler = () => {
290
+ if (isTaskRunning && currentRunningAgent) {
291
+ // A task is running — cancel it instead of exiting
292
+ currentRunningAgent.abort();
293
+ return;
294
+ }
295
+ const now = Date.now();
296
+ if (now - lastSigintTime > SIGINT_RESET_MS) {
297
+ // First press (or after reset window)
298
+ sigintCount = 1;
299
+ lastSigintTime = now;
300
+ // Write hint and redraw the prompt
301
+ const promptStr = `${C.LAVA}›${C.RESET} `;
302
+ process.stdout.write(`\n${c.yellow}⚠ Press Ctrl+C again to exit${c.reset}\n`);
303
+ drawLavaStatusBar();
304
+ process.stdout.write(promptStr);
305
+ // Auto-reset after the window expires
306
+ if (sigintResetTimer)
307
+ clearTimeout(sigintResetTimer);
308
+ sigintResetTimer = setTimeout(() => {
309
+ sigintCount = 0;
310
+ sigintResetTimer = null;
311
+ }, SIGINT_RESET_MS);
312
+ return;
313
+ }
314
+ // Second press within the window — exit
315
+ if (sigintResetTimer)
316
+ clearTimeout(sigintResetTimer);
317
+ sigintResetTimer = null;
318
+ sigintCount = 0;
278
319
  exitCleanup();
279
320
  console.log('\n\n👋 FixO CLI session ended safely. Core engine offline.');
280
321
  process.exit(0);
281
322
  };
323
+ // Listen on both the readline interface (catches Ctrl+C during rl.question())
324
+ // and the process (fallback for non-readline scenarios).
325
+ rl.on('SIGINT', sigintHandler);
282
326
  process.on('SIGINT', sigintHandler);
283
327
  const sigtermHandler = () => {
284
328
  exitCleanup();
@@ -458,7 +502,15 @@ export async function startREPL(options) {
458
502
  const keypressHandler = (_char, key) => {
459
503
  if (!isPrompting)
460
504
  return;
461
- if (key && (key.name === 'up' || key.name === 'down' || key.name === 'escape' || key.name === 'tab' || key.name === 'enter' || key.name === 'return')) {
505
+ // Intercept Escape to cancel a running task even when readline is in a question state
506
+ if (key && key.name === 'escape') {
507
+ if (isTaskRunning && currentRunningAgent) {
508
+ currentRunningAgent.abort();
509
+ return;
510
+ }
511
+ return;
512
+ }
513
+ if (key && (key.name === 'up' || key.name === 'down' || key.name === 'tab' || key.name === 'enter' || key.name === 'return')) {
462
514
  return;
463
515
  }
464
516
  process.nextTick(() => {
@@ -582,6 +634,15 @@ export async function startREPL(options) {
582
634
  }
583
635
  if (event === 'keypress') {
584
636
  const [char, key] = args;
637
+ // Intercept Escape or Ctrl+C to cancel a running task (when not prompting)
638
+ if (key && key.name === 'escape' && isTaskRunning && currentRunningAgent) {
639
+ currentRunningAgent.abort();
640
+ return true;
641
+ }
642
+ if (key && key.name === 'c' && key.ctrl && isTaskRunning && currentRunningAgent) {
643
+ currentRunningAgent.abort();
644
+ return true;
645
+ }
585
646
  // Tab on empty line → cycle mode (BEFORE suggestion handling, so it always works)
586
647
  if (isPrompting && key && key.name === 'tab' && rl.line.trim() === '') {
587
648
  const modes = ['BUILD', 'EXPLORE', 'SCOUT', 'PLAN'];
@@ -671,13 +732,20 @@ export async function startREPL(options) {
671
732
  case '/model': {
672
733
  if (args[0] === 'list') {
673
734
  // Print full model table grouped by provider
735
+ // Uses live-fetched cached models when available, otherwise falls
736
+ // back to the static registry list (tagged [unverified]).
674
737
  console.log(`\n${c.bold}${c.cyan}Available Models by Provider${c.reset}`);
675
738
  console.log(`${c.dim}${'─'.repeat(60)}${c.reset}`);
676
739
  for (const def of PROVIDER_REGISTRY) {
677
740
  const hasKey = ProvidersManager.has(def.name);
678
741
  const keyStatus = hasKey ? `${c.green}[key ✓]${c.reset}` : `${c.dim}[no key]${c.reset}`;
679
- console.log(`\n ${c.snow}${c.bold}${def.displayName}${c.reset} ${keyStatus}`);
680
- for (const model of def.models) {
742
+ const cached = ProvidersManager.getCachedModels(def.name);
743
+ const modelList = cached?.models?.length ? cached.models : def.models;
744
+ const sourceTag = cached?.source === 'live'
745
+ ? ''
746
+ : ` ${c.dim}[unverified]${c.reset}`;
747
+ console.log(`\n ${c.snow}${c.bold}${def.displayName}${c.reset} ${keyStatus}${sourceTag}`);
748
+ for (const model of modelList) {
681
749
  console.log(` ${c.cyan}•${c.reset} ${model}`);
682
750
  }
683
751
  }
@@ -742,6 +810,11 @@ export async function startREPL(options) {
742
810
  return;
743
811
  }
744
812
  currentModel = picked;
813
+ // Store hint — find which provider this model belongs to
814
+ const owningDef = PROVIDER_REGISTRY.find(d => d.models.includes(currentModel)
815
+ || ProvidersManager.getCachedModels(d.name)?.models?.includes(currentModel));
816
+ if (owningDef)
817
+ ProvidersManager.setModelProviderHint(currentModel, owningDef.name);
745
818
  conversation.setContextLimit(currentModel);
746
819
  console.log(`\n${c.green}✓ Model set to: ${c.bold}${currentModel}${c.reset}`);
747
820
  return;
@@ -777,6 +850,11 @@ export async function startREPL(options) {
777
850
  return;
778
851
  }
779
852
  currentModel = picked;
853
+ // Store explicit model-provider association so
854
+ // resolveDirectConfig can route this model directly
855
+ // to this provider (critical for live-fetched models
856
+ // that don't appear in the static registry).
857
+ ProvidersManager.setModelProviderHint(currentModel, def.name);
780
858
  conversation.setContextLimit(currentModel);
781
859
  console.log(`\n${c.green}✓ Model set to: ${c.bold}${currentModel}${c.reset}`);
782
860
  return;
@@ -1192,6 +1270,8 @@ export async function startREPL(options) {
1192
1270
  yes: true,
1193
1271
  };
1194
1272
  try {
1273
+ isTaskRunning = true;
1274
+ currentRunningAgent = agent;
1195
1275
  const result = await agent.runStreaming(context, conversation, rl);
1196
1276
  for (const file of result.modifiedFiles) {
1197
1277
  if (!modifiedFiles.includes(file)) {
@@ -1202,6 +1282,11 @@ export async function startREPL(options) {
1202
1282
  catch (err) {
1203
1283
  console.log(`\n${c.red}✗ Repair agent failed on attempt ${attempt}: ${err.message || err}${c.reset}`);
1204
1284
  }
1285
+ finally {
1286
+ isTaskRunning = false;
1287
+ currentRunningAgent = null;
1288
+ agent.reset();
1289
+ }
1205
1290
  testResult = runProjectTests(cwd);
1206
1291
  if (testResult.includes('Status: 0')) {
1207
1292
  console.log(`\n${c.green}✓ All tests passed after repair attempt ${attempt}!${c.reset}`);
@@ -1307,9 +1392,59 @@ export async function startREPL(options) {
1307
1392
  }
1308
1393
  return;
1309
1394
  }
1395
+ case '/rename': {
1396
+ // Renames the *active* session. Accepts the rest of the
1397
+ // input as a free-form label (so spaces don't need quoting).
1398
+ const rawLabel = args.join(' ').trim();
1399
+ const { isValidSessionLabel, MAX_LABEL_LENGTH } = await import('../runtime/session-snapshots.js');
1400
+ const { SessionManager } = await import('../agent/conversation.js');
1401
+ if (!rawLabel) {
1402
+ console.log(`\n${c.yellow}Usage: /rename <label>${c.reset}\n` +
1403
+ `${c.dim} Labels are 1..${MAX_LABEL_LENGTH} chars: letters, digits, space, dash, underscore, dot.${c.reset}`);
1404
+ return;
1405
+ }
1406
+ if (!isValidSessionLabel(rawLabel)) {
1407
+ console.log(`\n${c.red}✗ Invalid label.${c.reset} ${c.dim}Allowed: letters, digits, space, dash, underscore, dot — max ${MAX_LABEL_LENGTH} chars.${c.reset}`);
1408
+ return;
1409
+ }
1410
+ // Persist if the session has already been saved at least
1411
+ // once; otherwise just remember the label in memory until
1412
+ // the next save fires.
1413
+ try {
1414
+ SessionManager.renameSession(currentSessionId, rawLabel);
1415
+ }
1416
+ catch {
1417
+ /* tolerate first-rename-before-save */
1418
+ }
1419
+ currentSessionLabel = rawLabel;
1420
+ console.log(`\n${c.green}✓ Session renamed:${c.reset} ${c.cyan}${rawLabel}${c.reset} ${c.dim}(id: ${currentSessionId})${c.reset}`);
1421
+ return;
1422
+ }
1310
1423
  case '/session': {
1311
1424
  const sub = args[0];
1312
1425
  const { SessionManager } = await import('../agent/conversation.js');
1426
+ if (sub === 'rename') {
1427
+ const id = args[1];
1428
+ const rawLabel = args.slice(2).join(' ').trim();
1429
+ const { isValidSessionLabel, MAX_LABEL_LENGTH } = await import('../runtime/session-snapshots.js');
1430
+ if (!id || !rawLabel) {
1431
+ console.log(`\n${c.yellow}Usage: /session rename <id> <label>${c.reset}`);
1432
+ return;
1433
+ }
1434
+ if (!isValidSessionLabel(rawLabel)) {
1435
+ console.log(`\n${c.red}✗ Invalid label.${c.reset} ${c.dim}Max ${MAX_LABEL_LENGTH} chars; letters, digits, space, dash, underscore, dot only.${c.reset}`);
1436
+ return;
1437
+ }
1438
+ const ok = SessionManager.renameSession(id, rawLabel);
1439
+ if (!ok) {
1440
+ console.log(`\n${c.red}✗ Session not found: ${id}${c.reset}`);
1441
+ return;
1442
+ }
1443
+ if (id === currentSessionId)
1444
+ currentSessionLabel = rawLabel;
1445
+ console.log(`\n${c.green}✓ Renamed${c.reset} ${c.dim}${id}${c.reset} → ${c.cyan}${rawLabel}${c.reset}`);
1446
+ return;
1447
+ }
1313
1448
  if (sub === 'list') {
1314
1449
  const list = SessionManager.listSessions();
1315
1450
  if (list.length === 0) {
@@ -1319,7 +1454,10 @@ export async function startREPL(options) {
1319
1454
  console.log(`\n${c.cyan}${c.bold}Saved Sessions:${c.reset}`);
1320
1455
  for (const s of list) {
1321
1456
  const date = new Date(s.timestamp).toLocaleString();
1322
- console.log(` ${c.cyan}${s.sessionId}${c.reset} - ${c.bold}${s.model}${c.reset} (${s.messageCount} msgs)`);
1457
+ const labelDisplay = s.label
1458
+ ? `${c.cyan}${s.label}${c.reset} ${c.dim}(${s.sessionId.slice(0, 8)})${c.reset}`
1459
+ : `${c.cyan}${s.sessionId}${c.reset}`;
1460
+ console.log(` ${labelDisplay} - ${c.bold}${s.model}${c.reset} (${s.messageCount} msgs)`);
1323
1461
  console.log(` ${c.dim}Created: ${date} | Tokens: ${s.totalTokens.toLocaleString()}${c.reset}`);
1324
1462
  if (s.summary) {
1325
1463
  console.log(` ${c.dim}Summary: ${s.summary.slice(0, 80)}...${c.reset}`);
@@ -1342,6 +1480,7 @@ export async function startREPL(options) {
1342
1480
  conversation.setContextLimit(currentModel);
1343
1481
  sessionModifiedFiles = data.modifiedFiles || [];
1344
1482
  currentSessionId = data.sessionId;
1483
+ currentSessionLabel = data.label;
1345
1484
  stats.totalPromptTokens = data.tokenUsage?.prompt_tokens || 0;
1346
1485
  stats.totalCompletionTokens = data.tokenUsage?.completion_tokens || 0;
1347
1486
  console.log(`\n${c.green}✓ Session restored successfully: ${c.bold}${uuid}${c.reset}`);
@@ -1361,15 +1500,34 @@ export async function startREPL(options) {
1361
1500
  stats.totalDurationMs = 0;
1362
1501
  const { randomUUID } = await import('node:crypto');
1363
1502
  currentSessionId = randomUUID();
1503
+ currentSessionLabel = undefined;
1364
1504
  SessionManager.saveSession(conversation, currentModel, sessionModifiedFiles, {
1365
1505
  prompt_tokens: stats.totalPromptTokens,
1366
1506
  completion_tokens: stats.totalCompletionTokens,
1367
1507
  total_tokens: stats.totalPromptTokens + stats.totalCompletionTokens,
1368
- }, currentSessionId);
1508
+ }, currentSessionId, currentSessionLabel);
1509
+ try {
1510
+ const { saveSnapshot } = await import('../runtime/session-snapshots.js');
1511
+ saveSnapshot({
1512
+ cwd,
1513
+ conversation: [],
1514
+ tokens: 0,
1515
+ model: currentModel,
1516
+ mode: currentMode,
1517
+ selectedFiles: [],
1518
+ summary: '',
1519
+ label: undefined,
1520
+ id: currentSessionId,
1521
+ fixedInstructions: projectConfig?.systemPrompt,
1522
+ });
1523
+ }
1524
+ catch {
1525
+ // Ignore snapshot save errors on new session
1526
+ }
1369
1527
  console.log(`\n${c.green}✓ Active conversation memory purged. New session initialized: ${c.bold}${currentSessionId}${c.reset}`);
1370
1528
  }
1371
1529
  else {
1372
- console.log(`\n${c.yellow}Usage: /session [list | load <uuid> | new]${c.reset}`);
1530
+ console.log(`\n${c.yellow}Usage: /session [list | load <uuid> | new | rename <id> <label>]${c.reset}`);
1373
1531
  }
1374
1532
  return;
1375
1533
  }
@@ -1825,7 +1983,16 @@ export async function startREPL(options) {
1825
1983
  }
1826
1984
  else {
1827
1985
  console.log(`\n${c.cyan}[Routing Engine] Simple task detected (${classification.reason}). Routing to SingleAgent...${c.reset}`);
1828
- result = await agent.runStreaming(context, conversation, rl);
1986
+ isTaskRunning = true;
1987
+ currentRunningAgent = agent;
1988
+ try {
1989
+ result = await agent.runStreaming(context, conversation, rl);
1990
+ }
1991
+ finally {
1992
+ isTaskRunning = false;
1993
+ currentRunningAgent = null;
1994
+ agent.reset();
1995
+ }
1829
1996
  }
1830
1997
  // Print result summary
1831
1998
  console.log('');
@@ -1897,7 +2064,25 @@ export async function startREPL(options) {
1897
2064
  prompt_tokens: stats.totalPromptTokens,
1898
2065
  completion_tokens: stats.totalCompletionTokens,
1899
2066
  total_tokens: stats.totalPromptTokens + stats.totalCompletionTokens,
1900
- }, currentSessionId);
2067
+ }, currentSessionId, currentSessionLabel);
2068
+ const { saveSnapshot } = await import('../runtime/session-snapshots.js');
2069
+ saveSnapshot({
2070
+ cwd,
2071
+ conversation: conversation.exportHistory().map((m, idx) => ({
2072
+ role: m.role,
2073
+ content: m.content || '',
2074
+ name: m.name,
2075
+ index: idx,
2076
+ })),
2077
+ tokens: stats.totalPromptTokens + stats.totalCompletionTokens,
2078
+ model: currentModel,
2079
+ mode: currentMode,
2080
+ selectedFiles: [...selectedFiles],
2081
+ summary: conversation.getSummary(),
2082
+ label: currentSessionLabel,
2083
+ id: currentSessionId,
2084
+ fixedInstructions: projectConfig?.systemPrompt,
2085
+ });
1901
2086
  }
1902
2087
  catch (err) {
1903
2088
  // Ignore session save errors