@kinqs/brainrouter-cli 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +29 -52
  2. package/agents/architect.json +18 -0
  3. package/agents/explorer.json +18 -0
  4. package/agents/reviewer.json +18 -0
  5. package/agents/verifier.json +18 -0
  6. package/agents/worker.json +18 -0
  7. package/changelog/0.2.0.md +15 -0
  8. package/changelog/0.3.0.md +20 -0
  9. package/changelog/0.3.1.md +22 -0
  10. package/changelog/0.3.2.md +15 -0
  11. package/changelog/0.3.3.md +19 -0
  12. package/changelog/0.3.4.md +20 -0
  13. package/changelog/0.3.5.md +9 -0
  14. package/changelog/0.3.6.md +9 -0
  15. package/changelog/0.3.7.md +20 -0
  16. package/changelog/0.3.8.md +30 -0
  17. package/changelog/README.md +41 -0
  18. package/dist/agent/agent.d.ts +34 -1
  19. package/dist/agent/agent.js +372 -79
  20. package/dist/agent/toolCallRecovery.d.ts +57 -0
  21. package/dist/agent/toolCallRecovery.js +130 -0
  22. package/dist/agent/toolSafety.d.ts +17 -0
  23. package/dist/agent/toolSafety.js +102 -0
  24. package/dist/cli/banner.d.ts +20 -0
  25. package/dist/cli/banner.js +47 -14
  26. package/dist/cli/cliPrompt.d.ts +40 -3
  27. package/dist/cli/cliPrompt.js +117 -25
  28. package/dist/cli/commands/_context.d.ts +3 -1
  29. package/dist/cli/commands/_helpers.d.ts +1 -1
  30. package/dist/cli/commands/config.d.ts +46 -0
  31. package/dist/cli/commands/config.js +1042 -0
  32. package/dist/cli/commands/init.d.ts +20 -0
  33. package/dist/cli/commands/init.js +64 -0
  34. package/dist/cli/commands/login.d.ts +13 -0
  35. package/dist/cli/commands/login.js +179 -0
  36. package/dist/cli/commands/mcp.d.ts +13 -11
  37. package/dist/cli/commands/mcp.js +261 -74
  38. package/dist/cli/commands/mcpInstall.d.ts +20 -0
  39. package/dist/cli/commands/mcpInstall.js +87 -0
  40. package/dist/cli/commands/orchestration.js +51 -0
  41. package/dist/cli/commands/releaseNotes.d.ts +24 -0
  42. package/dist/cli/commands/releaseNotes.js +109 -0
  43. package/dist/cli/commands/schedule.d.ts +18 -0
  44. package/dist/cli/commands/schedule.js +189 -0
  45. package/dist/cli/commands/ui.js +119 -60
  46. package/dist/cli/commands/workflow.d.ts +2 -0
  47. package/dist/cli/commands/workflow.js +54 -8
  48. package/dist/cli/ink/ChatApp.d.ts +206 -0
  49. package/dist/cli/ink/ChatApp.js +493 -0
  50. package/dist/cli/ink/Frame.d.ts +26 -0
  51. package/dist/cli/ink/Frame.js +5 -0
  52. package/dist/cli/ink/Picker.d.ts +71 -0
  53. package/dist/cli/ink/Picker.js +168 -0
  54. package/dist/cli/ink/SlashPalette.d.ts +51 -0
  55. package/dist/cli/ink/SlashPalette.js +136 -0
  56. package/dist/cli/ink/TextField.d.ts +34 -0
  57. package/dist/cli/ink/TextField.js +47 -0
  58. package/dist/cli/ink/WizardApp.d.ts +7 -0
  59. package/dist/cli/ink/WizardApp.js +422 -0
  60. package/dist/cli/ink/ambientChat.d.ts +34 -0
  61. package/dist/cli/ink/ambientChat.js +7 -0
  62. package/dist/cli/ink/consoleCapture.d.ts +11 -0
  63. package/dist/cli/ink/consoleCapture.js +33 -0
  64. package/dist/cli/ink/markdownRender.d.ts +41 -0
  65. package/dist/cli/ink/markdownRender.js +278 -0
  66. package/dist/cli/ink/renderWithResizeClear.d.ts +14 -0
  67. package/dist/cli/ink/renderWithResizeClear.js +33 -0
  68. package/dist/cli/ink/runChat.d.ts +34 -0
  69. package/dist/cli/ink/runChat.js +682 -0
  70. package/dist/cli/ink/runPicker.d.ts +31 -0
  71. package/dist/cli/ink/runPicker.js +139 -0
  72. package/dist/cli/ink/runSlashPalette.d.ts +23 -0
  73. package/dist/cli/ink/runSlashPalette.js +33 -0
  74. package/dist/cli/ink/runWizard.d.ts +22 -0
  75. package/dist/cli/ink/runWizard.js +133 -0
  76. package/dist/cli/ink/stdinHandoff.d.ts +51 -0
  77. package/dist/cli/ink/stdinHandoff.js +78 -0
  78. package/dist/cli/ink/toolFormat.d.ts +75 -0
  79. package/dist/cli/ink/toolFormat.js +206 -0
  80. package/dist/cli/ink/useTerminalSize.d.ts +35 -0
  81. package/dist/cli/ink/useTerminalSize.js +26 -0
  82. package/dist/cli/repl.d.ts +25 -3
  83. package/dist/cli/repl.js +52 -714
  84. package/dist/cli/slashSuggest.d.ts +32 -0
  85. package/dist/cli/slashSuggest.js +146 -0
  86. package/dist/cli/wizard/modelsApi.d.ts +72 -0
  87. package/dist/cli/wizard/modelsApi.js +166 -0
  88. package/dist/cli/wizard/picker.d.ts +202 -0
  89. package/dist/cli/wizard/picker.js +547 -0
  90. package/dist/cli/wizard/providers.d.ts +86 -0
  91. package/dist/cli/wizard/providers.js +190 -0
  92. package/dist/cli/wizard/runner.d.ts +13 -0
  93. package/dist/cli/wizard/runner.js +488 -0
  94. package/dist/cli/wizard/types.d.ts +122 -0
  95. package/dist/cli/wizard/types.js +109 -0
  96. package/dist/config/config.d.ts +13 -1
  97. package/dist/config/config.js +45 -3
  98. package/dist/index.js +157 -206
  99. package/dist/memory/briefing.d.ts +1 -1
  100. package/dist/memory/briefing.js +4 -4
  101. package/dist/memory/consolidation.d.ts +1 -1
  102. package/dist/orchestration/agentRegistry.d.ts +36 -0
  103. package/dist/orchestration/agentRegistry.js +64 -0
  104. package/dist/orchestration/orchestrator.d.ts +7 -0
  105. package/dist/orchestration/orchestrator.js +2 -0
  106. package/dist/orchestration/tools.d.ts +105 -3
  107. package/dist/orchestration/tools.js +167 -8
  108. package/dist/prompt/skillCatalog.d.ts +11 -0
  109. package/dist/prompt/skillCatalog.js +134 -0
  110. package/dist/prompt/skillRunner.d.ts +2 -2
  111. package/dist/prompt/skillRunner.js +2 -31
  112. package/dist/prompt/systemPrompt.js +7 -2
  113. package/dist/runtime/anthropicAdapter.d.ts +100 -0
  114. package/dist/runtime/anthropicAdapter.js +293 -0
  115. package/dist/runtime/cronParser.d.ts +23 -0
  116. package/dist/runtime/cronParser.js +122 -0
  117. package/dist/runtime/mcpClient.js +14 -11
  118. package/dist/runtime/mcpPool.d.ts +170 -0
  119. package/dist/runtime/mcpPool.js +442 -0
  120. package/dist/runtime/mcpUtils.d.ts +17 -1
  121. package/dist/runtime/mcpUtils.js +23 -0
  122. package/dist/runtime/scheduleTicker.d.ts +33 -0
  123. package/dist/runtime/scheduleTicker.js +99 -0
  124. package/dist/runtime/vendorSnippets.d.ts +45 -0
  125. package/dist/runtime/vendorSnippets.js +153 -0
  126. package/dist/state/scheduleStore.d.ts +37 -0
  127. package/dist/state/scheduleStore.js +64 -0
  128. package/package.json +14 -5
  129. package/.env.example +0 -116
