@ekzs/cli 0.2.0 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -13
- package/dist/commands/agent.d.ts +0 -4
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +0 -6
- package/dist/commands/ask.d.ts +3 -5
- package/dist/commands/ask.d.ts.map +1 -1
- package/dist/commands/ask.js +50 -36
- package/dist/commands/local-agent.d.ts +0 -2
- package/dist/commands/local-agent.d.ts.map +1 -1
- package/dist/commands/local-agent.js +292 -131
- package/dist/commands/providers.d.ts +4 -0
- package/dist/commands/providers.d.ts.map +1 -0
- package/dist/commands/providers.js +6 -0
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +4 -0
- package/dist/index.js +41 -20
- package/dist/lib/commands-i18n.d.ts +12 -1
- package/dist/lib/commands-i18n.d.ts.map +1 -1
- package/dist/lib/commands-i18n.js +78 -14
- package/dist/lib/composer-model.d.ts +1 -1
- package/dist/lib/composer-model.d.ts.map +1 -1
- package/dist/lib/composer-model.js +2 -2
- package/dist/lib/global-config.d.ts +19 -0
- package/dist/lib/global-config.d.ts.map +1 -0
- package/dist/lib/global-config.js +52 -0
- package/dist/lib/help.d.ts.map +1 -1
- package/dist/lib/help.js +16 -12
- package/dist/lib/locale.d.ts.map +1 -1
- package/dist/lib/locale.js +2 -1
- package/dist/lib/onboarding.d.ts +20 -0
- package/dist/lib/onboarding.d.ts.map +1 -0
- package/dist/lib/onboarding.js +129 -0
- package/dist/lib/providers/agent-runner.d.ts +12 -0
- package/dist/lib/providers/agent-runner.d.ts.map +1 -0
- package/dist/lib/providers/agent-runner.js +167 -0
- package/dist/lib/providers/catalog.d.ts +15 -0
- package/dist/lib/providers/catalog.d.ts.map +1 -0
- package/dist/lib/providers/catalog.js +93 -0
- package/dist/lib/providers/chat.d.ts +10 -0
- package/dist/lib/providers/chat.d.ts.map +1 -0
- package/dist/lib/providers/chat.js +121 -0
- package/dist/lib/providers/credentials.d.ts +28 -0
- package/dist/lib/providers/credentials.d.ts.map +1 -0
- package/dist/lib/providers/credentials.js +70 -0
- package/dist/lib/providers/cursor-runner.d.ts +13 -0
- package/dist/lib/providers/cursor-runner.d.ts.map +1 -0
- package/dist/lib/providers/cursor-runner.js +89 -0
- package/dist/lib/providers/cursor-sdk.d.ts +8 -0
- package/dist/lib/providers/cursor-sdk.d.ts.map +1 -0
- package/dist/lib/providers/cursor-sdk.js +25 -0
- package/dist/lib/providers/store.d.ts +21 -0
- package/dist/lib/providers/store.d.ts.map +1 -0
- package/dist/lib/providers/store.js +84 -0
- package/dist/lib/providers/tools.d.ts +80 -0
- package/dist/lib/providers/tools.d.ts.map +1 -0
- package/dist/lib/providers/tools.js +145 -0
- package/dist/lib/providers/ui.d.ts +4 -0
- package/dist/lib/providers/ui.d.ts.map +1 -0
- package/dist/lib/providers/ui.js +188 -0
- package/dist/lib/setup-messages.d.ts +4 -0
- package/dist/lib/setup-messages.d.ts.map +1 -0
- package/dist/lib/setup-messages.js +13 -0
- package/dist/lib/ui/splash.d.ts.map +1 -1
- package/dist/lib/ui/splash.js +4 -0
- package/package.json +10 -2
- package/skills/ekz-sdk-cli/SKILL.md +6 -4
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type EkzLocale } from "../locale.js";
|
|
2
|
+
import { type SDKAgent } from "./cursor-sdk.js";
|
|
3
|
+
import { type ResolvedCredentials } from "./credentials.js";
|
|
4
|
+
declare function disposeAgent(agent: SDKAgent): Promise<void>;
|
|
5
|
+
declare function streamRun(agent: SDKAgent, prompt: string, locale: EkzLocale): 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":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
2
|
+
import { buildBootstrapContext } from "../context.js";
|
|
3
|
+
import { resolveComposerModel } from "../composer-model.js";
|
|
4
|
+
import { languageInstruction } from "../locale.js";
|
|
5
|
+
import { fail } from "../output.js";
|
|
6
|
+
import { agentScopeBlock } from "../scope.js";
|
|
7
|
+
import { toolDone, toolError, toolRunning } from "../theme.js";
|
|
8
|
+
import { loadCursorSdk } from "./cursor-sdk.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, locale) {
|
|
17
|
+
const { AgentBusyError, CursorAgentError } = await loadCursorSdk(locale);
|
|
18
|
+
const sendOptions = {
|
|
19
|
+
onDelta: ({ update }) => {
|
|
20
|
+
if (update.type === "text-delta" && update.text)
|
|
21
|
+
process.stdout.write(update.text);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
let run;
|
|
25
|
+
try {
|
|
26
|
+
run = await agent.send(prompt, sendOptions);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
if (err instanceof AgentBusyError) {
|
|
30
|
+
run = await agent.send(prompt, { ...sendOptions, local: { force: true } });
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for await (const event of run.stream()) {
|
|
37
|
+
if (event.type === "tool_call" && event.status === "running") {
|
|
38
|
+
process.stdout.write(toolRunning(event.name));
|
|
39
|
+
}
|
|
40
|
+
if (event.type === "tool_call" && event.status === "completed") {
|
|
41
|
+
process.stdout.write(toolDone(event.name));
|
|
42
|
+
}
|
|
43
|
+
if (event.type === "tool_call" && event.status === "error") {
|
|
44
|
+
process.stdout.write(toolError(event.name));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const result = await run.wait();
|
|
48
|
+
if (result.status === "error") {
|
|
49
|
+
throw new CursorAgentError(`Agent failed (${result.id})`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export async function executeCursorAskTurn(options) {
|
|
53
|
+
const cwd = resolve(options.cwd);
|
|
54
|
+
const ctx = await buildBootstrapContext(cwd);
|
|
55
|
+
const model = resolveComposerModel(process.env, options.creds.model);
|
|
56
|
+
const { Agent } = await loadCursorSdk(options.locale);
|
|
57
|
+
const prompt = `${agentScopeBlock(options.locale)}
|
|
58
|
+
|
|
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.
|
|
62
|
+
|
|
63
|
+
## Project context
|
|
64
|
+
${JSON.stringify({ issues: ctx.doctor.issues, scan: ctx.scan.slice(0, 12), env: ctx.env }, null, 2)}
|
|
65
|
+
|
|
66
|
+
## Question
|
|
67
|
+
${options.question}`;
|
|
68
|
+
let agent = null;
|
|
69
|
+
try {
|
|
70
|
+
agent = await Agent.create({
|
|
71
|
+
apiKey: options.creds.apiKey,
|
|
72
|
+
name: "Ekz Connect — ask",
|
|
73
|
+
model: { id: model.id, params: model.params },
|
|
74
|
+
local: { cwd, settingSources: ["project"] },
|
|
75
|
+
});
|
|
76
|
+
await streamRun(agent, prompt, options.locale);
|
|
77
|
+
console.log("");
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
if (agent)
|
|
86
|
+
await disposeAgent(agent);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export { disposeAgent, streamRun };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { EkzLocale } from "../locale.js";
|
|
2
|
+
export declare class CursorSdkMissingError extends Error {
|
|
3
|
+
constructor(locale?: EkzLocale);
|
|
4
|
+
}
|
|
5
|
+
type CursorSdkModule = typeof import("@cursor/sdk");
|
|
6
|
+
export declare function loadCursorSdk(locale?: EkzLocale): Promise<CursorSdkModule>;
|
|
7
|
+
export type { SDKAgent } from "@cursor/sdk";
|
|
8
|
+
//# sourceMappingURL=cursor-sdk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-sdk.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/cursor-sdk.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,MAAM,GAAE,SAAgB;CAWrC;AAED,KAAK,eAAe,GAAG,cAAc,aAAa,CAAC,CAAC;AAIpD,wBAAsB,aAAa,CAAC,MAAM,GAAE,SAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAQtF;AAED,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { providersCommandLabels } from "../commands-i18n.js";
|
|
2
|
+
export class CursorSdkMissingError extends Error {
|
|
3
|
+
constructor(locale = "en") {
|
|
4
|
+
const p = providersCommandLabels(locale);
|
|
5
|
+
const msg = locale === "pt"
|
|
6
|
+
? `Provider Cursor requer @cursor/sdk. Instala: npm install -g @cursor/sdk\nOu usa outro provider em ${p.repl}.`
|
|
7
|
+
: locale === "zh"
|
|
8
|
+
? `Cursor provider 需要 @cursor/sdk。安装: npm install -g @cursor/sdk\n或在 ${p.repl} 选择其他 provider。`
|
|
9
|
+
: `Cursor provider requires @cursor/sdk. Run: npm install -g @cursor/sdk\nOr pick another provider via ${p.repl}.`;
|
|
10
|
+
super(msg);
|
|
11
|
+
this.name = "CursorSdkMissingError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
let cached = null;
|
|
15
|
+
export async function loadCursorSdk(locale = "en") {
|
|
16
|
+
if (cached)
|
|
17
|
+
return cached;
|
|
18
|
+
try {
|
|
19
|
+
cached = await import("@cursor/sdk");
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new CursorSdkMissingError(locale);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -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;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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
import { clearGlobalOffline, markSetupComplete } from "../global-config.js";
|
|
6
|
+
const EKZ_HOME = join(homedir(), ".ekz");
|
|
7
|
+
const PROVIDERS_PATH = join(EKZ_HOME, "providers.json");
|
|
8
|
+
function ensureEkzHome() {
|
|
9
|
+
if (!existsSync(EKZ_HOME)) {
|
|
10
|
+
mkdirSync(EKZ_HOME, { recursive: true, mode: 0o700 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function providersFilePath() {
|
|
14
|
+
return PROVIDERS_PATH;
|
|
15
|
+
}
|
|
16
|
+
export function loadProvidersFile() {
|
|
17
|
+
ensureEkzHome();
|
|
18
|
+
if (!existsSync(PROVIDERS_PATH)) {
|
|
19
|
+
return { providers: {} };
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const data = JSON.parse(readFileSync(PROVIDERS_PATH, "utf8"));
|
|
23
|
+
return {
|
|
24
|
+
active: data.active,
|
|
25
|
+
providers: data.providers ?? {},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return { providers: {} };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function saveProvidersFile(data) {
|
|
33
|
+
ensureEkzHome();
|
|
34
|
+
writeFileSync(PROVIDERS_PATH, JSON.stringify(data, null, 2) + "\n", { mode: 0o600 });
|
|
35
|
+
try {
|
|
36
|
+
chmodSync(PROVIDERS_PATH, 0o600);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* windows */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function maskApiKey(key) {
|
|
43
|
+
const trimmed = key.trim();
|
|
44
|
+
if (trimmed.length <= 8)
|
|
45
|
+
return "••••••••";
|
|
46
|
+
return `${trimmed.slice(0, 4)}…${trimmed.slice(-4)}`;
|
|
47
|
+
}
|
|
48
|
+
export function getStoredProvider(id) {
|
|
49
|
+
return loadProvidersFile().providers[id];
|
|
50
|
+
}
|
|
51
|
+
export function setStoredProvider(id, entry) {
|
|
52
|
+
const file = loadProvidersFile();
|
|
53
|
+
file.providers[id] = entry;
|
|
54
|
+
if (!file.active)
|
|
55
|
+
file.active = id;
|
|
56
|
+
saveProvidersFile(file);
|
|
57
|
+
clearGlobalOffline();
|
|
58
|
+
markSetupComplete();
|
|
59
|
+
}
|
|
60
|
+
export function removeStoredProvider(id) {
|
|
61
|
+
const file = loadProvidersFile();
|
|
62
|
+
delete file.providers[id];
|
|
63
|
+
if (file.active === id) {
|
|
64
|
+
file.active = Object.keys(file.providers)[0];
|
|
65
|
+
}
|
|
66
|
+
saveProvidersFile(file);
|
|
67
|
+
}
|
|
68
|
+
export function setActiveProvider(id) {
|
|
69
|
+
const file = loadProvidersFile();
|
|
70
|
+
if (!file.providers[id]?.apiKey) {
|
|
71
|
+
throw new Error(`Provider "${id}" has no API key. Add one first.`);
|
|
72
|
+
}
|
|
73
|
+
file.active = id;
|
|
74
|
+
saveProvidersFile(file);
|
|
75
|
+
}
|
|
76
|
+
export function resolveModel(id, stored) {
|
|
77
|
+
const def = getProviderDefinition(id);
|
|
78
|
+
return stored?.model?.trim() || def?.defaultModel || "gpt-4o";
|
|
79
|
+
}
|
|
80
|
+
export function resolveBaseUrl(id, stored) {
|
|
81
|
+
if (stored?.baseUrl?.trim())
|
|
82
|
+
return stored.baseUrl.trim();
|
|
83
|
+
return getProviderDefinition(id)?.defaultBaseUrl;
|
|
84
|
+
}
|
|
@@ -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"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { execFile } from "child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
3
|
+
import { dirname, join, relative, resolve } from "path";
|
|
4
|
+
import { promisify } from "util";
|
|
5
|
+
import { detectShellEnvironment } from "../shell.js";
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
const MAX_FILE_BYTES = 120_000;
|
|
8
|
+
const MAX_CMD_OUTPUT = 24_000;
|
|
9
|
+
function safePath(cwd, input) {
|
|
10
|
+
const root = resolve(cwd);
|
|
11
|
+
const abs = resolve(root, input.trim());
|
|
12
|
+
const rel = relative(root, abs);
|
|
13
|
+
if (rel.startsWith("..") || rel.includes("..")) {
|
|
14
|
+
throw new Error(`Path escapes project root: ${input}`);
|
|
15
|
+
}
|
|
16
|
+
return abs;
|
|
17
|
+
}
|
|
18
|
+
export async function toolReadFile(cwd, path) {
|
|
19
|
+
const abs = safePath(cwd, path);
|
|
20
|
+
if (!existsSync(abs))
|
|
21
|
+
return `Error: file not found: ${path}`;
|
|
22
|
+
const stat = statSync(abs);
|
|
23
|
+
if (!stat.isFile())
|
|
24
|
+
return `Error: not a file: ${path}`;
|
|
25
|
+
if (stat.size > MAX_FILE_BYTES) {
|
|
26
|
+
return readFileSync(abs, "utf8").slice(0, MAX_FILE_BYTES) + "\n…[truncated]";
|
|
27
|
+
}
|
|
28
|
+
return readFileSync(abs, "utf8");
|
|
29
|
+
}
|
|
30
|
+
export async function toolWriteFile(cwd, path, content) {
|
|
31
|
+
const abs = safePath(cwd, path);
|
|
32
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
33
|
+
writeFileSync(abs, content, "utf8");
|
|
34
|
+
return `Wrote ${relative(resolve(cwd), abs)} (${content.length} bytes)`;
|
|
35
|
+
}
|
|
36
|
+
export async function toolListFiles(cwd, path = ".") {
|
|
37
|
+
const abs = safePath(cwd, path);
|
|
38
|
+
if (!existsSync(abs))
|
|
39
|
+
return `Error: path not found: ${path}`;
|
|
40
|
+
const stat = statSync(abs);
|
|
41
|
+
if (!stat.isDirectory())
|
|
42
|
+
return `Error: not a directory: ${path}`;
|
|
43
|
+
const entries = readdirSync(abs, { withFileTypes: true })
|
|
44
|
+
.slice(0, 200)
|
|
45
|
+
.map((e) => `${e.isDirectory() ? "d" : "f"} ${join(path, e.name).replace(/\\/g, "/")}`);
|
|
46
|
+
return entries.join("\n") || "(empty)";
|
|
47
|
+
}
|
|
48
|
+
export async function toolRunCommand(cwd, command) {
|
|
49
|
+
const shell = detectShellEnvironment();
|
|
50
|
+
const trimmed = command.trim();
|
|
51
|
+
if (!trimmed)
|
|
52
|
+
return "Error: empty command";
|
|
53
|
+
try {
|
|
54
|
+
if (shell.agentShell === "powershell") {
|
|
55
|
+
const { stdout, stderr } = await execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", trimmed], { cwd: resolve(cwd), timeout: 90_000, maxBuffer: MAX_CMD_OUTPUT });
|
|
56
|
+
return [stdout, stderr].filter(Boolean).join("\n").slice(0, MAX_CMD_OUTPUT) || "(no output)";
|
|
57
|
+
}
|
|
58
|
+
if (shell.agentShell === "cmd") {
|
|
59
|
+
const { stdout, stderr } = await execFileAsync("cmd.exe", ["/c", trimmed], {
|
|
60
|
+
cwd: resolve(cwd),
|
|
61
|
+
timeout: 90_000,
|
|
62
|
+
maxBuffer: MAX_CMD_OUTPUT,
|
|
63
|
+
});
|
|
64
|
+
return [stdout, stderr].filter(Boolean).join("\n").slice(0, MAX_CMD_OUTPUT) || "(no output)";
|
|
65
|
+
}
|
|
66
|
+
const { stdout, stderr } = await execFileAsync(trimmed, {
|
|
67
|
+
cwd: resolve(cwd),
|
|
68
|
+
timeout: 90_000,
|
|
69
|
+
maxBuffer: MAX_CMD_OUTPUT,
|
|
70
|
+
shell: true,
|
|
71
|
+
});
|
|
72
|
+
return [stdout, stderr].filter(Boolean).join("\n").slice(0, MAX_CMD_OUTPUT) || "(no output)";
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
const e = err;
|
|
76
|
+
const out = [e.stdout, e.stderr, e.message].filter(Boolean).join("\n");
|
|
77
|
+
return `Command failed:\n${out.slice(0, MAX_CMD_OUTPUT)}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export const AGENT_TOOL_DEFINITIONS = [
|
|
81
|
+
{
|
|
82
|
+
type: "function",
|
|
83
|
+
function: {
|
|
84
|
+
name: "read_file",
|
|
85
|
+
description: "Read a UTF-8 text file relative to the project root.",
|
|
86
|
+
parameters: {
|
|
87
|
+
type: "object",
|
|
88
|
+
properties: { path: { type: "string", description: "Relative file path" } },
|
|
89
|
+
required: ["path"],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
type: "function",
|
|
95
|
+
function: {
|
|
96
|
+
name: "write_file",
|
|
97
|
+
description: "Write or overwrite a UTF-8 text file relative to the project root.",
|
|
98
|
+
parameters: {
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: {
|
|
101
|
+
path: { type: "string" },
|
|
102
|
+
content: { type: "string" },
|
|
103
|
+
},
|
|
104
|
+
required: ["path", "content"],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
type: "function",
|
|
110
|
+
function: {
|
|
111
|
+
name: "list_files",
|
|
112
|
+
description: "List files and directories in a project-relative folder.",
|
|
113
|
+
parameters: {
|
|
114
|
+
type: "object",
|
|
115
|
+
properties: { path: { type: "string", description: "Directory path (default .)" } },
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: "function",
|
|
121
|
+
function: {
|
|
122
|
+
name: "run_command",
|
|
123
|
+
description: "Run a shell command in the project directory. Prefer ekz doctor/scan when possible.",
|
|
124
|
+
parameters: {
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: { command: { type: "string" } },
|
|
127
|
+
required: ["command"],
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
export async function executeAgentTool(cwd, name, args) {
|
|
133
|
+
switch (name) {
|
|
134
|
+
case "read_file":
|
|
135
|
+
return toolReadFile(cwd, String(args.path ?? ""));
|
|
136
|
+
case "write_file":
|
|
137
|
+
return toolWriteFile(cwd, String(args.path ?? ""), String(args.content ?? ""));
|
|
138
|
+
case "list_files":
|
|
139
|
+
return toolListFiles(cwd, args.path ? String(args.path) : ".");
|
|
140
|
+
case "run_command":
|
|
141
|
+
return toolRunCommand(cwd, String(args.command ?? ""));
|
|
142
|
+
default:
|
|
143
|
+
return `Unknown tool: ${name}`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +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"}
|