byterover-cli 3.10.1 → 3.10.2
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/agent/infra/agent/service-initializer.js +8 -2
- package/dist/agent/infra/llm/agent-llm-service.d.ts +9 -9
- package/dist/agent/infra/llm/agent-llm-service.js +28 -18
- package/dist/agent/infra/llm/generators/ai-sdk-content-generator.d.ts +10 -1
- package/dist/agent/infra/llm/generators/ai-sdk-content-generator.js +21 -4
- package/dist/agent/infra/llm/generators/ai-sdk-message-converter.d.ts +4 -0
- package/dist/agent/infra/llm/generators/ai-sdk-message-converter.js +8 -1
- package/dist/agent/infra/map/abstract-generator.d.ts +29 -0
- package/dist/agent/infra/map/abstract-generator.js +161 -0
- package/dist/agent/infra/map/abstract-queue.d.ts +7 -0
- package/dist/agent/infra/map/abstract-queue.js +100 -26
- package/dist/agent/infra/system-prompt/contributors/file-contributor.js +6 -2
- package/dist/agent/infra/tools/tool-manager.d.ts +10 -1
- package/dist/agent/infra/tools/tool-manager.js +10 -1
- package/dist/server/infra/dream/dream-state-schema.d.ts +35 -0
- package/dist/server/infra/dream/dream-state-schema.js +15 -0
- package/dist/server/infra/dream/dream-state-service.d.ts +22 -0
- package/dist/server/infra/dream/dream-state-service.js +62 -3
- package/dist/server/infra/dream/dream-trigger.js +6 -2
- package/dist/server/infra/executor/curate-executor.d.ts +16 -0
- package/dist/server/infra/executor/curate-executor.js +76 -5
- package/dist/server/infra/executor/dream-executor.d.ts +16 -0
- package/dist/server/infra/executor/dream-executor.js +44 -7
- package/dist/server/infra/transport/handlers/provider-handler.js +20 -3
- package/dist/tui/features/auth/api/get-auth-state.js +6 -3
- package/dist/tui/features/auth/components/auth-initializer.js +4 -2
- package/oclif.manifest.json +413 -413
- package/package.json +1 -1
|
@@ -48,6 +48,8 @@ export type DreamExecutorDeps = {
|
|
|
48
48
|
save(entry: DreamLogEntry): Promise<void>;
|
|
49
49
|
};
|
|
50
50
|
dreamStateService: {
|
|
51
|
+
drainStaleSummaryPaths(): Promise<string[]>;
|
|
52
|
+
enqueueStaleSummaryPaths(paths: string[]): Promise<void>;
|
|
51
53
|
read(): Promise<import('../dream/dream-state-schema.js').DreamState>;
|
|
52
54
|
update(updater: (state: import('../dream/dream-state-schema.js').DreamState) => import('../dream/dream-state-schema.js').DreamState): Promise<import('../dream/dream-state-schema.js').DreamState>;
|
|
53
55
|
write(state: import('../dream/dream-state-schema.js').DreamState): Promise<void>;
|
|
@@ -106,6 +108,20 @@ export declare class DreamExecutor {
|
|
|
106
108
|
signal: AbortSignal;
|
|
107
109
|
taskId: string;
|
|
108
110
|
}): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Regenerate parent `_index.md` files for the given paths and rebuild the
|
|
113
|
+
* manifest. Extracted as a seam so tests can override and assert which
|
|
114
|
+
* paths were passed (the A ∪ B merge in step 5 is the central correctness
|
|
115
|
+
* invariant of the deferral). Production constructs the services here so
|
|
116
|
+
* the dependency surface of {@link DreamExecutorDeps} stays narrow.
|
|
117
|
+
*/
|
|
118
|
+
protected runStaleSummaryPropagation(args: {
|
|
119
|
+
agent: ICipherAgent;
|
|
120
|
+
parentTaskId?: string;
|
|
121
|
+
paths: string[];
|
|
122
|
+
projectRoot: string;
|
|
123
|
+
}): Promise<void>;
|
|
124
|
+
/** Errors are tracked at the log level (status='error'), not per-operation — always 0 here. */
|
|
109
125
|
private computeSummary;
|
|
110
126
|
/**
|
|
111
127
|
* Dual-write: create curate log entries for dream operations that need human review.
|
|
@@ -74,7 +74,12 @@ export class DreamExecutor {
|
|
|
74
74
|
preState = await snapshotService.getCurrentState(projectRoot);
|
|
75
75
|
}
|
|
76
76
|
catch {
|
|
77
|
-
// Fail-open:
|
|
77
|
+
// Fail-open: leaving preState undefined skips the entire step 5 block
|
|
78
|
+
// (queue drain + propagation), so the stale-summary queue is left
|
|
79
|
+
// intact for the next successful dream cycle. Skipping drain here is
|
|
80
|
+
// safer than drain-then-fail: the atomic-drain design clears entries
|
|
81
|
+
// synchronously inside the RMW, so if we drained and then threw
|
|
82
|
+
// before reaching the catch's re-enqueue, the snapshot would be lost.
|
|
78
83
|
}
|
|
79
84
|
// Step 2: Load dream state
|
|
80
85
|
const dreamState = await this.deps.dreamStateService.read();
|
|
@@ -94,19 +99,37 @@ export class DreamExecutor {
|
|
|
94
99
|
taskId: options.taskId,
|
|
95
100
|
});
|
|
96
101
|
// Step 5: Post-dream propagation (fail-open)
|
|
102
|
+
// Two sources of stale summary paths:
|
|
103
|
+
// A. The stale-summary queue, drained from dream state — paths from
|
|
104
|
+
// curate operations that ran since the last dream cycle (the LLM
|
|
105
|
+
// cascade work was deferred from curate's hot path to here).
|
|
106
|
+
// B. Dream's own snapshot diff — paths changed by this dream's
|
|
107
|
+
// consolidate/synthesize/prune operations.
|
|
108
|
+
// Merging A ∪ B before calling propagateStaleness lets a path touched
|
|
109
|
+
// by both sources regenerate exactly once. The queue is drained
|
|
110
|
+
// atomically (cleared in the same RMW that captures the snapshot) so
|
|
111
|
+
// any concurrent curate enqueueing during propagation appends a fresh
|
|
112
|
+
// entry to the now-empty queue and the next dream picks it up.
|
|
97
113
|
if (preState) {
|
|
114
|
+
let drainedSnapshot = [];
|
|
98
115
|
try {
|
|
116
|
+
drainedSnapshot = await this.deps.dreamStateService.drainStaleSummaryPaths();
|
|
99
117
|
const postState = await snapshotService.getCurrentState(projectRoot);
|
|
100
118
|
const changedPaths = diffStates(preState, postState);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
await
|
|
104
|
-
const manifestService = new FileContextTreeManifestService({ baseDirectory: projectRoot });
|
|
105
|
-
await manifestService.buildManifest(projectRoot);
|
|
119
|
+
const merged = [...new Set([...changedPaths, ...drainedSnapshot])];
|
|
120
|
+
if (merged.length > 0) {
|
|
121
|
+
await this.runStaleSummaryPropagation({ agent, parentTaskId: options.taskId, paths: merged, projectRoot });
|
|
106
122
|
}
|
|
107
123
|
}
|
|
108
124
|
catch {
|
|
109
|
-
// Fail-open: propagation errors never block dream
|
|
125
|
+
// Fail-open: propagation errors never block dream. Re-enqueue the
|
|
126
|
+
// drained snapshot so the next dream cycle retries — atomic drain
|
|
127
|
+
// already removed them, so without this they would be lost.
|
|
128
|
+
if (drainedSnapshot.length > 0) {
|
|
129
|
+
await this.deps.dreamStateService.enqueueStaleSummaryPaths(drainedSnapshot).catch(() => {
|
|
130
|
+
// If the re-enqueue itself fails, there is nothing more to do here.
|
|
131
|
+
});
|
|
132
|
+
}
|
|
110
133
|
}
|
|
111
134
|
}
|
|
112
135
|
// Step 6: Write dream log
|
|
@@ -237,6 +260,20 @@ export class DreamExecutor {
|
|
|
237
260
|
taskId,
|
|
238
261
|
})));
|
|
239
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Regenerate parent `_index.md` files for the given paths and rebuild the
|
|
265
|
+
* manifest. Extracted as a seam so tests can override and assert which
|
|
266
|
+
* paths were passed (the A ∪ B merge in step 5 is the central correctness
|
|
267
|
+
* invariant of the deferral). Production constructs the services here so
|
|
268
|
+
* the dependency surface of {@link DreamExecutorDeps} stays narrow.
|
|
269
|
+
*/
|
|
270
|
+
async runStaleSummaryPropagation(args) {
|
|
271
|
+
const summaryService = new FileContextTreeSummaryService();
|
|
272
|
+
await summaryService.propagateStaleness(args.paths, args.agent, args.projectRoot, args.parentTaskId);
|
|
273
|
+
const manifestService = new FileContextTreeManifestService({ baseDirectory: args.projectRoot });
|
|
274
|
+
await manifestService.buildManifest(args.projectRoot);
|
|
275
|
+
}
|
|
276
|
+
/** Errors are tracked at the log level (status='error'), not per-operation — always 0 here. */
|
|
240
277
|
computeSummary(operations) {
|
|
241
278
|
const summary = { consolidated: 0, errors: 0, flaggedForReview: 0, pruned: 0, synthesized: 0 };
|
|
242
279
|
for (const op of operations) {
|
|
@@ -6,6 +6,16 @@ import { processLog } from '../../../utils/process-logger.js';
|
|
|
6
6
|
import { validateApiKey as validateApiKeyViaFetcher } from '../../http/provider-model-fetcher-registry.js';
|
|
7
7
|
import { OpenAICompatibleModelFetcher } from '../../http/provider-model-fetchers.js';
|
|
8
8
|
import { computeExpiresAt, exchangeCodeForTokens as defaultExchangeCodeForTokens, generatePkce as defaultGeneratePkce, parseAccountIdFromIdToken, ProviderCallbackServer, ProviderCallbackTimeoutError, } from '../../provider-oauth/index.js';
|
|
9
|
+
const BYTEROVER_AUTH_REQUIRED_MESSAGE = [
|
|
10
|
+
'ByteRover Provider requires a ByteRover account.',
|
|
11
|
+
'',
|
|
12
|
+
' • Interactive shell: brv login',
|
|
13
|
+
' • Headless / SSH / CI: create an account at https://app.byterover.dev,',
|
|
14
|
+
' generate an API key at https://app.byterover.dev/settings/keys, then:',
|
|
15
|
+
' brv login --api-key <key>',
|
|
16
|
+
'',
|
|
17
|
+
'Once signed in, retry: brv providers connect byterover',
|
|
18
|
+
].join('\n');
|
|
9
19
|
async function defaultValidateOpenAICompatibleEndpoint(params) {
|
|
10
20
|
const fetcher = new OpenAICompatibleModelFetcher(params.baseUrl, 'OpenAI Compatible');
|
|
11
21
|
return fetcher.validateApiKey(params.apiKey);
|
|
@@ -148,7 +158,7 @@ export class ProviderHandler {
|
|
|
148
158
|
this.transport.onRequest(ProviderEvents.CONNECT, async (data) => {
|
|
149
159
|
const { apiKey, baseUrl, providerId } = data;
|
|
150
160
|
if (providerId === 'byterover' && !this.isByteRoverAuthSatisfied()) {
|
|
151
|
-
return { error:
|
|
161
|
+
return { error: BYTEROVER_AUTH_REQUIRED_MESSAGE, success: false };
|
|
152
162
|
}
|
|
153
163
|
// Verify openai-compatible endpoint is reachable before persisting anything —
|
|
154
164
|
// a failed setup must not leave a placeholder config that masquerades as
|
|
@@ -187,7 +197,14 @@ export class ProviderHandler {
|
|
|
187
197
|
// "needs setup" and unmounts any in-flight setup flow on the home
|
|
188
198
|
// page. The model:setActive handler activates the provider when the
|
|
189
199
|
// user picks a model, which is the right moment.
|
|
190
|
-
|
|
200
|
+
//
|
|
201
|
+
// byterover bypasses this gate: it has no model fetcher and no
|
|
202
|
+
// `brv model switch` recovery path, so deferring would strand it as
|
|
203
|
+
// connected-but-never-active. Its model is resolved at runtime via
|
|
204
|
+
// DEFAULT_LLM_MODEL in agent-process.ts rather than persisted here,
|
|
205
|
+
// so future default changes roll out without a per-user migration.
|
|
206
|
+
const willHaveActiveModel = providerId === 'byterover'
|
|
207
|
+
|| Boolean(provider?.defaultModel)
|
|
191
208
|
|| Boolean(await this.providerConfigStore.getActiveModel(providerId));
|
|
192
209
|
await this.providerConfigStore.connectProvider(providerId, {
|
|
193
210
|
activeModel: provider?.defaultModel,
|
|
@@ -253,7 +270,7 @@ export class ProviderHandler {
|
|
|
253
270
|
setupSetActive() {
|
|
254
271
|
this.transport.onRequest(ProviderEvents.SET_ACTIVE, async (data) => {
|
|
255
272
|
if (data.providerId === 'byterover' && !this.isByteRoverAuthSatisfied()) {
|
|
256
|
-
return { error:
|
|
273
|
+
return { error: BYTEROVER_AUTH_REQUIRED_MESSAGE, success: false };
|
|
257
274
|
}
|
|
258
275
|
await this.providerConfigStore.setActiveProvider(data.providerId);
|
|
259
276
|
this.transport.broadcast(TransportDaemonEventNames.PROVIDER_UPDATED, {});
|
|
@@ -5,9 +5,12 @@ export const getAuthState = () => {
|
|
|
5
5
|
const { apiClient } = useTransportStore.getState();
|
|
6
6
|
if (!apiClient)
|
|
7
7
|
return Promise.reject(new Error('Not connected'));
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
8
|
+
// The daemon-side handler does a network round-trip to /user/me. Measured
|
|
9
|
+
// p99 across multiple networks ranges 1.2-3.1s with occasional outliers,
|
|
10
|
+
// so 4000ms gives ~1.3x headroom over the worst observed sample with
|
|
11
|
+
// margin left for slower connections (mobile, international, VPN).
|
|
12
|
+
// React Query retries once on failure for transient blips.
|
|
13
|
+
return apiClient.request(AuthEvents.GET_STATE, undefined, { timeout: 4000 });
|
|
11
14
|
};
|
|
12
15
|
export const getAuthStateQueryOptions = () => queryOptions({
|
|
13
16
|
gcTime: 5 * 60 * 1000,
|
|
@@ -23,8 +23,10 @@ export function AuthInitializer({ children }) {
|
|
|
23
23
|
const { data: authState, isFetched, isLoading, } = useGetAuthState({
|
|
24
24
|
queryConfig: {
|
|
25
25
|
enabled: apiClient !== null,
|
|
26
|
-
retry
|
|
27
|
-
|
|
26
|
+
// One retry covers transient blips; the per-attempt timeout is now generous
|
|
27
|
+
// (3s) so we don't need 5+ retries that would block startup for ~17s when offline.
|
|
28
|
+
retry: 1,
|
|
29
|
+
retryDelay: 500,
|
|
28
30
|
staleTime: 2 * 60 * 1000,
|
|
29
31
|
},
|
|
30
32
|
});
|