@ekzs/cli 0.2.0 → 0.3.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.
Files changed (67) hide show
  1. package/README.md +49 -13
  2. package/dist/commands/agent.d.ts +0 -4
  3. package/dist/commands/agent.d.ts.map +1 -1
  4. package/dist/commands/agent.js +0 -6
  5. package/dist/commands/ask.d.ts +3 -5
  6. package/dist/commands/ask.d.ts.map +1 -1
  7. package/dist/commands/ask.js +50 -36
  8. package/dist/commands/local-agent.d.ts +0 -2
  9. package/dist/commands/local-agent.d.ts.map +1 -1
  10. package/dist/commands/local-agent.js +292 -131
  11. package/dist/commands/providers.d.ts +4 -0
  12. package/dist/commands/providers.d.ts.map +1 -0
  13. package/dist/commands/providers.js +6 -0
  14. package/dist/commands/setup.d.ts +5 -0
  15. package/dist/commands/setup.d.ts.map +1 -0
  16. package/dist/commands/setup.js +4 -0
  17. package/dist/index.js +41 -20
  18. package/dist/lib/commands-i18n.d.ts +12 -1
  19. package/dist/lib/commands-i18n.d.ts.map +1 -1
  20. package/dist/lib/commands-i18n.js +78 -14
  21. package/dist/lib/composer-model.d.ts +1 -1
  22. package/dist/lib/composer-model.d.ts.map +1 -1
  23. package/dist/lib/composer-model.js +2 -2
  24. package/dist/lib/global-config.d.ts +19 -0
  25. package/dist/lib/global-config.d.ts.map +1 -0
  26. package/dist/lib/global-config.js +52 -0
  27. package/dist/lib/help.d.ts.map +1 -1
  28. package/dist/lib/help.js +16 -12
  29. package/dist/lib/locale.d.ts.map +1 -1
  30. package/dist/lib/locale.js +2 -1
  31. package/dist/lib/onboarding.d.ts +20 -0
  32. package/dist/lib/onboarding.d.ts.map +1 -0
  33. package/dist/lib/onboarding.js +129 -0
  34. package/dist/lib/providers/agent-runner.d.ts +12 -0
  35. package/dist/lib/providers/agent-runner.d.ts.map +1 -0
  36. package/dist/lib/providers/agent-runner.js +167 -0
  37. package/dist/lib/providers/catalog.d.ts +15 -0
  38. package/dist/lib/providers/catalog.d.ts.map +1 -0
  39. package/dist/lib/providers/catalog.js +93 -0
  40. package/dist/lib/providers/chat.d.ts +10 -0
  41. package/dist/lib/providers/chat.d.ts.map +1 -0
  42. package/dist/lib/providers/chat.js +121 -0
  43. package/dist/lib/providers/credentials.d.ts +28 -0
  44. package/dist/lib/providers/credentials.d.ts.map +1 -0
  45. package/dist/lib/providers/credentials.js +70 -0
  46. package/dist/lib/providers/cursor-runner.d.ts +13 -0
  47. package/dist/lib/providers/cursor-runner.d.ts.map +1 -0
  48. package/dist/lib/providers/cursor-runner.js +89 -0
  49. package/dist/lib/providers/cursor-sdk.d.ts +8 -0
  50. package/dist/lib/providers/cursor-sdk.d.ts.map +1 -0
  51. package/dist/lib/providers/cursor-sdk.js +25 -0
  52. package/dist/lib/providers/store.d.ts +21 -0
  53. package/dist/lib/providers/store.d.ts.map +1 -0
  54. package/dist/lib/providers/store.js +84 -0
  55. package/dist/lib/providers/tools.d.ts +80 -0
  56. package/dist/lib/providers/tools.d.ts.map +1 -0
  57. package/dist/lib/providers/tools.js +145 -0
  58. package/dist/lib/providers/ui.d.ts +4 -0
  59. package/dist/lib/providers/ui.d.ts.map +1 -0
  60. package/dist/lib/providers/ui.js +188 -0
  61. package/dist/lib/setup-messages.d.ts +4 -0
  62. package/dist/lib/setup-messages.d.ts.map +1 -0
  63. package/dist/lib/setup-messages.js +13 -0
  64. package/dist/lib/ui/splash.d.ts.map +1 -1
  65. package/dist/lib/ui/splash.js +4 -0
  66. package/package.json +10 -2
  67. package/skills/ekz-sdk-cli/SKILL.md +6 -4
