@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rajstats
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 ADDED
@@ -0,0 +1,35 @@
1
+ # @breviqcode/cli
2
+
3
+ An agentic coding CLI — read/write/edit files, run shell commands, search and understand code, and connect to MCP servers, all from your terminal, talking directly to the LLM provider of your choice (OpenAI, Anthropic, Gemini, Groq, OpenRouter, xAI, Azure OpenAI, Amazon Bedrock, Cloudflare Workers AI, or a local server like Ollama).
4
+
5
+ Local-only: no hosted backend, no account with us. It runs on your machine and talks straight to your chosen provider using your own API key.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @breviqcode/cli
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```bash
16
+ breviq # interactive TUI — stays open across a whole session
17
+ breviq chat "prompt" # one-shot: send one message, stream the reply, exit
18
+ breviq config # redo the first-run setup wizard
19
+ breviq mcp # list configured MCP servers and their tools
20
+ ```
21
+
22
+ The first run walks you through a short setup wizard: pick a provider, paste in your API key (stored in your OS's own credential manager, never a plain text file), and pick a model. A local server option (Ollama, LM Studio, etc.) needs no key at all.
23
+
24
+ ## Project-level configuration (all optional)
25
+
26
+ - `BREVIQ.md` or `AGENTS.md` at your project root — instructions automatically folded into every conversation.
27
+ - `.breviqcode/mcp.json` — MCP servers to connect to (`{"mcpServers": {"name": {"command": ..., "args": [...]}}}`).
28
+ - `.breviqcode/hooks.json` — pre/post-tool-use and prompt-submit hooks (shell commands or `.mjs` modules).
29
+ - `.breviqcode/commands/*.md` — custom `/`-commands for the interactive TUI.
30
+
31
+ Full documentation: see the project repository.
32
+
33
+ ## License
34
+
35
+ MIT
@@ -0,0 +1,22 @@
1
+ export interface ResolvedConfig {
2
+ provider: string;
3
+ baseUrl: string;
4
+ apiKey: string;
5
+ model: string;
6
+ maxContext: number;
7
+ azureResourceName?: string;
8
+ azureDeploymentName?: string;
9
+ azureApiVersion?: string;
10
+ awsRegion?: string;
11
+ }
12
+ /**
13
+ * Resolves provider config in priority order: real env vars (and `.env`,
14
+ * already loaded into env vars by the time this runs) first, for
15
+ * scripting/CI use — then the saved UserConfig/SecretStore from a prior
16
+ * onboarding run — and only if *neither* exists, runs the interactive
17
+ * onboarding wizard once and uses its result. This is what actually closes
18
+ * the "no first-run setup" gap: previously the only path was hand-editing
19
+ * `.env`, with no interactive alternative at all.
20
+ */
21
+ export declare function resolveConfig(configPath: string, secretsService?: string): Promise<ResolvedConfig>;
22
+ //# sourceMappingURL=config-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-resolver.d.ts","sourceRoot":"","sources":["../src/config-resolver.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,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;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA6DxG"}
@@ -0,0 +1,66 @@
1
+ import { SecretStore, UserConfig } from "@breviqcode/core";
2
+ import { runOnboarding } from "./onboarding.js";
3
+ /**
4
+ * Resolves provider config in priority order: real env vars (and `.env`,
5
+ * already loaded into env vars by the time this runs) first, for
6
+ * scripting/CI use — then the saved UserConfig/SecretStore from a prior
7
+ * onboarding run — and only if *neither* exists, runs the interactive
8
+ * onboarding wizard once and uses its result. This is what actually closes
9
+ * the "no first-run setup" gap: previously the only path was hand-editing
10
+ * `.env`, with no interactive alternative at all.
11
+ */
12
+ export async function resolveConfig(configPath, secretsService) {
13
+ const envProvider = process.env.BREVIQ_PROVIDER;
14
+ const envApiKey = process.env.BREVIQ_API_KEY;
15
+ const maxContext = Number(process.env.BREVIQ_MAX_CONTEXT) || 8192;
16
+ if (envProvider ||
17
+ envApiKey ||
18
+ process.env.BREVIQ_BASE_URL ||
19
+ process.env.BREVIQ_MODEL ||
20
+ process.env.BREVIQ_AWS_ACCESS_KEY_ID) {
21
+ const providerName = envProvider ?? "";
22
+ let baseUrl = process.env.BREVIQ_BASE_URL ?? "";
23
+ if (!baseUrl && (providerName === "" || providerName === "openai")) {
24
+ baseUrl = "http://localhost:11434/v1";
25
+ }
26
+ // Bedrock has no single "api key" — env-var scripting for it needs its
27
+ // own trio of vars, folded into the same JSON-blob shape buildProviderNamed
28
+ // expects (matching how the saved-config/keychain path stores it too).
29
+ let apiKey = envApiKey ?? "";
30
+ if (providerName === "bedrock" && process.env.BREVIQ_AWS_ACCESS_KEY_ID) {
31
+ apiKey = JSON.stringify({
32
+ accessKeyId: process.env.BREVIQ_AWS_ACCESS_KEY_ID,
33
+ secretAccessKey: process.env.BREVIQ_AWS_SECRET_ACCESS_KEY ?? "",
34
+ sessionToken: process.env.BREVIQ_AWS_SESSION_TOKEN || undefined,
35
+ });
36
+ }
37
+ return {
38
+ provider: providerName || "openai",
39
+ baseUrl,
40
+ apiKey,
41
+ model: process.env.BREVIQ_MODEL || "llama-3.3-70b-versatile",
42
+ maxContext,
43
+ azureResourceName: process.env.BREVIQ_AZURE_RESOURCE,
44
+ azureDeploymentName: process.env.BREVIQ_AZURE_DEPLOYMENT,
45
+ azureApiVersion: process.env.BREVIQ_AZURE_API_VERSION,
46
+ awsRegion: process.env.BREVIQ_AWS_REGION,
47
+ };
48
+ }
49
+ const userConfig = new UserConfig(configPath);
50
+ const secrets = new SecretStore(secretsService);
51
+ const saved = userConfig.load() ?? (await runOnboarding(configPath, secretsService));
52
+ return {
53
+ provider: saved.provider,
54
+ baseUrl: saved.baseUrl ?? (saved.provider === "openai" ? "http://localhost:11434/v1" : ""),
55
+ // Preset slot first (how keys are stored now), adapter-name slot as
56
+ // fallback for configs/keys saved before per-preset slots existed.
57
+ apiKey: (saved.preset ? secrets.getApiKey(saved.preset) : undefined) ?? secrets.getApiKey(saved.provider) ?? "",
58
+ model: saved.model,
59
+ maxContext: saved.maxContext ?? maxContext,
60
+ azureResourceName: saved.azureResourceName,
61
+ azureDeploymentName: saved.azureDeploymentName,
62
+ azureApiVersion: saved.azureApiVersion,
63
+ awsRegion: saved.awsRegion,
64
+ };
65
+ }
66
+ //# sourceMappingURL=config-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-resolver.js","sourceRoot":"","sources":["../src/config-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface CustomCommand {
2
+ name: string;
3
+ description: string;
4
+ argsHint?: string;
5
+ template: string;
6
+ }
7
+ /**
8
+ * Loads project-level custom slash-commands from `.breviqcode/commands/*.md`
9
+ * — one command per file, named after its filename (without extension),
10
+ * mirroring Claude Code's own `.claude/commands/*.md` convention under this
11
+ * project's own `.breviqcode/` directory instead. A malformed or
12
+ * incomplete file is skipped individually rather than failing the whole
13
+ * load, since one bad file shouldn't take down every other command.
14
+ */
15
+ export declare function loadCustomCommands(projectRoot: string): CustomCommand[];
16
+ /** Substitutes $ARGUMENTS with whatever the user typed after the command
17
+ * name. If the template has no placeholder, the args are appended on a new
18
+ * line instead, so a command still receives them even if its author forgot
19
+ * to reference $ARGUMENTS explicitly. */
20
+ export declare function expandCommand(cmd: CustomCommand, args: string): string;
21
+ //# sourceMappingURL=custom-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-commands.d.ts","sourceRoot":"","sources":["../src/custom-commands.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAkCD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CAgBvE;AAED;;;yCAGyC;AACzC,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtE"}
@@ -0,0 +1,73 @@
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { basename, join } from "node:path";
3
+ const FRONTMATTER_DELIMITER = "---";
4
+ /** Hand-rolled, minimal — only two plain string fields are needed
5
+ * (`description`, optional `args`), so a full YAML frontmatter parser
6
+ * would be a dependency for no real benefit. Returns undefined for any
7
+ * file that doesn't look like a command (missing/unclosed frontmatter, or
8
+ * no description), so the caller can skip it rather than fail the load. */
9
+ function parseCommandFile(name, raw) {
10
+ const lines = raw.split("\n");
11
+ if (lines[0]?.trim() !== FRONTMATTER_DELIMITER)
12
+ return undefined;
13
+ const closingIndex = lines.findIndex((line, i) => i > 0 && line.trim() === FRONTMATTER_DELIMITER);
14
+ if (closingIndex === -1)
15
+ return undefined;
16
+ const fields = {};
17
+ for (const line of lines.slice(1, closingIndex)) {
18
+ const colonIndex = line.indexOf(":");
19
+ if (colonIndex === -1)
20
+ continue;
21
+ const key = line.slice(0, colonIndex).trim();
22
+ const value = line.slice(colonIndex + 1).trim();
23
+ if (key)
24
+ fields[key] = value;
25
+ }
26
+ const description = fields.description;
27
+ if (!description)
28
+ return undefined;
29
+ const template = lines
30
+ .slice(closingIndex + 1)
31
+ .join("\n")
32
+ .trim();
33
+ return { name, description, argsHint: fields.args, template };
34
+ }
35
+ /**
36
+ * Loads project-level custom slash-commands from `.breviqcode/commands/*.md`
37
+ * — one command per file, named after its filename (without extension),
38
+ * mirroring Claude Code's own `.claude/commands/*.md` convention under this
39
+ * project's own `.breviqcode/` directory instead. A malformed or
40
+ * incomplete file is skipped individually rather than failing the whole
41
+ * load, since one bad file shouldn't take down every other command.
42
+ */
43
+ export function loadCustomCommands(projectRoot) {
44
+ const dir = join(projectRoot, ".breviqcode", "commands");
45
+ if (!existsSync(dir))
46
+ return [];
47
+ const commands = [];
48
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
49
+ if (!entry.isFile() || !entry.name.endsWith(".md"))
50
+ continue;
51
+ try {
52
+ const raw = readFileSync(join(dir, entry.name), "utf8");
53
+ const command = parseCommandFile(basename(entry.name, ".md"), raw);
54
+ if (command)
55
+ commands.push(command);
56
+ }
57
+ catch {
58
+ // unreadable file — skip it, don't fail the whole load
59
+ }
60
+ }
61
+ return commands;
62
+ }
63
+ /** Substitutes $ARGUMENTS with whatever the user typed after the command
64
+ * name. If the template has no placeholder, the args are appended on a new
65
+ * line instead, so a command still receives them even if its author forgot
66
+ * to reference $ARGUMENTS explicitly. */
67
+ export function expandCommand(cmd, args) {
68
+ if (cmd.template.includes("$ARGUMENTS")) {
69
+ return cmd.template.replaceAll("$ARGUMENTS", args);
70
+ }
71
+ return args ? `${cmd.template}\n\n${args}` : cmd.template;
72
+ }
73
+ //# sourceMappingURL=custom-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-commands.js","sourceRoot":"","sources":["../src/custom-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /** Pulls a `--resume <id>` pair out of an argv-style array, since every
2
+ * other flag in this CLI is boolean-only (`--continue`, `--plan`) — the
3
+ * first value-consuming flag this codebase has needed. Throws if
4
+ * `--resume` has no id following it. Shared by the one-shot `chat` command
5
+ * and the TUI's own startup arg parsing (`index.ts`, `tui/App.tsx`) so the
6
+ * two don't drift. */
7
+ export declare function extractResumeId(args: string[]): {
8
+ resumeSessionId?: string;
9
+ rest: string[];
10
+ };
11
+ //# sourceMappingURL=flags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;;;sBAKsB;AACtB,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAM5F"}
package/dist/flags.js ADDED
@@ -0,0 +1,16 @@
1
+ /** Pulls a `--resume <id>` pair out of an argv-style array, since every
2
+ * other flag in this CLI is boolean-only (`--continue`, `--plan`) — the
3
+ * first value-consuming flag this codebase has needed. Throws if
4
+ * `--resume` has no id following it. Shared by the one-shot `chat` command
5
+ * and the TUI's own startup arg parsing (`index.ts`, `tui/App.tsx`) so the
6
+ * two don't drift. */
7
+ export function extractResumeId(args) {
8
+ const idx = args.indexOf("--resume");
9
+ if (idx === -1)
10
+ return { rest: args };
11
+ const id = args[idx + 1];
12
+ if (!id)
13
+ throw new Error("--resume requires a session id (breviq --resume <id>)");
14
+ return { resumeSessionId: id, rest: [...args.slice(0, idx), ...args.slice(idx + 2)] };
15
+ }
16
+ //# sourceMappingURL=flags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flags.js","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;;;sBAKsB;AACtB,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACpC,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACrC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAA;IACxB,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAA;IACjF,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;AACvF,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+ import { randomBytes } from "node:crypto";
3
+ import { Loop } from "@breviqcode/core";
4
+ import { buildRuntime, configPath } from "./runtime.js";
5
+ import { createInteractiveIO } from "./prompt.js";
6
+ import { extractResumeId } from "./flags.js";
7
+ import { runOnboarding } from "./onboarding.js";
8
+ import { systemMessage } from "./system-prompt.js";
9
+ import { runTui } from "./tui/App.js";
10
+ try {
11
+ process.loadEnvFile(".env");
12
+ }
13
+ catch {
14
+ // no .env file present — fine, config comes from real env vars instead
15
+ }
16
+ function usage() {
17
+ console.error(`usage:
18
+ breviq [--continue] [--plan] [--resume <id>] open the interactive TUI
19
+ --resume opens straight into
20
+ a specific past session
21
+ breviq chat [--continue] [--plan] [--resume <id>] "prompt"
22
+ send one message and exit
23
+ --plan starts read-only:
24
+ only exit_plan_mode can
25
+ unlock write/execute tools
26
+ breviq config redo the first-run setup wizard
27
+ breviq mcp [test <name>] list configured MCP servers
28
+ (.breviqcode/mcp.json) and
29
+ their discovered tools`);
30
+ }
31
+ function newSessionId() {
32
+ return randomBytes(8).toString("hex");
33
+ }
34
+ async function runConfig() {
35
+ await runOnboarding(configPath());
36
+ }
37
+ async function runChat(args) {
38
+ const { resumeSessionId, rest } = extractResumeId(args);
39
+ const cont = rest.includes("--continue");
40
+ const plan = rest.includes("--plan");
41
+ const prompt = rest.filter((a) => a !== "--continue" && a !== "--plan").join(" ").trim();
42
+ if (!prompt) {
43
+ usage();
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ const initialMode = plan ? "plan" : "build";
48
+ const io = createInteractiveIO();
49
+ const runtime = await buildRuntime({
50
+ prompt: io.prompt,
51
+ ask: io.ask,
52
+ initialMode,
53
+ continueSession: cont,
54
+ newSessionId: newSessionId(),
55
+ resumeSessionId,
56
+ onSubAgentStatus: (text) => process.stderr.write(`${text}\n`),
57
+ });
58
+ try {
59
+ const preSubmit = await runtime.hooks.runUserPromptSubmit(prompt);
60
+ if (preSubmit.block) {
61
+ console.error(`prompt blocked by hook: ${preSubmit.reason ?? "denied"}`);
62
+ process.exitCode = 1;
63
+ return;
64
+ }
65
+ runtime.store.appendMessage(runtime.sessionId, "user", prompt);
66
+ const messages = [
67
+ systemMessage(runtime.projectRoot, initialMode, runtime.projectInstructions),
68
+ ...runtime.history,
69
+ { role: "user", content: prompt },
70
+ ];
71
+ if (plan)
72
+ process.stderr.write("[mode] plan (read-only until exit_plan_mode is approved)\n");
73
+ const loop = new Loop({
74
+ provider: runtime.provider,
75
+ tools: runtime.registry,
76
+ gate: runtime.gate,
77
+ hooks: runtime.hooks,
78
+ onTextDelta: (text) => process.stdout.write(text),
79
+ onStatusLine: (text) => process.stderr.write(`${text}\n`),
80
+ onMessage: (m) => runtime.store.appendMessage(runtime.sessionId, m.role, m.content, m.toolCalls ?? [], m.toolCallId ?? ""),
81
+ });
82
+ await loop.run(runtime.model, messages);
83
+ process.stdout.write("\n");
84
+ console.log("Session ID:", runtime.sessionId);
85
+ }
86
+ finally {
87
+ io.close();
88
+ await runtime.close();
89
+ }
90
+ }
91
+ /** Connects to every configured MCP server (same as a normal runtime
92
+ * startup) and reports which ones connected and what tools each exposes —
93
+ * `breviq mcp test <name>` narrows the report to one server, though every
94
+ * server is still connected to either way (there's no single-server
95
+ * connect path; filtering just changes what's printed). */
96
+ async function runMcp(args) {
97
+ const testTarget = args[0] === "test" ? args[1] : undefined;
98
+ const runtime = await buildRuntime({
99
+ prompt: async () => ({ approve: true, remember: false }),
100
+ ask: async () => "",
101
+ initialMode: "build",
102
+ continueSession: false,
103
+ newSessionId: newSessionId(),
104
+ });
105
+ try {
106
+ const servers = runtime.mcpManager.listServers();
107
+ const filtered = testTarget ? servers.filter((s) => s.name === testTarget) : servers;
108
+ if (filtered.length === 0) {
109
+ console.log(testTarget
110
+ ? `no configured MCP server named "${testTarget}"`
111
+ : "no MCP servers configured (add .breviqcode/mcp.json to configure some)");
112
+ return;
113
+ }
114
+ for (const s of filtered) {
115
+ if (s.connected) {
116
+ console.log(`${s.name}: connected (${s.toolNames.length} tool${s.toolNames.length === 1 ? "" : "s"})`);
117
+ for (const name of s.toolNames)
118
+ console.log(` - ${name}`);
119
+ }
120
+ else {
121
+ console.log(`${s.name}: failed to connect (${s.error})`);
122
+ }
123
+ }
124
+ }
125
+ finally {
126
+ await runtime.close();
127
+ }
128
+ }
129
+ async function main() {
130
+ const [, , command, ...rest] = process.argv;
131
+ if (command === "chat") {
132
+ await runChat(rest);
133
+ return;
134
+ }
135
+ if (command === "config") {
136
+ await runConfig();
137
+ return;
138
+ }
139
+ if (command === "mcp") {
140
+ await runMcp(rest);
141
+ return;
142
+ }
143
+ if (command === undefined ||
144
+ command === "tui" ||
145
+ command === "--continue" ||
146
+ command === "--plan" ||
147
+ command === "--resume") {
148
+ const args = command === "tui" ? rest : [command, ...rest].filter((a) => a !== undefined);
149
+ await runTui(args);
150
+ return;
151
+ }
152
+ usage();
153
+ process.exitCode = 1;
154
+ }
155
+ main().catch((err) => {
156
+ console.error("error:", err instanceof Error ? err.message : err);
157
+ process.exitCode = 1;
158
+ });
159
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type UserConfigData } from "@breviqcode/core";
2
+ /**
3
+ * Runs once, the first time `breviq` is used (no config file yet — see
4
+ * `resolveConfig`): picks a provider, stores its API key/credentials in the
5
+ * OS keychain via SecretStore (not a plaintext `.env`), and picks a default
6
+ * model. This closes a real gap both the Go version and this rewrite's
7
+ * first milestone had — there was never an interactive setup path, only a
8
+ * hand-edited `.env` file.
9
+ *
10
+ * Reads every answer off ONE shared readline async-iterator (`nextLine`),
11
+ * the same pattern `createInteractiveIO` in prompt.ts uses — NOT
12
+ * sequential `rl.question()` calls. `question()` attaches a one-shot
13
+ * listener only at call time; readline emits a `'line'` event for every
14
+ * buffered line as soon as it's parsed, with or without a listener
15
+ * present, so any lines that arrive before the next `question()` call
16
+ * attaches its listener are fired to nobody and silently lost. That's
17
+ * exactly what happened here the first time this file was written: piped
18
+ * input answered the first question, but subsequent answers were already
19
+ * sitting in the stream before `question()` was called again, so they were
20
+ * dropped and the next `question()` call hung on a `'line'` event that had
21
+ * already come and gone — until stdin's EOF let Node exit with nothing left
22
+ * keeping the event loop alive. The async-iterator protocol queues
23
+ * unclaimed lines instead of discarding them, so it's safe regardless of
24
+ * how fast the input arrives. See onboarding.test.ts for the regression
25
+ * test and CLAUDE.md for the full incident writeup.
26
+ *
27
+ * Also deliberately does NOT mask secret entry (no `***` echo) — masking
28
+ * would require reading raw keypresses outside this shared line queue,
29
+ * reintroducing the same class of bug. The security property that
30
+ * actually matters (secrets are never written to a plaintext file, only
31
+ * the OS credential store) holds regardless of terminal echo during
32
+ * one-time entry.
33
+ */
34
+ export declare function runOnboarding(configPath: string, secretsService?: string, input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream): Promise<UserConfigData>;
35
+ //# sourceMappingURL=onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../src/onboarding.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAY/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,MAAM,EACvB,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,GAC7C,OAAO,CAAC,cAAc,CAAC,CA6FzB"}