byterover-cli 0.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 +781 -0
- package/bin/dev.cmd +4 -0
- package/bin/dev.js +7 -0
- package/bin/run.cmd +4 -0
- package/bin/run.js +7 -0
- package/dist/commands/add.d.ts +60 -0
- package/dist/commands/add.js +230 -0
- package/dist/commands/clear.d.ts +13 -0
- package/dist/commands/clear.js +57 -0
- package/dist/commands/complete.d.ts +108 -0
- package/dist/commands/complete.js +340 -0
- package/dist/commands/gen-rules.d.ts +26 -0
- package/dist/commands/gen-rules.js +89 -0
- package/dist/commands/init.d.ts +24 -0
- package/dist/commands/init.js +135 -0
- package/dist/commands/login.d.ts +22 -0
- package/dist/commands/login.js +103 -0
- package/dist/commands/push.d.ts +33 -0
- package/dist/commands/push.js +150 -0
- package/dist/commands/retrieve.d.ts +26 -0
- package/dist/commands/retrieve.js +101 -0
- package/dist/commands/space/list.d.ts +22 -0
- package/dist/commands/space/list.js +105 -0
- package/dist/commands/space/switch.d.ts +20 -0
- package/dist/commands/space/switch.js +110 -0
- package/dist/commands/status.d.ts +22 -0
- package/dist/commands/status.js +116 -0
- package/dist/config/auth.config.d.ts +32 -0
- package/dist/config/auth.config.js +35 -0
- package/dist/config/environment.d.ts +35 -0
- package/dist/config/environment.js +39 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.js +12 -0
- package/dist/core/domain/entities/agent.d.ts +5 -0
- package/dist/core/domain/entities/agent.js +23 -0
- package/dist/core/domain/entities/auth-token.d.ts +43 -0
- package/dist/core/domain/entities/auth-token.js +70 -0
- package/dist/core/domain/entities/br-config.d.ts +25 -0
- package/dist/core/domain/entities/br-config.js +58 -0
- package/dist/core/domain/entities/bullet.d.ts +51 -0
- package/dist/core/domain/entities/bullet.js +94 -0
- package/dist/core/domain/entities/curator-output.d.ts +14 -0
- package/dist/core/domain/entities/curator-output.js +23 -0
- package/dist/core/domain/entities/delta-batch.d.ts +30 -0
- package/dist/core/domain/entities/delta-batch.js +52 -0
- package/dist/core/domain/entities/delta-operation.d.ts +31 -0
- package/dist/core/domain/entities/delta-operation.js +50 -0
- package/dist/core/domain/entities/event.d.ts +8 -0
- package/dist/core/domain/entities/event.js +15 -0
- package/dist/core/domain/entities/executor-output.d.ts +27 -0
- package/dist/core/domain/entities/executor-output.js +33 -0
- package/dist/core/domain/entities/memory.d.ts +55 -0
- package/dist/core/domain/entities/memory.js +90 -0
- package/dist/core/domain/entities/oauth-token-data.d.ts +13 -0
- package/dist/core/domain/entities/oauth-token-data.js +20 -0
- package/dist/core/domain/entities/playbook.d.ts +97 -0
- package/dist/core/domain/entities/playbook.js +275 -0
- package/dist/core/domain/entities/presigned-url.d.ts +9 -0
- package/dist/core/domain/entities/presigned-url.js +18 -0
- package/dist/core/domain/entities/presigned-urls-response.d.ts +10 -0
- package/dist/core/domain/entities/presigned-urls-response.js +18 -0
- package/dist/core/domain/entities/reflector-output.d.ts +38 -0
- package/dist/core/domain/entities/reflector-output.js +44 -0
- package/dist/core/domain/entities/retrieve-result.d.ts +35 -0
- package/dist/core/domain/entities/retrieve-result.js +35 -0
- package/dist/core/domain/entities/space.d.ts +24 -0
- package/dist/core/domain/entities/space.js +52 -0
- package/dist/core/domain/entities/team.d.ts +42 -0
- package/dist/core/domain/entities/team.js +89 -0
- package/dist/core/domain/entities/user.d.ts +20 -0
- package/dist/core/domain/entities/user.js +32 -0
- package/dist/core/domain/errors/ace-error.d.ts +34 -0
- package/dist/core/domain/errors/ace-error.js +53 -0
- package/dist/core/domain/errors/auth-error.d.ts +10 -0
- package/dist/core/domain/errors/auth-error.js +20 -0
- package/dist/core/domain/errors/discovery-error.d.ts +21 -0
- package/dist/core/domain/errors/discovery-error.js +33 -0
- package/dist/core/domain/errors/rule-error.d.ts +6 -0
- package/dist/core/domain/errors/rule-error.js +12 -0
- package/dist/core/interfaces/i-ace-prompt-builder.d.ts +48 -0
- package/dist/core/interfaces/i-ace-prompt-builder.js +1 -0
- package/dist/core/interfaces/i-auth-service.d.ts +35 -0
- package/dist/core/interfaces/i-auth-service.js +1 -0
- package/dist/core/interfaces/i-browser-launcher.d.ts +11 -0
- package/dist/core/interfaces/i-browser-launcher.js +1 -0
- package/dist/core/interfaces/i-bullet-content-store.d.ts +36 -0
- package/dist/core/interfaces/i-bullet-content-store.js +1 -0
- package/dist/core/interfaces/i-callback-handler.d.ts +35 -0
- package/dist/core/interfaces/i-callback-handler.js +1 -0
- package/dist/core/interfaces/i-delta-store.d.ts +15 -0
- package/dist/core/interfaces/i-delta-store.js +1 -0
- package/dist/core/interfaces/i-executor-output-store.d.ts +14 -0
- package/dist/core/interfaces/i-executor-output-store.js +1 -0
- package/dist/core/interfaces/i-file-service.d.ts +34 -0
- package/dist/core/interfaces/i-file-service.js +1 -0
- package/dist/core/interfaces/i-http-client.d.ts +33 -0
- package/dist/core/interfaces/i-http-client.js +1 -0
- package/dist/core/interfaces/i-memory-retrieval-service.d.ts +40 -0
- package/dist/core/interfaces/i-memory-retrieval-service.js +1 -0
- package/dist/core/interfaces/i-memory-storage-service.d.ts +55 -0
- package/dist/core/interfaces/i-memory-storage-service.js +1 -0
- package/dist/core/interfaces/i-oidc-discovery-service.d.ts +20 -0
- package/dist/core/interfaces/i-oidc-discovery-service.js +1 -0
- package/dist/core/interfaces/i-playbook-service.d.ts +69 -0
- package/dist/core/interfaces/i-playbook-service.js +1 -0
- package/dist/core/interfaces/i-playbook-store.d.ts +38 -0
- package/dist/core/interfaces/i-playbook-store.js +1 -0
- package/dist/core/interfaces/i-project-config-store.d.ts +26 -0
- package/dist/core/interfaces/i-project-config-store.js +1 -0
- package/dist/core/interfaces/i-reflection-store.d.ts +21 -0
- package/dist/core/interfaces/i-reflection-store.js +1 -0
- package/dist/core/interfaces/i-rule-template-service.d.ts +17 -0
- package/dist/core/interfaces/i-rule-template-service.js +4 -0
- package/dist/core/interfaces/i-rule-writer-service.d.ts +13 -0
- package/dist/core/interfaces/i-rule-writer-service.js +1 -0
- package/dist/core/interfaces/i-space-service.d.ts +28 -0
- package/dist/core/interfaces/i-space-service.js +1 -0
- package/dist/core/interfaces/i-team-service.d.ts +29 -0
- package/dist/core/interfaces/i-team-service.js +1 -0
- package/dist/core/interfaces/i-template-loader.d.ts +29 -0
- package/dist/core/interfaces/i-template-loader.js +1 -0
- package/dist/core/interfaces/i-token-store.d.ts +22 -0
- package/dist/core/interfaces/i-token-store.js +1 -0
- package/dist/core/interfaces/i-tracking-service.d.ts +21 -0
- package/dist/core/interfaces/i-tracking-service.js +1 -0
- package/dist/core/interfaces/i-user-service.d.ts +14 -0
- package/dist/core/interfaces/i-user-service.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/infra/ace/ace-file-utils.d.ts +46 -0
- package/dist/infra/ace/ace-file-utils.js +83 -0
- package/dist/infra/ace/ace-prompt-templates.d.ts +13 -0
- package/dist/infra/ace/ace-prompt-templates.js +177 -0
- package/dist/infra/ace/file-bullet-content-store.d.ts +27 -0
- package/dist/infra/ace/file-bullet-content-store.js +89 -0
- package/dist/infra/ace/file-delta-store.d.ts +9 -0
- package/dist/infra/ace/file-delta-store.js +26 -0
- package/dist/infra/ace/file-executor-output-store.d.ts +9 -0
- package/dist/infra/ace/file-executor-output-store.js +26 -0
- package/dist/infra/ace/file-playbook-store.d.ts +29 -0
- package/dist/infra/ace/file-playbook-store.js +107 -0
- package/dist/infra/ace/file-reflection-store.d.ts +10 -0
- package/dist/infra/ace/file-reflection-store.js +55 -0
- package/dist/infra/auth/oauth-service.d.ts +49 -0
- package/dist/infra/auth/oauth-service.js +126 -0
- package/dist/infra/auth/oidc-discovery-service.d.ts +51 -0
- package/dist/infra/auth/oidc-discovery-service.js +145 -0
- package/dist/infra/browser/system-browser-launcher.d.ts +10 -0
- package/dist/infra/browser/system-browser-launcher.js +18 -0
- package/dist/infra/config/file-config-store.d.ts +21 -0
- package/dist/infra/config/file-config-store.js +57 -0
- package/dist/infra/file/fs-file-service.d.ts +28 -0
- package/dist/infra/file/fs-file-service.js +57 -0
- package/dist/infra/http/authenticated-http-client.d.ts +46 -0
- package/dist/infra/http/authenticated-http-client.js +99 -0
- package/dist/infra/http/callback-handler.d.ts +13 -0
- package/dist/infra/http/callback-handler.js +24 -0
- package/dist/infra/http/callback-server.d.ts +18 -0
- package/dist/infra/http/callback-server.js +93 -0
- package/dist/infra/memory/http-memory-retrieval-service.d.ts +18 -0
- package/dist/infra/memory/http-memory-retrieval-service.js +63 -0
- package/dist/infra/memory/http-memory-storage-service.d.ts +18 -0
- package/dist/infra/memory/http-memory-storage-service.js +67 -0
- package/dist/infra/memory/memory-to-playbook-mapper.d.ts +33 -0
- package/dist/infra/memory/memory-to-playbook-mapper.js +51 -0
- package/dist/infra/playbook/file-playbook-service.d.ts +43 -0
- package/dist/infra/playbook/file-playbook-service.js +133 -0
- package/dist/infra/rule/agent-rule-config.d.ts +19 -0
- package/dist/infra/rule/agent-rule-config.js +77 -0
- package/dist/infra/rule/rule-template-service.d.ts +18 -0
- package/dist/infra/rule/rule-template-service.js +80 -0
- package/dist/infra/rule/rule-writer-service.d.ts +19 -0
- package/dist/infra/rule/rule-writer-service.js +43 -0
- package/dist/infra/space/http-space-service.d.ts +20 -0
- package/dist/infra/space/http-space-service.js +67 -0
- package/dist/infra/storage/keychain-token-store.d.ts +10 -0
- package/dist/infra/storage/keychain-token-store.js +40 -0
- package/dist/infra/team/http-team-service.d.ts +21 -0
- package/dist/infra/team/http-team-service.js +71 -0
- package/dist/infra/template/fs-template-loader.d.ts +33 -0
- package/dist/infra/template/fs-template-loader.js +62 -0
- package/dist/infra/tracking/mixpanel-tracking-service.d.ts +14 -0
- package/dist/infra/tracking/mixpanel-tracking-service.js +44 -0
- package/dist/infra/user/http-user-service.d.ts +12 -0
- package/dist/infra/user/http-user-service.js +26 -0
- package/dist/templates/README.md +103 -0
- package/dist/templates/base.md +3 -0
- package/dist/templates/sections/command-reference.md +141 -0
- package/dist/templates/sections/workflow.md +46 -0
- package/dist/utils/file-helpers.d.ts +15 -0
- package/dist/utils/file-helpers.js +45 -0
- package/oclif.manifest.json +476 -0
- package/package.json +82 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import { getAuthConfig } from '../config/auth.config.js';
|
|
3
|
+
import { getCurrentConfig } from '../config/environment.js';
|
|
4
|
+
import { AuthToken } from '../core/domain/entities/auth-token.js';
|
|
5
|
+
import { DiscoveryError } from '../core/domain/errors/discovery-error.js';
|
|
6
|
+
import { OAuthService } from '../infra/auth/oauth-service.js';
|
|
7
|
+
import { OidcDiscoveryService } from '../infra/auth/oidc-discovery-service.js';
|
|
8
|
+
import { SystemBrowserLauncher } from '../infra/browser/system-browser-launcher.js';
|
|
9
|
+
import { CallbackHandler } from '../infra/http/callback-handler.js';
|
|
10
|
+
import { KeychainTokenStore } from '../infra/storage/keychain-token-store.js';
|
|
11
|
+
import { MixpanelTrackingService } from '../infra/tracking/mixpanel-tracking-service.js';
|
|
12
|
+
import { HttpUserService } from '../infra/user/http-user-service.js';
|
|
13
|
+
export default class Login extends Command {
|
|
14
|
+
static description = 'Authenticate with ByteRover using OAuth 2.0 + PKCE (opens browser for secure login, stores tokens in keychain)';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> <%= command.id %>',
|
|
17
|
+
'# After authentication expires, re-login:\n<%= config.bin %> <%= command.id %>',
|
|
18
|
+
'# Check authentication status after login:\n<%= config.bin %> <%= command.id %>\n<%= config.bin %> status',
|
|
19
|
+
];
|
|
20
|
+
async createAuthService(discoveryService) {
|
|
21
|
+
const config = await getAuthConfig(discoveryService);
|
|
22
|
+
return new OAuthService(config);
|
|
23
|
+
}
|
|
24
|
+
createServices() {
|
|
25
|
+
const config = getCurrentConfig();
|
|
26
|
+
const tokenStore = new KeychainTokenStore();
|
|
27
|
+
const trackingService = new MixpanelTrackingService(tokenStore);
|
|
28
|
+
return {
|
|
29
|
+
browserLauncher: new SystemBrowserLauncher(),
|
|
30
|
+
callbackHandler: new CallbackHandler(),
|
|
31
|
+
discoveryService: new OidcDiscoveryService(),
|
|
32
|
+
tokenStore,
|
|
33
|
+
trackingService,
|
|
34
|
+
userService: new HttpUserService({ apiBaseUrl: config.apiBaseUrl }),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async run() {
|
|
38
|
+
const { browserLauncher, callbackHandler, discoveryService, tokenStore, trackingService, userService } = this.createServices();
|
|
39
|
+
try {
|
|
40
|
+
this.log('Starting authentication process...');
|
|
41
|
+
// Create auth service with discovered config
|
|
42
|
+
const authService = await this.createAuthService(discoveryService);
|
|
43
|
+
// Start callback server
|
|
44
|
+
await callbackHandler.start();
|
|
45
|
+
// Get port and build redirect URI
|
|
46
|
+
const port = callbackHandler.getPort();
|
|
47
|
+
if (!port) {
|
|
48
|
+
throw new Error('Failed to get callback server port');
|
|
49
|
+
}
|
|
50
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
51
|
+
// Initiate authorization (generates PKCE parameters and state internally)
|
|
52
|
+
const authContext = authService.initiateAuthorization(redirectUri);
|
|
53
|
+
// Try to open browser
|
|
54
|
+
let browserOpened = false;
|
|
55
|
+
try {
|
|
56
|
+
await browserLauncher.open(authContext.authUrl);
|
|
57
|
+
browserOpened = true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Browser launch failed, will return URL to user
|
|
61
|
+
}
|
|
62
|
+
// If browser failed to open, display the URL for manual copy
|
|
63
|
+
if (!browserOpened) {
|
|
64
|
+
this.log('\nBrowser failed to open automatically.');
|
|
65
|
+
this.log('Please open this URL in your browser:');
|
|
66
|
+
this.log(authContext.authUrl);
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
// Wait for callback with 5 minute timeout
|
|
70
|
+
const { code } = await callbackHandler.waitForCallback(authContext.state, 5 * 60 * 1000);
|
|
71
|
+
const authTokenData = await authService.exchangeCodeForToken(code, authContext, redirectUri);
|
|
72
|
+
const user = await userService.getCurrentUser(authTokenData.accessToken, authTokenData.sessionKey);
|
|
73
|
+
const authToken = new AuthToken({
|
|
74
|
+
accessToken: authTokenData.accessToken,
|
|
75
|
+
expiresAt: authTokenData.expiresAt,
|
|
76
|
+
refreshToken: authTokenData.refreshToken,
|
|
77
|
+
sessionKey: authTokenData.sessionKey,
|
|
78
|
+
tokenType: authTokenData.tokenType,
|
|
79
|
+
userEmail: user.email,
|
|
80
|
+
userId: user.id,
|
|
81
|
+
});
|
|
82
|
+
await tokenStore.save(authToken);
|
|
83
|
+
// Track successful authentication
|
|
84
|
+
await trackingService.track('auth:signed_in');
|
|
85
|
+
this.log('Successfully authenticated!');
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.error(error instanceof Error ? error.message : 'Authentication failed');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (error instanceof DiscoveryError) {
|
|
93
|
+
this.error(`Failed to configure authentication: ${error.message}\n` +
|
|
94
|
+
'Please check your network connection and try again.');
|
|
95
|
+
}
|
|
96
|
+
this.error(error instanceof Error ? error.message : 'Authentication failed');
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
// Always cleanup server
|
|
100
|
+
await callbackHandler.stop();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { AuthToken } from '../core/domain/entities/auth-token.js';
|
|
3
|
+
import type { BrConfig } from '../core/domain/entities/br-config.js';
|
|
4
|
+
import type { PresignedUrl } from '../core/domain/entities/presigned-url.js';
|
|
5
|
+
import type { PresignedUrlsResponse } from '../core/domain/entities/presigned-urls-response.js';
|
|
6
|
+
import type { IMemoryStorageService } from '../core/interfaces/i-memory-storage-service.js';
|
|
7
|
+
import type { IPlaybookStore } from '../core/interfaces/i-playbook-store.js';
|
|
8
|
+
import type { IProjectConfigStore } from '../core/interfaces/i-project-config-store.js';
|
|
9
|
+
import type { ITokenStore } from '../core/interfaces/i-token-store.js';
|
|
10
|
+
import { ITrackingService } from '../core/interfaces/i-tracking-service.js';
|
|
11
|
+
export default class Push extends Command {
|
|
12
|
+
static description: string;
|
|
13
|
+
static examples: string[];
|
|
14
|
+
static flags: {
|
|
15
|
+
branch: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
};
|
|
17
|
+
protected checkProjectInit(projectConfigStore: IProjectConfigStore): Promise<BrConfig>;
|
|
18
|
+
protected cleanUpLocalFiles(playbookStore: IPlaybookStore): Promise<void>;
|
|
19
|
+
protected confirmUpload(memoryService: IMemoryStorageService, token: AuthToken, projectConfig: BrConfig, requestId: string): Promise<void>;
|
|
20
|
+
protected createServices(): {
|
|
21
|
+
memoryService: IMemoryStorageService;
|
|
22
|
+
playbookStore: IPlaybookStore;
|
|
23
|
+
projectConfigStore: IProjectConfigStore;
|
|
24
|
+
tokenStore: ITokenStore;
|
|
25
|
+
trackingService: ITrackingService;
|
|
26
|
+
};
|
|
27
|
+
protected getPresignedUrls(memoryService: IMemoryStorageService, token: AuthToken, projectConfig: BrConfig): Promise<PresignedUrlsResponse>;
|
|
28
|
+
protected loadPlaybookContent(playbookStore: IPlaybookStore): Promise<string>;
|
|
29
|
+
run(): Promise<void>;
|
|
30
|
+
protected uploadFiles(memoryService: IMemoryStorageService, presignedUrls: ReadonlyArray<PresignedUrl>, playbookContent: string): Promise<void>;
|
|
31
|
+
protected validateAuth(tokenStore: ITokenStore): Promise<AuthToken>;
|
|
32
|
+
protected verifyPlaybookExists(playbookStore: IPlaybookStore): Promise<void>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Command, Flags, ux } from '@oclif/core';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
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 { FilePlaybookStore } from '../infra/ace/file-playbook-store.js';
|
|
6
|
+
import { ProjectConfigStore } from '../infra/config/file-config-store.js';
|
|
7
|
+
import { HttpMemoryStorageService } from '../infra/memory/http-memory-storage-service.js';
|
|
8
|
+
import { KeychainTokenStore } from '../infra/storage/keychain-token-store.js';
|
|
9
|
+
import { MixpanelTrackingService } from '../infra/tracking/mixpanel-tracking-service.js';
|
|
10
|
+
import { clearDirectory } from '../utils/file-helpers.js';
|
|
11
|
+
export default class Push extends Command {
|
|
12
|
+
static description = 'Push playbook to ByteRover memory storage and clean up local ACE files';
|
|
13
|
+
static examples = [
|
|
14
|
+
'<%= config.bin %> <%= command.id %>',
|
|
15
|
+
'<%= config.bin %> <%= command.id %> --branch develop',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> -b feature-auth',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
branch: Flags.string({
|
|
20
|
+
// Can pass either --branch or -b
|
|
21
|
+
char: 'b',
|
|
22
|
+
default: DEFAULT_BRANCH,
|
|
23
|
+
description: 'ByteRover branch name (not Git branch)',
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
async checkProjectInit(projectConfigStore) {
|
|
27
|
+
const projectConfig = await projectConfigStore.read();
|
|
28
|
+
if (projectConfig === undefined) {
|
|
29
|
+
this.error('Project not initialized. Run "br init" first.');
|
|
30
|
+
}
|
|
31
|
+
return projectConfig;
|
|
32
|
+
}
|
|
33
|
+
async cleanUpLocalFiles(playbookStore) {
|
|
34
|
+
this.log('\nCleaning up local files...');
|
|
35
|
+
// Clear playbook content
|
|
36
|
+
ux.action.start(' Clearing playbook');
|
|
37
|
+
await playbookStore.clear();
|
|
38
|
+
ux.action.stop('✓');
|
|
39
|
+
// Clean executor outputs
|
|
40
|
+
const baseDir = process.cwd();
|
|
41
|
+
const aceDir = join(baseDir, BR_DIR, ACE_DIR);
|
|
42
|
+
const executorOutputsDir = join(aceDir, EXECUTOR_OUTPUTS_DIR);
|
|
43
|
+
const reflectionsDir = join(aceDir, REFLECTIONS_DIR);
|
|
44
|
+
const deltasDir = join(aceDir, DELTAS_DIR);
|
|
45
|
+
ux.action.start(' Cleaning executor outputs');
|
|
46
|
+
const executorCount = await clearDirectory(executorOutputsDir);
|
|
47
|
+
ux.action.stop(`✓ (${executorCount} files removed)`);
|
|
48
|
+
// Clean reflections
|
|
49
|
+
ux.action.start(' Cleaning reflections');
|
|
50
|
+
const reflectionCount = await clearDirectory(reflectionsDir);
|
|
51
|
+
ux.action.stop(`✓ (${reflectionCount} files removed)`);
|
|
52
|
+
// Clean deltas
|
|
53
|
+
ux.action.start(' Cleaning deltas');
|
|
54
|
+
const deltaCount = await clearDirectory(deltasDir);
|
|
55
|
+
ux.action.stop(`✓ (${deltaCount} files removed)`);
|
|
56
|
+
}
|
|
57
|
+
async confirmUpload(memoryService, token, projectConfig, requestId) {
|
|
58
|
+
ux.action.start('Confirming upload');
|
|
59
|
+
await memoryService.confirmUpload({
|
|
60
|
+
accessToken: token.accessToken,
|
|
61
|
+
requestId,
|
|
62
|
+
sessionKey: token.sessionKey,
|
|
63
|
+
spaceId: projectConfig.spaceId,
|
|
64
|
+
teamId: projectConfig.teamId,
|
|
65
|
+
});
|
|
66
|
+
ux.action.stop('✓');
|
|
67
|
+
}
|
|
68
|
+
createServices() {
|
|
69
|
+
const envConfig = getCurrentConfig();
|
|
70
|
+
const tokenStore = new KeychainTokenStore();
|
|
71
|
+
const trackingService = new MixpanelTrackingService(tokenStore);
|
|
72
|
+
return {
|
|
73
|
+
memoryService: new HttpMemoryStorageService({
|
|
74
|
+
apiBaseUrl: envConfig.cogitApiBaseUrl,
|
|
75
|
+
}),
|
|
76
|
+
playbookStore: new FilePlaybookStore(),
|
|
77
|
+
projectConfigStore: new ProjectConfigStore(),
|
|
78
|
+
tokenStore,
|
|
79
|
+
trackingService,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async getPresignedUrls(memoryService, token, projectConfig) {
|
|
83
|
+
const { flags } = await this.parse(Push);
|
|
84
|
+
ux.action.start('Requesting upload URLs');
|
|
85
|
+
const response = await memoryService.getPresignedUrls({
|
|
86
|
+
accessToken: token.accessToken,
|
|
87
|
+
branch: flags.branch,
|
|
88
|
+
fileNames: ['playbook.json'],
|
|
89
|
+
sessionKey: token.sessionKey,
|
|
90
|
+
spaceId: projectConfig.spaceId,
|
|
91
|
+
teamId: projectConfig.teamId,
|
|
92
|
+
});
|
|
93
|
+
ux.action.stop();
|
|
94
|
+
return response;
|
|
95
|
+
}
|
|
96
|
+
async loadPlaybookContent(playbookStore) {
|
|
97
|
+
ux.action.start('Loading playbook');
|
|
98
|
+
const playbook = await playbookStore.load();
|
|
99
|
+
if (playbook === undefined) {
|
|
100
|
+
this.error('Failed to load playbook');
|
|
101
|
+
}
|
|
102
|
+
const playbookContent = playbook.dumps();
|
|
103
|
+
ux.action.stop();
|
|
104
|
+
return playbookContent;
|
|
105
|
+
}
|
|
106
|
+
async run() {
|
|
107
|
+
const { flags } = await this.parse(Push);
|
|
108
|
+
try {
|
|
109
|
+
const { memoryService, playbookStore, projectConfigStore, tokenStore, trackingService } = this.createServices();
|
|
110
|
+
await trackingService.track('mem:push');
|
|
111
|
+
const token = await this.validateAuth(tokenStore);
|
|
112
|
+
const projectConfig = await this.checkProjectInit(projectConfigStore);
|
|
113
|
+
await this.verifyPlaybookExists(playbookStore);
|
|
114
|
+
const response = await this.getPresignedUrls(memoryService, token, projectConfig);
|
|
115
|
+
const playbookContent = await this.loadPlaybookContent(playbookStore);
|
|
116
|
+
await this.uploadFiles(memoryService, response.presignedUrls, playbookContent);
|
|
117
|
+
await this.confirmUpload(memoryService, token, projectConfig, response.requestId);
|
|
118
|
+
await this.cleanUpLocalFiles(playbookStore);
|
|
119
|
+
// Success message
|
|
120
|
+
this.log('\n✓ Successfully pushed playbook to ByteRover memory storage!');
|
|
121
|
+
this.log(` Branch: ${flags.branch}`);
|
|
122
|
+
this.log(` Files uploaded: ${response.presignedUrls.length}`);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
this.error(error instanceof Error ? error.message : 'Push failed');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async uploadFiles(memoryService, presignedUrls, playbookContent) {
|
|
129
|
+
this.log('\nUploading files...');
|
|
130
|
+
ux.action.start(' Uploading files');
|
|
131
|
+
await Promise.all(presignedUrls.map((presignedUrl) => memoryService.uploadFile(presignedUrl.uploadUrl, playbookContent)));
|
|
132
|
+
ux.action.stop('✓');
|
|
133
|
+
}
|
|
134
|
+
async validateAuth(tokenStore) {
|
|
135
|
+
const token = await tokenStore.load();
|
|
136
|
+
if (token === undefined) {
|
|
137
|
+
this.error('Not authenticated. Run "br login" first.');
|
|
138
|
+
}
|
|
139
|
+
if (!token.isValid()) {
|
|
140
|
+
this.error('Authentication token expired. Run "br login" again.');
|
|
141
|
+
}
|
|
142
|
+
return token;
|
|
143
|
+
}
|
|
144
|
+
async verifyPlaybookExists(playbookStore) {
|
|
145
|
+
const playbookExists = await playbookStore.exists();
|
|
146
|
+
if (!playbookExists) {
|
|
147
|
+
this.error('Playbook not found. Run "br init" to create one.');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { AuthToken } from '../core/domain/entities/auth-token.js';
|
|
3
|
+
import type { BrConfig } from '../core/domain/entities/br-config.js';
|
|
4
|
+
import type { IMemoryRetrievalService } from '../core/interfaces/i-memory-retrieval-service.js';
|
|
5
|
+
import type { IProjectConfigStore } from '../core/interfaces/i-project-config-store.js';
|
|
6
|
+
import type { ITokenStore } from '../core/interfaces/i-token-store.js';
|
|
7
|
+
import { ITrackingService } from '../core/interfaces/i-tracking-service.js';
|
|
8
|
+
export default class Retrieve extends Command {
|
|
9
|
+
static description: string;
|
|
10
|
+
static examples: string[];
|
|
11
|
+
static flags: {
|
|
12
|
+
compact: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
'node-keys': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
query: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
};
|
|
16
|
+
protected checkProjectInt(projectConfigStore: IProjectConfigStore): Promise<BrConfig>;
|
|
17
|
+
protected createServices(): {
|
|
18
|
+
memoryService: IMemoryRetrievalService;
|
|
19
|
+
projectConfigStore: IProjectConfigStore;
|
|
20
|
+
tokenStore: ITokenStore;
|
|
21
|
+
trackingService: ITrackingService;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
protected validateAuth(tokenStore: ITokenStore): Promise<AuthToken>;
|
|
25
|
+
private buildJsonOutput;
|
|
26
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { getCurrentConfig } from '../config/environment.js';
|
|
3
|
+
import { ProjectConfigStore } from '../infra/config/file-config-store.js';
|
|
4
|
+
import { HttpMemoryRetrievalService } from '../infra/memory/http-memory-retrieval-service.js';
|
|
5
|
+
import { KeychainTokenStore } from '../infra/storage/keychain-token-store.js';
|
|
6
|
+
import { MixpanelTrackingService } from '../infra/tracking/mixpanel-tracking-service.js';
|
|
7
|
+
export default class Retrieve extends Command {
|
|
8
|
+
static description = 'Retrieve memories from ByteRover Memora service and output as JSON';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> <%= command.id %> --query "authentication best practices"',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> -q "error handling" -n "src/auth/login.ts,src/auth/oauth.ts"',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> -q "database connection issues" --compact',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
compact: Flags.boolean({
|
|
16
|
+
default: false,
|
|
17
|
+
description: 'Output compact JSON (single line)',
|
|
18
|
+
required: false,
|
|
19
|
+
}),
|
|
20
|
+
'node-keys': Flags.string({
|
|
21
|
+
char: 'n',
|
|
22
|
+
description: 'Comma-separated list of node keys (file paths) to filter results',
|
|
23
|
+
required: false,
|
|
24
|
+
}),
|
|
25
|
+
query: Flags.string({
|
|
26
|
+
char: 'q',
|
|
27
|
+
description: 'Search query string',
|
|
28
|
+
required: true,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
async checkProjectInt(projectConfigStore) {
|
|
32
|
+
const isInitialized = await projectConfigStore.exists();
|
|
33
|
+
if (!isInitialized) {
|
|
34
|
+
this.error('Project is not initialized. Please run "br init" first.');
|
|
35
|
+
}
|
|
36
|
+
const config = await projectConfigStore.read();
|
|
37
|
+
if (!config) {
|
|
38
|
+
this.error('Failed to read project configuration.');
|
|
39
|
+
}
|
|
40
|
+
return config;
|
|
41
|
+
}
|
|
42
|
+
createServices() {
|
|
43
|
+
const envConfig = getCurrentConfig();
|
|
44
|
+
const tokenStore = new KeychainTokenStore();
|
|
45
|
+
const trackingService = new MixpanelTrackingService(tokenStore);
|
|
46
|
+
return {
|
|
47
|
+
memoryService: new HttpMemoryRetrievalService({
|
|
48
|
+
apiBaseUrl: envConfig.memoraApiBaseUrl,
|
|
49
|
+
}),
|
|
50
|
+
projectConfigStore: new ProjectConfigStore(),
|
|
51
|
+
tokenStore,
|
|
52
|
+
trackingService,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async run() {
|
|
56
|
+
const { flags } = await this.parse(Retrieve);
|
|
57
|
+
const { memoryService, projectConfigStore, tokenStore, trackingService } = this.createServices();
|
|
58
|
+
try {
|
|
59
|
+
const token = await this.validateAuth(tokenStore);
|
|
60
|
+
const projectConfig = await this.checkProjectInt(projectConfigStore);
|
|
61
|
+
// Initialize tracking service
|
|
62
|
+
await trackingService.track('mem:retrieve');
|
|
63
|
+
// Parse node-keys if provided
|
|
64
|
+
const nodeKeys = flags['node-keys'] ? flags['node-keys'].split(',').map((key) => key.trim()) : undefined;
|
|
65
|
+
// Call memory service
|
|
66
|
+
const result = await memoryService.retrieve({
|
|
67
|
+
accessToken: token.accessToken,
|
|
68
|
+
nodeKeys,
|
|
69
|
+
query: flags.query,
|
|
70
|
+
sessionKey: token.sessionKey,
|
|
71
|
+
spaceId: projectConfig.spaceId,
|
|
72
|
+
});
|
|
73
|
+
// Build and output JSON
|
|
74
|
+
const output = this.buildJsonOutput(result, flags.query, projectConfig.spaceName, nodeKeys);
|
|
75
|
+
const jsonString = flags.compact ? JSON.stringify(output) : JSON.stringify(output, null, 2);
|
|
76
|
+
this.log(jsonString);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
this.error(error instanceof Error ? error.message : 'Failed to retrieve memories');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async validateAuth(tokenStore) {
|
|
83
|
+
const token = await tokenStore.load();
|
|
84
|
+
if (token === undefined) {
|
|
85
|
+
this.error('Not authenticated. Please run "br auth login" first.');
|
|
86
|
+
}
|
|
87
|
+
if (!token.isValid()) {
|
|
88
|
+
this.error('Authentication token expired. Please run "br auth login" again.');
|
|
89
|
+
}
|
|
90
|
+
return token;
|
|
91
|
+
}
|
|
92
|
+
buildJsonOutput(result, query, spaceName, nodeKeys) {
|
|
93
|
+
return {
|
|
94
|
+
query,
|
|
95
|
+
spaceName,
|
|
96
|
+
...(nodeKeys && nodeKeys.length > 0 && { nodeKeys }),
|
|
97
|
+
memories: result.memories.map((m) => m.toJson()),
|
|
98
|
+
relatedMemories: result.relatedMemories.map((m) => m.toJson()),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { IProjectConfigStore } from '../../core/interfaces/i-project-config-store.js';
|
|
3
|
+
import type { ISpaceService } from '../../core/interfaces/i-space-service.js';
|
|
4
|
+
import type { ITokenStore } from '../../core/interfaces/i-token-store.js';
|
|
5
|
+
import { AuthToken } from '../../core/domain/entities/auth-token.js';
|
|
6
|
+
export default class SpaceList extends Command {
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
static flags: {
|
|
10
|
+
all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
offset: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
protected createServices(): {
|
|
16
|
+
projectConfigStore: IProjectConfigStore;
|
|
17
|
+
spaceService: ISpaceService;
|
|
18
|
+
tokenStore: ITokenStore;
|
|
19
|
+
};
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
protected validateAuth(tokenStore: ITokenStore): Promise<AuthToken>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Command, Flags, ux } from '@oclif/core';
|
|
2
|
+
import { getCurrentConfig } from '../../config/environment.js';
|
|
3
|
+
import { ProjectConfigStore } from '../../infra/config/file-config-store.js';
|
|
4
|
+
import { HttpSpaceService } from '../../infra/space/http-space-service.js';
|
|
5
|
+
import { KeychainTokenStore } from '../../infra/storage/keychain-token-store.js';
|
|
6
|
+
const DEFAULT_LIMIT = 50;
|
|
7
|
+
const DEFAULT_OFFSET = 0;
|
|
8
|
+
export default class SpaceList extends Command {
|
|
9
|
+
static description = 'List all spaces for the current team (requires project initialization)';
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> <%= command.id %>',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --all',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> --limit 10',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> --limit 10 --offset 20',
|
|
15
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
16
|
+
];
|
|
17
|
+
static flags = {
|
|
18
|
+
all: Flags.boolean({
|
|
19
|
+
char: 'a',
|
|
20
|
+
default: false,
|
|
21
|
+
description: 'Fetch all spaces (may be slow for large teams)',
|
|
22
|
+
}),
|
|
23
|
+
json: Flags.boolean({
|
|
24
|
+
char: 'j',
|
|
25
|
+
default: false,
|
|
26
|
+
description: 'Output in JSON format',
|
|
27
|
+
}),
|
|
28
|
+
limit: Flags.integer({
|
|
29
|
+
char: 'l',
|
|
30
|
+
default: DEFAULT_LIMIT,
|
|
31
|
+
description: 'Maximum number of spaces to fetch',
|
|
32
|
+
}),
|
|
33
|
+
offset: Flags.integer({
|
|
34
|
+
char: 'o',
|
|
35
|
+
default: DEFAULT_OFFSET,
|
|
36
|
+
description: 'Number of spaces to skip',
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
createServices() {
|
|
40
|
+
const envConfig = getCurrentConfig();
|
|
41
|
+
return {
|
|
42
|
+
projectConfigStore: new ProjectConfigStore(),
|
|
43
|
+
spaceService: new HttpSpaceService({ apiBaseUrl: envConfig.apiBaseUrl }),
|
|
44
|
+
tokenStore: new KeychainTokenStore(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async run() {
|
|
48
|
+
try {
|
|
49
|
+
const { flags } = await this.parse(SpaceList);
|
|
50
|
+
const { projectConfigStore, spaceService, tokenStore } = this.createServices();
|
|
51
|
+
// Check project initialization
|
|
52
|
+
const projectConfig = await projectConfigStore.read();
|
|
53
|
+
if (projectConfig === undefined) {
|
|
54
|
+
this.error('Project not initialized. Run "br init" first.');
|
|
55
|
+
}
|
|
56
|
+
const token = await this.validateAuth(tokenStore);
|
|
57
|
+
// Fetch spaces for the team from project config
|
|
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();
|
|
61
|
+
// Handle empty results
|
|
62
|
+
if (result.spaces.length === 0) {
|
|
63
|
+
this.log(`No spaces found in team "${projectConfig.teamName}".`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Display results based on format
|
|
67
|
+
if (flags.json) {
|
|
68
|
+
this.log(JSON.stringify({
|
|
69
|
+
showing: result.spaces.length,
|
|
70
|
+
spaces: result.spaces.map((s) => s.toJson()),
|
|
71
|
+
team: { id: projectConfig.teamId, name: projectConfig.teamName },
|
|
72
|
+
total: result.total,
|
|
73
|
+
}, null, 2));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Human-readable format
|
|
77
|
+
this.log(`\nSpaces in team "${projectConfig.teamName}":\n`);
|
|
78
|
+
this.log(`Found ${result.spaces.length} space(s):\n`);
|
|
79
|
+
for (const [index, space] of result.spaces.entries()) {
|
|
80
|
+
this.log(` ${index + 1}. ${space.getDisplayName()}`);
|
|
81
|
+
}
|
|
82
|
+
// Pagination warning
|
|
83
|
+
if (!flags.all && result.spaces.length < result.total) {
|
|
84
|
+
const remaining = result.total - result.spaces.length - flags.offset;
|
|
85
|
+
this.log(`\nShowing ${result.spaces.length} of ${result.total} spaces.`);
|
|
86
|
+
if (remaining > 0) {
|
|
87
|
+
this.log('Use --all to fetch all spaces, or use --limit and --offset for pagination.');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
this.error(error instanceof Error ? error.message : 'Failed to list spaces');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async validateAuth(tokenStore) {
|
|
96
|
+
const token = await tokenStore.load();
|
|
97
|
+
if (token === undefined) {
|
|
98
|
+
this.error('Not authenticated. Please run "br login" first.');
|
|
99
|
+
}
|
|
100
|
+
if (!token.isValid()) {
|
|
101
|
+
this.error('Authentication token expired. Please run "br login" again.');
|
|
102
|
+
}
|
|
103
|
+
return token;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { Space } from '../../core/domain/entities/space.js';
|
|
3
|
+
import type { Team } from '../../core/domain/entities/team.js';
|
|
4
|
+
import type { IProjectConfigStore } from '../../core/interfaces/i-project-config-store.js';
|
|
5
|
+
import type { ISpaceService } from '../../core/interfaces/i-space-service.js';
|
|
6
|
+
import type { ITeamService } from '../../core/interfaces/i-team-service.js';
|
|
7
|
+
import type { ITokenStore } from '../../core/interfaces/i-token-store.js';
|
|
8
|
+
export default class SpaceSwitch extends Command {
|
|
9
|
+
static description: string;
|
|
10
|
+
static examples: string[];
|
|
11
|
+
protected createServices(): {
|
|
12
|
+
projectConfigStore: IProjectConfigStore;
|
|
13
|
+
spaceService: ISpaceService;
|
|
14
|
+
teamService: ITeamService;
|
|
15
|
+
tokenStore: ITokenStore;
|
|
16
|
+
};
|
|
17
|
+
protected promptForSpaceSelection(spaces: Space[]): Promise<Space>;
|
|
18
|
+
protected promptForTeamSelection(teams: Team[]): Promise<Team>;
|
|
19
|
+
run(): Promise<void>;
|
|
20
|
+
}
|