byterover-cli 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +6 -81
  2. package/dist/agent/core/domain/llm/index.d.ts +1 -1
  3. package/dist/agent/core/domain/llm/index.js +1 -1
  4. package/dist/agent/core/domain/llm/registry.d.ts +8 -0
  5. package/dist/agent/core/domain/llm/registry.js +34 -0
  6. package/dist/agent/core/domain/sandbox/types.d.ts +2 -0
  7. package/dist/agent/core/domain/tools/constants.d.ts +3 -0
  8. package/dist/agent/core/domain/tools/constants.js +3 -0
  9. package/dist/agent/core/interfaces/cipher-services.d.ts +2 -4
  10. package/dist/agent/core/interfaces/i-cipher-agent.d.ts +9 -1
  11. package/dist/agent/core/interfaces/i-sandbox-service.d.ts +8 -0
  12. package/dist/agent/core/interfaces/i-tool-provider.d.ts +10 -0
  13. package/dist/agent/core/interfaces/i-tool-scheduler.d.ts +9 -0
  14. package/dist/agent/infra/agent/agent-schemas.d.ts +0 -9
  15. package/dist/agent/infra/agent/agent-schemas.js +0 -3
  16. package/dist/agent/infra/agent/cipher-agent.d.ts +25 -1
  17. package/dist/agent/infra/agent/cipher-agent.js +138 -11
  18. package/dist/agent/infra/agent/provider-update-config.d.ts +0 -2
  19. package/dist/agent/infra/agent/service-initializer.d.ts +2 -6
  20. package/dist/agent/infra/agent/service-initializer.js +45 -38
  21. package/dist/agent/infra/blob/blob-storage-factory.d.ts +2 -2
  22. package/dist/agent/infra/blob/blob-storage-factory.js +4 -4
  23. package/dist/agent/infra/blob/file-blob-storage.d.ts +96 -0
  24. package/dist/agent/infra/blob/file-blob-storage.js +454 -0
  25. package/dist/agent/infra/blob/index.d.ts +2 -3
  26. package/dist/agent/infra/blob/index.js +4 -6
  27. package/dist/agent/infra/llm/agent-llm-service.d.ts +3 -0
  28. package/dist/agent/infra/llm/agent-llm-service.js +34 -52
  29. package/dist/agent/infra/llm/context/compression/compression-helpers.d.ts +35 -0
  30. package/dist/agent/infra/llm/context/compression/compression-helpers.js +124 -0
  31. package/dist/agent/infra/llm/context/compression/escalated-compression.d.ts +62 -0
  32. package/dist/agent/infra/llm/context/compression/escalated-compression.js +144 -0
  33. package/dist/agent/infra/llm/context/compression/index.d.ts +3 -0
  34. package/dist/agent/infra/llm/context/compression/index.js +3 -0
  35. package/dist/agent/infra/llm/context/compression/reactive-overflow.d.ts +0 -27
  36. package/dist/agent/infra/llm/context/compression/reactive-overflow.js +5 -122
  37. package/dist/agent/infra/llm/context/context-manager.d.ts +20 -1
  38. package/dist/agent/infra/llm/context/context-manager.js +37 -7
  39. package/dist/agent/infra/llm/providers/index.js +0 -2
  40. package/dist/agent/infra/llm/providers/types.d.ts +1 -5
  41. package/dist/agent/infra/map/agentic-map-service.d.ts +97 -0
  42. package/dist/agent/infra/map/agentic-map-service.js +309 -0
  43. package/dist/agent/infra/map/context-tree-store.d.ts +94 -0
  44. package/dist/agent/infra/map/context-tree-store.js +278 -0
  45. package/dist/agent/infra/map/index.d.ts +4 -0
  46. package/dist/agent/infra/map/index.js +4 -0
  47. package/dist/agent/infra/map/llm-map-memory.d.ts +59 -0
  48. package/dist/agent/infra/map/llm-map-memory.js +187 -0
  49. package/dist/agent/infra/map/llm-map-service.d.ts +36 -0
  50. package/dist/agent/infra/map/llm-map-service.js +118 -0
  51. package/dist/agent/infra/map/map-shared.d.ts +140 -0
  52. package/dist/agent/infra/map/map-shared.js +325 -0
  53. package/dist/agent/infra/map/worker-pool.d.ts +45 -0
  54. package/dist/agent/infra/map/worker-pool.js +73 -0
  55. package/dist/agent/infra/sandbox/curation-helpers.d.ts +62 -0
  56. package/dist/agent/infra/sandbox/curation-helpers.js +219 -0
  57. package/dist/agent/infra/sandbox/sandbox-service.d.ts +12 -0
  58. package/dist/agent/infra/sandbox/sandbox-service.js +39 -7
  59. package/dist/agent/infra/sandbox/tools-sdk.d.ts +48 -1
  60. package/dist/agent/infra/sandbox/tools-sdk.js +52 -1
  61. package/dist/agent/infra/session/session-manager.d.ts +8 -1
  62. package/dist/agent/infra/session/session-manager.js +24 -4
  63. package/dist/agent/infra/storage/file-key-storage.d.ts +142 -0
  64. package/dist/agent/infra/storage/file-key-storage.js +572 -0
  65. package/dist/agent/infra/storage/granular-history-storage.d.ts +1 -1
  66. package/dist/agent/infra/storage/granular-history-storage.js +1 -1
  67. package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.d.ts +4 -0
  68. package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.js +42 -14
  69. package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.d.ts +16 -0
  70. package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.js +47 -0
  71. package/dist/agent/infra/tools/core-tool-scheduler.js +3 -1
  72. package/dist/agent/infra/tools/implementations/agentic-map-tool.d.ts +35 -0
  73. package/dist/agent/infra/tools/implementations/agentic-map-tool.js +156 -0
  74. package/dist/agent/infra/tools/implementations/code-exec-tool.js +1 -0
  75. package/dist/agent/infra/tools/implementations/curate-tool.d.ts +9 -9
  76. package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +18 -0
  77. package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +43 -0
  78. package/dist/agent/infra/tools/implementations/llm-map-tool.d.ts +24 -0
  79. package/dist/agent/infra/tools/implementations/llm-map-tool.js +87 -0
  80. package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +28 -1
  81. package/dist/agent/infra/tools/implementations/memory-symbol-tree.js +27 -3
  82. package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -0
  83. package/dist/agent/infra/tools/implementations/search-knowledge-service.js +83 -12
  84. package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
  85. package/dist/agent/infra/tools/tool-manager.js +6 -0
  86. package/dist/agent/infra/tools/tool-provider.d.ts +12 -0
  87. package/dist/agent/infra/tools/tool-provider.js +78 -0
  88. package/dist/agent/infra/tools/tool-registry.d.ts +14 -0
  89. package/dist/agent/infra/tools/tool-registry.js +32 -0
  90. package/dist/agent/resources/prompts/system-prompt.yml +48 -74
  91. package/dist/agent/resources/tools/expand_knowledge.txt +20 -0
  92. package/dist/oclif/commands/curate/index.js +1 -2
  93. package/dist/oclif/commands/main.js +1 -0
  94. package/dist/oclif/commands/providers/connect.d.ts +1 -3
  95. package/dist/oclif/commands/providers/connect.js +7 -29
  96. package/dist/oclif/commands/query.js +1 -2
  97. package/dist/server/constants.d.ts +7 -0
  98. package/dist/server/constants.js +8 -0
  99. package/dist/server/core/domain/entities/provider-registry.js +1 -15
  100. package/dist/server/core/domain/knowledge/memory-scoring.js +1 -1
  101. package/dist/server/core/domain/knowledge/summary-types.d.ts +126 -0
  102. package/dist/server/core/domain/knowledge/summary-types.js +7 -0
  103. package/dist/server/core/domain/transport/schemas.d.ts +0 -4
  104. package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.d.ts +30 -0
  105. package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.js +1 -0
  106. package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.d.ts +30 -0
  107. package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.js +1 -0
  108. package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.d.ts +29 -0
  109. package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.js +1 -0
  110. package/dist/server/infra/cogit/context-tree-to-push-context-mapper.js +10 -3
  111. package/dist/server/infra/connectors/skill/skill-connector.d.ts +4 -0
  112. package/dist/server/infra/connectors/skill/skill-connector.js +4 -0
  113. package/dist/server/infra/context-tree/children-hash.d.ts +20 -0
  114. package/dist/server/infra/context-tree/children-hash.js +22 -0
  115. package/dist/server/infra/context-tree/derived-artifact.d.ts +28 -0
  116. package/dist/server/infra/context-tree/derived-artifact.js +48 -0
  117. package/dist/server/infra/context-tree/file-context-tree-archive-service.d.ts +37 -0
  118. package/dist/server/infra/context-tree/file-context-tree-archive-service.js +219 -0
  119. package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +50 -0
  120. package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +278 -0
  121. package/dist/server/infra/context-tree/file-context-tree-merger.js +4 -0
  122. package/dist/server/infra/context-tree/file-context-tree-snapshot-service.js +12 -4
  123. package/dist/server/infra/context-tree/file-context-tree-summary-service.d.ts +44 -0
  124. package/dist/server/infra/context-tree/file-context-tree-summary-service.js +313 -0
  125. package/dist/server/infra/context-tree/file-context-tree-writer-service.js +5 -0
  126. package/dist/server/infra/context-tree/prompts/summary-generation.d.ts +22 -0
  127. package/dist/server/infra/context-tree/prompts/summary-generation.js +45 -0
  128. package/dist/server/infra/context-tree/snapshot-diff.d.ts +19 -0
  129. package/dist/server/infra/context-tree/snapshot-diff.js +39 -0
  130. package/dist/server/infra/context-tree/summary-frontmatter.d.ts +24 -0
  131. package/dist/server/infra/context-tree/summary-frontmatter.js +111 -0
  132. package/dist/server/infra/daemon/agent-process.js +2 -14
  133. package/dist/server/infra/executor/curate-executor.d.ts +1 -0
  134. package/dist/server/infra/executor/curate-executor.js +82 -34
  135. package/dist/server/infra/executor/folder-pack-executor.js +1 -1
  136. package/dist/server/infra/executor/pre-compaction/compaction-escalation.d.ts +6 -0
  137. package/dist/server/infra/executor/pre-compaction/compaction-escalation.js +6 -0
  138. package/dist/server/infra/executor/pre-compaction/index.d.ts +3 -0
  139. package/dist/server/infra/executor/pre-compaction/index.js +1 -0
  140. package/dist/server/infra/executor/pre-compaction/pre-compaction-service.d.ts +59 -0
  141. package/dist/server/infra/executor/pre-compaction/pre-compaction-service.js +124 -0
  142. package/dist/server/infra/executor/pre-compaction/prompts.d.ts +24 -0
  143. package/dist/server/infra/executor/pre-compaction/prompts.js +47 -0
  144. package/dist/server/infra/executor/query-executor.d.ts +3 -0
  145. package/dist/server/infra/executor/query-executor.js +39 -4
  146. package/dist/server/infra/http/authenticated-http-client.js +4 -0
  147. package/dist/server/infra/http/provider-model-fetcher-registry.js +1 -5
  148. package/dist/server/infra/http/provider-model-fetchers.d.ts +0 -14
  149. package/dist/server/infra/http/provider-model-fetchers.js +0 -132
  150. package/dist/server/infra/provider/provider-config-resolver.js +0 -55
  151. package/dist/server/utils/curate-result-parser.d.ts +4 -4
  152. package/dist/shared/constants/curation.d.ts +6 -0
  153. package/dist/shared/constants/curation.js +6 -0
  154. package/dist/shared/utils/escalation-utils.d.ts +59 -0
  155. package/dist/shared/utils/escalation-utils.js +141 -0
  156. package/dist/tui/components/command-input.js +1 -1
  157. package/dist/tui/components/inline-prompts/inline-confirm.js +6 -1
  158. package/dist/tui/features/commands/definitions/exit.d.ts +2 -0
  159. package/dist/tui/features/commands/definitions/exit.js +9 -0
  160. package/dist/tui/features/commands/definitions/index.js +3 -0
  161. package/dist/tui/features/exit/components/exit-flow.d.ts +10 -0
  162. package/dist/tui/features/exit/components/exit-flow.js +19 -0
  163. package/dist/tui/features/provider/components/provider-flow.js +1 -21
  164. package/oclif.manifest.json +100 -109
  165. package/package.json +11 -4
  166. package/dist/agent/infra/blob/migrations.d.ts +0 -63
  167. package/dist/agent/infra/blob/migrations.js +0 -148
  168. package/dist/agent/infra/blob/sqlite-blob-storage.d.ts +0 -82
  169. package/dist/agent/infra/blob/sqlite-blob-storage.js +0 -307
  170. package/dist/agent/infra/llm/providers/google-vertex.d.ts +0 -15
  171. package/dist/agent/infra/llm/providers/google-vertex.js +0 -36
  172. package/dist/agent/infra/storage/blob-history-storage.d.ts +0 -81
  173. package/dist/agent/infra/storage/blob-history-storage.js +0 -193
  174. package/dist/agent/infra/storage/dual-format-history-storage.d.ts +0 -83
  175. package/dist/agent/infra/storage/dual-format-history-storage.js +0 -165
  176. package/dist/agent/infra/storage/sqlite-key-storage.d.ts +0 -113
  177. package/dist/agent/infra/storage/sqlite-key-storage.js +0 -438
  178. package/dist/server/infra/provider/vertex-ai-utils.d.ts +0 -10
  179. package/dist/server/infra/provider/vertex-ai-utils.js +0 -28
  180. package/dist/tui/features/provider/components/credential-path-dialog.d.ts +0 -30
  181. package/dist/tui/features/provider/components/credential-path-dialog.js +0 -85
