byterover-cli 1.4.0 → 1.6.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 (174) hide show
  1. package/README.md +193 -12
  2. package/dist/core/domain/cipher/process/types.d.ts +1 -1
  3. package/dist/core/domain/entities/provider-config.d.ts +92 -0
  4. package/dist/core/domain/entities/provider-config.js +181 -0
  5. package/dist/core/domain/entities/provider-registry.d.ts +55 -0
  6. package/dist/core/domain/entities/provider-registry.js +74 -0
  7. package/dist/core/domain/errors/headless-prompt-error.d.ts +11 -0
  8. package/dist/core/domain/errors/headless-prompt-error.js +18 -0
  9. package/dist/core/interfaces/cipher/i-content-generator.d.ts +30 -0
  10. package/dist/core/interfaces/cipher/i-content-generator.js +12 -1
  11. package/dist/core/interfaces/cipher/message-factory.d.ts +4 -1
  12. package/dist/core/interfaces/cipher/message-factory.js +5 -0
  13. package/dist/core/interfaces/cipher/message-types.d.ts +19 -1
  14. package/dist/core/interfaces/i-cogit-pull-service.d.ts +0 -1
  15. package/dist/core/interfaces/i-memory-retrieval-service.d.ts +0 -1
  16. package/dist/core/interfaces/i-memory-storage-service.d.ts +0 -2
  17. package/dist/core/interfaces/i-provider-config-store.d.ts +88 -0
  18. package/dist/core/interfaces/i-provider-config-store.js +1 -0
  19. package/dist/core/interfaces/i-provider-keychain-store.d.ts +33 -0
  20. package/dist/core/interfaces/i-provider-keychain-store.js +1 -0
  21. package/dist/core/interfaces/i-space-service.d.ts +1 -2
  22. package/dist/core/interfaces/i-team-service.d.ts +1 -2
  23. package/dist/core/interfaces/i-user-service.d.ts +1 -2
  24. package/dist/core/interfaces/usecase/i-curate-use-case.d.ts +2 -0
  25. package/dist/core/interfaces/usecase/i-init-use-case.d.ts +9 -3
  26. package/dist/core/interfaces/usecase/i-login-use-case.d.ts +4 -1
  27. package/dist/core/interfaces/usecase/i-pull-use-case.d.ts +5 -3
  28. package/dist/core/interfaces/usecase/i-push-use-case.d.ts +6 -4
  29. package/dist/core/interfaces/usecase/i-query-use-case.d.ts +2 -0
  30. package/dist/core/interfaces/usecase/i-status-use-case.d.ts +1 -0
  31. package/dist/infra/cipher/agent/service-initializer.d.ts +1 -1
  32. package/dist/infra/cipher/agent/service-initializer.js +0 -1
  33. package/dist/infra/cipher/file-system/file-system-service.js +5 -5
  34. package/dist/infra/cipher/http/internal-llm-http-service.d.ts +40 -1
  35. package/dist/infra/cipher/http/internal-llm-http-service.js +153 -4
  36. package/dist/infra/cipher/llm/formatters/gemini-formatter.js +8 -1
  37. package/dist/infra/cipher/llm/generators/byterover-content-generator.d.ts +2 -3
  38. package/dist/infra/cipher/llm/generators/byterover-content-generator.js +20 -11
  39. package/dist/infra/cipher/llm/generators/openrouter-content-generator.d.ts +1 -0
  40. package/dist/infra/cipher/llm/generators/openrouter-content-generator.js +26 -0
  41. package/dist/infra/cipher/llm/internal-llm-service.d.ts +13 -0
  42. package/dist/infra/cipher/llm/internal-llm-service.js +75 -4
  43. package/dist/infra/cipher/llm/model-capabilities.d.ts +74 -0
  44. package/dist/infra/cipher/llm/model-capabilities.js +157 -0
  45. package/dist/infra/cipher/llm/openrouter-llm-service.d.ts +35 -1
  46. package/dist/infra/cipher/llm/openrouter-llm-service.js +216 -28
  47. package/dist/infra/cipher/llm/stream-processor.d.ts +22 -2
  48. package/dist/infra/cipher/llm/stream-processor.js +78 -4
  49. package/dist/infra/cipher/llm/thought-parser.d.ts +1 -1
  50. package/dist/infra/cipher/llm/thought-parser.js +5 -5
  51. package/dist/infra/cipher/llm/transformers/openrouter-stream-transformer.d.ts +49 -0
  52. package/dist/infra/cipher/llm/transformers/openrouter-stream-transformer.js +272 -0
  53. package/dist/infra/cipher/llm/transformers/reasoning-extractor.d.ts +71 -0
  54. package/dist/infra/cipher/llm/transformers/reasoning-extractor.js +253 -0
  55. package/dist/infra/cipher/process/process-service.js +1 -1
  56. package/dist/infra/cipher/session/chat-session.d.ts +2 -0
  57. package/dist/infra/cipher/session/chat-session.js +13 -2
  58. package/dist/infra/cipher/storage/message-storage-service.js +4 -0
  59. package/dist/infra/cipher/tools/implementations/bash-exec-tool.js +3 -3
  60. package/dist/infra/cipher/tools/implementations/task-tool.js +1 -1
  61. package/dist/infra/cogit/http-cogit-pull-service.js +1 -1
  62. package/dist/infra/cogit/http-cogit-push-service.js +0 -1
  63. package/dist/infra/http/authenticated-http-client.d.ts +1 -3
  64. package/dist/infra/http/authenticated-http-client.js +1 -5
  65. package/dist/infra/http/openrouter-api-client.d.ts +148 -0
  66. package/dist/infra/http/openrouter-api-client.js +161 -0
  67. package/dist/infra/mcp/tools/task-result-waiter.js +9 -1
  68. package/dist/infra/memory/http-memory-retrieval-service.js +1 -1
  69. package/dist/infra/memory/http-memory-storage-service.js +2 -2
  70. package/dist/infra/process/agent-worker.js +178 -70
  71. package/dist/infra/process/inline-agent-executor.d.ts +32 -0
  72. package/dist/infra/process/inline-agent-executor.js +259 -0
  73. package/dist/infra/process/transport-handlers.d.ts +25 -4
  74. package/dist/infra/process/transport-handlers.js +57 -10
  75. package/dist/infra/repl/commands/connectors-command.js +2 -2
  76. package/dist/infra/repl/commands/index.js +5 -0
  77. package/dist/infra/repl/commands/model-command.d.ts +13 -0
  78. package/dist/infra/repl/commands/model-command.js +212 -0
  79. package/dist/infra/repl/commands/provider-command.d.ts +13 -0
  80. package/dist/infra/repl/commands/provider-command.js +181 -0
  81. package/dist/infra/repl/transport-client-helper.js +6 -2
  82. package/dist/infra/space/http-space-service.d.ts +1 -1
  83. package/dist/infra/space/http-space-service.js +2 -2
  84. package/dist/infra/storage/file-provider-config-store.d.ts +83 -0
  85. package/dist/infra/storage/file-provider-config-store.js +157 -0
  86. package/dist/infra/storage/provider-keychain-store.d.ts +37 -0
  87. package/dist/infra/storage/provider-keychain-store.js +75 -0
  88. package/dist/infra/storage/token-store.d.ts +4 -3
  89. package/dist/infra/storage/token-store.js +6 -5
  90. package/dist/infra/team/http-team-service.d.ts +1 -1
  91. package/dist/infra/team/http-team-service.js +2 -2
  92. package/dist/infra/terminal/headless-terminal.d.ts +91 -0
  93. package/dist/infra/terminal/headless-terminal.js +211 -0
  94. package/dist/infra/transport/socket-io-transport-client.d.ts +20 -0
  95. package/dist/infra/transport/socket-io-transport-client.js +88 -1
  96. package/dist/infra/usecase/curate-use-case.d.ts +40 -1
  97. package/dist/infra/usecase/curate-use-case.js +176 -15
  98. package/dist/infra/usecase/init-use-case.d.ts +27 -5
  99. package/dist/infra/usecase/init-use-case.js +200 -34
  100. package/dist/infra/usecase/login-use-case.d.ts +10 -8
  101. package/dist/infra/usecase/login-use-case.js +35 -2
  102. package/dist/infra/usecase/pull-use-case.d.ts +19 -5
  103. package/dist/infra/usecase/pull-use-case.js +71 -13
  104. package/dist/infra/usecase/push-use-case.d.ts +18 -5
  105. package/dist/infra/usecase/push-use-case.js +81 -14
  106. package/dist/infra/usecase/query-use-case.d.ts +21 -0
  107. package/dist/infra/usecase/query-use-case.js +114 -29
  108. package/dist/infra/usecase/space-list-use-case.js +1 -1
  109. package/dist/infra/usecase/space-switch-use-case.js +2 -2
  110. package/dist/infra/usecase/status-use-case.d.ts +36 -0
  111. package/dist/infra/usecase/status-use-case.js +185 -48
  112. package/dist/infra/user/http-user-service.d.ts +1 -1
  113. package/dist/infra/user/http-user-service.js +2 -2
  114. package/dist/oclif/commands/curate.d.ts +6 -1
  115. package/dist/oclif/commands/curate.js +24 -3
  116. package/dist/oclif/commands/init.d.ts +18 -0
  117. package/dist/oclif/commands/init.js +129 -0
  118. package/dist/oclif/commands/login.d.ts +9 -0
  119. package/dist/oclif/commands/login.js +45 -0
  120. package/dist/oclif/commands/pull.d.ts +16 -0
  121. package/dist/oclif/commands/pull.js +78 -0
  122. package/dist/oclif/commands/push.d.ts +17 -0
  123. package/dist/oclif/commands/push.js +87 -0
  124. package/dist/oclif/commands/query.d.ts +6 -1
  125. package/dist/oclif/commands/query.js +29 -4
  126. package/dist/oclif/commands/status.d.ts +5 -1
  127. package/dist/oclif/commands/status.js +17 -5
  128. package/dist/resources/tools/bash_exec.txt +1 -1
  129. package/dist/tui/components/api-key-dialog.d.ts +39 -0
  130. package/dist/tui/components/api-key-dialog.js +94 -0
  131. package/dist/tui/components/execution/execution-changes.d.ts +3 -1
  132. package/dist/tui/components/execution/execution-changes.js +4 -4
  133. package/dist/tui/components/execution/execution-content.d.ts +1 -1
  134. package/dist/tui/components/execution/execution-content.js +4 -12
  135. package/dist/tui/components/execution/execution-input.js +1 -1
  136. package/dist/tui/components/execution/execution-progress.d.ts +10 -13
  137. package/dist/tui/components/execution/execution-progress.js +70 -17
  138. package/dist/tui/components/execution/execution-reasoning.d.ts +16 -0
  139. package/dist/tui/components/execution/execution-reasoning.js +34 -0
  140. package/dist/tui/components/execution/execution-tool.d.ts +23 -0
  141. package/dist/tui/components/execution/execution-tool.js +125 -0
  142. package/dist/tui/components/execution/expanded-log-view.js +3 -3
  143. package/dist/tui/components/execution/log-item.d.ts +2 -0
  144. package/dist/tui/components/execution/log-item.js +6 -4
  145. package/dist/tui/components/index.d.ts +2 -0
  146. package/dist/tui/components/index.js +2 -0
  147. package/dist/tui/components/inline-prompts/inline-select.js +3 -2
  148. package/dist/tui/components/model-dialog.d.ts +63 -0
  149. package/dist/tui/components/model-dialog.js +89 -0
  150. package/dist/tui/components/onboarding/onboarding-flow.js +8 -2
  151. package/dist/tui/components/provider-dialog.d.ts +27 -0
  152. package/dist/tui/components/provider-dialog.js +31 -0
  153. package/dist/tui/components/reasoning-text.d.ts +26 -0
  154. package/dist/tui/components/reasoning-text.js +49 -0
  155. package/dist/tui/components/selectable-list.d.ts +54 -0
  156. package/dist/tui/components/selectable-list.js +180 -0
  157. package/dist/tui/components/streaming-text.d.ts +30 -0
  158. package/dist/tui/components/streaming-text.js +52 -0
  159. package/dist/tui/contexts/tasks-context.d.ts +15 -0
  160. package/dist/tui/contexts/tasks-context.js +224 -40
  161. package/dist/tui/contexts/theme-context.d.ts +1 -0
  162. package/dist/tui/contexts/theme-context.js +3 -2
  163. package/dist/tui/hooks/use-activity-logs.js +7 -1
  164. package/dist/tui/hooks/use-auth-polling.js +1 -1
  165. package/dist/tui/types/messages.d.ts +32 -5
  166. package/dist/tui/utils/index.d.ts +1 -1
  167. package/dist/tui/utils/index.js +1 -1
  168. package/dist/tui/utils/log.d.ts +0 -9
  169. package/dist/tui/utils/log.js +2 -53
  170. package/dist/tui/views/command-view.js +4 -1
  171. package/dist/utils/environment-detector.d.ts +15 -0
  172. package/dist/utils/environment-detector.js +62 -1
  173. package/oclif.manifest.json +287 -5
  174. package/package.json +1 -1
