byterover-cli 1.1.0 → 1.2.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 (103) hide show
  1. package/README.md +8 -4
  2. package/dist/commands/mcp.d.ts +13 -0
  3. package/dist/commands/mcp.js +61 -0
  4. package/dist/core/domain/cipher/agent-events/types.d.ts +44 -1
  5. package/dist/core/domain/entities/agent.js +72 -18
  6. package/dist/core/domain/entities/connector-type.d.ts +2 -1
  7. package/dist/core/domain/entities/connector-type.js +2 -1
  8. package/dist/core/interfaces/connectors/connector-types.d.ts +13 -0
  9. package/dist/core/interfaces/i-mcp-config-writer.d.ts +40 -0
  10. package/dist/core/interfaces/i-mcp-config-writer.js +1 -0
  11. package/dist/core/interfaces/i-rule-template-service.d.ts +4 -2
  12. package/dist/core/interfaces/transport/i-transport-client.d.ts +7 -0
  13. package/dist/infra/cipher/agent/cipher-agent.d.ts +8 -0
  14. package/dist/infra/cipher/agent/cipher-agent.js +16 -0
  15. package/dist/infra/cipher/llm/context/context-manager.d.ts +8 -0
  16. package/dist/infra/cipher/llm/context/context-manager.js +16 -0
  17. package/dist/infra/cipher/llm/internal-llm-service.d.ts +4 -0
  18. package/dist/infra/cipher/llm/internal-llm-service.js +38 -10
  19. package/dist/infra/cipher/session/chat-session.d.ts +3 -0
  20. package/dist/infra/cipher/session/chat-session.js +7 -1
  21. package/dist/infra/cipher/tools/implementations/curate-tool.d.ts +1 -8
  22. package/dist/infra/cipher/tools/implementations/curate-tool.js +360 -22
  23. package/dist/infra/connectors/connector-manager.js +2 -0
  24. package/dist/infra/connectors/mcp/index.d.ts +4 -0
  25. package/dist/infra/connectors/mcp/index.js +4 -0
  26. package/dist/infra/connectors/mcp/json-mcp-config-writer.d.ts +26 -0
  27. package/dist/infra/connectors/mcp/json-mcp-config-writer.js +71 -0
  28. package/dist/infra/connectors/mcp/mcp-connector-config.d.ts +229 -0
  29. package/dist/infra/connectors/mcp/mcp-connector-config.js +173 -0
  30. package/dist/infra/connectors/mcp/mcp-connector.d.ts +80 -0
  31. package/dist/infra/connectors/mcp/mcp-connector.js +324 -0
  32. package/dist/infra/connectors/mcp/toml-mcp-config-writer.d.ts +45 -0
  33. package/dist/infra/connectors/mcp/toml-mcp-config-writer.js +134 -0
  34. package/dist/infra/connectors/rules/rules-connector.d.ts +1 -8
  35. package/dist/infra/connectors/rules/rules-connector.js +20 -85
  36. package/dist/infra/connectors/shared/rule-file-manager.d.ts +72 -0
  37. package/dist/infra/connectors/shared/rule-file-manager.js +119 -0
  38. package/dist/infra/connectors/shared/template-service.d.ts +10 -1
  39. package/dist/infra/connectors/shared/template-service.js +53 -16
  40. package/dist/infra/mcp/index.d.ts +2 -0
  41. package/dist/infra/mcp/index.js +2 -0
  42. package/dist/infra/mcp/mcp-server.d.ts +58 -0
  43. package/dist/infra/mcp/mcp-server.js +178 -0
  44. package/dist/infra/mcp/tools/brv-curate-tool.d.ts +23 -0
  45. package/dist/infra/mcp/tools/brv-curate-tool.js +68 -0
  46. package/dist/infra/mcp/tools/brv-query-tool.d.ts +17 -0
  47. package/dist/infra/mcp/tools/brv-query-tool.js +68 -0
  48. package/dist/infra/mcp/tools/index.d.ts +3 -0
  49. package/dist/infra/mcp/tools/index.js +3 -0
  50. package/dist/infra/mcp/tools/task-result-waiter.d.ts +30 -0
  51. package/dist/infra/mcp/tools/task-result-waiter.js +56 -0
  52. package/dist/infra/process/agent-worker.js +37 -0
  53. package/dist/infra/repl/commands/curate-command.js +2 -2
  54. package/dist/infra/transport/socket-io-transport-client.d.ts +7 -0
  55. package/dist/infra/transport/socket-io-transport-client.js +25 -0
  56. package/dist/infra/transport/socket-io-transport-server.js +4 -0
  57. package/dist/infra/usecase/connectors-use-case.d.ts +4 -0
  58. package/dist/infra/usecase/connectors-use-case.js +29 -10
  59. package/dist/infra/usecase/init-use-case.js +2 -3
  60. package/dist/infra/usecase/status-use-case.d.ts +10 -0
  61. package/dist/infra/usecase/status-use-case.js +53 -0
  62. package/dist/resources/prompts/curate.yml +107 -4
  63. package/dist/templates/mcp-base.md +1 -0
  64. package/dist/templates/sections/mcp-workflow.md +13 -0
  65. package/dist/tui/app.js +4 -1
  66. package/dist/tui/components/command-details.js +1 -1
  67. package/dist/tui/components/execution/execution-changes.d.ts +2 -0
  68. package/dist/tui/components/execution/execution-changes.js +5 -1
  69. package/dist/tui/components/execution/execution-content.d.ts +2 -0
  70. package/dist/tui/components/execution/execution-content.js +8 -18
  71. package/dist/tui/components/execution/execution-input.d.ts +2 -0
  72. package/dist/tui/components/execution/execution-input.js +6 -4
  73. package/dist/tui/components/execution/execution-progress.d.ts +2 -0
  74. package/dist/tui/components/execution/execution-progress.js +6 -2
  75. package/dist/tui/components/execution/expanded-log-view.d.ts +20 -0
  76. package/dist/tui/components/execution/expanded-log-view.js +75 -0
  77. package/dist/tui/components/execution/expanded-message-view.d.ts +24 -0
  78. package/dist/tui/components/execution/expanded-message-view.js +68 -0
  79. package/dist/tui/components/execution/index.d.ts +2 -0
  80. package/dist/tui/components/execution/index.js +2 -0
  81. package/dist/tui/components/execution/log-item.d.ts +4 -0
  82. package/dist/tui/components/execution/log-item.js +2 -2
  83. package/dist/tui/components/footer.js +1 -1
  84. package/dist/tui/components/index.d.ts +2 -1
  85. package/dist/tui/components/index.js +2 -1
  86. package/dist/tui/components/init.js +2 -9
  87. package/dist/tui/components/logo.js +4 -3
  88. package/dist/tui/components/markdown.d.ts +13 -0
  89. package/dist/tui/components/markdown.js +88 -0
  90. package/dist/tui/components/message-item.js +1 -1
  91. package/dist/tui/components/onboarding/onboarding-flow.js +1 -1
  92. package/dist/tui/components/suggestions.js +3 -3
  93. package/dist/tui/contexts/mode-context.js +6 -2
  94. package/dist/tui/hooks/index.d.ts +1 -0
  95. package/dist/tui/hooks/index.js +1 -0
  96. package/dist/tui/hooks/use-is-latest-version.d.ts +6 -0
  97. package/dist/tui/hooks/use-is-latest-version.js +22 -0
  98. package/dist/tui/views/command-view.d.ts +1 -1
  99. package/dist/tui/views/command-view.js +83 -98
  100. package/dist/tui/views/logs-view.d.ts +8 -0
  101. package/dist/tui/views/logs-view.js +55 -27
  102. package/oclif.manifest.json +26 -1
  103. package/package.json +9 -1
