byterover-cli 3.0.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/.env.production +4 -0
  2. package/README.md +17 -0
  3. package/dist/agent/core/domain/tools/constants.d.ts +1 -0
  4. package/dist/agent/core/domain/tools/constants.js +1 -0
  5. package/dist/agent/core/interfaces/cipher-services.d.ts +8 -0
  6. package/dist/agent/core/interfaces/i-cipher-agent.d.ts +1 -0
  7. package/dist/agent/infra/agent/agent-error-codes.d.ts +0 -1
  8. package/dist/agent/infra/agent/agent-error-codes.js +0 -1
  9. package/dist/agent/infra/agent/agent-error.d.ts +0 -1
  10. package/dist/agent/infra/agent/agent-error.js +0 -1
  11. package/dist/agent/infra/agent/agent-schemas.d.ts +8 -0
  12. package/dist/agent/infra/agent/agent-schemas.js +1 -0
  13. package/dist/agent/infra/agent/agent-state-manager.d.ts +1 -3
  14. package/dist/agent/infra/agent/agent-state-manager.js +1 -3
  15. package/dist/agent/infra/agent/base-agent.d.ts +1 -1
  16. package/dist/agent/infra/agent/base-agent.js +1 -1
  17. package/dist/agent/infra/agent/cipher-agent.d.ts +15 -1
  18. package/dist/agent/infra/agent/cipher-agent.js +188 -3
  19. package/dist/agent/infra/agent/index.d.ts +1 -1
  20. package/dist/agent/infra/agent/index.js +1 -1
  21. package/dist/agent/infra/agent/service-initializer.d.ts +3 -3
  22. package/dist/agent/infra/agent/service-initializer.js +14 -8
  23. package/dist/agent/infra/agent/types.d.ts +0 -1
  24. package/dist/agent/infra/file-system/file-system-service.js +6 -5
  25. package/dist/agent/infra/folder-pack/folder-pack-service.d.ts +1 -0
  26. package/dist/agent/infra/folder-pack/folder-pack-service.js +29 -15
  27. package/dist/agent/infra/llm/providers/openai.js +12 -0
  28. package/dist/agent/infra/llm/stream-to-text.d.ts +7 -0
  29. package/dist/agent/infra/llm/stream-to-text.js +14 -0
  30. package/dist/agent/infra/map/abstract-generator.d.ts +22 -0
  31. package/dist/agent/infra/map/abstract-generator.js +67 -0
  32. package/dist/agent/infra/map/abstract-queue.d.ts +67 -0
  33. package/dist/agent/infra/map/abstract-queue.js +218 -0
  34. package/dist/agent/infra/memory/memory-deduplicator.d.ts +44 -0
  35. package/dist/agent/infra/memory/memory-deduplicator.js +88 -0
  36. package/dist/agent/infra/memory/memory-manager.d.ts +1 -0
  37. package/dist/agent/infra/memory/memory-manager.js +6 -5
  38. package/dist/agent/infra/sandbox/curate-service.d.ts +4 -2
  39. package/dist/agent/infra/sandbox/curate-service.js +20 -7
  40. package/dist/agent/infra/sandbox/local-sandbox.d.ts +5 -0
  41. package/dist/agent/infra/sandbox/local-sandbox.js +57 -1
  42. package/dist/agent/infra/sandbox/sandbox-service.js +1 -0
  43. package/dist/agent/infra/sandbox/tools-sdk.d.ts +13 -1
  44. package/dist/agent/infra/sandbox/tools-sdk.js +9 -1
  45. package/dist/agent/infra/session/session-compressor.d.ts +43 -0
  46. package/dist/agent/infra/session/session-compressor.js +296 -0
  47. package/dist/agent/infra/session/session-manager.d.ts +7 -0
  48. package/dist/agent/infra/session/session-manager.js +9 -0
  49. package/dist/agent/infra/tools/implementations/curate-tool.d.ts +3 -2
  50. package/dist/agent/infra/tools/implementations/curate-tool.js +54 -27
  51. package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +3 -3
  52. package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +34 -7
  53. package/dist/agent/infra/tools/implementations/ingest-resource-tool.d.ts +17 -0
  54. package/dist/agent/infra/tools/implementations/ingest-resource-tool.js +224 -0
  55. package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +8 -0
  56. package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -1
  57. package/dist/agent/infra/tools/implementations/search-knowledge-service.js +392 -106
  58. package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
  59. package/dist/agent/infra/tools/implementations/write-file-tool.d.ts +2 -1
  60. package/dist/agent/infra/tools/implementations/write-file-tool.js +16 -2
  61. package/dist/agent/infra/tools/tool-provider.js +1 -0
  62. package/dist/agent/infra/tools/tool-registry.d.ts +3 -0
  63. package/dist/agent/infra/tools/tool-registry.js +16 -5
  64. package/dist/agent/infra/tools/write-guard.d.ts +11 -0
  65. package/dist/agent/infra/tools/write-guard.js +48 -0
  66. package/dist/agent/resources/prompts/system-prompt.yml +9 -0
  67. package/dist/agent/resources/tools/expand_knowledge.txt +4 -0
  68. package/dist/agent/resources/tools/search_knowledge.txt +11 -1
  69. package/dist/oclif/commands/curate/index.js +4 -3
  70. package/dist/oclif/commands/curate/view.js +2 -2
  71. package/dist/oclif/commands/main.js +13 -0
  72. package/dist/oclif/commands/query.js +4 -3
  73. package/dist/oclif/commands/source/add.d.ts +12 -0
  74. package/dist/oclif/commands/source/add.js +42 -0
  75. package/dist/oclif/commands/source/index.d.ts +6 -0
  76. package/dist/oclif/commands/source/index.js +8 -0
  77. package/dist/oclif/commands/source/list.d.ts +6 -0
  78. package/dist/oclif/commands/source/list.js +32 -0
  79. package/dist/oclif/commands/source/remove.d.ts +9 -0
  80. package/dist/oclif/commands/source/remove.js +33 -0
  81. package/dist/oclif/commands/status.d.ts +5 -1
  82. package/dist/oclif/commands/status.js +41 -6
  83. package/dist/oclif/commands/worktree/add.d.ts +12 -0
  84. package/dist/oclif/commands/worktree/add.js +44 -0
  85. package/dist/oclif/commands/worktree/index.d.ts +6 -0
  86. package/dist/oclif/commands/worktree/index.js +8 -0
  87. package/dist/oclif/commands/worktree/list.d.ts +6 -0
  88. package/dist/oclif/commands/worktree/list.js +28 -0
  89. package/dist/oclif/commands/worktree/remove.d.ts +9 -0
  90. package/dist/oclif/commands/worktree/remove.js +35 -0
  91. package/dist/oclif/hooks/init/validate-brv-config.js +4 -0
  92. package/dist/oclif/lib/daemon-client.d.ts +4 -2
  93. package/dist/oclif/lib/daemon-client.js +19 -3
  94. package/dist/server/constants.d.ts +8 -0
  95. package/dist/server/constants.js +10 -0
  96. package/dist/server/core/domain/client/client-info.d.ts +7 -0
  97. package/dist/server/core/domain/client/client-info.js +11 -0
  98. package/dist/server/core/domain/knowledge/memory-scoring.d.ts +3 -3
  99. package/dist/server/core/domain/knowledge/memory-scoring.js +5 -5
  100. package/dist/server/core/domain/knowledge/summary-types.d.ts +4 -0
  101. package/dist/server/core/domain/project/worktrees-schema.d.ts +29 -0
  102. package/dist/server/core/domain/project/worktrees-schema.js +17 -0
  103. package/dist/server/core/domain/source/source-operations.d.ts +31 -0
  104. package/dist/server/core/domain/source/source-operations.js +201 -0
  105. package/dist/server/core/domain/source/source-schema.d.ts +94 -0
  106. package/dist/server/core/domain/source/source-schema.js +121 -0
  107. package/dist/server/core/domain/transport/schemas.d.ts +18 -10
  108. package/dist/server/core/domain/transport/schemas.js +4 -0
  109. package/dist/server/core/domain/transport/task-info.d.ts +2 -0
  110. package/dist/server/core/interfaces/client/i-client-manager.d.ts +13 -0
  111. package/dist/server/core/interfaces/executor/i-curate-executor.d.ts +4 -0
  112. package/dist/server/core/interfaces/executor/i-folder-pack-executor.d.ts +7 -3
  113. package/dist/server/core/interfaces/executor/i-query-executor.d.ts +2 -0
  114. package/dist/server/infra/client/client-manager.d.ts +1 -0
  115. package/dist/server/infra/client/client-manager.js +16 -0
  116. package/dist/server/infra/context-tree/derived-artifact.js +5 -1
  117. package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +2 -1
  118. package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +43 -7
  119. package/dist/server/infra/context-tree/file-context-tree-summary-service.js +20 -2
  120. package/dist/server/infra/daemon/agent-process.js +15 -5
  121. package/dist/server/infra/executor/curate-executor.js +6 -3
  122. package/dist/server/infra/executor/direct-search-responder.js +5 -1
  123. package/dist/server/infra/executor/folder-pack-executor.js +88 -7
  124. package/dist/server/infra/executor/query-executor.d.ts +23 -0
  125. package/dist/server/infra/executor/query-executor.js +125 -23
  126. package/dist/server/infra/mcp/mcp-mode-detector.d.ts +7 -5
  127. package/dist/server/infra/mcp/mcp-mode-detector.js +11 -18
  128. package/dist/server/infra/mcp/mcp-server.d.ts +1 -0
  129. package/dist/server/infra/mcp/mcp-server.js +11 -6
  130. package/dist/server/infra/mcp/tools/brv-curate-tool.d.ts +2 -1
  131. package/dist/server/infra/mcp/tools/brv-curate-tool.js +9 -16
  132. package/dist/server/infra/mcp/tools/brv-query-tool.d.ts +2 -1
  133. package/dist/server/infra/mcp/tools/brv-query-tool.js +9 -16
  134. package/dist/server/infra/mcp/tools/mcp-project-context.d.ts +11 -0
  135. package/dist/server/infra/mcp/tools/mcp-project-context.js +54 -0
  136. package/dist/server/infra/process/connection-coordinator.js +11 -0
  137. package/dist/server/infra/process/feature-handlers.js +4 -1
  138. package/dist/server/infra/process/task-router.d.ts +1 -0
  139. package/dist/server/infra/process/task-router.js +60 -5
  140. package/dist/server/infra/project/resolve-project.d.ts +106 -0
  141. package/dist/server/infra/project/resolve-project.js +473 -0
  142. package/dist/server/infra/transport/handlers/index.d.ts +4 -0
  143. package/dist/server/infra/transport/handlers/index.js +2 -0
  144. package/dist/server/infra/transport/handlers/source-handler.d.ts +12 -0
  145. package/dist/server/infra/transport/handlers/source-handler.js +37 -0
  146. package/dist/server/infra/transport/handlers/status-handler.js +65 -13
  147. package/dist/server/infra/transport/handlers/worktree-handler.d.ts +12 -0
  148. package/dist/server/infra/transport/handlers/worktree-handler.js +67 -0
  149. package/dist/server/infra/transport/transport-connector.d.ts +10 -4
  150. package/dist/server/infra/transport/transport-connector.js +2 -2
  151. package/dist/server/utils/curate-result-parser.d.ts +4 -4
  152. package/dist/server/utils/path-utils.d.ts +5 -0
  153. package/dist/server/utils/path-utils.js +11 -1
  154. package/dist/shared/transport/events/client-events.d.ts +3 -0
  155. package/dist/shared/transport/events/client-events.js +3 -0
  156. package/dist/shared/transport/events/index.d.ts +13 -0
  157. package/dist/shared/transport/events/index.js +9 -0
  158. package/dist/shared/transport/events/source-events.d.ts +30 -0
  159. package/dist/shared/transport/events/source-events.js +5 -0
  160. package/dist/shared/transport/events/status-events.d.ts +5 -0
  161. package/dist/shared/transport/events/task-events.d.ts +4 -1
  162. package/dist/shared/transport/events/worktree-events.d.ts +31 -0
  163. package/dist/shared/transport/events/worktree-events.js +5 -0
  164. package/dist/shared/transport/types/dto.d.ts +26 -0
  165. package/dist/tui/features/commands/definitions/index.js +6 -0
  166. package/dist/tui/features/commands/definitions/source-add.d.ts +2 -0
  167. package/dist/tui/features/commands/definitions/source-add.js +48 -0
  168. package/dist/tui/features/commands/definitions/source-list.d.ts +2 -0
  169. package/dist/tui/features/commands/definitions/source-list.js +47 -0
  170. package/dist/tui/features/commands/definitions/source-remove.d.ts +2 -0
  171. package/dist/tui/features/commands/definitions/source-remove.js +38 -0
  172. package/dist/tui/features/commands/definitions/source.d.ts +2 -0
  173. package/dist/tui/features/commands/definitions/source.js +8 -0
  174. package/dist/tui/features/commands/definitions/worktree-add.d.ts +2 -0
  175. package/dist/tui/features/commands/definitions/worktree-add.js +35 -0
  176. package/dist/tui/features/commands/definitions/worktree-list.d.ts +2 -0
  177. package/dist/tui/features/commands/definitions/worktree-list.js +36 -0
  178. package/dist/tui/features/commands/definitions/worktree-remove.d.ts +2 -0
  179. package/dist/tui/features/commands/definitions/worktree-remove.js +33 -0
  180. package/dist/tui/features/commands/definitions/worktree.d.ts +2 -0
  181. package/dist/tui/features/commands/definitions/worktree.js +8 -0
  182. package/dist/tui/features/curate/api/create-curate-task.js +3 -1
  183. package/dist/tui/features/query/api/create-query-task.js +3 -1
  184. package/dist/tui/features/source/api/source-api.d.ts +4 -0
  185. package/dist/tui/features/source/api/source-api.js +22 -0
  186. package/dist/tui/features/status/api/get-status.js +2 -1
  187. package/dist/tui/features/status/utils/format-status.js +23 -1
  188. package/dist/tui/features/transport/components/transport-initializer.js +36 -1
  189. package/dist/tui/features/worktree/api/worktree-api.d.ts +4 -0
  190. package/dist/tui/features/worktree/api/worktree-api.js +22 -0
  191. package/dist/tui/repl-startup.d.ts +2 -0
  192. package/dist/tui/repl-startup.js +5 -3
  193. package/dist/tui/stores/transport-store.d.ts +6 -0
  194. package/dist/tui/stores/transport-store.js +6 -0
  195. package/oclif.manifest.json +261 -1
  196. package/package.json +10 -4