@@ -273,116 +273,90 @@ prompt: |
273
273
 
274
274
  **CRITICAL RULES:**
275
275
  - NEVER print raw context — stdout is capped at 5K chars for curate mode
276
- - Use the metadata variable to understand context size and structure BEFORE peeking
276
+ - Use `tools.curation.recon()` to assess context BEFORE processing
277
277
  - Peek at context via slicing: `<ctxVar>.slice(0, 3000)` — NEVER `console.log(<ctxVar>)`
278
278
  - Use `silent: true` in code_exec for variable assignments (no stdout returned)
279
- - For large contexts (>10K chars), use `tools.agentQuery()` to delegate chunk processing
279
+ - For chunked contexts, use `tools.curation.mapExtract()` for parallel extraction
280
280
  - All large data stays inside async IIFE scope — variables do NOT leak to LLM context
281
281
 
282
- **Step 0 — Check metadata (always do this first):**
282
+ **Step 0 — Reconnaissance (always do this first):**
283
283
  ```javascript
284
- // Check context metadata before any processing
284
+ // Combined metadata + history + preview assessment — replaces separate Steps 0-2
285
285
  (async () => {
286
- const meta = <metaVar>;
287
- console.log(JSON.stringify(meta));
288
- // Output: { charCount: 25000, lineCount: 400, messageCount: 12, type: "string", preview: "..." }
286
+ const r = tools.curation.recon(<ctxVar>, <metaVar>, <histVar>);
287
+ console.log(JSON.stringify(r));
288
+ // Returns: { meta, history, headPreview, tailPreview, suggestedMode, suggestedChunkCount }
289
289
  })()
290
290
  ```
