byterover-cli 2.1.4 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/oclif/commands/locations.d.ts +14 -0
- package/dist/oclif/commands/locations.js +68 -0
- package/dist/oclif/commands/logout.d.ts +12 -0
- package/dist/oclif/commands/logout.js +59 -0
- package/dist/oclif/commands/status.js +3 -3
- package/dist/server/infra/daemon/brv-server.js +2 -0
- package/dist/server/infra/process/feature-handlers.d.ts +4 -1
- package/dist/server/infra/process/feature-handlers.js +9 -2
- package/dist/server/infra/transport/handlers/index.d.ts +2 -0
- package/dist/server/infra/transport/handlers/index.js +1 -0
- package/dist/server/infra/transport/handlers/locations-handler.d.ts +25 -0
- package/dist/server/infra/transport/handlers/locations-handler.js +64 -0
- package/dist/server/templates/skill/SKILL.md +19 -1
- package/dist/shared/transport/events/auth-events.d.ts +1 -0
- package/dist/shared/transport/events/index.d.ts +3 -0
- package/dist/shared/transport/events/index.js +3 -0
- package/dist/shared/transport/events/locations-events.d.ts +7 -0
- package/dist/shared/transport/events/locations-events.js +3 -0
- package/dist/shared/transport/types/dto.d.ts +11 -0
- package/dist/tui/features/commands/definitions/index.js +2 -0
- package/dist/tui/features/commands/definitions/locations.d.ts +2 -0
- package/dist/tui/features/commands/definitions/locations.js +11 -0
- package/dist/tui/features/locations/api/get-locations.d.ts +16 -0
- package/dist/tui/features/locations/api/get-locations.js +17 -0
- package/dist/tui/features/locations/components/locations-view.d.ts +3 -0
- package/dist/tui/features/locations/components/locations-view.js +25 -0
- package/dist/tui/features/locations/utils/format-locations.d.ts +2 -0
- package/dist/tui/features/locations/utils/format-locations.js +26 -0
- package/oclif.manifest.json +246 -167
- package/package.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { ProjectLocationDTO } from '../../shared/transport/types/dto.js';
|
|
3
|
+
import { type DaemonClientOptions } from '../lib/daemon-client.js';
|
|
4
|
+
export default class Locations extends Command {
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: string[];
|
|
7
|
+
static flags: {
|
|
8
|
+
format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
protected fetchLocations(options?: DaemonClientOptions): Promise<ProjectLocationDTO[]>;
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
private formatLocationEntry;
|
|
13
|
+
private formatTextOutput;
|
|
14
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { LocationsEvents } from '../../shared/transport/events/locations-events.js';
|
|
4
|
+
import { formatConnectionError, withDaemonRetry } from '../lib/daemon-client.js';
|
|
5
|
+
import { writeJsonResponse } from '../lib/json-response.js';
|
|
6
|
+
export default class Locations extends Command {
|
|
7
|
+
static description = 'List all registered projects and their context tree status';
|
|
8
|
+
static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --format json'];
|
|
9
|
+
static flags = {
|
|
10
|
+
format: Flags.string({
|
|
11
|
+
char: 'f',
|
|
12
|
+
default: 'text',
|
|
13
|
+
description: 'Output format',
|
|
14
|
+
options: ['text', 'json'],
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
async fetchLocations(options) {
|
|
18
|
+
return withDaemonRetry(async (client) => {
|
|
19
|
+
const response = await client.requestWithAck(LocationsEvents.GET);
|
|
20
|
+
return response.locations;
|
|
21
|
+
}, options);
|
|
22
|
+
}
|
|
23
|
+
async run() {
|
|
24
|
+
const { flags } = await this.parse(Locations);
|
|
25
|
+
const isJson = flags.format === 'json';
|
|
26
|
+
try {
|
|
27
|
+
const locations = await this.fetchLocations();
|
|
28
|
+
if (isJson) {
|
|
29
|
+
writeJsonResponse({ command: 'locations', data: { locations }, success: true });
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this.formatTextOutput(locations);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (isJson) {
|
|
37
|
+
writeJsonResponse({ command: 'locations', data: { error: formatConnectionError(error) }, success: false });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.log(formatConnectionError(error));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
formatLocationEntry(loc) {
|
|
45
|
+
const label = loc.isCurrent ? ' ' + chalk.green('[current]') : loc.isActive ? ' ' + chalk.yellow('[active]') : '';
|
|
46
|
+
const path = loc.isCurrent || loc.isActive ? chalk.bold(loc.projectPath) : loc.projectPath;
|
|
47
|
+
this.log(` ${path}${label}`);
|
|
48
|
+
if (loc.isInitialized) {
|
|
49
|
+
this.log(chalk.dim(' └─ .brv/context-tree/'));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
this.log(chalk.dim(' └─ .brv/context-tree/ (not initialized)'));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
formatTextOutput(locations) {
|
|
56
|
+
if (locations.length > 0) {
|
|
57
|
+
this.log(`Registered Projects — ${locations.length} found`);
|
|
58
|
+
this.log(chalk.dim('──────────────────────────────────────────'));
|
|
59
|
+
for (const loc of locations) {
|
|
60
|
+
this.formatLocationEntry(loc);
|
|
61
|
+
this.log('');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
this.log('Registered Projects — none found');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import { type AuthLogoutResponse } from '../../shared/transport/events/auth-events.js';
|
|
3
|
+
import { type DaemonClientOptions } from '../lib/daemon-client.js';
|
|
4
|
+
export default class Logout extends Command {
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: string[];
|
|
7
|
+
static flags: {
|
|
8
|
+
format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
protected performLogout(options?: DaemonClientOptions): Promise<AuthLogoutResponse>;
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { AuthEvents } from '../../shared/transport/events/auth-events.js';
|
|
3
|
+
import { formatConnectionError, withDaemonRetry } from '../lib/daemon-client.js';
|
|
4
|
+
import { writeJsonResponse } from '../lib/json-response.js';
|
|
5
|
+
export default class Logout extends Command {
|
|
6
|
+
static description = 'Disconnect from ByteRover cloud and clear stored credentials';
|
|
7
|
+
static examples = [
|
|
8
|
+
'<%= config.bin %> <%= command.id %>',
|
|
9
|
+
'',
|
|
10
|
+
'# JSON output (for automation)',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> --format json',
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
format: Flags.string({
|
|
15
|
+
default: 'text',
|
|
16
|
+
description: 'Output format (text or json)',
|
|
17
|
+
options: ['text', 'json'],
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
async performLogout(options) {
|
|
21
|
+
return withDaemonRetry(async (client) => client.requestWithAck(AuthEvents.LOGOUT), options);
|
|
22
|
+
}
|
|
23
|
+
async run() {
|
|
24
|
+
const { flags } = await this.parse(Logout);
|
|
25
|
+
const format = flags.format ?? 'text';
|
|
26
|
+
try {
|
|
27
|
+
if (format === 'text') {
|
|
28
|
+
this.log('Logging out...');
|
|
29
|
+
}
|
|
30
|
+
const response = await this.performLogout();
|
|
31
|
+
if (response.success) {
|
|
32
|
+
if (format === 'json') {
|
|
33
|
+
writeJsonResponse({ command: 'logout', data: {}, success: true });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.log('Logged out successfully');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const errorMessage = response.error ?? 'Logout failed';
|
|
41
|
+
if (format === 'json') {
|
|
42
|
+
writeJsonResponse({ command: 'logout', data: { error: errorMessage }, success: false });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.log(errorMessage);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const errorMessage = error instanceof Error ? error.message : 'Logout failed';
|
|
51
|
+
if (format === 'json') {
|
|
52
|
+
writeJsonResponse({ command: 'logout', data: { error: errorMessage }, success: false });
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
this.log(formatConnectionError(error));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -22,10 +22,10 @@ export default class Status extends Command {
|
|
|
22
22
|
}
|
|
23
23
|
async run() {
|
|
24
24
|
const { flags } = await this.parse(Status);
|
|
25
|
-
const
|
|
25
|
+
const isJson = flags.format === 'json';
|
|
26
26
|
try {
|
|
27
27
|
const status = await this.fetchStatus();
|
|
28
|
-
if (
|
|
28
|
+
if (isJson) {
|
|
29
29
|
writeJsonResponse({
|
|
30
30
|
command: 'status',
|
|
31
31
|
data: { ...status, cliVersion: this.config.version },
|
|
@@ -37,7 +37,7 @@ export default class Status extends Command {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
catch (error) {
|
|
40
|
-
if (
|
|
40
|
+
if (isJson) {
|
|
41
41
|
writeJsonResponse({
|
|
42
42
|
command: 'status',
|
|
43
43
|
data: { error: formatConnectionError(error) },
|
|
@@ -352,7 +352,9 @@ async function main() {
|
|
|
352
352
|
broadcastToProject(projectPath, event, data) {
|
|
353
353
|
broadcastToProjectRoom(projectRegistry, projectRouter, projectPath, event, data);
|
|
354
354
|
},
|
|
355
|
+
getActiveProjectPaths: () => clientManager.getActiveProjects(),
|
|
355
356
|
log,
|
|
357
|
+
projectRegistry,
|
|
356
358
|
providerConfigStore,
|
|
357
359
|
providerKeychainStore,
|
|
358
360
|
resolveProjectPath: (clientId) => clientManager.getClient(clientId)?.projectPath,
|
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { IProviderConfigStore } from '../../core/interfaces/i-provider-config-store.js';
|
|
8
8
|
import type { IProviderKeychainStore } from '../../core/interfaces/i-provider-keychain-store.js';
|
|
9
|
+
import type { IProjectRegistry } from '../../core/interfaces/project/i-project-registry.js';
|
|
9
10
|
import type { IAuthStateStore } from '../../core/interfaces/state/i-auth-state-store.js';
|
|
10
11
|
import type { ITransportServer } from '../../core/interfaces/transport/i-transport-server.js';
|
|
11
12
|
import type { ProjectBroadcaster, ProjectPathResolver } from '../transport/handlers/handler-types.js';
|
|
12
13
|
export interface FeatureHandlersOptions {
|
|
13
14
|
authStateStore: IAuthStateStore;
|
|
14
15
|
broadcastToProject: ProjectBroadcaster;
|
|
16
|
+
getActiveProjectPaths: () => string[];
|
|
15
17
|
log: (msg: string) => void;
|
|
18
|
+
projectRegistry: IProjectRegistry;
|
|
16
19
|
providerConfigStore: IProviderConfigStore;
|
|
17
20
|
providerKeychainStore: IProviderKeychainStore;
|
|
18
21
|
resolveProjectPath: ProjectPathResolver;
|
|
@@ -22,4 +25,4 @@ export interface FeatureHandlersOptions {
|
|
|
22
25
|
* Setup all feature handlers on the transport server.
|
|
23
26
|
* These handlers implement the TUI ↔ Server event contract (auth:*, config:*, status:*, etc.).
|
|
24
27
|
*/
|
|
25
|
-
export declare function setupFeatureHandlers({ authStateStore, broadcastToProject, log, providerConfigStore, providerKeychainStore, resolveProjectPath, transport, }: FeatureHandlersOptions): Promise<void>;
|
|
28
|
+
export declare function setupFeatureHandlers({ authStateStore, broadcastToProject, getActiveProjectPaths, log, projectRegistry, providerConfigStore, providerKeychainStore, resolveProjectPath, transport, }: FeatureHandlersOptions): Promise<void>;
|
|
@@ -29,13 +29,13 @@ import { HttpSpaceService } from '../space/http-space-service.js';
|
|
|
29
29
|
import { createTokenStore } from '../storage/token-store.js';
|
|
30
30
|
import { HttpTeamService } from '../team/http-team-service.js';
|
|
31
31
|
import { FsTemplateLoader } from '../template/fs-template-loader.js';
|
|
32
|
-
import { AuthHandler, ConfigHandler, ConnectorsHandler, HubHandler, InitHandler, ModelHandler, ProviderHandler, PullHandler, PushHandler, ResetHandler, SpaceHandler, StatusHandler, } from '../transport/handlers/index.js';
|
|
32
|
+
import { AuthHandler, ConfigHandler, ConnectorsHandler, HubHandler, InitHandler, LocationsHandler, ModelHandler, ProviderHandler, PullHandler, PushHandler, ResetHandler, SpaceHandler, StatusHandler, } from '../transport/handlers/index.js';
|
|
33
33
|
import { HttpUserService } from '../user/http-user-service.js';
|
|
34
34
|
/**
|
|
35
35
|
* Setup all feature handlers on the transport server.
|
|
36
36
|
* These handlers implement the TUI ↔ Server event contract (auth:*, config:*, status:*, etc.).
|
|
37
37
|
*/
|
|
38
|
-
export async function setupFeatureHandlers({ authStateStore, broadcastToProject, log, providerConfigStore, providerKeychainStore, resolveProjectPath, transport, }) {
|
|
38
|
+
export async function setupFeatureHandlers({ authStateStore, broadcastToProject, getActiveProjectPaths, log, projectRegistry, providerConfigStore, providerKeychainStore, resolveProjectPath, transport, }) {
|
|
39
39
|
const envConfig = getCurrentConfig();
|
|
40
40
|
const tokenStore = createTokenStore();
|
|
41
41
|
const projectConfigStore = new ProjectConfigStore();
|
|
@@ -90,6 +90,13 @@ export async function setupFeatureHandlers({ authStateStore, broadcastToProject,
|
|
|
90
90
|
tokenStore,
|
|
91
91
|
transport,
|
|
92
92
|
}).setup();
|
|
93
|
+
new LocationsHandler({
|
|
94
|
+
contextTreeService,
|
|
95
|
+
getActiveProjectPaths,
|
|
96
|
+
projectRegistry,
|
|
97
|
+
resolveProjectPath,
|
|
98
|
+
transport,
|
|
99
|
+
}).setup();
|
|
93
100
|
new PushHandler({
|
|
94
101
|
broadcastToProject,
|
|
95
102
|
cogitPushService,
|
|
@@ -10,6 +10,8 @@ export { HubHandler } from './hub-handler.js';
|
|
|
10
10
|
export type { HubHandlerDeps } from './hub-handler.js';
|
|
11
11
|
export { InitHandler } from './init-handler.js';
|
|
12
12
|
export type { InitHandlerDeps } from './init-handler.js';
|
|
13
|
+
export { LocationsHandler } from './locations-handler.js';
|
|
14
|
+
export type { LocationsHandlerDeps } from './locations-handler.js';
|
|
13
15
|
export { ModelHandler } from './model-handler.js';
|
|
14
16
|
export type { ModelHandlerDeps } from './model-handler.js';
|
|
15
17
|
export { ProviderHandler } from './provider-handler.js';
|
|
@@ -4,6 +4,7 @@ export { ConnectorsHandler } from './connectors-handler.js';
|
|
|
4
4
|
export { resolveRequiredProjectPath } from './handler-types.js';
|
|
5
5
|
export { HubHandler } from './hub-handler.js';
|
|
6
6
|
export { InitHandler } from './init-handler.js';
|
|
7
|
+
export { LocationsHandler } from './locations-handler.js';
|
|
7
8
|
export { ModelHandler } from './model-handler.js';
|
|
8
9
|
export { ProviderHandler } from './provider-handler.js';
|
|
9
10
|
export { PullHandler } from './pull-handler.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IContextTreeService } from '../../../core/interfaces/context-tree/i-context-tree-service.js';
|
|
2
|
+
import type { IProjectRegistry } from '../../../core/interfaces/project/i-project-registry.js';
|
|
3
|
+
import type { ITransportServer } from '../../../core/interfaces/transport/i-transport-server.js';
|
|
4
|
+
import { type ProjectPathResolver } from './handler-types.js';
|
|
5
|
+
export interface LocationsHandlerDeps {
|
|
6
|
+
contextTreeService: IContextTreeService;
|
|
7
|
+
getActiveProjectPaths: () => string[];
|
|
8
|
+
projectRegistry: IProjectRegistry;
|
|
9
|
+
resolveProjectPath: ProjectPathResolver;
|
|
10
|
+
transport: ITransportServer;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Handles locations:get event.
|
|
14
|
+
* Returns all registered project locations with context tree status.
|
|
15
|
+
*/
|
|
16
|
+
export declare class LocationsHandler {
|
|
17
|
+
private readonly contextTreeService;
|
|
18
|
+
private readonly getActiveProjectPaths;
|
|
19
|
+
private readonly projectRegistry;
|
|
20
|
+
private readonly resolveProjectPath;
|
|
21
|
+
private readonly transport;
|
|
22
|
+
constructor(deps: LocationsHandlerDeps);
|
|
23
|
+
setup(): void;
|
|
24
|
+
private buildLocations;
|
|
25
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { LocationsEvents } from '../../../../shared/transport/events/locations-events.js';
|
|
3
|
+
import { BRV_DIR, CONTEXT_TREE_DIR } from '../../../constants.js';
|
|
4
|
+
import { resolveRequiredProjectPath } from './handler-types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Handles locations:get event.
|
|
7
|
+
* Returns all registered project locations with context tree status.
|
|
8
|
+
*/
|
|
9
|
+
export class LocationsHandler {
|
|
10
|
+
contextTreeService;
|
|
11
|
+
getActiveProjectPaths;
|
|
12
|
+
projectRegistry;
|
|
13
|
+
resolveProjectPath;
|
|
14
|
+
transport;
|
|
15
|
+
constructor(deps) {
|
|
16
|
+
this.contextTreeService = deps.contextTreeService;
|
|
17
|
+
this.getActiveProjectPaths = deps.getActiveProjectPaths;
|
|
18
|
+
this.projectRegistry = deps.projectRegistry;
|
|
19
|
+
this.resolveProjectPath = deps.resolveProjectPath;
|
|
20
|
+
this.transport = deps.transport;
|
|
21
|
+
}
|
|
22
|
+
setup() {
|
|
23
|
+
this.transport.onRequest(LocationsEvents.GET, async (_data, clientId) => {
|
|
24
|
+
const projectPath = resolveRequiredProjectPath(this.resolveProjectPath, clientId);
|
|
25
|
+
try {
|
|
26
|
+
const locations = await this.buildLocations(projectPath);
|
|
27
|
+
return { locations };
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return { locations: [] };
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async buildLocations(currentProjectPath) {
|
|
35
|
+
const all = this.projectRegistry.getAll();
|
|
36
|
+
const activeSet = new Set(this.getActiveProjectPaths());
|
|
37
|
+
const results = await Promise.all([...all.entries()].map(async ([path]) => {
|
|
38
|
+
let isInitialized = false;
|
|
39
|
+
try {
|
|
40
|
+
isInitialized = await this.contextTreeService.exists(path);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// FS error — treat as not initialized
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
contextTreePath: join(path, BRV_DIR, CONTEXT_TREE_DIR),
|
|
47
|
+
isActive: activeSet.has(path) || path === currentProjectPath,
|
|
48
|
+
isCurrent: path === currentProjectPath,
|
|
49
|
+
isInitialized,
|
|
50
|
+
projectPath: path,
|
|
51
|
+
};
|
|
52
|
+
}));
|
|
53
|
+
// Sort: current first → active (has clients) → initialized → rest, all by registeredAt desc
|
|
54
|
+
return results.sort((a, b) => {
|
|
55
|
+
if (a.isCurrent !== b.isCurrent)
|
|
56
|
+
return a.isCurrent ? -1 : 1;
|
|
57
|
+
if (a.isActive !== b.isActive)
|
|
58
|
+
return a.isActive ? -1 : 1;
|
|
59
|
+
if (a.isInitialized !== b.isInitialized)
|
|
60
|
+
return a.isInitialized ? -1 : 1;
|
|
61
|
+
return (all.get(b.projectPath)?.registeredAt ?? 0) - (all.get(a.projectPath)?.registeredAt ?? 0);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -93,7 +93,25 @@ brv providers list
|
|
|
93
93
|
brv providers connect openai --api-key sk-xxx --model gpt-4.1
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
### 4.
|
|
96
|
+
### 4. Project Locations
|
|
97
|
+
**Overview:** List registered projects and their context tree paths. Returns project metadata including initialization status and active state. Use `-f json` for machine-readable output.
|
|
98
|
+
|
|
99
|
+
**Use this when:**
|
|
100
|
+
- You need to find a project's context tree path
|
|
101
|
+
- You need to check which projects are registered
|
|
102
|
+
- You need to verify if a project is initialized
|
|
103
|
+
|
|
104
|
+
**Do NOT use this when:**
|
|
105
|
+
- You already know the project path from your current context
|
|
106
|
+
- You need project content rather than metadata — use `brv query` instead
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
brv locations -f json
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
JSON fields: `projectPath`, `contextTreePath`, `isCurrent`, `isActive`, `isInitialized`.
|
|
113
|
+
|
|
114
|
+
### 5. Cloud Sync (Optional)
|
|
97
115
|
**Overview:** Sync your local knowledge with a team via ByteRover's cloud service. Requires ByteRover authentication.
|
|
98
116
|
|
|
99
117
|
**Setup steps:**
|
|
@@ -6,6 +6,7 @@ export * from './connector-events.js';
|
|
|
6
6
|
export * from './hub-events.js';
|
|
7
7
|
export * from './init-events.js';
|
|
8
8
|
export * from './llm-events.js';
|
|
9
|
+
export * from './locations-events.js';
|
|
9
10
|
export * from './model-events.js';
|
|
10
11
|
export * from './onboarding-events.js';
|
|
11
12
|
export * from './provider-events.js';
|
|
@@ -103,6 +104,8 @@ export declare const AllEventGroups: readonly [{
|
|
|
103
104
|
readonly EXECUTE: "reset:execute";
|
|
104
105
|
}, {
|
|
105
106
|
readonly SWITCHED: "session:switched";
|
|
107
|
+
}, {
|
|
108
|
+
readonly GET: "locations:get";
|
|
106
109
|
}, {
|
|
107
110
|
readonly LIST: "space:list";
|
|
108
111
|
readonly SWITCH: "space:switch";
|
|
@@ -8,6 +8,7 @@ export * from './connector-events.js';
|
|
|
8
8
|
export * from './hub-events.js';
|
|
9
9
|
export * from './init-events.js';
|
|
10
10
|
export * from './llm-events.js';
|
|
11
|
+
export * from './locations-events.js';
|
|
11
12
|
export * from './model-events.js';
|
|
12
13
|
export * from './onboarding-events.js';
|
|
13
14
|
export * from './provider-events.js';
|
|
@@ -26,6 +27,7 @@ import { ConnectorEvents } from './connector-events.js';
|
|
|
26
27
|
import { HubEvents } from './hub-events.js';
|
|
27
28
|
import { InitEvents } from './init-events.js';
|
|
28
29
|
import { LlmEvents } from './llm-events.js';
|
|
30
|
+
import { LocationsEvents } from './locations-events.js';
|
|
29
31
|
import { ModelEvents } from './model-events.js';
|
|
30
32
|
import { OnboardingEvents } from './onboarding-events.js';
|
|
31
33
|
import { ProviderEvents } from './provider-events.js';
|
|
@@ -55,6 +57,7 @@ export const AllEventGroups = [
|
|
|
55
57
|
PushEvents,
|
|
56
58
|
ResetEvents,
|
|
57
59
|
SessionEvents,
|
|
60
|
+
LocationsEvents,
|
|
58
61
|
SpaceEvents,
|
|
59
62
|
StatusEvents,
|
|
60
63
|
TaskEvents,
|
|
@@ -97,6 +97,17 @@ export interface HubEntryDTO {
|
|
|
97
97
|
type: 'agent-skill' | 'bundle';
|
|
98
98
|
version: string;
|
|
99
99
|
}
|
|
100
|
+
export interface ProjectLocationDTO {
|
|
101
|
+
/** Absolute path to the context tree directory (e.g., '/Users/foo/project/.brv/context-tree') */
|
|
102
|
+
contextTreePath: string;
|
|
103
|
+
/** True if this project has connected clients/agents or is the current project */
|
|
104
|
+
isActive: boolean;
|
|
105
|
+
/** True if this is the project the client is currently running from */
|
|
106
|
+
isCurrent: boolean;
|
|
107
|
+
/** True if .brv/context-tree exists */
|
|
108
|
+
isInitialized: boolean;
|
|
109
|
+
projectPath: string;
|
|
110
|
+
}
|
|
100
111
|
export interface StatusDTO {
|
|
101
112
|
authStatus: 'expired' | 'logged_in' | 'not_logged_in' | 'unknown';
|
|
102
113
|
contextTreeChanges?: ContextTreeChanges;
|
|
@@ -2,6 +2,7 @@ import { connectorsCommand } from './connectors.js';
|
|
|
2
2
|
import { curateCommand } from './curate.js';
|
|
3
3
|
import { exitCommand } from './exit.js';
|
|
4
4
|
import { hubCommand } from './hub.js';
|
|
5
|
+
import { locationsCommand } from './locations.js';
|
|
5
6
|
import { loginCommand } from './login.js';
|
|
6
7
|
import { logoutCommand } from './logout.js';
|
|
7
8
|
import { modelCommand } from './model.js';
|
|
@@ -22,6 +23,7 @@ import { statusCommand } from './status.js';
|
|
|
22
23
|
export const load = () => [
|
|
23
24
|
// Core workflow - most frequently used
|
|
24
25
|
statusCommand,
|
|
26
|
+
locationsCommand,
|
|
25
27
|
curateCommand,
|
|
26
28
|
queryCommand,
|
|
27
29
|
// Connectors management
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LocationsView } from '../../locations/components/locations-view.js';
|
|
3
|
+
export const locationsCommand = {
|
|
4
|
+
action() {
|
|
5
|
+
return {
|
|
6
|
+
render: ({ onCancel, onComplete }) => React.createElement(LocationsView, { onCancel, onComplete }),
|
|
7
|
+
};
|
|
8
|
+
},
|
|
9
|
+
description: 'List all registered projects and their context tree status',
|
|
10
|
+
name: 'locations',
|
|
11
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QueryConfig } from '../../../lib/react-query.js';
|
|
2
|
+
import { type LocationsGetResponse } from '../../../../shared/transport/events/index.js';
|
|
3
|
+
export declare const getLocations: () => Promise<LocationsGetResponse>;
|
|
4
|
+
export declare const getLocationsQueryOptions: () => import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<LocationsGetResponse, Error, LocationsGetResponse, string[]>, "queryFn"> & {
|
|
5
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<LocationsGetResponse, string[], never> | undefined;
|
|
6
|
+
} & {
|
|
7
|
+
queryKey: string[] & {
|
|
8
|
+
[dataTagSymbol]: LocationsGetResponse;
|
|
9
|
+
[dataTagErrorSymbol]: Error;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
type UseGetLocationsOptions = {
|
|
13
|
+
queryConfig?: QueryConfig<typeof getLocationsQueryOptions>;
|
|
14
|
+
};
|
|
15
|
+
export declare const useGetLocations: ({ queryConfig }?: UseGetLocationsOptions) => import("@tanstack/react-query").UseQueryResult<LocationsGetResponse, Error>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { queryOptions, useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { LocationsEvents } from '../../../../shared/transport/events/index.js';
|
|
3
|
+
import { useTransportStore } from '../../../stores/transport-store.js';
|
|
4
|
+
export const getLocations = () => {
|
|
5
|
+
const { apiClient } = useTransportStore.getState();
|
|
6
|
+
if (!apiClient)
|
|
7
|
+
return Promise.reject(new Error('Not connected'));
|
|
8
|
+
return apiClient.request(LocationsEvents.GET);
|
|
9
|
+
};
|
|
10
|
+
export const getLocationsQueryOptions = () => queryOptions({
|
|
11
|
+
queryFn: getLocations,
|
|
12
|
+
queryKey: ['locations'],
|
|
13
|
+
});
|
|
14
|
+
export const useGetLocations = ({ queryConfig } = {}) => useQuery({
|
|
15
|
+
...getLocationsQueryOptions(),
|
|
16
|
+
...queryConfig,
|
|
17
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text, useInput } from 'ink';
|
|
3
|
+
import Spinner from 'ink-spinner';
|
|
4
|
+
import { useEffect } from 'react';
|
|
5
|
+
import { useGetLocations } from '../api/get-locations.js';
|
|
6
|
+
import { formatLocations } from '../utils/format-locations.js';
|
|
7
|
+
export function LocationsView({ onCancel, onComplete }) {
|
|
8
|
+
const { data, error, isLoading } = useGetLocations();
|
|
9
|
+
useInput((_input, key) => {
|
|
10
|
+
if (key.escape)
|
|
11
|
+
onCancel();
|
|
12
|
+
});
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (data) {
|
|
15
|
+
onComplete(formatLocations(data.locations));
|
|
16
|
+
}
|
|
17
|
+
if (error) {
|
|
18
|
+
onComplete(`Failed to get locations: ${error.message}`);
|
|
19
|
+
}
|
|
20
|
+
}, [data, error, onComplete]);
|
|
21
|
+
if (isLoading) {
|
|
22
|
+
return (_jsxs(Text, { children: [_jsx(Spinner, { type: "dots" }), " Loading locations..."] }));
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
function formatLocationEntry(loc) {
|
|
3
|
+
const label = loc.isCurrent ? ' ' + chalk.green('[current]') : loc.isActive ? ' ' + chalk.yellow('[active]') : '';
|
|
4
|
+
const path = loc.isCurrent || loc.isActive ? chalk.bold(loc.projectPath) : loc.projectPath;
|
|
5
|
+
const lines = [` ${path}${label}`];
|
|
6
|
+
if (loc.isInitialized) {
|
|
7
|
+
lines.push(chalk.dim(' └─ .brv/context-tree/'));
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
lines.push(chalk.dim(' └─ .brv/context-tree/ (not initialized)'));
|
|
11
|
+
}
|
|
12
|
+
return lines;
|
|
13
|
+
}
|
|
14
|
+
export function formatLocations(locations) {
|
|
15
|
+
const lines = [];
|
|
16
|
+
if (locations.length > 0) {
|
|
17
|
+
lines.push(`Registered Projects — ${locations.length} found`, chalk.dim('──────────────────────────────────────────'));
|
|
18
|
+
for (const loc of locations) {
|
|
19
|
+
lines.push(...formatLocationEntry(loc), '');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
lines.push('Registered Projects — none found');
|
|
24
|
+
}
|
|
25
|
+
return lines.join('\n');
|
|
26
|
+
}
|
package/oclif.manifest.json
CHANGED
|
@@ -75,6 +75,45 @@
|
|
|
75
75
|
"hook-prompt-submit.js"
|
|
76
76
|
]
|
|
77
77
|
},
|
|
78
|
+
"locations": {
|
|
79
|
+
"aliases": [],
|
|
80
|
+
"args": {},
|
|
81
|
+
"description": "List all registered projects and their context tree status",
|
|
82
|
+
"examples": [
|
|
83
|
+
"<%= config.bin %> <%= command.id %>",
|
|
84
|
+
"<%= config.bin %> <%= command.id %> --format json"
|
|
85
|
+
],
|
|
86
|
+
"flags": {
|
|
87
|
+
"format": {
|
|
88
|
+
"char": "f",
|
|
89
|
+
"description": "Output format",
|
|
90
|
+
"name": "format",
|
|
91
|
+
"default": "text",
|
|
92
|
+
"hasDynamicHelp": false,
|
|
93
|
+
"multiple": false,
|
|
94
|
+
"options": [
|
|
95
|
+
"text",
|
|
96
|
+
"json"
|
|
97
|
+
],
|
|
98
|
+
"type": "option"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"hasDynamicHelp": false,
|
|
102
|
+
"hiddenAliases": [],
|
|
103
|
+
"id": "locations",
|
|
104
|
+
"pluginAlias": "byterover-cli",
|
|
105
|
+
"pluginName": "byterover-cli",
|
|
106
|
+
"pluginType": "core",
|
|
107
|
+
"strict": true,
|
|
108
|
+
"enableJsonFlag": false,
|
|
109
|
+
"isESM": true,
|
|
110
|
+
"relativePath": [
|
|
111
|
+
"dist",
|
|
112
|
+
"oclif",
|
|
113
|
+
"commands",
|
|
114
|
+
"locations.js"
|
|
115
|
+
]
|
|
116
|
+
},
|
|
78
117
|
"login": {
|
|
79
118
|
"aliases": [],
|
|
80
119
|
"args": {},
|
|
@@ -124,6 +163,46 @@
|
|
|
124
163
|
"login.js"
|
|
125
164
|
]
|
|
126
165
|
},
|
|
166
|
+
"logout": {
|
|
167
|
+
"aliases": [],
|
|
168
|
+
"args": {},
|
|
169
|
+
"description": "Disconnect from ByteRover cloud and clear stored credentials",
|
|
170
|
+
"examples": [
|
|
171
|
+
"<%= config.bin %> <%= command.id %>",
|
|
172
|
+
"",
|
|
173
|
+
"# JSON output (for automation)",
|
|
174
|
+
"<%= config.bin %> <%= command.id %> --format json"
|
|
175
|
+
],
|
|
176
|
+
"flags": {
|
|
177
|
+
"format": {
|
|
178
|
+
"description": "Output format (text or json)",
|
|
179
|
+
"name": "format",
|
|
180
|
+
"default": "text",
|
|
181
|
+
"hasDynamicHelp": false,
|
|
182
|
+
"multiple": false,
|
|
183
|
+
"options": [
|
|
184
|
+
"text",
|
|
185
|
+
"json"
|
|
186
|
+
],
|
|
187
|
+
"type": "option"
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"hasDynamicHelp": false,
|
|
191
|
+
"hiddenAliases": [],
|
|
192
|
+
"id": "logout",
|
|
193
|
+
"pluginAlias": "byterover-cli",
|
|
194
|
+
"pluginName": "byterover-cli",
|
|
195
|
+
"pluginType": "core",
|
|
196
|
+
"strict": true,
|
|
197
|
+
"enableJsonFlag": false,
|
|
198
|
+
"isESM": true,
|
|
199
|
+
"relativePath": [
|
|
200
|
+
"dist",
|
|
201
|
+
"oclif",
|
|
202
|
+
"commands",
|
|
203
|
+
"logout.js"
|
|
204
|
+
]
|
|
205
|
+
},
|
|
127
206
|
"main": {
|
|
128
207
|
"aliases": [],
|
|
129
208
|
"args": {},
|
|
@@ -857,15 +936,40 @@
|
|
|
857
936
|
"list.js"
|
|
858
937
|
]
|
|
859
938
|
},
|
|
860
|
-
"
|
|
939
|
+
"providers:connect": {
|
|
861
940
|
"aliases": [],
|
|
862
|
-
"args": {
|
|
863
|
-
|
|
941
|
+
"args": {
|
|
942
|
+
"provider": {
|
|
943
|
+
"description": "Provider ID to connect (e.g., anthropic, openai, openrouter)",
|
|
944
|
+
"name": "provider",
|
|
945
|
+
"required": true
|
|
946
|
+
}
|
|
947
|
+
},
|
|
948
|
+
"description": "Connect or switch to an LLM provider",
|
|
864
949
|
"examples": [
|
|
865
|
-
"<%= config.bin %>
|
|
866
|
-
"<%= config.bin %>
|
|
950
|
+
"<%= config.bin %> providers connect anthropic --api-key sk-xxx",
|
|
951
|
+
"<%= config.bin %> providers connect openai --api-key sk-xxx --model gpt-4.1",
|
|
952
|
+
"<%= config.bin %> providers connect byterover",
|
|
953
|
+
"<%= config.bin %> providers connect openai-compatible --base-url http://localhost:11434/v1",
|
|
954
|
+
"<%= config.bin %> providers connect openai-compatible --base-url http://localhost:11434/v1 --api-key sk-xxx --model llama3"
|
|
867
955
|
],
|
|
868
956
|
"flags": {
|
|
957
|
+
"api-key": {
|
|
958
|
+
"char": "k",
|
|
959
|
+
"description": "API key for the provider",
|
|
960
|
+
"name": "api-key",
|
|
961
|
+
"hasDynamicHelp": false,
|
|
962
|
+
"multiple": false,
|
|
963
|
+
"type": "option"
|
|
964
|
+
},
|
|
965
|
+
"base-url": {
|
|
966
|
+
"char": "b",
|
|
967
|
+
"description": "Base URL for OpenAI-compatible providers (e.g., http://localhost:11434/v1)",
|
|
968
|
+
"name": "base-url",
|
|
969
|
+
"hasDynamicHelp": false,
|
|
970
|
+
"multiple": false,
|
|
971
|
+
"type": "option"
|
|
972
|
+
},
|
|
869
973
|
"format": {
|
|
870
974
|
"description": "Output format (text or json)",
|
|
871
975
|
"name": "format",
|
|
@@ -877,11 +981,19 @@
|
|
|
877
981
|
"json"
|
|
878
982
|
],
|
|
879
983
|
"type": "option"
|
|
984
|
+
},
|
|
985
|
+
"model": {
|
|
986
|
+
"char": "m",
|
|
987
|
+
"description": "Model to set as active after connecting",
|
|
988
|
+
"name": "model",
|
|
989
|
+
"hasDynamicHelp": false,
|
|
990
|
+
"multiple": false,
|
|
991
|
+
"type": "option"
|
|
880
992
|
}
|
|
881
993
|
},
|
|
882
994
|
"hasDynamicHelp": false,
|
|
883
995
|
"hiddenAliases": [],
|
|
884
|
-
"id": "
|
|
996
|
+
"id": "providers:connect",
|
|
885
997
|
"pluginAlias": "byterover-cli",
|
|
886
998
|
"pluginName": "byterover-cli",
|
|
887
999
|
"pluginType": "core",
|
|
@@ -892,17 +1004,23 @@
|
|
|
892
1004
|
"dist",
|
|
893
1005
|
"oclif",
|
|
894
1006
|
"commands",
|
|
895
|
-
"
|
|
896
|
-
"
|
|
1007
|
+
"providers",
|
|
1008
|
+
"connect.js"
|
|
897
1009
|
]
|
|
898
1010
|
},
|
|
899
|
-
"
|
|
1011
|
+
"providers:disconnect": {
|
|
900
1012
|
"aliases": [],
|
|
901
|
-
"args": {
|
|
902
|
-
|
|
1013
|
+
"args": {
|
|
1014
|
+
"provider": {
|
|
1015
|
+
"description": "Provider ID to disconnect",
|
|
1016
|
+
"name": "provider",
|
|
1017
|
+
"required": true
|
|
1018
|
+
}
|
|
1019
|
+
},
|
|
1020
|
+
"description": "Disconnect an LLM provider",
|
|
903
1021
|
"examples": [
|
|
904
|
-
"<%= config.bin %>
|
|
905
|
-
"<%= config.bin %>
|
|
1022
|
+
"<%= config.bin %> providers disconnect anthropic",
|
|
1023
|
+
"<%= config.bin %> providers disconnect openai --format json"
|
|
906
1024
|
],
|
|
907
1025
|
"flags": {
|
|
908
1026
|
"format": {
|
|
@@ -916,19 +1034,11 @@
|
|
|
916
1034
|
"json"
|
|
917
1035
|
],
|
|
918
1036
|
"type": "option"
|
|
919
|
-
},
|
|
920
|
-
"provider": {
|
|
921
|
-
"char": "p",
|
|
922
|
-
"description": "Only list models for a specific provider",
|
|
923
|
-
"name": "provider",
|
|
924
|
-
"hasDynamicHelp": false,
|
|
925
|
-
"multiple": false,
|
|
926
|
-
"type": "option"
|
|
927
1037
|
}
|
|
928
1038
|
},
|
|
929
1039
|
"hasDynamicHelp": false,
|
|
930
1040
|
"hiddenAliases": [],
|
|
931
|
-
"id": "
|
|
1041
|
+
"id": "providers:disconnect",
|
|
932
1042
|
"pluginAlias": "byterover-cli",
|
|
933
1043
|
"pluginName": "byterover-cli",
|
|
934
1044
|
"pluginType": "core",
|
|
@@ -939,24 +1049,17 @@
|
|
|
939
1049
|
"dist",
|
|
940
1050
|
"oclif",
|
|
941
1051
|
"commands",
|
|
942
|
-
"
|
|
943
|
-
"
|
|
1052
|
+
"providers",
|
|
1053
|
+
"disconnect.js"
|
|
944
1054
|
]
|
|
945
1055
|
},
|
|
946
|
-
"
|
|
1056
|
+
"providers": {
|
|
947
1057
|
"aliases": [],
|
|
948
|
-
"args": {
|
|
949
|
-
|
|
950
|
-
"description": "Model ID to switch to (e.g., claude-sonnet-4-5, gpt-4.1)",
|
|
951
|
-
"name": "model",
|
|
952
|
-
"required": true
|
|
953
|
-
}
|
|
954
|
-
},
|
|
955
|
-
"description": "Switch the active model",
|
|
1058
|
+
"args": {},
|
|
1059
|
+
"description": "Show active provider and model",
|
|
956
1060
|
"examples": [
|
|
957
|
-
"<%= config.bin %>
|
|
958
|
-
"<%= config.bin %>
|
|
959
|
-
"<%= config.bin %> model switch claude-sonnet-4-5 --format json"
|
|
1061
|
+
"<%= config.bin %> providers",
|
|
1062
|
+
"<%= config.bin %> providers --format json"
|
|
960
1063
|
],
|
|
961
1064
|
"flags": {
|
|
962
1065
|
"format": {
|
|
@@ -970,19 +1073,11 @@
|
|
|
970
1073
|
"json"
|
|
971
1074
|
],
|
|
972
1075
|
"type": "option"
|
|
973
|
-
},
|
|
974
|
-
"provider": {
|
|
975
|
-
"char": "p",
|
|
976
|
-
"description": "Provider ID (defaults to active provider)",
|
|
977
|
-
"name": "provider",
|
|
978
|
-
"hasDynamicHelp": false,
|
|
979
|
-
"multiple": false,
|
|
980
|
-
"type": "option"
|
|
981
1076
|
}
|
|
982
1077
|
},
|
|
983
1078
|
"hasDynamicHelp": false,
|
|
984
1079
|
"hiddenAliases": [],
|
|
985
|
-
"id": "
|
|
1080
|
+
"id": "providers",
|
|
986
1081
|
"pluginAlias": "byterover-cli",
|
|
987
1082
|
"pluginName": "byterover-cli",
|
|
988
1083
|
"pluginType": "core",
|
|
@@ -993,22 +1088,21 @@
|
|
|
993
1088
|
"dist",
|
|
994
1089
|
"oclif",
|
|
995
1090
|
"commands",
|
|
996
|
-
"
|
|
997
|
-
"
|
|
1091
|
+
"providers",
|
|
1092
|
+
"index.js"
|
|
998
1093
|
]
|
|
999
1094
|
},
|
|
1000
|
-
"
|
|
1095
|
+
"providers:list": {
|
|
1001
1096
|
"aliases": [],
|
|
1002
1097
|
"args": {},
|
|
1003
|
-
"description": "List all
|
|
1098
|
+
"description": "List all available providers and their connection status",
|
|
1004
1099
|
"examples": [
|
|
1005
|
-
"<%= config.bin %>
|
|
1006
|
-
"<%= config.bin %>
|
|
1100
|
+
"<%= config.bin %> providers list",
|
|
1101
|
+
"<%= config.bin %> providers list --format json"
|
|
1007
1102
|
],
|
|
1008
1103
|
"flags": {
|
|
1009
1104
|
"format": {
|
|
1010
|
-
"
|
|
1011
|
-
"description": "Output format",
|
|
1105
|
+
"description": "Output format (text or json)",
|
|
1012
1106
|
"name": "format",
|
|
1013
1107
|
"default": "text",
|
|
1014
1108
|
"hasDynamicHelp": false,
|
|
@@ -1022,7 +1116,7 @@
|
|
|
1022
1116
|
},
|
|
1023
1117
|
"hasDynamicHelp": false,
|
|
1024
1118
|
"hiddenAliases": [],
|
|
1025
|
-
"id": "
|
|
1119
|
+
"id": "providers:list",
|
|
1026
1120
|
"pluginAlias": "byterover-cli",
|
|
1027
1121
|
"pluginName": "byterover-cli",
|
|
1028
1122
|
"pluginType": "core",
|
|
@@ -1033,22 +1127,27 @@
|
|
|
1033
1127
|
"dist",
|
|
1034
1128
|
"oclif",
|
|
1035
1129
|
"commands",
|
|
1036
|
-
"
|
|
1130
|
+
"providers",
|
|
1037
1131
|
"list.js"
|
|
1038
1132
|
]
|
|
1039
1133
|
},
|
|
1040
|
-
"
|
|
1134
|
+
"providers:switch": {
|
|
1041
1135
|
"aliases": [],
|
|
1042
|
-
"args": {
|
|
1043
|
-
|
|
1136
|
+
"args": {
|
|
1137
|
+
"provider": {
|
|
1138
|
+
"description": "Provider ID to switch to (e.g., anthropic, openai)",
|
|
1139
|
+
"name": "provider",
|
|
1140
|
+
"required": true
|
|
1141
|
+
}
|
|
1142
|
+
},
|
|
1143
|
+
"description": "Switch the active provider",
|
|
1044
1144
|
"examples": [
|
|
1045
|
-
"<%= config.bin %>
|
|
1046
|
-
"<%= config.bin %>
|
|
1145
|
+
"<%= config.bin %> providers switch anthropic",
|
|
1146
|
+
"<%= config.bin %> providers switch openai --format json"
|
|
1047
1147
|
],
|
|
1048
1148
|
"flags": {
|
|
1049
1149
|
"format": {
|
|
1050
|
-
"
|
|
1051
|
-
"description": "Output format",
|
|
1150
|
+
"description": "Output format (text or json)",
|
|
1052
1151
|
"name": "format",
|
|
1053
1152
|
"default": "text",
|
|
1054
1153
|
"hasDynamicHelp": false,
|
|
@@ -1058,29 +1157,11 @@
|
|
|
1058
1157
|
"json"
|
|
1059
1158
|
],
|
|
1060
1159
|
"type": "option"
|
|
1061
|
-
},
|
|
1062
|
-
"name": {
|
|
1063
|
-
"char": "n",
|
|
1064
|
-
"description": "Name of the space to switch to",
|
|
1065
|
-
"name": "name",
|
|
1066
|
-
"required": true,
|
|
1067
|
-
"hasDynamicHelp": false,
|
|
1068
|
-
"multiple": false,
|
|
1069
|
-
"type": "option"
|
|
1070
|
-
},
|
|
1071
|
-
"team": {
|
|
1072
|
-
"char": "t",
|
|
1073
|
-
"description": "Team name",
|
|
1074
|
-
"name": "team",
|
|
1075
|
-
"required": true,
|
|
1076
|
-
"hasDynamicHelp": false,
|
|
1077
|
-
"multiple": false,
|
|
1078
|
-
"type": "option"
|
|
1079
1160
|
}
|
|
1080
1161
|
},
|
|
1081
1162
|
"hasDynamicHelp": false,
|
|
1082
1163
|
"hiddenAliases": [],
|
|
1083
|
-
"id": "
|
|
1164
|
+
"id": "providers:switch",
|
|
1084
1165
|
"pluginAlias": "byterover-cli",
|
|
1085
1166
|
"pluginName": "byterover-cli",
|
|
1086
1167
|
"pluginType": "core",
|
|
@@ -1091,44 +1172,19 @@
|
|
|
1091
1172
|
"dist",
|
|
1092
1173
|
"oclif",
|
|
1093
1174
|
"commands",
|
|
1094
|
-
"
|
|
1175
|
+
"providers",
|
|
1095
1176
|
"switch.js"
|
|
1096
1177
|
]
|
|
1097
1178
|
},
|
|
1098
|
-
"
|
|
1179
|
+
"model": {
|
|
1099
1180
|
"aliases": [],
|
|
1100
|
-
"args": {
|
|
1101
|
-
|
|
1102
|
-
"description": "Provider ID to connect (e.g., anthropic, openai, openrouter)",
|
|
1103
|
-
"name": "provider",
|
|
1104
|
-
"required": true
|
|
1105
|
-
}
|
|
1106
|
-
},
|
|
1107
|
-
"description": "Connect or switch to an LLM provider",
|
|
1181
|
+
"args": {},
|
|
1182
|
+
"description": "Show the active model",
|
|
1108
1183
|
"examples": [
|
|
1109
|
-
"<%= config.bin %>
|
|
1110
|
-
"<%= config.bin %>
|
|
1111
|
-
"<%= config.bin %> providers connect byterover",
|
|
1112
|
-
"<%= config.bin %> providers connect openai-compatible --base-url http://localhost:11434/v1",
|
|
1113
|
-
"<%= config.bin %> providers connect openai-compatible --base-url http://localhost:11434/v1 --api-key sk-xxx --model llama3"
|
|
1184
|
+
"<%= config.bin %> model",
|
|
1185
|
+
"<%= config.bin %> model --format json"
|
|
1114
1186
|
],
|
|
1115
1187
|
"flags": {
|
|
1116
|
-
"api-key": {
|
|
1117
|
-
"char": "k",
|
|
1118
|
-
"description": "API key for the provider",
|
|
1119
|
-
"name": "api-key",
|
|
1120
|
-
"hasDynamicHelp": false,
|
|
1121
|
-
"multiple": false,
|
|
1122
|
-
"type": "option"
|
|
1123
|
-
},
|
|
1124
|
-
"base-url": {
|
|
1125
|
-
"char": "b",
|
|
1126
|
-
"description": "Base URL for OpenAI-compatible providers (e.g., http://localhost:11434/v1)",
|
|
1127
|
-
"name": "base-url",
|
|
1128
|
-
"hasDynamicHelp": false,
|
|
1129
|
-
"multiple": false,
|
|
1130
|
-
"type": "option"
|
|
1131
|
-
},
|
|
1132
1188
|
"format": {
|
|
1133
1189
|
"description": "Output format (text or json)",
|
|
1134
1190
|
"name": "format",
|
|
@@ -1140,19 +1196,11 @@
|
|
|
1140
1196
|
"json"
|
|
1141
1197
|
],
|
|
1142
1198
|
"type": "option"
|
|
1143
|
-
},
|
|
1144
|
-
"model": {
|
|
1145
|
-
"char": "m",
|
|
1146
|
-
"description": "Model to set as active after connecting",
|
|
1147
|
-
"name": "model",
|
|
1148
|
-
"hasDynamicHelp": false,
|
|
1149
|
-
"multiple": false,
|
|
1150
|
-
"type": "option"
|
|
1151
1199
|
}
|
|
1152
1200
|
},
|
|
1153
1201
|
"hasDynamicHelp": false,
|
|
1154
1202
|
"hiddenAliases": [],
|
|
1155
|
-
"id": "
|
|
1203
|
+
"id": "model",
|
|
1156
1204
|
"pluginAlias": "byterover-cli",
|
|
1157
1205
|
"pluginName": "byterover-cli",
|
|
1158
1206
|
"pluginType": "core",
|
|
@@ -1163,23 +1211,17 @@
|
|
|
1163
1211
|
"dist",
|
|
1164
1212
|
"oclif",
|
|
1165
1213
|
"commands",
|
|
1166
|
-
"
|
|
1167
|
-
"
|
|
1214
|
+
"model",
|
|
1215
|
+
"index.js"
|
|
1168
1216
|
]
|
|
1169
1217
|
},
|
|
1170
|
-
"
|
|
1218
|
+
"model:list": {
|
|
1171
1219
|
"aliases": [],
|
|
1172
|
-
"args": {
|
|
1173
|
-
|
|
1174
|
-
"description": "Provider ID to disconnect",
|
|
1175
|
-
"name": "provider",
|
|
1176
|
-
"required": true
|
|
1177
|
-
}
|
|
1178
|
-
},
|
|
1179
|
-
"description": "Disconnect an LLM provider",
|
|
1220
|
+
"args": {},
|
|
1221
|
+
"description": "List available models from all connected providers",
|
|
1180
1222
|
"examples": [
|
|
1181
|
-
"<%= config.bin %>
|
|
1182
|
-
"<%= config.bin %>
|
|
1223
|
+
"<%= config.bin %> model list",
|
|
1224
|
+
"<%= config.bin %> model list --format json"
|
|
1183
1225
|
],
|
|
1184
1226
|
"flags": {
|
|
1185
1227
|
"format": {
|
|
@@ -1193,11 +1235,19 @@
|
|
|
1193
1235
|
"json"
|
|
1194
1236
|
],
|
|
1195
1237
|
"type": "option"
|
|
1238
|
+
},
|
|
1239
|
+
"provider": {
|
|
1240
|
+
"char": "p",
|
|
1241
|
+
"description": "Only list models for a specific provider",
|
|
1242
|
+
"name": "provider",
|
|
1243
|
+
"hasDynamicHelp": false,
|
|
1244
|
+
"multiple": false,
|
|
1245
|
+
"type": "option"
|
|
1196
1246
|
}
|
|
1197
1247
|
},
|
|
1198
1248
|
"hasDynamicHelp": false,
|
|
1199
1249
|
"hiddenAliases": [],
|
|
1200
|
-
"id": "
|
|
1250
|
+
"id": "model:list",
|
|
1201
1251
|
"pluginAlias": "byterover-cli",
|
|
1202
1252
|
"pluginName": "byterover-cli",
|
|
1203
1253
|
"pluginType": "core",
|
|
@@ -1208,17 +1258,24 @@
|
|
|
1208
1258
|
"dist",
|
|
1209
1259
|
"oclif",
|
|
1210
1260
|
"commands",
|
|
1211
|
-
"
|
|
1212
|
-
"
|
|
1261
|
+
"model",
|
|
1262
|
+
"list.js"
|
|
1213
1263
|
]
|
|
1214
1264
|
},
|
|
1215
|
-
"
|
|
1265
|
+
"model:switch": {
|
|
1216
1266
|
"aliases": [],
|
|
1217
|
-
"args": {
|
|
1218
|
-
|
|
1267
|
+
"args": {
|
|
1268
|
+
"model": {
|
|
1269
|
+
"description": "Model ID to switch to (e.g., claude-sonnet-4-5, gpt-4.1)",
|
|
1270
|
+
"name": "model",
|
|
1271
|
+
"required": true
|
|
1272
|
+
}
|
|
1273
|
+
},
|
|
1274
|
+
"description": "Switch the active model",
|
|
1219
1275
|
"examples": [
|
|
1220
|
-
"<%= config.bin %>
|
|
1221
|
-
"<%= config.bin %>
|
|
1276
|
+
"<%= config.bin %> model switch claude-sonnet-4-5",
|
|
1277
|
+
"<%= config.bin %> model switch gpt-4.1 --provider openai",
|
|
1278
|
+
"<%= config.bin %> model switch claude-sonnet-4-5 --format json"
|
|
1222
1279
|
],
|
|
1223
1280
|
"flags": {
|
|
1224
1281
|
"format": {
|
|
@@ -1232,11 +1289,19 @@
|
|
|
1232
1289
|
"json"
|
|
1233
1290
|
],
|
|
1234
1291
|
"type": "option"
|
|
1292
|
+
},
|
|
1293
|
+
"provider": {
|
|
1294
|
+
"char": "p",
|
|
1295
|
+
"description": "Provider ID (defaults to active provider)",
|
|
1296
|
+
"name": "provider",
|
|
1297
|
+
"hasDynamicHelp": false,
|
|
1298
|
+
"multiple": false,
|
|
1299
|
+
"type": "option"
|
|
1235
1300
|
}
|
|
1236
1301
|
},
|
|
1237
1302
|
"hasDynamicHelp": false,
|
|
1238
1303
|
"hiddenAliases": [],
|
|
1239
|
-
"id": "
|
|
1304
|
+
"id": "model:switch",
|
|
1240
1305
|
"pluginAlias": "byterover-cli",
|
|
1241
1306
|
"pluginName": "byterover-cli",
|
|
1242
1307
|
"pluginType": "core",
|
|
@@ -1247,21 +1312,22 @@
|
|
|
1247
1312
|
"dist",
|
|
1248
1313
|
"oclif",
|
|
1249
1314
|
"commands",
|
|
1250
|
-
"
|
|
1251
|
-
"
|
|
1315
|
+
"model",
|
|
1316
|
+
"switch.js"
|
|
1252
1317
|
]
|
|
1253
1318
|
},
|
|
1254
|
-
"
|
|
1319
|
+
"space:list": {
|
|
1255
1320
|
"aliases": [],
|
|
1256
1321
|
"args": {},
|
|
1257
|
-
"description": "List all
|
|
1322
|
+
"description": "List all teams and spaces",
|
|
1258
1323
|
"examples": [
|
|
1259
|
-
"<%= config.bin %>
|
|
1260
|
-
"<%= config.bin %>
|
|
1324
|
+
"<%= config.bin %> space list",
|
|
1325
|
+
"<%= config.bin %> space list --format json"
|
|
1261
1326
|
],
|
|
1262
1327
|
"flags": {
|
|
1263
1328
|
"format": {
|
|
1264
|
-
"
|
|
1329
|
+
"char": "f",
|
|
1330
|
+
"description": "Output format",
|
|
1265
1331
|
"name": "format",
|
|
1266
1332
|
"default": "text",
|
|
1267
1333
|
"hasDynamicHelp": false,
|
|
@@ -1275,7 +1341,7 @@
|
|
|
1275
1341
|
},
|
|
1276
1342
|
"hasDynamicHelp": false,
|
|
1277
1343
|
"hiddenAliases": [],
|
|
1278
|
-
"id": "
|
|
1344
|
+
"id": "space:list",
|
|
1279
1345
|
"pluginAlias": "byterover-cli",
|
|
1280
1346
|
"pluginName": "byterover-cli",
|
|
1281
1347
|
"pluginType": "core",
|
|
@@ -1286,27 +1352,22 @@
|
|
|
1286
1352
|
"dist",
|
|
1287
1353
|
"oclif",
|
|
1288
1354
|
"commands",
|
|
1289
|
-
"
|
|
1355
|
+
"space",
|
|
1290
1356
|
"list.js"
|
|
1291
1357
|
]
|
|
1292
1358
|
},
|
|
1293
|
-
"
|
|
1359
|
+
"space:switch": {
|
|
1294
1360
|
"aliases": [],
|
|
1295
|
-
"args": {
|
|
1296
|
-
|
|
1297
|
-
"description": "Provider ID to switch to (e.g., anthropic, openai)",
|
|
1298
|
-
"name": "provider",
|
|
1299
|
-
"required": true
|
|
1300
|
-
}
|
|
1301
|
-
},
|
|
1302
|
-
"description": "Switch the active provider",
|
|
1361
|
+
"args": {},
|
|
1362
|
+
"description": "Switch to a different space",
|
|
1303
1363
|
"examples": [
|
|
1304
|
-
"<%= config.bin %>
|
|
1305
|
-
"<%= config.bin %>
|
|
1364
|
+
"<%= config.bin %> space switch --team acme --name my-space",
|
|
1365
|
+
"<%= config.bin %> space switch --team acme --name my-space --format json"
|
|
1306
1366
|
],
|
|
1307
1367
|
"flags": {
|
|
1308
1368
|
"format": {
|
|
1309
|
-
"
|
|
1369
|
+
"char": "f",
|
|
1370
|
+
"description": "Output format",
|
|
1310
1371
|
"name": "format",
|
|
1311
1372
|
"default": "text",
|
|
1312
1373
|
"hasDynamicHelp": false,
|
|
@@ -1316,11 +1377,29 @@
|
|
|
1316
1377
|
"json"
|
|
1317
1378
|
],
|
|
1318
1379
|
"type": "option"
|
|
1380
|
+
},
|
|
1381
|
+
"name": {
|
|
1382
|
+
"char": "n",
|
|
1383
|
+
"description": "Name of the space to switch to",
|
|
1384
|
+
"name": "name",
|
|
1385
|
+
"required": true,
|
|
1386
|
+
"hasDynamicHelp": false,
|
|
1387
|
+
"multiple": false,
|
|
1388
|
+
"type": "option"
|
|
1389
|
+
},
|
|
1390
|
+
"team": {
|
|
1391
|
+
"char": "t",
|
|
1392
|
+
"description": "Team name",
|
|
1393
|
+
"name": "team",
|
|
1394
|
+
"required": true,
|
|
1395
|
+
"hasDynamicHelp": false,
|
|
1396
|
+
"multiple": false,
|
|
1397
|
+
"type": "option"
|
|
1319
1398
|
}
|
|
1320
1399
|
},
|
|
1321
1400
|
"hasDynamicHelp": false,
|
|
1322
1401
|
"hiddenAliases": [],
|
|
1323
|
-
"id": "
|
|
1402
|
+
"id": "space:switch",
|
|
1324
1403
|
"pluginAlias": "byterover-cli",
|
|
1325
1404
|
"pluginName": "byterover-cli",
|
|
1326
1405
|
"pluginType": "core",
|
|
@@ -1331,7 +1410,7 @@
|
|
|
1331
1410
|
"dist",
|
|
1332
1411
|
"oclif",
|
|
1333
1412
|
"commands",
|
|
1334
|
-
"
|
|
1413
|
+
"space",
|
|
1335
1414
|
"switch.js"
|
|
1336
1415
|
]
|
|
1337
1416
|
},
|
|
@@ -1534,5 +1613,5 @@
|
|
|
1534
1613
|
]
|
|
1535
1614
|
}
|
|
1536
1615
|
},
|
|
1537
|
-
"version": "2.
|
|
1616
|
+
"version": "2.2.0"
|
|
1538
1617
|
}
|