package/.env.production CHANGED
@@ -1,3 +1,7 @@
1
+ # ByteRover CLI - Environment Configuration
2
+ # Copy this file to .env.development (for dev) or .env.production (for production)
3
+ # and fill in the values for your environment.
4
+
1
5
  BRV_API_BASE_URL=https://iam.byterover.dev/api/v1
2
6
  BRV_AUTHORIZATION_URL=https://iam.byterover.dev/api/v1/oidc/authorize
3
7
  BRV_COGIT_API_BASE_URL=https://v3-cgit.byterover.dev/api/v1
package/README.md CHANGED
@@ -241,6 +241,23 @@ ByteRover CLI supports 18 LLM providers out of the box. Use `brv providers conne
241
241
 
242
242
  </details>
243
243
 
244
+ ## Worktrees and Knowledge Sources
245
+
246
+ > **Vocabulary**
247
+ > - **Worktree link** — a subdirectory pointer to a parent project (`brv worktree`)
248
+ > - **Source** — a read-only reference to another project's knowledge (`brv source`)
249
+ > - **Origin** — where an indexed search result came from (`local` vs `shared`)
250
+
251
+ ByteRover can run from a linked subdirectory without creating a nested `.brv/`.
252
+
253
+ - `projectRoot`: the directory that owns `.brv/config.json`
254
+ - `worktreeRoot`: the linked worktree directory, or `projectRoot` when unlinked
255
+ - `clientCwd`: the shell cwd where you ran `brv`
256
+
257
+ When you run `brv query` or `brv curate` from a linked worktree, implicit defaults use `worktreeRoot` so scope stays stable even if `clientCwd` drifts deeper into the package. Explicit relative paths that you pass yourself, such as `brv curate -f ./src/auth.ts`, still resolve from `clientCwd` to match normal shell behavior.
258
+
259
+ Use `brv worktree add` from the project root to register a subdirectory (or sibling) as a worktree. This creates a `.brv` pointer file in the target directory that redirects to the parent project — the same pattern git uses for `git worktree`. Use `brv worktree remove` to unregister, and `brv worktree list` to inspect. To search another project's knowledge from here, use `brv source add <path>` (with `brv source list` / `brv source remove` to inspect or detach).
260
+
244
261
  ## Documentation
245
262
 
246
263
  Visit [**docs.byterover.dev**](https://docs.byterover.dev) for full guides on setup, integrations, and advanced usage.
@@ -9,6 +9,7 @@ export declare const ToolName: {
9
9
  readonly EXPAND_KNOWLEDGE: 'expand_knowledge';
10
10
  readonly GLOB_FILES: 'glob_files';
11
11
  readonly GREP_CONTENT: 'grep_content';
12
+ readonly INGEST_RESOURCE: 'ingest_resource';
12
13
  readonly LIST_DIRECTORY: 'list_directory';
13
14
  readonly LLM_MAP: 'llm_map';
14
15
  readonly READ_FILE: 'read_file';
@@ -9,6 +9,7 @@ export const ToolName = {
9
9
  EXPAND_KNOWLEDGE: 'expand_knowledge',
10
10
  GLOB_FILES: 'glob_files',
11
11
  GREP_CONTENT: 'grep_content',
12
+ INGEST_RESOURCE: 'ingest_resource',
12
13
  LIST_DIRECTORY: 'list_directory',
13
14
  LLM_MAP: 'llm_map',
14
15
  READ_FILE: 'read_file',
@@ -1,6 +1,7 @@
1
1
  import type { AgentEventBus, SessionEventBus } from '../../infra/events/event-emitter.js';
2
2
  import type { FileSystemService } from '../../infra/file-system/file-system-service.js';
3
3
  import type { CompactionService } from '../../infra/llm/context/compaction/compaction-service.js';
4
+ import type { AbstractGenerationQueue } from '../../infra/map/abstract-queue.js';
4
5
  import type { MemoryManager } from '../../infra/memory/memory-manager.js';
5
6
  import type { ProcessService } from '../../infra/process/process-service.js';
6
7
  import type { MessageStorageService } from '../../infra/storage/message-storage-service.js';
@@ -30,6 +31,11 @@ import type { IToolScheduler } from './i-tool-scheduler.js';
30
31
  * - ToolProvider: Provides available tools
31
32
  */
32
33
  export interface CipherAgentServices {
34
+ /**
35
+ * Background queue for generating L0/L1 abstract files (.abstract.md, .overview.md).
36
+ * Generator is injected lazily via setGenerator() from rebindCurateTools().
37
+ */
38
+ abstractQueue: AbstractGenerationQueue;
33
39
  agentEventBus: AgentEventBus;
34
40
  blobStorage: IBlobStorage;
35
41
  /**
@@ -50,6 +56,8 @@ export interface CipherAgentServices {
50
56
  toolManager: ToolManager;
51
57
  toolProvider: ToolProvider;
52
58
  toolScheduler: IToolScheduler;
59
+ /** Absolute path to the project working directory. */
60
+ workingDirectory: string;
53
61
  }
54
62
  /**
55
63
  * Session-specific services created per conversation session.
@@ -78,6 +78,7 @@ export interface ICipherAgent {
78
78
  */
79
79
  createTaskSession(taskId: string, commandType: string, options?: {
80
80
  mapRootEligible?: boolean;
81
+ userFacing?: boolean;
81
82
  }): Promise<string>;
82
83
  /**
83
84
  * Delete a sandbox variable from the agent's default session.
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * Agent-specific error codes.
3
- * Follows DextoAgent pattern for typed error identification.
4
3
  */
5
4
  export declare enum AgentErrorCode {
6
5
  ALREADY_STARTED = "agent_already_started",
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * Agent-specific error codes.
3
- * Follows DextoAgent pattern for typed error identification.
4
3
  */
5
4
  export var AgentErrorCode;
6
5
  (function (AgentErrorCode) {
@@ -4,7 +4,6 @@ import { AgentErrorCode } from './agent-error-codes.js';
4
4
  * Agent-specific error with typed error codes.
5
5
  * Extends ExitError for oclif CLI integration.
6
6
  *
7
- * Follows DextoAgent pattern with static factory methods
8
7
  * for creating well-typed errors.
9
8
  */
10
9
  export declare class AgentError extends ExitError {
@@ -4,7 +4,6 @@ import { AgentErrorCode } from './agent-error-codes.js';
4
4
  * Agent-specific error with typed error codes.
5
5
  * Extends ExitError for oclif CLI integration.
6
6
  *
7
- * Follows DextoAgent pattern with static factory methods
8
7
  * for creating well-typed errors.
9
8
  */
10
9
  export class AgentError extends ExitError {
@@ -46,13 +46,16 @@ export type ValidatedSessionConfig = z.output<typeof SessionConfigSchema>;
46
46
  */
47
47
  export declare const FileSystemConfigSchema: z.ZodObject<{
48
48
  allowedExtensions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
49
+ allowedPaths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
49
50
  maxFileSize: z.ZodOptional<z.ZodNumber>;
50
51
  workingDirectory: z.ZodOptional<z.ZodString>;
51
52
  }, "strict", z.ZodTypeAny, {
53
+ allowedPaths?: string[] | undefined;
52
54
  allowedExtensions?: string[] | undefined;
53
55
  workingDirectory?: string | undefined;
54
56
  maxFileSize?: number | undefined;
55
57
  }, {
58
+ allowedPaths?: string[] | undefined;
56
59
  allowedExtensions?: string[] | undefined;
57
60
  workingDirectory?: string | undefined;
58
61
  maxFileSize?: number | undefined;
@@ -101,13 +104,16 @@ export declare const AgentConfigSchema: z.ZodObject<{
101
104
  }>>;
102
105
  fileSystem: z.ZodOptional<z.ZodObject<{
103
106
  allowedExtensions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
107
+ allowedPaths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
104
108
  maxFileSize: z.ZodOptional<z.ZodNumber>;
105
109
  workingDirectory: z.ZodOptional<z.ZodString>;
106
110
  }, "strict", z.ZodTypeAny, {
111
+ allowedPaths?: string[] | undefined;
107
112
  allowedExtensions?: string[] | undefined;
108
113
  workingDirectory?: string | undefined;
109
114
  maxFileSize?: number | undefined;
110
115
  }, {
116
+ allowedPaths?: string[] | undefined;
111
117
  allowedExtensions?: string[] | undefined;
112
118
  workingDirectory?: string | undefined;
113
119
  maxFileSize?: number | undefined;
@@ -185,6 +191,7 @@ export declare const AgentConfigSchema: z.ZodObject<{
185
191
  storageDir: string;
186
192
  } | undefined;
187
193
  fileSystem?: {
194
+ allowedPaths?: string[] | undefined;
188
195
  allowedExtensions?: string[] | undefined;
189
196
  workingDirectory?: string | undefined;
190
197
  maxFileSize?: number | undefined;
@@ -223,6 +230,7 @@ export declare const AgentConfigSchema: z.ZodObject<{
223
230
  maxBlobSize?: number | undefined;
224
231
  } | undefined;
225
232
  fileSystem?: {
233
+ allowedPaths?: string[] | undefined;
226
234
  allowedExtensions?: string[] | undefined;
227
235
  workingDirectory?: string | undefined;
228
236
  maxFileSize?: number | undefined;
@@ -27,6 +27,7 @@ export const SessionConfigSchema = z
27
27
  export const FileSystemConfigSchema = z
28
28
  .object({
29
29
  allowedExtensions: z.array(z.string()).optional().describe('Allowed file extensions'),
30
+ allowedPaths: z.array(z.string()).optional().describe('Allowed paths for file operations (default: ["."])'),
30
31
  maxFileSize: z.number().positive().optional().describe('Maximum file size in bytes'),
31
32
  workingDirectory: z.string().optional().describe('Working directory for file operations'),
32
33
  })
@@ -9,11 +9,9 @@ export interface SessionOverride {
9
9
  llm?: Partial<ValidatedLLMConfig>;
10
10
  }
11
11
  /**
12
- * Unified agent state manager combining DextoAgent config patterns with execution state tracking.
13
- *
14
12
  * Manages two concerns:
15
13
  *
16
- * 1. Configuration State (DextoAgent pattern):
14
+ * 1. Configuration State:
17
15
  * - baselineConfig: Original validated config, never mutated
18
16
  * - runtimeConfig: Current active config, can be mutated
19
17
  * - sessionOverrides: Per-session config overrides
@@ -1,9 +1,7 @@
1
1
  /**
2
- * Unified agent state manager combining DextoAgent config patterns with execution state tracking.
3
- *
4
2
  * Manages two concerns:
5
3
  *
6
- * 1. Configuration State (DextoAgent pattern):
4
+ * 1. Configuration State:
7
5
  * - baselineConfig: Original validated config, never mutated
8
6
  * - runtimeConfig: Current active config, can be mutated
9
7
  * - sessionOverrides: Per-session config overrides
@@ -3,7 +3,7 @@ import type { AgentEventBus } from '../events/event-emitter.js';
3
3
  import { type LLMUpdates, type ValidatedAgentConfig, type ValidatedLLMConfig } from './agent-schemas.js';
4
4
  import { AgentStateManager } from './agent-state-manager.js';
5
5
  /**
6
- * Abstract base agent class encapsulating DextoAgent patterns.
6
+ * Abstract base agent class encapsulating.
7
7
  *
8
8
  * Provides:
9
9
  * - Two-phase initialization (constructor + start)
@@ -2,7 +2,7 @@ import { AgentError } from './agent-error.js';
2
2
  import { AgentConfigSchema, LLMUpdatesSchema } from './agent-schemas.js';
3
3
  import { AgentStateManager } from './agent-state-manager.js';
4
4
  /**
5
- * Abstract base agent class encapsulating DextoAgent patterns.
5
+ * Abstract base agent class encapsulating.
6
6
  *
7
7
  * Provides:
8
8
  * - Two-phase initialization (constructor + start)
@@ -25,7 +25,7 @@ import { BaseAgent } from './base-agent.js';
25
25
  * - Typed error handling
26
26
  * - Configuration validation (Zod)
27
27
  *
28
- * Architecture (DextoAgent pattern):
28
+ * Architecture:
29
29
  * - Agent creates AgentEventBus in constructor (available before start)
30
30
  * - Agent creates and owns shared services (ToolManager, SystemPromptManager, etc.)
31
31
  * - SessionManager creates session-specific services (LLM, SessionEventBus)
@@ -57,7 +57,11 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
57
57
  * Used for bulk deregistration on agent teardown (cleanupServices).
58
58
  */
59
59
  private readonly rootEligibleSessions;
60
+ /** Lazily-created session compressor, rebuilt on each rebindCurateTools() call. */
61
+ private sessionCompressor?;
60
62
  private sessionManager?;
63
+ /** Tracks user-facing task sessions for post-session memory extraction. */
64
+ private readonly userFacingTaskSessions;
61
65
  /**
62
66
  * Creates a new CipherAgent instance.
63
67
  * Does NOT initialize services - call start() for async initialization.
@@ -114,6 +118,7 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
114
118
  */
115
119
  createTaskSession(taskId: string, commandType: string, options?: {
116
120
  mapRootEligible?: boolean;
121
+ userFacing?: boolean;
117
122
  }): Promise<string>;
118
123
  /**
119
124
  * Delete a sandbox variable from the agent's default session.
@@ -131,6 +136,11 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
131
136
  * Delete a task session and all its resources (sandbox + history).
132
137
  */
133
138
  deleteTaskSession(sessionId: string): Promise<void>;
139
+ /**
140
+ * Wait for shared background work (such as abstract generation) to finish.
141
+ * Used by task executors before reporting task completion.
142
+ */
143
+ drainBackgroundWork(): Promise<void>;
134
144
  /**
135
145
  * Execute the agent with user input.
136
146
  * Uses the agent's default session (created during start()).
@@ -260,6 +270,8 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
260
270
  * Uses lazy providers when injected (child process mode), otherwise static config.
261
271
  */
262
272
  private buildHttpConfig;
273
+ private createFreshRetryableGenerator;
274
+ private drainAbstractQueue;
263
275
  private getHistoryStorageInternal;
264
276
  private getSessionIdInternal;
265
277
  private getSessionManagerInternal;
@@ -273,7 +285,9 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
273
285
  * Rebuild map tool dependencies and update ToolProvider + SandboxService.
274
286
  * Called from both start() (initial setup) and refreshProviderConfig() (hot-swap).
275
287
  */
288
+ private rebindCurateTools;
276
289
  private rebindMapTools;
290
+ private refreshSessionCompressorFromTransport;
277
291
  /**
278
292
  * Register a session as root-eligible and track it for lifecycle cleanup.
279
293
  * Routes all root-eligible registrations through a single point.
@@ -1,17 +1,25 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { setMaxListeners } from 'node:events';
3
+ import { TransportStateEventNames } from '../../../server/core/domain/transport/schemas.js';
4
+ import { agentLog } from '../../../server/utils/process-logger.js';
3
5
  import { getEffectiveMaxInputTokens, resolveRegistryProvider } from '../../core/domain/llm/index.js';
4
6
  import { STREAMING_EVENT_NAMES } from '../../core/domain/streaming/types.js';
5
7
  import { ToolName } from '../../core/domain/tools/constants.js';
6
8
  import { AgentEventBus } from '../events/event-emitter.js';
9
+ import { RetryableContentGenerator } from '../llm/generators/index.js';
7
10
  import { createGeneratorForProvider } from '../llm/providers/index.js';
11
+ import { DEFAULT_RETRY_POLICY } from '../llm/retry/retry-policy.js';
8
12
  import { EventBasedLogger } from '../logger/event-based-logger.js';
9
13
  import { deregisterRootEligibleSession, registerRootEligibleSession } from '../map/agentic-map-service.js';
14
+ import { MemoryDeduplicator } from '../memory/memory-deduplicator.js';
15
+ import { createCurateService } from '../sandbox/curate-service.js';
16
+ import { SessionCompressor } from '../session/session-compressor.js';
10
17
  import { SessionManager } from '../session/session-manager.js';
11
18
  import { TransportEventBridge } from '../transport/transport-event-bridge.js';
12
19
  import { AgentError } from './agent-error.js';
13
20
  import { BaseAgent } from './base-agent.js';
14
21
  import { createCipherAgentServices } from './service-initializer.js';
22
+ const QUEUE_TRACE_ENABLED = process.env.BRV_QUEUE_TRACE === '1';
15
23
  /**
16
24
  * CipherAgent - Main agent implementation extending BaseAgent.
17
25
  *
@@ -22,7 +30,7 @@ import { createCipherAgentServices } from './service-initializer.js';
22
30
  * - Typed error handling
23
31
  * - Configuration validation (Zod)
24
32
  *
25
- * Architecture (DextoAgent pattern):
33
+ * Architecture:
26
34
  * - Agent creates AgentEventBus in constructor (available before start)
27
35
  * - Agent creates and owns shared services (ToolManager, SystemPromptManager, etc.)
28
36
  * - SessionManager creates session-specific services (LLM, SessionEventBus)
@@ -55,7 +63,11 @@ export class CipherAgent extends BaseAgent {
55
63
  * Used for bulk deregistration on agent teardown (cleanupServices).
56
64
  */
57
65
  rootEligibleSessions = new Set();
66
+ /** Lazily-created session compressor, rebuilt on each rebindCurateTools() call. */
67
+ sessionCompressor;
58
68
  sessionManager;
69
+ /** Tracks user-facing task sessions for post-session memory extraction. */
70
+ userFacingTaskSessions = new Set();
59
71
  /**
60
72
  * Creates a new CipherAgent instance.
61
73
  * Does NOT initialize services - call start() for async initialization.
@@ -72,7 +84,7 @@ export class CipherAgent extends BaseAgent {
72
84
  constructor(config, brvConfig, options) {
73
85
  // Call parent constructor (validates with Zod)
74
86
  super(config);
75
- // Create event bus early (DextoAgent pattern - available before start)
87
+ // Create event bus early (available before start)
76
88
  this._agentEventBus = new AgentEventBus();
77
89
  this._brvConfig = brvConfig;
78
90
  this._projectIdProvider = options?.projectIdProvider;
@@ -146,6 +158,8 @@ export class CipherAgent extends BaseAgent {
146
158
  }
147
159
  // === Public Methods (alphabetical order) ===
148
160
  async cleanupServices() {
161
+ // Drain abstract generation queue before session disposal
162
+ await this.drainAbstractQueue();
149
163
  // Abort all active streams and clear controllers
150
164
  for (const controller of this.activeStreamControllers.values()) {
151
165
  controller.abort();
@@ -207,6 +221,10 @@ export class CipherAgent extends BaseAgent {
207
221
  if (options?.mapRootEligible) {
208
222
  this.registerSessionInternal(childSession.id);
209
223
  }
224
+ // Track user-facing sessions for post-session memory extraction.
225
+ if (options?.userFacing) {
226
+ this.userFacingTaskSessions.add(childSession.id);
227
+ }
210
228
  return childSession.id;
211
229
  }
212
230
  /**
@@ -248,6 +266,38 @@ export class CipherAgent extends BaseAgent {
248
266
  */
249
267
  async deleteTaskSession(sessionId) {
250
268
  this.ensureStarted();
269
+ // Compress memories for user-facing sessions before disposal (fail-open).
270
+ if (this.userFacingTaskSessions.has(sessionId) && this.sessionCompressor) {
271
+ try {
272
+ // Refresh OAuth token and rebuild compressor before compression
273
+ if (this._transportClient && this.services) {
274
+ try {
275
+ await this.refreshSessionCompressorFromTransport();
276
+ }
277
+ catch {
278
+ // Fail-open: use existing compressor with potentially stale token
279
+ }
280
+ }
281
+ const session = this.getSessionManagerInternal().getSession(sessionId);
282
+ if (session) {
283
+ const messages = session.getLLMService().getContextManager().getComprehensiveMessages();
284
+ const commandType = this.getSessionManagerInternal().getSessionCommandType(sessionId) ?? 'curate';
285
+ // Task sessions often contain a compact prompt/response trace, so use a
286
+ // lower threshold than the interactive default to preserve useful memories.
287
+ await this.sessionCompressor.compress(messages, commandType, { minMessages: 2 }).catch((error) => {
288
+ const msg = error instanceof Error ? error.message : String(error);
289
+ console.debug(`[CipherAgent] Session compression failed for ${sessionId}: ${msg}`);
290
+ });
291
+ }
292
+ }
293
+ catch (error) {
294
+ // Fail-open: synchronous errors in the session accessor chain (e.g. corrupted
295
+ // session state) must not prevent clearSession + deleteSession from running.
296
+ const msg = error instanceof Error ? error.message : String(error);
297
+ console.debug(`[CipherAgent] Session compression setup failed for ${sessionId}: ${msg}`);
298
+ }
299
+ this.userFacingTaskSessions.delete(sessionId);
300
+ }
251
301
  await this.services.sandboxService.clearSession(sessionId);
252
302
  await this.getSessionManagerInternal().deleteSession(sessionId);
253
303
  // Deregister root-eligible record if this agent owns it.
@@ -258,6 +308,14 @@ export class CipherAgent extends BaseAgent {
258
308
  this.rootEligibleSessions.delete(sessionId);
259
309
  }
260
310
  }
311
+ /**
312
+ * Wait for shared background work (such as abstract generation) to finish.
313
+ * Used by task executors before reporting task completion.
314
+ */
315
+ async drainBackgroundWork() {
316
+ this.ensureStarted();
317
+ await this.drainAbstractQueue();
318
+ }
261
319
  /**
262
320
  * Execute the agent with user input.
263
321
  * Uses the agent's default session (created during start()).
@@ -388,7 +446,7 @@ export class CipherAgent extends BaseAgent {
388
446
  return this.getSystemPromptManagerInternal().build({});
389
447
  }
390
448
  async initializeServices() {
391
- // Pass pre-created event bus to service initializer (DextoAgent pattern)
449
+ // Pass pre-created event bus to service initializer
392
450
  return createCipherAgentServices(this.config, this._agentEventBus);
393
451
  }
394
452
  /**
@@ -461,6 +519,8 @@ export class CipherAgent extends BaseAgent {
461
519
  this.services.sandboxService.setSessionManager?.(this.sessionManager);
462
520
  // Rebind map tools with fresh generator/tokenizer/maxContextTokens
463
521
  this.rebindMapTools(services, httpConfig, sessionLLMConfig);
522
+ // Rebind curate tools with fresh generator + abstract queue
523
+ this.rebindCurateTools(services, httpConfig, sessionLLMConfig);
464
524
  }
465
525
  /**
466
526
  * Reset the agent to initial state.
@@ -562,6 +622,8 @@ export class CipherAgent extends BaseAgent {
562
622
  // Uses rebindMapTools() which atomically replaces map tools with fresh deps
563
623
  // (generator, tokenizer, maxContextTokens, logger).
564
624
  this.rebindMapTools(services, httpConfig, sessionLLMConfig);
625
+ // Wire abstract generation queue with curate generator + rebuild curate service.
626
+ this.rebindCurateTools(services, httpConfig, sessionLLMConfig);
565
627
  // Create event bridge if transport client is injected (child process mode).
566
628
  // The bridge forwards AgentEventBus llmservice:* events to the transport server.
567
629
  if (this._transportClient) {
@@ -778,6 +840,64 @@ export class CipherAgent extends BaseAgent {
778
840
  };
779
841
  }
780
842
  // === Private Helpers (alphabetical order) ===
843
+ createFreshRetryableGenerator(fresh, options) {
844
+ if (fresh.providerKeyMissing || !fresh.activeProvider) {
845
+ return;
846
+ }
847
+ const provider = fresh.provider ?? (fresh.openRouterApiKey ? 'openrouter' : 'byterover');
848
+ const freshGenerator = createGeneratorForProvider(provider, {
849
+ apiKey: provider === 'openrouter'
850
+ ? (fresh.openRouterApiKey ?? fresh.providerApiKey)
851
+ : fresh.providerApiKey,
852
+ baseUrl: fresh.providerBaseUrl,
853
+ headers: fresh.providerHeaders,
854
+ httpConfig: options.httpConfig,
855
+ httpReferer: options.httpReferer,
856
+ maxTokens: 4096,
857
+ model: fresh.activeModel ?? options.modelFallback,
858
+ siteName: options.siteName,
859
+ temperature: 0,
860
+ });
861
+ return new RetryableContentGenerator(freshGenerator, { policy: DEFAULT_RETRY_POLICY });
862
+ }
863
+ async drainAbstractQueue() {
864
+ const abstractQueue = this.services?.abstractQueue;
865
+ if (!abstractQueue) {
866
+ return;
867
+ }
868
+ const settleDeadline = Date.now() + 5000;
869
+ let idleSince;
870
+ let pass = 0;
871
+ /* eslint-disable no-await-in-loop */
872
+ while (Date.now() <= settleDeadline) {
873
+ pass++;
874
+ if (QUEUE_TRACE_ENABLED) {
875
+ agentLog(`drainAbstractQueue:pass:${pass}:start`);
876
+ }
877
+ await abstractQueue.drain();
878
+ const status = abstractQueue.getStatus();
879
+ if (QUEUE_TRACE_ENABLED) {
880
+ agentLog(`drainAbstractQueue:pass:${pass}:status pending=${status.pending} processing=${status.processing} processed=${status.processed} failed=${status.failed}`);
881
+ }
882
+ if (!status.processing && status.pending === 0) {
883
+ idleSince ??= Date.now();
884
+ if (Date.now() - idleSince >= 250) {
885
+ if (QUEUE_TRACE_ENABLED) {
886
+ agentLog(`drainAbstractQueue:settled pass=${pass}`);
887
+ }
888
+ return;
889
+ }
890
+ }
891
+ else {
892
+ idleSince = undefined;
893
+ }
894
+ await new Promise((resolve) => { setTimeout(resolve, 100); });
895
+ }
896
+ /* eslint-enable no-await-in-loop */
897
+ if (QUEUE_TRACE_ENABLED) {
898
+ agentLog('drainAbstractQueue:deadline-reached');
899
+ }
900
+ }
781
901
  getHistoryStorageInternal() {
782
902
  const storage = this.services?.historyStorage;
783
903
  if (!storage) {
@@ -818,6 +938,54 @@ export class CipherAgent extends BaseAgent {
818
938
  * Rebuild map tool dependencies and update ToolProvider + SandboxService.
819
939
  * Called from both start() (initial setup) and refreshProviderConfig() (hot-swap).
820
940
  */
941
+ rebindCurateTools(services, httpConfig, sessionLLMConfig) {
942
+ const curateProvider = sessionLLMConfig.provider
943
+ ?? (sessionLLMConfig.openRouterApiKey ? 'openrouter' : 'byterover');
944
+ const curateGenerator = createGeneratorForProvider(curateProvider, {
945
+ apiKey: curateProvider === 'openrouter'
946
+ ? (sessionLLMConfig.openRouterApiKey ?? sessionLLMConfig.providerApiKey)
947
+ : sessionLLMConfig.providerApiKey,
948
+ baseUrl: sessionLLMConfig.providerBaseUrl,
949
+ headers: sessionLLMConfig.providerHeaders,
950
+ httpConfig: httpConfig,
951
+ httpReferer: sessionLLMConfig.httpReferer,
952
+ maxTokens: 4096,
953
+ model: sessionLLMConfig.model,
954
+ siteName: sessionLLMConfig.siteName,
955
+ temperature: 0,
956
+ });
957
+ // Wrap with retry for background resilience (no event bus — background tasks have no UI)
958
+ const retryableCurateGenerator = new RetryableContentGenerator(curateGenerator, {
959
+ policy: DEFAULT_RETRY_POLICY,
960
+ });
961
+ // Wire generator into the abstract queue so background generation can proceed
962
+ services.abstractQueue.setGenerator(retryableCurateGenerator);
963
+ // Refresh OAuth token before each background generation (tokens expire between tasks)
964
+ if (this._transportClient) {
965
+ const transportClient = this._transportClient;
966
+ services.abstractQueue.setBeforeProcess(async () => {
967
+ const fresh = await transportClient.requestWithAck(TransportStateEventNames.GET_PROVIDER_CONFIG);
968
+ const retryableFreshGenerator = this.createFreshRetryableGenerator(fresh, {
969
+ httpConfig,
970
+ httpReferer: sessionLLMConfig.httpReferer,
971
+ modelFallback: sessionLLMConfig.model,
972
+ siteName: sessionLLMConfig.siteName,
973
+ });
974
+ if (!retryableFreshGenerator) {
975
+ return;
976
+ }
977
+ services.abstractQueue.setGenerator(retryableFreshGenerator);
978
+ });
979
+ }
980
+ // Rebuild sandbox CurateService with the queue — reuses existing hot-swap path
981
+ const newCurateService = createCurateService(services.workingDirectory, services.abstractQueue);
982
+ services.sandboxService.setCurateService?.(newCurateService);
983
+ // Atomically rebuild CURATE + INGEST_RESOURCE tools so both enqueue abstracts
984
+ services.toolProvider.replaceTools([ToolName.CURATE, ToolName.INGEST_RESOURCE], { abstractQueue: services.abstractQueue, contentGenerator: retryableCurateGenerator });
985
+ // Rebuild session compressor with the new generator (used in deleteTaskSession)
986
+ const deduplicator = new MemoryDeduplicator(retryableCurateGenerator);
987
+ this.sessionCompressor = new SessionCompressor(deduplicator, retryableCurateGenerator, services.memoryManager);
988
+ }
821
989
  rebindMapTools(services, httpConfig, sessionLLMConfig) {
822
990
  const mapProvider = sessionLLMConfig.provider
823
991
  ?? (sessionLLMConfig.openRouterApiKey ? 'openrouter' : 'byterover');
@@ -855,6 +1023,23 @@ export class CipherAgent extends BaseAgent {
855
1023
  // Update sandbox for tools.curation.mapExtract()
856
1024
  services.sandboxService.setContentGenerator?.(mapGenerator);
857
1025
  }
1026
+ async refreshSessionCompressorFromTransport() {
1027
+ if (!this._transportClient || !this.services) {
1028
+ return;
1029
+ }
1030
+ const fresh = await this._transportClient.requestWithAck(TransportStateEventNames.GET_PROVIDER_CONFIG);
1031
+ const retryable = this.createFreshRetryableGenerator(fresh, {
1032
+ httpConfig: this.buildHttpConfig(),
1033
+ httpReferer: this.config.httpReferer,
1034
+ modelFallback: this.stateManager?.getModel() ?? this.config.model,
1035
+ siteName: this.config.siteName,
1036
+ });
1037
+ if (!retryable) {
1038
+ return;
1039
+ }
1040
+ const deduplicator = new MemoryDeduplicator(retryable);
1041
+ this.sessionCompressor = new SessionCompressor(deduplicator, retryable, this.services.memoryManager);
1042
+ }
858
1043
  /**
859
1044
  * Register a session as root-eligible and track it for lifecycle cleanup.
860
1045
  * Routes all root-eligible registrations through a single point.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Agent module - Complete cipher agent implementation following DextoAgent patterns
2
+ * Agent module - Complete cipher agent implementation
3
3
  *
4
4
  * This module provides the full agent architecture with:
5
5
  * - CipherAgent: Main agent class for LLM interactions
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Agent module - Complete cipher agent implementation following DextoAgent patterns
2
+ * Agent module - Complete cipher agent implementation
3
3
  *
4
4
  * This module provides the full agent architecture with:
5
5
  * - CipherAgent: Main agent class for LLM interactions
@@ -4,7 +4,7 @@
4
4
  * This module is responsible for initializing and wiring together all core agent services.
5
5
  * It provides a single entry point for constructing the service graph.
6
6
  *
7
- * Following DextoAgent pattern:
7
+ * Following pattern:
8
8
  * - Config file is source of truth (ValidatedAgentConfig)
9
9
  * - Centralized function (not factory class) for service creation
10
10
  * - Explicit dependency order with numbered steps
@@ -61,7 +61,7 @@ export type { CipherAgentServices, SessionManagerConfig, SessionServices } from
61
61
  * Creates shared services for CipherAgent.
62
62
  * These services are singletons shared across all sessions.
63
63
  *
64
- * Initialization order follows DextoAgent pattern (explicit numbered steps):
64
+ * Initialization order (explicit numbered steps):
65
65
  * 1. Logger (uses provided event bus)
66
66
  * 2. File system service (no dependencies)
67
67
  * 3. Process service (no dependencies)
@@ -76,7 +76,7 @@ export type { CipherAgentServices, SessionManagerConfig, SessionServices } from
76
76
  * 12. Return all services
77
77
  *
78
78
  * @param config - Validated agent configuration (Zod-validated)
79
- * @param agentEventBus - Pre-created event bus from agent constructor (DextoAgent pattern)
79
+ * @param agentEventBus - Pre-created event bus from agent constructor
80
80
  * @returns Initialized shared services
81
81
  */
82
82
  export declare function createCipherAgentServices(config: ValidatedAgentConfig, agentEventBus: AgentEventBus): Promise<CipherAgentServices>;