byterover-cli 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +108 -653
  2. package/bin/dev.cmd +1 -1
  3. package/bin/dev.js +1 -1
  4. package/bin/run.cmd +1 -1
  5. package/bin/run.js +1 -1
  6. package/dist/commands/add.d.ts +4 -15
  7. package/dist/commands/add.js +31 -69
  8. package/dist/commands/init.js +13 -8
  9. package/dist/commands/push.d.ts +6 -4
  10. package/dist/commands/push.js +39 -9
  11. package/dist/commands/retrieve.d.ts +2 -2
  12. package/dist/commands/retrieve.js +3 -3
  13. package/dist/commands/space/list.js +10 -5
  14. package/dist/commands/space/switch.js +8 -7
  15. package/dist/commands/status.js +5 -6
  16. package/dist/config/environment.d.ts +3 -2
  17. package/dist/config/environment.js +13 -11
  18. package/dist/constants.d.ts +8 -1
  19. package/dist/constants.js +8 -1
  20. package/dist/core/domain/entities/{br-config.d.ts → brv-config.d.ts} +5 -5
  21. package/dist/core/domain/entities/{br-config.js → brv-config.js} +5 -5
  22. package/dist/core/domain/entities/playbook.d.ts +4 -0
  23. package/dist/core/domain/entities/playbook.js +7 -0
  24. package/dist/core/interfaces/i-playbook-service.d.ts +1 -1
  25. package/dist/core/interfaces/i-project-config-store.d.ts +10 -10
  26. package/dist/hooks/init/welcome.d.ts +3 -0
  27. package/dist/hooks/init/welcome.js +31 -0
  28. package/dist/infra/ace/ace-file-utils.js +2 -2
  29. package/dist/infra/ace/file-bullet-content-store.d.ts +4 -4
  30. package/dist/infra/ace/file-bullet-content-store.js +7 -7
  31. package/dist/infra/ace/file-delta-store.d.ts +1 -1
  32. package/dist/infra/ace/file-delta-store.js +1 -1
  33. package/dist/infra/ace/file-executor-output-store.d.ts +1 -1
  34. package/dist/infra/ace/file-executor-output-store.js +1 -1
  35. package/dist/infra/ace/file-playbook-store.d.ts +3 -3
  36. package/dist/infra/ace/file-playbook-store.js +6 -6
  37. package/dist/infra/ace/file-reflection-store.d.ts +1 -1
  38. package/dist/infra/ace/file-reflection-store.js +1 -1
  39. package/dist/infra/config/file-config-store.d.ts +6 -8
  40. package/dist/infra/config/file-config-store.js +10 -11
  41. package/dist/infra/playbook/file-playbook-service.d.ts +0 -1
  42. package/dist/infra/playbook/file-playbook-service.js +7 -8
  43. package/dist/templates/README.md +5 -5
  44. package/dist/templates/sections/command-reference.md +23 -23
  45. package/dist/templates/sections/workflow.md +3 -4
  46. package/oclif.manifest.json +10 -3
  47. package/package.json +8 -5
package/bin/dev.cmd CHANGED
@@ -1,4 +1,4 @@
1
1
  @echo off
2
2
 
3
- set BR_ENV=development
3
+ set BRV_ENV=development
4
4
  node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %*
package/bin/dev.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning
2
2
 
3
- process.env.BR_ENV = 'development'
3
+ process.env.BRV_ENV = 'development'
4
4
 
5
5
  import {execute} from '@oclif/core'
6
6
 
package/bin/run.cmd CHANGED
@@ -1,4 +1,4 @@
1
1
  @echo off
2
2
 
3
- set BR_ENV=production
3
+ set BRV_ENV=production
4
4
  node "%~dp0\run" %*
package/bin/run.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- process.env.BR_ENV = 'production'
3
+ process.env.BRV_ENV = 'production'
4
4
 
5
5
  import {execute} from '@oclif/core'
6
6
 
@@ -1,18 +1,11 @@
1
1
  import { Command } from '@oclif/core';
2
- import type { Bullet } from '../core/domain/entities/bullet.js';
3
2
  import type { IPlaybookService } from '../core/interfaces/i-playbook-service.js';
4
3
  import type { IPlaybookStore } from '../core/interfaces/i-playbook-store.js';
5
4
  import type { ITrackingService } from '../core/interfaces/i-tracking-service.js';
6
- type UserAction = 'add' | 'update';
7
5
  interface SectionPromptOptions {
8
6
  readonly existingSections: readonly string[];
9
7
  readonly suggestedSections: readonly string[];
10
8
  }
