@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
@@ -13,7 +13,21 @@ export type ProviderDefinition = {
13
13
  models: string[];
14
14
  keyHint: string;
15
15
  docsUrl: string;
16
+ capabilities: {
17
+ requiresApiKey: boolean;
18
+ supportsTools: boolean;
19
+ supportsStreaming: boolean;
20
+ supportsReasoning: boolean;
21
+ liteTimeoutMs: number;
22
+ agentTimeoutMs: number;
23
+ };
16
24
  };
25
+ /**
26
+ * Model IDs synced from official provider docs (May 2026).
27
+ * Sources: cursor.com/docs, developers.openai.com, platform.claude.com,
28
+ * api-docs.deepseek.com, platform.kimi.ai, console.groq.com/docs/models,
29
+ * docs.mistral.ai, ai.google.dev/gemini-api/docs/models, ollama.com/library
30
+ */
17
31
  export declare const PROVIDER_CATALOG: ProviderDefinition[];
18
32
  export declare function getProviderDefinition(id: string): ProviderDefinition | undefined;
19
33
  export declare function resolveProviderModel(def: ProviderDefinition, storedModel?: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/catalog.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,mBAAmB,GAAG,WAAW,CAAC;AAExE,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,UAAU,GACV,MAAM,GACN,MAAM,GACN,SAAS,GACT,QAAQ,GACR,QAAQ,CAAC;AAEb,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,EAkHhD,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEhF;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1F"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/catalog.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,mBAAmB,GAAG,WAAW,CAAC;AAExE,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,UAAU,GACV,MAAM,GACN,MAAM,GACN,SAAS,GACT,QAAQ,GACR,QAAQ,CAAC;AAEb,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QACZ,cAAc,EAAE,OAAO,CAAC;QACxB,aAAa,EAAE,OAAO,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,iBAAiB,EAAE,OAAO,CAAC;QAC3B,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAWF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,EA2LhD,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEhF;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1F"}