package/README.md CHANGED
@@ -12,8 +12,11 @@ Command-line interface for ByteRover, featuring an interactive REPL with a moder
12
12
  * [Quick Start](#quick-start)
13
13
  * [Interactive REPL](#interactive-repl)
14
14
  * [Keyboard Shortcuts](#keyboard-shortcuts)
15
+ * [CLI Commands](#cli-commands)
16
+ * [Headless Mode](#headless-mode)
15
17
  * [What is Context Tree?](#what-is-context-tree)
16
18
  * [Supported AI Agents](#supported-ai-agents)
19
+ * [LLM Providers](#llm-providers) (BETA)
17
20
  * [Slash Commands Reference](#slash-commands-reference)
18
21
  * [Authentication](#authentication)
19
22
  * [Configuration](#configuration)
@@ -51,7 +54,7 @@ brv --version
51
54
 
52
55
  Visit [**ByteRover Docs**](https://docs.byterover.dev) for more information.
53
56
 
54
- Get started with ByteRover CLI in three simple steps:
57
+ Get started with ByteRover CLI:
55
58
 
56
59
  ### 1. Start the REPL
57
60
 
@@ -91,6 +94,14 @@ ByteRover automatically configures the best connector for your installed agents:
91
94
  - **MCP tools** for most other agents (universal protocol)
92
95
  - Switch connector types anytime via `/connectors`
93
96
 
97
+ ### 5. (Optional) Connect an LLM Provider
98
+
99
+ ```
100
+ /provider
101
+ ```
102
+
103
+ ByteRover works out of the box with its built-in LLM provider. To use your own models, connect to [OpenRouter](https://openrouter.ai/keys) for access to 200+ models. See [LLM Providers](#llm-providers) for details.
104
+
94
105
  You're now ready to use ByteRover! Try `/status` to see your project's current state.
95
106
 
96
107
  ## Interactive REPL
@@ -115,7 +126,7 @@ The terminal UI includes:
115
126
  - **Streaming Output**: Live responses with markdown rendering (headings, lists, blockquotes, code blocks)
116
127
  - **Reasoning Display**: View agent thinking process with streamed reasoning blocks
117
128
  - **File References**: Type `@` in curate mode to browse and attach files
118
- - **PDF Support**: Reference and extract text from PDF files using `@` (up to 100 pages)
129
+ - **PDF Support**: Reference and extract text from PDF files using `@` (100 pages default, 200 max)
119
130
  - **Dynamic Domains**: Automatically creates new knowledge domains as your context tree grows
120
131
  - **Session Persistence**: Sessions auto-resume after restart
121
132
  - **Expandable Views**: Press `Ctrl+O` to expand messages or logs to full-screen with vim-style navigation
@@ -133,17 +144,123 @@ The terminal UI includes:
133
144
  | `/` | Show command suggestions |
134
145
  | `@` | Browse files (in curate mode) |
135
146
 
136
- ### Using Commands
147
+ ## CLI Commands
137
148
 
138
- In the REPL, use slash commands (commands prefixed with `/`) to interact with ByteRover:
149
+ In addition to the interactive REPL, ByteRover CLI provides direct command-line commands for automation and scripting.
150
+
151
+ ### Authentication
152
+
153
+ | Command | Description |
154
+ |---------|-------------|
155
+ | `brv login -k <key>` | Authenticate with an API key |
139
156
 
157
+ **Example:**
158
+ ```bash
159
+ brv login --api-key your-api-key
140
160
  ```
141
- /status # Check your project status
142
- /curate # Add context interactively
143
- /push # Push changes to cloud
161
+
162
+ Get your API key at [app.byterover.dev/settings/keys](https://app.byterover.dev/settings/keys).
163
+
164
+ ### Project Commands
165
+
166
+ | Command | Description |
167
+ |---------|-------------|
168
+ | `brv init` | Initialize a project with ByteRover |
169
+ | `brv status [dir]` | Show CLI status and project information |
170
+
171
+ **Init flags:**
172
+ - `-f, --force`: Force re-initialization without confirmation
173
+ - `--headless`: Run in headless mode (requires `--team` and `--space`)
174
+ - `--team <id|name>`: Team ID or name
175
+ - `--space <id|name>`: Space ID or name
176
+ - `--format <text|json>`: Output format (default: text)
177
+
178
+ **Status flags:**
179
+ - `-f, --format <text|json>`: Output format (default: text)
180
+ - `--headless`: Run in headless mode
181
+
182
+ ### Context Operations
183
+
184
+ | Command | Description |
185
+ |---------|-------------|
186
+ | `brv query <question>` | Query the context tree |
187
+ | `brv curate [context]` | Curate context to the context tree |
188
+
189
+ **Note:** `query` and `curate` require a running `brv` instance in another terminal.
190
+
191
+ **Query flags:**
192
+ - `--headless`: Run in headless mode
193
+ - `--format <text|json>`: Output format (default: text)
194
+
195
+ **Curate flags:**
196
+ - `-f, --files <path>`: Include specific files (max 5, can be repeated)
197
+ - `--headless`: Run in headless mode
198
+ - `--format <text|json>`: Output format (default: text)
199
+
200
+ ### Cloud Sync
201
+
202
+ | Command | Description |
203
+ |---------|-------------|
204
+ | `brv push` | Push context tree to ByteRover cloud |
205
+ | `brv pull` | Pull context tree from ByteRover cloud |
206
+
207
+ **Push flags:**
208
+ - `-b, --branch <name>`: ByteRover branch name (default: main, not Git branch)
209
+ - `-y, --yes`: Skip confirmation prompt
210
+ - `--headless`: Run in headless mode (auto-skips confirmation)
211
+ - `--format <text|json>`: Output format (default: text)
212
+
213
+ **Pull flags:**
214
+ - `-b, --branch <name>`: ByteRover branch name (default: main, not Git branch)
215
+ - `--headless`: Run in headless mode
216
+ - `--format <text|json>`: Output format (default: text)
217
+
218
+ ## Headless Mode
219
+
220
+ ByteRover CLI supports headless mode for automation, CI/CD pipelines, and scripting. Headless mode disables interactive prompts and supports machine-readable JSON output.
221
+
222
+ ### Supported Commands
223
+
224
+ The following commands support `--headless` mode:
225
+ - `brv init` (requires `--team` and `--space`)
226
+ - `brv status`
227
+ - `brv query`
228
+ - `brv curate`
229
+ - `brv push` (auto-skips confirmation)
230
+ - `brv pull`
231
+
232
+ ### Output Formats
233
+
234
+ Use `--format` to control output:
235
+ - `text` (default): Human-readable text output
236
+ - `json`: NDJSON (newline-delimited JSON) for machine parsing
237
+
238
+ ### CI/CD Examples
239
+
240
+ **Initialize a project in CI:**
241
+ ```bash
242
+ brv login --api-key $BRV_API_KEY
243
+ brv init --headless --team "my-team" --space "my-space" --format json
244
+ ```
245
+
246
+ **Push context tree after tests pass:**
247
+ ```bash
248
+ brv push --headless --format json -y
249
+ ```
250
+
251
+ **Query context in a script:**
252
+ ```bash
253
+ brv query "What are the API endpoints?" --headless --format json
144
254
  ```
145
255
 
146
- Commands support tab completion for quick navigation.
256
+ ### JSON Output Structure
257
+
258
+ JSON output uses NDJSON format with message types:
259
+ - `log`: Progress messages
260
+ - `output`: Main output content
261
+ - `error`: Error messages
262
+ - `warning`: Warning messages
263
+ - `result`: Final operation result
147
264
 
148
265
  ## What is Context Tree?
149
266
 
@@ -203,6 +320,48 @@ ByteRover supports four connector types:
203
320
  - All others (16 agents): MCP connector
204
321
  - Rules: Available for all agents as fallback
205
322
 
323
+ ## LLM Providers (BETA)
324
+
325
+ ByteRover uses LLMs internally to power `/curate` and `/query` operations. By default, the built-in ByteRover provider is used with no configuration required. You can optionally connect to OpenRouter to access 200+ models.
326
+
327
+ ### Available Providers
328
+
329
+ | Provider | API Key Required | Models |
330
+ |----------|-----------------|--------|
331
+ | **ByteRover** (default) | No | Built-in internal model |
332
+ | **OpenRouter** | Yes | 200+ models from Anthropic, OpenAI, Google, Meta, and more |
333
+
334
+ ### Connecting a Provider
335
+
336
+ Use `/provider` (aliases: `/providers`, `/connect`) to switch providers:
337
+
338
+ ```
339
+ /provider
340
+ ```
341
+
342
+ This opens an interactive prompt showing all available providers with their connection status.
343
+
344
+ ### Selecting a Model
345
+
346
+ When connected to OpenRouter, use `/model` (alias: `/models`) to browse and select models:
347
+
348
+ ```
349
+ /model
350
+ ```
351
+
352
+ The model browser shows:
353
+ - **Pricing**: Input/output cost per million tokens (e.g., `$3.00/$15.00/M`)
354
+ - **Context window**: Maximum token capacity (e.g., `200K ctx`)
355
+ - **Free models**: Marked with `[Free]`
356
+ - **Favorites and recents**: Starred and recently used models appear first
357
+
358
+ ### OpenRouter Setup
359
+
360
+ 1. Get an API key at [openrouter.ai/keys](https://openrouter.ai/keys)
361
+ 2. Run `/provider` and select **OpenRouter**
362
+ 3. Paste your API key when prompted (stored securely in system keychain)
363
+ 4. Run `/model` to select a model (default: `anthropic/claude-3.5-sonnet`)
364
+
206
365
  ## Slash Commands Reference
207
366
 
208
367
  ### Core Workflow
@@ -279,6 +438,15 @@ ByteRover supports four connector types:
279
438
  **Reset options:**
280
439
  - `-y, --yes`: Skip confirmation prompt
281
440
 
441
+ ### LLM Providers (BETA)
442
+
443
+ | Command | Description |
444
+ |---------|-------------|
445
+ | `/provider` | Connect to and switch between LLM providers |
446
+ | `/model` | Select a model from the active provider (OpenRouter) |
447
+
448
+ **Aliases:** `/providers` and `/connect` for `/provider`; `/models` for `/model`
449
+
282
450
  ### Session Management
283
451
 
284
452
  | Command | Description |
@@ -288,7 +456,7 @@ ByteRover supports four connector types:
288
456
  **Options:**
289
457
  - `-y, --yes`: Skip confirmation prompt
290
458
 
291
- **Note:** Sessions are stateful and auto-resume after restart. Use `/new` to start fresh—this clears conversation history but does NOT affect the context tree.
459
+ **Note:** Sessions are stateful and auto-resume after restart (retained for 30 days). Use `/new` to start fresh—this clears conversation history but does NOT affect the context tree.
292
460
 
293
461
  ### Project Setup
294
462
 
@@ -308,16 +476,29 @@ ByteRover supports four connector types:
308
476
 
309
477
  ## Authentication
310
478
 
311
- ByteRover CLI uses **OAuth 2.0 with PKCE** (Proof Key for Code Exchange) for secure authentication.
479
+ ByteRover CLI supports two authentication methods to suit different workflows.
480
+
481
+ ### Authentication Methods
482
+
483
+ **1. OAuth 2.0 (Interactive)**
484
+ - Use `/login` in the REPL
485
+ - Opens browser for secure OAuth flow with PKCE
486
+ - Best for: Local development, interactive use
487
+
488
+ **2. API Key (Non-interactive)**
489
+ - Use `brv login --api-key <key>`
490
+ - No browser required
491
+ - Best for: CI/CD, automation, headless environments
492
+ - Get your key at [app.byterover.dev/settings/keys](https://app.byterover.dev/settings/keys)
312
493
 
313
- ### How it works
494
+ ### How OAuth Works
314
495
 
315
496
  1. Run `/login` in the REPL to start authentication
316
497
  2. Your browser opens to the ByteRover authorization page
317
498
  3. After successful login, tokens are securely stored in your system keychain
318
499
  4. All subsequent commands automatically use your stored credentials
319
500
 
320
- ### Security features
501
+ ### Security Features
321
502
 
322
503
  - **PKCE flow**: Prevents authorization code interception attacks
323
504
  - **System keychain**: Tokens stored in macOS Keychain, Windows Credential Manager, or Linux Secret Service
@@ -82,7 +82,7 @@ export interface ExecuteOptions {
82
82
  /**
83
83
  * Timeout in milliseconds (max: ProcessConfig.maxTimeout).
84
84
  *
85
- * @default 120000 (2 minutes)
85
+ * @default 300000 (5 minutes)
86
86
  */
87
87
  timeout?: number;
88
88
  }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Provider Configuration Entity
3
+ *
4
+ * Stores user's provider preferences and connection state.
5
+ * Non-sensitive data (API keys stored separately in keychain).
6
+ */
7
+ /**
8
+ * Configuration for a single connected provider.
9
+ */
10
+ export interface ConnectedProviderConfig {
11
+ /** Currently active model for this provider */
12
+ readonly activeModel?: string;
13
+ /** When the provider was connected */
14
+ readonly connectedAt: string;
15
+ /** User's favorite models (for quick access) */
16
+ readonly favoriteModels: readonly string[];
17
+ /** Recently used models (last 10) */
18
+ readonly recentModels: readonly string[];
19
+ }
20
+ /**
21
+ * Parameters for creating a ProviderConfig.
22
+ */
23
+ export interface ProviderConfigParams {
24
+ /** Currently active provider ID */
25
+ readonly activeProvider: string;
26
+ /** Configuration for each connected provider */
27
+ readonly providers: Readonly<Record<string, ConnectedProviderConfig>>;
28
+ }
29
+ /**
30
+ * Default configuration when no providers are connected.
31
+ */
32
+ export declare const DEFAULT_PROVIDER_CONFIG: ProviderConfigParams;
33
+ /**
34
+ * Represents the provider configuration for the CLI.
35
+ * Tracks which providers are connected and user preferences.
36
+ */
37
+ export declare class ProviderConfig {
38
+ readonly activeProvider: string;
39
+ readonly providers: Readonly<Record<string, ConnectedProviderConfig>>;
40
+ private constructor();
41
+ /**
42
+ * Creates a new ProviderConfig with default values.
43
+ */
44
+ static createDefault(): ProviderConfig;
45
+ /**
46
+ * Deserializes config from JSON format.
47
+ * Returns default config for invalid JSON structure.
48
+ */
49
+ static fromJson(json: unknown): ProviderConfig;
50
+ /**
51
+ * Get the active model for a provider.
52
+ */
53
+ getActiveModel(providerId: string): string | undefined;
54
+ /**
55
+ * Get favorite models for a provider.
56
+ */
57
+ getFavoriteModels(providerId: string): readonly string[];
58
+ /**
59
+ * Get recent models for a provider.
60
+ */
61
+ getRecentModels(providerId: string): readonly string[];
62
+ /**
63
+ * Check if a provider is connected.
64
+ */
65
+ isProviderConnected(providerId: string): boolean;
66
+ /**
67
+ * Serializes the config to JSON format.
68
+ */
69
+ toJson(): ProviderConfigParams;
70
+ /**
71
+ * Create a new config with the active model changed for a provider.
72
+ */
73
+ withActiveModel(providerId: string, modelId: string): ProviderConfig;
74
+ /**
75
+ * Create a new config with the active provider changed.
76
+ */
77
+ withActiveProvider(providerId: string): ProviderConfig;
78
+ /**
79
+ * Create a new config with a model toggled as favorite.
80
+ */
81
+ withFavoriteToggled(providerId: string, modelId: string): ProviderConfig;
82
+ /**
83
+ * Create a new config with a provider connected.
84
+ */
85
+ withProviderConnected(providerId: string, options?: {
86
+ activeModel?: string;
87
+ }): ProviderConfig;
88
+ /**
89
+ * Create a new config with a provider disconnected.
90
+ */
91
+ withProviderDisconnected(providerId: string): ProviderConfig;
92
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Provider Configuration Entity
3
+ *
4
+ * Stores user's provider preferences and connection state.
5
+ * Non-sensitive data (API keys stored separately in keychain).
6
+ */
7
+ /**
8
+ * Type guard for ProviderConfig JSON validation.
9
+ */
10
+ const isProviderConfigJson = (json) => {
11
+ if (typeof json !== 'object' || json === null)
12
+ return false;
13
+ const obj = json;
14
+ if (typeof obj.activeProvider !== 'string')
15
+ return false;
16
+ if (typeof obj.providers !== 'object' || obj.providers === null)
17
+ return false;
18
+ return true;
19
+ };
20
+ /**
21
+ * Default configuration when no providers are connected.
22
+ */
23
+ export const DEFAULT_PROVIDER_CONFIG = {
24
+ activeProvider: 'byterover',
25
+ providers: {},
26
+ };
27
+ /**
28
+ * Maximum number of recent models to track.
29
+ */
30
+ const MAX_RECENT_MODELS = 10;
31
+ /**
32
+ * Represents the provider configuration for the CLI.
33
+ * Tracks which providers are connected and user preferences.
34
+ */
35
+ export class ProviderConfig {
36
+ activeProvider;
37
+ providers;
38
+ constructor(params) {
39
+ this.activeProvider = params.activeProvider;
40
+ this.providers = params.providers;
41
+ }
42
+ /**
43
+ * Creates a new ProviderConfig with default values.
44
+ */
45
+ static createDefault() {
46
+ return new ProviderConfig(DEFAULT_PROVIDER_CONFIG);
47
+ }
48
+ /**
49
+ * Deserializes config from JSON format.
50
+ * Returns default config for invalid JSON structure.
51
+ */
52
+ static fromJson(json) {
53
+ if (!isProviderConfigJson(json)) {
54
+ return ProviderConfig.createDefault();
55
+ }
56
+ return new ProviderConfig(json);
57
+ }
58
+ /**
59
+ * Get the active model for a provider.
60
+ */
61
+ getActiveModel(providerId) {
62
+ return this.providers[providerId]?.activeModel;
63
+ }
64
+ /**
65
+ * Get favorite models for a provider.
66
+ */
67
+ getFavoriteModels(providerId) {
68
+ return this.providers[providerId]?.favoriteModels ?? [];
69
+ }
70
+ /**
71
+ * Get recent models for a provider.
72
+ */
73
+ getRecentModels(providerId) {
74
+ return this.providers[providerId]?.recentModels ?? [];
75
+ }
76
+ /**
77
+ * Check if a provider is connected.
78
+ */
79
+ isProviderConnected(providerId) {
80
+ return providerId in this.providers;
81
+ }
82
+ /**
83
+ * Serializes the config to JSON format.
84
+ */
85
+ toJson() {
86
+ return {
87
+ activeProvider: this.activeProvider,
88
+ providers: this.providers,
89
+ };
90
+ }
91
+ /**
92
+ * Create a new config with the active model changed for a provider.
93
+ */
94
+ withActiveModel(providerId, modelId) {
95
+ const existingConfig = this.providers[providerId];
96
+ if (!existingConfig) {
97
+ return this;
98
+ }
99
+ // Add to recent models (at the front, deduplicated)
100
+ const recentModels = [
101
+ modelId,
102
+ ...existingConfig.recentModels.filter((m) => m !== modelId),
103
+ ].slice(0, MAX_RECENT_MODELS);
104
+ const newProviderConfig = {
105
+ ...existingConfig,
106
+ activeModel: modelId,
107
+ recentModels,
108
+ };
109
+ return new ProviderConfig({
110
+ ...this.toJson(),
111
+ providers: {
112
+ ...this.providers,
113
+ [providerId]: newProviderConfig,
114
+ },
115
+ });
116
+ }
117
+ /**
118
+ * Create a new config with the active provider changed.
119
+ */
120
+ withActiveProvider(providerId) {
121
+ return new ProviderConfig({
122
+ ...this.toJson(),
123
+ activeProvider: providerId,
124
+ });
125
+ }
126
+ /**
127
+ * Create a new config with a model toggled as favorite.
128
+ */
129
+ withFavoriteToggled(providerId, modelId) {
130
+ const existingConfig = this.providers[providerId];
131
+ if (!existingConfig) {
132
+ return this;
133
+ }
134
+ const isFavorite = existingConfig.favoriteModels.includes(modelId);
135
+ const favoriteModels = isFavorite
136
+ ? existingConfig.favoriteModels.filter((m) => m !== modelId)
137
+ : [...existingConfig.favoriteModels, modelId];
138
+ const newProviderConfig = {
139
+ ...existingConfig,
140
+ favoriteModels,
141
+ };
142
+ return new ProviderConfig({
143
+ ...this.toJson(),
144
+ providers: {
145
+ ...this.providers,
146
+ [providerId]: newProviderConfig,
147
+ },
148
+ });
149
+ }
150
+ /**
151
+ * Create a new config with a provider connected.
152
+ */
153
+ withProviderConnected(providerId, options) {
154
+ const existingConfig = this.providers[providerId];
155
+ const newProviderConfig = {
156
+ activeModel: options?.activeModel ?? existingConfig?.activeModel,
157
+ connectedAt: existingConfig?.connectedAt ?? new Date().toISOString(),
158
+ favoriteModels: existingConfig?.favoriteModels ?? [],
159
+ recentModels: existingConfig?.recentModels ?? [],
160
+ };
161
+ return new ProviderConfig({
162
+ ...this.toJson(),
163
+ providers: {
164
+ ...this.providers,
165
+ [providerId]: newProviderConfig,
166
+ },
167
+ });
168
+ }
169
+ /**
170
+ * Create a new config with a provider disconnected.
171
+ */
172
+ withProviderDisconnected(providerId) {
173
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
174
+ const { [providerId]: _removed, ...remainingProviders } = this.providers;
175
+ const newActiveProvider = this.activeProvider === providerId ? 'byterover' : this.activeProvider;
176
+ return new ProviderConfig({
177
+ activeProvider: newActiveProvider,
178
+ providers: remainingProviders,
179
+ });
180
+ }
181
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Provider Registry
3
+ *
4
+ * Defines available LLM providers that can be connected to byterover-cli.
5
+ * Inspired by OpenCode's provider system.
6
+ */
7
+ /**
8
+ * Definition for an LLM provider.
9
+ */
10
+ export interface ProviderDefinition {
11
+ /** URL where users can get an API key */
12
+ readonly apiKeyUrl?: string;
13
+ /** API base URL (empty for internal providers) */
14
+ readonly baseUrl: string;
15
+ /** Category for grouping in UI */
16
+ readonly category: 'other' | 'popular';
17
+ /** Default model to use when first connected */
18
+ readonly defaultModel?: string;
19
+ /** Short description */
20
+ readonly description: string;
21
+ /** Default headers for API requests */
22
+ readonly headers: Readonly<Record<string, string>>;
23
+ /** Unique provider identifier */
24
+ readonly id: string;
25
+ /** Endpoint to fetch available models */
26
+ readonly modelsEndpoint: string;
27
+ /** Display name */
28
+ readonly name: string;
29
+ /** Priority for display order (lower = higher priority) */
30
+ readonly priority: number;
31
+ }
32
+ /**
33
+ * Registry of all available providers.
34
+ * Order by priority for consistent display.
35
+ */
36
+ export declare const PROVIDER_REGISTRY: Readonly<Record<string, ProviderDefinition>>;
37
+ /**
38
+ * Get all providers sorted by priority.
39
+ */
40
+ export declare function getProvidersSortedByPriority(): ProviderDefinition[];
41
+ /**
42
+ * Get providers grouped by category.
43
+ */
44
+ export declare function getProvidersGroupedByCategory(): {
45
+ other: ProviderDefinition[];
46
+ popular: ProviderDefinition[];
47
+ };
48
+ /**
49
+ * Get a provider by ID.
50
+ */
51
+ export declare function getProviderById(id: string): ProviderDefinition | undefined;
52
+ /**
53
+ * Check if a provider requires an API key.
54
+ */
55
+ export declare function providerRequiresApiKey(id: string): boolean;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Provider Registry
3
+ *
4
+ * Defines available LLM providers that can be connected to byterover-cli.
5
+ * Inspired by OpenCode's provider system.
6
+ */
7
+ /**
8
+ * Registry of all available providers.
9
+ * Order by priority for consistent display.
10
+ */
11
+ export const PROVIDER_REGISTRY = {
12
+ byterover: {
13
+ baseUrl: '',
14
+ category: 'popular',
15
+ description: 'Internal ByteRover LLM',
16
+ headers: {},
17
+ id: 'byterover',
18
+ modelsEndpoint: '',
19
+ name: 'ByteRover',
20
+ priority: 0,
21
+ },
22
+ openrouter: {
23
+ apiKeyUrl: 'https://openrouter.ai/keys',
24
+ baseUrl: 'https://openrouter.ai/api/v1',
25
+ category: 'popular',
26
+ defaultModel: 'anthropic/claude-3.5-sonnet',
27
+ description: 'Access 200+ models',
28
+ headers: {
29
+ 'HTTP-Referer': 'https://byterover.dev',
30
+ 'X-Title': 'byterover-cli',
31
+ },
32
+ id: 'openrouter',
33
+ modelsEndpoint: '/models',
34
+ name: 'OpenRouter',
35
+ priority: 1,
36
+ },
37
+ // Future providers can be added here:
38
+ // anthropic: { ... },
39
+ // openai: { ... },
40
+ // google: { ... },
41
+ // groq: { ... },
42
+ };
43
+ /**
44
+ * Get all providers sorted by priority.
45
+ */
46
+ export function getProvidersSortedByPriority() {
47
+ return Object.values(PROVIDER_REGISTRY).sort((a, b) => a.priority - b.priority);
48
+ }
49
+ /**
50
+ * Get providers grouped by category.
51
+ */
52
+ export function getProvidersGroupedByCategory() {
53
+ const providers = getProvidersSortedByPriority();
54
+ return {
55
+ other: providers.filter((p) => p.category === 'other'),
56
+ popular: providers.filter((p) => p.category === 'popular'),
57
+ };
58
+ }
59
+ /**
60
+ * Get a provider by ID.
61
+ */
62
+ export function getProviderById(id) {
63
+ return PROVIDER_REGISTRY[id];
64
+ }
65
+ /**
66
+ * Check if a provider requires an API key.
67
+ */
68
+ export function providerRequiresApiKey(id) {
69
+ const provider = getProviderById(id);
70
+ if (!provider)
71
+ return false;
72
+ // Internal providers (empty baseUrl) don't need API keys
73
+ return provider.baseUrl.length > 0;
74
+ }