byterover-cli 2.4.0 → 2.5.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/providers/index.d.ts +1 -0
- package/dist/oclif/commands/providers/index.js +9 -1
- package/dist/server/constants.d.ts +1 -1
- package/dist/server/constants.js +1 -1
- package/dist/server/core/domain/entities/provider-config.js +1 -1
- package/dist/server/core/domain/entities/provider-registry.js +1 -1
- package/dist/server/core/domain/transport/schemas.d.ts +2 -0
- package/dist/server/infra/auth/oauth-service.js +2 -0
- package/dist/server/infra/auth/oidc-discovery-service.js +1 -0
- package/dist/server/infra/cogit/http-cogit-push-service.js +1 -0
- package/dist/server/infra/daemon/agent-process.js +4 -11
- package/dist/server/infra/daemon/brv-server.js +10 -4
- package/dist/server/infra/daemon/task-validation.d.ts +18 -0
- package/dist/server/infra/daemon/task-validation.js +42 -0
- package/dist/server/infra/http/authenticated-http-client.js +3 -0
- package/dist/server/infra/http/models-dev-client.js +1 -0
- package/dist/server/infra/http/openrouter-api-client.js +1 -0
- package/dist/server/infra/http/provider-model-fetchers.js +3 -0
- package/dist/server/infra/hub/hub-install-service.js +1 -0
- package/dist/server/infra/hub/hub-registry-service.js +1 -0
- package/dist/server/infra/memory/http-memory-storage-service.js +1 -0
- package/dist/server/infra/process/feature-handlers.js +1 -0
- package/dist/server/infra/provider/provider-config-resolver.d.ts +8 -1
- package/dist/server/infra/provider/provider-config-resolver.js +11 -12
- package/dist/server/infra/provider-oauth/refresh-token-exchange.js +1 -0
- package/dist/server/infra/provider-oauth/token-exchange.js +1 -0
- package/dist/server/infra/transport/handlers/provider-handler.d.ts +4 -0
- package/dist/server/infra/transport/handlers/provider-handler.js +14 -1
- package/dist/shared/transport/events/provider-events.d.ts +4 -0
- package/dist/tui/features/onboarding/hooks/use-app-view-mode.d.ts +23 -8
- package/dist/tui/features/onboarding/hooks/use-app-view-mode.js +29 -17
- package/dist/tui/features/provider/components/provider-flow.d.ts +1 -1
- package/dist/tui/features/provider/components/provider-flow.js +39 -4
- package/oclif.manifest.json +99 -99
- package/package.json +1 -1
|
@@ -22,6 +22,7 @@ export default class Provider extends Command {
|
|
|
22
22
|
const provider = providers.find((p) => p.id === active.activeProviderId);
|
|
23
23
|
return {
|
|
24
24
|
activeModel: active.activeModel,
|
|
25
|
+
loginRequired: active.loginRequired,
|
|
25
26
|
providerId: active.activeProviderId,
|
|
26
27
|
providerName: provider?.name ?? active.activeProviderId,
|
|
27
28
|
};
|
|
@@ -33,7 +34,11 @@ export default class Provider extends Command {
|
|
|
33
34
|
try {
|
|
34
35
|
const info = await this.fetchActiveProvider();
|
|
35
36
|
if (format === 'json') {
|
|
36
|
-
|
|
37
|
+
const { loginRequired, ...rest } = info;
|
|
38
|
+
const data = loginRequired
|
|
39
|
+
? { ...rest, warning: "Not logged in. Run 'brv login' to authenticate." }
|
|
40
|
+
: rest;
|
|
41
|
+
writeJsonResponse({ command: 'providers', data, success: true });
|
|
37
42
|
}
|
|
38
43
|
else {
|
|
39
44
|
this.log(`Provider: ${info.providerName} (${info.providerId})`);
|
|
@@ -45,6 +50,9 @@ export default class Provider extends Command {
|
|
|
45
50
|
this.log('Model: Not set. Run "brv model list" to see available models, or "brv model switch <model>" to set one.');
|
|
46
51
|
}
|
|
47
52
|
}
|
|
53
|
+
if (info.loginRequired) {
|
|
54
|
+
this.log("Warning: Not logged in. Run 'brv login' to authenticate.");
|
|
55
|
+
}
|
|
48
56
|
}
|
|
49
57
|
}
|
|
50
58
|
catch (error) {
|
|
@@ -55,7 +55,7 @@ export declare const SHUTDOWN_FORCE_EXIT_MS = 5000;
|
|
|
55
55
|
export declare const AUTH_STATE_POLL_INTERVAL_MS = 5000;
|
|
56
56
|
export declare const AGENT_MAX_CONCURRENT_TASKS = 5;
|
|
57
57
|
export declare const AGENT_POOL_MAX_SIZE = 10;
|
|
58
|
-
export declare const AGENT_PROCESS_READY_TIMEOUT_MS =
|
|
58
|
+
export declare const AGENT_PROCESS_READY_TIMEOUT_MS = 30000;
|
|
59
59
|
export declare const AGENT_PROCESS_STOP_TIMEOUT_MS = 5000;
|
|
60
60
|
export declare const CURATE_LOG_DIR = "curate-log";
|
|
61
61
|
export declare const CURATE_LOG_ID_PREFIX = "cur";
|
package/dist/server/constants.js
CHANGED
|
@@ -75,7 +75,7 @@ export const AUTH_STATE_POLL_INTERVAL_MS = 5000; // Poll token store every 5s
|
|
|
75
75
|
// Agent Pool (T6)
|
|
76
76
|
export const AGENT_MAX_CONCURRENT_TASKS = 5; // Max parallel curate/query tasks per agent process
|
|
77
77
|
export const AGENT_POOL_MAX_SIZE = 10;
|
|
78
|
-
export const AGENT_PROCESS_READY_TIMEOUT_MS =
|
|
78
|
+
export const AGENT_PROCESS_READY_TIMEOUT_MS = 30_000; // 30s max wait for child process to register
|
|
79
79
|
export const AGENT_PROCESS_STOP_TIMEOUT_MS = 5000; // 5s max wait for child process to stop gracefully
|
|
80
80
|
// Curate log
|
|
81
81
|
export const CURATE_LOG_DIR = 'curate-log';
|
|
@@ -184,7 +184,7 @@ export class ProviderConfig {
|
|
|
184
184
|
withProviderDisconnected(providerId) {
|
|
185
185
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
186
186
|
const { [providerId]: _removed, ...remainingProviders } = this.providers;
|
|
187
|
-
const newActiveProvider = this.activeProvider === providerId ? '
|
|
187
|
+
const newActiveProvider = this.activeProvider === providerId ? '' : this.activeProvider;
|
|
188
188
|
return new ProviderConfig({
|
|
189
189
|
activeProvider: newActiveProvider,
|
|
190
190
|
providers: remainingProviders,
|
|
@@ -26,7 +26,7 @@ export const PROVIDER_REGISTRY = {
|
|
|
26
26
|
byterover: {
|
|
27
27
|
baseUrl: '',
|
|
28
28
|
category: 'popular',
|
|
29
|
-
description: 'Built-in LLM,
|
|
29
|
+
description: 'Built-in LLM, logged-in ByteRover account required. Limited free usage.',
|
|
30
30
|
headers: {},
|
|
31
31
|
id: 'byterover',
|
|
32
32
|
modelsEndpoint: '',
|
|
@@ -465,6 +465,8 @@ export interface ProviderConfigResponse {
|
|
|
465
465
|
activeProvider: string;
|
|
466
466
|
/** How the provider was authenticated ('api-key' | 'oauth'). Undefined for internal providers. */
|
|
467
467
|
authMethod?: 'api-key' | 'oauth';
|
|
468
|
+
/** True when the active provider requires login but the user is not logged in. */
|
|
469
|
+
loginRequired?: boolean;
|
|
468
470
|
maxInputTokens?: number;
|
|
469
471
|
openRouterApiKey?: string;
|
|
470
472
|
provider?: string;
|
|
@@ -52,6 +52,7 @@ export class OAuthService {
|
|
|
52
52
|
},
|
|
53
53
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
54
54
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
55
|
+
proxy: false,
|
|
55
56
|
});
|
|
56
57
|
return this.parseTokenResponse(response.data);
|
|
57
58
|
}
|
|
@@ -97,6 +98,7 @@ export class OAuthService {
|
|
|
97
98
|
}, {
|
|
98
99
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
99
100
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
101
|
+
proxy: false,
|
|
100
102
|
});
|
|
101
103
|
return this.parseTokenResponse(response.data);
|
|
102
104
|
}
|
|
@@ -38,6 +38,7 @@ import { QueryExecutor } from '../executor/query-executor.js';
|
|
|
38
38
|
import { AgentInstanceDiscovery } from '../transport/agent-instance-discovery.js';
|
|
39
39
|
import { createAgentLogger } from './agent-logger.js';
|
|
40
40
|
import { resolveSessionId } from './session-resolver.js';
|
|
41
|
+
import { validateProviderForTask } from './task-validation.js';
|
|
41
42
|
// ============================================================================
|
|
42
43
|
// Environment
|
|
43
44
|
// ============================================================================
|
|
@@ -308,17 +309,9 @@ async function executeTask(task, curateExecutor, folderPackExecutor, queryExecut
|
|
|
308
309
|
if (!transport || !agent)
|
|
309
310
|
return;
|
|
310
311
|
const freshProviderConfig = await transport.requestWithAck(TransportStateEventNames.GET_PROVIDER_CONFIG);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
transport.request(TransportTaskEventNames.ERROR, { clientId, error, taskId });
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
if (freshProviderConfig.providerKeyMissing) {
|
|
317
|
-
const modelInfo = freshProviderConfig.activeModel ? ` (model: ${freshProviderConfig.activeModel})` : '';
|
|
318
|
-
const credentialType = freshProviderConfig.authMethod === 'oauth' ? 'authentication has expired' : 'API key is missing';
|
|
319
|
-
const errorMessage = `${freshProviderConfig.activeProvider} ${credentialType}${modelInfo}. Use /provider in the REPL to reconnect.`;
|
|
320
|
-
const error = serializeTaskError(new TaskError(errorMessage, TaskErrorCode.PROVIDER_NOT_CONFIGURED));
|
|
321
|
-
transport.request(TransportTaskEventNames.ERROR, { clientId, error, taskId });
|
|
312
|
+
const validationError = validateProviderForTask(freshProviderConfig);
|
|
313
|
+
if (validationError) {
|
|
314
|
+
transport.request(TransportTaskEventNames.ERROR, { clientId, error: validationError, taskId });
|
|
322
315
|
return;
|
|
323
316
|
}
|
|
324
317
|
activeTaskCount++;
|
|
@@ -204,7 +204,11 @@ async function main() {
|
|
|
204
204
|
agentPool = new AgentPool({
|
|
205
205
|
agentIdleTimeoutPolicy,
|
|
206
206
|
agentProcessFactory(projectPath) {
|
|
207
|
-
|
|
207
|
+
// Prevent console window flash on Windows when forking agent processes.
|
|
208
|
+
// windowsHide is supported at runtime (fork delegates to spawn) but not in ForkOptions types,
|
|
209
|
+
// so we extract the options to a variable to bypass excess property checking.
|
|
210
|
+
const e2eStdio = ['ignore', 'inherit', 'inherit', 'ipc'];
|
|
211
|
+
const forkOptions = {
|
|
208
212
|
cwd: projectPath,
|
|
209
213
|
env: {
|
|
210
214
|
...process.env,
|
|
@@ -212,8 +216,10 @@ async function main() {
|
|
|
212
216
|
BRV_AGENT_PROJECT_PATH: projectPath,
|
|
213
217
|
},
|
|
214
218
|
// In E2E mode, inherit stderr to see agent errors
|
|
215
|
-
stdio: process.env.BRV_E2E_MODE === 'true' ?
|
|
216
|
-
|
|
219
|
+
stdio: process.env.BRV_E2E_MODE === 'true' ? e2eStdio : undefined,
|
|
220
|
+
windowsHide: true,
|
|
221
|
+
};
|
|
222
|
+
return fork(agentProcessPath, [], forkOptions);
|
|
217
223
|
},
|
|
218
224
|
log,
|
|
219
225
|
transportServer,
|
|
@@ -353,7 +359,7 @@ async function main() {
|
|
|
353
359
|
// is returned to the onboarding flow rather than hitting a cryptic API key error mid-task.
|
|
354
360
|
await clearStaleProviderConfig(providerConfigStore, providerKeychainStore, providerOAuthTokenStore);
|
|
355
361
|
// State endpoint: provider config — agents request this on startup and after provider:updated
|
|
356
|
-
transportServer.onRequest(TransportStateEventNames.GET_PROVIDER_CONFIG, async () => resolveProviderConfig(providerConfigStore, providerKeychainStore, tokenRefreshManager));
|
|
362
|
+
transportServer.onRequest(TransportStateEventNames.GET_PROVIDER_CONFIG, async () => resolveProviderConfig({ authStateStore, providerConfigStore, providerKeychainStore, tokenRefreshManager }));
|
|
357
363
|
// Feature handlers (auth, init, status, push, pull, etc.) require async OIDC discovery.
|
|
358
364
|
// Placed after daemon:getState so the debug endpoint is available immediately,
|
|
359
365
|
// without waiting for OIDC discovery (~400ms).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-task Provider Validation
|
|
3
|
+
*
|
|
4
|
+
* Pure validation logic extracted from agent-process.ts for testability.
|
|
5
|
+
* Checks that the provider config is ready for task execution.
|
|
6
|
+
*/
|
|
7
|
+
import type { TaskErrorData } from '../../core/domain/errors/task-error.js';
|
|
8
|
+
import type { ProviderConfigResponse } from '../../core/domain/transport/schemas.js';
|
|
9
|
+
/**
|
|
10
|
+
* Validate provider config before executing a task.
|
|
11
|
+
* Returns a TaskErrorData if validation fails, undefined if all checks pass.
|
|
12
|
+
*
|
|
13
|
+
* Check order matters — most fundamental issues first:
|
|
14
|
+
* 1. No provider connected
|
|
15
|
+
* 2. Provider credential missing (API key or expired OAuth token)
|
|
16
|
+
* 3. Provider requires authentication (ByteRover auth gate)
|
|
17
|
+
*/
|
|
18
|
+
export declare const validateProviderForTask: (config: ProviderConfigResponse) => TaskErrorData | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-task Provider Validation
|
|
3
|
+
*
|
|
4
|
+
* Pure validation logic extracted from agent-process.ts for testability.
|
|
5
|
+
* Checks that the provider config is ready for task execution.
|
|
6
|
+
*/
|
|
7
|
+
import { TaskErrorCode } from '../../core/domain/errors/task-error.js';
|
|
8
|
+
/**
|
|
9
|
+
* Validate provider config before executing a task.
|
|
10
|
+
* Returns a TaskErrorData if validation fails, undefined if all checks pass.
|
|
11
|
+
*
|
|
12
|
+
* Check order matters — most fundamental issues first:
|
|
13
|
+
* 1. No provider connected
|
|
14
|
+
* 2. Provider credential missing (API key or expired OAuth token)
|
|
15
|
+
* 3. Provider requires authentication (ByteRover auth gate)
|
|
16
|
+
*/
|
|
17
|
+
export const validateProviderForTask = (config) => {
|
|
18
|
+
if (!config.activeProvider) {
|
|
19
|
+
return {
|
|
20
|
+
code: TaskErrorCode.PROVIDER_NOT_CONFIGURED,
|
|
21
|
+
message: 'No provider connected. Use /provider in the REPL to configure a provider.',
|
|
22
|
+
name: 'TaskError',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (config.providerKeyMissing) {
|
|
26
|
+
const modelInfo = config.activeModel ? ` (model: ${config.activeModel})` : '';
|
|
27
|
+
const credentialType = config.authMethod === 'oauth' ? 'authentication has expired' : 'API key is missing';
|
|
28
|
+
return {
|
|
29
|
+
code: TaskErrorCode.PROVIDER_NOT_CONFIGURED,
|
|
30
|
+
message: `${config.activeProvider} ${credentialType}${modelInfo}. Use /provider in the REPL to reconnect.`,
|
|
31
|
+
name: 'TaskError',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (config.loginRequired) {
|
|
35
|
+
return {
|
|
36
|
+
code: TaskErrorCode.PROVIDER_NOT_CONFIGURED,
|
|
37
|
+
message: 'Provider requires authentication. Run /login or brv login to sign in.',
|
|
38
|
+
name: 'TaskError',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
};
|
|
@@ -30,6 +30,7 @@ export class AuthenticatedHttpClient {
|
|
|
30
30
|
headers: this.buildHeaders(config?.headers),
|
|
31
31
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
32
32
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
33
|
+
proxy: false,
|
|
33
34
|
timeout: config?.timeout,
|
|
34
35
|
};
|
|
35
36
|
const response = await axios.get(url, axiosConfig);
|
|
@@ -53,6 +54,7 @@ export class AuthenticatedHttpClient {
|
|
|
53
54
|
headers: this.buildHeaders(config?.headers),
|
|
54
55
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
55
56
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
57
|
+
proxy: false,
|
|
56
58
|
timeout: config?.timeout,
|
|
57
59
|
};
|
|
58
60
|
const response = await axios.post(url, data, axiosConfig);
|
|
@@ -76,6 +78,7 @@ export class AuthenticatedHttpClient {
|
|
|
76
78
|
headers: this.buildHeaders(config?.headers),
|
|
77
79
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
78
80
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
81
|
+
proxy: false,
|
|
79
82
|
timeout: config?.timeout,
|
|
80
83
|
};
|
|
81
84
|
const response = await axios.put(url, data, axiosConfig);
|
|
@@ -349,6 +349,7 @@ export class OpenAICompatibleModelFetcher {
|
|
|
349
349
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
350
350
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
351
351
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
352
|
+
proxy: false,
|
|
352
353
|
timeout: 30_000,
|
|
353
354
|
});
|
|
354
355
|
// Handle different response formats:
|
|
@@ -381,6 +382,7 @@ export class OpenAICompatibleModelFetcher {
|
|
|
381
382
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
382
383
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
383
384
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
385
|
+
proxy: false,
|
|
384
386
|
timeout: 15_000,
|
|
385
387
|
});
|
|
386
388
|
return { isValid: true };
|
|
@@ -438,6 +440,7 @@ export class ChatBasedModelFetcher {
|
|
|
438
440
|
},
|
|
439
441
|
httpAgent: ProxyConfig.getProxyAgent(),
|
|
440
442
|
httpsAgent: ProxyConfig.getProxyAgent(),
|
|
443
|
+
proxy: false,
|
|
441
444
|
timeout: 15_000,
|
|
442
445
|
});
|
|
443
446
|
return { isValid: true };
|
|
@@ -9,6 +9,7 @@ import type { IProviderConfigStore } from '../../core/interfaces/i-provider-conf
|
|
|
9
9
|
import type { IProviderKeychainStore } from '../../core/interfaces/i-provider-keychain-store.js';
|
|
10
10
|
import type { IProviderOAuthTokenStore } from '../../core/interfaces/i-provider-oauth-token-store.js';
|
|
11
11
|
import type { ITokenRefreshManager } from '../../core/interfaces/i-token-refresh-manager.js';
|
|
12
|
+
import type { IAuthStateStore } from '../../core/interfaces/state/i-auth-state-store.js';
|
|
12
13
|
import { type ProviderConfigResponse } from '../../core/domain/transport/schemas.js';
|
|
13
14
|
/**
|
|
14
15
|
* Validate provider config integrity at startup.
|
|
@@ -29,4 +30,10 @@ export declare function clearStaleProviderConfig(providerConfigStore: IProviderC
|
|
|
29
30
|
* the API key (keychain → env fallback), and maps provider-specific
|
|
30
31
|
* fields (base URL, headers, location, etc.).
|
|
31
32
|
*/
|
|
32
|
-
export
|
|
33
|
+
export type ResolveProviderConfigParams = {
|
|
34
|
+
authStateStore?: IAuthStateStore;
|
|
35
|
+
providerConfigStore: IProviderConfigStore;
|
|
36
|
+
providerKeychainStore: IProviderKeychainStore;
|
|
37
|
+
tokenRefreshManager?: ITokenRefreshManager;
|
|
38
|
+
};
|
|
39
|
+
export declare function resolveProviderConfig(params: ResolveProviderConfigParams): Promise<ProviderConfigResponse>;
|
|
@@ -49,9 +49,9 @@ export async function clearStaleProviderConfig(providerConfigStore, providerKeyc
|
|
|
49
49
|
for (const providerId of staleProviderIds) {
|
|
50
50
|
newConfig = newConfig.withProviderDisconnected(providerId);
|
|
51
51
|
}
|
|
52
|
-
// withProviderDisconnected()
|
|
53
|
-
// removed
|
|
54
|
-
//
|
|
52
|
+
// withProviderDisconnected() already sets activeProvider to '' when the active
|
|
53
|
+
// provider is removed. This call is a no-op but kept for readability — it makes
|
|
54
|
+
// the "clear active provider" intent explicit at the call site.
|
|
55
55
|
if (staleProviderIds.includes(config.activeProvider)) {
|
|
56
56
|
newConfig = newConfig.withActiveProvider('');
|
|
57
57
|
}
|
|
@@ -67,19 +67,18 @@ export async function clearStaleProviderConfig(providerConfigStore, providerKeyc
|
|
|
67
67
|
// The user will encounter a provider error when submitting a task instead.
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*
|
|
73
|
-
* Reads the active provider/model from the config store, resolves
|
|
74
|
-
* the API key (keychain → env fallback), and maps provider-specific
|
|
75
|
-
* fields (base URL, headers, location, etc.).
|
|
76
|
-
*/
|
|
77
|
-
export async function resolveProviderConfig(providerConfigStore, providerKeychainStore, tokenRefreshManager) {
|
|
70
|
+
export async function resolveProviderConfig(params) {
|
|
71
|
+
const { authStateStore, providerConfigStore, providerKeychainStore, tokenRefreshManager } = params;
|
|
78
72
|
const config = await providerConfigStore.read();
|
|
79
73
|
const { activeProvider } = config;
|
|
80
74
|
const activeModel = config.getActiveModel(activeProvider);
|
|
81
75
|
const maxInputTokens = config.getActiveModelContextLength(activeProvider);
|
|
82
|
-
if (
|
|
76
|
+
if (activeProvider === 'byterover') {
|
|
77
|
+
const authToken = authStateStore?.getToken();
|
|
78
|
+
const loginRequired = authStateStore ? !authToken || !authToken.isValid() : undefined;
|
|
79
|
+
return { activeModel, activeProvider, loginRequired: loginRequired ? true : undefined, maxInputTokens };
|
|
80
|
+
}
|
|
81
|
+
if (!activeProvider) {
|
|
83
82
|
return { activeModel, activeProvider, maxInputTokens };
|
|
84
83
|
}
|
|
85
84
|
// Resolve API key: keychain first, then environment variable
|
|
@@ -2,10 +2,12 @@ import type { IProviderConfigStore } from '../../../core/interfaces/i-provider-c
|
|
|
2
2
|
import type { IProviderKeychainStore } from '../../../core/interfaces/i-provider-keychain-store.js';
|
|
3
3
|
import type { IProviderOAuthTokenStore } from '../../../core/interfaces/i-provider-oauth-token-store.js';
|
|
4
4
|
import type { IBrowserLauncher } from '../../../core/interfaces/services/i-browser-launcher.js';
|
|
5
|
+
import type { IAuthStateStore } from '../../../core/interfaces/state/i-auth-state-store.js';
|
|
5
6
|
import type { ITransportServer } from '../../../core/interfaces/transport/i-transport-server.js';
|
|
6
7
|
import type { PkceParameters, ProviderTokenResponse, TokenExchangeParams } from '../../provider-oauth/index.js';
|
|
7
8
|
import { ProviderCallbackServer } from '../../provider-oauth/index.js';
|
|
8
9
|
export interface ProviderHandlerDeps {
|
|
10
|
+
authStateStore: IAuthStateStore;
|
|
9
11
|
browserLauncher: IBrowserLauncher;
|
|
10
12
|
/** Factory for creating callback servers (injectable for testing) */
|
|
11
13
|
createCallbackServer?: (options: {
|
|
@@ -26,6 +28,7 @@ export interface ProviderHandlerDeps {
|
|
|
26
28
|
* Business logic for provider management — no terminal/UI calls.
|
|
27
29
|
*/
|
|
28
30
|
export declare class ProviderHandler {
|
|
31
|
+
private readonly authStateStore;
|
|
29
32
|
private readonly browserLauncher;
|
|
30
33
|
private readonly createCallbackServer;
|
|
31
34
|
private readonly exchangeCodeForTokens;
|
|
@@ -38,6 +41,7 @@ export declare class ProviderHandler {
|
|
|
38
41
|
constructor(deps: ProviderHandlerDeps);
|
|
39
42
|
setup(): void;
|
|
40
43
|
private cleanupFlowsForClient;
|
|
44
|
+
private isByteRoverAuthSatisfied;
|
|
41
45
|
private setupAwaitOAuthCallback;
|
|
42
46
|
private setupCancelOAuth;
|
|
43
47
|
private setupConnect;
|
|
@@ -10,6 +10,7 @@ import { computeExpiresAt, exchangeCodeForTokens as defaultExchangeCodeForTokens
|
|
|
10
10
|
* Business logic for provider management — no terminal/UI calls.
|
|
11
11
|
*/
|
|
12
12
|
export class ProviderHandler {
|
|
13
|
+
authStateStore;
|
|
13
14
|
browserLauncher;
|
|
14
15
|
createCallbackServer;
|
|
15
16
|
exchangeCodeForTokens;
|
|
@@ -20,6 +21,7 @@ export class ProviderHandler {
|
|
|
20
21
|
providerOAuthTokenStore;
|
|
21
22
|
transport;
|
|
22
23
|
constructor(deps) {
|
|
24
|
+
this.authStateStore = deps.authStateStore;
|
|
23
25
|
this.browserLauncher = deps.browserLauncher;
|
|
24
26
|
this.createCallbackServer = deps.createCallbackServer ?? ((options) => new ProviderCallbackServer(options));
|
|
25
27
|
this.exchangeCodeForTokens = deps.exchangeCodeForTokens ?? defaultExchangeCodeForTokens;
|
|
@@ -53,6 +55,10 @@ export class ProviderHandler {
|
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
}
|
|
58
|
+
isByteRoverAuthSatisfied() {
|
|
59
|
+
const token = this.authStateStore.getToken();
|
|
60
|
+
return token !== undefined && token.isValid();
|
|
61
|
+
}
|
|
56
62
|
setupAwaitOAuthCallback() {
|
|
57
63
|
this.transport.onRequest(ProviderEvents.AWAIT_OAUTH_CALLBACK, async (data) => {
|
|
58
64
|
const flow = this.oauthFlows.get(data.providerId);
|
|
@@ -133,6 +139,9 @@ export class ProviderHandler {
|
|
|
133
139
|
setupConnect() {
|
|
134
140
|
this.transport.onRequest(ProviderEvents.CONNECT, async (data) => {
|
|
135
141
|
const { apiKey, baseUrl, providerId } = data;
|
|
142
|
+
if (providerId === 'byterover' && !this.isByteRoverAuthSatisfied()) {
|
|
143
|
+
return { error: 'ByteRover Provider requires authentication. Run /login or brv login to sign in', success: false };
|
|
144
|
+
}
|
|
136
145
|
// Store API key if provided (supports optional keys for openai-compatible)
|
|
137
146
|
if (apiKey) {
|
|
138
147
|
await this.providerKeychainStore.setApiKey(providerId, apiKey);
|
|
@@ -161,7 +170,8 @@ export class ProviderHandler {
|
|
|
161
170
|
this.transport.onRequest(ProviderEvents.GET_ACTIVE, async () => {
|
|
162
171
|
const activeProviderId = await this.providerConfigStore.getActiveProvider();
|
|
163
172
|
const activeModel = await this.providerConfigStore.getActiveModel(activeProviderId);
|
|
164
|
-
|
|
173
|
+
const loginRequired = activeProviderId === 'byterover' && !this.isByteRoverAuthSatisfied();
|
|
174
|
+
return { activeModel, activeProviderId, loginRequired: loginRequired ? true : undefined };
|
|
165
175
|
});
|
|
166
176
|
}
|
|
167
177
|
setupList() {
|
|
@@ -198,6 +208,9 @@ export class ProviderHandler {
|
|
|
198
208
|
}
|
|
199
209
|
setupSetActive() {
|
|
200
210
|
this.transport.onRequest(ProviderEvents.SET_ACTIVE, async (data) => {
|
|
211
|
+
if (data.providerId === 'byterover' && !this.isByteRoverAuthSatisfied()) {
|
|
212
|
+
return { error: 'ByteRover Provider requires authentication. Run /login or brv login to sign in', success: false };
|
|
213
|
+
}
|
|
201
214
|
await this.providerConfigStore.setActiveProvider(data.providerId);
|
|
202
215
|
this.transport.broadcast(TransportDaemonEventNames.PROVIDER_UPDATED, {});
|
|
203
216
|
return { success: true };
|
|
@@ -21,6 +21,7 @@ export interface ProviderConnectRequest {
|
|
|
21
21
|
providerId: string;
|
|
22
22
|
}
|
|
23
23
|
export interface ProviderConnectResponse {
|
|
24
|
+
error?: string;
|
|
24
25
|
success: boolean;
|
|
25
26
|
}
|
|
26
27
|
export interface ProviderDisconnectRequest {
|
|
@@ -40,11 +41,14 @@ export interface ProviderValidateApiKeyResponse {
|
|
|
40
41
|
export interface ProviderGetActiveResponse {
|
|
41
42
|
activeModel?: string;
|
|
42
43
|
activeProviderId: string;
|
|
44
|
+
/** True when the active provider requires login but the user is not logged in. */
|
|
45
|
+
loginRequired?: boolean;
|
|
43
46
|
}
|
|
44
47
|
export interface ProviderSetActiveRequest {
|
|
45
48
|
providerId: string;
|
|
46
49
|
}
|
|
47
50
|
export interface ProviderSetActiveResponse {
|
|
51
|
+
error?: string;
|
|
48
52
|
success: boolean;
|
|
49
53
|
}
|
|
50
54
|
export interface ProviderCancelOAuthRequest {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* This is the single source of truth for determining what UI to show.
|
|
6
6
|
*/
|
|
7
7
|
/**
|
|
8
|
-
* The
|
|
8
|
+
* The valid application view modes as a discriminated union.
|
|
9
9
|
*/
|
|
10
10
|
export type AppViewMode = {
|
|
11
11
|
type: 'config-provider';
|
|
@@ -15,13 +15,28 @@ export type AppViewMode = {
|
|
|
15
15
|
type: 'ready';
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
|
|
18
|
+
* Parameters for the pure view mode derivation function.
|
|
19
|
+
*/
|
|
20
|
+
export type DeriveAppViewModeParams = {
|
|
21
|
+
activeModel?: string;
|
|
22
|
+
activeProviderId?: string;
|
|
23
|
+
isAuthorized: boolean;
|
|
24
|
+
isLoading: boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Pure decision logic for determining the app view mode.
|
|
28
|
+
* Extracted from useAppViewMode for testability.
|
|
20
29
|
*
|
|
21
|
-
*
|
|
22
|
-
* 1. Loading
|
|
23
|
-
* 2.
|
|
24
|
-
* 3.
|
|
25
|
-
* 4.
|
|
30
|
+
* Decision tree:
|
|
31
|
+
* 1. Loading → 'loading'
|
|
32
|
+
* 2. ByteRover + unauthenticated → 'config-provider'
|
|
33
|
+
* 3. ByteRover + authenticated → 'ready'
|
|
34
|
+
* 4. Non-byterover + no active model → 'config-provider'
|
|
35
|
+
* 5. Otherwise → 'ready'
|
|
36
|
+
*/
|
|
37
|
+
export declare function deriveAppViewMode(params: DeriveAppViewModeParams): AppViewMode;
|
|
38
|
+
/**
|
|
39
|
+
* React hook that derives the current view mode from stored state.
|
|
40
|
+
* Thin wrapper around deriveAppViewMode — reads from stores, delegates logic.
|
|
26
41
|
*/
|
|
27
42
|
export declare function useAppViewMode(): AppViewMode;
|
|
@@ -7,30 +7,42 @@
|
|
|
7
7
|
import { useAuthStore } from '../../auth/stores/auth-store.js';
|
|
8
8
|
import { useGetActiveProviderConfig } from '../../provider/api/get-active-provider-config.js';
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Pure decision logic for determining the app view mode.
|
|
11
|
+
* Extracted from useAppViewMode for testability.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
* 1. Loading
|
|
15
|
-
* 2.
|
|
16
|
-
* 3.
|
|
17
|
-
* 4.
|
|
13
|
+
* Decision tree:
|
|
14
|
+
* 1. Loading → 'loading'
|
|
15
|
+
* 2. ByteRover + unauthenticated → 'config-provider'
|
|
16
|
+
* 3. ByteRover + authenticated → 'ready'
|
|
17
|
+
* 4. Non-byterover + no active model → 'config-provider'
|
|
18
|
+
* 5. Otherwise → 'ready'
|
|
18
19
|
*/
|
|
19
|
-
export function
|
|
20
|
-
|
|
21
|
-
const { data: activeData, isLoading: isLoadingActive } = useGetActiveProviderConfig();
|
|
22
|
-
// Still loading auth or active provider check
|
|
23
|
-
if (isLoadingAuth || isLoadingActive) {
|
|
20
|
+
export function deriveAppViewMode(params) {
|
|
21
|
+
if (params.isLoading) {
|
|
24
22
|
return { type: 'loading' };
|
|
25
23
|
}
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
if (params.activeProviderId === 'byterover' && !params.isAuthorized) {
|
|
25
|
+
return { type: 'config-provider' };
|
|
26
|
+
}
|
|
27
|
+
if (params.activeProviderId === 'byterover') {
|
|
28
28
|
return { type: 'ready' };
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
if (!activeData?.activeModel) {
|
|
30
|
+
if (!params.activeModel) {
|
|
32
31
|
return { type: 'config-provider' };
|
|
33
32
|
}
|
|
34
|
-
// Normal app state
|
|
35
33
|
return { type: 'ready' };
|
|
36
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* React hook that derives the current view mode from stored state.
|
|
37
|
+
* Thin wrapper around deriveAppViewMode — reads from stores, delegates logic.
|
|
38
|
+
*/
|
|
39
|
+
export function useAppViewMode() {
|
|
40
|
+
const { isAuthorized, isLoadingInitial: isLoadingAuth } = useAuthStore();
|
|
41
|
+
const { data: activeData, isLoading: isLoadingActive } = useGetActiveProviderConfig();
|
|
42
|
+
return deriveAppViewMode({
|
|
43
|
+
activeModel: activeData?.activeModel,
|
|
44
|
+
activeProviderId: activeData?.activeProviderId,
|
|
45
|
+
isAuthorized,
|
|
46
|
+
isLoading: isLoadingAuth || isLoadingActive,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ProviderFlow Component
|
|
3
3
|
*
|
|
4
4
|
* Multi-step React flow for the /providers command.
|
|
5
|
-
* State machine: loading → select → provider_actions → api_key → connecting → done
|
|
5
|
+
* State machine: loading → select → login_prompt → login → provider_actions → api_key → connecting → done
|
|
6
6
|
*
|
|
7
7
|
* Owns the UX flow — fetches providers, renders selection,
|
|
8
8
|
* handles API key input, and calls connect/setActive mutations.
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
* ProviderFlow Component
|
|
4
4
|
*
|
|
5
5
|
* Multi-step React flow for the /providers command.
|
|
6
|
-
* State machine: loading → select → provider_actions → api_key → connecting → done
|
|
6
|
+
* State machine: loading → select → login_prompt → login → provider_actions → api_key → connecting → done
|
|
7
7
|
*
|
|
8
8
|
* Owns the UX flow — fetches providers, renders selection,
|
|
9
9
|
* handles API key input, and calls connect/setActive mutations.
|
|
@@ -11,9 +11,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
*/
|
|
12
12
|
import { Box, Text } from 'ink';
|
|
13
13
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
14
|
+
import { InlineConfirm } from '../../../components/inline-prompts/inline-confirm.js';
|
|
14
15
|
import { SelectableList } from '../../../components/selectable-list.js';
|
|
15
16
|
import { useTheme } from '../../../hooks/index.js';
|
|
16
17
|
import { formatTransportError } from '../../../utils/index.js';
|
|
18
|
+
import { LoginFlow } from '../../auth/components/login-flow.js';
|
|
19
|
+
import { useAuthStore } from '../../auth/stores/auth-store.js';
|
|
17
20
|
import { useConnectProvider } from '../api/connect-provider.js';
|
|
18
21
|
import { useDisconnectProvider } from '../api/disconnect-provider.js';
|
|
19
22
|
import { useGetProviders } from '../api/get-providers.js';
|
|
@@ -36,6 +39,7 @@ export const ProviderFlow = ({ hideCancelButton = false, isActive = true, onCanc
|
|
|
36
39
|
const disconnectMutation = useDisconnectProvider();
|
|
37
40
|
const setActiveMutation = useSetActiveProvider();
|
|
38
41
|
const validateMutation = useValidateApiKey();
|
|
42
|
+
const isAuthorized = useAuthStore((s) => s.isAuthorized);
|
|
39
43
|
const providers = data?.providers ?? [];
|
|
40
44
|
// Exit gracefully when providers query fails — don't leave user stuck
|
|
41
45
|
useEffect(() => {
|
|
@@ -98,6 +102,11 @@ export const ProviderFlow = ({ hideCancelButton = false, isActive = true, onCanc
|
|
|
98
102
|
const handleSelect = useCallback(async (provider) => {
|
|
99
103
|
setSelectedProvider(provider);
|
|
100
104
|
setError(null);
|
|
105
|
+
// ByteRover requires authentication
|
|
106
|
+
if (provider.id === 'byterover' && !isAuthorized) {
|
|
107
|
+
setStep('login_prompt');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
101
110
|
// ByteRover + already active → complete
|
|
102
111
|
if (provider.id === 'byterover' && provider.isCurrent) {
|
|
103
112
|
onComplete(`Connected to ${provider.name}`);
|
|
@@ -108,11 +117,12 @@ export const ProviderFlow = ({ hideCancelButton = false, isActive = true, onCanc
|
|
|
108
117
|
setStep('provider_actions');
|
|
109
118
|
return;
|
|
110
119
|
}
|
|
111
|
-
// ByteRover + not connected → connect directly, no model select
|
|
120
|
+
// ByteRover + not connected → connect + activate directly, no model select
|
|
112
121
|
if (provider.id === 'byterover') {
|
|
113
122
|
setStep('connecting');
|
|
114
123
|
try {
|
|
115
124
|
await connectMutation.mutateAsync({ providerId: provider.id });
|
|
125
|
+
await setActiveMutation.mutateAsync({ providerId: provider.id });
|
|
116
126
|
onComplete(`Connected to ${provider.name}`);
|
|
117
127
|
}
|
|
118
128
|
catch (error_) {
|
|
@@ -146,12 +156,16 @@ export const ProviderFlow = ({ hideCancelButton = false, isActive = true, onCanc
|
|
|
146
156
|
setError(formatTransportError(error_));
|
|
147
157
|
setStep('select');
|
|
148
158
|
}
|
|
149
|
-
}, [connectMutation, onComplete]);
|
|
159
|
+
}, [connectMutation, isAuthorized, onComplete, setActiveMutation]);
|
|
150
160
|
const handleAction = useCallback(async (action) => {
|
|
151
161
|
if (!selectedProvider)
|
|
152
162
|
return;
|
|
153
163
|
switch (action.id) {
|
|
154
164
|
case 'activate': {
|
|
165
|
+
if (selectedProvider.id === 'byterover' && !isAuthorized) {
|
|
166
|
+
setStep('login_prompt');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
155
169
|
setStep('connecting');
|
|
156
170
|
try {
|
|
157
171
|
await setActiveMutation.mutateAsync({ providerId: selectedProvider.id });
|
|
@@ -199,7 +213,14 @@ export const ProviderFlow = ({ hideCancelButton = false, isActive = true, onCanc
|
|
|
199
213
|
break;
|
|
200
214
|
}
|
|
201
215
|
}
|
|
202
|
-
}, [disconnectMutation, onComplete, selectedProvider, setActiveMutation]);
|
|
216
|
+
}, [disconnectMutation, isAuthorized, onComplete, selectedProvider, setActiveMutation]);
|
|
217
|
+
const handleLoginComplete = useCallback((message) => {
|
|
218
|
+
const nowAuthorized = useAuthStore.getState().isAuthorized;
|
|
219
|
+
if (!nowAuthorized) {
|
|
220
|
+
setError(message);
|
|
221
|
+
}
|
|
222
|
+
setStep('select');
|
|
223
|
+
}, []);
|
|
203
224
|
const handleBaseUrlSubmit = useCallback((url) => {
|
|
204
225
|
setBaseUrl(url);
|
|
205
226
|
setStep('api_key');
|
|
@@ -285,6 +306,20 @@ export const ProviderFlow = ({ hideCancelButton = false, isActive = true, onCanc
|
|
|
285
306
|
case 'connecting': {
|
|
286
307
|
return (_jsx(Box, { children: _jsxs(Text, { color: colors.primary, children: ["Connecting to ", selectedProvider?.name, "..."] }) }));
|
|
287
308
|
}
|
|
309
|
+
case 'login': {
|
|
310
|
+
return (_jsx(LoginFlow, { onCancel: () => { }, onComplete: handleLoginComplete }));
|
|
311
|
+
}
|
|
312
|
+
case 'login_prompt': {
|
|
313
|
+
return (_jsx(InlineConfirm, { default: true, message: "ByteRover requires authentication. Sign in now", onConfirm: (confirmed) => {
|
|
314
|
+
if (confirmed) {
|
|
315
|
+
setStep('login');
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
setStep('select');
|
|
319
|
+
setSelectedProvider(null);
|
|
320
|
+
}
|
|
321
|
+
} }));
|
|
322
|
+
}
|
|
288
323
|
case 'model_select': {
|
|
289
324
|
return selectedProvider ? (_jsx(ModelSelectStep, { isActive: isActive, onCancel: () => setStep('select'), onComplete: (modelName) => onComplete(`Connected to ${selectedProvider.name}, model set to ${modelName}`), providerId: selectedProvider.id, providerName: selectedProvider.name })) : null;
|
|
290
325
|
}
|
package/oclif.manifest.json
CHANGED
|
@@ -1083,6 +1083,104 @@
|
|
|
1083
1083
|
"switch.js"
|
|
1084
1084
|
]
|
|
1085
1085
|
},
|
|
1086
|
+
"space:list": {
|
|
1087
|
+
"aliases": [],
|
|
1088
|
+
"args": {},
|
|
1089
|
+
"description": "List all teams and spaces",
|
|
1090
|
+
"examples": [
|
|
1091
|
+
"<%= config.bin %> space list",
|
|
1092
|
+
"<%= config.bin %> space list --format json"
|
|
1093
|
+
],
|
|
1094
|
+
"flags": {
|
|
1095
|
+
"format": {
|
|
1096
|
+
"char": "f",
|
|
1097
|
+
"description": "Output format",
|
|
1098
|
+
"name": "format",
|
|
1099
|
+
"default": "text",
|
|
1100
|
+
"hasDynamicHelp": false,
|
|
1101
|
+
"multiple": false,
|
|
1102
|
+
"options": [
|
|
1103
|
+
"text",
|
|
1104
|
+
"json"
|
|
1105
|
+
],
|
|
1106
|
+
"type": "option"
|
|
1107
|
+
}
|
|
1108
|
+
},
|
|
1109
|
+
"hasDynamicHelp": false,
|
|
1110
|
+
"hiddenAliases": [],
|
|
1111
|
+
"id": "space:list",
|
|
1112
|
+
"pluginAlias": "byterover-cli",
|
|
1113
|
+
"pluginName": "byterover-cli",
|
|
1114
|
+
"pluginType": "core",
|
|
1115
|
+
"strict": true,
|
|
1116
|
+
"enableJsonFlag": false,
|
|
1117
|
+
"isESM": true,
|
|
1118
|
+
"relativePath": [
|
|
1119
|
+
"dist",
|
|
1120
|
+
"oclif",
|
|
1121
|
+
"commands",
|
|
1122
|
+
"space",
|
|
1123
|
+
"list.js"
|
|
1124
|
+
]
|
|
1125
|
+
},
|
|
1126
|
+
"space:switch": {
|
|
1127
|
+
"aliases": [],
|
|
1128
|
+
"args": {},
|
|
1129
|
+
"description": "Switch to a different space",
|
|
1130
|
+
"examples": [
|
|
1131
|
+
"<%= config.bin %> space switch --team acme --name my-space",
|
|
1132
|
+
"<%= config.bin %> space switch --team acme --name my-space --format json"
|
|
1133
|
+
],
|
|
1134
|
+
"flags": {
|
|
1135
|
+
"format": {
|
|
1136
|
+
"char": "f",
|
|
1137
|
+
"description": "Output format",
|
|
1138
|
+
"name": "format",
|
|
1139
|
+
"default": "text",
|
|
1140
|
+
"hasDynamicHelp": false,
|
|
1141
|
+
"multiple": false,
|
|
1142
|
+
"options": [
|
|
1143
|
+
"text",
|
|
1144
|
+
"json"
|
|
1145
|
+
],
|
|
1146
|
+
"type": "option"
|
|
1147
|
+
},
|
|
1148
|
+
"name": {
|
|
1149
|
+
"char": "n",
|
|
1150
|
+
"description": "Name of the space to switch to",
|
|
1151
|
+
"name": "name",
|
|
1152
|
+
"required": true,
|
|
1153
|
+
"hasDynamicHelp": false,
|
|
1154
|
+
"multiple": false,
|
|
1155
|
+
"type": "option"
|
|
1156
|
+
},
|
|
1157
|
+
"team": {
|
|
1158
|
+
"char": "t",
|
|
1159
|
+
"description": "Team name",
|
|
1160
|
+
"name": "team",
|
|
1161
|
+
"required": true,
|
|
1162
|
+
"hasDynamicHelp": false,
|
|
1163
|
+
"multiple": false,
|
|
1164
|
+
"type": "option"
|
|
1165
|
+
}
|
|
1166
|
+
},
|
|
1167
|
+
"hasDynamicHelp": false,
|
|
1168
|
+
"hiddenAliases": [],
|
|
1169
|
+
"id": "space:switch",
|
|
1170
|
+
"pluginAlias": "byterover-cli",
|
|
1171
|
+
"pluginName": "byterover-cli",
|
|
1172
|
+
"pluginType": "core",
|
|
1173
|
+
"strict": true,
|
|
1174
|
+
"enableJsonFlag": false,
|
|
1175
|
+
"isESM": true,
|
|
1176
|
+
"relativePath": [
|
|
1177
|
+
"dist",
|
|
1178
|
+
"oclif",
|
|
1179
|
+
"commands",
|
|
1180
|
+
"space",
|
|
1181
|
+
"switch.js"
|
|
1182
|
+
]
|
|
1183
|
+
},
|
|
1086
1184
|
"providers:connect": {
|
|
1087
1185
|
"aliases": [],
|
|
1088
1186
|
"args": {
|
|
@@ -1339,104 +1437,6 @@
|
|
|
1339
1437
|
"switch.js"
|
|
1340
1438
|
]
|
|
1341
1439
|
},
|
|
1342
|
-
"space:list": {
|
|
1343
|
-
"aliases": [],
|
|
1344
|
-
"args": {},
|
|
1345
|
-
"description": "List all teams and spaces",
|
|
1346
|
-
"examples": [
|
|
1347
|
-
"<%= config.bin %> space list",
|
|
1348
|
-
"<%= config.bin %> space list --format json"
|
|
1349
|
-
],
|
|
1350
|
-
"flags": {
|
|
1351
|
-
"format": {
|
|
1352
|
-
"char": "f",
|
|
1353
|
-
"description": "Output format",
|
|
1354
|
-
"name": "format",
|
|
1355
|
-
"default": "text",
|
|
1356
|
-
"hasDynamicHelp": false,
|
|
1357
|
-
"multiple": false,
|
|
1358
|
-
"options": [
|
|
1359
|
-
"text",
|
|
1360
|
-
"json"
|
|
1361
|
-
],
|
|
1362
|
-
"type": "option"
|
|
1363
|
-
}
|
|
1364
|
-
},
|
|
1365
|
-
"hasDynamicHelp": false,
|
|
1366
|
-
"hiddenAliases": [],
|
|
1367
|
-
"id": "space:list",
|
|
1368
|
-
"pluginAlias": "byterover-cli",
|
|
1369
|
-
"pluginName": "byterover-cli",
|
|
1370
|
-
"pluginType": "core",
|
|
1371
|
-
"strict": true,
|
|
1372
|
-
"enableJsonFlag": false,
|
|
1373
|
-
"isESM": true,
|
|
1374
|
-
"relativePath": [
|
|
1375
|
-
"dist",
|
|
1376
|
-
"oclif",
|
|
1377
|
-
"commands",
|
|
1378
|
-
"space",
|
|
1379
|
-
"list.js"
|
|
1380
|
-
]
|
|
1381
|
-
},
|
|
1382
|
-
"space:switch": {
|
|
1383
|
-
"aliases": [],
|
|
1384
|
-
"args": {},
|
|
1385
|
-
"description": "Switch to a different space",
|
|
1386
|
-
"examples": [
|
|
1387
|
-
"<%= config.bin %> space switch --team acme --name my-space",
|
|
1388
|
-
"<%= config.bin %> space switch --team acme --name my-space --format json"
|
|
1389
|
-
],
|
|
1390
|
-
"flags": {
|
|
1391
|
-
"format": {
|
|
1392
|
-
"char": "f",
|
|
1393
|
-
"description": "Output format",
|
|
1394
|
-
"name": "format",
|
|
1395
|
-
"default": "text",
|
|
1396
|
-
"hasDynamicHelp": false,
|
|
1397
|
-
"multiple": false,
|
|
1398
|
-
"options": [
|
|
1399
|
-
"text",
|
|
1400
|
-
"json"
|
|
1401
|
-
],
|
|
1402
|
-
"type": "option"
|
|
1403
|
-
},
|
|
1404
|
-
"name": {
|
|
1405
|
-
"char": "n",
|
|
1406
|
-
"description": "Name of the space to switch to",
|
|
1407
|
-
"name": "name",
|
|
1408
|
-
"required": true,
|
|
1409
|
-
"hasDynamicHelp": false,
|
|
1410
|
-
"multiple": false,
|
|
1411
|
-
"type": "option"
|
|
1412
|
-
},
|
|
1413
|
-
"team": {
|
|
1414
|
-
"char": "t",
|
|
1415
|
-
"description": "Team name",
|
|
1416
|
-
"name": "team",
|
|
1417
|
-
"required": true,
|
|
1418
|
-
"hasDynamicHelp": false,
|
|
1419
|
-
"multiple": false,
|
|
1420
|
-
"type": "option"
|
|
1421
|
-
}
|
|
1422
|
-
},
|
|
1423
|
-
"hasDynamicHelp": false,
|
|
1424
|
-
"hiddenAliases": [],
|
|
1425
|
-
"id": "space:switch",
|
|
1426
|
-
"pluginAlias": "byterover-cli",
|
|
1427
|
-
"pluginName": "byterover-cli",
|
|
1428
|
-
"pluginType": "core",
|
|
1429
|
-
"strict": true,
|
|
1430
|
-
"enableJsonFlag": false,
|
|
1431
|
-
"isESM": true,
|
|
1432
|
-
"relativePath": [
|
|
1433
|
-
"dist",
|
|
1434
|
-
"oclif",
|
|
1435
|
-
"commands",
|
|
1436
|
-
"space",
|
|
1437
|
-
"switch.js"
|
|
1438
|
-
]
|
|
1439
|
-
},
|
|
1440
1440
|
"hub:registry:add": {
|
|
1441
1441
|
"aliases": [],
|
|
1442
1442
|
"args": {
|
|
@@ -1636,5 +1636,5 @@
|
|
|
1636
1636
|
]
|
|
1637
1637
|
}
|
|
1638
1638
|
},
|
|
1639
|
-
"version": "2.
|
|
1639
|
+
"version": "2.5.0"
|
|
1640
1640
|
}
|