byterover-cli 1.0.4 → 1.1.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 +24 -11
- package/dist/commands/curate.js +1 -1
- package/dist/commands/hook-prompt-submit.d.ts +27 -0
- package/dist/commands/hook-prompt-submit.js +39 -0
- package/dist/commands/main.d.ts +13 -0
- package/dist/commands/main.js +53 -2
- package/dist/commands/query.js +1 -1
- package/dist/commands/status.js +8 -3
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +2 -2
- package/dist/core/domain/cipher/llm/registry.js +53 -2
- package/dist/core/domain/cipher/llm/types.d.ts +2 -0
- package/dist/core/domain/cipher/process/types.d.ts +7 -0
- package/dist/core/domain/cipher/session/session-metadata.d.ts +178 -0
- package/dist/core/domain/cipher/session/session-metadata.js +147 -0
- 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 +24 -0
- package/dist/core/domain/entities/connector-type.d.ts +9 -0
- package/dist/core/domain/entities/connector-type.js +8 -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/knowledge/markdown-writer.d.ts +15 -18
- package/dist/core/domain/knowledge/markdown-writer.js +232 -34
- package/dist/core/domain/knowledge/relation-parser.d.ts +25 -39
- package/dist/core/domain/knowledge/relation-parser.js +39 -61
- package/dist/core/domain/transport/schemas.d.ts +77 -2
- package/dist/core/domain/transport/schemas.js +51 -2
- package/dist/core/interfaces/cipher/i-session-persistence.d.ts +133 -0
- package/dist/core/interfaces/cipher/i-session-persistence.js +7 -0
- package/dist/core/interfaces/cipher/message-types.d.ts +6 -0
- package/dist/core/interfaces/connectors/connector-types.d.ts +57 -0
- package/dist/core/interfaces/connectors/i-connector-manager.d.ts +72 -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/executor/i-curate-executor.d.ts +2 -2
- package/dist/core/interfaces/i-context-file-reader.d.ts +3 -0
- package/dist/core/interfaces/i-file-service.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/core/interfaces/usecase/{i-clear-use-case.d.ts → i-reset-use-case.d.ts} +1 -1
- package/dist/core/interfaces/usecase/i-reset-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/agent-schemas.d.ts +6 -6
- package/dist/infra/cipher/agent/service-initializer.js +4 -4
- 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/file-system/context-tree-file-system-factory.js +3 -2
- package/dist/infra/cipher/file-system/file-system-service.js +1 -0
- package/dist/infra/cipher/http/internal-llm-http-service.js +3 -5
- package/dist/infra/cipher/interactive-loop.js +3 -1
- package/dist/infra/cipher/llm/context/context-manager.d.ts +2 -2
- package/dist/infra/cipher/llm/context/context-manager.js +63 -18
- package/dist/infra/cipher/llm/formatters/gemini-formatter.d.ts +13 -0
- package/dist/infra/cipher/llm/formatters/gemini-formatter.js +146 -15
- package/dist/infra/cipher/llm/generators/byterover-content-generator.js +6 -2
- package/dist/infra/cipher/llm/internal-llm-service.js +2 -2
- package/dist/infra/cipher/llm/thought-parser.d.ts +21 -0
- package/dist/infra/cipher/llm/thought-parser.js +27 -0
- package/dist/infra/cipher/llm/tool-output-processor.d.ts +10 -0
- package/dist/infra/cipher/llm/tool-output-processor.js +80 -7
- package/dist/infra/cipher/process/process-service.js +11 -3
- package/dist/infra/cipher/session/chat-session.d.ts +7 -2
- package/dist/infra/cipher/session/chat-session.js +90 -52
- package/dist/infra/cipher/session/session-metadata-store.d.ts +52 -0
- package/dist/infra/cipher/session/session-metadata-store.js +406 -0
- 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.js +132 -36
- 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/implementations/task-tool.js +1 -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 +156 -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/{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 +41 -0
- package/dist/infra/connectors/rules/rules-connector.js +204 -0
- package/dist/infra/{rule/rule-template-service.d.ts → connectors/shared/template-service.d.ts} +3 -3
- package/dist/infra/{rule/rule-template-service.js → connectors/shared/template-service.js} +1 -1
- package/dist/infra/context-tree/file-context-file-reader.js +4 -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/core/task-processor.d.ts +2 -2
- package/dist/infra/file/fs-file-service.d.ts +7 -0
- package/dist/infra/file/fs-file-service.js +15 -1
- package/dist/infra/process/agent-worker.d.ts +2 -2
- package/dist/infra/process/agent-worker.js +626 -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 +89 -1
- package/dist/infra/process/process-manager.js +293 -9
- 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 +82 -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/index.js +8 -4
- package/dist/infra/repl/commands/init-command.js +11 -7
- package/dist/infra/repl/commands/new-command.d.ts +14 -0
- package/dist/infra/repl/commands/new-command.js +61 -0
- package/dist/infra/repl/commands/query-command.js +22 -2
- package/dist/infra/repl/commands/{clear-command.d.ts → reset-command.d.ts} +2 -2
- package/dist/infra/repl/commands/{clear-command.js → reset-command.js} +11 -11
- package/dist/infra/transport/socket-io-transport-client.d.ts +68 -0
- package/dist/infra/transport/socket-io-transport-client.js +283 -7
- package/dist/infra/usecase/connectors-use-case.d.ts +59 -0
- package/dist/infra/usecase/connectors-use-case.js +203 -0
- package/dist/infra/usecase/init-use-case.d.ts +8 -43
- package/dist/infra/usecase/init-use-case.js +29 -253
- package/dist/infra/usecase/logout-use-case.js +2 -2
- package/dist/infra/usecase/pull-use-case.js +5 -5
- package/dist/infra/usecase/push-use-case.js +5 -5
- package/dist/infra/usecase/{clear-use-case.d.ts → reset-use-case.d.ts} +5 -5
- package/dist/infra/usecase/{clear-use-case.js → reset-use-case.js} +7 -8
- package/dist/infra/usecase/space-list-use-case.js +3 -3
- package/dist/infra/usecase/space-switch-use-case.js +3 -3
- package/dist/resources/prompts/curate.yml +75 -13
- 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/curate.txt +60 -15
- package/dist/resources/tools/search_knowledge.txt +32 -0
- package/dist/templates/sections/brv-instructions.md +98 -0
- package/dist/tui/components/inline-prompts/inline-confirm.js +2 -2
- package/dist/tui/components/onboarding/onboarding-flow.js +14 -10
- package/dist/tui/components/onboarding/welcome-box.js +1 -1
- package/dist/tui/contexts/onboarding-context.d.ts +4 -0
- package/dist/tui/contexts/onboarding-context.js +14 -2
- package/dist/tui/views/command-view.js +19 -0
- package/dist/utils/file-validator.d.ts +1 -1
- package/dist/utils/file-validator.js +34 -35
- package/dist/utils/type-guards.d.ts +5 -0
- package/dist/utils/type-guards.js +7 -0
- package/oclif.manifest.json +32 -6
- package/package.json +4 -1
- package/dist/config/context-tree-domains.d.ts +0 -29
- package/dist/config/context-tree-domains.js +0 -29
- 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/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-clear-use-case.js → connectors/connector-types.js} +0 -0
- /package/dist/core/interfaces/{usecase/i-generate-rules-use-case.js → connectors/i-connector-manager.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;
|
|
@@ -81,7 +77,7 @@ export class InitUseCase {
|
|
|
81
77
|
this.terminal.log(' - Regenerate rule instructions\n');
|
|
82
78
|
return this.terminal.confirm({
|
|
83
79
|
default: false,
|
|
84
|
-
message: 'Continue with re-initialization
|
|
80
|
+
message: 'Continue with re-initialization',
|
|
85
81
|
});
|
|
86
82
|
}
|
|
87
83
|
detectWorkspacesForAgent(agent) {
|
|
@@ -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') {
|
|
182
|
+
this.terminal.warn(`\n⚠️ Please restart ${selectedAgent} to apply the new hooks.`);
|
|
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
|
}
|
|
@@ -259,7 +207,7 @@ export class InitUseCase {
|
|
|
259
207
|
this.terminal.log(' This folder and all its contents can be safely removed.\n');
|
|
260
208
|
return this.terminal.confirm({
|
|
261
209
|
default: true,
|
|
262
|
-
message: 'Remove the ACE folder and its contents
|
|
210
|
+
message: 'Remove the ACE folder and its contents',
|
|
263
211
|
});
|
|
264
212
|
}
|
|
265
213
|
/**
|
|
@@ -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' });
|
|
@@ -464,134 +364,10 @@ export class InitUseCase {
|
|
|
464
364
|
}
|
|
465
365
|
this.terminal.actionStop();
|
|
466
366
|
}
|
|
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
367
|
logSuccess(space) {
|
|
530
368
|
this.terminal.log(`\n✓ Project initialized successfully!`);
|
|
531
369
|
this.terminal.log(`✓ Connected to space: ${space.getDisplayName()}`);
|
|
532
370
|
this.terminal.log(`✓ Configuration saved to: ${BRV_DIR}/${PROJECT_CONFIG_FILE}`);
|
|
533
371
|
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
372
|
}
|
|
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
373
|
}
|
|
@@ -12,7 +12,7 @@ export class LogoutUseCase {
|
|
|
12
12
|
async confirmLogout(userEmail) {
|
|
13
13
|
return this.terminal.confirm({
|
|
14
14
|
default: true,
|
|
15
|
-
message: `Logging out ${userEmail}. Are you sure
|
|
15
|
+
message: `Logging out ${userEmail}. Are you sure`,
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
async run(options) {
|
|
@@ -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
|
}
|
|
@@ -106,17 +106,17 @@ export class PushUseCase {
|
|
|
106
106
|
this.terminal.log(` Branch: ${branch}`);
|
|
107
107
|
return this.terminal.confirm({
|
|
108
108
|
default: false,
|
|
109
|
-
message: 'Push to ByteRover
|
|
109
|
+
message: 'Push to ByteRover',
|
|
110
110
|
});
|
|
111
111
|
}
|
|
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;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { IContextTreeService } from '../../core/interfaces/i-context-tree-service.js';
|
|
2
2
|
import type { IContextTreeSnapshotService } from '../../core/interfaces/i-context-tree-snapshot-service.js';
|
|
3
3
|
import type { ITerminal } from '../../core/interfaces/i-terminal.js';
|
|
4
|
-
import type {
|
|
5
|
-
export interface
|
|
4
|
+
import type { IResetUseCase } from '../../core/interfaces/usecase/i-reset-use-case.js';
|
|
5
|
+
export interface ResetUseCaseOptions {
|
|
6
6
|
contextTreeService: IContextTreeService;
|
|
7
7
|
contextTreeSnapshotService: IContextTreeSnapshotService;
|
|
8
8
|
terminal: ITerminal;
|
|
9
9
|
}
|
|
10
|
-
export declare class
|
|
10
|
+
export declare class ResetUseCase implements IResetUseCase {
|
|
11
11
|
private readonly contextTreeService;
|
|
12
12
|
private readonly contextTreeSnapshotService;
|
|
13
13
|
private readonly terminal;
|
|
14
|
-
constructor(options:
|
|
15
|
-
protected
|
|
14
|
+
constructor(options: ResetUseCaseOptions);
|
|
15
|
+
protected confirmReset(): Promise<boolean>;
|
|
16
16
|
run(options: {
|
|
17
17
|
directory?: string;
|
|
18
18
|
skipConfirmation: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { rm } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { BRV_DIR, CONTEXT_TREE_DIR } from '../../constants.js';
|
|
4
|
-
export class
|
|
4
|
+
export class ResetUseCase {
|
|
5
5
|
contextTreeService;
|
|
6
6
|
contextTreeSnapshotService;
|
|
7
7
|
terminal;
|
|
@@ -11,10 +11,10 @@ export class ClearUseCase {
|
|
|
11
11
|
this.terminal = options.terminal;
|
|
12
12
|
}
|
|
13
13
|
// Protected method for testability - can be overridden in tests
|
|
14
|
-
async
|
|
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) {
|
|
@@ -22,12 +22,12 @@ export class ClearUseCase {
|
|
|
22
22
|
// Check if context tree exists
|
|
23
23
|
const exists = await this.contextTreeService.exists(options.directory);
|
|
24
24
|
if (!exists) {
|
|
25
|
-
this.terminal.log('No context tree found. Nothing to
|
|
25
|
+
this.terminal.log('No context tree found. Nothing to reset.');
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
// Confirmation prompt (unless skipConfirmation is true)
|
|
29
29
|
if (!options.skipConfirmation) {
|
|
30
|
-
const confirmed = await this.
|
|
30
|
+
const confirmed = await this.confirmReset();
|
|
31
31
|
if (!confirmed) {
|
|
32
32
|
this.terminal.log('Cancelled. Context tree was not reset.');
|
|
33
33
|
return;
|
|
@@ -37,12 +37,11 @@ export class ClearUseCase {
|
|
|
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
|