byterover-cli 1.0.2 → 1.0.4

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 (128) hide show
  1. package/README.md +62 -10
  2. package/dist/commands/curate.js +2 -2
  3. package/dist/commands/main.js +2 -2
  4. package/dist/commands/query.js +2 -2
  5. package/dist/commands/status.js +2 -2
  6. package/dist/config/context-tree-domains.d.ts +14 -2
  7. package/dist/config/context-tree-domains.js +22 -27
  8. package/dist/constants.d.ts +1 -0
  9. package/dist/constants.js +3 -0
  10. package/dist/core/domain/cipher/file-system/types.d.ts +2 -0
  11. package/dist/core/domain/entities/auth-token.js +6 -3
  12. package/dist/core/domain/entities/event.d.ts +1 -1
  13. package/dist/core/domain/entities/event.js +2 -1
  14. package/dist/core/domain/knowledge/relation-parser.d.ts +16 -1
  15. package/dist/core/domain/knowledge/relation-parser.js +19 -2
  16. package/dist/core/domain/transport/schemas.d.ts +17 -1
  17. package/dist/core/domain/transport/schemas.js +9 -1
  18. package/dist/core/interfaces/cipher/i-blob-storage.d.ts +6 -0
  19. package/dist/core/interfaces/cipher/index.d.ts +0 -1
  20. package/dist/core/interfaces/executor/i-curate-executor.d.ts +2 -0
  21. package/dist/infra/cipher/agent/cipher-agent.js +4 -0
  22. package/dist/infra/cipher/file-system/file-system-service.d.ts +4 -0
  23. package/dist/infra/cipher/file-system/file-system-service.js +5 -0
  24. package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.js +4 -2
  25. package/dist/infra/cipher/tools/implementations/create-knowledge-topic-tool.js +24 -17
  26. package/dist/infra/cipher/tools/implementations/curate-tool.js +28 -33
  27. package/dist/infra/cipher/tools/implementations/read-file-tool.js +3 -12
  28. package/dist/infra/cipher/tools/implementations/spec-analyze-tool.js +18 -15
  29. package/dist/infra/cipher/tools/implementations/task-tool.js +53 -7
  30. package/dist/infra/context-tree/file-context-tree-service.js +4 -15
  31. package/dist/infra/core/executors/curate-executor.d.ts +2 -7
  32. package/dist/infra/core/executors/curate-executor.js +18 -53
  33. package/dist/infra/core/executors/query-executor.d.ts +1 -7
  34. package/dist/infra/core/executors/query-executor.js +10 -35
  35. package/dist/infra/core/task-processor.d.ts +2 -0
  36. package/dist/infra/core/task-processor.js +1 -0
  37. package/dist/infra/http/authenticated-http-client.js +5 -0
  38. package/dist/infra/process/agent-worker.js +113 -6
  39. package/dist/infra/process/constants.d.ts +1 -0
  40. package/dist/infra/process/constants.js +1 -0
  41. package/dist/infra/process/task-queue-manager.js +2 -1
  42. package/dist/infra/process/transport-handlers.js +4 -0
  43. package/dist/infra/process/transport-worker.js +89 -1
  44. package/dist/infra/repl/commands/curate-command.js +2 -2
  45. package/dist/infra/repl/commands/gen-rules-command.js +2 -2
  46. package/dist/infra/repl/commands/init-command.js +2 -2
  47. package/dist/infra/repl/commands/login-command.js +2 -2
  48. package/dist/infra/repl/commands/logout-command.js +2 -2
  49. package/dist/infra/repl/commands/pull-command.js +2 -2
  50. package/dist/infra/repl/commands/push-command.js +2 -2
  51. package/dist/infra/repl/commands/query-command.js +2 -2
  52. package/dist/infra/repl/commands/space/list-command.js +2 -2
  53. package/dist/infra/repl/commands/space/switch-command.js +2 -2
  54. package/dist/infra/repl/commands/status-command.js +2 -2
  55. package/dist/infra/repl/repl-startup.js +0 -2
  56. package/dist/infra/storage/file-token-store.d.ts +31 -0
  57. package/dist/infra/storage/file-token-store.js +98 -0
  58. package/dist/infra/storage/keychain-token-store.d.ts +4 -1
  59. package/dist/infra/storage/keychain-token-store.js +6 -4
  60. package/dist/infra/storage/token-store.d.ts +10 -0
  61. package/dist/infra/storage/token-store.js +14 -0
  62. package/dist/infra/usecase/curate-use-case.js +1 -1
  63. package/dist/infra/usecase/init-use-case.js +2 -4
  64. package/dist/infra/user/http-user-service.js +6 -11
  65. package/dist/resources/prompts/curate.yml +14 -5
  66. package/dist/resources/prompts/plan.yml +6 -0
  67. package/dist/tui/app.js +1 -1
  68. package/dist/tui/components/execution/log-item.js +2 -5
  69. package/dist/tui/components/header.d.ts +1 -1
  70. package/dist/tui/components/header.js +25 -4
  71. package/dist/tui/components/index.d.ts +5 -1
  72. package/dist/tui/components/index.js +3 -1
  73. package/dist/tui/components/init.d.ts +33 -0
  74. package/dist/tui/components/init.js +253 -0
  75. package/dist/tui/components/onboarding/index.d.ts +1 -0
  76. package/dist/tui/components/onboarding/index.js +1 -0
  77. package/dist/tui/components/onboarding/onboarding-flow.d.ts +2 -0
  78. package/dist/tui/components/onboarding/onboarding-flow.js +8 -229
  79. package/dist/tui/components/onboarding/onboarding-step.js +1 -1
  80. package/dist/tui/components/onboarding/welcome-box.d.ts +14 -0
  81. package/dist/tui/components/onboarding/welcome-box.js +23 -0
  82. package/dist/tui/components/status-badge.d.ts +22 -0
  83. package/dist/tui/components/status-badge.js +32 -0
  84. package/dist/tui/contexts/auth-context.js +2 -1
  85. package/dist/tui/contexts/index.d.ts +1 -0
  86. package/dist/tui/contexts/index.js +1 -0
  87. package/dist/tui/contexts/onboarding-context.d.ts +14 -0
  88. package/dist/tui/contexts/onboarding-context.js +17 -22
  89. package/dist/tui/contexts/status-context.d.ts +33 -0
  90. package/dist/tui/contexts/status-context.js +159 -0
  91. package/dist/tui/hooks/use-auth-polling.d.ts +4 -1
  92. package/dist/tui/hooks/use-auth-polling.js +21 -7
  93. package/dist/tui/hooks/use-tab-navigation.js +0 -2
  94. package/dist/tui/providers/app-providers.js +2 -2
  95. package/dist/tui/types/index.d.ts +2 -0
  96. package/dist/tui/types/index.js +2 -0
  97. package/dist/tui/types/status.d.ts +46 -0
  98. package/dist/tui/types/status.js +13 -0
  99. package/dist/tui/utils/index.d.ts +6 -0
  100. package/dist/tui/utils/index.js +6 -0
  101. package/dist/tui/utils/time.d.ts +10 -0
  102. package/dist/tui/utils/time.js +15 -0
  103. package/dist/tui/views/command-view.js +0 -2
  104. package/dist/tui/views/index.d.ts +1 -0
  105. package/dist/tui/views/index.js +1 -0
  106. package/dist/tui/views/init-view.d.ts +15 -0
  107. package/dist/tui/views/init-view.js +29 -0
  108. package/dist/tui/views/logs-view.js +22 -8
  109. package/dist/utils/environment-detector.d.ts +5 -0
  110. package/dist/utils/environment-detector.js +31 -0
  111. package/dist/utils/global-data-path.d.ts +11 -0
  112. package/dist/utils/global-data-path.js +32 -0
  113. package/oclif.manifest.json +1 -1
  114. package/package.json +1 -1
  115. package/dist/core/interfaces/cipher/i-agent-storage.d.ts +0 -152
  116. package/dist/core/interfaces/cipher/i-agent-storage.js +0 -1
  117. package/dist/infra/cipher/consumer/consumer-lock.d.ts +0 -20
  118. package/dist/infra/cipher/consumer/consumer-lock.js +0 -41
  119. package/dist/infra/cipher/consumer/consumer-service.d.ts +0 -99
  120. package/dist/infra/cipher/consumer/consumer-service.js +0 -166
  121. package/dist/infra/cipher/consumer/execution-consumer.d.ts +0 -126
  122. package/dist/infra/cipher/consumer/execution-consumer.js +0 -561
  123. package/dist/infra/cipher/consumer/index.d.ts +0 -33
  124. package/dist/infra/cipher/consumer/index.js +0 -34
  125. package/dist/infra/cipher/consumer/queue-polling-service.d.ts +0 -120
  126. package/dist/infra/cipher/consumer/queue-polling-service.js +0 -249
  127. package/dist/infra/cipher/storage/agent-storage.d.ts +0 -246
  128. package/dist/infra/cipher/storage/agent-storage.js +0 -956