291
291
 
292
- **Step 1 Read history and check duplicates:**
293
- ```javascript
294
- // Check curate history for duplicates and existing domains
295
- (async () => {
296
- const history = <histVar>; // Direct variable access — no file I/O needed
297
- const domainSummary = Object.entries(history.entries || [])
298
- .reduce((acc, entry) => {
299
- const key = entry.domain || 'unknown';
300
- if (!acc[key]) acc[key] = [];
301
- acc[key].push(entry.title);
302
- return acc;
303
- }, {});
304
- console.log('=== Existing Domains ===');
305
- console.log(Object.entries(domainSummary).map(([d, t]) => `${d}: ${t.join(', ')}`).join('\n') || 'None yet');
306
- console.log(`Total processed: ${history.totalProcessed || 0}`);
307
- })()
308
- ```
292
+ **When recon().suggestedMode is 'single-pass':**
293
+ Skip chunking entirely. Read the full context via slicing, detect domains, and curate
294
+ in 2 code_exec calls (recon + curate). Do NOT use agentQuery, chunk(), or mapExtract() for small contexts.
309
295
 
310
- **Step 2Peek at context via slicing (NOT console.log of full content):**
296
+ **Step 1Extract (for chunked contexts, suggestedMode === 'chunked'):**
297
+ IMPORTANT: Use timeout: 300000 on the code_exec tool call itself (not inside mapExtract options).
311
298
  ```javascript
312
- // Peek at context structurefirst and last sections only
299
+ // Parallel extraction via mapExtractchunks context and processes all chunks concurrently
313
300
  (async () => {
314
- const raw = <ctxVar>;
315
- const head = raw.slice(0, 3000);
316
- const tail = raw.slice(-2000);
317
- const lines = head.split('\n');
318
- const sessionId = lines.find(l => l.startsWith('Session ID:'))?.split(': ')[1]?.trim();
319
- const date = lines.find(l => l.startsWith('Date:'))?.split(': ')[1]?.trim();
320
- console.log(JSON.stringify({ sessionId, date, headPreview: head.slice(0, 500), tailPreview: tail.slice(0, 500) }));
301
+ const result = await tools.curation.mapExtract(<ctxVar>, {
302
+ prompt: 'Extract factual statements from the chunk. Return JSON array of {statement, category, subject}.',
303
+ chunkSize: 8000,
304
+ taskId: <taskIdVar>, // bare variable, do NOT quote
305
+ });
306
+ // result: { facts: CurationFact[], succeeded, failed, total }
307
+ if (result.failed > 0) console.log(`Warning: ${result.failed}/${result.total} chunks failed`);
308
+ const deduped = tools.curation.dedup(result.facts);
309
+ const grouped = tools.curation.groupBySubject(deduped);
310
+ console.log(JSON.stringify({ groups: Object.keys(grouped).length, totalFacts: deduped.length }));
321
311
  })()
322
312
  ```
