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