byterover-cli 1.0.5 → 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.
- package/README.md +19 -13
- package/dist/commands/hook-prompt-submit.d.ts +27 -0
- package/dist/commands/hook-prompt-submit.js +39 -0
- package/dist/commands/mcp.d.ts +13 -0
- package/dist/commands/mcp.js +61 -0
- package/dist/commands/status.js +8 -3
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/core/domain/cipher/agent-events/types.d.ts +44 -1
- package/dist/core/domain/cipher/tools/constants.d.ts +1 -0
- package/dist/core/domain/cipher/tools/constants.js +1 -0
- package/dist/core/domain/entities/agent.d.ts +16 -0
- package/dist/core/domain/entities/agent.js +78 -0
- package/dist/core/domain/entities/connector-type.d.ts +10 -0
- package/dist/core/domain/entities/connector-type.js +9 -0
- package/dist/core/domain/entities/event.d.ts +1 -1
- package/dist/core/domain/entities/event.js +2 -0
- package/dist/core/domain/errors/task-error.d.ts +4 -0
- package/dist/core/domain/errors/task-error.js +7 -0
- package/dist/core/domain/transport/schemas.d.ts +40 -0
- package/dist/core/domain/transport/schemas.js +28 -0
- package/dist/core/interfaces/connectors/connector-types.d.ts +70 -0
- package/dist/core/interfaces/connectors/i-connector-manager.d.ts +72 -0
- package/dist/core/interfaces/connectors/i-connector-manager.js +1 -0
- package/dist/core/interfaces/connectors/i-connector.d.ts +54 -0
- package/dist/core/interfaces/connectors/i-connector.js +1 -0
- package/dist/core/interfaces/i-file-service.d.ts +7 -0
- package/dist/core/interfaces/i-mcp-config-writer.d.ts +40 -0
- package/dist/core/interfaces/i-mcp-config-writer.js +1 -0
- package/dist/core/interfaces/i-rule-template-service.d.ts +4 -2
- package/dist/core/interfaces/transport/i-transport-client.d.ts +7 -0
- package/dist/core/interfaces/usecase/i-connectors-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-connectors-use-case.js +1 -0
- package/dist/hooks/init/update-notifier.d.ts +1 -0
- package/dist/hooks/init/update-notifier.js +10 -1
- package/dist/infra/cipher/agent/cipher-agent.d.ts +8 -0
- package/dist/infra/cipher/agent/cipher-agent.js +16 -0
- package/dist/infra/cipher/file-system/binary-utils.d.ts +7 -12
- package/dist/infra/cipher/file-system/binary-utils.js +46 -31
- package/dist/infra/cipher/llm/context/context-manager.d.ts +10 -2
- package/dist/infra/cipher/llm/context/context-manager.js +39 -2
- package/dist/infra/cipher/llm/formatters/gemini-formatter.js +48 -9
- package/dist/infra/cipher/llm/internal-llm-service.d.ts +4 -0
- package/dist/infra/cipher/llm/internal-llm-service.js +40 -12
- package/dist/infra/cipher/session/chat-session.d.ts +3 -0
- package/dist/infra/cipher/session/chat-session.js +7 -1
- package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.d.ts +6 -7
- package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.js +57 -18
- package/dist/infra/cipher/tools/implementations/curate-tool.d.ts +1 -8
- package/dist/infra/cipher/tools/implementations/curate-tool.js +380 -24
- package/dist/infra/cipher/tools/implementations/read-file-tool.js +38 -17
- package/dist/infra/cipher/tools/implementations/search-knowledge-tool.d.ts +7 -0
- package/dist/infra/cipher/tools/implementations/search-knowledge-tool.js +303 -0
- package/dist/infra/cipher/tools/index.d.ts +1 -0
- package/dist/infra/cipher/tools/index.js +1 -0
- package/dist/infra/cipher/tools/tool-manager.js +1 -0
- package/dist/infra/cipher/tools/tool-registry.js +7 -0
- package/dist/infra/connectors/connector-manager.d.ts +32 -0
- package/dist/infra/connectors/connector-manager.js +158 -0
- package/dist/infra/connectors/hook/hook-connector-config.d.ts +52 -0
- package/dist/infra/connectors/hook/hook-connector-config.js +41 -0
- package/dist/infra/connectors/hook/hook-connector.d.ts +46 -0
- package/dist/infra/connectors/hook/hook-connector.js +231 -0
- package/dist/infra/connectors/mcp/index.d.ts +4 -0
- package/dist/infra/connectors/mcp/index.js +4 -0
- package/dist/infra/connectors/mcp/json-mcp-config-writer.d.ts +26 -0
- package/dist/infra/connectors/mcp/json-mcp-config-writer.js +71 -0
- package/dist/infra/connectors/mcp/mcp-connector-config.d.ts +229 -0
- package/dist/infra/connectors/mcp/mcp-connector-config.js +173 -0
- package/dist/infra/connectors/mcp/mcp-connector.d.ts +80 -0
- package/dist/infra/connectors/mcp/mcp-connector.js +324 -0
- package/dist/infra/connectors/mcp/toml-mcp-config-writer.d.ts +45 -0
- package/dist/infra/connectors/mcp/toml-mcp-config-writer.js +134 -0
- package/dist/infra/{rule → connectors/rules}/legacy-rule-detector.d.ts +2 -2
- package/dist/infra/{rule → connectors/rules}/legacy-rule-detector.js +1 -1
- package/dist/infra/connectors/rules/rules-connector-config.d.ts +95 -0
- package/dist/infra/{rule/agent-rule-config.js → connectors/rules/rules-connector-config.js} +10 -10
- package/dist/infra/connectors/rules/rules-connector.d.ts +34 -0
- package/dist/infra/connectors/rules/rules-connector.js +139 -0
- package/dist/infra/connectors/shared/rule-file-manager.d.ts +72 -0
- package/dist/infra/connectors/shared/rule-file-manager.js +119 -0
- package/dist/infra/connectors/shared/template-service.d.ts +27 -0
- package/dist/infra/connectors/shared/template-service.js +125 -0
- package/dist/infra/context-tree/file-context-tree-writer-service.d.ts +5 -2
- package/dist/infra/context-tree/file-context-tree-writer-service.js +20 -5
- package/dist/infra/core/executors/curate-executor.d.ts +2 -2
- package/dist/infra/core/executors/curate-executor.js +7 -7
- package/dist/infra/core/executors/query-executor.d.ts +12 -0
- package/dist/infra/core/executors/query-executor.js +62 -1
- package/dist/infra/file/fs-file-service.d.ts +7 -0
- package/dist/infra/file/fs-file-service.js +15 -1
- package/dist/infra/mcp/index.d.ts +2 -0
- package/dist/infra/mcp/index.js +2 -0
- package/dist/infra/mcp/mcp-server.d.ts +58 -0
- package/dist/infra/mcp/mcp-server.js +178 -0
- package/dist/infra/mcp/tools/brv-curate-tool.d.ts +23 -0
- package/dist/infra/mcp/tools/brv-curate-tool.js +68 -0
- package/dist/infra/mcp/tools/brv-query-tool.d.ts +17 -0
- package/dist/infra/mcp/tools/brv-query-tool.js +68 -0
- package/dist/infra/mcp/tools/index.d.ts +3 -0
- package/dist/infra/mcp/tools/index.js +3 -0
- package/dist/infra/mcp/tools/task-result-waiter.d.ts +30 -0
- package/dist/infra/mcp/tools/task-result-waiter.js +56 -0
- package/dist/infra/process/agent-worker.d.ts +2 -2
- package/dist/infra/process/agent-worker.js +663 -142
- package/dist/infra/process/constants.d.ts +1 -1
- package/dist/infra/process/constants.js +1 -1
- package/dist/infra/process/ipc-types.d.ts +17 -4
- package/dist/infra/process/ipc-types.js +3 -3
- package/dist/infra/process/parent-heartbeat.d.ts +47 -0
- package/dist/infra/process/parent-heartbeat.js +118 -0
- package/dist/infra/process/process-manager.d.ts +79 -0
- package/dist/infra/process/process-manager.js +277 -3
- package/dist/infra/process/task-queue-manager.d.ts +13 -0
- package/dist/infra/process/task-queue-manager.js +19 -0
- package/dist/infra/process/transport-handlers.d.ts +3 -0
- package/dist/infra/process/transport-handlers.js +51 -5
- package/dist/infra/process/transport-worker.js +9 -69
- package/dist/infra/repl/commands/connectors-command.d.ts +8 -0
- package/dist/infra/repl/commands/{gen-rules-command.js → connectors-command.js} +21 -10
- package/dist/infra/repl/commands/curate-command.js +2 -2
- package/dist/infra/repl/commands/index.js +3 -2
- package/dist/infra/repl/commands/init-command.js +11 -7
- package/dist/infra/repl/commands/query-command.js +22 -2
- package/dist/infra/repl/commands/reset-command.js +1 -1
- package/dist/infra/transport/socket-io-transport-client.d.ts +75 -0
- package/dist/infra/transport/socket-io-transport-client.js +308 -7
- package/dist/infra/transport/socket-io-transport-server.js +4 -0
- package/dist/infra/usecase/connectors-use-case.d.ts +63 -0
- package/dist/infra/usecase/connectors-use-case.js +222 -0
- package/dist/infra/usecase/init-use-case.d.ts +8 -43
- package/dist/infra/usecase/init-use-case.js +27 -252
- package/dist/infra/usecase/logout-use-case.js +1 -1
- package/dist/infra/usecase/pull-use-case.js +5 -5
- package/dist/infra/usecase/push-use-case.js +4 -4
- package/dist/infra/usecase/reset-use-case.js +3 -4
- package/dist/infra/usecase/space-list-use-case.js +3 -3
- package/dist/infra/usecase/space-switch-use-case.js +3 -3
- package/dist/infra/usecase/status-use-case.d.ts +10 -0
- package/dist/infra/usecase/status-use-case.js +53 -0
- package/dist/resources/prompts/curate.yml +114 -4
- package/dist/resources/prompts/explore.yml +34 -0
- package/dist/resources/prompts/query-orchestrator.yml +112 -0
- package/dist/resources/prompts/system-prompt.yml +12 -2
- package/dist/resources/tools/search_knowledge.txt +32 -0
- package/dist/templates/mcp-base.md +1 -0
- package/dist/templates/sections/brv-instructions.md +98 -0
- package/dist/templates/sections/mcp-workflow.md +13 -0
- package/dist/tui/app.js +4 -1
- package/dist/tui/components/command-details.js +1 -1
- package/dist/tui/components/execution/execution-changes.d.ts +2 -0
- package/dist/tui/components/execution/execution-changes.js +5 -1
- package/dist/tui/components/execution/execution-content.d.ts +2 -0
- package/dist/tui/components/execution/execution-content.js +8 -18
- package/dist/tui/components/execution/execution-input.d.ts +2 -0
- package/dist/tui/components/execution/execution-input.js +6 -4
- package/dist/tui/components/execution/execution-progress.d.ts +2 -0
- package/dist/tui/components/execution/execution-progress.js +6 -2
- package/dist/tui/components/execution/expanded-log-view.d.ts +20 -0
- package/dist/tui/components/execution/expanded-log-view.js +75 -0
- package/dist/tui/components/execution/expanded-message-view.d.ts +24 -0
- package/dist/tui/components/execution/expanded-message-view.js +68 -0
- package/dist/tui/components/execution/index.d.ts +2 -0
- package/dist/tui/components/execution/index.js +2 -0
- package/dist/tui/components/execution/log-item.d.ts +4 -0
- package/dist/tui/components/execution/log-item.js +2 -2
- package/dist/tui/components/footer.js +1 -1
- package/dist/tui/components/index.d.ts +2 -1
- package/dist/tui/components/index.js +2 -1
- package/dist/tui/components/init.js +2 -9
- package/dist/tui/components/logo.js +4 -3
- package/dist/tui/components/markdown.d.ts +13 -0
- package/dist/tui/components/markdown.js +88 -0
- package/dist/tui/components/message-item.js +1 -1
- package/dist/tui/components/onboarding/onboarding-flow.js +14 -11
- package/dist/tui/components/onboarding/welcome-box.js +1 -1
- package/dist/tui/components/suggestions.js +3 -3
- package/dist/tui/contexts/mode-context.js +6 -2
- package/dist/tui/contexts/onboarding-context.d.ts +4 -0
- package/dist/tui/contexts/onboarding-context.js +14 -2
- package/dist/tui/hooks/index.d.ts +1 -0
- package/dist/tui/hooks/index.js +1 -0
- package/dist/tui/hooks/use-is-latest-version.d.ts +6 -0
- package/dist/tui/hooks/use-is-latest-version.js +22 -0
- package/dist/tui/views/command-view.d.ts +1 -1
- package/dist/tui/views/command-view.js +87 -98
- package/dist/tui/views/logs-view.d.ts +8 -0
- package/dist/tui/views/logs-view.js +55 -27
- package/dist/utils/file-validator.d.ts +1 -1
- package/dist/utils/file-validator.js +25 -28
- package/dist/utils/type-guards.d.ts +5 -0
- package/dist/utils/type-guards.js +7 -0
- package/oclif.manifest.json +55 -4
- package/package.json +12 -1
- package/dist/core/interfaces/usecase/i-generate-rules-use-case.d.ts +0 -3
- package/dist/infra/repl/commands/gen-rules-command.d.ts +0 -7
- package/dist/infra/rule/agent-rule-config.d.ts +0 -19
- package/dist/infra/rule/rule-template-service.d.ts +0 -18
- package/dist/infra/rule/rule-template-service.js +0 -88
- package/dist/infra/usecase/generate-rules-use-case.d.ts +0 -61
- package/dist/infra/usecase/generate-rules-use-case.js +0 -285
- /package/dist/core/interfaces/{usecase/i-generate-rules-use-case.js → connectors/connector-types.js} +0 -0
- /package/dist/infra/{rule → connectors/shared}/constants.d.ts +0 -0
- /package/dist/infra/{rule → connectors/shared}/constants.js +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Agent } from '../../../core/domain/entities/agent.js';
|
|
2
|
+
import type { ConnectorType } from '../../../core/domain/entities/connector-type.js';
|
|
3
|
+
import type { IRuleTemplateService } from '../../../core/interfaces/i-rule-template-service.js';
|
|
4
|
+
import type { ITemplateLoader } from '../../../core/interfaces/i-template-loader.js';
|
|
5
|
+
/**
|
|
6
|
+
* Service for generating rule templates for different agents.
|
|
7
|
+
* Loads templates from external files and assembles them with agent-specific context.
|
|
8
|
+
*/
|
|
9
|
+
export declare class RuleTemplateService implements IRuleTemplateService {
|
|
10
|
+
private readonly templateLoader;
|
|
11
|
+
constructor(templateLoader: ITemplateLoader);
|
|
12
|
+
/**
|
|
13
|
+
* Generates rule content for the specified agent by loading and assembling templates.
|
|
14
|
+
* @param agent The agent for which to generate rules.
|
|
15
|
+
* @returns Promise resolving to the rule content as a string.
|
|
16
|
+
* @throws Error if templates cannot be loaded or assembled.
|
|
17
|
+
*/
|
|
18
|
+
generateRuleContent(agent: Agent, type?: ConnectorType): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Generates CLI mode content with full workflow and command reference.
|
|
21
|
+
*/
|
|
22
|
+
private generateCliContent;
|
|
23
|
+
/**
|
|
24
|
+
* Generates MCP mode content with concise tool-focused instructions.
|
|
25
|
+
*/
|
|
26
|
+
private generateMcpContent;
|
|
27
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { BRV_RULE_MARKERS, BRV_RULE_TAG } from './constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps rule content with boundary markers for identification and replacement.
|
|
4
|
+
*
|
|
5
|
+
* @param content The rule content to wrap.
|
|
6
|
+
* @param agent The agent name for the footer tag.
|
|
7
|
+
* @param header Agent-specific header.
|
|
8
|
+
* @returns The wrapped content with boundary markers.
|
|
9
|
+
*/
|
|
10
|
+
const wrapContentWithBoundaryMarkers = (content, agent, header) => {
|
|
11
|
+
const parts = [BRV_RULE_MARKERS.START, header, content, '---', `${BRV_RULE_TAG} ${agent}`, BRV_RULE_MARKERS.END];
|
|
12
|
+
return parts.join('\n');
|
|
13
|
+
};
|
|
14
|
+
const guideHeaders = [
|
|
15
|
+
{
|
|
16
|
+
agent: 'Augment Code',
|
|
17
|
+
value: `---
|
|
18
|
+
type: "always_apply"
|
|
19
|
+
---`,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
agent: 'Cursor',
|
|
23
|
+
value: `---
|
|
24
|
+
description: ByteRover CLI Rules
|
|
25
|
+
alwaysApply: true
|
|
26
|
+
---`,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
agent: 'Kiro',
|
|
30
|
+
value: `---
|
|
31
|
+
inclusion: always
|
|
32
|
+
---`,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
agent: 'Qoder',
|
|
36
|
+
value: `---
|
|
37
|
+
trigger: always_on
|
|
38
|
+
alwaysApply: true
|
|
39
|
+
---`,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
agent: 'Windsurf',
|
|
43
|
+
value: `---
|
|
44
|
+
trigger: always_on
|
|
45
|
+
---`,
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* Service for generating rule templates for different agents.
|
|
50
|
+
* Loads templates from external files and assembles them with agent-specific context.
|
|
51
|
+
*/
|
|
52
|
+
export class RuleTemplateService {
|
|
53
|
+
templateLoader;
|
|
54
|
+
constructor(templateLoader) {
|
|
55
|
+
this.templateLoader = templateLoader;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Generates rule content for the specified agent by loading and assembling templates.
|
|
59
|
+
* @param agent The agent for which to generate rules.
|
|
60
|
+
* @returns Promise resolving to the rule content as a string.
|
|
61
|
+
* @throws Error if templates cannot be loaded or assembled.
|
|
62
|
+
*/
|
|
63
|
+
async generateRuleContent(agent, type) {
|
|
64
|
+
try {
|
|
65
|
+
// Load section templates
|
|
66
|
+
let content;
|
|
67
|
+
switch (type) {
|
|
68
|
+
case 'mcp': {
|
|
69
|
+
content = await this.generateMcpContent();
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case 'rules': {
|
|
73
|
+
content = await this.generateCliContent(agent);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
default: {
|
|
77
|
+
throw new Error(`Unsupported connector type: ${type}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Add agent-specific header if available
|
|
81
|
+
const header = guideHeaders.find((h) => h.agent === agent)?.value || '';
|
|
82
|
+
return wrapContentWithBoundaryMarkers(content, agent, header);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw new Error(`Failed to generate rule content for agent '${agent}' - type '${type}': ${error instanceof Error ? error.message : String(error)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Generates CLI mode content with full workflow and command reference.
|
|
90
|
+
*/
|
|
91
|
+
async generateCliContent(agent) {
|
|
92
|
+
// Load section templates
|
|
93
|
+
const workflow = await this.templateLoader.loadSection('workflow');
|
|
94
|
+
const commandReference = await this.templateLoader.loadSection('command-reference');
|
|
95
|
+
// Load base template
|
|
96
|
+
const baseTemplate = await this.templateLoader.loadTemplate('base.md');
|
|
97
|
+
// Assemble context for variable substitution
|
|
98
|
+
const context = {
|
|
99
|
+
/* eslint-disable camelcase */
|
|
100
|
+
agent_name: agent,
|
|
101
|
+
command_reference: commandReference,
|
|
102
|
+
workflow,
|
|
103
|
+
/* eslint-enable camelcase */
|
|
104
|
+
};
|
|
105
|
+
// Substitute variables and get content
|
|
106
|
+
return this.templateLoader.substituteVariables(baseTemplate, context);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Generates MCP mode content with concise tool-focused instructions.
|
|
110
|
+
*/
|
|
111
|
+
async generateMcpContent() {
|
|
112
|
+
// Load MCP-specific section
|
|
113
|
+
const mcpWorkflow = await this.templateLoader.loadSection('mcp-workflow');
|
|
114
|
+
// Load MCP base template
|
|
115
|
+
const mcpBaseTemplate = await this.templateLoader.loadTemplate('mcp-base.md');
|
|
116
|
+
// Assemble context for variable substitution
|
|
117
|
+
const context = {
|
|
118
|
+
/* eslint-disable camelcase */
|
|
119
|
+
mcp_workflow: mcpWorkflow,
|
|
120
|
+
/* eslint-enable camelcase */
|
|
121
|
+
};
|
|
122
|
+
// Substitute variables and get content
|
|
123
|
+
return this.templateLoader.substituteVariables(mcpBaseTemplate, context);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -15,11 +15,14 @@ export declare class FileContextTreeWriterService implements IContextTreeWriterS
|
|
|
15
15
|
private readonly snapshotService;
|
|
16
16
|
constructor(dependencies: ContextTreeWriterServiceDependencies, config?: ContextTreeWriterServiceConfig);
|
|
17
17
|
sync(params: SyncParams): Promise<SyncResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Builds a map of remote files with normalized paths.
|
|
20
|
+
* Filters out README.md at root level to match getCurrentState behavior.
|
|
21
|
+
*/
|
|
22
|
+
private buildRemoteFilesMap;
|
|
18
23
|
/**
|
|
19
24
|
* Normalizes a file path by converting backslashes to forward slashes
|
|
20
25
|
* and removing leading slashes.
|
|
21
|
-
* Ensures cross-platform compatibility and handles legacy API responses
|
|
22
|
-
* that may include leading slashes or Windows-style backslashes.
|
|
23
26
|
*/
|
|
24
27
|
private normalizePath;
|
|
25
28
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
|
-
import { BRV_DIR, CONTEXT_TREE_DIR } from '../../constants.js';
|
|
4
|
+
import { BRV_DIR, CONTEXT_TREE_DIR, README_FILE } from '../../constants.js';
|
|
5
5
|
import { toUnixPath } from './path-utils.js';
|
|
6
6
|
/**
|
|
7
7
|
* File-based implementation of IContextTreeWriterService.
|
|
@@ -19,8 +19,9 @@ export class FileContextTreeWriterService {
|
|
|
19
19
|
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
20
20
|
// Get current local state
|
|
21
21
|
const localState = await this.snapshotService.getCurrentState(params.directory);
|
|
22
|
-
// Build map of remote files
|
|
23
|
-
|
|
22
|
+
// Build map of remote files, filtering out README.md at root level
|
|
23
|
+
// This matches getCurrentState behavior which also excludes root README.md
|
|
24
|
+
const remoteFiles = this.buildRemoteFilesMap(params.files);
|
|
24
25
|
const added = [];
|
|
25
26
|
const edited = [];
|
|
26
27
|
const deleted = [];
|
|
@@ -53,11 +54,25 @@ export class FileContextTreeWriterService {
|
|
|
53
54
|
}
|
|
54
55
|
return { added, deleted, edited };
|
|
55
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Builds a map of remote files with normalized paths.
|
|
59
|
+
* Filters out README.md at root level to match getCurrentState behavior.
|
|
60
|
+
*/
|
|
61
|
+
buildRemoteFilesMap(files) {
|
|
62
|
+
const result = new Map();
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
const normalizedPath = this.normalizePath(file.path);
|
|
65
|
+
// Skip README.md at root level (matches getCurrentState behavior)
|
|
66
|
+
if (normalizedPath === README_FILE) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
result.set(normalizedPath, file);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
56
73
|
/**
|
|
57
74
|
* Normalizes a file path by converting backslashes to forward slashes
|
|
58
75
|
* and removing leading slashes.
|
|
59
|
-
* Ensures cross-platform compatibility and handles legacy API responses
|
|
60
|
-
* that may include leading slashes or Windows-style backslashes.
|
|
61
76
|
*/
|
|
62
77
|
normalizePath(path) {
|
|
63
78
|
return toUnixPath(path).replace(/^\/+/, '');
|
|
@@ -23,8 +23,8 @@ export declare class CurateExecutor implements ICurateExecutor {
|
|
|
23
23
|
*
|
|
24
24
|
* @param filePaths - Array of file paths (relative or absolute)
|
|
25
25
|
* @param clientCwd - Client's working directory for file validation (optional, defaults to process.cwd())
|
|
26
|
-
* @returns Formatted instructions for the agent to read the specified files
|
|
27
|
-
*
|
|
26
|
+
* @returns Formatted instructions for the agent to read the specified files
|
|
27
|
+
* @throws {FileValidationError} If any file validation fails
|
|
28
28
|
*/
|
|
29
29
|
private processFileReferences;
|
|
30
30
|
}
|
|
@@ -19,10 +19,8 @@ export class CurateExecutor {
|
|
|
19
19
|
static MAX_FILES = 5;
|
|
20
20
|
async executeWithAgent(agent, options) {
|
|
21
21
|
const { clientCwd, content, files, taskId } = options;
|
|
22
|
+
// Process file references (throws FileValidationError if validation fails)
|
|
22
23
|
const fileReferenceInstructions = this.processFileReferences(files ?? [], clientCwd);
|
|
23
|
-
if (fileReferenceInstructions === undefined) {
|
|
24
|
-
throw new FileValidationError();
|
|
25
|
-
}
|
|
26
24
|
// Build prompt with optional file reference instructions
|
|
27
25
|
const prompt = fileReferenceInstructions ? `${content}\n${fileReferenceInstructions}` : content;
|
|
28
26
|
// Execute with curate commandType
|
|
@@ -39,8 +37,8 @@ export class CurateExecutor {
|
|
|
39
37
|
*
|
|
40
38
|
* @param filePaths - Array of file paths (relative or absolute)
|
|
41
39
|
* @param clientCwd - Client's working directory for file validation (optional, defaults to process.cwd())
|
|
42
|
-
* @returns Formatted instructions for the agent to read the specified files
|
|
43
|
-
*
|
|
40
|
+
* @returns Formatted instructions for the agent to read the specified files
|
|
41
|
+
* @throws {FileValidationError} If any file validation fails
|
|
44
42
|
*/
|
|
45
43
|
processFileReferences(filePaths, clientCwd) {
|
|
46
44
|
if (!filePaths || filePaths.length === 0) {
|
|
@@ -64,9 +62,10 @@ export class CurateExecutor {
|
|
|
64
62
|
errors.push(result.error ?? `Invalid file: ${filePath}`);
|
|
65
63
|
}
|
|
66
64
|
}
|
|
67
|
-
// If there are any validation errors,
|
|
65
|
+
// If there are any validation errors, throw with specific messages
|
|
68
66
|
if (errors.length > 0) {
|
|
69
|
-
|
|
67
|
+
const errorMessage = `File validation failed:\n${errors.map((e) => ` - ${e}`).join('\n')}`;
|
|
68
|
+
throw new FileValidationError(errorMessage);
|
|
70
69
|
}
|
|
71
70
|
// Format instructions for the agent
|
|
72
71
|
const instructions = [
|
|
@@ -80,6 +79,7 @@ export class CurateExecutor {
|
|
|
80
79
|
'- You MUST use the `read_file` tool to read ALL of these files IN PARALLEL (in a single iteration) before proceeding to create knowledge topics',
|
|
81
80
|
'- These files contain essential context that will help you create comprehensive and accurate knowledge topics',
|
|
82
81
|
'- Read them in parallel to maximize efficiency - they do not depend on each other',
|
|
82
|
+
'- **CRITICAL:** Only curate files where `read_file` returns `success: true`. Files that return `success: false` are error messages and should not be curated.',
|
|
83
83
|
'- After reading all files, proceed with the normal workflow: detect domains, find existing knowledge, and create/update topics',
|
|
84
84
|
'',
|
|
85
85
|
];
|
|
@@ -11,7 +11,19 @@ import type { IQueryExecutor, QueryExecuteOptions } from '../../../core/interfac
|
|
|
11
11
|
* - Event streaming is handled by agent-worker (subscribes to agentEventBus)
|
|
12
12
|
* - Transport handles task lifecycle (task:started, task:completed, task:error)
|
|
13
13
|
* - Executor focuses solely on query execution
|
|
14
|
+
*
|
|
15
|
+
* Enhanced with multi-perspective search strategy for comprehensive results.
|
|
14
16
|
*/
|
|
15
17
|
export declare class QueryExecutor implements IQueryExecutor {
|
|
16
18
|
executeWithAgent(agent: ICipherAgent, options: QueryExecuteOptions): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Build an enhanced query prompt with multi-perspective search instructions.
|
|
21
|
+
*
|
|
22
|
+
* The prompt instructs the agent to:
|
|
23
|
+
* 1. Analyze the query to understand intent
|
|
24
|
+
* 2. Generate 2-3 search perspectives for comprehensive coverage
|
|
25
|
+
* 3. Execute searches using the task tool with explore subagents
|
|
26
|
+
* 4. Synthesize results into a cohesive answer with citations
|
|
27
|
+
*/
|
|
28
|
+
private buildQueryPrompt;
|
|
17
29
|
}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* - Event streaming is handled by agent-worker (subscribes to agentEventBus)
|
|
10
10
|
* - Transport handles task lifecycle (task:started, task:completed, task:error)
|
|
11
11
|
* - Executor focuses solely on query execution
|
|
12
|
+
*
|
|
13
|
+
* Enhanced with multi-perspective search strategy for comprehensive results.
|
|
12
14
|
*/
|
|
13
15
|
export class QueryExecutor {
|
|
14
16
|
async executeWithAgent(agent, options) {
|
|
@@ -16,11 +18,70 @@ export class QueryExecutor {
|
|
|
16
18
|
// Execute with query commandType
|
|
17
19
|
// Agent uses its default session (created during start())
|
|
18
20
|
// Task lifecycle is managed by Transport (task:started, task:completed, task:error)
|
|
19
|
-
const prompt =
|
|
21
|
+
const prompt = this.buildQueryPrompt(query);
|
|
20
22
|
const response = await agent.execute(prompt, {
|
|
21
23
|
executionContext: { commandType: 'query' },
|
|
22
24
|
taskId,
|
|
23
25
|
});
|
|
24
26
|
return response;
|
|
25
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Build an enhanced query prompt with multi-perspective search instructions.
|
|
30
|
+
*
|
|
31
|
+
* The prompt instructs the agent to:
|
|
32
|
+
* 1. Analyze the query to understand intent
|
|
33
|
+
* 2. Generate 2-3 search perspectives for comprehensive coverage
|
|
34
|
+
* 3. Execute searches using the task tool with explore subagents
|
|
35
|
+
* 4. Synthesize results into a cohesive answer with citations
|
|
36
|
+
*/
|
|
37
|
+
buildQueryPrompt(query) {
|
|
38
|
+
return `## User Query
|
|
39
|
+
${query}
|
|
40
|
+
|
|
41
|
+
## Query Processing Instructions
|
|
42
|
+
|
|
43
|
+
You are searching the context tree to answer the user's question. Follow this strategy for comprehensive results:
|
|
44
|
+
|
|
45
|
+
### Step 1: Query Analysis
|
|
46
|
+
First, analyze the query:
|
|
47
|
+
- What is the user trying to learn? (core intent)
|
|
48
|
+
- What are the key concepts mentioned?
|
|
49
|
+
- Is this a factual, analytical, or exploratory question?
|
|
50
|
+
|
|
51
|
+
### Step 2: Multi-Perspective Search
|
|
52
|
+
Generate 2-3 complementary search perspectives:
|
|
53
|
+
|
|
54
|
+
1. **Direct Search**: Use exact terms from the query
|
|
55
|
+
2. **Related Concepts**: Search for synonyms, related terms, technical jargon
|
|
56
|
+
3. **Implementation Patterns**: Search for how things are used or implemented
|
|
57
|
+
|
|
58
|
+
### Step 3: Execute Parallel Searches
|
|
59
|
+
Use the \`task\` tool to spawn explore subagents for each perspective:
|
|
60
|
+
- Each subagent focuses on ONE search angle
|
|
61
|
+
- Use \`contextTreeOnly=true\` to search only the context tree
|
|
62
|
+
- Provide clear, specific search instructions
|
|
63
|
+
|
|
64
|
+
Example:
|
|
65
|
+
\`\`\`
|
|
66
|
+
task(
|
|
67
|
+
subagentType="explore",
|
|
68
|
+
description="Search [perspective]",
|
|
69
|
+
prompt="Search for [specific terms]. Look in .brv/context-tree/ for [what to find].",
|
|
70
|
+
contextTreeOnly=true
|
|
71
|
+
)
|
|
72
|
+
\`\`\`
|
|
73
|
+
|
|
74
|
+
### Step 4: Synthesize Results
|
|
75
|
+
After gathering information:
|
|
76
|
+
1. Identify overlapping findings (likely most relevant)
|
|
77
|
+
2. Combine unique insights from each perspective
|
|
78
|
+
3. Provide a clear, organized answer
|
|
79
|
+
4. Cite sources with file paths
|
|
80
|
+
|
|
81
|
+
### Response Format
|
|
82
|
+
- **Summary**: Brief answer (2-3 sentences)
|
|
83
|
+
- **Details**: Expanded explanation with findings
|
|
84
|
+
- **Sources**: File paths for referenced information
|
|
85
|
+
- **Gaps**: Note any aspects that couldn't be answered`;
|
|
86
|
+
}
|
|
26
87
|
}
|
|
@@ -4,6 +4,13 @@ import { type IFileService, type WriteMode } from '../../core/interfaces/i-file-
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class FsFileService implements IFileService {
|
|
6
6
|
createBackup(filePath: string): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Deletes a file at the specified path.
|
|
9
|
+
*
|
|
10
|
+
* @param filePath The path to the file to delete.
|
|
11
|
+
* @returns A promise that resolves when the file has been deleted.
|
|
12
|
+
*/
|
|
13
|
+
delete(filePath: string): Promise<void>;
|
|
7
14
|
/**
|
|
8
15
|
* Checks if a file exists at the specified path.
|
|
9
16
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, appendFile, copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { access, appendFile, copyFile, mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { dirname } from 'node:path';
|
|
3
3
|
/**
|
|
4
4
|
* File service implementation using Node.js fs module.
|
|
@@ -16,6 +16,20 @@ export class FsFileService {
|
|
|
16
16
|
throw new Error(`Failed to create backup file '${filePath}': ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Deletes a file at the specified path.
|
|
21
|
+
*
|
|
22
|
+
* @param filePath The path to the file to delete.
|
|
23
|
+
* @returns A promise that resolves when the file has been deleted.
|
|
24
|
+
*/
|
|
25
|
+
async delete(filePath) {
|
|
26
|
+
try {
|
|
27
|
+
await unlink(filePath);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`Failed to delete file '${filePath}': ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
19
33
|
/**
|
|
20
34
|
* Checks if a file exists at the specified path.
|
|
21
35
|
*
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface McpServerConfig {
|
|
2
|
+
/** CLI version for MCP server identification */
|
|
3
|
+
version: string;
|
|
4
|
+
/** Working directory for file operations */
|
|
5
|
+
workingDirectory: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* ByteRover MCP Server.
|
|
9
|
+
*
|
|
10
|
+
* Exposes brv-query and brv-curate as MCP tools for coding agents.
|
|
11
|
+
* Connects to a running brv instance via Socket.IO transport.
|
|
12
|
+
*
|
|
13
|
+
* Architecture:
|
|
14
|
+
* - Coding agent spawns `brv mcp` process
|
|
15
|
+
* - MCP server connects to running brv instance via Socket.IO
|
|
16
|
+
* - MCP tools create tasks via transport
|
|
17
|
+
* - Tasks are executed by the existing agent process
|
|
18
|
+
*/
|
|
19
|
+
export declare class ByteRoverMcpServer {
|
|
20
|
+
private client;
|
|
21
|
+
private readonly config;
|
|
22
|
+
private currentReconnectDelay;
|
|
23
|
+
private isReconnecting;
|
|
24
|
+
private reconnectTimer;
|
|
25
|
+
private readonly server;
|
|
26
|
+
private transport;
|
|
27
|
+
constructor(config: McpServerConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Starts the MCP server.
|
|
30
|
+
*
|
|
31
|
+
* 1. Connects to running brv instance via Socket.IO
|
|
32
|
+
* 2. Starts MCP server with stdio transport
|
|
33
|
+
*
|
|
34
|
+
* @throws NoInstanceRunningError - No brv instance is running
|
|
35
|
+
* @throws ConnectionFailedError - Failed to connect to brv instance
|
|
36
|
+
*/
|
|
37
|
+
start(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Stops the MCP server.
|
|
40
|
+
*
|
|
41
|
+
* Disconnects from the brv instance.
|
|
42
|
+
*/
|
|
43
|
+
stop(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Attempts to reconnect to the brv instance.
|
|
46
|
+
* Uses exponential backoff for retry delays.
|
|
47
|
+
*/
|
|
48
|
+
private attemptReconnect;
|
|
49
|
+
/**
|
|
50
|
+
* Log to stderr (stdout is reserved for MCP protocol).
|
|
51
|
+
*/
|
|
52
|
+
private log;
|
|
53
|
+
/**
|
|
54
|
+
* Sets up the state change handler for a client.
|
|
55
|
+
* Handles disconnection by triggering auto-reconnect.
|
|
56
|
+
*/
|
|
57
|
+
private setupStateChangeHandler;
|
|
58
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createTransportClientFactory } from '../transport/transport-client-factory.js';
|
|
4
|
+
import { registerBrvCurateTool, registerBrvQueryTool } from './tools/index.js';
|
|
5
|
+
/** Reconnection configuration */
|
|
6
|
+
const RECONNECT_DELAY_MS = 1000;
|
|
7
|
+
const RECONNECT_MAX_DELAY_MS = 30_000;
|
|
8
|
+
const RECONNECT_BACKOFF_MULTIPLIER = 1.5;
|
|
9
|
+
/**
|
|
10
|
+
* ByteRover MCP Server.
|
|
11
|
+
*
|
|
12
|
+
* Exposes brv-query and brv-curate as MCP tools for coding agents.
|
|
13
|
+
* Connects to a running brv instance via Socket.IO transport.
|
|
14
|
+
*
|
|
15
|
+
* Architecture:
|
|
16
|
+
* - Coding agent spawns `brv mcp` process
|
|
17
|
+
* - MCP server connects to running brv instance via Socket.IO
|
|
18
|
+
* - MCP tools create tasks via transport
|
|
19
|
+
* - Tasks are executed by the existing agent process
|
|
20
|
+
*/
|
|
21
|
+
export class ByteRoverMcpServer {
|
|
22
|
+
client;
|
|
23
|
+
config;
|
|
24
|
+
currentReconnectDelay = RECONNECT_DELAY_MS;
|
|
25
|
+
isReconnecting = false;
|
|
26
|
+
reconnectTimer;
|
|
27
|
+
server;
|
|
28
|
+
transport;
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this.config = config;
|
|
31
|
+
this.server = new McpServer({
|
|
32
|
+
name: 'byterover',
|
|
33
|
+
version: config.version,
|
|
34
|
+
});
|
|
35
|
+
// Register tools with lazy client getter
|
|
36
|
+
// Client will be set when start() is called
|
|
37
|
+
registerBrvQueryTool(this.server, () => this.client, () => this.config.workingDirectory);
|
|
38
|
+
registerBrvCurateTool(this.server, () => this.client, () => this.config.workingDirectory);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Starts the MCP server.
|
|
42
|
+
*
|
|
43
|
+
* 1. Connects to running brv instance via Socket.IO
|
|
44
|
+
* 2. Starts MCP server with stdio transport
|
|
45
|
+
*
|
|
46
|
+
* @throws NoInstanceRunningError - No brv instance is running
|
|
47
|
+
* @throws ConnectionFailedError - Failed to connect to brv instance
|
|
48
|
+
*/
|
|
49
|
+
async start() {
|
|
50
|
+
this.log('Starting MCP server...');
|
|
51
|
+
this.log(`Working directory: ${this.config.workingDirectory}`);
|
|
52
|
+
// Connect to running brv instance
|
|
53
|
+
const factory = createTransportClientFactory();
|
|
54
|
+
this.log('Connecting to brv instance...');
|
|
55
|
+
let connectionResult;
|
|
56
|
+
try {
|
|
57
|
+
connectionResult = await factory.connect(this.config.workingDirectory);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
this.log(`Connection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
const { client, projectRoot } = connectionResult;
|
|
64
|
+
this.client = client;
|
|
65
|
+
this.log(`Connected to brv instance at ${projectRoot}`);
|
|
66
|
+
this.log(`Client ID: ${client.getClientId()}`);
|
|
67
|
+
this.log(`Initial connection state: ${client.getState()}`);
|
|
68
|
+
// Monitor connection state changes and handle reconnection
|
|
69
|
+
this.setupStateChangeHandler(client);
|
|
70
|
+
// Start MCP server with stdio transport
|
|
71
|
+
this.transport = new StdioServerTransport();
|
|
72
|
+
await this.server.connect(this.transport);
|
|
73
|
+
this.log('MCP server started and ready for tool calls');
|
|
74
|
+
// Log client state periodically to debug connection issues
|
|
75
|
+
setInterval(() => {
|
|
76
|
+
if (this.client) {
|
|
77
|
+
this.log(`[heartbeat] Client state: ${this.client.getState()}, ID: ${this.client.getClientId()}`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.log('[heartbeat] Client is undefined!');
|
|
81
|
+
}
|
|
82
|
+
}, 10_000);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Stops the MCP server.
|
|
86
|
+
*
|
|
87
|
+
* Disconnects from the brv instance.
|
|
88
|
+
*/
|
|
89
|
+
async stop() {
|
|
90
|
+
// Clear any pending reconnection timer
|
|
91
|
+
if (this.reconnectTimer) {
|
|
92
|
+
clearTimeout(this.reconnectTimer);
|
|
93
|
+
this.reconnectTimer = undefined;
|
|
94
|
+
}
|
|
95
|
+
this.isReconnecting = false;
|
|
96
|
+
if (this.client) {
|
|
97
|
+
await this.client.disconnect();
|
|
98
|
+
this.client = undefined;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Attempts to reconnect to the brv instance.
|
|
103
|
+
* Uses exponential backoff for retry delays.
|
|
104
|
+
*/
|
|
105
|
+
async attemptReconnect() {
|
|
106
|
+
if (this.isReconnecting) {
|
|
107
|
+
this.log('Reconnection already in progress, skipping...');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.isReconnecting = true;
|
|
111
|
+
this.log(`Attempting to reconnect in ${this.currentReconnectDelay}ms...`);
|
|
112
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
113
|
+
try {
|
|
114
|
+
const factory = createTransportClientFactory();
|
|
115
|
+
const result = await factory.connect(this.config.workingDirectory);
|
|
116
|
+
// Disconnect old client if it exists
|
|
117
|
+
if (this.client) {
|
|
118
|
+
try {
|
|
119
|
+
await this.client.disconnect();
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Ignore disconnect errors on old client
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
this.client = result.client;
|
|
126
|
+
this.log(`Reconnected successfully! Client ID: ${result.client.getClientId()}`);
|
|
127
|
+
// Reset backoff delay on successful connection
|
|
128
|
+
this.currentReconnectDelay = RECONNECT_DELAY_MS;
|
|
129
|
+
this.isReconnecting = false;
|
|
130
|
+
// Set up state change handler for the new client
|
|
131
|
+
this.setupStateChangeHandler(result.client);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
this.log(`Reconnection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
135
|
+
// Increase delay with exponential backoff (capped at max)
|
|
136
|
+
this.currentReconnectDelay = Math.min(this.currentReconnectDelay * RECONNECT_BACKOFF_MULTIPLIER, RECONNECT_MAX_DELAY_MS);
|
|
137
|
+
this.isReconnecting = false;
|
|
138
|
+
// Schedule next reconnection attempt
|
|
139
|
+
this.attemptReconnect();
|
|
140
|
+
}
|
|
141
|
+
}, this.currentReconnectDelay);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Log to stderr (stdout is reserved for MCP protocol).
|
|
145
|
+
*/
|
|
146
|
+
log(msg) {
|
|
147
|
+
process.stderr.write(`[brv-mcp] ${msg}\n`);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Sets up the state change handler for a client.
|
|
151
|
+
* Handles disconnection by triggering auto-reconnect.
|
|
152
|
+
*/
|
|
153
|
+
setupStateChangeHandler(client) {
|
|
154
|
+
client.onStateChange((state) => {
|
|
155
|
+
const timestamp = new Date().toISOString();
|
|
156
|
+
this.log(`[${timestamp}] Connection state changed: ${state}`);
|
|
157
|
+
switch (state) {
|
|
158
|
+
case 'connected': {
|
|
159
|
+
this.log(`[${timestamp}] Connected to brv instance.`);
|
|
160
|
+
// Reset backoff delay on successful connection
|
|
161
|
+
this.currentReconnectDelay = RECONNECT_DELAY_MS;
|
|
162
|
+
this.isReconnecting = false;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case 'disconnected': {
|
|
166
|
+
this.log(`[${timestamp}] Socket disconnected from brv instance. Initiating reconnection...`);
|
|
167
|
+
// Trigger auto-reconnect
|
|
168
|
+
this.attemptReconnect();
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case 'reconnecting': {
|
|
172
|
+
this.log(`[${timestamp}] Socket.IO attempting to reconnect...`);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|