@ekzs/cli 0.2.0 → 0.3.0

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 (47) hide show
  1. package/README.md +21 -11
  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 +36 -35
  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 +200 -125
  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/index.js +25 -20
  15. package/dist/lib/commands-i18n.d.ts +12 -1
  16. package/dist/lib/commands-i18n.d.ts.map +1 -1
  17. package/dist/lib/commands-i18n.js +69 -14
  18. package/dist/lib/composer-model.d.ts +1 -1
  19. package/dist/lib/composer-model.d.ts.map +1 -1
  20. package/dist/lib/composer-model.js +2 -2
  21. package/dist/lib/help.js +13 -12
  22. package/dist/lib/providers/agent-runner.d.ts +12 -0
  23. package/dist/lib/providers/agent-runner.d.ts.map +1 -0
  24. package/dist/lib/providers/agent-runner.js +167 -0
  25. package/dist/lib/providers/catalog.d.ts +15 -0
  26. package/dist/lib/providers/catalog.d.ts.map +1 -0
  27. package/dist/lib/providers/catalog.js +93 -0
  28. package/dist/lib/providers/chat.d.ts +10 -0
  29. package/dist/lib/providers/chat.d.ts.map +1 -0
  30. package/dist/lib/providers/chat.js +121 -0
  31. package/dist/lib/providers/credentials.d.ts +26 -0
  32. package/dist/lib/providers/credentials.d.ts.map +1 -0
  33. package/dist/lib/providers/credentials.js +54 -0
  34. package/dist/lib/providers/cursor-runner.d.ts +13 -0
  35. package/dist/lib/providers/cursor-runner.d.ts.map +1 -0
  36. package/dist/lib/providers/cursor-runner.js +87 -0
  37. package/dist/lib/providers/store.d.ts +21 -0
  38. package/dist/lib/providers/store.d.ts.map +1 -0
  39. package/dist/lib/providers/store.js +81 -0
  40. package/dist/lib/providers/tools.d.ts +80 -0
  41. package/dist/lib/providers/tools.d.ts.map +1 -0
  42. package/dist/lib/providers/tools.js +145 -0
  43. package/dist/lib/providers/ui.d.ts +4 -0
  44. package/dist/lib/providers/ui.d.ts.map +1 -0
  45. package/dist/lib/providers/ui.js +188 -0
  46. package/package.json +1 -1
  47. package/skills/ekz-sdk-cli/SKILL.md +6 -4