@@ -1,3 +1,17 @@
1
+ const CLOUD_AGENT_CAPABILITIES = {
2
+ requiresApiKey: true,
3
+ supportsTools: true,
4
+ supportsStreaming: false,
5
+ supportsReasoning: false,
6
+ liteTimeoutMs: 20_000,
7
+ agentTimeoutMs: 60_000,
8
+ };
9
+ /**
10
+ * Model IDs synced from official provider docs (May 2026).
11
+ * Sources: cursor.com/docs, developers.openai.com, platform.claude.com,
12
+ * api-docs.deepseek.com, platform.kimi.ai, console.groq.com/docs/models,
13
+ * docs.mistral.ai, ai.google.dev/gemini-api/docs/models, ollama.com/library
14
+ */
1
15
  export const PROVIDER_CATALOG = [
2
16
  {
3
17
  id: "cursor",
@@ -7,110 +21,183 @@ export const PROVIDER_CATALOG = [
7
21
  defaultModel: "composer-2.5-fast",
8
22
  models: [
9
23
  "composer-2.5-fast",
10
- "composer-2-fast",
11
24
  "composer-2.5",
25
+ "composer-2-fast",
12
26
  "composer-2",
13
- "claude-4.6-sonnet-medium-thinking",
14
- "claude-opus-4-7-thinking-xhigh",
15
- "gemini-3-flash",
16
- "gemini-3.1-pro",
17
- "gpt-5.3-codex",
18
- "gpt-5.5-medium",
27
+ "claude-4.6-sonnet-thinking",
28
+ "claude-opus-4-7",
29
+ "gpt-5.5",
30
+ "gemini-3.5-flash",
19
31
  "kimi-k2.5",
20
32
  ],
21
33
  keyHint: "crsr_…",
22
34
  docsUrl: "https://cursor.com/dashboard/integrations",
35
+ capabilities: {
36
+ requiresApiKey: true,
37
+ supportsTools: true,
38
+ supportsStreaming: true,
39
+ supportsReasoning: false,
40
+ liteTimeoutMs: 20_000,
41
+ agentTimeoutMs: 90_000,
42
+ },
23
43
  },
24
44
  {
25
45
  id: "openai",
26
46
  name: "OpenAI",
27
47
  kind: "openai-compatible",
28
- description: "GPT-4o, o-series",
29
- defaultModel: "gpt-4o",
48
+ description: "GPT-5.5 frontier · GPT-5.4 · o-series",
49
+ defaultModel: "gpt-5.5",
30
50
  defaultBaseUrl: "https://api.openai.com/v1",
31
- models: ["gpt-4o", "gpt-4o-mini", "gpt-4.1", "gpt-4.1-mini", "o1", "o1-mini", "o3-mini"],
51
+ models: [
52
+ "gpt-5.5",
53
+ "gpt-5.4",
54
+ "gpt-5.4-mini",
55
+ "gpt-5.4-nano",
56
+ "gpt-4.1",
57
+ "gpt-4.1-mini",
58
+ "gpt-4o",
59
+ "gpt-4o-mini",
60
+ "o3",
61
+ "o4-mini",
62
+ ],
32
63
  keyHint: "sk-…",
33
64
  docsUrl: "https://platform.openai.com/api-keys",
65
+ capabilities: CLOUD_AGENT_CAPABILITIES,
34
66
  },
35
67
  {
36
68
  id: "anthropic",
37
69
  name: "Anthropic",
38
70
  kind: "anthropic",
39
- description: "Claude Sonnet / Opus",
40
- defaultModel: "claude-sonnet-4-20250514",
71
+ description: "Claude Opus 4.7 · Sonnet 4.6 · Haiku 4.5",
72
+ defaultModel: "claude-sonnet-4-6",
41
73
  models: [
42
- "claude-sonnet-4-20250514",
43
- "claude-opus-4-20250514",
44
- "claude-3-5-haiku-20241022",
74
+ "claude-sonnet-4-6",
75
+ "claude-opus-4-7",
76
+ "claude-haiku-4-5-20251001",
77
+ "claude-opus-4-6",
78
+ "claude-sonnet-4-5-20250929",
79
+ "claude-opus-4-5-20251101",
45
80
  ],
46
81
  keyHint: "sk-ant-…",
47
82
  docsUrl: "https://console.anthropic.com/settings/keys",
83
+ capabilities: CLOUD_AGENT_CAPABILITIES,
48
84
  },
49
85
  {
50
86
  id: "deepseek",
51
87
  name: "DeepSeek",
52
88
  kind: "openai-compatible",
53
- description: "DeepSeek Chat / Reasoner",
54
- defaultModel: "deepseek-chat",
55
- defaultBaseUrl: "https://api.deepseek.com",
56
- models: ["deepseek-chat", "deepseek-reasoner"],
89
+ description: "DeepSeek V4 Pro · V4 Flash",
90
+ defaultModel: "deepseek-v4-flash",
91
+ defaultBaseUrl: "https://api.deepseek.com/v1",
92
+ models: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-chat", "deepseek-reasoner"],
57
93
  keyHint: "sk-…",
58
94
  docsUrl: "https://platform.deepseek.com/api_keys",
95
+ capabilities: {
96
+ ...CLOUD_AGENT_CAPABILITIES,
97
+ supportsReasoning: true,
98
+ },
59
99
  },
60
100
  {
61
101
  id: "kimi",
62
102
  name: "Kimi (Moonshot)",
63
103
  kind: "openai-compatible",
64
- description: "Moonshot AI",
65
- defaultModel: "moonshot-v1-8k",
66
- defaultBaseUrl: "https://api.moonshot.cn/v1",
67
- models: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],
104
+ description: "Kimi K2.6 · K2.5 · Moonshot V1",
105
+ defaultModel: "kimi-k2.6",
106
+ defaultBaseUrl: "https://api.moonshot.ai/v1",
107
+ models: [
108
+ "kimi-k2.6",
109
+ "kimi-k2.5",
110
+ "moonshot-v1-8k",
111
+ "moonshot-v1-32k",
112
+ "moonshot-v1-128k",
113
+ ],
68
114
  keyHint: "sk-…",
69
- docsUrl: "https://platform.moonshot.cn/console/api-keys",
115
+ docsUrl: "https://platform.kimi.ai/docs/models",
116
+ capabilities: CLOUD_AGENT_CAPABILITIES,
70
117
  },
71
118
  {
72
119
  id: "groq",
73
120
  name: "Groq",
74
121
  kind: "openai-compatible",
75
- description: "Fast inference",
122
+ description: "Fast Llama · GPT-OSS · Qwen3",
76
123
  defaultModel: "llama-3.3-70b-versatile",
77
124
  defaultBaseUrl: "https://api.groq.com/openai/v1",
78
- models: ["llama-3.3-70b-versatile", "llama-3.1-8b-instant", "mixtral-8x7b-32768"],
125
+ models: [
126
+ "llama-3.3-70b-versatile",
127
+ "llama-3.1-8b-instant",
128
+ "openai/gpt-oss-120b",
129
+ "openai/gpt-oss-20b",
130
+ "qwen/qwen3-32b",
131
+ "meta-llama/llama-4-scout-17b-16e-instruct",
132
+ ],
79
133
  keyHint: "gsk_…",
80
- docsUrl: "https://console.groq.com/keys",
134
+ docsUrl: "https://console.groq.com/docs/models",
135
+ capabilities: CLOUD_AGENT_CAPABILITIES,
81
136
  },
82
137
  {
83
138
  id: "mistral",
84
139
  name: "Mistral",
85
140
  kind: "openai-compatible",
86
- description: "Mistral Large",
141
+ description: "Mistral Large · Small · Codestral",
87
142
  defaultModel: "mistral-large-latest",
88
143
  defaultBaseUrl: "https://api.mistral.ai/v1",
89
- models: ["mistral-large-latest", "mistral-small-latest", "codestral-latest"],
144
+ models: [
145
+ "mistral-large-latest",
146
+ "mistral-small-latest",
147
+ "mistral-medium-latest",
148
+ "codestral-latest",
149
+ "devstral-latest",
150
+ "magistral-medium-latest",
151
+ ],
90
152
  keyHint: "…",
91
- docsUrl: "https://console.mistral.ai/api-keys",
153
+ docsUrl: "https://docs.mistral.ai/models/overview",
154
+ capabilities: CLOUD_AGENT_CAPABILITIES,
92
155
  },
93
156
  {
94
157
  id: "google",
95
158
  name: "Google Gemini",
96
159
  kind: "openai-compatible",
97
- description: "Gemini models",
98
- defaultModel: "gemini-2.0-flash",
160
+ description: "Gemini 3.5 · 3.1 · 2.5",
161
+ defaultModel: "gemini-3.5-flash",
99
162
  defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
100
- models: ["gemini-2.0-flash", "gemini-2.0-flash-lite", "gemini-1.5-pro", "gemini-1.5-flash"],
163
+ models: [
164
+ "gemini-3.5-flash",
165
+ "gemini-3.1-pro-preview",
166
+ "gemini-3.1-flash-lite-preview",
167
+ "gemini-2.5-pro",
168
+ "gemini-2.5-flash",
169
+ "gemini-2.5-flash-lite",
170
+ ],
101
171
  keyHint: "AI…",
102
- docsUrl: "https://aistudio.google.com/apikey",
172
+ docsUrl: "https://ai.google.dev/gemini-api/docs/models",
173
+ capabilities: CLOUD_AGENT_CAPABILITIES,
103
174
  },
104
175
  {
105
176
  id: "ollama",
106
177
  name: "Ollama",
107
178
  kind: "openai-compatible",
108
- description: "Local models",
109
- defaultModel: "llama3.2",
179
+ description: "Local models (tags match `ollama run`)",
180
+ defaultModel: "llama3.3",
110
181
  defaultBaseUrl: "http://127.0.0.1:11434/v1",
111
- models: ["llama3.2", "llama3.1", "qwen2.5", "mistral", "deepseek-r1"],
182
+ models: [
183
+ "llama3.3",
184
+ "llama3.2",
185
+ "qwen3:8b",
186
+ "qwen2.5-coder:7b",
187
+ "deepseek-r1:8b",
188
+ "mistral",
189
+ "gemma3:4b",
190
+ ],
112
191
  keyHint: "ollama (optional)",
113
- docsUrl: "https://ollama.com",
192
+ docsUrl: "https://ollama.com/library",
193
+ capabilities: {
194
+ requiresApiKey: false,
195
+ supportsTools: false,
196
+ supportsStreaming: false,
197
+ supportsReasoning: false,
198
+ liteTimeoutMs: 10_000,
199
+ agentTimeoutMs: 30_000,
200
+ },
114
201
  },
115
202
  ];