@@ -0,0 +1,190 @@
1
+ /**
2
+ * 0.3.7 wizard — curated provider catalogue.
3
+ *
4
+ * One source of truth for "which LLM providers do we present in the
5
+ * onboarding picker?" — keeps the wizard step and the `/config` provider
6
+ * picker in sync. Each entry carries the canonical endpoint, the env-var
7
+ * name the user is most likely to have set (so we can pre-detect), a
8
+ * short hint line for the picker, and a curated model short-list.
9
+ *
10
+ * Lineage:
11
+ * - The "env-var-name as a hint" pattern is borrowed from
12
+ * `openSrc/codex/codex-rs/tui/src/onboarding/auth.rs`
13
+ * (`ApiKeyInputState.prepopulated_from_env`).
14
+ * - The "configured / needs-key / optional-key" row tag is from
15
+ * `openSrc/DeepSeek-TUI/crates/tui/src/tui/provider_picker.rs`.
16
+ *
17
+ * Adding a provider here makes it appear in the wizard AND the
18
+ * `/config` panel — no other registration needed.
19
+ */
20
+ export const PROVIDER_CATALOG = [
21
+ // NOTE: endpoint values are the BASE URL (ending in `/v1` or
22
+ // `/api/v1`), NOT the full `/chat/completions` URL. The agent's
23
+ // callOpenAI() in agent.ts appends `/chat/completions` itself. An
24
+ // older revision of this catalog stored the full URL, which led to
25
+ // a duplicated `/chat/completions/chat/completions` and a 404 on
26
+ // the first chat turn. agent.ts now normalizes either shape, but
27
+ // the catalog stays on the base-URL form going forward.
28
+ {
29
+ id: 'openai',
30
+ label: 'OpenAI',
31
+ hint: 'cloud · gpt-4o / gpt-5 / o-series',
32
+ endpoint: 'https://api.openai.com/v1',
33
+ envKey: 'OPENAI_API_KEY',
34
+ local: false,
35
+ models: ['gpt-4o-mini', 'gpt-4o', 'gpt-5', 'o3-mini', 'gpt-5-mini'],
36
+ defaultModel: 'gpt-4o-mini',
37
+ },
38
+ {
39
+ id: 'deepseek',
40
+ label: 'DeepSeek',
41
+ hint: 'cloud · deepseek-chat / deepseek-reasoner',
42
+ endpoint: 'https://api.deepseek.com/v1',
43
+ envKey: 'DEEPSEEK_API_KEY',
44
+ local: false,
45
+ models: ['deepseek-chat', 'deepseek-reasoner', 'deepseek-v3', 'deepseek-r1'],
46
+ defaultModel: 'deepseek-chat',
47
+ },
48
+ {
49
+ id: 'openrouter',
50
+ label: 'OpenRouter',
51
+ hint: 'cloud gateway · any vendor through one key',
52
+ endpoint: 'https://openrouter.ai/api/v1',
53
+ envKey: 'OPENROUTER_API_KEY',
54
+ local: false,
55
+ models: [
56
+ 'anthropic/claude-sonnet-4',
57
+ 'openai/gpt-4o-mini',
58
+ 'google/gemini-2.5-flash',
59
+ 'deepseek/deepseek-chat',
60
+ 'qwen/qwen3-coder',
61
+ ],
62
+ defaultModel: 'anthropic/claude-sonnet-4',
63
+ },
64
+ {
65
+ // Claude needs an OpenAI-compatible gateway today because the
66
+ // CLI's chat path drives `/v1/chat/completions` and Anthropic's
67
+ // native API uses `/v1/messages` with a different request shape
68
+ // (tool_use blocks inside user messages, `thinking: { budget_tokens }`
69
+ // instead of `reasoning_effort`, etc.). A native `/v1/messages`
70
+ // adapter is tracked for 0.3.8 — see brainrouter-roadmap/0.3.7.md
71
+ // Item 6 "Out of scope". Until then, the OpenRouter gateway path
72
+ // (this entry) is the supported way to talk to Claude.
73
+ id: 'anthropic-via-gateway',
74
+ label: 'Claude (via OpenRouter)',
75
+ hint: 'cloud · claude-* models routed through OpenRouter\'s OpenAI-compat gateway',
76
+ endpoint: 'https://openrouter.ai/api/v1',
77
+ envKey: 'OPENROUTER_API_KEY',
78
+ local: false,
79
+ models: [
80
+ 'anthropic/claude-sonnet-4.5',
81
+ 'anthropic/claude-opus-4.1',
82
+ 'anthropic/claude-sonnet-4',
83
+ 'anthropic/claude-haiku-4.5',
84
+ 'anthropic/claude-haiku-4',
85
+ ],
86
+ defaultModel: 'anthropic/claude-sonnet-4.5',
87
+ },
88
+ {
89
+ id: 'gemini',
90
+ label: 'Gemini (OpenAI-compat)',
91
+ hint: 'cloud · Google\'s OpenAI-compat endpoint',
92
+ endpoint: 'https://generativelanguage.googleapis.com/v1beta/openai',
93
+ envKey: 'GEMINI_API_KEY',
94
+ local: false,
95
+ models: ['gemini-2.5-flash', 'gemini-2.5-pro'],
96
+ defaultModel: 'gemini-2.5-flash',
97
+ },
98
+ {
99
+ id: 'lmstudio',
100
+ label: 'LM Studio (local)',
101
+ hint: 'local · http://localhost:1234 · blank API key OK',
102
+ endpoint: 'http://localhost:1234/v1',
103
+ envKey: 'LMSTUDIO_API_KEY',
104
+ local: true,
105
+ models: ['qwen2.5-coder', 'gpt-oss-20b', 'deepseek-r1-distill-qwen-32b'],
106
+ defaultModel: 'qwen2.5-coder',
107
+ },
108
+ {
109
+ id: 'ollama',
110
+ label: 'Ollama (local)',
111
+ hint: 'local · http://localhost:11434 · blank API key OK',
112
+ endpoint: 'http://localhost:11434/v1',
113
+ envKey: 'OLLAMA_API_KEY',
114
+ local: true,
115
+ models: ['qwen2.5-coder:7b', 'llama3.1:8b', 'deepseek-r1:14b'],
116
+ defaultModel: 'qwen2.5-coder:7b',
117
+ },
118
+ ];
119
+ /**
120
+ * Look up a provider entry by stable id. Returns undefined when the id
121
+ * isn't in the catalog — caller decides whether that's an error
122
+ * (`/config` reject) or a fallback (custom-endpoint flow).
123
+ */
124
+ export function findProvider(id) {
125
+ return PROVIDER_CATALOG.find((p) => p.id === id);
126
+ }
127
+ /**
128
+ * Pre-detect which providers already have a usable key in the shell
129
+ * environment. Used by the wizard's Provider step to pre-select the
130
+ * row most likely to "just work". Returns the FIRST hit so first-time
131
+ * users with multiple keys set don't get a random pick — order in
132
+ * PROVIDER_CATALOG is the precedence.
133
+ */
134
+ export function detectProviderFromEnv(env = process.env) {
135
+ for (const provider of PROVIDER_CATALOG) {
136
+ const value = env[provider.envKey];
137
+ if (value && value.trim().length > 0)
138
+ return provider;
139
+ }
140
+ return undefined;
141
+ }
142
+ const KNOWN_PREFIXES = [
143
+ 'sk-', // OpenAI
144
+ 'sk-or-v1-', // OpenRouter
145
+ 'sk-proj-', // OpenAI scoped
146
+ 'dsk-', // DeepSeek
147
+ 'sk-ant-', // Anthropic
148
+ ];
149
+ export function validateApiKey(raw, provider) {
150
+ const key = raw.trim();
151
+ // Local endpoints (LM Studio, Ollama, custom) accept blank keys —
152
+ // they often want a literal "lm-studio" / "ollama" / "local" string
153
+ // because the server checks for non-empty Bearer presence.
154
+ if (provider.local) {
155
+ return { kind: 'accept' };
156
+ }
157
+ if (key.length === 0) {
158
+ return { kind: 'reject', reason: 'API key is required for cloud providers.' };
159
+ }
160
+ // Suspiciously short for a real provider key — almost always a paste
161
+ // error (the user copied a tag, not the full secret).
162
+ if (key.length < 16) {
163
+ return { kind: 'reject', reason: `Key is ${key.length} characters — that looks like a paste error (real provider keys are 32+ chars).` };
164
+ }
165
+ const hasKnownPrefix = KNOWN_PREFIXES.some((p) => key.startsWith(p));
166
+ if (!hasKnownPrefix) {
167
+ return {
168
+ kind: 'accept',
169
+ warning: `Unfamiliar key prefix (expected one of ${KNOWN_PREFIXES.slice(0, 3).join(', ')}…). Saved as-is — if calls fail, double-check the value from your provider's dashboard.`,
170
+ };
171
+ }
172
+ return { kind: 'accept' };
173
+ }
174
+ /**
175
+ * Last-four masking for API keys. Visible everywhere the key is
176
+ * displayed (Done step summary, `/config` panel, `/where` workspace
177
+ * block). Always keeps a fixed-width tail so two keys with different
178
+ * lengths align in the panel.
179
+ *
180
+ * Borrowed from `openSrc/DeepSeek-TUI/crates/tui/src/tui/onboarding/api_key.rs:77`
181
+ * (`mask_key()`).
182
+ */
183
+ export function maskApiKey(raw) {
184
+ const key = raw.trim();
185
+ if (key.length === 0)
186
+ return '(none)';
187
+ if (key.length <= 4)
188
+ return '·'.repeat(key.length);
189
+ return '·'.repeat(8) + key.slice(-4);
190
+ }
@@ -0,0 +1,13 @@
1
+ import { type Config } from '../../config/config.js';
2
+ import { type WizardState } from './types.js';
3
+ export declare function isOnboarded(): boolean;
4
+ export declare function markOnboarded(): void;
5
+ export interface WizardRunOptions {
6
+ ownsReadline: boolean;
7
+ workspaceRoot: string;
8
+ }
9
+ export interface WizardRunResult {
10
+ state: WizardState;
11
+ config?: Config;
12
+ }
13
+ export declare function runWizard(opts: WizardRunOptions): Promise<WizardRunResult>;