323
313
 
324
- **Step 3For large contexts, delegate chunk processing to sub-agent:**
314
+ **Step 2Curate + verify inline:**
325
315
  ```javascript
326
- // Delegate chunk processing with variable injection (RLM pattern chunk stays out of prompt)
327
- (async () => {
328
- const raw = <ctxVar>;
329
- const chunkSize = 8000;
330
- const chunks = [];
331
- for (let i = 0; i < raw.length; i += chunkSize) {
332
- chunks.push(raw.slice(i, i + chunkSize));
333
- }
334
- const extractions = [];
335
- for (let i = 0; i < chunks.length; i++) {
336
- const result = await tools.agentQuery(
337
- `Extract all factual statements, preferences, and key information from variable __chunk (${chunks[i].length} chars). Return as JSON array of {statement, category, subject}.`,
338
- { contextData: { __chunk: chunks[i] } }
339
- );
340
- extractions.push(result);
341
- }
342
- console.log(JSON.stringify({ chunkCount: chunks.length, extractions }));
343
- })()
344
- ```
345
-
346
- **Step 4 — Curate with extracted data:**
347
- ```javascript
348
- // Curate extracted content
316
+ // Curate extracted content and verify via resultno readFile needed
349
317
  (async () => {
350
318
  const result = await tools.curate([{
351
319
  type: 'UPSERT', path: '<domain>/<topic>', title: '<title>',
352
320
  content: { rawConcept: { task: '...', /* ... */ }, narrative: { /* ... */ } },
353
321
  reason: 'Curate from RLM context'
354
322
  }]);
355
- console.log(JSON.stringify({ curated: result.summary }));
323
+ // Verify inline — CurateResult.applied[].filePath already has paths
324
+ const created = result.applied.filter(r => r.status === 'success').map(r => r.filePath);
325
+ // Update history using helper (intentionally mutating)
326
+ tools.curation.recordProgress(<histVar>, { domain: '<domain>', title: '<title>', keyFacts: ['fact1', 'fact2'] });
327
+ console.log(JSON.stringify({ summary: result.summary, files: created }));
356
328
  })()
357
329
  ```
358
330
 
359
- Then update history in a separate **silent** code_exec (`silent: true`):
360
- ```javascript
361
- // Update history variable (silent — no stdout needed)
362
- <histVar>.entries.push({
363
- sessionId: '<id>', timestamp: new Date().toISOString(), title: '<title>',
364
- domain: '<domain>/<topic>', keyFacts: ['fact1', 'fact2']
365
- });
366
- <histVar>.totalProcessed++;
367
- ```
368
-
369
- **Step 5 — Post-Curate Verification + Status Reporting (REQUIRED):**
370
- After every `tools.curate()` call:
331
+ **Step 3 Status Reporting (REQUIRED):**
332
+ After all curate operations:
371
333
  1. Check `result.summary` — ensure `failed === 0`
372
334
  2. If `failed > 0`, log the error and retry with corrected operations
373
- 3. Verify curated files exist: `await tools.readFile('.brv/context-tree/' + path + '/' + title + '.md')`
374
- 4. If file doesn't exist, retry the curate operation
375
- 5. Report final status via `setFinalResult()` including summary and verification:
335
+ 3. Report final status via `setFinalResult()` including summary:
376
336
  ```javascript
377
337
  (async () => {
378
338
  const status = {
379
339
  summary: result.summary,
380
- verification: { checked: paths.length, confirmed: verifiedCount, missing: missingPaths },
340
+ verification: { checked: created.length, confirmed: created.length, missing: [] },
381
341
  };
382
342
  setFinalResult('Curation complete.\n```json\n' + JSON.stringify(status, null, 2) + '\n```\n\n' + humanSummary);
383
343
  })()
384
344
  ```
385
345
 
346
+ **Curation helper functions available via `tools.curation.*`:**
347
+ - `tools.curation.recon(ctx, meta, history)` — Combined recon: metadata + history domains + head/tail preview + mode recommendation
348
+ - `tools.curation.mapExtract(ctx, {prompt, chunkSize?, concurrency?, maxContextTokens?, taskId?})` — Parallel LLM extraction: chunks context, processes in parallel, returns `{facts: CurationFact[], succeeded, failed, total}`. Throws if all chunks fail.
349
+ - `tools.curation.chunk(ctx, {size?, overlap?})` — Intelligent chunking: respects paragraph boundaries, code fences, message markers
350
+ - `tools.curation.groupBySubject(facts)` — Group CurationFact[] by subject (fallback: category)
351
+ - `tools.curation.dedup(facts, threshold?)` — Deduplicate facts using Jaccard word-overlap similarity
352
+ - `tools.curation.detectMessageBoundaries(ctx)` — Find [USER]/[ASSISTANT] markers with offsets
353
+ - `tools.curation.recordProgress(history, entry)` — Push entry into history + increment totalProcessed
354
+
355
+ **Context compression awareness:**
356
+ - Conversation context may be compacted via escalation when exceeding token limits.
357
+ - When precision matters, re-read files or tool outputs rather than assuming full conversational recall.
358
+ - `summaryHandle` from map tools is a compact summary — for full per-item data, read the JSONL output file.
359
+
386
360
  **History retrieval patterns (use within code):**
