@ekzs/cli 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ import { runScan } from "./commands/scan.js";
13
13
  import { runProvidersCommand } from "./commands/providers.js";
14
14
  import { runSetupCommand } from "./commands/setup.js";
15
15
  import { runWebhookTest } from "./commands/webhook.js";
16
+ import { packageVersion } from "./lib/version.js";
16
17
  const SUBCOMMANDS = new Set([
17
18
  "doctor",
18
19
  "health",
@@ -40,7 +41,7 @@ const program = new Command();
40
41
  program
41
42
  .name("ekz")
42
43
  .description("EKZ CONNECT — e-Kwanza v2.4 coding agent by Alberto Moisés")
43
- .version("0.3.0");
44
+ .version(packageVersion());
44
45
  program
45
46
  .command("doctor")
46
47
  .description("Validate .env and run live credential checks (free)")
@@ -5,7 +5,7 @@ import { parseLocale } from "./locale.js";
5
5
  import { formatSetupRequiredMessage } from "./setup-messages.js";
6
6
  import { info, ok } from "./output.js";
7
7
  import { ProviderSetupError, resolveActiveCredentials, resolveCredentialsWithOverride, } from "./providers/credentials.js";
8
- import { runProvidersInteractive } from "./providers/ui.js";
8
+ import { runSetupProviderWizard } from "./providers/ui.js";
9
9
  import { c, muted } from "./theme.js";
10
10
  function t(locale, pt, en, zh) {
11
11
  if (locale === "pt")
@@ -80,8 +80,8 @@ async function providerStep(locale) {
80
80
  return "offline";
81
81
  }
82
82
  if (choice === "1" || choice === "p" || choice === "providers" || choice === "provedores" || choice === "供应商") {
83
- await runProvidersInteractive(locale);
84
- if (resolveActiveCredentials()) {
83
+ const configured = await runSetupProviderWizard(locale);
84
+ if (configured && resolveActiveCredentials()) {
85
85
  clearGlobalOffline();
86
86
  ok(t(locale, "Provedor configurado.", "Provider configured.", "Provider 已配置。"));
87
87
  return "configured";
@@ -5,11 +5,16 @@ export type ProviderDefinition = {
5
5
  name: string;
6
6
  kind: ProviderKind;
7
7
  description: string;
8
+ /** Default model when user presses Enter */
8
9
  defaultModel: string;
10
+ /** Predefined API base — never shown in UI */
9
11
  defaultBaseUrl?: string;
12
+ /** Selectable models in setup / providers menu */
13
+ models: string[];
10
14
  keyHint: string;
11
15
  docsUrl: string;
12
16
  };
13
17
  export declare const PROVIDER_CATALOG: ProviderDefinition[];
14
18
  export declare function getProviderDefinition(id: string): ProviderDefinition | undefined;
19
+ export declare function resolveProviderModel(def: ProviderDefinition, storedModel?: string): string;
15
20
  //# sourceMappingURL=catalog.d.ts.map
@@ -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,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,EAyFhD,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEhF"}
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"}
@@ -5,6 +5,19 @@ export const PROVIDER_CATALOG = [
5
5
  kind: "cursor",
6
6
  description: "Composer local agent (@cursor/sdk)",
7
7
  defaultModel: "composer-2.5-fast",
8
+ models: [
9
+ "composer-2.5-fast",
10
+ "composer-2-fast",
11
+ "composer-2.5",
12
+ "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",
19
+ "kimi-k2.5",
20
+ ],
8
21
  keyHint: "crsr_…",
9
22
  docsUrl: "https://cursor.com/dashboard/integrations",
10
23
  },
@@ -15,6 +28,7 @@ export const PROVIDER_CATALOG = [
15
28
  description: "GPT-4o, o-series",
16
29
  defaultModel: "gpt-4o",
17
30
  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"],
18
32
  keyHint: "sk-…",
19
33
  docsUrl: "https://platform.openai.com/api-keys",
20
34
  },
@@ -24,6 +38,11 @@ export const PROVIDER_CATALOG = [
24
38
  kind: "anthropic",
25
39
  description: "Claude Sonnet / Opus",
26
40
  defaultModel: "claude-sonnet-4-20250514",
41
+ models: [
42
+ "claude-sonnet-4-20250514",
43
+ "claude-opus-4-20250514",
44
+ "claude-3-5-haiku-20241022",
45
+ ],
27
46
  keyHint: "sk-ant-…",
28
47
  docsUrl: "https://console.anthropic.com/settings/keys",
29
48
  },
@@ -34,6 +53,7 @@ export const PROVIDER_CATALOG = [
34
53
  description: "DeepSeek Chat / Reasoner",
35
54
  defaultModel: "deepseek-chat",
36
55
  defaultBaseUrl: "https://api.deepseek.com",
56
+ models: ["deepseek-chat", "deepseek-reasoner"],
37
57
  keyHint: "sk-…",
38
58
  docsUrl: "https://platform.deepseek.com/api_keys",
39
59
  },
@@ -44,6 +64,7 @@ export const PROVIDER_CATALOG = [
44
64
  description: "Moonshot AI",
45
65
  defaultModel: "moonshot-v1-8k",
46
66
  defaultBaseUrl: "https://api.moonshot.cn/v1",
67
+ models: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],
47
68
  keyHint: "sk-…",
48
69
  docsUrl: "https://platform.moonshot.cn/console/api-keys",
49
70
  },
@@ -54,6 +75,7 @@ export const PROVIDER_CATALOG = [
54
75
  description: "Fast inference",
55
76
  defaultModel: "llama-3.3-70b-versatile",
56
77
  defaultBaseUrl: "https://api.groq.com/openai/v1",
78
+ models: ["llama-3.3-70b-versatile", "llama-3.1-8b-instant", "mixtral-8x7b-32768"],
57
79
  keyHint: "gsk_…",
58
80
  docsUrl: "https://console.groq.com/keys",
59
81
  },
@@ -64,6 +86,7 @@ export const PROVIDER_CATALOG = [
64
86
  description: "Mistral Large",
65
87
  defaultModel: "mistral-large-latest",
66
88
  defaultBaseUrl: "https://api.mistral.ai/v1",
89
+ models: ["mistral-large-latest", "mistral-small-latest", "codestral-latest"],
67
90
  keyHint: "…",
68
91
  docsUrl: "https://console.mistral.ai/api-keys",
69
92
  },
@@ -71,9 +94,10 @@ export const PROVIDER_CATALOG = [
71
94
  id: "google",
72
95
  name: "Google Gemini",
73
96
  kind: "openai-compatible",
74
- description: "Gemini via OpenAI-compatible endpoint",
97
+ description: "Gemini models",
75
98
  defaultModel: "gemini-2.0-flash",
76
99
  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"],
77
101
  keyHint: "AI…",
78
102
  docsUrl: "https://aistudio.google.com/apikey",
79
103
  },
@@ -84,6 +108,7 @@ export const PROVIDER_CATALOG = [
84
108
  description: "Local models",
85
109
  defaultModel: "llama3.2",
86
110
  defaultBaseUrl: "http://127.0.0.1:11434/v1",
111
+ models: ["llama3.2", "llama3.1", "qwen2.5", "mistral", "deepseek-r1"],
87
112
  keyHint: "ollama (optional)",
88
113
  docsUrl: "https://ollama.com",
89
114
  },
@@ -91,3 +116,11 @@ export const PROVIDER_CATALOG = [
91
116
  export function getProviderDefinition(id) {
92
117
  return PROVIDER_CATALOG.find((p) => p.id === id);
93
118
  }
119
+ export function resolveProviderModel(def, storedModel) {
120
+ const trimmed = storedModel?.trim();
121
+ if (trimmed && def.models.includes(trimmed))
122
+ return trimmed;
123
+ if (trimmed && !def.models.includes(trimmed))
124
+ return trimmed;
125
+ return def.defaultModel;
126
+ }
@@ -17,5 +17,5 @@ export declare function setStoredProvider(id: ProviderId, entry: StoredProvider)
17
17
  export declare function removeStoredProvider(id: ProviderId): void;
18
18
  export declare function setActiveProvider(id: ProviderId): void;
19
19
  export declare function resolveModel(id: ProviderId, stored?: StoredProvider): string;
20
- export declare function resolveBaseUrl(id: ProviderId, stored?: StoredProvider): string | undefined;
20
+ export declare function resolveBaseUrl(id: ProviderId, _stored?: StoredProvider): string | undefined;
21
21
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/store.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAyB,MAAM,cAAc,CAAC;AAGtE,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;CACxD,CAAC;AAWF,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,iBAAiB,IAAI,aAAa,CAcjD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,QAQpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,GAAG,cAAc,GAAG,SAAS,CAE5E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,cAAc,QAOtE;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,UAAU,QAOlD;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,QAO/C;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,MAAM,CAG5E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAG1F"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/store.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAyB,MAAM,cAAc,CAAC;AAGtE,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;CACxD,CAAC;AAWF,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,iBAAiB,IAAI,aAAa,CAcjD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,QAQpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,GAAG,cAAc,GAAG,SAAS,CAE5E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,cAAc,QAQtE;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,UAAU,QAOlD;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,QAO/C;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,MAAM,CAM5E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAE3F"}
@@ -50,9 +50,9 @@ export function getStoredProvider(id) {
50
50
  }
51
51
  export function setStoredProvider(id, entry) {
52
52
  const file = loadProvidersFile();
53
- file.providers[id] = entry;
54
- if (!file.active)
55
- file.active = id;
53
+ const { baseUrl: _ignored, ...rest } = entry;
54
+ file.providers[id] = rest;
55
+ file.active = id;
56
56
  saveProvidersFile(file);
57
57
  clearGlobalOffline();
58
58
  markSetupComplete();
@@ -75,10 +75,13 @@ export function setActiveProvider(id) {
75
75
  }
76
76
  export function resolveModel(id, stored) {
77
77
  const def = getProviderDefinition(id);
78
- return stored?.model?.trim() || def?.defaultModel || "gpt-4o";
78
+ if (!def)
79
+ return stored?.model?.trim() || "gpt-4o";
80
+ const trimmed = stored?.model?.trim();
81
+ if (trimmed)
82
+ return trimmed;
83
+ return def.defaultModel;
79
84
  }
80
- export function resolveBaseUrl(id, stored) {
81
- if (stored?.baseUrl?.trim())
82
- return stored.baseUrl.trim();
85
+ export function resolveBaseUrl(id, _stored) {
83
86
  return getProviderDefinition(id)?.defaultBaseUrl;
84
87
  }
@@ -1,4 +1,6 @@
1
1
  import { type EkzLocale } from "../locale.js";
2
+ /** One-shot provider pick + configure — used by `ekz setup`. */
3
+ export declare function runSetupProviderWizard(locale?: EkzLocale): Promise<boolean>;
2
4
  export declare function runProvidersInteractive(locale?: EkzLocale): Promise<void>;
3
5
  export declare function formatActiveProviderLabel(locale: EkzLocale): string;
4
6
  //# sourceMappingURL=ui.d.ts.map
@@ -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;AA+L9C,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;AAqN9C,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"}
@@ -88,10 +88,46 @@ function printProviderList(rows, locale) {
88
88
  console.log(` ${muted(t(locale, "[número] configurar · u usar · r remover · q sair", "[number] configure · u use · r remove · q quit", "[数字] 配置 · u 使用 · r 删除 · q 退出"))}`);
89
89
  console.log("");
90
90
  }
91
+ function printCatalogPicker(locale) {
92
+ console.log("");
93
+ console.log(` ${c.bold}${t(locale, "Escolhe o provedor", "Choose provider", "选择 provider")}${c.reset}`);
94
+ console.log("");
95
+ PROVIDER_CATALOG.forEach((def, index) => {
96
+ console.log(` ${c.bold}${String(index + 1).padStart(2)}.${c.reset} ${def.name.padEnd(16)} ${muted(def.description)}`);
97
+ });
98
+ console.log("");
99
+ }
100
+ async function pickModel(id, locale) {
101
+ const def = getProviderDefinition(id);
102
+ if (!def)
103
+ return null;
104
+ const defaultIndex = Math.max(0, def.models.findIndex((m) => m === def.defaultModel));
105
+ const defaultNum = defaultIndex + 1;
106
+ console.log("");
107
+ console.log(` ${c.bold}${t(locale, "Modelo", "Model", "模型")}${c.reset}`);
108
+ def.models.forEach((model, index) => {
109
+ const n = index + 1;
110
+ const tag = model === def.defaultModel
111
+ ? muted(t(locale, " · predefinição", " · default", " · 默认"))
112
+ : "";
113
+ console.log(` ${c.bold}${String(n).padStart(2)}.${c.reset} ${model}${tag}`);
114
+ });
115
+ console.log("");
116
+ const prompt = t(locale, ` Escolha [${defaultNum}]: `, ` Choice [${defaultNum}]: `, ` 选择 [${defaultNum}]: `);
117
+ const choice = await askLine(prompt);
118
+ if (!choice)
119
+ return def.defaultModel;
120
+ const num = Number(choice);
121
+ if (Number.isInteger(num) && num >= 1 && num <= def.models.length) {
122
+ return def.models[num - 1];
123
+ }
124
+ warn(t(locale, "Opção inválida — a usar predefinição.", "Invalid choice — using default.", "无效选项 — 使用默认。"));
125
+ return def.defaultModel;
126
+ }
91
127
  async function configureProvider(id, locale) {
92
128
  const def = getProviderDefinition(id);
93
129
  if (!def)
94
- return;
130
+ return false;
95
131
  console.log("");
96
132
  console.log(` ${c.bold}${def.name}${c.reset} — ${muted(def.description)}`);
97
133
  console.log(` ${muted(def.docsUrl)}`);
@@ -100,29 +136,14 @@ async function configureProvider(id, locale) {
100
136
  const apiKey = await askLine(keyPrompt, true);
101
137
  if (!apiKey) {
102
138
  warn(t(locale, "Chave vazia — cancelado.", "Empty key — cancelled.", "密钥为空,已取消。"));
103
- return;
104
- }
105
- const modelDefault = def.defaultModel;
106
- const modelPrompt = t(locale, `Modelo [${modelDefault}]: `, `Model [${modelDefault}]: `, `模型 [${modelDefault}]: `);
107
- const modelInput = await askLine(modelPrompt);
108
- const model = modelInput || modelDefault;
109
- let baseUrl;
110
- if (def.kind === "openai-compatible" || def.defaultBaseUrl) {
111
- const urlPrompt = t(locale, `Base URL [${def.defaultBaseUrl ?? "(default)"}]: `, `Base URL [${def.defaultBaseUrl ?? "(default)"}]: `, `Base URL [${def.defaultBaseUrl ?? "(default)"}]: `);
112
- const urlInput = await askLine(urlPrompt);
113
- if (urlInput)
114
- baseUrl = urlInput;
115
- }
116
- setStoredProvider(id, { apiKey, model, baseUrl });
117
- ok(t(locale, `Guardado ${def.name} (${maskApiKey(apiKey)})`, `Saved ${def.name} (${maskApiKey(apiKey)})`, `已保存 ${def.name} (${maskApiKey(apiKey)})`));
118
- const active = resolveActiveCredentials();
119
- if (!active || active.id !== id) {
120
- const useNow = await askLine(t(locale, "Usar como provider activo? [Y/n]: ", "Use as active provider? [Y/n]: ", "设为当前 provider? [Y/n]: "), false);
121
- if (!useNow || useNow.toLowerCase() === "y" || useNow.toLowerCase() === "s" || useNow === "") {
122
- setActiveProvider(id);
123
- ok(t(locale, `${def.name} activo.`, `${def.name} is now active.`, `${def.name} 已激活。`));
124
- }
139
+ return false;
125
140
  }
141
+ const model = await pickModel(id, locale);
142
+ if (!model)
143
+ return false;
144
+ setStoredProvider(id, { apiKey, model });
145
+ ok(t(locale, `Guardado ${def.name} · ${model} (${maskApiKey(apiKey)})`, `Saved ${def.name} · ${model} (${maskApiKey(apiKey)})`, `已保存 ${def.name} · ${model} (${maskApiKey(apiKey)})`));
146
+ return true;
126
147
  }
127
148
  function resolveRowTarget(rows, target) {
128
149
  const trimmed = target.trim().toLowerCase();
@@ -132,6 +153,21 @@ function resolveRowTarget(rows, target) {
132
153
  }
133
154
  return rows.find((r) => r.definition.id === trimmed);
134
155
  }
156
+ /** One-shot provider pick + configure — used by `ekz setup`. */
157
+ export async function runSetupProviderWizard(locale = "pt") {
158
+ printCatalogPicker(locale);
159
+ const prompt = t(locale, " Número do provedor (Enter cancelar): ", " Provider number (Enter to cancel): ", " Provider 编号 (Enter 取消): ");
160
+ const choice = (await askLine(prompt)).trim();
161
+ if (!choice)
162
+ return false;
163
+ const num = Number(choice);
164
+ if (!Number.isInteger(num) || num < 1 || num > PROVIDER_CATALOG.length) {
165
+ warn(t(locale, "Opção inválida.", "Invalid option.", "无效选项。"));
166
+ return false;
167
+ }
168
+ const def = PROVIDER_CATALOG[num - 1];
169
+ return configureProvider(def.id, locale);
170
+ }
135
171
  export async function runProvidersInteractive(locale = "pt") {
136
172
  while (true) {
137
173
  const rows = listProviderRows();
@@ -184,5 +220,5 @@ export function formatActiveProviderLabel(locale) {
184
220
  if (!creds) {
185
221
  return t(locale, "sem provider", "no provider", "未配置");
186
222
  }
187
- return `${creds.definition.name} · ${creds.maskedKey}`;
223
+ return `${creds.definition.name} · ${creds.model} · ${creds.maskedKey}`;
188
224
  }
@@ -0,0 +1,2 @@
1
+ export declare function packageVersion(): string;
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/lib/version.ts"],"names":[],"mappings":"AAMA,wBAAgB,cAAc,IAAI,MAAM,CASvC"}
@@ -0,0 +1,13 @@
1
+ import { readFileSync } from "fs";
2
+ import { dirname, join } from "path";
3
+ import { fileURLToPath } from "url";
4
+ const here = dirname(fileURLToPath(import.meta.url));
5
+ export function packageVersion() {
6
+ try {
7
+ const pkg = JSON.parse(readFileSync(join(here, "../../package.json"), "utf8"));
8
+ return pkg.version ?? "0.0.0";
9
+ }
10
+ catch {
11
+ return "0.0.0";
12
+ }
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekzs/cli",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "CLI agent for e-Kwanza v2.4 — health checks, code scan, webhook tests, AI assistance",
5
5
  "type": "module",
6
6
  "bin": {