@ekzs/cli 0.3.5 → 0.3.8

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 (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +12 -12
  3. package/dist/commands/ask.d.ts.map +1 -1
  4. package/dist/commands/ask.js +12 -5
  5. package/dist/commands/local-agent.d.ts.map +1 -1
  6. package/dist/commands/local-agent.js +47 -3
  7. package/dist/lib/context.d.ts +12 -2
  8. package/dist/lib/context.d.ts.map +1 -1
  9. package/dist/lib/context.js +75 -23
  10. package/dist/lib/doctor-quiet.d.ts +3 -1
  11. package/dist/lib/doctor-quiet.d.ts.map +1 -1
  12. package/dist/lib/doctor-quiet.js +16 -2
  13. package/dist/lib/local-answer.d.ts +4 -0
  14. package/dist/lib/local-answer.d.ts.map +1 -0
  15. package/dist/lib/local-answer.js +26 -0
  16. package/dist/lib/providers/agent-runner.d.ts +1 -0
  17. package/dist/lib/providers/agent-runner.d.ts.map +1 -1
  18. package/dist/lib/providers/agent-runner.js +48 -22
  19. package/dist/lib/providers/catalog.d.ts +14 -0
  20. package/dist/lib/providers/catalog.d.ts.map +1 -1
  21. package/dist/lib/providers/catalog.js +125 -38
  22. package/dist/lib/providers/chat.d.ts.map +1 -1
  23. package/dist/lib/providers/chat.js +46 -31
  24. package/dist/lib/providers/cursor-runner.d.ts.map +1 -1
  25. package/dist/lib/providers/cursor-runner.js +16 -8
  26. package/dist/lib/providers/http.d.ts +6 -0
  27. package/dist/lib/providers/http.d.ts.map +1 -0
  28. package/dist/lib/providers/http.js +35 -0
  29. package/dist/lib/providers/ui.d.ts.map +1 -1
  30. package/dist/lib/providers/ui.js +4 -3
  31. package/dist/lib/skills.d.ts +3 -1
  32. package/dist/lib/skills.d.ts.map +1 -1
  33. package/dist/lib/skills.js +18 -8
  34. package/dist/lib/terminal-answer.d.ts +5 -0
  35. package/dist/lib/terminal-answer.d.ts.map +1 -0
  36. package/dist/lib/terminal-answer.js +55 -0
  37. package/package.json +2 -2
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alberto Moises
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ekzs/cli
2
2
 
3
- **Version:** 0.3.5
3
+ **Version:** 0.3.8
4
4
 
5
5
  **Ekz** is a local coding agent for e-Kwanza Pagamento Integrado v2.4 — like Claude Code, but specialized for `@ekzs/connect`, GPO, EMIS ref, and Ticket integrations.
6
6
 
@@ -65,17 +65,17 @@ Setup required · Configuração necessária · 需要设置
65
65
 
66
66
  ### Supported providers
67
67
 
68
- | Provider | Example models |
69
- |----------|----------------|
70
- | **Cursor** | Requires `@cursor/sdk` (offered during setup) · `composer-2.5-fast`, `gpt-5.3-codex`, … |
71
- | **OpenAI** | `gpt-4o`, `gpt-4o-mini`, `o1`, `o3-mini`, … |
72
- | **Anthropic** | `claude-sonnet-4-20250514`, `claude-opus-4-20250514`, … |
73
- | **DeepSeek** | `deepseek-chat`, `deepseek-reasoner` |
74
- | **Kimi (Moonshot)** | `moonshot-v1-8k`, `moonshot-v1-32k`, … |
75
- | **Groq** | `llama-3.3-70b-versatile`, … |
76
- | **Mistral** | `mistral-large-latest`, `codestral-latest`, … |
77
- | **Google Gemini** | `gemini-2.0-flash`, `gemini-1.5-pro`, … |
78
- | **Ollama** | `llama3.2`, `qwen2.5`, … (local) |
68
+ | Provider | Example models (May 2026) |
69
+ |----------|---------------------------|
70
+ | **Cursor** | `composer-2.5-fast`, `composer-2.5`, `claude-4.6-sonnet-thinking`, `gpt-5.5`, … |
71
+ | **OpenAI** | `gpt-5.5`, `gpt-5.4-mini`, `gpt-4.1`, `o3`, `o4-mini`, … |
72
+ | **Anthropic** | `claude-sonnet-4-6`, `claude-opus-4-7`, `claude-haiku-4-5-20251001`, … |
73
+ | **DeepSeek** | `deepseek-v4-flash`, `deepseek-v4-pro` (legacy: `deepseek-chat` until Jul 2026) |
74
+ | **Kimi (Moonshot)** | `kimi-k2.6`, `kimi-k2.5`, `moonshot-v1-8k`, … |
75
+ | **Groq** | `llama-3.3-70b-versatile`, `openai/gpt-oss-120b`, `qwen/qwen3-32b`, … |
76
+ | **Mistral** | `mistral-large-latest`, `codestral-latest`, `devstral-latest`, … |
77
+ | **Google Gemini** | `gemini-3.5-flash`, `gemini-3.1-pro-preview`, `gemini-2.5-pro`, … |
78
+ | **Ollama** | `llama3.3`, `qwen3:8b`, `deepseek-r1:8b`, … (local tags) |
79
79
 
80
80
  Manage keys anytime:
81
81
 
@@ -1 +1 @@
1
- {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/commands/ask.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAA0B,MAAM,kBAAkB,CAAC;AAyC1E,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,mDAAmD;AACnD,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CA0B1E;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,iBAO9D;AAgDD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,iBAwEA;AAED,wBAAsB,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM/E"}
1
+ {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/commands/ask.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAA0B,MAAM,kBAAkB,CAAC;AA2C1E,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,mDAAmD;AACnD,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAgC1E;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,iBAO9D;AAgDD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,iBAwEA;AAED,wBAAsB,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM/E"}
@@ -6,6 +6,8 @@ import { parseMode } from "../lib/mode.js";
6
6
  import { fail, heading, info, ok } from "../lib/output.js";
7
7
  import { loadPreferences, savePreferences } from "../lib/preferences.js";
8
8
  import { ensureAgentReady, offlineModelLabel } from "../lib/onboarding.js";
9
+ import { localQuickAnswer } from "../lib/local-answer.js";
10
+ import { formatTerminalAnswer } from "../lib/terminal-answer.js";
9
11
  import { executeByokAskTurn } from "../lib/providers/chat.js";
10
12
  import { executeCursorAskTurn } from "../lib/providers/cursor-runner.js";
11
13
  import { isCursorProvider, requireActiveCredentials, ProviderSetupError, } from "../lib/providers/credentials.js";
@@ -14,24 +16,29 @@ import { redactText } from "../lib/redact.js";
14
16
  import { askWithPlaceholder, formatInputPrompt } from "../lib/ui/prompt.js";
15
17
  import { inputPlaceholder } from "../lib/ui/splash.js";
16
18
  function deterministicAnswer(question, ctx, locale) {
17
- const lines = ["## Ekz assistant (offline)", "", question, ""];
19
+ const lines = ["Ekz assistant (offline):", "", question, ""];
18
20
  if (ctx.doctor.issues.length) {
19
- lines.push("### Issues", ...ctx.doctor.issues.map((i) => `- ${i}`), "");
21
+ lines.push("Issues:", ...ctx.doctor.issues.map((i) => `- ${i}`), "");
20
22
  }
21
23
  if (ctx.scan.length) {
22
- lines.push("### Scan", ...ctx.scan.slice(0, 8).map((f) => `- \`${f.file}:${f.line}\` · ${f.message}`), "");
24
+ lines.push("Scan:", ...ctx.scan.slice(0, 8).map((f) => `- \`${f.file}:${f.line}\` · ${f.message}`), "");
23
25
  }
24
- lines.push("### Next steps", "- Run `ekz setup` to configure language, name, and provider", "- Or `ekz --offline` for doctor/scan only");
26
+ lines.push("Next steps:", "- Run `ekz setup` to configure language, name, and provider", "- Or `ekz --offline` for doctor/scan only");
25
27
  return lines.join("\n");
26
28
  }
27
29
  /** Q&A via BYOK provider (no local file edits). */
28
30
  export async function executeAskTurn(options) {
29
31
  const { cwd, question, offline, quiet, locale = "pt" } = options;
32
+ const quick = localQuickAnswer(question, locale);
33
+ if (quick) {
34
+ console.log("\n" + quick);
35
+ return true;
36
+ }
30
37
  if (offline) {
31
38
  const ctx = await buildBootstrapContext(cwd);
32
39
  if (!quiet)
33
40
  info("Ask mode (offline) · no file edits.\n");
34
- console.log("\n" + deterministicAnswer(question, ctx, locale));
41
+ console.log("\n" + formatTerminalAnswer(deterministicAnswer(question, ctx, locale)));
35
42
  return true;
36
43
  }
37
44
  let creds;
@@ -1 +1 @@
1
- {"version":3,"file":"local-agent.d.ts","sourceRoot":"","sources":["../../src/commands/local-agent.ts"],"names":[],"mappings":"AAWA,OAAO,EAAsC,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAsBlF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AA2PF,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,iBA0I1D;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,aAAa,CAAC,iBAmG9F"}
1
+ {"version":3,"file":"local-agent.d.ts","sourceRoot":"","sources":["../../src/commands/local-agent.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAsC,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAsBlF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAiQF,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,iBA0I1D;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,aAAa,CAAC,iBAmG9F"}
@@ -6,9 +6,10 @@ import { inputPlaceholder, printHelp, printLangSwitch, printModeSwitch, printWel
6
6
  import { loadProjectEnv } from "../lib/env.js";
7
7
  import { ensureAgentReady, offlineAgentHint, offlineModelLabel } from "../lib/onboarding.js";
8
8
  import { resolveReplMetaCommand, isProvidersMetaCommand } from "../lib/commands-i18n.js";
9
- import { buildAgentPrompt, buildBootstrapContext } from "../lib/context.js";
9
+ import { buildAgentPrompt, buildBootstrapContext, invalidateBootstrapContext, isLiteTurn, wantsLocalScan, } from "../lib/context.js";
10
10
  import { resolveComposerModel } from "../lib/composer-model.js";
11
11
  import { parseLocale, uiStrings } from "../lib/locale.js";
12
+ import { localQuickAnswer } from "../lib/local-answer.js";
12
13
  import { modeRequiresCursorAgent, parseMode } from "../lib/mode.js";
13
14
  import { loadPreferences, savePreferences } from "../lib/preferences.js";
14
15
  import { runByokAgentTurn, usesCursorSdk } from "../lib/providers/agent-runner.js";
@@ -47,13 +48,14 @@ function providerModelLabel(creds) {
47
48
  return `${creds.definition.name} · ${creds.model}`;
48
49
  }
49
50
  async function runAgentTurn(options) {
51
+ const lite = options.lite ?? isLiteTurn(options.task);
50
52
  if (usesCursorSdk(options.creds)) {
51
53
  if (!options.cursorAgent) {
52
54
  fail(options.locale === "pt" ? "Sem agente Cursor activo." : "No active Cursor agent.");
53
55
  return { cursorAgent: null, ok: false };
54
56
  }
55
- const ctx = await buildBootstrapContext(options.cwd);
56
- const prompt = buildAgentPrompt(options.task, ctx, options.locale);
57
+ const ctx = await buildBootstrapContext(options.cwd, { includeScan: !lite });
58
+ const prompt = buildAgentPrompt(options.task, ctx, options.locale, { lite });
57
59
  try {
58
60
  await streamRun(options.cursorAgent, prompt, options.locale);
59
61
  console.log("\n");
@@ -73,6 +75,7 @@ async function runAgentTurn(options) {
73
75
  creds: options.creds,
74
76
  locale: options.locale,
75
77
  mode: options.mode,
78
+ lite,
76
79
  });
77
80
  return { cursorAgent: options.cursorAgent, ok: okResult };
78
81
  }
@@ -161,10 +164,12 @@ function handleMetaCommand(line, locale, cwd, currentMode) {
161
164
  return { kind: "mode", mode: next };
162
165
  }
163
166
  if (cmd === "doctor") {
167
+ invalidateBootstrapContext(cwd);
164
168
  void runDoctor(cwd).then(() => console.log(""));
165
169
  return { kind: "handled" };
166
170
  }
167
171
  if (cmd === "scan") {
172
+ invalidateBootstrapContext(cwd);
168
173
  void runScan(cwd).then(() => console.log(""));
169
174
  return { kind: "handled" };
170
175
  }
@@ -489,6 +494,21 @@ async function runRepl(opts) {
489
494
  if (live) {
490
495
  currentOffline = false;
491
496
  currentCreds = live;
497
+ if (currentMode !== "ask" && usesCursorSdk(live)) {
498
+ currentAgent = await recreateAgentForMode(opts.cwd, currentAgent, currentMode, opts.apiKey, currentLocale);
499
+ }
500
+ else if (currentAgent) {
501
+ await disposeAgent(currentAgent);
502
+ currentAgent = null;
503
+ }
504
+ }
505
+ else {
506
+ currentOffline = true;
507
+ currentCreds = null;
508
+ if (currentAgent) {
509
+ await disposeAgent(currentAgent);
510
+ currentAgent = null;
511
+ }
492
512
  }
493
513
  continue;
494
514
  }
@@ -569,7 +589,24 @@ async function runRepl(opts) {
569
589
  }
570
590
  console.log("");
571
591
  process.stdout.write(turnDivider());
592
+ const quick = localQuickAnswer(line, currentLocale);
593
+ if (quick) {
594
+ console.log(quick + "\n");
595
+ turn++;
596
+ continue;
597
+ }
598
+ if (wantsLocalScan(line)) {
599
+ invalidateBootstrapContext(opts.cwd);
600
+ info(currentLocale === "pt" ? "Scan local (sem LLM)..." : "Local scan (no LLM)...");
601
+ await runScan(opts.cwd);
602
+ console.log("\n");
603
+ turn++;
604
+ continue;
605
+ }
572
606
  if (currentMode === "ask") {
607
+ if (!currentOffline && resolveCreds()) {
608
+ info(`${currentCreds.definition.name} · ${currentCreds.model}…`);
609
+ }
573
610
  await executeAskTurn({
574
611
  cwd: opts.cwd,
575
612
  question: line,
@@ -591,8 +628,14 @@ async function runRepl(opts) {
591
628
  fail(currentLocale === "pt" ? "Sem agente Cursor activo." : "No active Cursor agent.");
592
629
  continue;
593
630
  }
631
+ info(currentLocale === "pt"
632
+ ? `${creds.definition.name} · ${creds.model}…`
633
+ : currentLocale === "zh"
634
+ ? `${creds.definition.name} · ${creds.model}…`
635
+ : `${creds.definition.name} · ${creds.model}…`);
594
636
  if (currentAgent)
595
637
  await persistAgent(opts.cwd, currentAgent, creds);
638
+ const lite = isLiteTurn(line);
596
639
  const outcome = await runAgentTurn({
597
640
  cwd: opts.cwd,
598
641
  task: line,
@@ -600,6 +643,7 @@ async function runRepl(opts) {
600
643
  locale: currentLocale,
601
644
  mode: currentMode,
602
645
  cursorAgent: currentAgent,
646
+ lite,
603
647
  });
604
648
  if (outcome.cursorAgent)
605
649
  currentAgent = outcome.cursorAgent;
@@ -6,7 +6,17 @@ export type BootstrapContext = {
6
6
  scan: Awaited<ReturnType<typeof collectScanFindings>>;
7
7
  env: Record<string, string>;
8
8
  };
9
- export declare function buildBootstrapContext(cwd: string): Promise<BootstrapContext>;
10
- export declare function buildAgentPrompt(task: string, ctx: BootstrapContext, locale?: EkzLocale): string;
9
+ export declare function invalidateBootstrapContext(cwd?: string): void;
10
+ /** Integration-heavy tasks need repo scan + full skill bundle. */
11
+ export declare function needsIntegrationContext(task: string): boolean;
12
+ export declare function isLiteTurn(task: string): boolean;
13
+ export declare function wantsLocalScan(line: string): boolean;
14
+ export declare function buildBootstrapContext(cwd: string, options?: {
15
+ refresh?: boolean;
16
+ includeScan?: boolean;
17
+ }): Promise<BootstrapContext>;
18
+ export declare function buildAgentPrompt(task: string, ctx: BootstrapContext, locale?: EkzLocale, options?: {
19
+ lite?: boolean;
20
+ }): string;
11
21
  export declare const FIX_DEFAULT_TASK = "Audit this project's e-Kwanza v2.4 integration end-to-end.\nFix env wiring, payment rails (gpo / emis_ref / ticket), checkout flows, and webhook handlers.\nUse @ekzs/connect. Follow the loaded Ekz skills. Stay within e-Kwanza payment scope only \u2014 read unrelated code for context, do not edit it.\nAfter edits, suggest running `ekz doctor`.";
12
22
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/lib/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,aAAa,CAAC;AAIlE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC;IACxD,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC;IACtD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC;AAEF,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAalF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,GAAE,SAAgB,GAAG,MAAM,CAoCtG;AAED,eAAO,MAAM,gBAAgB,6VAGgB,CAAC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/lib/context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,aAAa,CAAC;AAMlE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC;IACxD,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC;IACtD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC;AASF,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,MAAM,QAGtD;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAS7D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,OAAO,CAAC,gBAAgB,CAAC,CA6B3B;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,EACrB,MAAM,GAAE,SAAgB,EACxB,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3B,MAAM,CA4CR;AAED,eAAO,MAAM,gBAAgB,6VAGgB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { resolve } from "path";
1
2
  import { collectDoctorResult } from "./doctor-quiet.js";
2
3
  import { collectScanFindings } from "./scan-quiet.js";
3
4
  import { loadProjectEnv } from "./env.js";
@@ -6,23 +7,81 @@ import { formatSkillsForPrompt, selectSkillsForTask } from "./skills.js";
6
7
  import { languageInstruction } from "./locale.js";
7
8
  import { agentScopeBlock } from "./scope.js";
8
9
  import { detectShellEnvironment, shellGuidanceBlock } from "./shell.js";
9
- export async function buildBootstrapContext(cwd) {
10
- const doctor = await collectDoctorResult(cwd);
11
- const scan = await collectScanFindings(cwd);
12
- const { env } = loadProjectEnv(cwd);
10
+ import { isLocalQuickTurn } from "./local-answer.js";
11
+ import { terminalStyleInstruction } from "./terminal-answer.js";
12
+ const bootstrapCache = new Map();
13
+ export function invalidateBootstrapContext(cwd) {
14
+ if (cwd)
15
+ bootstrapCache.delete(resolve(cwd));
16
+ else
17
+ bootstrapCache.clear();
18
+ }
19
+ /** Integration-heavy tasks need repo scan + full skill bundle. */
20
+ export function needsIntegrationContext(task) {
21
+ const t = task.trim();
22
+ if (t.length < 4)
23
+ return false;
24
+ if (isLocalQuickTurn(t)) {
25
+ return false;
26
+ }
27
+ return /ekwanza|webhook|gpo|emis|ticket|checkout|integr|doctor|scan|payment|cobran|multicaixa|fix|\.env|rail|sdk|connect|audit|implement|starter|projeto|project|merchant|cobrança|referência|multicaixa|appypay|oauth|env var/i.test(t);
28
+ }
29
+ export function isLiteTurn(task) {
30
+ return !needsIntegrationContext(task);
31
+ }
32
+ export function wantsLocalScan(line) {
33
+ return /\b(scan|analis[aá]r?)\b/i.test(line) && /\b(run|corre|execut|faz|do|faça)\b/i.test(line);
34
+ }
35
+ export async function buildBootstrapContext(cwd, options) {
36
+ const root = resolve(cwd);
37
+ const includeScan = options?.includeScan !== false;
38
+ if (!options?.refresh && bootstrapCache.has(root)) {
39
+ const cached = bootstrapCache.get(root);
40
+ if (!includeScan || cached.scanComplete)
41
+ return cached.ctx;
42
+ }
43
+ const doctor = await collectDoctorResult(root, { live: false });
44
+ const scan = includeScan
45
+ ? await collectScanFindings(root)
46
+ : bootstrapCache.get(root)?.ctx.scan ?? [];
47
+ const { env } = loadProjectEnv(root);
13
48
  const envSnapshot = {};
14
49
  for (const key of Object.keys(env)) {
15
50
  if (key.startsWith("EKWANZA_") || key.startsWith("EKZ_")) {
16
51
  envSnapshot[key] = env[key];
17
52
  }
18
53
  }
19
- return { doctor, scan, env: redactEnv(envSnapshot) };
54
+ const ctx = {
55
+ doctor,
56
+ scan,
57
+ env: redactEnv(envSnapshot),
58
+ };
59
+ bootstrapCache.set(root, { ctx, scanComplete: includeScan });
60
+ return ctx;
20
61
  }
21
- export function buildAgentPrompt(task, ctx, locale = "pt") {
22
- const scanHints = ctx.scan.map((f) => `${f.rule}: ${f.message}`);
23
- const skills = selectSkillsForTask(task, scanHints);
24
- const skillBlock = formatSkillsForPrompt(skills);
62
+ export function buildAgentPrompt(task, ctx, locale = "pt", options) {
63
+ const lite = options?.lite ?? isLiteTurn(task);
64
+ const scanHints = lite ? [] : ctx.scan.map((f) => `${f.rule}: ${f.message}`);
65
+ const skills = selectSkillsForTask(task, scanHints, { lite });
66
+ const skillBlock = lite
67
+ ? `# Skill: ekz-connect\n\nScoped e-Kwanza v2.4 assistant. Use /analisar or /diagnóstico for free local checks.`
68
+ : formatSkillsForPrompt(skills);
25
69
  const shell = detectShellEnvironment();
70
+ const diagnostics = lite
71
+ ? {
72
+ issues: ctx.doctor.issues.slice(0, 6),
73
+ rails: ctx.doctor.rails,
74
+ envKeys: Object.keys(ctx.env),
75
+ }
76
+ : {
77
+ issues: ctx.doctor.issues,
78
+ warnings: ctx.doctor.warnings,
79
+ rails: ctx.doctor.rails,
80
+ health: ctx.doctor.health,
81
+ scan: ctx.scan.slice(0, 12),
82
+ env: ctx.env,
83
+ shell,
84
+ };
26
85
  return `${skillBlock}
27
86
 
28
87
  ---
@@ -32,20 +91,13 @@ Never commit secrets.
32
91
 
33
92
  ${agentScopeBlock(locale)}
34
93
 
35
- ${shellGuidanceBlock(locale)}
36
-
37
- ${languageInstruction(locale)}
38
-
39
- ## Pre-flight diagnostics (ekz doctor + scan)
40
- ${JSON.stringify({
41
- issues: ctx.doctor.issues,
42
- warnings: ctx.doctor.warnings,
43
- rails: ctx.doctor.rails,
44
- health: ctx.doctor.health,
45
- scan: ctx.scan.slice(0, 12),
46
- env: ctx.env,
47
- shell,
48
- }, null, 2)}
94
+ ${lite ? "" : `${shellGuidanceBlock(locale)}\n\n`}
95
+ ${languageInstruction(locale)}
96
+
97
+ ${terminalStyleInstruction(locale)}
98
+
99
+ ## Pre-flight diagnostics (ekz doctor + scan)
100
+ ${JSON.stringify(diagnostics, null, 2)}
49
101
 
50
102
  ## Task
51
103
  ${task}`;
@@ -7,5 +7,7 @@ export type DoctorResult = {
7
7
  warnings: string[];
8
8
  health: Awaited<ReturnType<EkzConnect["healthCheck"]>> | null;
9
9
  };
10
- export declare function collectDoctorResult(cwd: string): Promise<DoctorResult>;
10
+ export declare function collectDoctorResult(cwd: string, options?: {
11
+ live?: boolean;
12
+ }): Promise<DoctorResult>;
11
13
  //# sourceMappingURL=doctor-quiet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor-quiet.d.ts","sourceRoot":"","sources":["../../src/lib/doctor-quiet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,eAAe,CAAC;AAE1D,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC/D,CAAC;AAEF,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAmC5E"}
1
+ {"version":3,"file":"doctor-quiet.d.ts","sourceRoot":"","sources":["../../src/lib/doctor-quiet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,eAAe,CAAC;AAE1D,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC/D,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3B,OAAO,CAAC,YAAY,CAAC,CAkDvB"}
@@ -1,6 +1,7 @@
1
1
  import { EkzConnect, configFromEnv } from "@ekzs/connect";
2
2
  import { auditEnv, loadProjectEnv } from "./env.js";
3
- export async function collectDoctorResult(cwd) {
3
+ export async function collectDoctorResult(cwd, options) {
4
+ const live = options?.live !== false;
4
5
  const { envFiles, env } = loadProjectEnv(cwd);
5
6
  const audit = auditEnv(env);
6
7
  const issues = [];
@@ -18,13 +19,26 @@ export async function collectDoctorResult(cwd) {
18
19
  }
19
20
  let health = null;
20
21
  const cfg = configFromEnv(env);
21
- if (cfg) {
22
+ if (cfg && live) {
22
23
  health = await new EkzConnect(cfg).healthCheck();
23
24
  if (!health.oauth)
24
25
  issues.push("OAuth authentication failed");
25
26
  if (!health.configured)
26
27
  warnings.push("healthCheck.configured is false");
27
28
  }
29
+ else if (cfg && !live) {
30
+ health = {
31
+ oauth: false,
32
+ gpo: Boolean(cfg.paymentMethodIdGpo),
33
+ emisRef: Boolean(cfg.paymentMethodIdEmisRef),
34
+ ticket: Boolean(cfg.notificationToken && cfg.apiKey && cfg.partnerRegistrationNumber),
35
+ configured: Boolean(cfg.clientId &&
36
+ cfg.clientSecret &&
37
+ cfg.merchantIdentifier &&
38
+ cfg.apiKey),
39
+ env: cfg.env ?? "sandbox",
40
+ };
41
+ }
28
42
  else {
29
43
  issues.push("Core EKWANZA_* vars missing");
30
44
  }
@@ -0,0 +1,4 @@
1
+ import type { EkzLocale } from "./locale.js";
2
+ export declare function isLocalQuickTurn(input: string): boolean;
3
+ export declare function localQuickAnswer(input: string, locale: EkzLocale): string | null;
4
+ //# sourceMappingURL=local-answer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-answer.d.ts","sourceRoot":"","sources":["../../src/lib/local-answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAO7C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGvD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAoBhF"}
@@ -0,0 +1,26 @@
1
+ const GREETING_RE = /^(olá|ola|oi|hello|hi|hey|bom dia|boa tarde|boa noite|你好|您好)[!.?\s]*$/i;
2
+ const THANKS_RE = /^(obrigado|obrigada|thanks|thank you|valeu|谢谢|多谢)[!.?\s]*$/i;
3
+ export function isLocalQuickTurn(input) {
4
+ const text = input.trim();
5
+ return GREETING_RE.test(text) || THANKS_RE.test(text);
6
+ }
7
+ export function localQuickAnswer(input, locale) {
8
+ const text = input.trim();
9
+ if (GREETING_RE.test(text)) {
10
+ if (locale === "zh") {
11
+ return "你好。我可以帮你处理 e-Kwanza 支付集成、checkout、webhook、订阅、票务和用量计费。告诉我你要接入什么,或运行 /scan 做本地诊断。";
12
+ }
13
+ if (locale === "en") {
14
+ return "Hello. I can help with e-Kwanza payments, checkout, webhooks, subscriptions, tickets, and overage billing. Tell me what you want to integrate, or run /scan for a local diagnostic.";
15
+ }
16
+ return "Olá. Posso ajudar com pagamentos e-Kwanza, checkout, webhooks, subscrições, tickets e cobrança de excedentes. Diz-me o que queres integrar, ou corre /scan para um diagnóstico local.";
17
+ }
18
+ if (THANKS_RE.test(text)) {
19
+ if (locale === "zh")
20
+ return "不客气。需要时我可以继续检查支付集成。";
21
+ if (locale === "en")
22
+ return "You are welcome. I can keep checking the payment integration whenever you are ready.";
23
+ return "De nada. Quando quiseres, posso continuar a verificar a integração de pagamentos.";
24
+ }
25
+ return null;
26
+ }
@@ -7,6 +7,7 @@ export declare function runByokAgentTurn(options: {
7
7
  creds: ResolvedCredentials;
8
8
  locale: EkzLocale;
9
9
  mode: EkzMode;
10
+ lite?: boolean;
10
11
  }): Promise<boolean>;
11
12
  export declare function usesCursorSdk(creds: ResolvedCredentials): boolean;
12
13
  //# sourceMappingURL=agent-runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/agent-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AA+L5D,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,OAAO,CAAC,OAAO,CAAC,CAgCnB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAEjE"}
1
+ {"version":3,"file":"agent-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/agent-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAsM5D,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0DnB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAEjE"}
@@ -1,34 +1,40 @@
1
1
  import { resolve } from "path";
2
- import { buildAgentPrompt, buildBootstrapContext } from "../context.js";
3
- import { fail } from "../output.js";
2
+ import { buildAgentPrompt, buildBootstrapContext, isLiteTurn, needsIntegrationContext } from "../context.js";
3
+ import { localQuickAnswer } from "../local-answer.js";
4
+ import { fail, warn } from "../output.js";
5
+ import { formatTerminalAnswer } from "../terminal-answer.js";
4
6
  import { toolDone, toolError, toolRunning } from "../theme.js";
7
+ import { deepseekRequestBody, fetchWithTimeout, resolveChatCompletionsUrl } from "./http.js";
5
8
  import { AGENT_TOOL_DEFINITIONS, executeAgentTool } from "./tools.js";
6
- const MAX_TOOL_ROUNDS = 24;
9
+ const MAX_TOOL_ROUNDS = 12;
7
10
  function planInstruction(mode) {
8
11
  if (mode === "plan") {
9
- return "You are in **plan mode**: output a clear numbered plan first. Only call write_file after the plan is clear.";
12
+ return "You are in plan mode: output a clear numbered plan first. Only call write_file after the plan is clear.";
10
13
  }
11
14
  if (mode === "ask") {
12
- return "You are in **ask mode**: answer only. Do not call write_file or run_command.";
15
+ return "You are in ask mode: answer only. Do not call write_file or run_command.";
13
16
  }
14
- return "You are in **agent mode**: use tools to inspect and fix the e-Kwanza integration.";
17
+ return "You are in agent mode: use tools to inspect and fix the e-Kwanza integration.";
15
18
  }
16
- async function openAiAgentLoop(creds, cwd, messages, enableTools) {
17
- const base = (creds.baseUrl ?? "https://api.openai.com/v1").replace(/\/$/, "");
18
- const url = base.endsWith("/chat/completions") ? base : `${base}/chat/completions`;
19
+ async function openAiAgentLoop(creds, cwd, messages, enableTools, thinking = true, timeoutMs) {
20
+ const url = resolveChatCompletionsUrl(creds.baseUrl);
19
21
  for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
20
22
  const headers = { "Content-Type": "application/json" };
21
23
  if (creds.apiKey && creds.apiKey !== "ollama") {
22
24
  headers.Authorization = `Bearer ${creds.apiKey}`;
23
25
  }
24
- const body = {
26
+ const payload = {
25
27
  model: creds.model,
26
28
  messages,
27
29
  temperature: 0.2,
28
30
  };
29
31
  if (enableTools)
30
- body.tools = AGENT_TOOL_DEFINITIONS;
31
- const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
32
+ payload.tools = AGENT_TOOL_DEFINITIONS;
33
+ const res = await fetchWithTimeout(url, {
34
+ method: "POST",
35
+ headers,
36
+ body: JSON.stringify(deepseekRequestBody(creds.model, payload, { thinking })),
37
+ }, timeoutMs);
32
38
  const data = (await res.json().catch(() => ({})));
33
39
  if (!res.ok)
34
40
  throw new Error(data.error?.message ?? `Provider error (${res.status})`);
@@ -73,7 +79,7 @@ async function openAiAgentLoop(creds, cwd, messages, enableTools) {
73
79
  }
74
80
  throw new Error("Tool loop exceeded maximum rounds.");
75
81
  }
76
- async function anthropicAgentLoop(creds, cwd, system, messages, enableTools) {
82
+ async function anthropicAgentLoop(creds, cwd, system, messages, enableTools, timeoutMs) {
77
83
  const tools = enableTools
78
84
  ? AGENT_TOOL_DEFINITIONS.map((t) => ({
79
85
  name: t.function.name,
@@ -82,7 +88,7 @@ async function anthropicAgentLoop(creds, cwd, system, messages, enableTools) {
82
88
  }))
83
89
  : undefined;
84
90
  for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
85
- const res = await fetch("https://api.anthropic.com/v1/messages", {
91
+ const res = await fetchWithTimeout("https://api.anthropic.com/v1/messages", {
86
92
  method: "POST",
87
93
  headers: {
88
94
  "Content-Type": "application/json",
@@ -96,7 +102,7 @@ async function anthropicAgentLoop(creds, cwd, system, messages, enableTools) {
96
102
  messages,
97
103
  ...(tools ? { tools } : {}),
98
104
  }),
99
- });
105
+ }, timeoutMs);
100
106
  const data = (await res.json().catch(() => ({})));
101
107
  if (!res.ok)
102
108
  throw new Error(data.error?.message ?? `Anthropic error (${res.status})`);
@@ -138,23 +144,43 @@ async function anthropicAgentLoop(creds, cwd, system, messages, enableTools) {
138
144
  }
139
145
  export async function runByokAgentTurn(options) {
140
146
  const cwd = resolve(options.cwd);
141
- const ctx = await buildBootstrapContext(cwd);
142
- const prompt = buildAgentPrompt(options.task, ctx, options.locale);
147
+ const quick = localQuickAnswer(options.task, options.locale);
148
+ if (quick) {
149
+ console.log("\n" + quick);
150
+ return true;
151
+ }
152
+ const lite = options.lite ?? isLiteTurn(options.task);
153
+ const ctx = await buildBootstrapContext(cwd, { includeScan: !lite });
154
+ const prompt = buildAgentPrompt(options.task, ctx, options.locale, { lite });
143
155
  const system = `${planInstruction(options.mode)}\n\n${prompt.split("## Task")[0] ?? prompt}`;
144
156
  const userTask = `## Task\n${options.task}`;
145
- const enableTools = options.mode !== "ask";
157
+ const wantsTools = options.mode !== "ask" && !lite;
158
+ const enableTools = wantsTools && options.creds.definition.capabilities.supportsTools;
159
+ const thinking = !lite &&
160
+ options.creds.definition.capabilities.supportsReasoning &&
161
+ needsIntegrationContext(options.task);
162
+ const timeoutMs = lite
163
+ ? options.creds.definition.capabilities.liteTimeoutMs
164
+ : options.creds.definition.capabilities.agentTimeoutMs;
165
+ if (wantsTools && !enableTools) {
166
+ warn(options.locale === "pt"
167
+ ? `${options.creds.definition.name} não anuncia ferramentas de edição; vou responder sem alterar ficheiros.`
168
+ : options.locale === "zh"
169
+ ? `${options.creds.definition.name} 未声明编辑工具支持;我将只回答,不修改文件。`
170
+ : `${options.creds.definition.name} does not advertise edit tools; answering without changing files.`);
171
+ }
146
172
  try {
147
173
  if (options.creds.definition.kind === "anthropic") {
148
- const text = await anthropicAgentLoop(options.creds, cwd, system, [{ role: "user", content: userTask }], enableTools);
149
- console.log("\n" + text);
174
+ const text = await anthropicAgentLoop(options.creds, cwd, system, [{ role: "user", content: userTask }], enableTools, timeoutMs);
175
+ console.log("\n" + formatTerminalAnswer(text));
150
176
  return true;
151
177
  }
152
178
  const messages = [
153
179
  { role: "system", content: system },
154
180
  { role: "user", content: userTask },
155
181
  ];
156
- const text = await openAiAgentLoop(options.creds, cwd, messages, enableTools);
157
- console.log("\n" + text);
182
+ const text = await openAiAgentLoop(options.creds, cwd, messages, enableTools, thinking, timeoutMs);
183
+ console.log("\n" + formatTerminalAnswer(text));
158
184
  return true;
159
185
  }
160
186
  catch (err) {