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
|
@@ -5,34 +5,30 @@ import { ACE_DIR, BRV_CONFIG_VERSION, BRV_DIR, DEFAULT_BRANCH, PROJECT_CONFIG_FI
|
|
|
5
5
|
import { AGENT_VALUES } from '../../core/domain/entities/agent.js';
|
|
6
6
|
import { BrvConfig } from '../../core/domain/entities/brv-config.js';
|
|
7
7
|
import { BrvConfigVersionError } from '../../core/domain/errors/brv-config-version-error.js';
|
|
8
|
-
import { AGENT_RULE_CONFIGS } from '../rule/agent-rule-config.js';
|
|
9
|
-
import { BRV_RULE_MARKERS, BRV_RULE_TAG } from '../rule/constants.js';
|
|
10
8
|
import { WorkspaceDetectorService } from '../workspace/workspace-detector-service.js';
|
|
11
9
|
export class InitUseCase {
|
|
12
10
|
cogitPullService;
|
|
11
|
+
connectorManager;
|
|
13
12
|
contextTreeService;
|
|
14
13
|
contextTreeSnapshotService;
|
|
15
14
|
contextTreeWriterService;
|
|
16
15
|
fileService;
|
|
17
|
-
legacyRuleDetector;
|
|
18
16
|
projectConfigStore;
|
|
19
17
|
spaceService;
|
|
20
18
|
teamService;
|
|
21
|
-
templateService;
|
|
22
19
|
terminal;
|
|
23
20
|
tokenStore;
|
|
24
21
|
trackingService;
|
|
25
22
|
constructor(options) {
|
|
26
23
|
this.cogitPullService = options.cogitPullService;
|
|
24
|
+
this.connectorManager = options.connectorManager;
|
|
27
25
|
this.contextTreeService = options.contextTreeService;
|
|
28
26
|
this.contextTreeSnapshotService = options.contextTreeSnapshotService;
|
|
29
27
|
this.contextTreeWriterService = options.contextTreeWriterService;
|
|
30
28
|
this.fileService = options.fileService;
|
|
31
|
-
this.legacyRuleDetector = options.legacyRuleDetector;
|
|
32
29
|
this.projectConfigStore = options.projectConfigStore;
|
|
33
30
|
this.spaceService = options.spaceService;
|
|
34
31
|
this.teamService = options.teamService;
|
|
35
|
-
this.templateService = options.templateService;
|
|
36
32
|
this.terminal = options.terminal;
|
|
37
33
|
this.tokenStore = options.tokenStore;
|
|
38
34
|
this.trackingService = options.trackingService;
|
|
@@ -126,78 +122,6 @@ export class InitUseCase {
|
|
|
126
122
|
this.terminal.log();
|
|
127
123
|
return this.promptForTeamSelection(teams);
|
|
128
124
|
}
|
|
129
|
-
async generateRulesForAgent(selectedAgent) {
|
|
130
|
-
this.terminal.log(`Generating rules for: ${selectedAgent}`);
|
|
131
|
-
// try {
|
|
132
|
-
// await ruleWriterService.writeRule(agent, false)
|
|
133
|
-
// this.log(`✅ Successfully generated rule file for ${agent}`)
|
|
134
|
-
// } catch (error) {
|
|
135
|
-
// if (error instanceof RuleExistsError) {
|
|
136
|
-
// const overwrite = await this.promptForOverwriteConfirmation(agent)
|
|
137
|
-
// if (overwrite) {
|
|
138
|
-
// await ruleWriterService.writeRule(agent, true)
|
|
139
|
-
// this.log(`✅ Successfully generated rule file for ${agent}`)
|
|
140
|
-
// } else {
|
|
141
|
-
// this.log(`Skipping rule file generation for ${agent}`)
|
|
142
|
-
// }
|
|
143
|
-
// } else {
|
|
144
|
-
// throw error
|
|
145
|
-
// }
|
|
146
|
-
// }
|
|
147
|
-
const { filePath, writeMode } = AGENT_RULE_CONFIGS[selectedAgent];
|
|
148
|
-
// STEP 1: Check if file exists
|
|
149
|
-
const fileExists = await this.fileService.exists(filePath);
|
|
150
|
-
if (!fileExists) {
|
|
151
|
-
// Scenario A: File doesn't exist
|
|
152
|
-
const shouldCreate = await this.promptForFileCreation(selectedAgent, filePath);
|
|
153
|
-
if (!shouldCreate) {
|
|
154
|
-
this.terminal.log(`Skipped rule file creation for ${selectedAgent}`);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
await this.createNewRuleFile({
|
|
158
|
-
agent: selectedAgent,
|
|
159
|
-
filePath,
|
|
160
|
-
});
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
// STEP 2: File exists - read content
|
|
164
|
-
const content = await this.fileService.read(filePath);
|
|
165
|
-
// STEP 3: Check for LEGACY rules (priority: clean these up first)
|
|
166
|
-
const hasFooterTag = content.includes(`${BRV_RULE_TAG} ${selectedAgent}`);
|
|
167
|
-
const hasBoundaryMarkers = content.includes(BRV_RULE_MARKERS.START) && content.includes(BRV_RULE_MARKERS.END);
|
|
168
|
-
const hasLegacyRules = hasFooterTag && !hasBoundaryMarkers;
|
|
169
|
-
if (hasLegacyRules) {
|
|
170
|
-
// Scenario B: Legacy rules detected - handle cleanup
|
|
171
|
-
await this.handleLegacyRulesCleanup({
|
|
172
|
-
agent: selectedAgent,
|
|
173
|
-
content,
|
|
174
|
-
filePath,
|
|
175
|
-
});
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
// STEP 4: Check for NEW rules (boundary markers)
|
|
179
|
-
if (hasBoundaryMarkers) {
|
|
180
|
-
// Scenario C: New rules exist - prompt for overwrite
|
|
181
|
-
const shouldOverwrite = await this.promptForOverwriteConfirmation(selectedAgent);
|
|
182
|
-
if (!shouldOverwrite) {
|
|
183
|
-
this.terminal.log(`Skipped rule file update for ${selectedAgent}`);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
await this.replaceExistingRules({
|
|
187
|
-
agent: selectedAgent,
|
|
188
|
-
content,
|
|
189
|
-
filePath,
|
|
190
|
-
writeMode,
|
|
191
|
-
});
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
// STEP 5: No ByteRover content - append rules
|
|
195
|
-
await this.appendRulesToFile({
|
|
196
|
-
agent: selectedAgent,
|
|
197
|
-
filePath,
|
|
198
|
-
writeMode,
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
125
|
async getExistingConfig() {
|
|
202
126
|
const exists = await this.projectConfigStore.exists();
|
|
203
127
|
if (!exists)
|
|
@@ -239,6 +163,30 @@ export class InitUseCase {
|
|
|
239
163
|
this.terminal.warn(`${name} initialization skipped: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
240
164
|
}
|
|
241
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Installs the default connector for the selected agent.
|
|
168
|
+
* Uses ConnectorManager to handle the installation.
|
|
169
|
+
*/
|
|
170
|
+
async installConnectorForAgent(selectedAgent) {
|
|
171
|
+
const defaultType = this.connectorManager.getDefaultConnectorType(selectedAgent);
|
|
172
|
+
const result = await this.connectorManager.installDefault(selectedAgent);
|
|
173
|
+
if (result.success) {
|
|
174
|
+
if (result.alreadyInstalled) {
|
|
175
|
+
this.terminal.log(`${selectedAgent} is already connected via ${defaultType}`);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
this.terminal.log(`${selectedAgent} connected via ${defaultType}`);
|
|
179
|
+
this.terminal.log(` Installed: ${result.configPath}`);
|
|
180
|
+
// Show restart message for hook connector
|
|
181
|
+
if (defaultType === 'hook' || defaultType === 'mcp') {
|
|
182
|
+
this.terminal.warn(`\n⚠️ Please restart ${selectedAgent} to apply the new ${defaultType}.`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
this.terminal.error(`Failed to install connector for ${selectedAgent}: ${result.message}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
242
190
|
isLegacyProjectConfig(config) {
|
|
243
191
|
return 'type' in config && config.type === 'legacy';
|
|
244
192
|
}
|
|
@@ -282,51 +230,6 @@ export class InitUseCase {
|
|
|
282
230
|
},
|
|
283
231
|
});
|
|
284
232
|
}
|
|
285
|
-
/**
|
|
286
|
-
* Prompts the user to choose cleanup strategy for legacy rules.
|
|
287
|
-
* This method is protected to allow test overrides.
|
|
288
|
-
* @returns The chosen cleanup strategy
|
|
289
|
-
*/
|
|
290
|
-
async promptForCleanupStrategy() {
|
|
291
|
-
return this.terminal.select({
|
|
292
|
-
choices: [
|
|
293
|
-
{
|
|
294
|
-
description: 'New rules will be added with boundary markers. You manually remove old sections at your convenience.',
|
|
295
|
-
name: 'Manual cleanup (recommended)',
|
|
296
|
-
value: 'manual',
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
description: '⚠️ We will remove all detected old sections. May cause content loss if detection is imperfect. A backup will be created.',
|
|
300
|
-
name: 'Automatic cleanup',
|
|
301
|
-
value: 'automatic',
|
|
302
|
-
},
|
|
303
|
-
],
|
|
304
|
-
message: 'How would you like to proceed?',
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Prompts the user to create a new rule file.
|
|
309
|
-
* This method is protected to allow test overrides.
|
|
310
|
-
* @param agent The agent for which the rule file doesn't exist
|
|
311
|
-
* @param filePath The path where the file would be created
|
|
312
|
-
* @returns True if the user wants to create the file, false otherwise
|
|
313
|
-
*/
|
|
314
|
-
async promptForFileCreation(agent, filePath) {
|
|
315
|
-
return this.terminal.confirm({
|
|
316
|
-
default: true,
|
|
317
|
-
message: `Rule file '${filePath}' doesn't exist. Create it with ByteRover rules`,
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Prompts the user to confirm overwriting an existing rule file.
|
|
322
|
-
* This method is protected to allow test overrides.
|
|
323
|
-
*/
|
|
324
|
-
async promptForOverwriteConfirmation(agent) {
|
|
325
|
-
return this.terminal.confirm({
|
|
326
|
-
default: true,
|
|
327
|
-
message: `Rule file already exists for ${agent}. Overwrite`,
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
233
|
async promptForSpaceSelection(spaces) {
|
|
331
234
|
const selectedSpaceId = await this.terminal.select({
|
|
332
235
|
choices: spaces.map((space) => ({
|
|
@@ -403,7 +306,6 @@ export class InitUseCase {
|
|
|
403
306
|
});
|
|
404
307
|
this.terminal.log();
|
|
405
308
|
const selectedAgent = await this.promptForAgentSelection();
|
|
406
|
-
this.terminal.log('Detecting workspaces...');
|
|
407
309
|
const { chatLogPath, cwd } = this.detectWorkspacesForAgent(selectedAgent);
|
|
408
310
|
this.terminal.log(`✓ Detected workspace: ${cwd}`);
|
|
409
311
|
const config = BrvConfig.fromSpace({
|
|
@@ -413,10 +315,8 @@ export class InitUseCase {
|
|
|
413
315
|
space: selectedSpace,
|
|
414
316
|
});
|
|
415
317
|
await this.projectConfigStore.write(config);
|
|
416
|
-
this.terminal.log(`\nGenerate rule instructions for coding agents to work with ByteRover correctly`);
|
|
417
318
|
this.terminal.log();
|
|
418
|
-
await this.
|
|
419
|
-
await this.trackingService.track('rule:generate');
|
|
319
|
+
await this.installConnectorForAgent(selectedAgent);
|
|
420
320
|
await this.trackingService.track('space:init');
|
|
421
321
|
this.logSuccess(selectedSpace);
|
|
422
322
|
await this.trackingService.track('init', { status: 'finished' });
|
|
@@ -451,7 +351,6 @@ export class InitUseCase {
|
|
|
451
351
|
this.terminal.log('✓ Context tree initialized');
|
|
452
352
|
}
|
|
453
353
|
else {
|
|
454
|
-
// Remote has real data - sync it to local
|
|
455
354
|
await this.contextTreeWriterService.sync({ files: [...coGitSnapshot.files] });
|
|
456
355
|
await this.contextTreeSnapshotService.saveSnapshot();
|
|
457
356
|
this.terminal.log(`✓ Synced ${coGitSnapshot.files.length} context files from remote`);
|
|
@@ -464,134 +363,10 @@ export class InitUseCase {
|
|
|
464
363
|
}
|
|
465
364
|
this.terminal.actionStop();
|
|
466
365
|
}
|
|
467
|
-
/**
|
|
468
|
-
* Appends ByteRover rules to a file that has no ByteRover content.
|
|
469
|
-
*/
|
|
470
|
-
async appendRulesToFile(params) {
|
|
471
|
-
const { agent, filePath, writeMode } = params;
|
|
472
|
-
const ruleContent = await this.templateService.generateRuleContent(agent);
|
|
473
|
-
// For dedicated ByteRover files, overwrite; for shared instruction files, append
|
|
474
|
-
const mode = writeMode === 'overwrite' ? 'overwrite' : 'append';
|
|
475
|
-
await this.fileService.write(ruleContent, filePath, mode);
|
|
476
|
-
this.terminal.log(`✅ Successfully added rule file for ${agent}`);
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Creates a new rule file with ByteRover rules.
|
|
480
|
-
*/
|
|
481
|
-
async createNewRuleFile(params) {
|
|
482
|
-
const { agent, filePath } = params;
|
|
483
|
-
const ruleContent = await this.templateService.generateRuleContent(agent);
|
|
484
|
-
await this.fileService.write(ruleContent, filePath, 'overwrite');
|
|
485
|
-
this.terminal.log(`✅ Successfully created rule file for ${agent} at ${filePath}`);
|
|
486
|
-
}
|
|
487
|
-
async handleLegacyRulesCleanup(params) {
|
|
488
|
-
const { agent, content, filePath } = params;
|
|
489
|
-
const detectionResult = this.legacyRuleDetector.detectLegacyRules(content, agent);
|
|
490
|
-
const { reliableMatches, uncertainMatches } = detectionResult;
|
|
491
|
-
this.terminal.log(`\n⚠️ Detected ${reliableMatches.length + uncertainMatches.length} old ByteRover rule section(s) in ${filePath}:\n`);
|
|
492
|
-
if (reliableMatches.length > 0) {
|
|
493
|
-
this.terminal.log('Reliable matches:');
|
|
494
|
-
for (const [index, match] of reliableMatches.entries()) {
|
|
495
|
-
this.terminal.log(` Section ${index + 1}: lines ${match.startLine}-${match.endLine}`);
|
|
496
|
-
}
|
|
497
|
-
this.terminal.log();
|
|
498
|
-
}
|
|
499
|
-
if (uncertainMatches.length > 0) {
|
|
500
|
-
this.terminal.log(' ⚠️ Uncertain matches (cannot determine start):');
|
|
501
|
-
for (const match of uncertainMatches) {
|
|
502
|
-
this.terminal.log(` Footer found at line ${match.footerLine}`);
|
|
503
|
-
this.terminal.log(` Reason: ${match.reason}`);
|
|
504
|
-
}
|
|
505
|
-
this.terminal.log();
|
|
506
|
-
this.terminal.log('⚠️ Due to uncertain matches, only manual cleanup is available.\n');
|
|
507
|
-
await this.performManualCleanup({
|
|
508
|
-
agent,
|
|
509
|
-
filePath,
|
|
510
|
-
reliableMatches,
|
|
511
|
-
uncertainMatches,
|
|
512
|
-
});
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
const selectedStrategy = await this.promptForCleanupStrategy();
|
|
516
|
-
await (selectedStrategy === 'manual'
|
|
517
|
-
? this.performManualCleanup({
|
|
518
|
-
agent,
|
|
519
|
-
filePath,
|
|
520
|
-
reliableMatches,
|
|
521
|
-
uncertainMatches,
|
|
522
|
-
})
|
|
523
|
-
: this.performAutomaticCleanup({
|
|
524
|
-
agent,
|
|
525
|
-
filePath,
|
|
526
|
-
reliableMatches,
|
|
527
|
-
}));
|
|
528
|
-
}
|
|
529
366
|
logSuccess(space) {
|
|
530
367
|
this.terminal.log(`\n✓ Project initialized successfully!`);
|
|
531
368
|
this.terminal.log(`✓ Connected to space: ${space.getDisplayName()}`);
|
|
532
369
|
this.terminal.log(`✓ Configuration saved to: ${BRV_DIR}/${PROJECT_CONFIG_FILE}`);
|
|
533
370
|
this.terminal.log("NOTE: It's recommended to add .brv/ to your .gitignore file since ByteRover already takes care of memory/context versioning for you.");
|
|
534
371
|
}
|
|
535
|
-
async performAutomaticCleanup(params) {
|
|
536
|
-
const { agent, filePath, reliableMatches } = params;
|
|
537
|
-
const backupPath = await this.fileService.createBackup(filePath);
|
|
538
|
-
this.terminal.log(`📦 Backup created: ${backupPath}`);
|
|
539
|
-
let content = await this.fileService.read(filePath);
|
|
540
|
-
// Remove all reliable matches (in reverse order to preserve line numbers)
|
|
541
|
-
const sortedMatches = [...reliableMatches].sort((a, b) => b.startLine - a.startLine);
|
|
542
|
-
for (const match of sortedMatches) {
|
|
543
|
-
content = content.replace(match.content, '');
|
|
544
|
-
}
|
|
545
|
-
// Write cleaned content
|
|
546
|
-
await this.fileService.write(content, filePath, 'overwrite');
|
|
547
|
-
// Append new rules
|
|
548
|
-
const ruleContent = await this.templateService.generateRuleContent(agent);
|
|
549
|
-
await this.fileService.write(ruleContent, filePath, 'append');
|
|
550
|
-
this.terminal.log(`✅ Removed ${reliableMatches.length} old ByteRover section(s)`);
|
|
551
|
-
this.terminal.log(`✅ Added new rules with boundary markers`);
|
|
552
|
-
this.terminal.log(`\nYou can safely delete the backup file once verified.`);
|
|
553
|
-
}
|
|
554
|
-
async performManualCleanup(params) {
|
|
555
|
-
const { agent, filePath, reliableMatches, uncertainMatches } = params;
|
|
556
|
-
const ruleContent = await this.templateService.generateRuleContent(agent);
|
|
557
|
-
await this.fileService.write(ruleContent, filePath, 'append');
|
|
558
|
-
this.terminal.log(`✅ New ByteRover rules added with boundary markers\n`);
|
|
559
|
-
this.terminal.log('Please manually remove old sections:');
|
|
560
|
-
for (const [index, match] of reliableMatches.entries()) {
|
|
561
|
-
this.terminal.log(` - Section ${index + 1}: lines ${match.startLine}-${match.endLine} in ${filePath}`);
|
|
562
|
-
}
|
|
563
|
-
for (const match of uncertainMatches) {
|
|
564
|
-
this.terminal.log(` - Section ending at line ${match.footerLine} in ${filePath}`);
|
|
565
|
-
}
|
|
566
|
-
this.terminal.log('\nKeep only the section between:');
|
|
567
|
-
this.terminal.log(' <!-- BEGIN BYTEROVER RULES -->');
|
|
568
|
-
this.terminal.log(' <!-- END BYTEROVER RULES -->');
|
|
569
|
-
}
|
|
570
|
-
/**
|
|
571
|
-
* Replaces existing ByteRover rules (with boundary markers) with new rules.
|
|
572
|
-
*/
|
|
573
|
-
async replaceExistingRules(params) {
|
|
574
|
-
const { agent, content, filePath, writeMode } = params;
|
|
575
|
-
const ruleContent = await this.templateService.generateRuleContent(agent);
|
|
576
|
-
if (writeMode === 'overwrite') {
|
|
577
|
-
// For dedicated ByteRover files, just overwrite the entire file
|
|
578
|
-
await this.fileService.write(ruleContent, filePath, 'overwrite');
|
|
579
|
-
}
|
|
580
|
-
else {
|
|
581
|
-
// For shared instruction files, replace the section between markers
|
|
582
|
-
const startMarker = BRV_RULE_MARKERS.START;
|
|
583
|
-
const endMarker = BRV_RULE_MARKERS.END;
|
|
584
|
-
const startIndex = content.indexOf(startMarker);
|
|
585
|
-
const endIndex = content.indexOf(endMarker, startIndex);
|
|
586
|
-
if (startIndex === -1 || endIndex === -1) {
|
|
587
|
-
this.terminal.log('Could not find boundary markers in the file');
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
const before = content.slice(0, startIndex);
|
|
591
|
-
const after = content.slice(endIndex + endMarker.length);
|
|
592
|
-
const newContent = before + ruleContent + after;
|
|
593
|
-
await this.fileService.write(newContent, filePath, 'overwrite');
|
|
594
|
-
}
|
|
595
|
-
this.terminal.log(`✅ Successfully updated rule file for ${agent}`);
|
|
596
|
-
}
|
|
597
372
|
}
|
|
@@ -38,7 +38,7 @@ export class LogoutUseCase {
|
|
|
38
38
|
await this.tokenStore.clear();
|
|
39
39
|
await this.onboardingPreferenceStore.clear();
|
|
40
40
|
this.terminal.log("Successfully logged out.");
|
|
41
|
-
this.terminal.log("Run '
|
|
41
|
+
this.terminal.log("Run '/login' to authenticate again.");
|
|
42
42
|
}
|
|
43
43
|
catch (error) {
|
|
44
44
|
if (error instanceof Error && error.message.includes("keychain")) {
|
|
@@ -23,7 +23,7 @@ export class PullUseCase {
|
|
|
23
23
|
async checkProjectInit() {
|
|
24
24
|
const projectConfig = await this.projectConfigStore.read();
|
|
25
25
|
if (projectConfig === undefined) {
|
|
26
|
-
throw new WorkspaceNotInitializedError('Project not initialized. Please run "
|
|
26
|
+
throw new WorkspaceNotInitializedError('Project not initialized. Please run "/init" to select your team and workspace.', '.brv');
|
|
27
27
|
}
|
|
28
28
|
return projectConfig;
|
|
29
29
|
}
|
|
@@ -39,7 +39,7 @@ export class PullUseCase {
|
|
|
39
39
|
const hasLocalChanges = await this.checkLocalChanges();
|
|
40
40
|
this.terminal.actionStop();
|
|
41
41
|
if (hasLocalChanges) {
|
|
42
|
-
this.terminal.log('You have local changes that have not been pushed. Run "
|
|
42
|
+
this.terminal.log('You have local changes that have not been pushed. Run "/push" first.');
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
// Pull from CoGit
|
|
@@ -67,7 +67,7 @@ export class PullUseCase {
|
|
|
67
67
|
// Stop action if it's in progress
|
|
68
68
|
this.terminal.actionStop();
|
|
69
69
|
if (error instanceof WorkspaceNotInitializedError) {
|
|
70
|
-
this.terminal.log('Project not initialized. Please run "
|
|
70
|
+
this.terminal.log('Project not initialized. Please run "/init" to select your team and workspace.');
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
const message = error instanceof Error ? error.message : 'Pull failed';
|
|
@@ -77,11 +77,11 @@ export class PullUseCase {
|
|
|
77
77
|
async validateAuth() {
|
|
78
78
|
const token = await this.tokenStore.load();
|
|
79
79
|
if (token === undefined) {
|
|
80
|
-
this.terminal.error('Not authenticated. Run "
|
|
80
|
+
this.terminal.error('Not authenticated. Run "/login" first.');
|
|
81
81
|
return undefined;
|
|
82
82
|
}
|
|
83
83
|
if (!token.isValid()) {
|
|
84
|
-
this.terminal.error('Authentication token expired. Run "
|
|
84
|
+
this.terminal.error('Authentication token expired. Run "/login" again.');
|
|
85
85
|
return undefined;
|
|
86
86
|
}
|
|
87
87
|
return token;
|
|
@@ -82,7 +82,7 @@ export class PushUseCase {
|
|
|
82
82
|
// Stop action if it's in progress
|
|
83
83
|
this.terminal.actionStop();
|
|
84
84
|
if (error instanceof WorkspaceNotInitializedError) {
|
|
85
|
-
this.terminal.log('Project not initialized. Please run "
|
|
85
|
+
this.terminal.log('Project not initialized. Please run "/init" to select your team and workspace.');
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
// For other errors, to properly display error before exit
|
|
@@ -96,7 +96,7 @@ export class PushUseCase {
|
|
|
96
96
|
async checkProjectInit() {
|
|
97
97
|
const projectConfig = await this.projectConfigStore.read();
|
|
98
98
|
if (projectConfig === undefined) {
|
|
99
|
-
throw new WorkspaceNotInitializedError('Project not initialized. Please run "
|
|
99
|
+
throw new WorkspaceNotInitializedError('Project not initialized. Please run "/init" to select your team and workspace.', '.brv');
|
|
100
100
|
}
|
|
101
101
|
return projectConfig;
|
|
102
102
|
}
|
|
@@ -112,11 +112,11 @@ export class PushUseCase {
|
|
|
112
112
|
async validateAuth() {
|
|
113
113
|
const token = await this.tokenStore.load();
|
|
114
114
|
if (token === undefined) {
|
|
115
|
-
this.terminal.error('Not authenticated. Run "
|
|
115
|
+
this.terminal.error('Not authenticated. Run "/login" first.');
|
|
116
116
|
return undefined;
|
|
117
117
|
}
|
|
118
118
|
if (!token.isValid()) {
|
|
119
|
-
this.terminal.error('Authentication token expired. Run "
|
|
119
|
+
this.terminal.error('Authentication token expired. Run "/login" again.');
|
|
120
120
|
return undefined;
|
|
121
121
|
}
|
|
122
122
|
return token;
|
|
@@ -14,7 +14,7 @@ export class ResetUseCase {
|
|
|
14
14
|
async confirmReset() {
|
|
15
15
|
return this.terminal.confirm({
|
|
16
16
|
default: false,
|
|
17
|
-
message: 'Are you sure you want to reset the context tree? This will remove all existing context
|
|
17
|
+
message: 'Are you sure you want to reset the context tree? This will remove all existing context. Your context tree will be empty.',
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
async run(options) {
|
|
@@ -37,12 +37,11 @@ export class ResetUseCase {
|
|
|
37
37
|
const baseDir = options.directory ?? process.cwd();
|
|
38
38
|
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
39
39
|
await rm(contextTreeDir, { force: true, recursive: true });
|
|
40
|
-
// Re-initialize context tree
|
|
40
|
+
// Re-initialize empty context tree
|
|
41
41
|
await this.contextTreeService.initialize(options.directory);
|
|
42
42
|
// Re-initialize empty snapshot
|
|
43
43
|
await this.contextTreeSnapshotService.initEmptySnapshot(options.directory);
|
|
44
|
-
this.terminal.log('✓ Context tree reset successfully.');
|
|
45
|
-
this.terminal.log(' 6 default domains restored: code_style, design, structure, compliance, testing, bug_fixes');
|
|
44
|
+
this.terminal.log('✓ Context tree reset successfully. Your context tree is now empty.');
|
|
46
45
|
}
|
|
47
46
|
catch (error) {
|
|
48
47
|
// Handle user cancelling the prompt (Ctrl+C or closing stdin)
|
|
@@ -15,16 +15,16 @@ export class SpaceListUseCase {
|
|
|
15
15
|
// Check project initialization
|
|
16
16
|
const projectConfig = await this.projectConfigStore.read();
|
|
17
17
|
if (!projectConfig) {
|
|
18
|
-
this.terminal.error('Project not initialized. Please run "
|
|
18
|
+
this.terminal.error('Project not initialized. Please run "/init" first.');
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
const token = await this.tokenStore.load();
|
|
22
22
|
if (!token) {
|
|
23
|
-
this.terminal.error('Not authenticated. Please run "
|
|
23
|
+
this.terminal.error('Not authenticated. Please run "/login" first.');
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
26
|
if (!token.isValid()) {
|
|
27
|
-
this.terminal.error('Authentication token expired. Please run "
|
|
27
|
+
this.terminal.error('Authentication token expired. Please run "/login" again.');
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
// Fetch spaces for the team from project config
|
|
@@ -74,7 +74,7 @@ export class SpaceSwitchUseCase {
|
|
|
74
74
|
// Check project initialization (MUST exist for switch)
|
|
75
75
|
const currentConfig = await this.projectConfigStore.read();
|
|
76
76
|
if (!currentConfig) {
|
|
77
|
-
this.terminal.log('Project not initialized. Please run "
|
|
77
|
+
this.terminal.log('Project not initialized. Please run "/init" first.');
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
// Show current configuration
|
|
@@ -85,11 +85,11 @@ export class SpaceSwitchUseCase {
|
|
|
85
85
|
// Validate authentication
|
|
86
86
|
const token = await this.tokenStore.load();
|
|
87
87
|
if (!token) {
|
|
88
|
-
this.terminal.log('Not authenticated. Please run "
|
|
88
|
+
this.terminal.log('Not authenticated. Please run "/login" first.');
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
if (!token.isValid()) {
|
|
92
|
-
this.terminal.log('Authentication token expired. Please run "
|
|
92
|
+
this.terminal.log('Authentication token expired. Please run "/login" again.');
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
95
|
// Fetch all teams
|
|
@@ -4,10 +4,12 @@ import type { IProjectConfigStore } from '../../core/interfaces/i-project-config
|
|
|
4
4
|
import type { ITerminal } from '../../core/interfaces/i-terminal.js';
|
|
5
5
|
import type { ITokenStore } from '../../core/interfaces/i-token-store.js';
|
|
6
6
|
import type { ITrackingService } from '../../core/interfaces/i-tracking-service.js';
|
|
7
|
+
import type { IInstanceDiscovery } from '../../core/interfaces/instance/i-instance-discovery.js';
|
|
7
8
|
import type { IStatusUseCase } from '../../core/interfaces/usecase/i-status-use-case.js';
|
|
8
9
|
export interface StatusUseCaseOptions {
|
|
9
10
|
contextTreeService: IContextTreeService;
|
|
10
11
|
contextTreeSnapshotService: IContextTreeSnapshotService;
|
|
12
|
+
instanceDiscovery?: IInstanceDiscovery;
|
|
11
13
|
projectConfigStore: IProjectConfigStore;
|
|
12
14
|
terminal: ITerminal;
|
|
13
15
|
tokenStore: ITokenStore;
|
|
@@ -16,6 +18,7 @@ export interface StatusUseCaseOptions {
|
|
|
16
18
|
export declare class StatusUseCase implements IStatusUseCase {
|
|
17
19
|
private readonly contextTreeService;
|
|
18
20
|
private readonly contextTreeSnapshotService;
|
|
21
|
+
private readonly instanceDiscovery;
|
|
19
22
|
private readonly projectConfigStore;
|
|
20
23
|
private readonly terminal;
|
|
21
24
|
private readonly tokenStore;
|
|
@@ -24,4 +27,11 @@ export declare class StatusUseCase implements IStatusUseCase {
|
|
|
24
27
|
run(options: {
|
|
25
28
|
cliVersion: string;
|
|
26
29
|
}): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Checks the MCP connection status by:
|
|
32
|
+
* 1. Discovering running brv instance
|
|
33
|
+
* 2. Connecting to it via Socket.IO
|
|
34
|
+
* 3. Verifying bidirectional communication with ping
|
|
35
|
+
*/
|
|
36
|
+
private checkMcpStatus;
|
|
27
37
|
}
|
|
@@ -2,9 +2,12 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { BRV_DIR, CONTEXT_TREE_DIR } from '../../constants.js';
|
|
4
4
|
import { getErrorMessage } from '../../utils/error-helpers.js';
|
|
5
|
+
import { FileInstanceDiscovery } from '../instance/file-instance-discovery.js';
|
|
6
|
+
import { SocketIOTransportClient } from '../transport/socket-io-transport-client.js';
|
|
5
7
|
export class StatusUseCase {
|
|
6
8
|
contextTreeService;
|
|
7
9
|
contextTreeSnapshotService;
|
|
10
|
+
instanceDiscovery;
|
|
8
11
|
projectConfigStore;
|
|
9
12
|
terminal;
|
|
10
13
|
tokenStore;
|
|
@@ -12,6 +15,7 @@ export class StatusUseCase {
|
|
|
12
15
|
constructor(options) {
|
|
13
16
|
this.contextTreeService = options.contextTreeService;
|
|
14
17
|
this.contextTreeSnapshotService = options.contextTreeSnapshotService;
|
|
18
|
+
this.instanceDiscovery = options.instanceDiscovery ?? new FileInstanceDiscovery();
|
|
15
19
|
this.projectConfigStore = options.projectConfigStore;
|
|
16
20
|
this.terminal = options.terminal;
|
|
17
21
|
this.tokenStore = options.tokenStore;
|
|
@@ -56,6 +60,8 @@ export class StatusUseCase {
|
|
|
56
60
|
this.terminal.log('Project Status: Unable to read project configuration');
|
|
57
61
|
this.terminal.warn(`Warning: ${getErrorMessage(error)}`);
|
|
58
62
|
}
|
|
63
|
+
// MCP connection status
|
|
64
|
+
await this.checkMcpStatus();
|
|
59
65
|
// Context tree status
|
|
60
66
|
try {
|
|
61
67
|
const contextTreeExists = await this.contextTreeService.exists();
|
|
@@ -94,4 +100,51 @@ export class StatusUseCase {
|
|
|
94
100
|
this.terminal.warn(`Warning: ${error instanceof Error ? error.message : 'Context Tree unable to check status'}`);
|
|
95
101
|
}
|
|
96
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Checks the MCP connection status by:
|
|
105
|
+
* 1. Discovering running brv instance
|
|
106
|
+
* 2. Connecting to it via Socket.IO
|
|
107
|
+
* 3. Verifying bidirectional communication with ping
|
|
108
|
+
*/
|
|
109
|
+
async checkMcpStatus() {
|
|
110
|
+
try {
|
|
111
|
+
// Step 1: Discover running instance
|
|
112
|
+
const discoveryResult = await this.instanceDiscovery.discover(process.cwd());
|
|
113
|
+
if (!discoveryResult.found) {
|
|
114
|
+
if (discoveryResult.reason === 'instance_crashed') {
|
|
115
|
+
this.terminal.log(`MCP Status: ${chalk.red('Instance crashed')} (stale instance file found)`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
this.terminal.log(`MCP Status: ${chalk.yellow('No instance running')}`);
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const { instance, projectRoot } = discoveryResult;
|
|
123
|
+
this.terminal.log(`MCP Status: Instance found (PID: ${instance.pid}, Port: ${instance.port})`);
|
|
124
|
+
// Step 2: Connect to instance
|
|
125
|
+
const client = new SocketIOTransportClient();
|
|
126
|
+
const url = instance.getTransportUrl();
|
|
127
|
+
try {
|
|
128
|
+
await client.connect(url);
|
|
129
|
+
}
|
|
130
|
+
catch (connectError) {
|
|
131
|
+
this.terminal.log(`MCP Status: ${chalk.red('Connection failed')} - ${getErrorMessage(connectError)}`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Step 3: Verify bidirectional communication with ping
|
|
135
|
+
const isResponsive = await client.isConnected(2000);
|
|
136
|
+
if (isResponsive) {
|
|
137
|
+
this.terminal.log(`MCP Status: ${chalk.green('Connected and responsive')} (${projectRoot})`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
this.terminal.log(`MCP Status: ${chalk.yellow('Connected but not responsive')} (ping timeout)`);
|
|
141
|
+
}
|
|
142
|
+
// Clean up
|
|
143
|
+
await client.disconnect();
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
this.terminal.log(`MCP Status: ${chalk.red('Error checking status')}`);
|
|
147
|
+
this.terminal.warn(`Warning: ${getErrorMessage(error)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
97
150
|
}
|