387
361
  - Duplicate check: `history.entries.some(e => e.sessionId === currentId)`
388
362
  - Related entries: `history.entries.filter(e => e.domain === 'domain/topic')`
@@ -0,0 +1,20 @@
1
+ Retrieve full content from archived knowledge entries in `.brv/context-tree/_archived/`.
2
+
3
+ When searching the knowledge base, you may encounter results with `symbolKind: "archive_stub"`. These are archived entries that have been evicted from active storage but remain searchable via short ghost cues. Use this tool to retrieve the full original content.
4
+
5
+ **When to use:**
6
+ - A search result has `symbolKind: "archive_stub"` and you need the full content
7
+ - You want to drill into an archived entry to access its complete knowledge
8
+
9
+ **Parameters:**
10
+ - `stubPath` (required): Path to the `.stub.md` file (the `path` field from search results where `symbolKind === "archive_stub"`)
11
+
12
+ **Returns:**
13
+ - `originalPath`: The original file path before archiving
14
+ - `fullContent`: Complete original content of the archived entry
15
+ - `tokenCount`: Estimated token count of the full content
16
+
17
+ **Example:**
18
+ - Search returns: `{ path: "_archived/auth/jwt-tokens/refresh-flow.stub.md", symbolKind: "archive_stub" }`
19
+ - Call: `expand_knowledge({ stubPath: "_archived/auth/jwt-tokens/refresh-flow.stub.md" })`
20
+ - Returns full original content of the refresh-flow knowledge entry
@@ -91,8 +91,7 @@ Bad examples:
91
91
  throw new Error('No provider connected. Run "brv providers connect byterover" to use the free built-in provider, or connect another provider.');
92
92
  }
93
93
  if (active.providerKeyMissing) {
94
- throw new Error(active.providerCredentialError
95
- ?? `${active.activeProvider} API key is missing from storage.\nPlease reconnect: brv providers connect ${active.activeProvider} --api-key <your-key>`);
94
+ throw new Error(`${active.activeProvider} API key is missing from storage.\nPlease reconnect: brv providers connect ${active.activeProvider} --api-key <your-key>`);
96
95
  }
97
96
  await this.submitTask({ client, content: resolvedContent, flags, format, projectRoot, taskType });
98
97
  }, {
@@ -35,5 +35,6 @@ export default class Main extends Command {
35
35
  await startRepl({
36
36
  version: this.config.version,
37
37
  });
38
+ this.exit(0);
38
39
  }
39
40
  }