11
- interface ContentPromptContext {
12
- readonly action: UserAction;
13
- readonly existingContent?: string;
14
- readonly section: string;
15
- }
16
9
  export default class Add extends Command {
17
10
  static description: string;
18
11
  static examples: string[];
@@ -28,24 +21,20 @@ export default class Add extends Command {
28
21
  trackingService: ITrackingService;
29
22
  };
30
23
  /**
31
- * Prompt user to choose between adding a new bullet or updating an existing one
32
- */
33
- protected promptForAction(): Promise<UserAction>;
34
- /**
35
- * Prompt user to select a bullet to update
24
+ * Prompt user to confirm adding the bullet
36
25
  */
37
- protected promptForBullet(bullets: Bullet[]): Promise<string>;
26
+ protected promptForConfirmation(bulletId: string, section: string, content: string): Promise<boolean>;
38
27
  /**
39
28
  * Prompt user to enter bullet content
40
29
  */
41
- protected promptForContent(context: ContentPromptContext): Promise<string>;
30
+ protected promptForContent(section: string): Promise<string>;
42
31
  /**
43
32
  * Prompt user to select or create a section name
44
33
  */
45
34
  protected promptForSection(options: SectionPromptOptions): Promise<string>;
46
35
  run(): Promise<void>;
47
36
  /**
48
- * Display success message after adding or updating a bullet
37
+ * Display success message after adding a bullet
49
38
  */
50
39
  private displaySuccess;
51
40
  /**
@@ -1,4 +1,4 @@
1
- import { input, search, select } from '@inquirer/prompts';
1
+ import { confirm, input, search } from '@inquirer/prompts';
2
2
  import { Command, Flags } from '@oclif/core';
3
3
  import { Playbook } from '../core/domain/entities/playbook.js';
4
4
  import { FilePlaybookStore } from '../infra/ace/file-playbook-store.js';
@@ -54,55 +54,27 @@ export default class Add extends Command {
54
54
  };
55
55
  }
56
56
  /**
57
- * Prompt user to choose between adding a new bullet or updating an existing one
57
+ * Prompt user to confirm adding the bullet
58
58
  */
59
- async promptForAction() {
60
- const action = await select({
61
- choices: [
62
- { name: 'Add a new bullet', value: 'add' },
63
- { name: 'Update an existing bullet', value: 'update' },
64
- ],
65
- message: 'What would you like to do?',
59
+ async promptForConfirmation(bulletId, section, content) {
60
+ this.log('\nReview your bullet:');
61
+ this.log(` ID: ${bulletId}`);
62
+ this.log(` Section: ${section}`);
63
+ const contentDisplay = content.length > 200 ? `${content.slice(0, 200)}...` : content;
64
+ this.log(` Content: ${contentDisplay}`);
65
+ this.log('\nTip: Use `brv status` to view and update bullets later');
66
+ const confirmed = await confirm({
67
+ default: true,
68
+ message: 'Add this bullet?',
66
69
  });
67
- return action;
68
- }
69
- /**
70
- * Prompt user to select a bullet to update
71
- */
72
- async promptForBullet(bullets) {
73
- const displayBullets = bullets.map((bullet) => ({
74
- contentPreview: bullet.content.length > 60 ? `${bullet.content.slice(0, 60)}...` : bullet.content,
75
- id: bullet.id,
76
- section: bullet.section,
77
- tags: bullet.metadata.tags,
78
- timestamp: new Date(bullet.metadata.timestamp).toLocaleDateString(),
79
- }));
80
- const bulletId = await search({
81
- message: 'Select a bullet to update:',
82
- async source(input) {
83
- const filtered = input
84
- ? displayBullets.filter((b) => b.section.toLowerCase().includes(input.toLowerCase()) ||
85
- b.contentPreview.toLowerCase().includes(input.toLowerCase()) ||
86
- b.id.toLowerCase().includes(input.toLowerCase()))
87
- : displayBullets;
88
- return filtered.map((b) => ({
89
- description: `Tags: ${b.tags.join(', ')} | Date: ${b.timestamp}`,
90
- name: `[${b.id}] ${b.section}: ${b.contentPreview}`,
91
- value: b.id,
92
- }));
93
- },
94
- });
95
- return bulletId;
70
+ return confirmed;
96
71
  }
97
72
  /**
98
73
  * Prompt user to enter bullet content
99
74
  */
100
- async promptForContent(context) {
101
- const message = context.action === 'update'
102
- ? `Enter new content for bullet in "${context.section}":`
103
- : `Enter content for new bullet in "${context.section}":`;
75
+ async promptForContent(section) {
76
+ const message = `Enter content for new bullet in "${section}":`;
104
77
  const content = await input({
105
- default: context.existingContent,
106
78
  message,
107
79
  validate(value) {
108
80
  if (!validateContent(value)) {
@@ -139,11 +111,10 @@ export default class Add extends Command {
139
111
  return flags.interactive ? this.runInteractive() : this.runFlagBased(flags);
140
112
  }
141
113
  /**
142
- * Display success message after adding or updating a bullet
114
+ * Display success message after adding a bullet
143
115
  */
144
- displaySuccess(bullet, action) {
145
- const actionText = action === 'update' ? 'Updated' : 'Added';
146
- this.log(`\n✓ ${actionText} bullet successfully!`);
116
+ displaySuccess(bullet) {
117
+ this.log(`\n✓ Added bullet successfully!`);
147
118
  this.log(` ID: ${bullet.id}`);
148
119
  this.log(` Section: ${bullet.section}`);
149
120
  this.log(` Content: ${bullet.content}`);
@@ -173,7 +144,7 @@ export default class Add extends Command {
173
144
  content: flags.content,
174
145
  section: flags.section,
175
146
  });
176
- this.displaySuccess(bullet, flags['bullet-id'] ? 'update' : 'add');
147
+ this.displaySuccess(bullet);
177
148
  }
178
149
  catch (error) {
179
150
  this.error(error instanceof Error ? error.message : 'Unexpected error occurred');
@@ -185,43 +156,34 @@ export default class Add extends Command {
185
156
  async runInteractive() {
186
157
  const { playbookService, playbookStore, trackingService } = this.createServices();
187
158
  try {
159
+ // Display welcome message
160
+ this.log('Press Ctrl+C at any time to cancel the process\n');
188
161
  // Load existing playbook or create new one
189
162
  let playbook = await playbookStore.load();
190
163
  if (!playbook) {
191
164
  playbook = new Playbook();
192
165
  }
193
- const action = await this.promptForAction();
194
166
  const sectionOptions = {
195
167
  existingSections: playbook.getSections(),
196
168
  suggestedSections: SUGGESTED_SECTIONS,
197
169
  };
198
170
  const section = await this.promptForSection(sectionOptions);
199
- let bulletId;
200
- let existingContent;
201
- if (action === 'update') {
202
- const bullets = playbook.getBullets();
203
- if (bullets.length === 0) {
204
- this.warn('No bullets available to update. Creating new bullet instead.');
205
- }
206
- else {
207
- bulletId = await this.promptForBullet(bullets);
208
- const bullet = playbook.getBullet(bulletId);
209
- existingContent = bullet?.content;
210
- }
171
+ const content = await this.promptForContent(section);
172
+ // Get next bullet ID for confirmation
173
+ const nextId = playbook.getNextId();
174
+ // Prompt for confirmation
175
+ const confirmed = await this.promptForConfirmation(nextId, section, content);
176
+ if (!confirmed) {
177
+ this.log('\nBullet not added. Operation cancelled.');
178
+ return;
211
179
  }
212
- const contentContext = {
213
- action: bulletId ? 'update' : 'add',
214
- existingContent,
215
- section,
216
- };
217
- const content = await this.promptForContent(contentContext);
218
180
  const bullet = await playbookService.addOrUpdateBullet({
219
- bulletId,
181
+ bulletId: undefined,
220
182
  content,
221
183
  section,
222
184
  });
223
185
  await trackingService.track('ace:add_bullet');
224
- this.displaySuccess(bullet, bulletId ? 'update' : 'add');
186
+ this.displaySuccess(bullet);
225
187
  }
226
188
  catch (error) {
227
189
  this.error(error instanceof Error ? error.message : 'Unexpected error occurred');
@@ -1,7 +1,8 @@
1
1
  import { select } from '@inquirer/prompts';
2
2
  import { Command, ux } from '@oclif/core';
3
3
  import { getCurrentConfig } from '../config/environment.js';
4
- import { BrConfig } from '../core/domain/entities/br-config.js';
4
+ import { BRV_DIR, PROJECT_CONFIG_FILE } from '../constants.js';
5
+ import { BrvConfig } from '../core/domain/entities/brv-config.js';
5
6
  import { ProjectConfigStore } from '../infra/config/file-config-store.js';
6
7
  import { FilePlaybookService } from '../infra/playbook/file-playbook-service.js';
7
8
  import { HttpSpaceService } from '../infra/space/http-space-service.js';
@@ -9,7 +10,7 @@ import { KeychainTokenStore } from '../infra/storage/keychain-token-store.js';
9
10
  import { HttpTeamService } from '../infra/team/http-team-service.js';
10
11
  import { MixpanelTrackingService } from '../infra/tracking/mixpanel-tracking-service.js';
11
12
  export default class Init extends Command {
12
- static description = 'Initialize a project with ByteRover (creates .br/config.json with team/space selection and initializes ACE playbook)';
13
+ static description = `Initialize a project with ByteRover (creates ${BRV_DIR}/${PROJECT_CONFIG_FILE} with team/space selection and initializes ACE playbook)`;
13
14
  static examples = [
14
15
  '<%= config.bin %> <%= command.id %>',
15
16
  '# Re-initialize if config exists (will show current config and exit):\n<%= config.bin %> <%= command.id %>',
@@ -75,10 +76,10 @@ export default class Init extends Command {
75
76
  // 2. Load and validate authentication token
76
77
  const token = await tokenStore.load();
77
78
  if (token === undefined) {
78
- this.error('Not authenticated. Please run "br login" first.');
79
+ this.error('Not authenticated. Please run "brv login" first.');
79
80
  }
80
81
  if (!token.isValid()) {
81
- this.error('Authentication token expired. Please run "br login" again.');
82
+ this.error('Authentication token expired. Please run "brv login" again.');
82
83
  }
83
84
  // 3. Fetch all teams with spinner
84
85
  ux.action.start('Fetching all teams');
@@ -86,7 +87,9 @@ export default class Init extends Command {
86
87
  ux.action.stop();
87
88
  const { teams } = teamResult;
88
89
  if (teams.length === 0) {
89
- this.error('No teams found. Please create a team in the ByteRover dashboard first.');
90
+ this.log('No teams found.');
91
+ this.log(`Please visit ${getCurrentConfig().webAppUrl} to create your first team.`);
92
+ return;
90
93
  }
91
94
  // 4. Prompt for team selection
92
95
  this.log();
@@ -99,13 +102,15 @@ export default class Init extends Command {
99
102
  ux.action.stop();
100
103
  const { spaces } = spaceResult;
101
104
  if (spaces.length === 0) {
102
- this.error(`No spaces found in team "${selectedTeam.getDisplayName()}". Please create a space in the ByteRover dashboard first.`);
105
+ this.log(`No spaces found in team "${selectedTeam.getDisplayName()}"`);
106
+ this.log(`Please visit ${getCurrentConfig().webAppUrl} to create your first space for ${selectedTeam.getDisplayName()}.`);
107
+ return;
103
108
  }
104
109
  // 6. Prompt for space selection
105
110
  this.log();
106
111
  const selectedSpace = await this.promptForSpaceSelection(spaces);
107
112
  // 7. Create and save configuration
108
- const config = BrConfig.fromSpace(selectedSpace);
113
+ const config = BrvConfig.fromSpace(selectedSpace);
109
114
  await projectConfigStore.write(config);
110
115
  // 8. Initialize ACE playbook
111
116
  this.log('\nInitializing ACE context...');
@@ -126,7 +131,7 @@ export default class Init extends Command {
126
131
  // 10. Display success
127
132
  this.log(`\n✓ Project initialized successfully!`);
128
133
  this.log(`✓ Connected to space: ${selectedSpace.getDisplayName()}`);
129
- this.log(`✓ Configuration saved to: .br/config.json`);
134
+ this.log(`✓ Configuration saved to: ${BRV_DIR}/${PROJECT_CONFIG_FILE}`);
130
135
  }
131
136
  catch (error) {
132
137
  this.error(error instanceof Error ? error.message : 'Initialization failed');
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { AuthToken } from '../core/domain/entities/auth-token.js';
3
- import type { BrConfig } from '../core/domain/entities/br-config.js';
3
+ import type { BrvConfig } from '../core/domain/entities/brv-config.js';
4
4
  import type { PresignedUrl } from '../core/domain/entities/presigned-url.js';
5
5
  import type { PresignedUrlsResponse } from '../core/domain/entities/presigned-urls-response.js';
6
6
  import type { IMemoryStorageService } from '../core/interfaces/i-memory-storage-service.js';
@@ -13,10 +13,12 @@ export default class Push extends Command {
13
13
  static examples: string[];
14
14
  static flags: {
15
15
  branch: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
16
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
17
  };
17
- protected checkProjectInit(projectConfigStore: IProjectConfigStore): Promise<BrConfig>;
18
+ protected checkProjectInit(projectConfigStore: IProjectConfigStore): Promise<BrvConfig>;
18
19
  protected cleanUpLocalFiles(playbookStore: IPlaybookStore): Promise<void>;
19
- protected confirmUpload(memoryService: IMemoryStorageService, token: AuthToken, projectConfig: BrConfig, requestId: string): Promise<void>;
20
+ protected confirmPush(projectConfig: BrvConfig, branch: string, fileCount: number): Promise<boolean>;
21
+ protected confirmUpload(memoryService: IMemoryStorageService, token: AuthToken, projectConfig: BrvConfig, requestId: string): Promise<void>;
20
22
  protected createServices(): {
21
23
  memoryService: IMemoryStorageService;
22
24
  playbookStore: IPlaybookStore;
@@ -24,7 +26,7 @@ export default class Push extends Command {
24
26
  tokenStore: ITokenStore;
25
27
  trackingService: ITrackingService;
26
28
  };
27
- protected getPresignedUrls(memoryService: IMemoryStorageService, token: AuthToken, projectConfig: BrConfig): Promise<PresignedUrlsResponse>;
29
+ protected getPresignedUrls(memoryService: IMemoryStorageService, token: AuthToken, projectConfig: BrvConfig): Promise<PresignedUrlsResponse>;
28
30
  protected loadPlaybookContent(playbookStore: IPlaybookStore): Promise<string>;
29
31
  run(): Promise<void>;
30
32
  protected uploadFiles(memoryService: IMemoryStorageService, presignedUrls: ReadonlyArray<PresignedUrl>, playbookContent: string): Promise<void>;
@@ -1,7 +1,8 @@
1
+ import { confirm } from '@inquirer/prompts';
1
2
  import { Command, Flags, ux } from '@oclif/core';
2
3
  import { join } from 'node:path';
3
4
  import { getCurrentConfig } from '../config/environment.js';
4
- import { ACE_DIR, BR_DIR, DEFAULT_BRANCH, DELTAS_DIR, EXECUTOR_OUTPUTS_DIR, REFLECTIONS_DIR } from '../constants.js';
5
+ import { ACE_DIR, BRV_DIR, BULLETS_DIR, DEFAULT_BRANCH, DELTAS_DIR, EXECUTOR_OUTPUTS_DIR, PLAYBOOK_FILE, REFLECTIONS_DIR, } from '../constants.js';
5
6
  import { FilePlaybookStore } from '../infra/ace/file-playbook-store.js';
6
7
  import { ProjectConfigStore } from '../infra/config/file-config-store.js';
7
8
  import { HttpMemoryStorageService } from '../infra/memory/http-memory-storage-service.js';
@@ -22,23 +23,28 @@ export default class Push extends Command {
22
23
  default: DEFAULT_BRANCH,
23
24
  description: 'ByteRover branch name (not Git branch)',
24
25
  }),
26
+ yes: Flags.boolean({
27
+ char: 'y',
28
+ default: false,
29
+ description: 'Skip confirmation prompt',
30
+ }),
25
31
  };
26
32
  async checkProjectInit(projectConfigStore) {
27
33
  const projectConfig = await projectConfigStore.read();
28
34
  if (projectConfig === undefined) {
29
- this.error('Project not initialized. Run "br init" first.');
35
+ this.error('Project not initialized. Run "brv init" first.');
30
36
  }
31
37
  return projectConfig;
32
38
  }
33
39
  async cleanUpLocalFiles(playbookStore) {
34
40
  this.log('\nCleaning up local files...');
35
- // Clear playbook content
36
- ux.action.start(' Clearing playbook');
41
+ // Clear playbook content and bullet files
42
+ ux.action.start(' Clearing playbook and bullet files');
37
43
  await playbookStore.clear();
38
44
  ux.action.stop('✓');
39
45
  // Clean executor outputs
40
46
  const baseDir = process.cwd();
41
- const aceDir = join(baseDir, BR_DIR, ACE_DIR);
47
+ const aceDir = join(baseDir, BRV_DIR, ACE_DIR);
42
48
  const executorOutputsDir = join(aceDir, EXECUTOR_OUTPUTS_DIR);
43
49
  const reflectionsDir = join(aceDir, REFLECTIONS_DIR);
44
50
  const deltasDir = join(aceDir, DELTAS_DIR);
@@ -54,6 +60,22 @@ export default class Push extends Command {
54
60
  const deltaCount = await clearDirectory(deltasDir);
55
61
  ux.action.stop(`✓ (${deltaCount} files removed)`);
56
62
  }
63
+ async confirmPush(projectConfig, branch, fileCount) {
64
+ this.log('\nYou are about to push to ByteRover memory storage:');
65
+ this.log(` Space: ${projectConfig.spaceName}`);
66
+ this.log(` Branch: ${branch}`);
67
+ this.log(` Files to upload: ${fileCount}`);
68
+ this.log('\nAfter successful push, these local files will be cleaned up:');
69
+ this.log(' - Playbook content');
70
+ this.log(` - Bullet files (${BRV_DIR}/${ACE_DIR}/${BULLETS_DIR}/)`);
71
+ this.log(` - Executor outputs (${BRV_DIR}/${ACE_DIR}/${EXECUTOR_OUTPUTS_DIR}/)`);
72
+ this.log(` - Reflections (${BRV_DIR}/${ACE_DIR}/${REFLECTIONS_DIR}/)`);
73
+ this.log(` - Deltas (${BRV_DIR}/${ACE_DIR}/${DELTAS_DIR}/)`);
74
+ return confirm({
75
+ default: false,
76
+ message: 'Push to ByteRover and clean up local files?',
77
+ });
78
+ }
57
79
  async confirmUpload(memoryService, token, projectConfig, requestId) {
58
80
  ux.action.start('Confirming upload');
59
81
  await memoryService.confirmUpload({
@@ -85,7 +107,7 @@ export default class Push extends Command {
85
107
  const response = await memoryService.getPresignedUrls({
86
108
  accessToken: token.accessToken,
87
109
  branch: flags.branch,
88
- fileNames: ['playbook.json'],
110
+ fileNames: [`${PLAYBOOK_FILE}`],
89
111
  sessionKey: token.sessionKey,
90
112
  spaceId: projectConfig.spaceId,
91
113
  teamId: projectConfig.teamId,
@@ -111,6 +133,14 @@ export default class Push extends Command {
111
133
  const token = await this.validateAuth(tokenStore);
112
134
  const projectConfig = await this.checkProjectInit(projectConfigStore);
113
135
  await this.verifyPlaybookExists(playbookStore);
136
+ // Prompt for confirmation unless --yes flag is provided
137
+ if (!flags.yes) {
138
+ const confirmed = await this.confirmPush(projectConfig, flags.branch, 1);
139
+ if (!confirmed) {
140
+ this.log('Push cancelled. No files were uploaded or cleaned.');
141
+ return;
142
+ }
143
+ }
114
144
  const response = await this.getPresignedUrls(memoryService, token, projectConfig);
115
145
  const playbookContent = await this.loadPlaybookContent(playbookStore);
116
146
  await this.uploadFiles(memoryService, response.presignedUrls, playbookContent);
@@ -134,17 +164,17 @@ export default class Push extends Command {
134
164
  async validateAuth(tokenStore) {
135
165
  const token = await tokenStore.load();
136
166
  if (token === undefined) {
137
- this.error('Not authenticated. Run "br login" first.');
167
+ this.error('Not authenticated. Run "brv login" first.');
138
168
  }
139
169
  if (!token.isValid()) {
140
- this.error('Authentication token expired. Run "br login" again.');
170
+ this.error('Authentication token expired. Run "brv login" again.');
141
171
  }
142
172
  return token;
143
173
  }
144
174
  async verifyPlaybookExists(playbookStore) {
145
175
  const playbookExists = await playbookStore.exists();
146
176
  if (!playbookExists) {
147
- this.error('Playbook not found. Run "br init" to create one.');
177
+ this.error('Playbook not found. Run "brv init" to create one.');
148
178
  }
149
179
  }
150
180
  }
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  import type { AuthToken } from '../core/domain/entities/auth-token.js';
3
- import type { BrConfig } from '../core/domain/entities/br-config.js';
3
+ import type { BrvConfig } from '../core/domain/entities/brv-config.js';
4
4
  import type { IMemoryRetrievalService } from '../core/interfaces/i-memory-retrieval-service.js';
5
5
  import type { IProjectConfigStore } from '../core/interfaces/i-project-config-store.js';
6
6
  import type { ITokenStore } from '../core/interfaces/i-token-store.js';
@@ -13,7 +13,7 @@ export default class Retrieve extends Command {
13
13
  'node-keys': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
14
  query: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
15
  };
16
- protected checkProjectInt(projectConfigStore: IProjectConfigStore): Promise<BrConfig>;
16
+ protected checkProjectInt(projectConfigStore: IProjectConfigStore): Promise<BrvConfig>;
17
17
  protected createServices(): {
18
18
  memoryService: IMemoryRetrievalService;
19
19
  projectConfigStore: IProjectConfigStore;
@@ -31,7 +31,7 @@ export default class Retrieve extends Command {
31
31
  async checkProjectInt(projectConfigStore) {
32
32
  const isInitialized = await projectConfigStore.exists();
33
33
  if (!isInitialized) {
34
- this.error('Project is not initialized. Please run "br init" first.');
34
+ this.error('Project is not initialized. Please run "brv init" first.');
35
35
  }
36
36
  const config = await projectConfigStore.read();
37
37
  if (!config) {
@@ -82,10 +82,10 @@ export default class Retrieve extends Command {
82
82
  async validateAuth(tokenStore) {
83
83
  const token = await tokenStore.load();
84
84
  if (token === undefined) {
85
- this.error('Not authenticated. Please run "br auth login" first.');
85
+ this.error('Not authenticated. Please run "brv login" first.');
86
86
  }
87
87
  if (!token.isValid()) {
88
- this.error('Authentication token expired. Please run "br auth login" again.');
88
+ this.error('Authentication token expired. Please run "brv login" again.');
89
89
  }
90
90
  return token;
91
91
  }
@@ -51,13 +51,18 @@ export default class SpaceList extends Command {
51
51
  // Check project initialization
52
52
  const projectConfig = await projectConfigStore.read();
53
53
  if (projectConfig === undefined) {
54
- this.error('Project not initialized. Run "br init" first.');
54
+ this.error('Project not initialized. Run "brv init" first.');
55
55
  }
56
56
  const token = await this.validateAuth(tokenStore);
57
57
  // Fetch spaces for the team from project config
58
58
  ux.action.start(`Fetching spaces for ${projectConfig.teamName}`);
59
- const result = await spaceService.getSpaces(token.accessToken, token.sessionKey, projectConfig.teamId, flags.all ? { fetchAll: true } : { limit: flags.limit, offset: flags.offset });
60
- ux.action.stop();
59
+ let result;
60
+ try {
61
+ result = await spaceService.getSpaces(token.accessToken, token.sessionKey, projectConfig.teamId, flags.all ? { fetchAll: true } : { limit: flags.limit, offset: flags.offset });
62
+ }
63
+ finally {
64
+ ux.action.stop();
65
+ }
61
66
  // Handle empty results
62
67
  if (result.spaces.length === 0) {
63
68
  this.log(`No spaces found in team "${projectConfig.teamName}".`);
@@ -95,10 +100,10 @@ export default class SpaceList extends Command {
95
100
  async validateAuth(tokenStore) {
96
101
  const token = await tokenStore.load();
97
102
  if (token === undefined) {
98
- this.error('Not authenticated. Please run "br login" first.');
103
+ this.error('Not authenticated. Please run "brv login" first.');
99
104
  }
100
105
  if (!token.isValid()) {
101
- this.error('Authentication token expired. Please run "br login" again.');
106
+ this.error('Authentication token expired. Please run "brv login" again.');
102
107
  }
103
108
  return token;
104
109
  }
@@ -1,13 +1,14 @@
1
1
  import { select } from '@inquirer/prompts';
2
2
  import { Command, ux } from '@oclif/core';
3
3
  import { getCurrentConfig } from '../../config/environment.js';
4
- import { BrConfig } from '../../core/domain/entities/br-config.js';
4
+ import { BRV_DIR, PROJECT_CONFIG_FILE } from '../../constants.js';
5
+ import { BrvConfig } from '../../core/domain/entities/brv-config.js';
5
6
  import { ProjectConfigStore } from '../../infra/config/file-config-store.js';
6
7
  import { HttpSpaceService } from '../../infra/space/http-space-service.js';
7
8
  import { KeychainTokenStore } from '../../infra/storage/keychain-token-store.js';
8
9
  import { HttpTeamService } from '../../infra/team/http-team-service.js';
9
10
  export default class SpaceSwitch extends Command {
10
- static description = 'Switch to a different team or space (updates .br/config.json)';
11
+ static description = `Switch to a different team or space (updates ${BRV_DIR}/${PROJECT_CONFIG_FILE})`;
11
12
  static examples = [
12
13
  '<%= config.bin %> <%= command.id %>',
13
14
  '# Shows current configuration, then prompts for new team/space selection',
@@ -59,7 +60,7 @@ export default class SpaceSwitch extends Command {
59
60
  // Check project initialization (MUST exist for switch)
60
61
  const currentConfig = await projectConfigStore.read();
61
62
  if (currentConfig === undefined) {
62
- this.error('Project not initialized. Run "br init" first.');
63
+ this.error('Project not initialized. Run "brv init" first.');
63
64
  }
64
65
  // Show current configuration
65
66
  this.log('Current configuration:');
@@ -69,10 +70,10 @@ export default class SpaceSwitch extends Command {
69
70
  // Validate authentication
70
71
  const token = await tokenStore.load();
71
72
  if (token === undefined) {
72
- this.error('Not authenticated. Please run "br login" first.');
73
+ this.error('Not authenticated. Please run "brv login" first.');
73
74
  }
74
75
  if (!token.isValid()) {
75
- this.error('Authentication token expired. Please run "br login" again.');
76
+ this.error('Authentication token expired. Please run "brv login" again.');
76
77
  }
77
78
  // Fetch all teams
78
79
  ux.action.start('Fetching all teams');
@@ -97,11 +98,11 @@ export default class SpaceSwitch extends Command {
97
98
  this.log();
98
99
  const selectedSpace = await this.promptForSpaceSelection(spaceResult.spaces);
99
100
  // Update configuration
100
- const newConfig = BrConfig.fromSpace(selectedSpace);
101
+ const newConfig = BrvConfig.fromSpace(selectedSpace);
101
102
  await projectConfigStore.write(newConfig);
102
103
  // Display success
103
104
  this.log(`\n✓ Successfully switched to space: ${selectedSpace.getDisplayName()}`);
104
- this.log(`✓ Configuration updated in: .br/config.json`);
105
+ this.log(`✓ Configuration updated in: ${BRV_DIR}/${PROJECT_CONFIG_FILE}`);
105
106
  }
106
107
  catch (error) {
107
108
  this.error(error instanceof Error ? error.message : 'Switch failed');
@@ -1,6 +1,6 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
2
  import chalk from 'chalk';
3
- import { ACE_DIR, BR_DIR, BULLETS_DIR } from '../constants.js';
3
+ import { ACE_DIR, BRV_DIR, BULLETS_DIR } from '../constants.js';
4
4
  import { FilePlaybookStore } from '../infra/ace/file-playbook-store.js';
5
5
  import { ProjectConfigStore } from '../infra/config/file-config-store.js';
6
6
  import { KeychainTokenStore } from '../infra/storage/keychain-token-store.js';
@@ -80,7 +80,7 @@ export default class Status extends Command {
80
80
  try {
81
81
  const playbook = await playbookStore.load(args.directory);
82
82
  if (!playbook) {
83
- this.error('Playbook not found. Run `br init` to initialize.');
83
+ this.error('Playbook not found. Run `brv init` to initialize.');
84
84
  }
85
85
  // Display based on format
86
86
  if (flags.format === 'json') {
@@ -90,7 +90,7 @@ export default class Status extends Command {
90
90
  const bullets = playbook.getBullets();
91
91
  const sections = playbook.getSections();
92
92
  if (bullets.length === 0) {
93
- this.log('Playbook is empty. Use "br add" commands to add knowledge.');
93
+ this.log('Playbook is empty. Use "brv add" commands to add knowledge.');
94
94
  return;
95
95
  }
96
96
  this.log(`\nMemory not pushed to cloud:`);
@@ -101,13 +101,12 @@ export default class Status extends Command {
101
101
  this.log(`# ${section}`);
102
102
  const sectionBullets = playbook.getBulletsInSection(section);
103
103
  for (const bullet of sectionBullets) {
104
- const relativePath = `${BR_DIR}/${ACE_DIR}/${BULLETS_DIR}/${bullet.id}.md`;
104
+ const relativePath = `${BRV_DIR}/${ACE_DIR}/${BULLETS_DIR}/${bullet.id}.md`;
105
105
  // Display like git status: red path
106
106
  this.log(` ${chalk.red(relativePath)}`);
107
107
  }
108
108
  }
109
- // Guide user to push memory to cloud
110
- this.log(`Use "br push" to push memory to cloud.`);
109
+ this.log(`\nUse "brv push" to push playbook to ByteRover memory storage.`);
111
110
  }
112
111
  catch (error) {
113
112
  this.error(error instanceof Error ? error.message : 'Failed to load playbook statistics');
@@ -4,8 +4,8 @@
4
4
  type Environment = 'development' | 'production';
5
5
  /**
6
6
  * Current environment - set at runtime by the launcher scripts.
7
- * - `./bin/dev.js` sets BR_ENV=development
8
- * - `./bin/run.js` sets BR_ENV=production
7
+ * - `./bin/dev.js` sets BRV_ENV=development
8
+ * - `./bin/run.js` sets BRV_ENV=production
9
9
  */
10
10
  export declare const ENVIRONMENT: Environment;
11
11
  /**
@@ -21,6 +21,7 @@ type EnvironmentConfig = {
21
21
  mixpanelToken: string;
22
22
  scopes: string[];
23
23
  tokenUrl: string;
24
+ webAppUrl: string;
24
25
  };
25
26
  /**
26
27
  * Configuration for each environment.