package/README.md CHANGED
@@ -31,6 +31,7 @@ Command-line interface for ByteRover, featuring an interactive REPL with a moder
31
31
  - Debian/Ubuntu: `sudo apt-get install libsecret-1-dev`
32
32
  - Red Hat-based: `sudo yum install libsecret-devel`
33
33
  - Arch Linux: `sudo pacman -S libsecret`
34
+ - **WSL (Windows Subsystem for Linux)**: Supported with automatic file-based token storage fallback when keychain is unavailable
34
35
 
35
36
  ### Install globally via npm
36
37
 
@@ -99,7 +100,9 @@ The terminal UI includes:
99
100
  - **Command Completion**: Type `/` to see available commands with auto-completion
100
101
  - **Activity Log**: Real-time task status and execution progress
101
102
  - **Streaming Output**: Live responses from AI-powered operations
102
- - **File References**: Type `@` in curate mode to browse and attach files
103
+ - **File References**: Type `@` in curate mode to browse and attach files (supports PDF)
104
+ - **Dynamic Domains**: Automatically creates new knowledge domains as your context tree grows
105
+ - **Session Persistence**: Sessions auto-resume after restart
103
106
 
104
107
  ### Using Commands
105
108
 
@@ -141,9 +144,10 @@ Use `/connectors` to manage integrations with your AI coding agents:
141
144
  /connectors