@@ -0,0 +1,93 @@
1
+ export const PROVIDER_CATALOG = [
2
+ {
3
+ id: "cursor",
4
+ name: "Cursor",
5
+ kind: "cursor",
6
+ description: "Composer local agent (@cursor/sdk)",
7
+ defaultModel: "composer-2.5-fast",
8
+ keyHint: "crsr_…",
9
+ docsUrl: "https://cursor.com/dashboard/integrations",
10
+ },
11
+ {
12
+ id: "openai",
13
+ name: "OpenAI",
14
+ kind: "openai-compatible",
15
+ description: "GPT-4o, o-series",
16
+ defaultModel: "gpt-4o",
17
+ defaultBaseUrl: "https://api.openai.com/v1",
18
+ keyHint: "sk-…",
19
+ docsUrl: "https://platform.openai.com/api-keys",
20
+ },
21
+ {
22
+ id: "anthropic",
23
+ name: "Anthropic",
24
+ kind: "anthropic",
25
+ description: "Claude Sonnet / Opus",
26
+ defaultModel: "claude-sonnet-4-20250514",
27
+ keyHint: "sk-ant-…",
28
+ docsUrl: "https://console.anthropic.com/settings/keys",
29
+ },
30
+ {
31
+ id: "deepseek",
32
+ name: "DeepSeek",
33
+ kind: "openai-compatible",
34
+ description: "DeepSeek Chat / Reasoner",
35
+ defaultModel: "deepseek-chat",
36
+ defaultBaseUrl: "https://api.deepseek.com",
37
+ keyHint: "sk-…",
38
+ docsUrl: "https://platform.deepseek.com/api_keys",
39
+ },
40
+ {
41
+ id: "kimi",
42
+ name: "Kimi (Moonshot)",
43
+ kind: "openai-compatible",
44
+ description: "Moonshot AI",
45
+ defaultModel: "moonshot-v1-8k",
46
+ defaultBaseUrl: "https://api.moonshot.cn/v1",
47
+ keyHint: "sk-…",
48
+ docsUrl: "https://platform.moonshot.cn/console/api-keys",
49
+ },
50
+ {
51
+ id: "groq",
52
+ name: "Groq",
53
+ kind: "openai-compatible",
54
+ description: "Fast inference",
55
+ defaultModel: "llama-3.3-70b-versatile",
56
+ defaultBaseUrl: "https://api.groq.com/openai/v1",
57
+ keyHint: "gsk_…",
58
+ docsUrl: "https://console.groq.com/keys",
59
+ },
60
+ {
61
+ id: "mistral",
62
+ name: "Mistral",
63
+ kind: "openai-compatible",
64
+ description: "Mistral Large",
65
+ defaultModel: "mistral-large-latest",
66
+ defaultBaseUrl: "https://api.mistral.ai/v1",
67
+ keyHint: "…",
68
+ docsUrl: "https://console.mistral.ai/api-keys",
69
+ },
70
+ {
71
+ id: "google",
72
+ name: "Google Gemini",
73
+ kind: "openai-compatible",
74
+ description: "Gemini via OpenAI-compatible endpoint",
75
+ defaultModel: "gemini-2.0-flash",
76
+ defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
77
+ keyHint: "AI…",
78
+ docsUrl: "https://aistudio.google.com/apikey",
79
+ },
80
+ {
81
+ id: "ollama",
82
+ name: "Ollama",
83
+ kind: "openai-compatible",
84
+ description: "Local models",
85
+ defaultModel: "llama3.2",
86
+ defaultBaseUrl: "http://127.0.0.1:11434/v1",
87
+ keyHint: "ollama (optional)",
88
+ docsUrl: "https://ollama.com",
89
+ },
90
+ ];
91
+ export function getProviderDefinition(id) {
92
+ return PROVIDER_CATALOG.find((p) => p.id === id);
93
+ }
@@ -0,0 +1,10 @@
1
+ import { type EkzLocale } from "../locale.js";
2
+ import { type ResolvedCredentials } from "./credentials.js";
3
+ export declare function executeByokAskTurn(options: {
4
+ cwd: string;
5
+ question: string;
6
+ locale?: EkzLocale;
7
+ creds?: ResolvedCredentials | null;
8
+ quiet?: boolean;
9
+ }): Promise<boolean>;
10
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,121 @@
1
+ import { buildBootstrapContext } from "../context.js";
2
+ import { languageInstruction } from "../locale.js";
3
+ import { agentScopeBlock } from "../scope.js";
4
+ import { fail, info, ok } from "../output.js";
5
+ import { ProviderSetupError, requireActiveCredentials, } from "./credentials.js";
6
+ function buildAskSystemPrompt(ctx, locale) {
7
+ return `You are **Ekz Connect** — an e-Kwanza v2.4 integration assistant.
8
+ Answer in clear, actionable steps. You are in **ask mode**: explain and guide only; do not claim you edited files.
9
+
10
+ ${agentScopeBlock(locale)}
11
+
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)}`;
23
+ }
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`;
27
+ const headers = {
28
+ "Content-Type": "application/json",
29
+ };
30
+ if (creds.apiKey && creds.apiKey !== "ollama") {
31
+ headers.Authorization = `Bearer ${creds.apiKey}`;
32
+ }
33
+ const res = await fetch(url, {
34
+ method: "POST",
35
+ headers,
36
+ body: JSON.stringify({
37
+ model: creds.model,
38
+ messages,
39
+ temperature: 0.2,
40
+ }),
41
+ });
42
+ const data = (await res.json().catch(() => ({})));
43
+ if (!res.ok) {
44
+ throw new Error(data.error?.message ?? `Provider error (${res.status})`);
45
+ }
46
+ const text = data.choices?.[0]?.message?.content?.trim();
47
+ if (!text)
48
+ throw new Error("Empty response from provider.");
49
+ return text;
50
+ }
51
+ async function chatAnthropic(creds, system, question) {
52
+ const res = await fetch("https://api.anthropic.com/v1/messages", {
53
+ method: "POST",
54
+ headers: {
55
+ "Content-Type": "application/json",
56
+ "x-api-key": creds.apiKey,
57
+ "anthropic-version": "2023-06-01",
58
+ },
59
+ body: JSON.stringify({
60
+ model: creds.model,
61
+ max_tokens: 4096,
62
+ system,
63
+ messages: [{ role: "user", content: question }],
64
+ }),
65
+ });
66
+ const data = (await res.json().catch(() => ({})));
67
+ if (!res.ok) {
68
+ throw new Error(data.error?.message ?? `Anthropic error (${res.status})`);
69
+ }
70
+ const text = data.content
71
+ ?.filter((b) => b.type === "text")
72
+ .map((b) => b.text ?? "")
73
+ .join("")
74
+ .trim();
75
+ if (!text)
76
+ throw new Error("Empty response from Anthropic.");
77
+ return text;
78
+ }
79
+ export async function executeByokAskTurn(options) {
80
+ const locale = options.locale ?? "pt";
81
+ const ctx = await buildBootstrapContext(options.cwd);
82
+ let creds;
83
+ try {
84
+ creds = options.creds ?? requireActiveCredentials(locale);
85
+ }
86
+ catch (err) {
87
+ if (err instanceof ProviderSetupError) {
88
+ fail(err.message);
89
+ return false;
90
+ }
91
+ throw err;
92
+ }
93
+ if (creds.definition.kind === "cursor") {
94
+ fail(locale === "pt"
95
+ ? "Cursor em modo ask usa o agente Cursor (BYOK). Usa `/mode agent` ou escolhe OpenAI/Anthropic em `/provedores`."
96
+ : locale === "zh"
97
+ ? "Cursor 问答模式请使用 Cursor 代理,或在 `/供应商` 选择 OpenAI/Anthropic。"
98
+ : "Cursor ask uses the Cursor agent path — switch provider or use agent mode.");
99
+ return false;
100
+ }
101
+ const system = buildAskSystemPrompt(ctx, locale);
102
+ if (!options.quiet) {
103
+ info(`${creds.definition.name} · ${creds.model}`);
104
+ }
105
+ try {
106
+ const answer = creds.definition.kind === "anthropic"
107
+ ? await chatAnthropic(creds, system, options.question)
108
+ : await chatOpenAiCompatible(creds, [
109
+ { role: "system", content: system },
110
+ { role: "user", content: options.question },
111
+ ]);
112
+ if (!options.quiet)
113
+ ok(creds.definition.name);
114
+ console.log("\n" + answer);
115
+ return true;
116
+ }
117
+ catch (err) {
118
+ fail(err instanceof Error ? err.message : String(err));
119
+ return false;
120
+ }
121
+ }
@@ -0,0 +1,26 @@
1
+ import { type ProviderDefinition, type ProviderId } from "./catalog.js";
2
+ import { type StoredProvider } from "./store.js";
3
+ export type ResolvedCredentials = {
4
+ id: ProviderId;
5
+ definition: ProviderDefinition;
6
+ apiKey: string;
7
+ model: string;
8
+ baseUrl?: string;
9
+ maskedKey: string;
10
+ };
11
+ export declare class ProviderSetupError extends Error {
12
+ constructor(message: string);
13
+ }
14
+ export type ProviderRow = {
15
+ definition: ProviderDefinition;
16
+ stored?: StoredProvider;
17
+ active: boolean;
18
+ maskedKey: string | null;
19
+ model: string;
20
+ };
21
+ export declare function listProviderRows(): ProviderRow[];
22
+ export declare function getActiveProviderId(): ProviderId | undefined;
23
+ export declare function resolveActiveCredentials(): ResolvedCredentials | null;
24
+ export declare function requireActiveCredentials(locale?: "pt" | "en" | "zh"): ResolvedCredentials;
25
+ export declare function isCursorProvider(creds: ResolvedCredentials): boolean;
26
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1F,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,UAAU,CAAC;IACf,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,gBAAgB,IAAI,WAAW,EAAE,CAYhD;AAED,wBAAgB,mBAAmB,IAAI,UAAU,GAAG,SAAS,CAE5D;AAED,wBAAgB,wBAAwB,IAAI,mBAAmB,GAAG,IAAI,CAgBrE;AAED,wBAAgB,wBAAwB,CAAC,MAAM,GAAE,IAAI,GAAG,IAAI,GAAG,IAAW,GAAG,mBAAmB,CAI/F;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAEpE"}
@@ -0,0 +1,54 @@
1
+ import { PROVIDER_CATALOG } from "./catalog.js";
2
+ import { providersSetupHint } from "../commands-i18n.js";
3
+ import { loadProvidersFile, maskApiKey, resolveBaseUrl, resolveModel, } from "./store.js";
4
+ export class ProviderSetupError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "ProviderSetupError";
8
+ }
9
+ }
10
+ export function listProviderRows() {
11
+ const file = loadProvidersFile();
12
+ return PROVIDER_CATALOG.map((definition) => {
13
+ const stored = file.providers[definition.id];
14
+ return {
15
+ definition,
16
+ stored,
17
+ active: file.active === definition.id,
18
+ maskedKey: stored?.apiKey ? maskApiKey(stored.apiKey) : null,
19
+ model: resolveModel(definition.id, stored),
20
+ };
21
+ });
22
+ }
23
+ export function getActiveProviderId() {
24
+ return loadProvidersFile().active;
25
+ }
26
+ export function resolveActiveCredentials() {
27
+ const file = loadProvidersFile();
28
+ const id = file.active;
29
+ if (!id)
30
+ return null;
31
+ const stored = file.providers[id];
32
+ if (!stored?.apiKey?.trim())
33
+ return null;
34
+ const definition = PROVIDER_CATALOG.find((p) => p.id === id);
35
+ if (!definition)
36
+ return null;
37
+ return {
38
+ id,
39
+ definition,
40
+ apiKey: stored.apiKey.trim(),
41
+ model: resolveModel(id, stored),
42
+ baseUrl: resolveBaseUrl(id, stored),
43
+ maskedKey: maskApiKey(stored.apiKey),
44
+ };
45
+ }
46
+ export function requireActiveCredentials(locale = "en") {
47
+ const creds = resolveActiveCredentials();
48
+ if (creds)
49
+ return creds;
50
+ throw new ProviderSetupError(providersSetupHint(locale));
51
+ }
52
+ export function isCursorProvider(creds) {
53
+ return creds.definition.kind === "cursor";
54
+ }
@@ -0,0 +1,13 @@
1
+ import { type SDKAgent } from "@cursor/sdk";
2
+ import { type EkzLocale } from "../locale.js";
3
+ import { type ResolvedCredentials } from "./credentials.js";
4
+ declare function disposeAgent(agent: SDKAgent): Promise<void>;
5
+ declare function streamRun(agent: SDKAgent, prompt: string): Promise<void>;
6
+ export declare function executeCursorAskTurn(options: {
7
+ cwd: string;
8
+ question: string;
9
+ creds: ResolvedCredentials;
10
+ locale: EkzLocale;
11
+ }): Promise<boolean>;
12
+ export { disposeAgent, streamRun };
13
+ //# sourceMappingURL=cursor-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/cursor-runner.ts"],"names":[],"mappings":"AACA,OAAO,EAA2C,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIrF,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAK9C,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,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCvE;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,CAkCnB;AAED,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,87 @@
1
+ import { resolve } from "path";
2
+ import { Agent, AgentBusyError, CursorAgentError } from "@cursor/sdk";
3
+ import { buildBootstrapContext } from "../context.js";
4
+ import { resolveComposerModel } from "../composer-model.js";
5
+ import { fail } from "../output.js";
6
+ import { toolDone, toolError, toolRunning } from "../theme.js";
7
+ import { languageInstruction } from "../locale.js";
8
+ import { agentScopeBlock } from "../scope.js";
9
+ async function disposeAgent(agent) {
10
+ const disposer = agent[Symbol.asyncDispose];
11
+ if (typeof disposer === "function")
12
+ await disposer.call(agent);
13
+ else
14
+ agent.close();
15
+ }
16
+ async function streamRun(agent, prompt) {
17
+ const sendOptions = {
18
+ onDelta: ({ update }) => {
19
+ if (update.type === "text-delta" && update.text)
20
+ process.stdout.write(update.text);
21
+ },
22
+ };
23
+ let run;
24
+ try {
25
+ run = await agent.send(prompt, sendOptions);
26
+ }
27
+ catch (err) {
28
+ if (err instanceof AgentBusyError) {
29
+ run = await agent.send(prompt, { ...sendOptions, local: { force: true } });
30
+ }
31
+ else {
32
+ throw err;
33
+ }
34
+ }
35
+ for await (const event of run.stream()) {
36
+ if (event.type === "tool_call" && event.status === "running") {
37
+ process.stdout.write(toolRunning(event.name));
38
+ }
39
+ if (event.type === "tool_call" && event.status === "completed") {
40
+ process.stdout.write(toolDone(event.name));
41
+ }
42
+ if (event.type === "tool_call" && event.status === "error") {
43
+ process.stdout.write(toolError(event.name));
44
+ }
45
+ }
46
+ const result = await run.wait();
47
+ if (result.status === "error") {
48
+ throw new CursorAgentError(`Agent failed (${result.id})`);
49
+ }
50
+ }
51
+ export async function executeCursorAskTurn(options) {
52
+ const cwd = resolve(options.cwd);
53
+ const ctx = await buildBootstrapContext(cwd);
54
+ const model = resolveComposerModel(process.env, options.creds.model);
55
+ const prompt = `${agentScopeBlock(options.locale)}
56
+
57
+ ${languageInstruction(options.locale)}
58
+
59
+ You are in **ask mode** — answer only. Do not edit files or run tools unless the user explicitly asks for a command example.
60
+
61
+ ## Project context
62
+ ${JSON.stringify({ issues: ctx.doctor.issues, scan: ctx.scan.slice(0, 12), env: ctx.env }, null, 2)}
63
+
64
+ ## Question
65
+ ${options.question}`;
66
+ let agent = null;
67
+ try {
68
+ agent = await Agent.create({
69
+ apiKey: options.creds.apiKey,
70
+ name: "Ekz Connect — ask",
71
+ model: { id: model.id, params: model.params },
72
+ local: { cwd, settingSources: ["project"] },
73
+ });
74
+ await streamRun(agent, prompt);
75
+ console.log("");
76
+ return true;
77
+ }
78
+ catch (err) {
79
+ fail(err instanceof Error ? err.message : String(err));
80
+ return false;
81
+ }
82
+ finally {
83
+ if (agent)
84
+ await disposeAgent(agent);
85
+ }
86
+ }
87
+ export { disposeAgent, streamRun };
@@ -0,0 +1,21 @@
1
+ import { type ProviderId } from "./catalog.js";
2
+ export type StoredProvider = {
3
+ apiKey: string;
4
+ model?: string;
5
+ baseUrl?: string;
6
+ };
7
+ export type ProvidersFile = {
8
+ active?: ProviderId;
9
+ providers: Partial<Record<ProviderId, StoredProvider>>;
10
+ };
11
+ export declare function providersFilePath(): string;
12
+ export declare function loadProvidersFile(): ProvidersFile;
13
+ export declare function saveProvidersFile(data: ProvidersFile): void;
14
+ export declare function maskApiKey(key: string): string;
15
+ export declare function getStoredProvider(id: ProviderId): StoredProvider | undefined;
16
+ export declare function setStoredProvider(id: ProviderId, entry: StoredProvider): void;
17
+ export declare function removeStoredProvider(id: ProviderId): void;
18
+ export declare function setActiveProvider(id: ProviderId): void;
19
+ export declare function resolveModel(id: ProviderId, stored?: StoredProvider): string;
20
+ export declare function resolveBaseUrl(id: ProviderId, stored?: StoredProvider): string | undefined;
21
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +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;AAEtE,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,QAKtE;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"}
@@ -0,0 +1,81 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ import { getProviderDefinition } from "./catalog.js";
5
+ const EKZ_HOME = join(homedir(), ".ekz");
6
+ const PROVIDERS_PATH = join(EKZ_HOME, "providers.json");
7
+ function ensureEkzHome() {
8
+ if (!existsSync(EKZ_HOME)) {
9
+ mkdirSync(EKZ_HOME, { recursive: true, mode: 0o700 });
10
+ }
11
+ }
12
+ export function providersFilePath() {
13
+ return PROVIDERS_PATH;
14
+ }
15
+ export function loadProvidersFile() {
16
+ ensureEkzHome();
17
+ if (!existsSync(PROVIDERS_PATH)) {
18
+ return { providers: {} };
19
+ }
20
+ try {
21
+ const data = JSON.parse(readFileSync(PROVIDERS_PATH, "utf8"));
22
+ return {
23
+ active: data.active,
24
+ providers: data.providers ?? {},
25
+ };
26
+ }
27
+ catch {
28
+ return { providers: {} };
29
+ }
30
+ }
31
+ export function saveProvidersFile(data) {
32
+ ensureEkzHome();
33
+ writeFileSync(PROVIDERS_PATH, JSON.stringify(data, null, 2) + "\n", { mode: 0o600 });
34
+ try {
35
+ chmodSync(PROVIDERS_PATH, 0o600);
36
+ }
37
+ catch {
38
+ /* windows */
39
+ }
40
+ }
41
+ export function maskApiKey(key) {
42
+ const trimmed = key.trim();
43
+ if (trimmed.length <= 8)
44
+ return "••••••••";
45
+ return `${trimmed.slice(0, 4)}…${trimmed.slice(-4)}`;
46
+ }
47
+ export function getStoredProvider(id) {
48
+ return loadProvidersFile().providers[id];
49
+ }
50
+ export function setStoredProvider(id, entry) {
51
+ const file = loadProvidersFile();
52
+ file.providers[id] = entry;
53
+ if (!file.active)
54
+ file.active = id;
55
+ saveProvidersFile(file);
56
+ }
57
+ export function removeStoredProvider(id) {
58
+ const file = loadProvidersFile();
59
+ delete file.providers[id];
60
+ if (file.active === id) {
61
+ file.active = Object.keys(file.providers)[0];
62
+ }
63
+ saveProvidersFile(file);
64
+ }
65
+ export function setActiveProvider(id) {
66
+ const file = loadProvidersFile();
67
+ if (!file.providers[id]?.apiKey) {
68
+ throw new Error(`Provider "${id}" has no API key. Add one first.`);
69
+ }
70
+ file.active = id;
71
+ saveProvidersFile(file);
72
+ }
73
+ export function resolveModel(id, stored) {
74
+ const def = getProviderDefinition(id);
75
+ return stored?.model?.trim() || def?.defaultModel || "gpt-4o";
76
+ }
77
+ export function resolveBaseUrl(id, stored) {
78
+ if (stored?.baseUrl?.trim())
79
+ return stored.baseUrl.trim();
80
+ return getProviderDefinition(id)?.defaultBaseUrl;
81
+ }
@@ -0,0 +1,80 @@
1
+ export declare function toolReadFile(cwd: string, path: string): Promise<string>;
2
+ export declare function toolWriteFile(cwd: string, path: string, content: string): Promise<string>;
3
+ export declare function toolListFiles(cwd: string, path?: string): Promise<string>;
4
+ export declare function toolRunCommand(cwd: string, command: string): Promise<string>;
5
+ export declare const AGENT_TOOL_DEFINITIONS: ({
6
+ type: "function";
7
+ function: {
8
+ name: string;
9
+ description: string;
10
+ parameters: {
11
+ type: string;
12
+ properties: {
13
+ path: {
14
+ type: string;
15
+ description: string;
16
+ };
17
+ content?: undefined;
18
+ command?: undefined;
19
+ };
20
+ required: string[];
21
+ };
22
+ };
23
+ } | {
24
+ type: "function";
25
+ function: {
26
+ name: string;
27
+ description: string;
28
+ parameters: {
29
+ type: string;
30
+ properties: {
31
+ path: {
32
+ type: string;
33
+ description?: undefined;
34
+ };
35
+ content: {
36
+ type: string;
37
+ };
38
+ command?: undefined;
39
+ };
40
+ required: string[];
41
+ };
42
+ };
43
+ } | {
44
+ type: "function";
45
+ function: {
46
+ name: string;
47
+ description: string;
48
+ parameters: {
49
+ type: string;
50
+ properties: {
51
+ path: {
52
+ type: string;
53
+ description: string;
54
+ };
55
+ content?: undefined;
56
+ command?: undefined;
57
+ };
58
+ required?: undefined;
59
+ };
60
+ };
61
+ } | {
62
+ type: "function";
63
+ function: {
64
+ name: string;
65
+ description: string;
66
+ parameters: {
67
+ type: string;
68
+ properties: {
69
+ command: {
70
+ type: string;
71
+ };
72
+ path?: undefined;
73
+ content?: undefined;
74
+ };
75
+ required: string[];
76
+ };
77
+ };
78
+ })[];
79
+ export declare function executeAgentTool(cwd: string, name: string, args: Record<string, unknown>): Promise<string>;
80
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/tools.ts"],"names":[],"mappings":"AAqBA,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS7E;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK/F;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,SAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAU5E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkClF;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmDlC,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC,CAajB"}