@@ -1,33 +0,0 @@
1
- /**
2
- * Consumer Module - Public API for queue processing and UI monitoring
3
- *
4
- * Architecture (legacy):
5
- * - ConsumerService: Singleton background worker (start once in main)
6
- * - QueuePollingService: UI subscribes here for real-time updates
7
- * - Both communicate via AgentStorage (SQLite DB)
8
- *
9
- * Usage:
10
- * ```typescript
11
- * // Main process - start consumer singleton
12
- * import { getConsumerService } from 'byterover-cli/dist/infra/cipher/consumer'
13
- * const consumer = getConsumerService({ concurrency: 5 })
14
- * await consumer.start()
15
- *
16
- * // UI components - subscribe to polling service
17
- * import { getQueuePollingService } from 'byterover-cli/dist/infra/cipher/consumer'
18
- * const poller = getQueuePollingService({ pollInterval: 500 })
19
- * poller.on('snapshot', (snapshot) => renderUI(snapshot))
20
- * poller.on('execution:completed', (exec) => showNotification(exec))
21
- * await poller.start()
22
- *
23
- * // Cleanup
24
- * consumer.dispose()
25
- * poller.stop()
26
- * ```
27
- */
28
- export { isConsumerRunning, isConsumerRunningSync } from './consumer-lock.js';
29
- export { ConsumerService, disposeConsumerService, getConsumerService } from './consumer-service.js';
30
- export type { ConsumerServiceOptions } from './consumer-service.js';
31
- export { createExecutionConsumer, ExecutionConsumer, getConsumer, stopConsumer, tryStartConsumer, } from './execution-consumer.js';
32
- export { getQueuePollingService, QueuePollingService, stopQueuePollingService } from './queue-polling-service.js';
33
- export type { ExecutionWithToolCalls, QueueSnapshot, QueueStats } from './queue-polling-service.js';
@@ -1,34 +0,0 @@
1
- // TODO(v0.5.0): Remove this entire module. Replaced by CoreProcess + TaskProcessor + Transport events.
2
- /**
3
- * Consumer Module - Public API for queue processing and UI monitoring
4
- *
5
- * Architecture (legacy):
6
- * - ConsumerService: Singleton background worker (start once in main)
7
- * - QueuePollingService: UI subscribes here for real-time updates
8
- * - Both communicate via AgentStorage (SQLite DB)
9
- *
10
- * Usage:
11
- * ```typescript
12
- * // Main process - start consumer singleton
13
- * import { getConsumerService } from 'byterover-cli/dist/infra/cipher/consumer'
14
- * const consumer = getConsumerService({ concurrency: 5 })
15
- * await consumer.start()
16
- *
17
- * // UI components - subscribe to polling service
18
- * import { getQueuePollingService } from 'byterover-cli/dist/infra/cipher/consumer'
19
- * const poller = getQueuePollingService({ pollInterval: 500 })
20
- * poller.on('snapshot', (snapshot) => renderUI(snapshot))
21
- * poller.on('execution:completed', (exec) => showNotification(exec))
22
- * await poller.start()
23
- *
24
- * // Cleanup
25
- * consumer.dispose()
26
- * poller.stop()
27
- * ```
28
- */
29
- // ==================== LOW-LEVEL API (for advanced usage) ====================
30
- export { isConsumerRunning, isConsumerRunningSync } from './consumer-lock.js';
31
- // ==================== HIGH-LEVEL API (for UI/REPL) ====================
32
- export { ConsumerService, disposeConsumerService, getConsumerService } from './consumer-service.js';
33
- export { createExecutionConsumer, ExecutionConsumer, getConsumer, stopConsumer, tryStartConsumer, } from './execution-consumer.js';
34
- export { getQueuePollingService, QueuePollingService, stopQueuePollingService } from './queue-polling-service.js';
@@ -1,120 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- import type { Execution, ToolCall } from '../storage/agent-storage.js';
3
- export interface QueueStats {
4
- completed: number;
5
- failed: number;
6
- queued: number;
7
- running: number;
8
- total: number;
9
- }
10
- export interface ExecutionWithToolCalls {
11
- execution: Execution;
12
- toolCalls: ToolCall[];
13
- }
14
- export interface QueueSnapshot {
15
- /** All executions for the current session (with tool calls) - ordered by created_at ASC */
16
- sessionExecutions: ExecutionWithToolCalls[];
17
- stats: QueueStats;
18
- timestamp: number;
19
- }
20
- export type QueueEventType = 'error' | 'execution:completed' | 'execution:failed' | 'execution:started' | 'reconnected' | 'snapshot' | 'stats:updated' | 'stopped';
21
- export interface QueueEvents {
22
- error: (error: Error) => void;
23
- 'execution:completed': (execution: Execution) => void;
24
- 'execution:failed': (execution: Execution) => void;
25
- 'execution:started': (execution: Execution) => void;
26
- reconnected: () => void;
27
- snapshot: (snapshot: QueueSnapshot) => void;
28
- 'stats:updated': (stats: QueueStats) => void;
29
- stopped: () => void;
30
- }
31
- /**
32
- * QueuePollingService - Singleton service that polls agent.db and emits events
33
- *
34
- * Architecture:
35
- * - Polls database at configurable interval (default 500ms)
36
- * - Compares snapshots to detect changes
37
- * - Emits granular events for UI updates
38
- * - Singleton pattern prevents memory leaks from multiple instances
39
- *
40
- * Events:
41
- * - 'snapshot': Full queue snapshot (for initial render)
42
- * - 'stats:updated': Queue statistics changed
43
- * - 'execution:started': New execution started
44
- * - 'execution:completed': Execution completed successfully
45
- * - 'execution:failed': Execution failed
46
- * - 'error': Polling error occurred
47
- * - 'stopped': Service stopped
48
- */
49
- export declare class QueuePollingService extends EventEmitter {
50
- private consumerId?;
51
- private initialized;
52
- private lastSnapshot;
53
- private pollInterval;
54
- private pollTimer;
55
- private running;
56
- private seenExecutionIds;
57
- constructor(options?: {
58
- consumerId?: string;
59
- pollInterval?: number;
60
- });
61
- /**
62
- * Get current snapshot without polling
63
- */
64
- getCurrentSnapshot(): null | QueueSnapshot;
65
- /**
66
- * Check if service is running
67
- */
68
- isRunning(): boolean;
69
- /**
70
- * Set consumer ID for session-based execution history
71
- * Takes effect on next poll cycle
72
- */
73
- setConsumerId(consumerId: string | undefined): void;
74
- /**
75
- * Set poll interval (takes effect on next poll)
76
- */
77
- setPollInterval(ms: number): void;
78
- /**
79
- * Start polling
80
- */
81
- start(): Promise<void>;
82
- /**
83
- * Stop polling
84
- */
85
- stop(): void;
86
- /**
87
- * Build current snapshot from database
88
- */
89
- private buildSnapshot;
90
- /**
91
- * Detect changes and emit appropriate events
92
- */
93
- private detectChangesAndEmit;
94
- /**
95
- * Single poll iteration
96
- */
97
- private poll;
98
- /**
99
- * Schedule next poll
100
- */
101
- private schedulePoll;
102
- /**
103
- * Compare two stats objects for equality
104
- */
105
- private statsEqual;
106
- }
107
- /**
108
- * Get singleton QueuePollingService instance
109
- * @param options - Configuration options
110
- * @param options.consumerId - Optional consumer identifier
111
- * @param options.pollInterval - Optional poll interval in milliseconds
112
- */
113
- export declare function getQueuePollingService(options?: {
114
- consumerId?: string;
115
- pollInterval?: number;
116
- }): QueuePollingService;
117
- /**
118
- * Stop and clear singleton instance
119
- */
120
- export declare function stopQueuePollingService(): void;
@@ -1,249 +0,0 @@
1
- // TODO(v0.5.0): Remove this file. QueuePollingService is replaced by Transport events.
2
- import { EventEmitter } from 'node:events';
3
- import { closeAgentStorage, getAgentStorage, getAgentStorageSync } from '../storage/agent-storage.js';
4
- // ==================== SERVICE ====================
5
- /**
6
- * QueuePollingService - Singleton service that polls agent.db and emits events
7
- *
8
- * Architecture:
9
- * - Polls database at configurable interval (default 500ms)
10
- * - Compares snapshots to detect changes
11
- * - Emits granular events for UI updates
12
- * - Singleton pattern prevents memory leaks from multiple instances
13
- *
14
- * Events:
15
- * - 'snapshot': Full queue snapshot (for initial render)
16
- * - 'stats:updated': Queue statistics changed
17
- * - 'execution:started': New execution started
18
- * - 'execution:completed': Execution completed successfully
19
- * - 'execution:failed': Execution failed
20
- * - 'error': Polling error occurred
21
- * - 'stopped': Service stopped
22
- */
23
- // eslint-disable-next-line unicorn/prefer-event-target -- EventEmitter better for Node.js typed events
24
- export class QueuePollingService extends EventEmitter {
25
- consumerId;
26
- initialized = false;
27
- lastSnapshot = null;
28
- pollInterval;
29
- pollTimer = null;
30
- running = false;
31
- seenExecutionIds = new Set();
32
- constructor(options) {
33
- super();
34
- this.consumerId = options?.consumerId;
35
- this.pollInterval = options?.pollInterval ?? 500;
36
- }
37
- /**
38
- * Get current snapshot without polling
39
- */
40
- getCurrentSnapshot() {
41
- return this.lastSnapshot;
42
- }
43
- /**
44
- * Check if service is running
45
- */
46
- isRunning() {
47
- return this.running;
48
- }
49
- /**
50
- * Set consumer ID for session-based execution history
51
- * Takes effect on next poll cycle
52
- */
53
- setConsumerId(consumerId) {
54
- this.consumerId = consumerId;
55
- // Clear last snapshot to force fresh data with new consumer
56
- this.lastSnapshot = null;
57
- this.seenExecutionIds.clear();
58
- }
59
- /**
60
- * Set poll interval (takes effect on next poll)
61
- */
62
- setPollInterval(ms) {
63
- this.pollInterval = ms;
64
- }
65
- /**
66
- * Start polling
67
- */
68
- async start() {
69
- if (this.running)
70
- return;
71
- try {
72
- // Initialize storage (auto-detects .brv/blobs from cwd)
73
- await getAgentStorage();
74
- this.initialized = true;
75
- this.running = true;
76
- // Initial poll
77
- await this.poll();
78
- // Start poll loop
79
- this.schedulePoll();
80
- }
81
- catch (error) {
82
- this.emit('error', error instanceof Error ? error : new Error(String(error)));
83
- }
84
- }
85
- /**
86
- * Stop polling
87
- */
88
- stop() {
89
- this.running = false;
90
- if (this.pollTimer) {
91
- clearTimeout(this.pollTimer);
92
- this.pollTimer = null;
93
- }
94
- if (this.initialized) {
95
- closeAgentStorage();
96
- this.initialized = false;
97
- }
98
- this.emit('stopped');
99
- }
100
- // ==================== PRIVATE ====================
101
- /**
102
- * Build current snapshot from database
103
- */
104
- buildSnapshot() {
105
- const storage = getAgentStorageSync();
106
- // Get session executions with tool calls (if consumerId is set)
107
- let sessionExecutions = [];
108
- if (this.consumerId) {
109
- const sessionExecs = storage.getSessionExecutions(this.consumerId);
110
- sessionExecutions = sessionExecs.map((exec) => ({
111
- execution: exec,
112
- toolCalls: storage.getToolCalls(exec.id),
113
- }));
114
- }
115
- // Get stats directly from DB (accurate counts)
116
- const stats = storage.getStats();
117
- return {
118
- sessionExecutions,
119
- stats,
120
- timestamp: Date.now(),
121
- };
122
- }
123
- /**
124
- * Detect changes and emit appropriate events
125
- */
126
- detectChangesAndEmit(oldSnapshot, newSnapshot) {
127
- // Always emit snapshot for subscribers that want full state
128
- this.emit('snapshot', newSnapshot);
129
- // Detect stats changes
130
- if (!oldSnapshot || !this.statsEqual(oldSnapshot.stats, newSnapshot.stats)) {
131
- this.emit('stats:updated', newSnapshot.stats);
132
- }
133
- // Detect execution state changes
134
- const executions = newSnapshot.sessionExecutions.map((e) => e.execution);
135
- for (const exec of executions) {
136
- const wasSeenBefore = this.seenExecutionIds.has(exec.id);
137
- if (wasSeenBefore) {
138
- // Check if status changed
139
- const oldExecs = oldSnapshot?.sessionExecutions.map((e) => e.execution) ?? [];
140
- const oldExec = oldExecs.find((e) => e.id === exec.id);
141
- if (oldExec && oldExec.status !== exec.status) {
142
- if (exec.status === 'completed') {
143
- this.emit('execution:completed', exec);
144
- }
145
- else if (exec.status === 'failed') {
146
- this.emit('execution:failed', exec);
147
- }
148
- }
149
- }
150
- else {
151
- this.seenExecutionIds.add(exec.id);
152
- if (exec.status === 'running') {
153
- this.emit('execution:started', exec);
154
- }
155
- }
156
- }
157
- // Limit seen IDs to prevent memory growth
158
- if (this.seenExecutionIds.size > 1000) {
159
- const idsToKeep = new Set(executions.map((e) => e.id));
160
- this.seenExecutionIds = idsToKeep;
161
- }
162
- }
163
- /**
164
- * Single poll iteration
165
- */
166
- async poll() {
167
- if (!this.running || !this.initialized)
168
- return;
169
- try {
170
- // Check if DB file was replaced (e.g., by brv init in another terminal)
171
- const storage = getAgentStorageSync();
172
- if (storage.isDbFileChanged()) {
173
- // DB file was replaced - reconnect
174
- await storage.reconnect();
175
- // Clear seen IDs since DB was reset
176
- this.seenExecutionIds.clear();
177
- this.lastSnapshot = null;
178
- this.emit('reconnected');
179
- }
180
- const newSnapshot = this.buildSnapshot();
181
- this.detectChangesAndEmit(this.lastSnapshot, newSnapshot);
182
- this.lastSnapshot = newSnapshot;
183
- }
184
- catch (error) {
185
- // If stop() was called during poll, silently exit - this is expected during shutdown
186
- if (!this.running)
187
- return;
188
- // Try to recover from errors (connection lost, storage closed, etc.)
189
- try {
190
- // Use getAgentStorage() which auto-reinitializes if singleton was closed
191
- const storage = await getAgentStorage();
192
- await storage.reconnect();
193
- this.seenExecutionIds.clear();
194
- this.lastSnapshot = null;
195
- this.emit('reconnected');
196
- }
197
- catch {
198
- // Reconnect failed - only emit error if still running (not during intentional shutdown)
199
- if (this.running) {
200
- this.emit('error', error instanceof Error ? error : new Error(String(error)));
201
- }
202
- }
203
- }
204
- }
205
- /**
206
- * Schedule next poll
207
- */
208
- schedulePoll() {
209
- if (!this.running)
210
- return;
211
- this.pollTimer = setTimeout(async () => {
212
- await this.poll();
213
- this.schedulePoll();
214
- }, this.pollInterval);
215
- }
216
- /**
217
- * Compare two stats objects for equality
218
- */
219
- statsEqual(a, b) {
220
- return (a.queued === b.queued &&
221
- a.running === b.running &&
222
- a.completed === b.completed &&
223
- a.failed === b.failed &&
224
- a.total === b.total);
225
- }
226
- }
227
- // ==================== SINGLETON ====================
228
- let instance = null;
229
- /**
230
- * Get singleton QueuePollingService instance
231
- * @param options - Configuration options
232
- * @param options.consumerId - Optional consumer identifier
233
- * @param options.pollInterval - Optional poll interval in milliseconds
234
- */
235
- export function getQueuePollingService(options) {
236
- if (!instance) {
237
- instance = new QueuePollingService(options);
238
- }
239
- return instance;
240
- }
241
- /**
242
- * Stop and clear singleton instance
243
- */
244
- export function stopQueuePollingService() {
245
- if (instance) {
246
- instance.stop();
247
- instance = null;
248
- }
249
- }
@@ -1,246 +0,0 @@
1
- import type { Execution, ExecutionStatus, ExecutionType, ToolCall, ToolCallInfo, ToolCallStatus, ToolCallUpdateOptions } from '../../../core/domain/cipher/queue/types.js';
2
- import type { IAgentStorage } from '../../../core/interfaces/cipher/i-agent-storage.js';
3
- export type { ConsumerLock, Execution, ExecutionStatus, ExecutionType, ToolCall, ToolCallInfo, ToolCallStatus, ToolCallUpdateOptions, } from '../../../core/domain/cipher/queue/types.js';
4
- /**
5
- * AgentStorage - SQLite-based storage for execution queue and tool calls
6
- *
7
- * Features:
8
- * - Single database file at .brv/blobs/agent.db
9
- * - Job queue via executions.status = 'queued'
10
- * - Tool call tracking for UI polling
11
- * - Prepared statement caching (no memory leak)
12
- * - WAL mode for concurrent read/write
13
- * - Orphan cleanup on startup
14
- * - Old execution cleanup (max 100)
15
- */
16
- export declare class AgentStorage implements IAgentStorage {
17
- initialized: boolean;
18
- private db;
19
- private dbFileInode;
20
- private readonly dbPath;
21
- private readonly inMemory;
22
- private stmtAddToolCall;
23
- private stmtCleanupOrphans;
24
- private stmtCountCompletedFailed;
25
- private stmtCreateExecution;
26
- private stmtDeleteConsumerLock;
27
- private stmtDeleteOldExecutions;
28
- private stmtDequeueBatchSelect;
29
- private stmtDequeueSelect;
30
- private stmtFailQuery;
31
- private stmtGetExecution;
32
- private stmtGetExecutionsSince;
33
- private stmtGetQueuedExecutions;
34
- private stmtGetRecentExecutions;
35
- private stmtGetRunningExecutions;
36
- private stmtGetToolCalls;
37
- private stmtOrphanFromConsumer;
38
- private stmtOrphanMissingConsumer;
39
- private stmtOrphanNullConsumer;
40
- private stmtUpdateStatus;
41
- private stmtUpdateToolCall;
42
- private readonly storageDir;
43
- constructor(config?: {
44
- inMemory?: boolean;
45
- storageDir?: string;
46
- });
47
- /**
48
- * Acquire consumer lock (register this consumer)
49
- * Only ONE consumer can run at a time - checks for any active consumer first
50
- * @returns true if lock acquired, false if another consumer is already running
51
- */
52
- acquireConsumerLock(consumerId: string): boolean;
53
- /**
54
- * Add a tool call record
55
- * @returns tool call id
56
- */
57
- addToolCall(executionId: string, info: ToolCallInfo): string;
58
- /**
59
- * Cleanup old executions, keep only maxKeep most recent completed/failed
60
- */
61
- cleanupOldExecutions(maxKeep?: number): number;
62
- /**
63
- * Cleanup orphaned executions (status='running') from previous session crash
64
- * Should be called on startup
65
- */
66
- cleanupOrphanedExecutions(): number;
67
- /**
68
- * Cleanup stale consumers and orphan their executions
69
- * A consumer is stale if its heartbeat is older than timeoutMs
70
- * @param timeoutMs - heartbeat timeout (default 30 seconds)
71
- * @returns number of orphaned executions
72
- */
73
- cleanupStaleConsumers(timeoutMs?: number): number;
74
- /**
75
- * Close database connection
76
- */
77
- close(): void;
78
- /**
79
- * Create a new execution
80
- * @param type - 'curate' or 'query'
81
- * @param input - content (curate) or query string (query)
82
- * @returns execution id
83
- */
84
- createExecution(type: ExecutionType, input: string): string;
85
- /**
86
- * Dequeue multiple executions at once (atomic batch SELECT + UPDATE)
87
- * This is more efficient than calling dequeueExecution() multiple times
88
- * and ensures all queued items are seen in a single transaction snapshot
89
- * @param limit - max number of executions to dequeue
90
- * @param consumerId - ID of the consumer claiming these executions
91
- * @returns array of executions (may be empty if queue is empty)
92
- */
93
- dequeueBatch(limit: number, consumerId?: string): Execution[];
94
- /**
95
- * Dequeue next queued execution (atomic SELECT + UPDATE)
96
- * @param consumerId - ID of the consumer claiming this execution
97
- * @returns execution or null if queue is empty
98
- */
99
- dequeueExecution(consumerId?: string): Execution | null;
100
- /**
101
- * Get execution by id
102
- */
103
- getExecution(id: string): Execution | null;
104
- /**
105
- * Get executions updated since timestamp (for incremental polling)
106
- */
107
- getExecutionsSince(timestamp: number): Execution[];
108
- /**
109
- * Get execution with all its tool calls (for UI display)
110
- */
111
- getExecutionWithToolCalls(id: string): null | {
112
- execution: Execution;
113
- toolCalls: ToolCall[];
114
- };
115
- /**
116
- * Get all queued executions
117
- */
118
- getQueuedExecutions(): Execution[];
119
- /**
120
- * Get recent executions (for UI display)
121
- */
122
- getRecentExecutions(limit?: number): Execution[];
123
- /**
124
- * Get all running executions
125
- */
126
- getRunningExecutions(): Execution[];
127
- /**
128
- * Get all executions belonging to a specific consumer session.
129
- * Returns executions ordered by created_at ASC (oldest first, newest last).
130
- * Includes:
131
- * - Curate executions with matching consumer_id
132
- * - Query executions created after consumer started (no consumer_id)
133
- */
134
- getSessionExecutions(consumerId: string): Execution[];
135
- /**
136
- * Get queue statistics (queries DB directly for accurate counts)
137
- */
138
- getStats(): {
139
- completed: number;
140
- failed: number;
141
- queued: number;
142
- running: number;
143
- total: number;
144
- };
145
- /**
146
- * Get all tool calls for an execution
147
- */
148
- getToolCalls(executionId: string): ToolCall[];
149
- /**
150
- * Check if any consumer is currently active (has recent heartbeat)
151
- * @param timeoutMs - heartbeat timeout (default 30 seconds)
152
- */
153
- hasActiveConsumer(timeoutMs?: number): boolean;
154
- /**
155
- * Check if a specific consumer lock exists in the database
156
- * Used by Consumer to verify its lock is still valid after DB reconnection
157
- */
158
- hasConsumerLock(consumerId: string): boolean;
159
- /**
160
- * Initialize storage - create tables, enable WAL
161
- * @param options - Initialization options
162
- * @param options.cleanupOrphans - If true, cleanup orphaned executions (only Consumer should set this)
163
- */
164
- initialize(options?: {
165
- cleanupOrphans?: boolean;
166
- }): Promise<void>;
167
- /**
168
- * Check if the DB file has been replaced (different inode)
169
- * Returns true if DB needs reconnection
170
- */
171
- isDbFileChanged(): boolean;
172
- /**
173
- * Reconnect to the database (close and reinitialize)
174
- * Use when DB file has been replaced by another process (e.g., brv init)
175
- */
176
- reconnect(): Promise<void>;
177
- /**
178
- * Release consumer lock (unregister this consumer)
179
- */
180
- releaseConsumerLock(consumerId: string): void;
181
- /**
182
- * Update consumer heartbeat
183
- */
184
- updateConsumerHeartbeat(consumerId: string): void;
185
- /**
186
- * Update execution status
187
- */
188
- updateExecutionStatus(id: string, status: ExecutionStatus, result?: string, error?: string): void;
189
- /**
190
- * Update tool call status and result
191
- */
192
- updateToolCall(id: string, status: ToolCallStatus, options?: ToolCallUpdateOptions): void;
193
- /**
194
- * Ensure storage has been initialized
195
- */
196
- private ensureInitialized;
197
- /**
198
- * Get database instance with type safety (throws if not initialized)
199
- * Use this instead of this.getDb() for proper type narrowing
200
- */
201
- private getDb;
202
- /**
203
- * Convert database row to Execution object
204
- */
205
- private rowToExecution;
206
- /**
207
- * Convert database row to ToolCall object
208
- */
209
- private rowToToolCall;
210
- }
211
- /**
212
- * Get the singleton AgentStorage instance (auto-initializes if needed)
213
- *
214
- * This is the PRIMARY API - just call this and it handles everything.
215
- * First call will initialize with provided config, subsequent calls return cached instance.
216
- *
217
- * @param config - Configuration options
218
- * @param config.cleanupOrphans - Cleanup orphaned executions (only Consumer should set this)
219
- * @param config.inMemory - Use in-memory database (for testing)
220
- * @param config.storageDir - Directory for agent.db (default: .brv/blobs)
221
- */
222
- export declare function getAgentStorage(config?: {
223
- cleanupOrphans?: boolean;
224
- inMemory?: boolean;
225
- storageDir?: string;
226
- }): Promise<AgentStorage>;
227
- /**
228
- * Get the singleton AgentStorage instance (sync version)
229
- * THROWS if not initialized - use getAgentStorage() instead for auto-init
230
- *
231
- * Use this only when you KNOW storage is already initialized (e.g., in Consumer after start)
232
- */
233
- export declare function getAgentStorageSync(): AgentStorage;
234
- /**
235
- * Initialize the singleton AgentStorage instance
236
- * @deprecated Use getAgentStorage() directly - it auto-initializes
237
- */
238
- export declare function initializeAgentStorage(config?: {
239
- cleanupOrphans?: boolean;
240
- inMemory?: boolean;
241
- storageDir?: string;
242
- }): Promise<AgentStorage>;
243
- /**
244
- * Close and clear the singleton AgentStorage instance
245
- */
246
- export declare function closeAgentStorage(): void;