@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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -0
  3. package/dist/config-resolver.d.ts +22 -0
  4. package/dist/config-resolver.d.ts.map +1 -0
  5. package/dist/config-resolver.js +66 -0
  6. package/dist/config-resolver.js.map +1 -0
  7. package/dist/custom-commands.d.ts +21 -0
  8. package/dist/custom-commands.d.ts.map +1 -0
  9. package/dist/custom-commands.js +73 -0
  10. package/dist/custom-commands.js.map +1 -0
  11. package/dist/flags.d.ts +11 -0
  12. package/dist/flags.d.ts.map +1 -0
  13. package/dist/flags.js +16 -0
  14. package/dist/flags.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +159 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/onboarding.d.ts +35 -0
  20. package/dist/onboarding.d.ts.map +1 -0
  21. package/dist/onboarding.js +131 -0
  22. package/dist/onboarding.js.map +1 -0
  23. package/dist/prompt.d.ts +29 -0
  24. package/dist/prompt.d.ts.map +1 -0
  25. package/dist/prompt.js +60 -0
  26. package/dist/prompt.js.map +1 -0
  27. package/dist/provider-presets.d.ts +22 -0
  28. package/dist/provider-presets.d.ts.map +1 -0
  29. package/dist/provider-presets.js +60 -0
  30. package/dist/provider-presets.js.map +1 -0
  31. package/dist/provider.d.ts +26 -0
  32. package/dist/provider.d.ts.map +1 -0
  33. package/dist/provider.js +61 -0
  34. package/dist/provider.js.map +1 -0
  35. package/dist/runtime.d.ts +68 -0
  36. package/dist/runtime.d.ts.map +1 -0
  37. package/dist/runtime.js +127 -0
  38. package/dist/runtime.js.map +1 -0
  39. package/dist/system-prompt.d.ts +17 -0
  40. package/dist/system-prompt.d.ts.map +1 -0
  41. package/dist/system-prompt.js +32 -0
  42. package/dist/system-prompt.js.map +1 -0
  43. package/dist/tui/App.d.ts +44 -0
  44. package/dist/tui/App.d.ts.map +1 -0
  45. package/dist/tui/App.js +894 -0
  46. package/dist/tui/App.js.map +1 -0
  47. package/dist/tui/format-tool-call.d.ts +35 -0
  48. package/dist/tui/format-tool-call.d.ts.map +1 -0
  49. package/dist/tui/format-tool-call.js +129 -0
  50. package/dist/tui/format-tool-call.js.map +1 -0
  51. 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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"}
@@ -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"}
@@ -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"}
@@ -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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"}