@@ -1,83 +1,87 @@
1
1
  import { resolve } from "path";
2
- import { Agent, AgentBusyError, CursorAgentError } from "@cursor/sdk";
3
2
  import { executeAskTurn } from "../commands/ask.js";
4
3
  import { runDoctor } from "../commands/doctor.js";
5
4
  import { runScan } from "../commands/scan.js";
6
5
  import { inputPlaceholder, printHelp, printLangSwitch, printModeSwitch, printWelcome } from "../lib/banner.js";
7
6
  import { loadProjectEnv } from "../lib/env.js";
8
- import { resolveReplMetaCommand } from "../lib/commands-i18n.js";
7
+ import { ensureAgentReady, offlineAgentHint, offlineModelLabel } from "../lib/onboarding.js";
8
+ import { resolveReplMetaCommand, isProvidersMetaCommand } from "../lib/commands-i18n.js";
9
9
  import { buildAgentPrompt, buildBootstrapContext } from "../lib/context.js";
10
10
  import { resolveComposerModel } from "../lib/composer-model.js";
11
11
  import { parseLocale, uiStrings } from "../lib/locale.js";
12
12
  import { modeRequiresCursorAgent, parseMode } from "../lib/mode.js";
13
13
  import { loadPreferences, savePreferences } from "../lib/preferences.js";
14
+ import { runByokAgentTurn, usesCursorSdk } from "../lib/providers/agent-runner.js";
15
+ import { CursorSdkMissingError, loadCursorSdk } from "../lib/providers/cursor-sdk.js";
16
+ import { disposeAgent, streamRun } from "../lib/providers/cursor-runner.js";
17
+ import { resolveActiveCredentials, resolveCredentialsWithOverride, } from "../lib/providers/credentials.js";
18
+ import { runProvidersInteractive, formatActiveProviderLabel } from "../lib/providers/ui.js";
14
19
  import { clearSession, getSessionByIndex, loadSession, persistSession, saveNamedSession, } from "../lib/session.js";
15
20
  import { fail, info, ok, warn } from "../lib/output.js";
16
- import { toolDone, toolError, toolRunning, turnDivider } from "../lib/theme.js";
21
+ import { turnDivider } from "../lib/theme.js";
17
22
  import { askWithPlaceholder, formatInputPrompt } from "../lib/ui/prompt.js";