116
203
  export function getProviderDefinition(id) {
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/chat.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAGnE,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAuG1B,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgDnB"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/chat.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAGnE,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAsH1B,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,OAAO,CAAC,CA6DnB"}
@@ -1,44 +1,51 @@
1
- import { buildBootstrapContext } from "../context.js";
1
+ import { buildBootstrapContext, isLiteTurn, needsIntegrationContext } from "../context.js";
2
2
  import { languageInstruction } from "../locale.js";
3
3
  import { agentScopeBlock } from "../scope.js";
4
4
  import { fail, info, ok } from "../output.js";
5
5
  import { ProviderSetupError, requireActiveCredentials, } from "./credentials.js";
6
- function buildAskSystemPrompt(ctx, locale) {
6
+ import { deepseekRequestBody, fetchWithTimeout, resolveChatCompletionsUrl, } from "./http.js";
7
+ import { formatTerminalAnswer, terminalStyleInstruction } from "../terminal-answer.js";
8
+ function buildAskSystemPrompt(ctx, locale, lite) {
9
+ const diagnostics = lite
10
+ ? { issues: ctx.doctor.issues.slice(0, 6), rails: ctx.doctor.rails, envKeys: Object.keys(ctx.env) }
11
+ : {
12
+ issues: ctx.doctor.issues,
13
+ warnings: ctx.doctor.warnings,
14
+ rails: ctx.doctor.rails,
15
+ health: ctx.doctor.health,
16
+ scan: ctx.scan.slice(0, 12),
17
+ env: ctx.env,
18
+ };
7
19
  return `You are **Ekz Connect** — an e-Kwanza v2.4 integration assistant.
8
20
  Answer in clear, actionable steps. You are in **ask mode**: explain and guide only; do not claim you edited files.
9
21
 
10
22
  ${agentScopeBlock(locale)}
11
23
 
12
- ${languageInstruction(locale)}
13
-
14
- ## Project context (doctor + scan)
15
- ${JSON.stringify({
16
- issues: ctx.doctor.issues,
17
- warnings: ctx.doctor.warnings,
18
- rails: ctx.doctor.rails,
19
- health: ctx.doctor.health,
20
- scan: ctx.scan.slice(0, 12),
21
- env: ctx.env,
22
- }, null, 2)}`;
24
+ ${languageInstruction(locale)}
25
+
26
+ ${terminalStyleInstruction(locale)}
27
+
28
+ ## Project context (doctor + scan)
29
+ ${JSON.stringify(diagnostics, null, 2)}`;
23
30
  }
24
- async function chatOpenAiCompatible(creds, messages) {
25
- const base = (creds.baseUrl ?? "https://api.openai.com/v1").replace(/\/$/, "");
26
- const url = base.endsWith("/chat/completions") ? base : `${base}/chat/completions`;
31
+ async function chatOpenAiCompatible(creds, messages, options) {
32
+ const url = resolveChatCompletionsUrl(creds.baseUrl);
27
33
  const headers = {
28
34
  "Content-Type": "application/json",
29
35
  };
30
36
  if (creds.apiKey && creds.apiKey !== "ollama") {
31
37
  headers.Authorization = `Bearer ${creds.apiKey}`;
32
38
  }
33
- const res = await fetch(url, {
39
+ const body = deepseekRequestBody(creds.model, {
40
+ model: creds.model,
41
+ messages,
42
+ temperature: 0.2,
43
+ }, { thinking: options?.thinking });
44
+ const res = await fetchWithTimeout(url, {
34
45
  method: "POST",
35
46
  headers,
36
- body: JSON.stringify({
37
- model: creds.model,
38
- messages,
39
- temperature: 0.2,
40
- }),
41
- });
47
+ body: JSON.stringify(body),
48
+ }, options?.timeoutMs);
42
49
  const data = (await res.json().catch(() => ({})));
43
50
  if (!res.ok) {
44
51
  throw new Error(data.error?.message ?? `Provider error (${res.status})`);
@@ -48,8 +55,8 @@ async function chatOpenAiCompatible(creds, messages) {
48
55
  throw new Error("Empty response from provider.");
49
56
  return text;
50
57
  }
51
- async function chatAnthropic(creds, system, question) {
52
- const res = await fetch("https://api.anthropic.com/v1/messages", {
58
+ async function chatAnthropic(creds, system, question, timeoutMs) {
59
+ const res = await fetchWithTimeout("https://api.anthropic.com/v1/messages", {
53
60
  method: "POST",
54
61
  headers: {
55
62
  "Content-Type": "application/json",
@@ -62,7 +69,7 @@ async function chatAnthropic(creds, system, question) {
62
69
  system,
63
70
  messages: [{ role: "user", content: question }],
64
71
  }),
65
- });
72
+ }, timeoutMs);
66
73
  const data = (await res.json().catch(() => ({})));
67
74
  if (!res.ok) {
68
75
  throw new Error(data.error?.message ?? `Anthropic error (${res.status})`);
@@ -78,7 +85,8 @@ async function chatAnthropic(creds, system, question) {
78
85
  }
79
86
  export async function executeByokAskTurn(options) {
80
87
  const locale = options.locale ?? "pt";
81
- const ctx = await buildBootstrapContext(options.cwd);
88
+ const lite = isLiteTurn(options.question);
89
+ const ctx = await buildBootstrapContext(options.cwd, { includeScan: !lite });
82
90
  let creds;
83
91
  try {
84
92
  creds = options.creds ?? requireActiveCredentials(locale);
@@ -98,20 +106,27 @@ export async function executeByokAskTurn(options) {
98
106
  : "Cursor ask uses the Cursor agent path — switch provider or use agent mode.");
99
107
  return false;
100
108
  }
101
- const system = buildAskSystemPrompt(ctx, locale);
109
+ const system = buildAskSystemPrompt(ctx, locale, lite);
110
+ const timeoutMs = lite
111
+ ? creds.definition.capabilities.liteTimeoutMs
112
+ : creds.definition.capabilities.agentTimeoutMs;
102
113
  if (!options.quiet) {
103
114
  info(`${creds.definition.name} · ${creds.model}`);
104
115
  }
105
116
  try {
106
117
  const answer = creds.definition.kind === "anthropic"
107
- ? await chatAnthropic(creds, system, options.question)
118
+ ? await chatAnthropic(creds, system, options.question, timeoutMs)
108
119
  : await chatOpenAiCompatible(creds, [
109
120
  { role: "system", content: system },
110
121
  { role: "user", content: options.question },
111
- ]);
122
+ ], {
123
+ thinking: creds.definition.capabilities.supportsReasoning &&
124
+ needsIntegrationContext(options.question),
125
+ timeoutMs,
126
+ });
112
127
  if (!options.quiet)
113
128
  ok(creds.definition.name);
114
- console.log("\n" + answer);
129
+ console.log("\n" + formatTerminalAnswer(answer));
115
130
  return true;
116
131
  }
117
132
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"cursor-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/cursor-runner.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,cAAc,CAAC;AAInE,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,iBAAe,YAAY,CAAC,KAAK,EAAE,QAAQ,iBAI1C;AAED,iBAAe,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC1F;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,SAAS,CAAC;CACnB,GAAG,OAAO,CAAC,OAAO,CAAC,CAmCnB;AAED,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"cursor-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/cursor-runner.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,cAAc,CAAC;AAKnE,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,iBAAe,YAAY,CAAC,KAAK,EAAE,QAAQ,iBAI1C;AAED,iBAAe,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC1F;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,SAAS,CAAC;CACnB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0CnB;AAED,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import { resolve } from "path";
2
- import { buildBootstrapContext } from "../context.js";
2
+ import { buildBootstrapContext, isLiteTurn } from "../context.js";
3
3
  import { resolveComposerModel } from "../composer-model.js";
4
4
  import { languageInstruction } from "../locale.js";
5
5
  import { fail } from "../output.js";
6
6
  import { agentScopeBlock } from "../scope.js";
7
+ import { formatTerminalDelta, terminalStyleInstruction } from "../terminal-answer.js";
7
8
  import { toolDone, toolError, toolRunning } from "../theme.js";
8
9
  import { loadCursorSdk } from "./cursor-sdk.js";
9
10
  async function disposeAgent(agent) {
@@ -17,8 +18,9 @@ async function streamRun(agent, prompt, locale) {
17
18
  const { AgentBusyError, CursorAgentError } = await loadCursorSdk(locale);
18
19
  const sendOptions = {
19
20
  onDelta: ({ update }) => {
20
- if (update.type === "text-delta" && update.text)
21
- process.stdout.write(update.text);
21
+ if (update.type === "text-delta" && update.text) {
22
+ process.stdout.write(formatTerminalDelta(update.text));
23
+ }
22
24
  },
23
25
  };
24
26
  let run;
@@ -51,17 +53,23 @@ async function streamRun(agent, prompt, locale) {
51
53
  }
52
54
  export async function executeCursorAskTurn(options) {
53
55
  const cwd = resolve(options.cwd);
54
- const ctx = await buildBootstrapContext(cwd);
56
+ const lite = isLiteTurn(options.question);
57
+ const ctx = await buildBootstrapContext(cwd, { includeScan: !lite });
55
58
  const model = resolveComposerModel(process.env, options.creds.model);
56
59
  const { Agent } = await loadCursorSdk(options.locale);
60
+ const diagnostics = lite
61
+ ? { issues: ctx.doctor.issues.slice(0, 6), rails: ctx.doctor.rails, envKeys: Object.keys(ctx.env) }
62
+ : { issues: ctx.doctor.issues, scan: ctx.scan.slice(0, 12), env: ctx.env };
57
63
  const prompt = `${agentScopeBlock(options.locale)}
58
64
 
59
- ${languageInstruction(options.locale)}
60
-
61
- You are in **ask mode** — answer only. Do not edit files or run tools unless the user explicitly asks for a command example.
65
+ ${languageInstruction(options.locale)}
66
+
67
+ ${terminalStyleInstruction(options.locale)}
68
+
69
+ You are in ask mode: answer only. Do not edit files or run tools unless the user explicitly asks for a command example.
62
70
 
63
71
  ## Project context
64
- ${JSON.stringify({ issues: ctx.doctor.issues, scan: ctx.scan.slice(0, 12), env: ctx.env }, null, 2)}
72
+ ${JSON.stringify(diagnostics, null, 2)}
65
73
 
66
74
  ## Question
67
75
  ${options.question}`;
@@ -0,0 +1,6 @@
1
+ export declare function resolveChatCompletionsUrl(baseUrl?: string): string;
2
+ export declare function fetchWithTimeout(url: string, init: RequestInit, timeoutMs?: number): Promise<Response>;
3
+ export declare function deepseekRequestBody(model: string, body: Record<string, unknown>, options?: {
4
+ thinking?: boolean;
5
+ }): Record<string, unknown>;
6
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/http.ts"],"names":[],"mappings":"AAEA,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAKlE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,SAAS,SAAqB,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAanB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB"}
@@ -0,0 +1,35 @@
1
+ const DEFAULT_TIMEOUT_MS = 60_000;
2
+ export function resolveChatCompletionsUrl(baseUrl) {
3
+ const base = (baseUrl ?? "https://api.openai.com/v1").replace(/\/$/, "");
4
+ if (base.endsWith("/chat/completions"))
5
+ return base;
6
+ if (base.endsWith("/v1"))
7
+ return `${base}/chat/completions`;
8
+ return `${base}/chat/completions`;
9
+ }
10
+ export async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_TIMEOUT_MS) {
11
+ const controller = new AbortController();
12
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
13
+ try {
14
+ return await fetch(url, { ...init, signal: controller.signal });
15
+ }
16
+ catch (err) {
17
+ if (err instanceof Error && err.name === "AbortError") {
18
+ throw new Error(`Provider request timed out after ${Math.round(timeoutMs / 1000)}s.`);
19
+ }
20
+ throw err;
21
+ }
22
+ finally {
23
+ clearTimeout(timer);
24
+ }
25
+ }
26
+ export function deepseekRequestBody(model, body, options) {
27
+ if (!model.startsWith("deepseek-v4"))
28
+ return body;
29
+ if (options?.thinking === false)
30
+ return body;
31
+ return {
32
+ ...body,
33
+ thinking: { type: "enabled" },
34
+ };
35
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/ui.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AA2N9C,gEAAgE;AAChE,wBAAsB,sBAAsB,CAAC,MAAM,GAAE,SAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBvF;AAED,wBAAsB,uBAAuB,CAAC,MAAM,GAAE,SAAgB,iBAuDrE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAMnE"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/ui.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AA4N9C,gEAAgE;AAChE,wBAAsB,sBAAsB,CAAC,MAAM,GAAE,SAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBvF;AAED,wBAAsB,uBAAuB,CAAC,MAAM,GAAE,SAAgB,iBAuDrE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAMnE"}
@@ -140,15 +140,16 @@ async function configureProvider(id, locale) {
140
140
  }
141
141
  const keyPrompt = t(locale, `Cola a API key (${def.keyHint}): `, `Paste API key (${def.keyHint}): `, `粘贴 API key (${def.keyHint}): `);
142
142
  const apiKey = await askLine(keyPrompt, true);
143
- if (!apiKey) {
143
+ if (!apiKey && def.capabilities.requiresApiKey) {
144
144
  warn(t(locale, "Chave vazia — cancelado.", "Empty key — cancelled.", "密钥为空,已取消。"));
145
145
  return false;
146
146
  }
147
+ const storedApiKey = apiKey || def.id;
147
148
  const model = await pickModel(id, locale);
148
149
  if (!model)
149
150
  return false;
150
- setStoredProvider(id, { apiKey, model });
151
- ok(t(locale, `Guardado ${def.name} · ${model} (${maskApiKey(apiKey)})`, `Saved ${def.name} · ${model} (${maskApiKey(apiKey)})`, `已保存 ${def.name} · ${model} (${maskApiKey(apiKey)})`));
151
+ setStoredProvider(id, { apiKey: storedApiKey, model });
152
+ ok(t(locale, `Guardado ${def.name} · ${model} (${maskApiKey(storedApiKey)})`, `Saved ${def.name} · ${model} (${maskApiKey(storedApiKey)})`, `已保存 ${def.name} · ${model} (${maskApiKey(storedApiKey)})`));
152
153
  return true;
153
154
  }
154
155
  function resolveRowTarget(rows, target) {
@@ -7,7 +7,9 @@ export type EkzSkill = {
7
7
  declare const SKILL_IDS: readonly ["ekz-connect", "ekz-payment-core-architecture", "ekz-ekwanza-provider-adapter", "ekz-webhook-normalization", "ekz-one-time-product-payments", "ekz-ticket-invite-selling", "ekz-subscription-billing", "ekz-overage-billing", "ekz-integration-playbook", "ekz-data-layer-design", "ekz-data-postgres", "ekz-data-mysql", "ekz-data-sqlite", "ekz-data-mongo", "ekz-sdk-cli"];
8
8
  export type EkzSkillId = (typeof SKILL_IDS)[number];
9
9
  export declare function loadAllSkills(): EkzSkill[];
10
- export declare function selectSkillsForTask(task: string, scanRules?: string[]): EkzSkill[];
10
+ export declare function selectSkillsForTask(task: string, scanRules?: string[], options?: {
11
+ lite?: boolean;
12
+ }): EkzSkill[];
11
13
  export declare function formatSkillsForPrompt(skills: EkzSkill[]): string;
12
14
  export declare function listSkillIds(): string[];
13
15
  /** @deprecated use formatSkillsForPrompt(selectSkillsForTask(...)) */
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/lib/skills.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,QAAA,MAAM,SAAS,yXAgBL,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAkIpD,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAe1C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAoClF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAIhE;AAED,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAQvC;AAED,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,6IAGiB,CAAC"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/lib/skills.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,QAAA,MAAM,SAAS,yXAgBL,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAoIpD,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAkB1C;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3B,QAAQ,EAAE,CA8CZ;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAIhE;AAED,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAQvC;AAED,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,6IAGiB,CAAC"}
@@ -132,7 +132,10 @@ function loadSkillFromDir(root, id) {
132
132
  const { name, description, body } = parseFrontmatter(raw);
133
133
  return { id, name: name || id, description, body };
134
134
  }
135
+ let cachedSkills = null;
135
136
  export function loadAllSkills() {
137
+ if (cachedSkills)
138
+ return cachedSkills;
136
139
  const roots = resolveSkillsRoots();
137
140
  const out = [];
138
141
  for (const id of SKILL_IDS) {
@@ -144,12 +147,16 @@ export function loadAllSkills() {
144
147
  }
145
148
  }
146
149
  }
150
+ cachedSkills = out;
147
151
  return out;
148
152
  }
149
- export function selectSkillsForTask(task, scanRules) {
153
+ export function selectSkillsForTask(task, scanRules, options) {
150
154
  const all = loadAllSkills();
151
155
  const byId = new Map(all.map((s) => [s.id, s]));
152
156
  const selected = new Set(["ekz-connect"]);
157
+ if (options?.lite) {
158
+ return [byId.get("ekz-connect")].filter((s) => Boolean(s));
159
+ }
153
160
  const haystack = [task, ...(scanRules ?? [])].join("\n");
154
161
  for (const { pattern, skills } of TASK_SKILL_MAP) {
155
162
  if (pattern.test(haystack)) {
@@ -164,14 +171,17 @@ export function selectSkillsForTask(task, scanRules) {
164
171
  selected.has("ekz-integration-playbook")) {
165
172
  selected.add("ekz-data-layer-design");
166
173
  }
167
- // Default bundle when nothing matched beyond orchestrator
174
+ // Full integration bundle only when the task actually needs it.
168
175
  if (selected.size === 1) {
169
- selected.add("ekz-payment-core-architecture");
170
- selected.add("ekz-ekwanza-provider-adapter");
171
- selected.add("ekz-webhook-normalization");
172
- selected.add("ekz-integration-playbook");
173
- selected.add("ekz-data-layer-design");
174
- selected.add("ekz-sdk-cli");
176
+ const needsBundle = /ekwanza|webhook|gpo|emis|ticket|checkout|integr|fix|audit|payment|rail|sdk|connect|scan|doctor|env/i.test(task);
177
+ if (needsBundle) {
178
+ selected.add("ekz-payment-core-architecture");
179
+ selected.add("ekz-ekwanza-provider-adapter");
180
+ selected.add("ekz-webhook-normalization");
181
+ selected.add("ekz-integration-playbook");
182
+ selected.add("ekz-data-layer-design");
183
+ selected.add("ekz-sdk-cli");
184
+ }
175
185
  }
176
186
  return SKILL_IDS.filter((id) => selected.has(id))
177
187
  .map((id) => byId.get(id))
@@ -0,0 +1,5 @@
1
+ import type { EkzLocale } from "./locale.js";
2
+ export declare function formatTerminalDelta(text: string): string;
3
+ export declare function formatTerminalAnswer(text: string): string;
4
+ export declare function terminalStyleInstruction(locale: EkzLocale): string;
5
+ //# sourceMappingURL=terminal-answer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-answer.d.ts","sourceRoot":"","sources":["../../src/lib/terminal-answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAkB7C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASzD;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CA4BlE"}