142
145
  ```
143
146
 
144
- ByteRover supports two connector types:
147
+ ByteRover supports three connector types:
145
148
  - **Hook integration** (Claude Code): Direct injection via IDE settings for seamless integration
146
149
  - **Rules-based** (all agents): Generates agent-specific rule files (e.g., `CLAUDE.md`, `.cursorrules`) that instruct the agent how to read from and contribute to your context tree
150
+ - **MCP integration** (Model Context Protocol): Exposes `brv-query` and `brv-curate` as MCP tools that AI agents can call directly
147
151
 
148
152
  ## Slash Commands Reference
149
153
 
@@ -159,7 +163,7 @@ ByteRover supports two connector types:
159
163
  ```
160
164
  /curate # Interactive mode
161
165
  /curate "Auth uses JWT tokens" # Autonomous mode with text
162
- /curate "API docs" @src/api.ts @README.md # With file references (max 5)
166
+ /curate "API docs" @src/api.ts @README.md # With file references (max 5, supports PDF)
163
167
  ```
164
168
 
165
169
  **Query example:**
@@ -219,7 +223,7 @@ ByteRover supports two connector types:
219
223
  **Options:**
220
224
  - `-y, --yes`: Skip confirmation prompt
221
225
 
222
- **Note:** This command does NOT affect the context treeit only clears the conversation history and starts a new session.
226
+ **Note:** Sessions are stateful and auto-resume after restart. Use `/new` to start freshthis clears conversation history but does NOT affect the context tree.
223
227
 
224
228
  ### Project Setup
225
229
 
@@ -0,0 +1,13 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * MCP command - starts the MCP server for coding agent integration.
4
+ *
5
+ * This command is spawned by coding agents (Claude Code, Cursor, Windsurf)
6
+ * and connects to a running brv instance via Socket.IO.
7
+ */
8
+ export default class Mcp extends Command {
9
+ static description: string;
10
+ static examples: string[];
11
+ static hidden: boolean;
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,61 @@
1
+ import { Command } from '@oclif/core';
2
+ import { NoInstanceRunningError } from '../core/domain/errors/connection-error.js';
3
+ import { ByteRoverMcpServer } from '../infra/mcp/index.js';
4
+ /**
5
+ * MCP command - starts the MCP server for coding agent integration.
6
+ *
7
+ * This command is spawned by coding agents (Claude Code, Cursor, Windsurf)
8
+ * and connects to a running brv instance via Socket.IO.
9
+ */
10
+ export default class Mcp extends Command {
11
+ static description = `Start MCP server for coding agent integration
12
+
13
+ Connects to a running brv instance via Socket.IO.
14
+ Requires: brv running in another terminal.
15
+
16
+ Exposes tools:
17
+ - brv-query: Query the context tree
18
+ - brv-curate: Curate context to the tree`;
19
+ static examples = [
20
+ '# Start MCP server (typically called by coding agents)',
21
+ '<%= config.bin %> <%= command.id %>',
22
+ ];
23
+ static hidden = true; // Called by agents, not users directly
24
+ async run() {
25
+ try {
26
+ const server = new ByteRoverMcpServer({
27
+ version: this.config.version,
28
+ workingDirectory: process.cwd(),
29
+ });
30
+ // Graceful shutdown
31
+ const cleanup = async () => {
32
+ await server.stop();
33
+ // eslint-disable-next-line n/no-process-exit, unicorn/no-process-exit
34
+ process.exit(0);
35
+ };
36
+ process.on('SIGTERM', cleanup);
37
+ process.on('SIGINT', cleanup);
38
+ await server.start();
39
+ // Keep the process alive - MCP server runs on stdio
40
+ // The process will be terminated by SIGTERM/SIGINT or when the parent process closes stdin
41
+ await new Promise((resolve) => {
42
+ process.stdin.on('close', () => {
43
+ resolve();
44
+ });
45
+ process.stdin.on('end', () => {
46
+ resolve();
47
+ });
48
+ });
49
+ await server.stop();
50
+ }
51
+ catch (error) {
52
+ if (error instanceof NoInstanceRunningError) {
53
+ this.logToStderr('Error: No ByteRover instance running.');
54
+ this.logToStderr('Start one with: brv');
55
+ // eslint-disable-next-line n/no-process-exit, unicorn/no-process-exit
56
+ process.exit(1);
57
+ }
58
+ throw error;
59
+ }
60
+ }
61
+ }
@@ -497,11 +497,13 @@ export interface SessionEventMap {
497
497
  * Emitted when a chunk of content is received (streaming).
498
498
  * @property {string} content - Content of the chunk
499
499
  * @property {boolean} [isComplete] - Whether this is the final chunk
500
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
500
501
  * @property {'reasoning' | 'text'} type - Type of chunk (text or reasoning)
501
502
  */
502
503
  'llmservice:chunk': {
503
504
  content: string;
504
505
  isComplete?: boolean;
506
+ taskId?: string;
505
507
  type: 'reasoning' | 'text';
506
508
  };
507
509
  /**
@@ -509,32 +511,38 @@ export interface SessionEventMap {
509
511
  * @property {number} compressedTokens - Token count after compression
510
512
  * @property {number} originalTokens - Token count before compression
511
513
  * @property {'middle_removal' | 'oldest_removal' | 'summary'} strategy - Compression strategy used
514
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
512
515
  */
513
516
  'llmservice:contextCompressed': {
514
517
  compressedTokens: number;
515
518
  originalTokens: number;
516
519
  strategy: 'middle_removal' | 'oldest_removal' | 'summary';
520
+ taskId?: string;
517
521
  };
518
522
  /**
519
523
  * Emitted when context is approaching the token limit.
520
524
  * @property {number} currentTokens - Current token count
521
525
  * @property {number} maxTokens - Maximum allowed tokens
526
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
522
527
  * @property {number} utilizationPercent - Percentage of context used (0-100)
523
528
  */
524
529
  'llmservice:contextOverflow': {
525
530
  currentTokens: number;
526
531
  maxTokens: number;
532
+ taskId?: string;
527
533
  utilizationPercent: number;
528
534
  };
529
535
  /**
530
536
  * Emitted when old tool outputs are pruned to save context space.
531
537
  * @property {number} pruneCount - Number of tool outputs pruned
532
538
  * @property {'manual' | 'overflow'} reason - Why pruning was triggered
539
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
533
540
  * @property {number} tokensSaved - Estimated tokens saved
534
541
  */
535
542
  'llmservice:contextPruned': {
536
543
  pruneCount: number;
537
544
  reason: 'manual' | 'overflow';
545
+ taskId?: string;
538
546
  tokensSaved: number;
539
547
  };
540
548
  /**
@@ -543,32 +551,38 @@ export interface SessionEventMap {
543
551
  * @property {Record<string, unknown>} args - Arguments that were repeated
544
552
  * @property {'exact_repeat' | 'oscillation'} loopType - Type of loop detected
545
553
  * @property {number} repeatCount - Number of times the pattern repeated
554
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
546
555
  * @property {string} toolName - Name of the tool involved in the loop
547
556
  */
548
557
  'llmservice:doomLoopDetected': {
549
558
  args: Record<string, unknown>;
550
559
  loopType: 'exact_repeat' | 'oscillation';
551
560
  repeatCount: number;
561
+ taskId?: string;
552
562
  toolName: string;
553
563
  };
554
564
  /**
555
565
  * Emitted when an error occurs during LLM service operation.
556
566
  * @property {string} [code] - Error code (optional)
557
567
  * @property {string} error - Error message
568
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
558
569
  */
559
570
  'llmservice:error': {
560
571
  code?: string;
561
572
  error: string;
573
+ taskId?: string;
562
574
  };
563
575
  /**
564
576
  * Emitted when tool output is truncated due to size.
565
577
  * @property {number} originalLength - Original output length before truncation
566
578
  * @property {string} savedToFile - Path to file where full output was saved
579
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
567
580
  * @property {string} toolName - Name of the tool that produced the output
568
581
  */
569
582
  'llmservice:outputTruncated': {
570
583
  originalLength: number;
571
584
  savedToFile: string;
585
+ taskId?: string;
572
586
  toolName: string;
573
587
  };
574
588
  /**
@@ -578,6 +592,7 @@ export interface SessionEventMap {
578
592
  * @property {boolean} [partial] - Whether this is a partial response (e.g., max iterations reached)
579
593
  * @property {string} [provider] - LLM provider name
580
594
  * @property {string} [reasoning] - Internal reasoning (if available)
595
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
581
596
  * @property {TokenUsage} [tokenUsage] - Token usage statistics
582
597
  */
583
598
  'llmservice:response': {
@@ -586,30 +601,38 @@ export interface SessionEventMap {
586
601
  partial?: boolean;
587
602
  provider?: string;
588
603
  reasoning?: string;
604
+ taskId?: string;
589
605
  tokenUsage?: TokenUsage;
590
606
  };
591
607
  /**
592
608
  * Emitted when LLM service starts thinking/processing.
609
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
593
610
  */
594
- 'llmservice:thinking': void;
611
+ 'llmservice:thinking': void | {
612
+ taskId?: string;
613
+ };
595
614
  /**
596
615
  * Emitted when LLM generates a thought (Gemini models only).
597
616
  * @property {string} description - Detailed thought description
598
617
  * @property {string} subject - Brief thought subject
618
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
599
619
  */
600
620
  'llmservice:thought': {
601
621
  description: string;
602
622
  subject: string;
623
+ taskId?: string;
603
624
  };
604
625
  /**
605
626
  * Emitted when LLM requests a tool call.
606
627
  * @property {Record<string, unknown>} args - Arguments for the tool
607
628
  * @property {string} [callId] - Unique identifier for this tool call
629
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
608
630
  * @property {string} toolName - Name of the tool to execute
609
631
  */
610
632
  'llmservice:toolCall': {
611
633
  args: Record<string, unknown>;
612
634
  callId?: string;
635
+ taskId?: string;
613
636
  toolName: string;
614
637
  };
615
638
  /**
@@ -617,11 +640,13 @@ export interface SessionEventMap {
617
640
  * Allows tools to push real-time updates (e.g., bash output streaming).
618
641
  * @property {string} callId - Tool call identifier
619
642
  * @property {Record<string, unknown>} metadata - The metadata update
643
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
620
644
  * @property {string} toolName - Name of the tool streaming metadata
621
645
  */
622
646
  'llmservice:toolMetadata': {
623
647
  callId: string;
624
648
  metadata: Record<string, unknown>;
649
+ taskId?: string;
625
650
  toolName: string;
626
651
  };
627
652
  /**
@@ -632,6 +657,7 @@ export interface SessionEventMap {
632
657
  * @property {Record<string, unknown>} [metadata] - Execution metadata (duration, tokens, etc.)
633
658
  * @property {unknown} [result] - Tool execution result
634
659
  * @property {boolean} success - Whether execution succeeded
660
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
635
661
  * @property {string} toolName - Name of the executed tool
636
662
  */
637
663
  'llmservice:toolResult': {
@@ -641,32 +667,39 @@ export interface SessionEventMap {
641
667
  metadata?: Record<string, unknown>;
642
668
  result?: unknown;
643
669
  success: boolean;
670
+ taskId?: string;
644
671
  toolName: string;
645
672
  };
646
673
  /**
647
674
  * Emitted when LLM receives unsupported input.
648
675
  * @property {string} reason - Reason why input is unsupported
676
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
649
677
  */
650
678
  'llmservice:unsupportedInput': {
651
679
  reason: string;
680
+ taskId?: string;
652
681
  };
653
682
  /**
654
683
  * Emitted when LLM service encounters a warning (e.g., max iterations reached).
655
684
  * @property {string} message - Warning message
656
685
  * @property {string} [model] - Model identifier
657
686
  * @property {string} [provider] - LLM provider name
687
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
658
688
  */
659
689
  'llmservice:warning': {
660
690
  message: string;
661
691
  model?: string;
662
692
  provider?: string;
693
+ taskId?: string;
663
694
  };
664
695
  /**
665
696
  * Emitted when queued messages are dequeued for processing.
666
697
  * @property {number} count - Number of messages that were dequeued
698
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
667
699
  */
668
700
  'message:dequeued': {
669
701
  count: number;
702
+ taskId?: string;
670
703
  };
671
704
  /**
672
705
  * Emitted when a message is queued because session is busy.
@@ -675,6 +708,7 @@ export interface SessionEventMap {
675
708
  * @property {string} message.content - Message text content
676
709
  * @property {number} message.queuedAt - Timestamp when queued
677
710
  * @property {number} position - Position in the queue (1-based)
711
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
678
712
  */
679
713
  'message:queued': {
680
714
  message: {
@@ -683,6 +717,7 @@ export interface SessionEventMap {
683
717
  queuedAt: number;
684
718
  };
685
719
  position: number;
720
+ taskId?: string;
686
721
  };
687
722
  /**
688
723
  * Emitted when a session run completes (streaming API lifecycle event).
@@ -690,20 +725,24 @@ export interface SessionEventMap {
690
725
  * @property {Error} [error] - Error if terminated due to error
691
726
  * @property {'cancelled' | 'error' | 'max-iterations' | 'stop' | 'timeout'} finishReason - Why execution terminated
692
727
  * @property {number} stepCount - Number of agentic steps completed
728
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
693
729
  */
694
730
  'run:complete': {
695
731
  durationMs: number;
696
732
  error?: Error;
697
733
  finishReason: 'cancelled' | 'error' | 'max-iterations' | 'stop' | 'timeout';
698
734
  stepCount: number;
735
+ taskId?: string;
699
736
  };
700
737
  /**
701
738
  * Emitted when session status changes.
702
739
  * Tracks the lifecycle state of a session (idle, busy, retry, waiting).
703
740
  * @property {SessionStatusType} status - The new session status
741
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
704
742
  */
705
743
  'session:statusChanged': {
706
744
  status: SessionStatusType;
745
+ taskId?: string;
707
746
  };
708
747
  /**
709
748
  * Emitted when an execution step finishes.
@@ -711,20 +750,24 @@ export interface SessionEventMap {
711
750
  * @property {number} cost - Cost in dollars for this step
712
751
  * @property {'max_tokens' | 'stop' | 'tool_calls'} finishReason - Why step finished
713
752
  * @property {number} stepIndex - Step index (0-based)
753
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
714
754
  * @property {StepTokenUsage} tokens - Token usage for this step
715
755
  */
716
756
  'step:finished': {
717
757
  cost: number;
718
758
  finishReason: 'max_tokens' | 'stop' | 'tool_calls';
719
759
  stepIndex: number;
760
+ taskId?: string;
720
761
  tokens: StepTokenUsage;
721
762
  };
722
763
  /**
723
764
  * Emitted when an execution step starts.
724
765
  * @property {number} stepIndex - Step index (0-based)
766
+ * @property {string} [taskId] - Optional task ID for concurrent task isolation
725
767
  */
726
768
  'step:started': {
727
769
  stepIndex: number;
770
+ taskId?: string;
728
771
  };
729
772
  }
730
773
  /**
@@ -26,22 +26,76 @@ export const AGENT_VALUES = [
26
26
  * Defines which connectors each agent supports and which is the default.
27
27
  */
28
28
  export const AGENT_CONNECTOR_CONFIG = {
29
- Amp: { default: 'rules', supported: ['rules'] },
30
- 'Augment Code': { default: 'rules', supported: ['rules'] },
31
- 'Claude Code': { default: 'hook', supported: ['rules', 'hook'] },
32
- Cline: { default: 'rules', supported: ['rules'] },
33
- Codex: { default: 'rules', supported: ['rules'] },
34
- Cursor: { default: 'rules', supported: ['rules'] },
35
- 'Gemini CLI': { default: 'rules', supported: ['rules'] },
36
- 'Github Copilot': { default: 'rules', supported: ['rules'] },
37
- Junie: { default: 'rules', supported: ['rules'] },
38
- 'Kilo Code': { default: 'rules', supported: ['rules'] },
39
- Kiro: { default: 'rules', supported: ['rules'] },
40
- Qoder: { default: 'rules', supported: ['rules'] },
41
- 'Qwen Code': { default: 'rules', supported: ['rules'] },
42
- 'Roo Code': { default: 'rules', supported: ['rules'] },
43
- 'Trae.ai': { default: 'rules', supported: ['rules'] },
44
- Warp: { default: 'rules', supported: ['rules'] },
45
- Windsurf: { default: 'rules', supported: ['rules'] },
46
- Zed: { default: 'rules', supported: ['rules'] },
29
+ Amp: {
30
+ default: 'mcp',
31
+ supported: ['rules', 'mcp'],
32
+ },
33
+ 'Augment Code': {
34
+ default: 'mcp',
35
+ supported: ['rules', 'mcp'],
36
+ },
37
+ 'Claude Code': {
38
+ default: 'hook',
39
+ supported: ['rules', 'hook', 'mcp'],
40
+ },
41
+ Cline: {
42
+ default: 'mcp',
43
+ supported: ['rules', 'mcp'],
44
+ },
45
+ Codex: {
46
+ default: 'mcp',
47
+ supported: ['rules', 'mcp'],
48
+ },
49
+ Cursor: {
50
+ default: 'mcp',
51
+ supported: ['rules', 'mcp'],
52
+ },
53
+ 'Gemini CLI': {
54
+ default: 'mcp',
55
+ supported: ['rules', 'mcp'],
56
+ },
57
+ 'Github Copilot': {
58
+ default: 'mcp',
59
+ supported: ['rules', 'mcp'],
60
+ },
61
+ Junie: {
62
+ default: 'mcp',
63
+ supported: ['rules', 'mcp'],
64
+ },
65
+ 'Kilo Code': {
66
+ default: 'mcp',
67
+ supported: ['rules', 'mcp'],
68
+ },
69
+ Kiro: {
70
+ default: 'mcp',
71
+ supported: ['rules', 'mcp'],
72
+ },
73
+ Qoder: {
74
+ default: 'mcp',
75
+ supported: ['rules', 'mcp'],
76
+ },
77
+ 'Qwen Code': {
78
+ default: 'mcp',
79
+ supported: ['rules', 'mcp'],
80
+ },
81
+ 'Roo Code': {
82
+ default: 'mcp',
83
+ supported: ['rules', 'mcp'],
84
+ },
85
+ 'Trae.ai': {
86
+ default: 'mcp',
87
+ supported: ['rules', 'mcp'],
88
+ },
89
+ Warp: {
90
+ default: 'mcp',
91
+ supported: ['rules', 'mcp'],
92
+ },
93
+ Windsurf: {
94
+ default: 'mcp',
95
+ supported: ['rules', 'mcp'],
96
+ },
97
+ Zed: {
98
+ default: 'mcp',
99
+ supported: ['rules', 'mcp'],
100
+ },
47
101
  };
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * - 'rules': Agent reads instructions from a rule file (e.g., CLAUDE.md)
6
6
  * - 'hook': Instructions are injected on each prompt via agent hooks
7
+ * - 'mcp': Agent uses mcp tools to interact with brv
7
8
  */
8
- export declare const CONNECTOR_TYPES: readonly ["rules", "hook"];
9
+ export declare const CONNECTOR_TYPES: readonly ["rules", "hook", "mcp"];
9
10
  export type ConnectorType = (typeof CONNECTOR_TYPES)[number];
@@ -4,5 +4,6 @@
4
4
  *
5
5
  * - 'rules': Agent reads instructions from a rule file (e.g., CLAUDE.md)
6
6
  * - 'hook': Instructions are injected on each prompt via agent hooks
7
+ * - 'mcp': Agent uses mcp tools to interact with brv
7
8
  */
8
- export const CONNECTOR_TYPES = ['rules', 'hook'];
9
+ export const CONNECTOR_TYPES = ['rules', 'hook', 'mcp'];
@@ -1,4 +1,13 @@
1
1
  import type { ConnectorType } from '../../domain/entities/connector-type.js';
2
+ /**
3
+ * Instructions for manual MCP setup when automatic configuration is not possible.
4
+ */
5
+ export type ManualInstallInstructions = {
6
+ /** The config content to copy (JSON or TOML formatted) */
7
+ configContent: string;
8
+ /** Guide URL or step-by-step instructions */
9
+ guide: string;
10
+ };
2
11
  /**
3
12
  * Result of a connector installation operation.
4
13
  */
@@ -7,8 +16,12 @@ export type ConnectorInstallResult = {
7
16
  alreadyInstalled: boolean;
8
17
  /** Path to the configuration/rule file */
9
18
  configPath: string;
19
+ /** Instructions for manual setup (present when requiresManualSetup is true) */
20
+ manualInstructions?: ManualInstallInstructions;
10
21
  /** Human-readable message describing the result */
11
22
  message: string;
23
+ /** Whether this requires manual setup by the user */
24
+ requiresManualSetup?: boolean;
12
25
  /** Whether the installation was successful */
13
26
  success: boolean;
14
27
  };
@@ -0,0 +1,40 @@
1
+ import type { McpServerConfig } from '../../infra/connectors/mcp/mcp-connector-config.js';
2
+ /**
3
+ * Result of checking if MCP config exists.
4
+ */
5
+ export type McpConfigExistsResult = {
6
+ /** Whether the config file exists */
7
+ fileExists: boolean;
8
+ /** Whether the BRV MCP server entry exists in the config */
9
+ serverExists: boolean;
10
+ };
11
+ /**
12
+ * Interface for writing MCP server configurations to agent config files.
13
+ * Different implementations handle different file formats (JSON, TOML, etc.).
14
+ */
15
+ export interface IMcpConfigWriter {
16
+ /**
17
+ * Check if the config file and BRV server entry exist.
18
+ *
19
+ * @param filePath - Absolute path to the config file
20
+ * @returns Object indicating file and server existence
21
+ */
22
+ exists(filePath: string): Promise<McpConfigExistsResult>;
23
+ /**
24
+ * Remove the BRV MCP server entry from the config file.
25
+ * Does not delete the file, only removes the server entry.
26
+ *
27
+ * @param filePath - Absolute path to the config file
28
+ * @returns True if the server was removed, false if it didn't exist
29
+ */
30
+ remove(filePath: string): Promise<boolean>;
31
+ /**
32
+ * Write the MCP server configuration to the config file.
33
+ * Creates the file if it doesn't exist.
34
+ * Preserves existing configuration.
35
+ *
36
+ * @param filePath - Absolute path to the config file
37
+ * @param serverConfig - The MCP server configuration to write
38
+ */
39
+ write(filePath: string, serverConfig: McpServerConfig): Promise<void>;
40
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,13 +1,15 @@
1
1
  import { Agent } from '../domain/entities/agent.js';
2
+ import { ConnectorType } from '../domain/entities/connector-type.js';
2
3
  /**
3
4
  * Interface for rule template service operations.
4
5
  */
5
6
  export interface IRuleTemplateService {
6
7
  /**
7
- * Generates rule content based on the provided agent.
8
+ * Generates rule content based on the provided agent and connector type.
8
9
  *
9
10
  * @param agent The agent for which to generate the rule content.
11
+ * @param type The connector type (rules or mcp). Defaults to 'rules'.
10
12
  * @returns Promise resolving to the generated rule content.
11
13
  */
12
- generateRuleContent: (agent: Agent) => Promise<string>;
14
+ generateRuleContent: (agent: Agent, type: ConnectorType) => Promise<string>;
13
15
  }
@@ -54,6 +54,13 @@ export interface ITransportClient {
54
54
  * Returns the current connection state.
55
55
  */
56
56
  getState: () => ConnectionState;
57
+ /**
58
+ * Checks if the socket is actually connected and responsive.
59
+ * Verifies bidirectional communication by sending a ping and waiting for response.
60
+ * @param timeoutMs - Timeout in milliseconds (default: 2000)
61
+ * @returns true if socket is connected and responsive, false otherwise
62
+ */
63
+ isConnected: (timeoutMs?: number) => Promise<boolean>;
57
64
  /**
58
65
  * Joins a room for targeted broadcasts.
59
66
  * @param room - The room identifier to join
@@ -158,6 +158,14 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
158
158
  * @returns AsyncIterator that yields StreamingEvent objects
159
159
  */
160
160
  stream(input: string, options?: StreamOptions): Promise<AsyncIterableIterator<StreamingEvent>>;
161
+ /**
162
+ * Switch the default session to a different session ID.
163
+ * The session must already exist (created via createSession).
164
+ *
165
+ * @param sessionId - The session ID to switch to
166
+ * @throws Error if session does not exist
167
+ */
168
+ switchDefaultSession(sessionId: string): void;
161
169
  private getHistoryStorageInternal;
162
170
  private getSessionIdInternal;
163
171
  private getSessionManagerInternal;
@@ -520,6 +520,22 @@ export class CipherAgent extends BaseAgent {
520
520
  };
521
521
  return iterator;
522
522
  }
523
+ /**
524
+ * Switch the default session to a different session ID.
525
+ * The session must already exist (created via createSession).
526
+ *
527
+ * @param sessionId - The session ID to switch to
528
+ * @throws Error if session does not exist
529
+ */
530
+ switchDefaultSession(sessionId) {
531
+ this.ensureStarted();
532
+ // Verify the session exists
533
+ const session = this.getSessionManagerInternal().getSession(sessionId);
534
+ if (!session) {
535
+ throw new Error(`Session ${sessionId} does not exist. Create it first with createSession().`);
536
+ }
537
+ this._sessionId = sessionId;
538
+ }
523
539
  // === Private Helpers (alphabetical order) ===
524
540
  getHistoryStorageInternal() {
525
541
  const storage = this.services?.historyStorage;
@@ -178,6 +178,14 @@ export declare class ContextManager<T> {
178
178
  * Also clears persisted history if storage is enabled.
179
179
  */
180
180
  clearHistory(): Promise<void>;
181
+ /**
182
+ * Compress messages by removing oldest messages until total tokens fit within the budget.
183
+ * This directly modifies the internal messages array by slicing from the beginning.
184
+ *
185
+ * @param maxTokens - Maximum token budget allowed
186
+ * @param messageTokens - Array of token counts corresponding to each message
187
+ */
188
+ compressMessage(maxTokens: number, messageTokens: number[]): void;
181
189
  /**
182
190
  * Flush any pending history writes to storage.
183
191
  * Provides explicit durability guarantee - ensures all messages