@@ -9,14 +9,12 @@ export default class ProviderConnect extends Command {
9
9
  static flags: {
10
10
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
- 'credential-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
12
  format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
13
  model: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
14
  };
16
- protected connectProvider({ apiKey, baseUrl, credentialFile, model, providerId }: {
15
+ protected connectProvider({ apiKey, baseUrl, model, providerId }: {
17
16
  apiKey?: string;
18
17
  baseUrl?: string;
19
- credentialFile?: string;
20
18
  model?: string;
21
19
  providerId: string;
22
20
  }, options?: DaemonClientOptions): Promise<{
@@ -17,7 +17,6 @@ export default class ProviderConnect extends Command {
17
17
  '<%= config.bin %> providers connect byterover',
18
18
  '<%= config.bin %> providers connect openai-compatible --base-url http://localhost:11434/v1',
19
19
  '<%= config.bin %> providers connect openai-compatible --base-url http://localhost:11434/v1 --api-key sk-xxx --model llama3',
20
- '<%= config.bin %> providers connect google-vertex --credential-file /path/to/service-account.json',
21
20
  ];
22
21
  static flags = {
23
22
  'api-key': Flags.string({
@@ -28,10 +27,6 @@ export default class ProviderConnect extends Command {
28
27
  char: 'b',
29
28
  description: 'Base URL for OpenAI-compatible providers (e.g., http://localhost:11434/v1)',
30
29
  }),
31
- 'credential-file': Flags.string({
32
- char: 'f',
33
- description: 'Path to service account JSON key file (for Google Vertex AI)',
34
- }),
35
30
  format: Flags.string({
36
31
  default: 'text',
37
32
  description: 'Output format (text or json)',
@@ -42,7 +37,7 @@ export default class ProviderConnect extends Command {
42
37
  description: 'Model to set as active after connecting',
43
38
  }),
44
39
  };
45
- async connectProvider({ apiKey, baseUrl, credentialFile, model, providerId }, options) {
40
+ async connectProvider({ apiKey, baseUrl, model, providerId }, options) {
46
41
  return withDaemonRetry(async (client) => {
47
42
  // 1. Verify provider exists
48
43
  const { providers } = await client.requestWithAck(ProviderEvents.LIST);
@@ -69,21 +64,7 @@ export default class ProviderConnect extends Command {
69
64
  }
70
65
  }
71
66
  }
72
- // 3. Validate credential file for google-vertex
73
- if (providerId === 'google-vertex') {
74
- if (credentialFile) {
75
- const validation = await client.requestWithAck(ProviderEvents.VALIDATE_API_KEY, { apiKey: credentialFile, providerId });
76
- if (!validation.isValid) {
77
- throw new Error(validation.error ?? 'The credential file is invalid. Please check the path and try again.');
78
- }
79
- }
80
- else if (!provider.isConnected) {
81
- throw new Error('Provider "google-vertex" requires a service account credential file. Use the --credential-file flag.'
82
- + '\nExample: brv providers connect google-vertex --credential-file /path/to/service-account.json'
83
- + '\nGet your service account key at: https://console.cloud.google.com/iam-admin/serviceaccounts');
84
- }
85
- }
86
- // 4. Validate API key if provided and required (skip for openai-compatible)
67
+ // 3. Validate API key if provided and required (skip for openai-compatible)
87
68
  if (apiKey && provider.requiresApiKey) {
88
69
  const validation = await client.requestWithAck(ProviderEvents.VALIDATE_API_KEY, { apiKey, providerId });
89
70
  if (!validation.isValid) {
@@ -94,14 +75,12 @@ export default class ProviderConnect extends Command {
94
75
  throw new Error(`Provider "${providerId}" requires an API key. Use the --api-key flag to provide one.`
95
76
  + (provider.apiKeyUrl ? `\nDon't have one? Get your API key at: ${provider.apiKeyUrl}` : ''));
96
77
  }
97
- // 5. Connect or switch active provider
98
- // For google-vertex, credentialFile is passed as apiKey through the transport layer
99
- const effectiveApiKey = providerId === 'google-vertex' ? credentialFile : apiKey;
100
- const hasNewConfig = effectiveApiKey || baseUrl;
78
+ // 4. Connect or switch active provider
79
+ const hasNewConfig = apiKey || baseUrl;
101
80
  await (provider.isConnected && !hasNewConfig
102
81
  ? client.requestWithAck(ProviderEvents.SET_ACTIVE, { providerId })
103
- : client.requestWithAck(ProviderEvents.CONNECT, { apiKey: effectiveApiKey, baseUrl, providerId }));
104
- // 6. Set model if specified
82
+ : client.requestWithAck(ProviderEvents.CONNECT, { apiKey, baseUrl, providerId }));
83
+ // 5. Set model if specified
105
84
  if (model) {
106
85
  await client.requestWithAck(ModelEvents.SET_ACTIVE, { modelId: model, providerId });
107
86
  }
@@ -113,11 +92,10 @@ export default class ProviderConnect extends Command {
113
92
  const providerId = args.provider;
114
93
  const apiKey = flags['api-key'];
115
94
  const baseUrl = flags['base-url'];
116
- const credentialFile = flags['credential-file'];
117
95
  const { model } = flags;
118
96
  const format = flags.format;
119
97
  try {
120
- const result = await this.connectProvider({ apiKey, baseUrl, credentialFile, model, providerId });
98
+ const result = await this.connectProvider({ apiKey, baseUrl, model, providerId });
121
99
  if (format === 'json') {
122
100
  writeJsonResponse({ command: 'providers connect', data: result, success: true });
123
101
  }
@@ -54,8 +54,7 @@ Bad:
54
54
  throw new Error('No provider connected. Run "brv providers connect byterover" to use the free built-in provider, or connect another provider.');
55
55
  }
56
56
  if (active.providerKeyMissing) {
57
- throw new Error(active.providerCredentialError
58
- ?? `${active.activeProvider} API key is missing from storage.\nPlease reconnect: brv providers connect ${active.activeProvider} --api-key <your-key>`);
57
+ throw new Error(`${active.activeProvider} API key is missing from storage.\nPlease reconnect: brv providers connect ${active.activeProvider} --api-key <your-key>`);
59
58
  }
60
59
  await this.submitTask({ client, format, projectRoot, query: args.query });
61
60
  }, {
@@ -59,3 +59,10 @@ export declare const AGENT_PROCESS_READY_TIMEOUT_MS = 15000;
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";
62
+ export declare const SUMMARY_INDEX_FILE = "_index.md";
63
+ export declare const ARCHIVE_DIR = "_archived";
64
+ export declare const STUB_EXTENSION = ".stub.md";
65
+ export declare const FULL_ARCHIVE_EXTENSION = ".full.md";
66
+ export declare const MANIFEST_FILE = "_manifest.json";
67
+ export declare const ARCHIVE_IMPORTANCE_THRESHOLD = 35;
68
+ export declare const DEFAULT_GHOST_CUE_MAX_TOKENS = 220;
@@ -80,3 +80,11 @@ export const AGENT_PROCESS_STOP_TIMEOUT_MS = 5000; // 5s max wait for child proc
80
80
  // Curate log
81
81
  export const CURATE_LOG_DIR = 'curate-log';
82
82
  export const CURATE_LOG_ID_PREFIX = 'cur';
83
+ // === Hierarchical DAG (summary, archive, manifest) ===
84
+ export const SUMMARY_INDEX_FILE = '_index.md';
85
+ export const ARCHIVE_DIR = '_archived';
86
+ export const STUB_EXTENSION = '.stub.md';
87
+ export const FULL_ARCHIVE_EXTENSION = '.full.md';
88
+ export const MANIFEST_FILE = '_manifest.json';
89
+ export const ARCHIVE_IMPORTANCE_THRESHOLD = 35;
90
+ export const DEFAULT_GHOST_CUE_MAX_TOKENS = 220;
@@ -97,19 +97,6 @@ export const PROVIDER_REGISTRY = {
97
97
  name: 'Google Gemini',
98
98
  priority: 4,
99
99
  },
100
- 'google-vertex': {
101
- apiKeyUrl: 'https://console.cloud.google.com/iam-admin/serviceaccounts',
102
- baseUrl: '',
103
- category: 'popular',
104
- defaultModel: 'gemini-2.5-flash',
105
- description: 'Gemini via Google Cloud Vertex AI',
106
- envVars: ['GOOGLE_APPLICATION_CREDENTIALS'],
107
- headers: {},
108
- id: 'google-vertex',
109
- modelsEndpoint: '',
110
- name: 'Google Vertex AI',
111
- priority: 5,
112
- },
113
100
  groq: {
114
101
  apiKeyUrl: 'https://console.groq.com/keys',
115
102
  baseUrl: 'https://api.groq.com/openai/v1',
@@ -286,9 +273,8 @@ export function providerRequiresApiKey(id) {
286
273
  if (!provider)
287
274
  return false;
288
275
  // Internal providers (byterover) don't need API keys.
289
- // Vertex AI uses Application Default Credentials, not API keys.
290
276
  // OpenAI Compatible has optional API key (handled in provider-command).
291
- if (id === 'byterover' || id === 'google-vertex' || id === 'openai-compatible')
277
+ if (id === 'byterover' || id === 'openai-compatible')
292
278
  return false;
293
279
  return true;
294
280
  }
@@ -21,7 +21,7 @@ export const ACCESS_IMPORTANCE_BONUS = 3;
21
21
  /** Importance bonus per curate update */
22
22
  export const UPDATE_IMPORTANCE_BONUS = 5;
23
23
  /** BM25 relevance weight in compound score */
24
- export const W_RELEVANCE = 1.0;
24
+ export const W_RELEVANCE = 1;
25
25
  /** Importance weight in compound score */
26
26
  export const W_IMPORTANCE = 0;
27
27
  /** Recency weight in compound score */
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Type definitions for the Hierarchical DAG architecture.
3
+ *
4
+ * Covers summary nodes, archive stubs, manifest entries, and
5
+ * result types used by summary/archive/manifest services.
6
+ */
7
+ /** Condensation order: 0 = raw context, 1 = topic, 2 = domain, 3 = root */
8
+ export type CondensationOrder = 0 | 1 | 2 | 3;
9
+ /** Summary level labels corresponding to condensation orders */
10
+ export type SummaryLevel = 'd0' | 'd1' | 'd2' | 'd3';
11
+ export interface SummaryFrontmatter {
12
+ /** Hash of sorted path:contentHash pairs for staleness detection */
13
+ children_hash: string;
14
+ /** Compression ratio achieved (output tokens / input tokens) */
15
+ compression_ratio: number;
16
+ /** Condensation order (depth from leaves) */
17
+ condensation_order: CondensationOrder;
18
+ /** Sorted child names this summary covers */
19
+ covers: string[];
20
+ /** Total tokens across all covered children */
21
+ covers_token_total: number;
22
+ /** Summary level label */
23
+ summary_level: SummaryLevel;
24
+ /** Token count of this summary */
25
+ token_count: number;
26
+ /** Discriminator */
27
+ type: 'summary';
28
+ }
29
+ export interface ArchiveStubFrontmatter {
30
+ /** ISO timestamp when the entry was evicted */
31
+ evicted_at: string;
32
+ /** Importance score at eviction time */
33
+ evicted_importance: number;
34
+ /** Original relative path before archiving (for restore) */
35
+ original_path: string;
36
+ /** Original token count before archiving */
37
+ original_token_count: number;
38
+ /** Relative path to the .full.md preserved content */
39
+ points_to: string;
40
+ /** Discriminator */
41
+ type: 'archive_stub';
42
+ }
43
+ export interface ManifestEntry {
44
+ /** Importance score from frontmatter (0-100, default 50) */
45
+ importance?: number;
46
+ /** Condensation order (only for summaries) */
47
+ order?: CondensationOrder;
48
+ /** Relative path within the context tree */
49
+ path: string;
50
+ /** Estimated token count */
51
+ tokens: number;
52
+ /** Entry type */
53
+ type: 'context' | 'stub' | 'summary';
54
+ }
55
+ export interface LaneTokens {
56
+ contexts: number;
57
+ stubs: number;
58
+ summaries: number;
59
+ }
60
+ export interface ContextManifest {
61
+ /** Active context entries selected by lane budgeting */
62
+ active_context: ManifestEntry[];
63
+ /** ISO timestamp when the manifest was generated */
64
+ generated_at: string;
65
+ /** Token allocation per lane */
66
+ lane_tokens: LaneTokens;
67
+ /** Fingerprint of source files (hash of sorted path:mtime:size) for freshness check */
68
+ source_fingerprint: string;
69
+ /** Total tokens across all active entries */
70
+ total_tokens: number;
71
+ /** Schema version */
72
+ version: 1;
73
+ }
74
+ export declare const DEFAULT_LANE_BUDGETS: LaneTokens;
75
+ export interface StalenessCheckResult {
76
+ /** Recomputed hash from current children */
77
+ currentChildrenHash: string;
78
+ /** Whether the summary is stale */
79
+ isStale: boolean;
80
+ /** Directory path checked */
81
+ path: string;
82
+ /** Hash stored in existing _index.md (empty string if no summary exists) */
83
+ storedChildrenHash: string;
84
+ }
85
+ export interface SummaryGenerationResult {
86
+ /** Whether a summary was actually written */
87
+ actionTaken: boolean;
88
+ /** Compression ratio achieved (0 if not generated) */
89
+ compressionRatio: number;
90
+ /** Directory path */
91
+ path: string;
92
+ /** Why generation was skipped (only set when actionTaken is false) */
93
+ reason?: 'empty_directory' | 'io_error' | 'llm_error';
94
+ /** Which escalation tier succeeded */
95
+ tier?: 'aggressive' | 'fallback' | 'normal';
96
+ /** Token count of the generated summary (0 if not generated) */
97
+ tokenCount: number;
98
+ }
99
+ export interface ArchiveResult {
100
+ /** Path to the .full.md preserved content */
101
+ fullPath: string;
102
+ /** Token count of the ghost cue */
103
+ ghostCueTokenCount: number;
104
+ /** Original relative path of the archived entry */
105
+ originalPath: string;
106
+ /** Path to the .stub.md ghost cue */
107
+ stubPath: string;
108
+ }
109
+ export interface DrillDownResult {
110
+ /** Full original content */
111
+ fullContent: string;
112
+ /** Original path before archiving */
113
+ originalPath: string;
114
+ /** Token count of the full content */
115
+ tokenCount: number;
116
+ }
117
+ export interface ResolvedEntry {
118
+ /** File content */
119
+ content: string;
120
+ /** Relative path */
121
+ path: string;
122
+ /** Token count */
123
+ tokens: number;
124
+ /** Entry type */
125
+ type: 'context' | 'stub' | 'summary';
126
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Type definitions for the Hierarchical DAG architecture.
3
+ *
4
+ * Covers summary nodes, archive stubs, manifest entries, and
5
+ * result types used by summary/archive/manifest services.
6
+ */
7
+ export const DEFAULT_LANE_BUDGETS = { contexts: 4000, stubs: 500, summaries: 2000 };
@@ -468,12 +468,8 @@ export interface ProviderConfigResponse {
468
468
  provider?: string;
469
469
  providerApiKey?: string;
470
470
  providerBaseUrl?: string;
471
- providerCredentialError?: string;
472
- providerCredentialPath?: string;
473
471
  providerHeaders?: Record<string, string>;
474
472
  providerKeyMissing?: boolean;
475
- providerLocation?: string;
476
- providerProject?: string;
477
473
  }
478
474
  /**
479
475
  * Transport-generated client lifecycle events.
@@ -0,0 +1,30 @@
1
+ import type { ICipherAgent } from '../../../../agent/core/interfaces/i-cipher-agent.js';
2
+ import type { ArchiveResult, DrillDownResult } from '../../domain/knowledge/summary-types.js';
3
+ /**
4
+ * Service for archiving and restoring context tree entries.
5
+ *
6
+ * Archives low-importance entries into _archived/ with:
7
+ * - .stub.md: searchable ghost cue (~220 tokens)
8
+ * - .full.md: lossless preserved original content
9
+ */
10
+ export interface IContextTreeArchiveService {
11
+ /**
12
+ * Archive a context entry: write .full.md + .stub.md, delete original.
13
+ * Uses LLM to generate ghost cue with deterministic fallback.
14
+ */
15
+ archiveEntry(relativePath: string, agent: ICipherAgent, directory?: string): Promise<ArchiveResult>;
16
+ /**
17
+ * Drill down into an archived entry: read .full.md via stub's points_to.
18
+ * No LLM call — purely file-based lookup.
19
+ */
20
+ drillDown(stubPath: string, directory?: string): Promise<DrillDownResult>;
21
+ /**
22
+ * Find entries that are candidates for archiving.
23
+ * Returns paths where importance < ARCHIVE_IMPORTANCE_THRESHOLD and maturity === 'draft'.
24
+ */
25
+ findArchiveCandidates(directory?: string): Promise<string[]>;
26
+ /**
27
+ * Restore an archived entry: write .full.md content to original_path, delete stub + full.
28
+ */
29
+ restoreEntry(stubPath: string, directory?: string): Promise<string>;
30
+ }
@@ -0,0 +1,30 @@
1
+ import type { ContextManifest, LaneTokens, ResolvedEntry } from '../../domain/knowledge/summary-types.js';
2
+ /**
3
+ * Service for building and reading the context manifest (_manifest.json).
4
+ *
5
+ * The manifest allocates context tree entries into three lanes
6
+ * (summaries, contexts, stubs) with token budgets, enabling
7
+ * efficient context injection for queries.
8
+ */
9
+ export interface IContextTreeManifestService {
10
+ /**
11
+ * Build (or rebuild) the manifest from current context tree state.
12
+ * Writes _manifest.json and returns the manifest.
13
+ */
14
+ buildManifest(directory?: string, laneBudgets?: LaneTokens): Promise<ContextManifest>;
15
+ /**
16
+ * Read the manifest from disk. Returns null if no manifest exists.
17
+ */
18
+ readManifest(directory?: string): Promise<ContextManifest | null>;
19
+ /**
20
+ * Read the manifest only if it is fresh (source-fingerprint match).
21
+ * Returns null if the manifest is stale or missing.
22
+ */
23
+ readManifestIfFresh(directory?: string): Promise<ContextManifest | null>;
24
+ /**
25
+ * Resolve manifest entries into content ready for prompt injection.
26
+ * Orders: summaries (broadest first) → contexts → stubs.
27
+ * If query is provided, reorders contexts by BM25 relevance.
28
+ */
29
+ resolveForInjection(manifest: ContextManifest, query?: string, directory?: string): Promise<ResolvedEntry[]>;
30
+ }
@@ -0,0 +1,29 @@
1
+ import type { ICipherAgent } from '../../../../agent/core/interfaces/i-cipher-agent.js';
2
+ import type { StalenessCheckResult, SummaryGenerationResult } from '../../domain/knowledge/summary-types.js';
3
+ /**
4
+ * Service for managing hierarchical summary nodes (_index.md) in the context tree.
5
+ *
6
+ * Agent is passed per-call (not setter-based) to avoid race conditions
7
+ * with concurrent tasks (AGENT_MAX_CONCURRENT_TASKS = 5).
8
+ */
9
+ export interface IContextTreeSummaryService {
10
+ /**
11
+ * Check whether the summary for a directory is stale.
12
+ * Returns isStale: true if no _index.md exists or if children hash has changed.
13
+ */
14
+ checkStaleness(directoryPath: string, directory?: string): Promise<StalenessCheckResult>;
15
+ /**
16
+ * Generate or regenerate the _index.md summary for a directory.
17
+ * Uses three-tier escalation: normal → aggressive → deterministic fallback.
18
+ * Fail-open: returns { actionTaken: false } on any error.
19
+ */
20
+ generateSummary(directoryPath: string, agent: ICipherAgent, directory?: string): Promise<SummaryGenerationResult>;
21
+ /** Check whether a directory has an existing _index.md summary. */
22
+ hasSummary(directoryPath: string, directory?: string): Promise<boolean>;
23
+ /**
24
+ * Propagate staleness upward from changed paths.
25
+ * Processes bottom-up: regenerates stale summaries from deepest to shallowest.
26
+ * Stops climbing on LLM/IO errors; continues on empty directories.
27
+ */
28
+ propagateStaleness(changedPaths: string[], agent: ICipherAgent, directory?: string): Promise<SummaryGenerationResult[]>;
29
+ }