@breviqcode/cli 0.1.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.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/config-resolver.d.ts +22 -0
- package/dist/config-resolver.d.ts.map +1 -0
- package/dist/config-resolver.js +66 -0
- package/dist/config-resolver.js.map +1 -0
- package/dist/custom-commands.d.ts +21 -0
- package/dist/custom-commands.d.ts.map +1 -0
- package/dist/custom-commands.js +73 -0
- package/dist/custom-commands.js.map +1 -0
- package/dist/flags.d.ts +11 -0
- package/dist/flags.d.ts.map +1 -0
- package/dist/flags.js +16 -0
- package/dist/flags.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +159 -0
- package/dist/index.js.map +1 -0
- package/dist/onboarding.d.ts +35 -0
- package/dist/onboarding.d.ts.map +1 -0
- package/dist/onboarding.js +131 -0
- package/dist/onboarding.js.map +1 -0
- package/dist/prompt.d.ts +29 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +60 -0
- package/dist/prompt.js.map +1 -0
- package/dist/provider-presets.d.ts +22 -0
- package/dist/provider-presets.d.ts.map +1 -0
- package/dist/provider-presets.js +60 -0
- package/dist/provider-presets.js.map +1 -0
- package/dist/provider.d.ts +26 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +61 -0
- package/dist/provider.js.map +1 -0
- package/dist/runtime.d.ts +68 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +127 -0
- package/dist/runtime.js.map +1 -0
- package/dist/system-prompt.d.ts +17 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +32 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/tui/App.d.ts +44 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +894 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/format-tool-call.d.ts +35 -0
- package/dist/tui/format-tool-call.d.ts.map +1 -0
- package/dist/tui/format-tool-call.js +129 -0
- package/dist/tui/format-tool-call.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { SecretStore, UserConfig } from "@breviqcode/core";
|
|
3
|
+
import { PROVIDER_PRESETS } from "./provider-presets.js";
|
|
4
|
+
/** See prompt.ts's stripBOM — same PowerShell-piped-input gotcha applies here. */
|
|
5
|
+
function stripBOM(s) {
|
|
6
|
+
return s.replace(/^/, "");
|
|
7
|
+
}
|
|
8
|
+
// The provider menu itself lives in provider-presets.ts, shared with the
|
|
9
|
+
// TUI's in-session /provider picker so the two lists can never drift.
|
|
10
|
+
// Numbering here is just each preset's 1-based position.
|
|
11
|
+
/**
|
|
12
|
+
* Runs once, the first time `breviq` is used (no config file yet — see
|
|
13
|
+
* `resolveConfig`): picks a provider, stores its API key/credentials in the
|
|
14
|
+
* OS keychain via SecretStore (not a plaintext `.env`), and picks a default
|
|
15
|
+
* model. This closes a real gap both the Go version and this rewrite's
|
|
16
|
+
* first milestone had — there was never an interactive setup path, only a
|
|
17
|
+
* hand-edited `.env` file.
|
|
18
|
+
*
|
|
19
|
+
* Reads every answer off ONE shared readline async-iterator (`nextLine`),
|
|
20
|
+
* the same pattern `createInteractiveIO` in prompt.ts uses — NOT
|
|
21
|
+
* sequential `rl.question()` calls. `question()` attaches a one-shot
|
|
22
|
+
* listener only at call time; readline emits a `'line'` event for every
|
|
23
|
+
* buffered line as soon as it's parsed, with or without a listener
|
|
24
|
+
* present, so any lines that arrive before the next `question()` call
|
|
25
|
+
* attaches its listener are fired to nobody and silently lost. That's
|
|
26
|
+
* exactly what happened here the first time this file was written: piped
|
|
27
|
+
* input answered the first question, but subsequent answers were already
|
|
28
|
+
* sitting in the stream before `question()` was called again, so they were
|
|
29
|
+
* dropped and the next `question()` call hung on a `'line'` event that had
|
|
30
|
+
* already come and gone — until stdin's EOF let Node exit with nothing left
|
|
31
|
+
* keeping the event loop alive. The async-iterator protocol queues
|
|
32
|
+
* unclaimed lines instead of discarding them, so it's safe regardless of
|
|
33
|
+
* how fast the input arrives. See onboarding.test.ts for the regression
|
|
34
|
+
* test and CLAUDE.md for the full incident writeup.
|
|
35
|
+
*
|
|
36
|
+
* Also deliberately does NOT mask secret entry (no `***` echo) — masking
|
|
37
|
+
* would require reading raw keypresses outside this shared line queue,
|
|
38
|
+
* reintroducing the same class of bug. The security property that
|
|
39
|
+
* actually matters (secrets are never written to a plaintext file, only
|
|
40
|
+
* the OS credential store) holds regardless of terminal echo during
|
|
41
|
+
* one-time entry.
|
|
42
|
+
*/
|
|
43
|
+
export async function runOnboarding(configPath, secretsService, input = process.stdin, output = process.stderr) {
|
|
44
|
+
const rl = createInterface({ input, output });
|
|
45
|
+
const lines = rl[Symbol.asyncIterator]();
|
|
46
|
+
const nextLine = async () => {
|
|
47
|
+
const { value: rawLine, done } = await lines.next();
|
|
48
|
+
return stripBOM(done ? "" : rawLine).trim();
|
|
49
|
+
};
|
|
50
|
+
const ask = async (promptText) => {
|
|
51
|
+
output.write(promptText);
|
|
52
|
+
return nextLine();
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
output.write("Welcome to BreviqCode! Let's set up your provider.\n\n");
|
|
56
|
+
PROVIDER_PRESETS.forEach((preset, i) => {
|
|
57
|
+
output.write(` [${i + 1}] ${preset.label}\n`);
|
|
58
|
+
});
|
|
59
|
+
const providerAnswer = await ask(`\nChoose a provider [1-${PROVIDER_PRESETS.length}]: `);
|
|
60
|
+
const byNumber = PROVIDER_PRESETS[Number(providerAnswer) - 1];
|
|
61
|
+
const choice = byNumber ?? PROVIDER_PRESETS.find((p) => p.id === providerAnswer) ?? PROVIDER_PRESETS[0];
|
|
62
|
+
let baseUrl;
|
|
63
|
+
let azureResourceName;
|
|
64
|
+
let azureDeploymentName;
|
|
65
|
+
let azureApiVersion;
|
|
66
|
+
let awsRegion;
|
|
67
|
+
let apiKey;
|
|
68
|
+
switch (choice.flow) {
|
|
69
|
+
case "ask-base-url": {
|
|
70
|
+
const answer = await ask(`Base URL (blank for local Ollama at ${choice.askDefaultBaseUrl}): `);
|
|
71
|
+
baseUrl = answer || undefined;
|
|
72
|
+
apiKey = await ask("API key (leave blank for a keyless local server): ");
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case "fixed-base-url": {
|
|
76
|
+
baseUrl = choice.fixedBaseUrl;
|
|
77
|
+
apiKey = await ask(`${choice.label} API key: `);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case "workers-ai": {
|
|
81
|
+
const accountId = await ask("Cloudflare account ID: ");
|
|
82
|
+
baseUrl = `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1`;
|
|
83
|
+
apiKey = await ask("Cloudflare API token: ");
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "azure": {
|
|
87
|
+
azureResourceName = await ask("Azure resource name (the <name> in <name>.openai.azure.com): ");
|
|
88
|
+
azureDeploymentName = await ask("Azure deployment name: ");
|
|
89
|
+
azureApiVersion = (await ask("API version [2024-06-01]: ")) || "2024-06-01";
|
|
90
|
+
apiKey = await ask("Azure OpenAI API key: ");
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case "bedrock": {
|
|
94
|
+
const accessKeyId = await ask("AWS access key ID: ");
|
|
95
|
+
const secretAccessKey = await ask("AWS secret access key: ");
|
|
96
|
+
const sessionToken = await ask("AWS session token (blank if not using temporary credentials): ");
|
|
97
|
+
awsRegion = (await ask("AWS region [us-east-1]: ")) || "us-east-1";
|
|
98
|
+
apiKey = JSON.stringify({ accessKeyId, secretAccessKey, sessionToken: sessionToken || undefined });
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case "none":
|
|
102
|
+
default:
|
|
103
|
+
apiKey = await ask(`${choice.label} API key: `);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
const modelAnswer = await ask(`Model name [${choice.defaultModel}]: `);
|
|
107
|
+
const config = {
|
|
108
|
+
preset: choice.id,
|
|
109
|
+
provider: choice.adapter,
|
|
110
|
+
baseUrl,
|
|
111
|
+
model: modelAnswer || choice.defaultModel,
|
|
112
|
+
azureResourceName,
|
|
113
|
+
azureDeploymentName,
|
|
114
|
+
azureApiVersion,
|
|
115
|
+
awsRegion,
|
|
116
|
+
};
|
|
117
|
+
new UserConfig(configPath).save(config);
|
|
118
|
+
if (apiKey) {
|
|
119
|
+
// Keyed by preset id, not adapter name — Groq/OpenAI/OpenRouter all
|
|
120
|
+
// use the "openai" adapter but must keep separate stored keys, or
|
|
121
|
+
// switching between them silently reuses the wrong credential.
|
|
122
|
+
new SecretStore(secretsService).setApiKey(choice.id, apiKey);
|
|
123
|
+
}
|
|
124
|
+
output.write("\nSaved. You can redo this any time with `breviq config`.\n\n");
|
|
125
|
+
return config;
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
rl.close();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=onboarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../src/onboarding.ts"],"names":[],"mappings":"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"}
|
package/dist/prompt.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Asker, Prompter } from "@breviqcode/core";
|
|
2
|
+
/**
|
|
3
|
+
* Builds interactive stdin/stderr I/O for one CLI run, backed by ONE
|
|
4
|
+
* shared readline interface and its async-iterator protocol — both the
|
|
5
|
+
* permission-confirmation prompter and the `question` tool's asker read
|
|
6
|
+
* from the same queue, since they can otherwise interleave within a
|
|
7
|
+
* single run (a tool call needing confirmation, then the model asking the
|
|
8
|
+
* user something, or vice versa).
|
|
9
|
+
*
|
|
10
|
+
* This matters for two reasons: (1) a single agent turn can call multiple
|
|
11
|
+
* tools needing confirmation (the model sometimes double-checks itself,
|
|
12
|
+
* calling write_file twice in a row), so the prompter must be reusable
|
|
13
|
+
* across many calls in one run; (2) `readline.Interface.question()`
|
|
14
|
+
* attaches a one-shot listener only at the moment it's called — if piped
|
|
15
|
+
* input delivers several lines in one burst *before* the next `question()`
|
|
16
|
+
* call attaches its listener (entirely possible with piped/scripted
|
|
17
|
+
* input, since there's no natural typing delay between answers), the
|
|
18
|
+
* extra buffered lines are silently dropped with no error. The async
|
|
19
|
+
* iterator protocol (`for await` / `Symbol.asyncIterator`) queues
|
|
20
|
+
* unclaimed lines instead of discarding them, so calling `.next()`
|
|
21
|
+
* repeatedly — from either consumer — is safe regardless of how the
|
|
22
|
+
* input arrives.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createInteractiveIO(input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream): {
|
|
25
|
+
prompt: Prompter;
|
|
26
|
+
ask: Asker;
|
|
27
|
+
close: () => void;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAUvD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,GAC7C;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAiCrD"}
|
package/dist/prompt.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
/** Strips a leading UTF-8 byte-order mark, defensively — some shells (we
|
|
3
|
+
* hit this with PowerShell piping into the original Go version) prefix
|
|
4
|
+
* piped string input with one, and it isn't Unicode whitespace so a plain
|
|
5
|
+
* trim leaves it behind. */
|
|
6
|
+
function stripBOM(s) {
|
|
7
|
+
return s.replace(/^/, "");
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Builds interactive stdin/stderr I/O for one CLI run, backed by ONE
|
|
11
|
+
* shared readline interface and its async-iterator protocol — both the
|
|
12
|
+
* permission-confirmation prompter and the `question` tool's asker read
|
|
13
|
+
* from the same queue, since they can otherwise interleave within a
|
|
14
|
+
* single run (a tool call needing confirmation, then the model asking the
|
|
15
|
+
* user something, or vice versa).
|
|
16
|
+
*
|
|
17
|
+
* This matters for two reasons: (1) a single agent turn can call multiple
|
|
18
|
+
* tools needing confirmation (the model sometimes double-checks itself,
|
|
19
|
+
* calling write_file twice in a row), so the prompter must be reusable
|
|
20
|
+
* across many calls in one run; (2) `readline.Interface.question()`
|
|
21
|
+
* attaches a one-shot listener only at the moment it's called — if piped
|
|
22
|
+
* input delivers several lines in one burst *before* the next `question()`
|
|
23
|
+
* call attaches its listener (entirely possible with piped/scripted
|
|
24
|
+
* input, since there's no natural typing delay between answers), the
|
|
25
|
+
* extra buffered lines are silently dropped with no error. The async
|
|
26
|
+
* iterator protocol (`for await` / `Symbol.asyncIterator`) queues
|
|
27
|
+
* unclaimed lines instead of discarding them, so calling `.next()`
|
|
28
|
+
* repeatedly — from either consumer — is safe regardless of how the
|
|
29
|
+
* input arrives.
|
|
30
|
+
*/
|
|
31
|
+
export function createInteractiveIO(input = process.stdin, output = process.stderr) {
|
|
32
|
+
const rl = createInterface({ input, output });
|
|
33
|
+
const lines = rl[Symbol.asyncIterator]();
|
|
34
|
+
const nextLine = async () => {
|
|
35
|
+
const { value: rawLine, done } = await lines.next();
|
|
36
|
+
return stripBOM(done ? "" : rawLine).trim();
|
|
37
|
+
};
|
|
38
|
+
const prompt = async (toolName, argsJson, dangerous) => {
|
|
39
|
+
const label = dangerous ? "DANGEROUS - confirm" : "confirm";
|
|
40
|
+
output.write(`[${label}] run ${toolName} ${argsJson} ? [y]es / [n]o / [a]lways this run: `);
|
|
41
|
+
const answer = (await nextLine()).toLowerCase();
|
|
42
|
+
switch (answer) {
|
|
43
|
+
case "y":
|
|
44
|
+
case "yes":
|
|
45
|
+
return { approve: true, remember: false };
|
|
46
|
+
case "a":
|
|
47
|
+
case "always":
|
|
48
|
+
return { approve: true, remember: true };
|
|
49
|
+
default:
|
|
50
|
+
return { approve: false, remember: false };
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const ask = async (question, options) => {
|
|
54
|
+
const suffix = options && options.length > 0 ? ` (${options.join(" / ")})` : "";
|
|
55
|
+
output.write(`[question] ${question}${suffix}: `);
|
|
56
|
+
return nextLine();
|
|
57
|
+
};
|
|
58
|
+
return { prompt, ask, close: () => rl.close() };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,wBAAwB,CAAA;AAGxE;;;4BAG4B;AAC5B,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;AAC5B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA+B,OAAO,CAAC,KAAK,EAC5C,SAAgC,OAAO,CAAC,MAAM;IAE9C,MAAM,EAAE,GAAc,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IACxD,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;IAExC,MAAM,QAAQ,GAAG,KAAK,IAAqB,EAAE;QAC3C,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;QACnD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;IAC7C,CAAC,CAAA;IAED,MAAM,MAAM,GAAa,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE;QAC/D,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAA;QAC3D,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,QAAQ,IAAI,QAAQ,uCAAuC,CAAC,CAAA;QAE3F,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;QAC/C,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,GAAG,CAAC;YACT,KAAK,KAAK;gBACR,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;YAC3C,KAAK,GAAG,CAAC;YACT,KAAK,QAAQ;gBACX,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;YAC1C;gBACE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;QAC9C,CAAC;IACH,CAAC,CAAA;IAED,MAAM,GAAG,GAAU,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/E,MAAM,CAAC,KAAK,CAAC,cAAc,QAAQ,GAAG,MAAM,IAAI,CAAC,CAAA;QACjD,OAAO,QAAQ,EAAE,CAAA;IACnB,CAAC,CAAA;IAED,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAA;AACjD,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single source of truth for every named provider choice — used by
|
|
3
|
+
* both the first-run onboarding wizard (`onboarding.ts`) and the TUI's
|
|
4
|
+
* in-session `/provider` picker, so the two can never drift apart.
|
|
5
|
+
*
|
|
6
|
+
* `id` is the preset's own identity (and its keychain slot — Groq and
|
|
7
|
+
* OpenAI both use the `openai` *adapter* but must not share one stored
|
|
8
|
+
* key, which is exactly what happened when keys were slotted by adapter
|
|
9
|
+
* name). `adapter` is what `buildProviderNamed` actually constructs.
|
|
10
|
+
*/
|
|
11
|
+
export type PresetFlow = "ask-base-url" | "none" | "fixed-base-url" | "workers-ai" | "azure" | "bedrock";
|
|
12
|
+
export interface ProviderPreset {
|
|
13
|
+
id: string;
|
|
14
|
+
adapter: "openai" | "anthropic" | "gemini" | "azure" | "bedrock";
|
|
15
|
+
label: string;
|
|
16
|
+
defaultModel: string;
|
|
17
|
+
flow: PresetFlow;
|
|
18
|
+
fixedBaseUrl?: string;
|
|
19
|
+
askDefaultBaseUrl?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const PROVIDER_PRESETS: ProviderPreset[];
|
|
22
|
+
//# sourceMappingURL=provider-presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-presets.d.ts","sourceRoot":"","sources":["../src/provider-presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,MAAM,GAAG,gBAAgB,GAAG,YAAY,GAAG,OAAO,GAAG,SAAS,CAAA;AAExG,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAA;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,UAAU,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,eAAO,MAAM,gBAAgB,EAAE,cAAc,EA0D5C,CAAA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const PROVIDER_PRESETS = [
|
|
2
|
+
{
|
|
3
|
+
id: "openai",
|
|
4
|
+
adapter: "openai",
|
|
5
|
+
label: "OpenAI",
|
|
6
|
+
defaultModel: "gpt-4o-mini",
|
|
7
|
+
flow: "fixed-base-url",
|
|
8
|
+
fixedBaseUrl: "https://api.openai.com/v1",
|
|
9
|
+
},
|
|
10
|
+
{ id: "anthropic", adapter: "anthropic", label: "Anthropic", defaultModel: "claude-3-5-sonnet-latest", flow: "none" },
|
|
11
|
+
{ id: "gemini", adapter: "gemini", label: "Google Gemini", defaultModel: "gemini-2.0-flash", flow: "none" },
|
|
12
|
+
{
|
|
13
|
+
id: "groq",
|
|
14
|
+
adapter: "openai",
|
|
15
|
+
label: "Groq",
|
|
16
|
+
defaultModel: "llama-3.3-70b-versatile",
|
|
17
|
+
flow: "fixed-base-url",
|
|
18
|
+
fixedBaseUrl: "https://api.groq.com/openai/v1",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "openrouter",
|
|
22
|
+
adapter: "openai",
|
|
23
|
+
label: "OpenRouter",
|
|
24
|
+
defaultModel: "openai/gpt-4o-mini",
|
|
25
|
+
flow: "fixed-base-url",
|
|
26
|
+
fixedBaseUrl: "https://openrouter.ai/api/v1",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "xai",
|
|
30
|
+
adapter: "openai",
|
|
31
|
+
label: "xAI (Grok)",
|
|
32
|
+
defaultModel: "grok-4.3",
|
|
33
|
+
flow: "fixed-base-url",
|
|
34
|
+
fixedBaseUrl: "https://api.x.ai/v1",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "local",
|
|
38
|
+
adapter: "openai",
|
|
39
|
+
label: "Ollama / LM Studio / other local or custom OpenAI-compatible server",
|
|
40
|
+
defaultModel: "llama3.2",
|
|
41
|
+
flow: "ask-base-url",
|
|
42
|
+
askDefaultBaseUrl: "http://localhost:11434/v1",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "workers-ai",
|
|
46
|
+
adapter: "openai",
|
|
47
|
+
label: "Cloudflare Workers AI",
|
|
48
|
+
defaultModel: "@cf/meta/llama-3.1-8b-instruct",
|
|
49
|
+
flow: "workers-ai",
|
|
50
|
+
},
|
|
51
|
+
{ id: "azure", adapter: "azure", label: "Azure OpenAI", defaultModel: "gpt-4o", flow: "azure" },
|
|
52
|
+
{
|
|
53
|
+
id: "bedrock",
|
|
54
|
+
adapter: "bedrock",
|
|
55
|
+
label: "Amazon Bedrock",
|
|
56
|
+
defaultModel: "anthropic.claude-3-5-sonnet-20241022-v2:0",
|
|
57
|
+
flow: "bedrock",
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
//# sourceMappingURL=provider-presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-presets.js","sourceRoot":"","sources":["../src/provider-presets.ts"],"names":[],"mappings":"AAsBA,MAAM,CAAC,MAAM,gBAAgB,GAAqB;IAChD;QACE,EAAE,EAAE,QAAQ;QACZ,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,QAAQ;QACf,YAAY,EAAE,aAAa;QAC3B,IAAI,EAAE,gBAAgB;QACtB,YAAY,EAAE,2BAA2B;KAC1C;IACD,EAAE,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,EAAE;IACrH,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE;IAC3G;QACE,EAAE,EAAE,MAAM;QACV,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,MAAM;QACb,YAAY,EAAE,yBAAyB;QACvC,IAAI,EAAE,gBAAgB;QACtB,YAAY,EAAE,gCAAgC;KAC/C;IACD;QACE,EAAE,EAAE,YAAY;QAChB,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,YAAY;QACnB,YAAY,EAAE,oBAAoB;QAClC,IAAI,EAAE,gBAAgB;QACtB,YAAY,EAAE,8BAA8B;KAC7C;IACD;QACE,EAAE,EAAE,KAAK;QACT,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,YAAY;QACnB,YAAY,EAAE,UAAU;QACxB,IAAI,EAAE,gBAAgB;QACtB,YAAY,EAAE,qBAAqB;KACpC;IACD;QACE,EAAE,EAAE,OAAO;QACX,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,qEAAqE;QAC5E,YAAY,EAAE,UAAU;QACxB,IAAI,EAAE,cAAc;QACpB,iBAAiB,EAAE,2BAA2B;KAC/C;IACD;QACE,EAAE,EAAE,YAAY;QAChB,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,uBAAuB;QAC9B,YAAY,EAAE,gCAAgC;QAC9C,IAAI,EAAE,YAAY;KACnB;IACD,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;IAC/F;QACE,EAAE,EAAE,SAAS;QACb,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,gBAAgB;QACvB,YAAY,EAAE,2CAA2C;QACzD,IAAI,EAAE,SAAS;KAChB;CACF,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ModelProvider } from "@breviqcode/shared";
|
|
2
|
+
export interface ProviderConfig {
|
|
3
|
+
provider: string;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
maxContext: number;
|
|
7
|
+
azureResourceName?: string;
|
|
8
|
+
azureDeploymentName?: string;
|
|
9
|
+
azureApiVersion?: string;
|
|
10
|
+
awsRegion?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Constructs the configured ModelProvider. `provider` selects the adapter:
|
|
14
|
+
* "openai" (default — any OpenAI-compatible endpoint, which also covers
|
|
15
|
+
* OpenRouter/xAI/Cloudflare Workers AI/Ollama/LM Studio/vLLM/llama.cpp —
|
|
16
|
+
* they're all just a base URL + key away, no separate adapter code needed),
|
|
17
|
+
* "anthropic", "gemini", "azure" (Azure OpenAI — different URL shape and
|
|
18
|
+
* auth header, same wire format otherwise), or "bedrock" (Amazon Bedrock —
|
|
19
|
+
* genuinely different transport, AWS SigV4-signed via the official SDK).
|
|
20
|
+
*
|
|
21
|
+
* Takes one config object rather than a positional parameter list because
|
|
22
|
+
* azure/bedrock each need a few provider-specific extra fields beyond the
|
|
23
|
+
* common baseUrl/apiKey/maxContext shape.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildProviderNamed(config: ProviderConfig): ModelProvider;
|
|
26
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,aAAa,CA+CxE"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AnthropicProvider, BedrockProvider, createAzureOpenAIProvider, GeminiProvider, OpenAICompatibleProvider, } from "@breviqcode/core";
|
|
2
|
+
/**
|
|
3
|
+
* Constructs the configured ModelProvider. `provider` selects the adapter:
|
|
4
|
+
* "openai" (default — any OpenAI-compatible endpoint, which also covers
|
|
5
|
+
* OpenRouter/xAI/Cloudflare Workers AI/Ollama/LM Studio/vLLM/llama.cpp —
|
|
6
|
+
* they're all just a base URL + key away, no separate adapter code needed),
|
|
7
|
+
* "anthropic", "gemini", "azure" (Azure OpenAI — different URL shape and
|
|
8
|
+
* auth header, same wire format otherwise), or "bedrock" (Amazon Bedrock —
|
|
9
|
+
* genuinely different transport, AWS SigV4-signed via the official SDK).
|
|
10
|
+
*
|
|
11
|
+
* Takes one config object rather than a positional parameter list because
|
|
12
|
+
* azure/bedrock each need a few provider-specific extra fields beyond the
|
|
13
|
+
* common baseUrl/apiKey/maxContext shape.
|
|
14
|
+
*/
|
|
15
|
+
export function buildProviderNamed(config) {
|
|
16
|
+
switch (config.provider) {
|
|
17
|
+
case "":
|
|
18
|
+
case "openai":
|
|
19
|
+
return new OpenAICompatibleProvider(config.baseUrl, config.apiKey, config.maxContext);
|
|
20
|
+
case "anthropic": {
|
|
21
|
+
const maxTokens = Number(process.env.BREVIQ_MAX_TOKENS) || 4096;
|
|
22
|
+
return new AnthropicProvider(config.baseUrl, config.apiKey, maxTokens, config.maxContext);
|
|
23
|
+
}
|
|
24
|
+
case "gemini":
|
|
25
|
+
return new GeminiProvider(config.baseUrl, config.apiKey, config.maxContext);
|
|
26
|
+
case "azure":
|
|
27
|
+
if (!config.azureResourceName || !config.azureDeploymentName || !config.azureApiVersion) {
|
|
28
|
+
throw new Error("azure provider requires azureResourceName, azureDeploymentName, and azureApiVersion");
|
|
29
|
+
}
|
|
30
|
+
return createAzureOpenAIProvider({
|
|
31
|
+
resourceName: config.azureResourceName,
|
|
32
|
+
deploymentName: config.azureDeploymentName,
|
|
33
|
+
apiVersion: config.azureApiVersion,
|
|
34
|
+
apiKey: config.apiKey,
|
|
35
|
+
maxContext: config.maxContext,
|
|
36
|
+
});
|
|
37
|
+
case "bedrock": {
|
|
38
|
+
// apiKey holds a JSON-encoded {accessKeyId, secretAccessKey, sessionToken?}
|
|
39
|
+
// blob — Bedrock needs a credential pair (plus optional session
|
|
40
|
+
// token), not a single key, but SecretStore's per-provider slot only
|
|
41
|
+
// stores one string, so it's structured the same way every other
|
|
42
|
+
// provider's single secret is stored.
|
|
43
|
+
let creds;
|
|
44
|
+
try {
|
|
45
|
+
creds = JSON.parse(config.apiKey);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw new Error("bedrock provider requires AWS credentials (run `breviq config` again)");
|
|
49
|
+
}
|
|
50
|
+
return new BedrockProvider({
|
|
51
|
+
accessKeyId: creds.accessKeyId,
|
|
52
|
+
secretAccessKey: creds.secretAccessKey,
|
|
53
|
+
sessionToken: creds.sessionToken,
|
|
54
|
+
region: config.awsRegion || "us-east-1",
|
|
55
|
+
}, config.maxContext);
|
|
56
|
+
}
|
|
57
|
+
default:
|
|
58
|
+
throw new Error(`unknown provider "${config.provider}" (expected openai, anthropic, gemini, azure, or bedrock)`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,yBAAyB,EACzB,cAAc,EACd,wBAAwB,GACzB,MAAM,kBAAkB,CAAA;AAczB;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAsB;IACvD,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,EAAE,CAAC;QACR,KAAK,QAAQ;YACX,OAAO,IAAI,wBAAwB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;QACvF,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI,CAAA;YAC/D,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;QAC3F,CAAC;QACD,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;QAC7E,KAAK,OAAO;YACV,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;gBACxF,MAAM,IAAI,KAAK,CAAC,qFAAqF,CAAC,CAAA;YACxG,CAAC;YACD,OAAO,yBAAyB,CAAC;gBAC/B,YAAY,EAAE,MAAM,CAAC,iBAAiB;gBACtC,cAAc,EAAE,MAAM,CAAC,mBAAmB;gBAC1C,UAAU,EAAE,MAAM,CAAC,eAAe;gBAClC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,UAAU,EAAE,MAAM,CAAC,UAAU;aAC9B,CAAC,CAAA;QACJ,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,4EAA4E;YAC5E,gEAAgE;YAChE,qEAAqE;YACrE,iEAAiE;YACjE,sCAAsC;YACtC,IAAI,KAA8E,CAAA;YAClF,IAAI,CAAC;gBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;YAC1F,CAAC;YACD,OAAO,IAAI,eAAe,CACxB;gBACE,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,eAAe,EAAE,KAAK,CAAC,eAAe;gBACtC,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,MAAM,EAAE,MAAM,CAAC,SAAS,IAAI,WAAW;aACxC,EACD,MAAM,CAAC,UAAU,CAClB,CAAA;QACH,CAAC;QACD;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,QAAQ,2DAA2D,CAAC,CAAA;IACpH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Gate, HookRunner, LspManager, McpManager, Registry, Root, SessionStore, SymbolIndex, TodoStore, type Asker, type Prompter, type ProjectInstructions } from "@breviqcode/core";
|
|
2
|
+
import type { AgentMode, Message, ModelProvider } from "@breviqcode/shared";
|
|
3
|
+
export declare function breviqDataDir(): string;
|
|
4
|
+
export declare function configPath(): string;
|
|
5
|
+
export interface RuntimeOptions {
|
|
6
|
+
prompt: Prompter;
|
|
7
|
+
ask: Asker;
|
|
8
|
+
initialMode: AgentMode;
|
|
9
|
+
/** Reuse the most recently created session and its history instead of
|
|
10
|
+
* starting a fresh one. Ignored when resumeSessionId is set. */
|
|
11
|
+
continueSession: boolean;
|
|
12
|
+
/** Pre-generated id for a fresh session; unused when continuing or resuming. */
|
|
13
|
+
newSessionId: string;
|
|
14
|
+
/** Resume this specific session id instead of the latest/a fresh one
|
|
15
|
+
* (`--resume <id>` / the TUI's `/resume` picker). Throws if no session
|
|
16
|
+
* with this id exists. */
|
|
17
|
+
resumeSessionId?: string;
|
|
18
|
+
/** Forwards a delegated sub-agent's own status lines (see TaskTool),
|
|
19
|
+
* prefixed with its description, so its progress isn't a black box. */
|
|
20
|
+
onSubAgentStatus?: (text: string) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface Runtime {
|
|
23
|
+
/** Current provider — a live getter, since /provider can swap it
|
|
24
|
+
* mid-session; everything (including TaskTool's sub-agents) follows. */
|
|
25
|
+
readonly provider: ModelProvider;
|
|
26
|
+
/** Current model id — a live getter, /model can change it. */
|
|
27
|
+
readonly model: string;
|
|
28
|
+
/** Advertised max context from the originally resolved config; reused
|
|
29
|
+
* when /provider rebuilds a provider instance mid-session. */
|
|
30
|
+
maxContext: number;
|
|
31
|
+
/** Project-root BREVIQ.md/AGENTS.md content, if present — computed once
|
|
32
|
+
* here and reused at every systemMessage() call site rather than
|
|
33
|
+
* re-reading the file each turn. */
|
|
34
|
+
projectInstructions: ProjectInstructions | undefined;
|
|
35
|
+
/** Swaps the active provider + model (the /provider command). */
|
|
36
|
+
setProviderAndModel(provider: ModelProvider, model: string): void;
|
|
37
|
+
/** Changes just the model (the /model command). */
|
|
38
|
+
setModel(model: string): void;
|
|
39
|
+
projectRoot: string;
|
|
40
|
+
root: Root;
|
|
41
|
+
registry: Registry;
|
|
42
|
+
gate: Gate;
|
|
43
|
+
store: SessionStore;
|
|
44
|
+
todoStore: TodoStore;
|
|
45
|
+
symbolIndex: SymbolIndex;
|
|
46
|
+
lspManager: LspManager;
|
|
47
|
+
sessionId: string;
|
|
48
|
+
/** Existing history if continuing a session, otherwise empty. */
|
|
49
|
+
history: Message[];
|
|
50
|
+
/** Connections to every configured .breviqcode/mcp.json server (whether
|
|
51
|
+
* or not each one connected successfully) — for the breviq mcp
|
|
52
|
+
* subcommand and the TUI's /mcp screen. */
|
|
53
|
+
mcpManager: McpManager;
|
|
54
|
+
/** Pre/post-tool-use hooks loaded from .breviqcode/hooks.json, passed
|
|
55
|
+
* into every Loop constructed against this runtime. */
|
|
56
|
+
hooks: HookRunner;
|
|
57
|
+
close(): Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Builds everything one chat turn (or a whole interactive TUI session)
|
|
61
|
+
* needs: resolved provider config, the full tool registry, the permission
|
|
62
|
+
* gate, and the session/todo/symbol-index/LSP stores — factored out of
|
|
63
|
+
* `index.ts`'s one-shot `chat` command so the interactive TUI (which needs
|
|
64
|
+
* the exact same wiring, just kept alive across many turns instead of one)
|
|
65
|
+
* doesn't duplicate it.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildRuntime(opts: RuntimeOptions): Promise<Runtime>;
|
|
68
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,IAAI,EAGJ,UAAU,EACV,UAAU,EAEV,UAAU,EAGV,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,WAAW,EAEX,SAAS,EAQT,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAI3E,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,QAAQ,CAAA;IAChB,GAAG,EAAE,KAAK,CAAA;IACV,WAAW,EAAE,SAAS,CAAA;IACtB;oEACgE;IAChE,eAAe,EAAE,OAAO,CAAA;IACxB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAA;IACpB;;8BAE0B;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;2EACuE;IACvE,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC1C;AAED,MAAM,WAAW,OAAO;IACtB;4EACwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;kEAC8D;IAC9D,UAAU,EAAE,MAAM,CAAA;IAClB;;wCAEoC;IACpC,mBAAmB,EAAE,mBAAmB,GAAG,SAAS,CAAA;IACpD,iEAAiE;IACjE,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACjE,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,IAAI,CAAA;IACV,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,IAAI,CAAA;IACV,KAAK,EAAE,YAAY,CAAA;IACnB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,OAAO,EAAE,OAAO,EAAE,CAAA;IAClB;;+CAE2C;IAC3C,UAAU,EAAE,UAAU,CAAA;IACtB;2DACuD;IACvD,KAAK,EAAE,UAAU,CAAA;IACjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CA+GzE"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { ApplyPatchTool, BashTool, EditTool, ExitPlanModeTool, FindSymbolTool, Gate, GlobTool, GrepTool, HookRunner, LspManager, LspTool, McpManager, QuestionTool, ReadTool, Registry, Root, SessionStore, SymbolIndex, TaskTool, TodoStore, TodoWriteTool, WebFetchTool, WebSearchTool, WriteTool, loadHooksConfig, loadMcpConfig, loadProjectInstructions, } from "@breviqcode/core";
|
|
5
|
+
import { buildProviderNamed } from "./provider.js";
|
|
6
|
+
import { resolveConfig } from "./config-resolver.js";
|
|
7
|
+
export function breviqDataDir() {
|
|
8
|
+
const dir = join(homedir(), ".breviqcode");
|
|
9
|
+
mkdirSync(dir, { recursive: true });
|
|
10
|
+
return dir;
|
|
11
|
+
}
|
|
12
|
+
export function configPath() {
|
|
13
|
+
return join(breviqDataDir(), "config.json");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Builds everything one chat turn (or a whole interactive TUI session)
|
|
17
|
+
* needs: resolved provider config, the full tool registry, the permission
|
|
18
|
+
* gate, and the session/todo/symbol-index/LSP stores — factored out of
|
|
19
|
+
* `index.ts`'s one-shot `chat` command so the interactive TUI (which needs
|
|
20
|
+
* the exact same wiring, just kept alive across many turns instead of one)
|
|
21
|
+
* doesn't duplicate it.
|
|
22
|
+
*/
|
|
23
|
+
export async function buildRuntime(opts) {
|
|
24
|
+
const resolved = await resolveConfig(configPath());
|
|
25
|
+
let currentProvider = buildProviderNamed(resolved);
|
|
26
|
+
let currentModel = resolved.model;
|
|
27
|
+
const dataDir = breviqDataDir();
|
|
28
|
+
const store = new SessionStore(join(dataDir, "session.db"));
|
|
29
|
+
const todoStore = new TodoStore(join(dataDir, "todos.db"));
|
|
30
|
+
const gate = new Gate(opts.prompt, join(dataDir, "permissions.db"), opts.initialMode);
|
|
31
|
+
const projectRoot = process.cwd();
|
|
32
|
+
const projectDataDir = join(projectRoot, ".breviqcode");
|
|
33
|
+
mkdirSync(projectDataDir, { recursive: true });
|
|
34
|
+
const symbolIndex = new SymbolIndex(projectRoot, join(projectDataDir, "index.db"));
|
|
35
|
+
const lspManager = new LspManager(projectRoot);
|
|
36
|
+
const root = new Root(projectRoot);
|
|
37
|
+
const projectInstructions = loadProjectInstructions(projectRoot);
|
|
38
|
+
const hooks = new HookRunner(loadHooksConfig(projectRoot), projectRoot);
|
|
39
|
+
const session = opts.resumeSessionId
|
|
40
|
+
? store.loadSession(opts.resumeSessionId)
|
|
41
|
+
: opts.continueSession
|
|
42
|
+
? store.latestSession()
|
|
43
|
+
: undefined;
|
|
44
|
+
if (opts.resumeSessionId && !session) {
|
|
45
|
+
throw new Error(`no session found with id "${opts.resumeSessionId}"`);
|
|
46
|
+
}
|
|
47
|
+
const sessionId = session?.id ?? opts.newSessionId;
|
|
48
|
+
if (!session)
|
|
49
|
+
store.createSession(sessionId);
|
|
50
|
+
const history = session
|
|
51
|
+
? store.loadMessages(sessionId).map((m) => ({
|
|
52
|
+
role: m.role,
|
|
53
|
+
content: m.content,
|
|
54
|
+
toolCalls: m.toolCalls.length > 0 ? m.toolCalls : undefined,
|
|
55
|
+
toolCallId: m.toolCallId || undefined,
|
|
56
|
+
}))
|
|
57
|
+
: [];
|
|
58
|
+
const registry = new Registry();
|
|
59
|
+
registry.register(new ReadTool(root));
|
|
60
|
+
registry.register(new GrepTool(root));
|
|
61
|
+
registry.register(new GlobTool(root));
|
|
62
|
+
registry.register(new WriteTool(root));
|
|
63
|
+
registry.register(new EditTool(root));
|
|
64
|
+
registry.register(new ApplyPatchTool(root));
|
|
65
|
+
registry.register(new BashTool(root));
|
|
66
|
+
registry.register(new TodoWriteTool(todoStore, sessionId));
|
|
67
|
+
registry.register(new QuestionTool(opts.ask));
|
|
68
|
+
registry.register(new WebFetchTool());
|
|
69
|
+
// Only registered when a key is configured — same graceful-degradation
|
|
70
|
+
// pattern as LSP servers (only if on PATH) and Bedrock (only if AWS
|
|
71
|
+
// creds are present), rather than registering a tool that would just
|
|
72
|
+
// fail on every call.
|
|
73
|
+
if (process.env.BREVIQ_WEBSEARCH_API_KEY) {
|
|
74
|
+
registry.register(new WebSearchTool(process.env.BREVIQ_WEBSEARCH_API_KEY));
|
|
75
|
+
}
|
|
76
|
+
registry.register(new FindSymbolTool(symbolIndex));
|
|
77
|
+
registry.register(new LspTool(root, lspManager));
|
|
78
|
+
registry.register(new ExitPlanModeTool(opts.ask, gate));
|
|
79
|
+
// Connected and registered before TaskTool, which snapshots the registry
|
|
80
|
+
// once at construction — MCP tools registered after it would be
|
|
81
|
+
// invisible to sub-agents.
|
|
82
|
+
const mcpManager = new McpManager();
|
|
83
|
+
const mcpTools = await mcpManager.connectAll(loadMcpConfig(projectRoot));
|
|
84
|
+
for (const tool of mcpTools)
|
|
85
|
+
registry.register(tool);
|
|
86
|
+
// Getter form so sub-agents spawned after a /provider or /model switch
|
|
87
|
+
// use the *current* provider/model, not the ones from startup.
|
|
88
|
+
registry.register(new TaskTool(() => currentProvider, () => currentModel, registry, gate, undefined, opts.onSubAgentStatus));
|
|
89
|
+
return {
|
|
90
|
+
get provider() {
|
|
91
|
+
return currentProvider;
|
|
92
|
+
},
|
|
93
|
+
get model() {
|
|
94
|
+
return currentModel;
|
|
95
|
+
},
|
|
96
|
+
maxContext: resolved.maxContext,
|
|
97
|
+
projectInstructions,
|
|
98
|
+
setProviderAndModel(provider, model) {
|
|
99
|
+
currentProvider = provider;
|
|
100
|
+
currentModel = model;
|
|
101
|
+
},
|
|
102
|
+
setModel(model) {
|
|
103
|
+
currentModel = model;
|
|
104
|
+
},
|
|
105
|
+
projectRoot,
|
|
106
|
+
root,
|
|
107
|
+
registry,
|
|
108
|
+
gate,
|
|
109
|
+
store,
|
|
110
|
+
todoStore,
|
|
111
|
+
symbolIndex,
|
|
112
|
+
lspManager,
|
|
113
|
+
sessionId,
|
|
114
|
+
history,
|
|
115
|
+
mcpManager,
|
|
116
|
+
hooks,
|
|
117
|
+
async close() {
|
|
118
|
+
gate.close();
|
|
119
|
+
store.close();
|
|
120
|
+
todoStore.close();
|
|
121
|
+
symbolIndex.close();
|
|
122
|
+
lspManager.close();
|
|
123
|
+
await mcpManager.closeAll();
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|