18
- function getApiKey(override, cwd) {
19
- if (cwd)
20
- loadProjectEnv(cwd);
21
- else
22
- loadProjectEnv(process.cwd());
23
- const key = override ?? process.env.CURSOR_API_KEY?.trim();
24
- if (!key) {
25
- throw new Error("CURSOR_API_KEY required. Add it to .env.local or export it — https://cursor.com/dashboard/integrations");
26
- }
27
- return key;
28
- }
29
- async function disposeAgent(agent) {
30
- const disposer = agent[Symbol.asyncDispose];
31
- if (typeof disposer === "function")
32
- await disposer.call(agent);
33
- else
34
- agent.close();
35
- }
36
- async function streamRun(agent, prompt, locale, opts) {
37
- const t = uiStrings(locale);
38
- const sendOptions = {
39
- onDelta: ({ update }) => {
40
- if (update.type === "text-delta" && update.text) {
41
- process.stdout.write(update.text);
42
- }
43
- },
44
- ...(opts?.force ? { local: { force: true } } : {}),
45
- };
46
- let run;
23
+ async function prepareAgentSession(opts, prefs) {
47
24
  try {
48
- run = await agent.send(prompt, sendOptions);
25
+ const ready = await ensureAgentReady({
26
+ locale: prefs.locale,
27
+ offlineFlag: opts.askOffline,
28
+ apiKey: opts.apiKey,
29
+ });
30
+ return { offline: ready.offline, creds: ready.creds };
49
31
  }
50
32
  catch (err) {
51
- if (err instanceof AgentBusyError) {
52
- warn(t.busyRun);
53
- run = await agent.send(prompt, { ...sendOptions, local: { force: true } });
54
- }
55
- else {
56
- throw err;
57
- }
33
+ fail(err instanceof Error ? err.message : String(err));
34
+ process.exitCode = 1;
35
+ return null;
58
36
  }
59
- for await (const event of run.stream()) {
60
- if (event.type === "tool_call" && event.status === "running") {
61
- process.stdout.write(toolRunning(event.name));
37
+ }
38
+ function resolveAgentCredentials(override, locale = "pt") {
39
+ return resolveCredentialsWithOverride(override, locale);
40
+ }
41
+ function resolveCursorModel(creds) {
42
+ return resolveComposerModel(process.env, creds.model);
43
+ }
44
+ function providerModelLabel(creds) {
45
+ if (usesCursorSdk(creds))
46
+ return resolveCursorModel(creds).label;
47
+ return `${creds.definition.name} · ${creds.model}`;
48
+ }
49
+ async function runAgentTurn(options) {
50
+ if (usesCursorSdk(options.creds)) {
51
+ if (!options.cursorAgent) {
52
+ fail(options.locale === "pt" ? "Sem agente Cursor activo." : "No active Cursor agent.");
53
+ return { cursorAgent: null, ok: false };
62
54
  }
63
- if (event.type === "tool_call" && event.status === "completed") {
64
- process.stdout.write(toolDone(event.name));
55
+ const ctx = await buildBootstrapContext(options.cwd);
56
+ const prompt = buildAgentPrompt(options.task, ctx, options.locale);
57
+ try {
58
+ await streamRun(options.cursorAgent, prompt, options.locale);
59
+ console.log("\n");
60
+ return { cursorAgent: options.cursorAgent, ok: true };
65
61
  }
66
- if (event.type === "tool_call" && event.status === "error") {
67
- process.stdout.write(toolError(event.name));
62
+ catch (err) {
63
+ if (err instanceof Error && err.name === "CursorAgentError") {
64
+ fail(err.message);
65
+ return { cursorAgent: options.cursorAgent, ok: false };
66
+ }
67
+ throw err;
68
68
  }
69
69
  }
70
- const result = await run.wait();
71
- if (result.status === "error") {
72
- fail(`${t.agentFailed} (${result.id})`);
73
- process.exitCode = 2;
74
- }
75
- return { status: result.status, result: result.result };
70
+ const okResult = await runByokAgentTurn({
71
+ cwd: options.cwd,
72
+ task: options.task,
73
+ creds: options.creds,
74
+ locale: options.locale,
75
+ mode: options.mode,
76
+ });
77
+ return { cursorAgent: options.cursorAgent, ok: okResult };
76
78
  }
77
- async function createOrResumeAgent(opts) {
79
+ async function createOrResumeAgent(opts, locale = "pt") {
78
80
  const cwd = resolve(opts.cwd);
79
- const apiKey = getApiKey(opts.apiKey, cwd);
80
- const model = resolveComposerModel();
81
+ const creds = resolveAgentCredentials(opts.apiKey, locale);
82
+ const { Agent } = await loadCursorSdk(locale);
83
+ const apiKey = creds.apiKey;
84
+ const model = resolveCursorModel(creds);
81
85
  const usePlan = opts.mode === "plan" || Boolean(opts.plan);
82
86
  if (opts.fresh)
83
87
  clearSession(cwd);
@@ -100,9 +104,12 @@ async function createOrResumeAgent(opts) {
100
104
  });
101
105
  return { agent, resumed: false };
102
106
  }
103
- async function recreateAgentForMode(cwd, current, mode, apiKey) {
107
+ async function recreateAgentForMode(cwd, current, mode, apiKey, locale = "pt") {
104
108
  if (!modeRequiresCursorAgent(mode))
105
109
  return null;
110
+ const creds = resolveAgentCredentials(apiKey, locale);
111
+ if (!usesCursorSdk(creds))
112
+ return null;
106
113
  if (current)
107
114
  await disposeAgent(current);
108
115
  const { agent } = await createOrResumeAgent({
@@ -111,12 +118,12 @@ async function recreateAgentForMode(cwd, current, mode, apiKey) {
111
118
  fresh: true,
112
119
  mode,
113
120
  apiKey,
114
- });
121
+ }, locale);
115
122
  await persistAgent(cwd, agent);
116
123
  return agent;
117
124
  }
118
- async function persistAgent(cwd, agent) {
119
- const model = resolveComposerModel();
125
+ async function persistAgent(cwd, agent, creds) {
126
+ const model = creds ? resolveCursorModel(creds) : resolveComposerModel();
120
127
  persistSession(cwd, {
121
128
  agentId: agent.agentId,
122
129
  cwd: resolve(cwd),
@@ -180,37 +187,53 @@ function handleMetaCommand(line, locale, cwd, currentMode) {
180
187
  }
181
188
  return null;
182
189
  }
183
- async function resumeAgentInRepl(cwd, current, agentId, locale) {
190
+ async function resumeAgentInRepl(cwd, current, agentId, locale, apiKeyOverride) {
184
191
  if (current)
185
192
  await disposeAgent(current);
186
- const apiKey = getApiKey(undefined, cwd);
187
- const model = resolveComposerModel();
193
+ const creds = resolveAgentCredentials(apiKeyOverride, locale);
194
+ if (!usesCursorSdk(creds)) {
195
+ throw new Error(locale === "pt"
196
+ ? "Retomar sessão só com provider Cursor."
197
+ : locale === "zh"
198
+ ? "恢复会话仅适用于 Cursor provider。"
199
+ : "Resume session is Cursor-only.");
200
+ }
201
+ const { Agent } = await loadCursorSdk(locale);
202
+ const model = resolveCursorModel(creds);
188
203
  const agent = await Agent.resume(agentId, {
189
- apiKey,
204
+ apiKey: creds.apiKey,
190
205
  model: { id: model.id, params: model.params },
191
206
  local: { cwd: resolve(cwd), settingSources: ["project"] },
192
207
  });
193
- await persistAgent(cwd, agent);
208
+ await persistAgent(cwd, agent, creds);
194
209
  ok(locale === "pt" ? "Sessão retomada." : "Session resumed.");
195
210
  return agent;
196
211
  }
197
212
  export async function runLocalAgent(opts) {
198
213
  const cwd = resolve(opts.cwd);
199
214
  loadProjectEnv(cwd);
200
- const model = resolveComposerModel();
201
215
  const prefs = loadPreferences(cwd, opts.locale, opts.mode, opts.plan);
202
216
  const mode = prefs.mode;
217
+ const session = await prepareAgentSession(opts, prefs);
218
+ if (!session)
219
+ return;
220
+ const { offline, creds: sessionCreds } = session;
221
+ const askOffline = offline || Boolean(opts.askOffline);
222
+ const providerLabel = askOffline
223
+ ? offlineModelLabel(prefs.locale)
224
+ : sessionCreds
225
+ ? formatActiveProviderLabel(prefs.locale)
226
+ : formatActiveProviderLabel(prefs.locale);
203
227
  if (mode === "ask") {
204
- printWelcome({ cwd, locale: prefs.locale, mode: "ask" });
228
+ printWelcome({ cwd, locale: prefs.locale, mode: "ask", model: providerLabel });
205
229
  if (opts.task.trim()) {
206
230
  info(`${uiStrings(prefs.locale).workingOn}: ${opts.task.slice(0, 120)}${opts.task.length > 120 ? "…" : ""}\n`);
207
231
  await executeAskTurn({
208
232
  cwd,
209
233
  question: opts.task.trim(),
210
- apiKey: opts.askApiKey,
211
- apiUrl: opts.askApiUrl,
212
- offline: opts.askOffline,
234
+ offline: askOffline,
213
235
  quiet: true,
236
+ locale: prefs.locale,
214
237
  });
215
238
  console.log("");
216
239
  }
@@ -221,44 +244,88 @@ export async function runLocalAgent(opts) {
221
244
  locale: prefs.locale,
222
245
  mode: "ask",
223
246
  apiKey: opts.apiKey,
224
- askApiKey: opts.askApiKey,
225
- askApiUrl: opts.askApiUrl,
226
- askOffline: opts.askOffline,
247
+ askOffline,
248
+ creds: sessionCreds,
249
+ offline: askOffline,
250
+ });
251
+ }
252
+ return;
253
+ }
254
+ if (askOffline) {
255
+ printWelcome({ cwd, locale: prefs.locale, mode, model: providerLabel });
256
+ savePreferences(cwd, { mode });
257
+ if (opts.task.trim()) {
258
+ info(`${uiStrings(prefs.locale).workingOn}: ${opts.task.slice(0, 120)}${opts.task.length > 120 ? "…" : ""}\n`);
259
+ warn(offlineAgentHint(prefs.locale));
260
+ }
261
+ if (opts.interactive !== false) {
262
+ await runRepl({
263
+ agent: null,
264
+ cwd,
265
+ locale: prefs.locale,
266
+ mode,
267
+ apiKey: opts.apiKey,
268
+ askOffline: true,
269
+ creds: null,
270
+ offline: true,
227
271
  });
228
272
  }
229
273
  return;
230
274
  }
231
- let agent;
275
+ if (!sessionCreds) {
276
+ fail(offlineAgentHint(prefs.locale));
277
+ process.exitCode = 1;
278
+ return;
279
+ }
280
+ let agent = null;
232
281
  let resumed = false;
282
+ const creds = sessionCreds;
233
283
  try {
234
- ({ agent, resumed } = await createOrResumeAgent({ ...opts, mode }));
284
+ if (usesCursorSdk(creds)) {
285
+ ({ agent, resumed } = await createOrResumeAgent({ ...opts, mode }, prefs.locale));
286
+ }
235
287
  }
236
288
  catch (err) {
237
- if (err instanceof CursorAgentError) {
289
+ if (err instanceof CursorSdkMissingError) {
290
+ fail(err.message);
291
+ process.exitCode = 1;
292
+ return;
293
+ }
294
+ if (err instanceof Error && err.name === "CursorAgentError") {
238
295
  fail(`Agent startup failed: ${err.message}`);
239
296
  process.exitCode = 1;
240
297
  return;
241
298
  }
242
- throw err;
299
+ fail(err instanceof Error ? err.message : String(err));
300
+ process.exitCode = 1;
301
+ return;
243
302
  }
244
303
  printWelcome({
245
304
  cwd,
246
- model: model.label,
305
+ model: providerModelLabel(creds),
247
306
  locale: prefs.locale,
248
307
  mode,
249
308
  resumed,
250
- agentId: agent.agentId,
309
+ agentId: agent?.agentId,
251
310
  });
252
- await persistAgent(cwd, agent);
311
+ if (agent)
312
+ await persistAgent(cwd, agent, creds);
253
313
  savePreferences(cwd, { mode });
254
- const bootstrap = await buildBootstrapContext(cwd);
255
- const prompt = buildAgentPrompt(opts.task, bootstrap, prefs.locale);
256
314
  const t = uiStrings(prefs.locale);
257
315
  try {
258
316
  info(`${t.workingOn}: ${opts.task.slice(0, 120)}${opts.task.length > 120 ? "…" : ""}\n`);
259
- const outcome = await streamRun(agent, prompt, prefs.locale);
260
- console.log("\n");
261
- ok(`${t.done} (${outcome.status})`);
317
+ const outcome = await runAgentTurn({
318
+ cwd,
319
+ task: opts.task,
320
+ creds,
321
+ locale: prefs.locale,
322
+ mode,
323
+ cursorAgent: agent,
324
+ });
325
+ if (outcome.ok)
326
+ ok(t.done);
327
+ if (outcome.cursorAgent)
328
+ agent = outcome.cursorAgent;
262
329
  if (opts.interactive !== false) {
263
330
  await runRepl({
264
331
  agent,
@@ -266,9 +333,9 @@ export async function runLocalAgent(opts) {
266
333
  locale: prefs.locale,
267
334
  mode,
268
335
  apiKey: opts.apiKey,
269
- askApiKey: opts.askApiKey,
270
- askApiUrl: opts.askApiUrl,
271
- askOffline: opts.askOffline,
336
+ askOffline,
337
+ creds,
338
+ offline: false,
272
339
  });
273
340
  }
274
341
  else {
@@ -276,51 +343,90 @@ export async function runLocalAgent(opts) {
276
343
  }
277
344
  }
278
345
  finally {
279
- await disposeAgent(agent);
346
+ if (agent)
347
+ await disposeAgent(agent);
280
348
  }
281
349
  }
282
350
  export async function runInteractiveAgent(opts) {
283
351
  const cwd = resolve(opts.cwd);
284
352
  loadProjectEnv(cwd);
285
- const model = resolveComposerModel();
286
353
  const prefs = loadPreferences(cwd, opts.locale, opts.mode, opts.plan);
287
354
  const mode = prefs.mode;
355
+ const session = await prepareAgentSession({ ...opts, task: "" }, prefs);
356
+ if (!session)
357
+ return;
358
+ const { offline, creds: sessionCreds } = session;
359
+ const askOffline = offline || Boolean(opts.askOffline);
360
+ const providerLabel = askOffline
361
+ ? offlineModelLabel(prefs.locale)
362
+ : formatActiveProviderLabel(prefs.locale);
288
363
  if (mode === "ask") {
289
- printWelcome({ cwd, locale: prefs.locale, mode: "ask" });
364
+ printWelcome({ cwd, locale: prefs.locale, mode: "ask", model: providerLabel });
290
365
  await runRepl({
291
366
  agent: null,
292
367
  cwd,
293
368
  locale: prefs.locale,
294
369
  mode: "ask",
295
370
  apiKey: opts.apiKey,
296
- askApiKey: opts.askApiKey,
297
- askApiUrl: opts.askApiUrl,
298
- askOffline: opts.askOffline,
371
+ askOffline,
372
+ creds: sessionCreds,
373
+ offline: askOffline,
299
374
  });
300
375
  return;
301
376
  }
302
- let agent;
377
+ if (askOffline) {
378
+ printWelcome({ cwd, locale: prefs.locale, mode, model: providerLabel });
379
+ savePreferences(cwd, { mode });
380
+ await runRepl({
381
+ agent: null,
382
+ cwd,
383
+ locale: prefs.locale,
384
+ mode,
385
+ apiKey: opts.apiKey,
386
+ askOffline: true,
387
+ creds: null,
388
+ offline: true,
389
+ });
390
+ return;
391
+ }
392
+ if (!sessionCreds) {
393
+ fail(offlineAgentHint(prefs.locale));
394
+ process.exitCode = 1;
395
+ return;
396
+ }
397
+ let agent = null;
303
398
  let resumed = false;
399
+ const creds = sessionCreds;
304
400
  try {
305
- ({ agent, resumed } = await createOrResumeAgent({ ...opts, task: "", mode }));
401
+ if (usesCursorSdk(creds)) {
402
+ ({ agent, resumed } = await createOrResumeAgent({ ...opts, task: "", mode }, prefs.locale));
403
+ }
306
404
  }
307
405
  catch (err) {
308
- if (err instanceof CursorAgentError) {
406
+ if (err instanceof CursorSdkMissingError) {
407
+ fail(err.message);
408
+ process.exitCode = 1;
409
+ return;
410
+ }
411
+ if (err instanceof Error && err.name === "CursorAgentError") {
309
412
  fail(`Agent startup failed: ${err.message}`);
310
413
  process.exitCode = 1;
311
414
  return;
312
415
  }
313
- throw err;
416
+ fail(err instanceof Error ? err.message : String(err));
417
+ process.exitCode = 1;
418
+ return;
314
419
  }
315
420
  printWelcome({
316
421
  cwd,
317
- model: model.label,
422
+ model: providerModelLabel(creds),
318
423
  locale: prefs.locale,
319
424
  mode,
320
425
  resumed,
321
- agentId: agent.agentId,
426
+ agentId: agent?.agentId,
322
427
  });
323
- await persistAgent(cwd, agent);
428
+ if (agent)
429
+ await persistAgent(cwd, agent, creds);
324
430
  savePreferences(cwd, { mode });
325
431
  try {
326
432
  await runRepl({
@@ -329,21 +435,47 @@ export async function runInteractiveAgent(opts) {
329
435
  locale: prefs.locale,
330
436
  mode,
331
437
  apiKey: opts.apiKey,
332
- askApiKey: opts.askApiKey,
333
- askApiUrl: opts.askApiUrl,
334
- askOffline: opts.askOffline,
438
+ askOffline,
439
+ creds,
440
+ offline: false,
335
441
  });
336
442
  }
337
443
  finally {
338
- await disposeAgent(agent);
444
+ if (agent)
445
+ await disposeAgent(agent);
339
446
  }
340
447
  }
341
448
  async function runRepl(opts) {
342
449
  let currentLocale = opts.locale;
343
450
  let currentMode = opts.mode;
344
451
  let currentAgent = opts.agent;
452
+ let currentCreds = opts.creds;
453
+ let currentOffline = opts.offline;
345
454
  let turn = 0;
346
455
  const t = () => uiStrings(currentLocale);
456
+ const resolveCreds = () => {
457
+ if (currentOffline) {
458
+ try {
459
+ const live = resolveActiveCredentials();
460
+ if (live) {
461
+ currentOffline = false;
462
+ currentCreds = live;
463
+ return live;
464
+ }
465
+ }
466
+ catch {
467
+ /* stay offline */
468
+ }
469
+ return null;
470
+ }
471
+ try {
472
+ currentCreds = resolveAgentCredentials(opts.apiKey, currentLocale);
473
+ return currentCreds;
474
+ }
475
+ catch {
476
+ return currentCreds;
477
+ }
478
+ };
347
479
  while (true) {
348
480
  const line = (await askWithPlaceholder({
349
481
  prompt: formatInputPrompt(),
@@ -351,6 +483,15 @@ async function runRepl(opts) {
351
483
  })).trim();
352
484
  if (!line || line === "exit" || line === "quit" || line === "sair" || line === "退出")
353
485
  break;
486
+ if (isProvidersMetaCommand(line.trim().split(/\s+/)[0] ?? "")) {
487
+ await runProvidersInteractive(currentLocale);
488
+ const live = resolveActiveCredentials();
489
+ if (live) {
490
+ currentOffline = false;
491
+ currentCreds = live;
492
+ }
493
+ continue;
494
+ }
354
495
  const meta = handleMetaCommand(line, currentLocale, opts.cwd, currentMode);
355
496
  if (meta?.kind === "handled")
356
497
  continue;
@@ -369,7 +510,14 @@ async function runRepl(opts) {
369
510
  }
370
511
  }
371
512
  else {
372
- currentAgent = await recreateAgentForMode(opts.cwd, currentAgent, currentMode, opts.apiKey);
513
+ const creds = resolveCreds();
514
+ if (creds && usesCursorSdk(creds)) {
515
+ currentAgent = await recreateAgentForMode(opts.cwd, currentAgent, currentMode, opts.apiKey, currentLocale);
516
+ }
517
+ else if (currentAgent) {
518
+ await disposeAgent(currentAgent);
519
+ currentAgent = null;
520
+ }
373
521
  }
374
522
  }
375
523
  catch (err) {
@@ -378,8 +526,13 @@ async function runRepl(opts) {
378
526
  continue;
379
527
  }
380
528
  if (meta?.kind === "resume") {
381
- if (currentMode === "ask") {
382
- warn(currentLocale === "pt" ? "Sessões Cursor em modo agent/plan." : "Cursor sessions only in agent/plan mode.");
529
+ const resumeCreds = resolveCreds();
530
+ if (currentMode === "ask" || !resumeCreds || !usesCursorSdk(resumeCreds)) {
531
+ warn(currentLocale === "pt"
532
+ ? "Sessões guardadas só com provider Cursor."
533
+ : currentLocale === "zh"
534
+ ? "保存的会话仅适用于 Cursor。"
535
+ : "Saved sessions are Cursor-only.");
383
536
  continue;
384
537
  }
385
538
  try {
@@ -387,7 +540,7 @@ async function runRepl(opts) {
387
540
  fail(currentLocale === "pt" ? "Sem agente activo." : "No active agent.");
388
541
  continue;
389
542
  }
390
- currentAgent = await resumeAgentInRepl(opts.cwd, currentAgent, meta.agentId, currentLocale);
543
+ currentAgent = await resumeAgentInRepl(opts.cwd, currentAgent, meta.agentId, currentLocale, opts.apiKey);
391
544
  }
392
545
  catch (err) {
393
546
  fail(err instanceof Error ? err.message : String(err));
@@ -395,8 +548,13 @@ async function runRepl(opts) {
395
548
  continue;
396
549
  }
397
550
  if (meta?.kind === "save") {
398
- if (!currentAgent) {
399
- warn(currentLocale === "pt" ? "Guardar sessão só em modo agent/plan." : "Save session only in agent/plan mode.");
551
+ const saveCreds = resolveCreds();
552
+ if (!currentAgent || !saveCreds || !usesCursorSdk(saveCreds)) {
553
+ warn(currentLocale === "pt"
554
+ ? "Guardar sessão só com provider Cursor."
555
+ : currentLocale === "zh"
556
+ ? "保存会话仅适用于 Cursor。"
557
+ : "Save session is Cursor-only.");
400
558
  continue;
401
559
  }
402
560
  const model = resolveComposerModel();
@@ -415,35 +573,38 @@ async function runRepl(opts) {
415
573
  await executeAskTurn({
416
574
  cwd: opts.cwd,
417
575
  question: line,
418
- apiKey: opts.askApiKey,
419
- apiUrl: opts.askApiUrl,
420
- offline: opts.askOffline,
576
+ offline: currentOffline || Boolean(opts.askOffline),
421
577
  quiet: true,
578
+ locale: currentLocale,
422
579
  });
423
580
  console.log("\n");
424
581
  turn++;
425
582
  continue;
426
583
  }
427
- if (!currentAgent) {
428
- fail(currentLocale === "pt" ? "Sem agente activo." : "No active agent.");
584
+ if (currentOffline || !resolveCreds()) {
585
+ warn(offlineAgentHint(currentLocale));
586
+ turn++;
429
587
  continue;
430
588
  }
431
- await persistAgent(opts.cwd, currentAgent);
432
- const ctx = await buildBootstrapContext(opts.cwd);
433
- const prompt = buildAgentPrompt(line, ctx, currentLocale);
434
- try {
435
- await streamRun(currentAgent, prompt, currentLocale);
436
- }
437
- catch (err) {
438
- if (err instanceof CursorAgentError) {
439
- fail(err.message);
440
- turn++;
441
- continue;
442
- }
443
- throw err;
589
+ const creds = currentCreds;
590
+ if (usesCursorSdk(creds) && !currentAgent) {
591
+ fail(currentLocale === "pt" ? "Sem agente Cursor activo." : "No active Cursor agent.");
592
+ continue;
444
593
  }
445
- console.log("\n");
446
- await persistAgent(opts.cwd, currentAgent);
594
+ if (currentAgent)
595
+ await persistAgent(opts.cwd, currentAgent, creds);
596
+ const outcome = await runAgentTurn({
597
+ cwd: opts.cwd,
598
+ task: line,
599
+ creds,
600
+ locale: currentLocale,
601
+ mode: currentMode,
602
+ cursorAgent: currentAgent,
603
+ });
604
+ if (outcome.cursorAgent)
605
+ currentAgent = outcome.cursorAgent;
606
+ if (currentAgent)
607
+ await persistAgent(opts.cwd, currentAgent, creds);
447
608
  turn++;
448
609
  }
449
610
  ok(t().goodbye);
@@ -0,0 +1,4 @@
1
+ export declare function runProvidersCommand(opts: {
2
+ locale?: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/commands/providers.ts"],"names":[],"mappings":"AAGA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,iBAGlE"}
@@ -0,0 +1,6 @@
1
+ import { parseLocale } from "../lib/locale.js";
2
+ import { runProvidersInteractive } from "../lib/providers/ui.js";
3
+ export async function runProvidersCommand(opts) {
4
+ const locale = parseLocale(opts.locale) ?? "pt";
5
+ await runProvidersInteractive(locale);
6
+ }
@@ -0,0 +1,5 @@
1
+ export declare function runSetupCommand(opts: {
2
+ locale?: string;
3
+ force?: boolean;
4
+ }): Promise<void>;
5
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAEA,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,iBAE/E"}
@@ -0,0 +1,4 @@
1
+ import { runSetupWizard } from "../lib/onboarding.js";
2
+ export async function runSetupCommand(opts) {
3
+ await runSetupWizard(opts);
4
+ }