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.
- package/README.md +6 -81
- package/dist/agent/core/domain/llm/index.d.ts +1 -1
- package/dist/agent/core/domain/llm/index.js +1 -1
- package/dist/agent/core/domain/llm/registry.d.ts +8 -0
- package/dist/agent/core/domain/llm/registry.js +34 -0
- package/dist/agent/core/domain/sandbox/types.d.ts +2 -0
- package/dist/agent/core/domain/tools/constants.d.ts +3 -0
- package/dist/agent/core/domain/tools/constants.js +3 -0
- package/dist/agent/core/interfaces/cipher-services.d.ts +2 -4
- package/dist/agent/core/interfaces/i-cipher-agent.d.ts +9 -1
- package/dist/agent/core/interfaces/i-sandbox-service.d.ts +8 -0
- package/dist/agent/core/interfaces/i-tool-provider.d.ts +10 -0
- package/dist/agent/core/interfaces/i-tool-scheduler.d.ts +9 -0
- package/dist/agent/infra/agent/agent-schemas.d.ts +0 -9
- package/dist/agent/infra/agent/agent-schemas.js +0 -3
- package/dist/agent/infra/agent/cipher-agent.d.ts +25 -1
- package/dist/agent/infra/agent/cipher-agent.js +138 -11
- package/dist/agent/infra/agent/provider-update-config.d.ts +0 -2
- package/dist/agent/infra/agent/service-initializer.d.ts +2 -6
- package/dist/agent/infra/agent/service-initializer.js +45 -38
- package/dist/agent/infra/blob/blob-storage-factory.d.ts +2 -2
- package/dist/agent/infra/blob/blob-storage-factory.js +4 -4
- package/dist/agent/infra/blob/file-blob-storage.d.ts +96 -0
- package/dist/agent/infra/blob/file-blob-storage.js +454 -0
- package/dist/agent/infra/blob/index.d.ts +2 -3
- package/dist/agent/infra/blob/index.js +4 -6
- package/dist/agent/infra/llm/agent-llm-service.d.ts +3 -0
- package/dist/agent/infra/llm/agent-llm-service.js +34 -52
- package/dist/agent/infra/llm/context/compression/compression-helpers.d.ts +35 -0
- package/dist/agent/infra/llm/context/compression/compression-helpers.js +124 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.d.ts +62 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.js +144 -0
- package/dist/agent/infra/llm/context/compression/index.d.ts +3 -0
- package/dist/agent/infra/llm/context/compression/index.js +3 -0
- package/dist/agent/infra/llm/context/compression/reactive-overflow.d.ts +0 -27
- package/dist/agent/infra/llm/context/compression/reactive-overflow.js +5 -122
- package/dist/agent/infra/llm/context/context-manager.d.ts +20 -1
- package/dist/agent/infra/llm/context/context-manager.js +37 -7
- package/dist/agent/infra/llm/providers/index.js +0 -2
- package/dist/agent/infra/llm/providers/types.d.ts +1 -5
- package/dist/agent/infra/map/agentic-map-service.d.ts +97 -0
- package/dist/agent/infra/map/agentic-map-service.js +309 -0
- package/dist/agent/infra/map/context-tree-store.d.ts +94 -0
- package/dist/agent/infra/map/context-tree-store.js +278 -0
- package/dist/agent/infra/map/index.d.ts +4 -0
- package/dist/agent/infra/map/index.js +4 -0
- package/dist/agent/infra/map/llm-map-memory.d.ts +59 -0
- package/dist/agent/infra/map/llm-map-memory.js +187 -0
- package/dist/agent/infra/map/llm-map-service.d.ts +36 -0
- package/dist/agent/infra/map/llm-map-service.js +118 -0
- package/dist/agent/infra/map/map-shared.d.ts +140 -0
- package/dist/agent/infra/map/map-shared.js +325 -0
- package/dist/agent/infra/map/worker-pool.d.ts +45 -0
- package/dist/agent/infra/map/worker-pool.js +73 -0
- package/dist/agent/infra/sandbox/curation-helpers.d.ts +62 -0
- package/dist/agent/infra/sandbox/curation-helpers.js +219 -0
- package/dist/agent/infra/sandbox/sandbox-service.d.ts +12 -0
- package/dist/agent/infra/sandbox/sandbox-service.js +39 -7
- package/dist/agent/infra/sandbox/tools-sdk.d.ts +48 -1
- package/dist/agent/infra/sandbox/tools-sdk.js +52 -1
- package/dist/agent/infra/session/session-manager.d.ts +8 -1
- package/dist/agent/infra/session/session-manager.js +24 -4
- package/dist/agent/infra/storage/file-key-storage.d.ts +142 -0
- package/dist/agent/infra/storage/file-key-storage.js +572 -0
- package/dist/agent/infra/storage/granular-history-storage.d.ts +1 -1
- package/dist/agent/infra/storage/granular-history-storage.js +1 -1
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.d.ts +4 -0
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.js +42 -14
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.d.ts +16 -0
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.js +47 -0
- package/dist/agent/infra/tools/core-tool-scheduler.js +3 -1
- package/dist/agent/infra/tools/implementations/agentic-map-tool.d.ts +35 -0
- package/dist/agent/infra/tools/implementations/agentic-map-tool.js +156 -0
- package/dist/agent/infra/tools/implementations/code-exec-tool.js +1 -0
- package/dist/agent/infra/tools/implementations/curate-tool.d.ts +9 -9
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +18 -0
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +43 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.d.ts +24 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.js +87 -0
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +28 -1
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.js +27 -3
- package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -0
- package/dist/agent/infra/tools/implementations/search-knowledge-service.js +83 -12
- package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
- package/dist/agent/infra/tools/tool-manager.js +6 -0
- package/dist/agent/infra/tools/tool-provider.d.ts +12 -0
- package/dist/agent/infra/tools/tool-provider.js +78 -0
- package/dist/agent/infra/tools/tool-registry.d.ts +14 -0
- package/dist/agent/infra/tools/tool-registry.js +32 -0
- package/dist/agent/resources/prompts/system-prompt.yml +48 -74
- package/dist/agent/resources/tools/expand_knowledge.txt +20 -0
- package/dist/oclif/commands/curate/index.js +1 -2
- package/dist/oclif/commands/main.js +1 -0
- package/dist/oclif/commands/providers/connect.d.ts +1 -3
- package/dist/oclif/commands/providers/connect.js +7 -29
- package/dist/oclif/commands/query.js +1 -2
- package/dist/server/constants.d.ts +7 -0
- package/dist/server/constants.js +8 -0
- package/dist/server/core/domain/entities/provider-registry.js +1 -15
- package/dist/server/core/domain/knowledge/memory-scoring.js +1 -1
- package/dist/server/core/domain/knowledge/summary-types.d.ts +126 -0
- package/dist/server/core/domain/knowledge/summary-types.js +7 -0
- package/dist/server/core/domain/transport/schemas.d.ts +0 -4
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.d.ts +29 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.js +1 -0
- package/dist/server/infra/cogit/context-tree-to-push-context-mapper.js +10 -3
- package/dist/server/infra/connectors/skill/skill-connector.d.ts +4 -0
- package/dist/server/infra/connectors/skill/skill-connector.js +4 -0
- package/dist/server/infra/context-tree/children-hash.d.ts +20 -0
- package/dist/server/infra/context-tree/children-hash.js +22 -0
- package/dist/server/infra/context-tree/derived-artifact.d.ts +28 -0
- package/dist/server/infra/context-tree/derived-artifact.js +48 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.d.ts +37 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.js +219 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +50 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +278 -0
- package/dist/server/infra/context-tree/file-context-tree-merger.js +4 -0
- package/dist/server/infra/context-tree/file-context-tree-snapshot-service.js +12 -4
- package/dist/server/infra/context-tree/file-context-tree-summary-service.d.ts +44 -0
- package/dist/server/infra/context-tree/file-context-tree-summary-service.js +313 -0
- package/dist/server/infra/context-tree/file-context-tree-writer-service.js +5 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.d.ts +22 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.js +45 -0
- package/dist/server/infra/context-tree/snapshot-diff.d.ts +19 -0
- package/dist/server/infra/context-tree/snapshot-diff.js +39 -0
- package/dist/server/infra/context-tree/summary-frontmatter.d.ts +24 -0
- package/dist/server/infra/context-tree/summary-frontmatter.js +111 -0
- package/dist/server/infra/daemon/agent-process.js +2 -14
- package/dist/server/infra/executor/curate-executor.d.ts +1 -0
- package/dist/server/infra/executor/curate-executor.js +82 -34
- package/dist/server/infra/executor/folder-pack-executor.js +1 -1
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.d.ts +6 -0
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.js +6 -0
- package/dist/server/infra/executor/pre-compaction/index.d.ts +3 -0
- package/dist/server/infra/executor/pre-compaction/index.js +1 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.d.ts +59 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.js +124 -0
- package/dist/server/infra/executor/pre-compaction/prompts.d.ts +24 -0
- package/dist/server/infra/executor/pre-compaction/prompts.js +47 -0
- package/dist/server/infra/executor/query-executor.d.ts +3 -0
- package/dist/server/infra/executor/query-executor.js +39 -4
- package/dist/server/infra/http/authenticated-http-client.js +4 -0
- package/dist/server/infra/http/provider-model-fetcher-registry.js +1 -5
- package/dist/server/infra/http/provider-model-fetchers.d.ts +0 -14
- package/dist/server/infra/http/provider-model-fetchers.js +0 -132
- package/dist/server/infra/provider/provider-config-resolver.js +0 -55
- package/dist/server/utils/curate-result-parser.d.ts +4 -4
- package/dist/shared/constants/curation.d.ts +6 -0
- package/dist/shared/constants/curation.js +6 -0
- package/dist/shared/utils/escalation-utils.d.ts +59 -0
- package/dist/shared/utils/escalation-utils.js +141 -0
- package/dist/tui/components/command-input.js +1 -1
- package/dist/tui/components/inline-prompts/inline-confirm.js +6 -1
- package/dist/tui/features/commands/definitions/exit.d.ts +2 -0
- package/dist/tui/features/commands/definitions/exit.js +9 -0
- package/dist/tui/features/commands/definitions/index.js +3 -0
- package/dist/tui/features/exit/components/exit-flow.d.ts +10 -0
- package/dist/tui/features/exit/components/exit-flow.js +19 -0
- package/dist/tui/features/provider/components/provider-flow.js +1 -21
- package/oclif.manifest.json +100 -109
- package/package.json +11 -4
- package/dist/agent/infra/blob/migrations.d.ts +0 -63
- package/dist/agent/infra/blob/migrations.js +0 -148
- package/dist/agent/infra/blob/sqlite-blob-storage.d.ts +0 -82
- package/dist/agent/infra/blob/sqlite-blob-storage.js +0 -307
- package/dist/agent/infra/llm/providers/google-vertex.d.ts +0 -15
- package/dist/agent/infra/llm/providers/google-vertex.js +0 -36
- package/dist/agent/infra/storage/blob-history-storage.d.ts +0 -81
- package/dist/agent/infra/storage/blob-history-storage.js +0 -193
- package/dist/agent/infra/storage/dual-format-history-storage.d.ts +0 -83
- package/dist/agent/infra/storage/dual-format-history-storage.js +0 -165
- package/dist/agent/infra/storage/sqlite-key-storage.d.ts +0 -113
- package/dist/agent/infra/storage/sqlite-key-storage.js +0 -438
- package/dist/server/infra/provider/vertex-ai-utils.d.ts +0 -10
- package/dist/server/infra/provider/vertex-ai-utils.js +0 -28
- package/dist/tui/features/provider/components/credential-path-dialog.d.ts +0 -30
- package/dist/tui/features/provider/components/credential-path-dialog.js +0 -85
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { ContextTreeStore } from '../map/context-tree-store.js';
|
|
2
|
+
import { executeLlmMapMemory } from '../map/llm-map-memory.js';
|
|
3
|
+
import { chunk, dedup, detectMessageBoundaries, groupBySubject, recon, recordProgress, } from './curation-helpers.js';
|
|
1
4
|
/**
|
|
2
5
|
* Creates a Tools SDK instance for sandbox code execution.
|
|
3
6
|
*
|
|
@@ -8,7 +11,8 @@
|
|
|
8
11
|
* @returns ToolsSDK instance ready to be injected into sandbox context
|
|
9
12
|
*/
|
|
10
13
|
export function createToolsSDK(options) {
|
|
11
|
-
const { curateService, fileSystem, parentSessionId, sandboxService, searchKnowledgeService, sessionManager } = options;
|
|
14
|
+
const { commandType, contentGenerator, curateService, fileSystem, parentSessionId, sandboxService, searchKnowledgeService, sessionManager } = options;
|
|
15
|
+
const isReadOnly = commandType === 'query';
|
|
12
16
|
return {
|
|
13
17
|
async agentQuery(prompt, options) {
|
|
14
18
|
if (!sessionManager || !parentSessionId) {
|
|
@@ -37,6 +41,9 @@ export function createToolsSDK(options) {
|
|
|
37
41
|
}
|
|
38
42
|
},
|
|
39
43
|
async curate(operations, options) {
|
|
44
|
+
if (isReadOnly) {
|
|
45
|
+
throw new Error('curate() is disabled in read-only (query) mode');
|
|
46
|
+
}
|
|
40
47
|
if (!curateService) {
|
|
41
48
|
return {
|
|
42
49
|
applied: [{
|
|
@@ -56,6 +63,47 @@ export function createToolsSDK(options) {
|
|
|
56
63
|
}
|
|
57
64
|
return curateService.curate(operations, options);
|
|
58
65
|
},
|
|
66
|
+
curation: {
|
|
67
|
+
chunk,
|
|
68
|
+
dedup,
|
|
69
|
+
detectMessageBoundaries,
|
|
70
|
+
groupBySubject,
|
|
71
|
+
async mapExtract(context, options) {
|
|
72
|
+
if (commandType !== 'curate') {
|
|
73
|
+
throw new Error('mapExtract only available in curate mode');
|
|
74
|
+
}
|
|
75
|
+
if (!contentGenerator) {
|
|
76
|
+
throw new Error('mapExtract not available — no content generator configured');
|
|
77
|
+
}
|
|
78
|
+
const chunks = chunk(context, { size: options.chunkSize ?? 8000 });
|
|
79
|
+
const items = chunks.chunks.map((c, i) => ({ chunk: c, index: i, totalChunks: chunks.totalChunks }));
|
|
80
|
+
// Construct ContextTreeStore with adapter tokenizer (zero-divergence)
|
|
81
|
+
const tauHard = Math.floor((options.maxContextTokens ?? 100_000) * 0.5);
|
|
82
|
+
const contextTreeStore = new ContextTreeStore({
|
|
83
|
+
generator: contentGenerator,
|
|
84
|
+
tauHard,
|
|
85
|
+
tokenizer: { countTokens: (text) => contentGenerator.estimateTokensSync(text) },
|
|
86
|
+
});
|
|
87
|
+
const result = await executeLlmMapMemory({
|
|
88
|
+
concurrency: options.concurrency ?? 8,
|
|
89
|
+
contextTreeStore,
|
|
90
|
+
generator: contentGenerator,
|
|
91
|
+
items,
|
|
92
|
+
prompt: options.prompt,
|
|
93
|
+
taskId: options.taskId,
|
|
94
|
+
});
|
|
95
|
+
// Throw when all chunks fail — no facts to work with
|
|
96
|
+
if (result.succeeded === 0 && result.total > 0) {
|
|
97
|
+
throw new Error(`mapExtract failed: all ${result.total} chunks failed extraction`);
|
|
98
|
+
}
|
|
99
|
+
const facts = result.results
|
|
100
|
+
.filter((r) => r !== null)
|
|
101
|
+
.flat();
|
|
102
|
+
return { facts, failed: result.failed, succeeded: result.succeeded, total: result.total };
|
|
103
|
+
},
|
|
104
|
+
recon,
|
|
105
|
+
recordProgress,
|
|
106
|
+
},
|
|
59
107
|
async detectDomains(domains) {
|
|
60
108
|
if (!curateService) {
|
|
61
109
|
return {
|
|
@@ -105,6 +153,9 @@ export function createToolsSDK(options) {
|
|
|
105
153
|
return searchKnowledgeService.search(query, options);
|
|
106
154
|
},
|
|
107
155
|
async writeFile(filePath, content, options) {
|
|
156
|
+
if (isReadOnly) {
|
|
157
|
+
throw new Error('writeFile() is disabled in read-only (query) mode');
|
|
158
|
+
}
|
|
108
159
|
return fileSystem.writeFile(filePath, content, {
|
|
109
160
|
createDirs: options?.createDirs ?? false,
|
|
110
161
|
});
|
|
@@ -31,8 +31,14 @@ export interface SessionMetadata {
|
|
|
31
31
|
/**
|
|
32
32
|
* Options for SessionManager constructor
|
|
33
33
|
*/
|
|
34
|
+
export type SessionRemovalReason = 'deleted' | 'ended' | 'ttl_expired';
|
|
34
35
|
export interface SessionManagerOptions {
|
|
35
36
|
config?: SessionManagerConfig;
|
|
37
|
+
/**
|
|
38
|
+
* Optional lifecycle callback fired after a session is removed from memory maps.
|
|
39
|
+
* Used by CipherAgent to synchronize external registries (e.g., nesting registry).
|
|
40
|
+
*/
|
|
41
|
+
onSessionRemoved?: (sessionId: string, reason: SessionRemovalReason) => void;
|
|
36
42
|
}
|
|
37
43
|
/**
|
|
38
44
|
* Session manager.
|
|
@@ -46,6 +52,7 @@ export declare class SessionManager {
|
|
|
46
52
|
private readonly config;
|
|
47
53
|
private readonly httpConfig;
|
|
48
54
|
private readonly llmConfig;
|
|
55
|
+
private readonly onSessionRemoved?;
|
|
49
56
|
private pendingCreations;
|
|
50
57
|
/** Agent name for each session (e.g., 'plan', 'query', 'curate') */
|
|
51
58
|
private readonly sessionAgentNames;
|
|
@@ -145,7 +152,7 @@ export declare class SessionManager {
|
|
|
145
152
|
* @param id - Session ID to end
|
|
146
153
|
* @returns True if session existed and was ended
|
|
147
154
|
*/
|
|
148
|
-
endSession(id: string): Promise<boolean>;
|
|
155
|
+
endSession(id: string, reason?: SessionRemovalReason): Promise<boolean>;
|
|
149
156
|
/**
|
|
150
157
|
* Get a session by ID.
|
|
151
158
|
*
|
|
@@ -19,6 +19,7 @@ export class SessionManager {
|
|
|
19
19
|
config;
|
|
20
20
|
httpConfig;
|
|
21
21
|
llmConfig;
|
|
22
|
+
onSessionRemoved;
|
|
22
23
|
pendingCreations = new Map();
|
|
23
24
|
/** Agent name for each session (e.g., 'plan', 'query', 'curate') */
|
|
24
25
|
sessionAgentNames = new Map();
|
|
@@ -54,6 +55,7 @@ export class SessionManager {
|
|
|
54
55
|
this.sharedServices = sharedServices;
|
|
55
56
|
this.httpConfig = httpConfig;
|
|
56
57
|
this.llmConfig = llmConfig;
|
|
58
|
+
this.onSessionRemoved = options?.onSessionRemoved;
|
|
57
59
|
this.config = {
|
|
58
60
|
maxSessions: options?.config?.maxSessions ?? 100,
|
|
59
61
|
sessionTTL: options?.config?.sessionTTL ?? 3_600_000, // 1 hour
|
|
@@ -199,7 +201,16 @@ export class SessionManager {
|
|
|
199
201
|
this.sessionAgentNames.delete(id);
|
|
200
202
|
this.sessionParentIds.delete(id);
|
|
201
203
|
// Remove from memory
|
|
202
|
-
|
|
204
|
+
const deleted = this.sessions.delete(id);
|
|
205
|
+
if (deleted) {
|
|
206
|
+
try {
|
|
207
|
+
this.onSessionRemoved?.(id, 'deleted');
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Fail-open: session deletion must not fail due to callback errors
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return deleted;
|
|
203
214
|
}
|
|
204
215
|
/**
|
|
205
216
|
* Stop cleanup timer and dispose of all resources.
|
|
@@ -235,7 +246,7 @@ export class SessionManager {
|
|
|
235
246
|
* @param id - Session ID to end
|
|
236
247
|
* @returns True if session existed and was ended
|
|
237
248
|
*/
|
|
238
|
-
async endSession(id) {
|
|
249
|
+
async endSession(id, reason = 'ended') {
|
|
239
250
|
const session = this.sessions.get(id);
|
|
240
251
|
if (!session) {
|
|
241
252
|
return false;
|
|
@@ -252,7 +263,16 @@ export class SessionManager {
|
|
|
252
263
|
this.sessionAgentNames.delete(id);
|
|
253
264
|
this.sessionParentIds.delete(id);
|
|
254
265
|
// Remove from memory only - history remains in storage
|
|
255
|
-
|
|
266
|
+
const ended = this.sessions.delete(id);
|
|
267
|
+
if (ended) {
|
|
268
|
+
try {
|
|
269
|
+
this.onSessionRemoved?.(id, reason);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// Fail-open: session ending must not fail due to callback errors
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return ended;
|
|
256
276
|
}
|
|
257
277
|
/**
|
|
258
278
|
* Get a session by ID.
|
|
@@ -349,7 +369,7 @@ export class SessionManager {
|
|
|
349
369
|
const lastActivity = this.sessionLastActivity.get(id) ?? 0;
|
|
350
370
|
if (now - lastActivity > this.config.sessionTTL) {
|
|
351
371
|
// eslint-disable-next-line no-await-in-loop
|
|
352
|
-
await this.endSession(id); // Preserve history
|
|
372
|
+
await this.endSession(id, 'ttl_expired'); // Preserve history
|
|
353
373
|
cleaned++;
|
|
354
374
|
}
|
|
355
375
|
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { BatchOperation, IKeyStorage, StorageKey } from '../../core/interfaces/i-key-storage.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for file-based key storage.
|
|
4
|
+
*/
|
|
5
|
+
export interface FileKeyStorageConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Enable in-memory mode for testing.
|
|
8
|
+
* Uses a Map instead of the filesystem — no I/O, fast unit tests.
|
|
9
|
+
* Defaults to false.
|
|
10
|
+
*/
|
|
11
|
+
inMemory?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Storage directory for the keystore.
|
|
14
|
+
* Required when inMemory is false.
|
|
15
|
+
*/
|
|
16
|
+
storageDir?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* File-based key storage implementation.
|
|
20
|
+
*
|
|
21
|
+
* Stores key-value pairs as individual JSON files on the filesystem.
|
|
22
|
+
* Composite keys map to directory paths:
|
|
23
|
+
* ["message", sessionId, msgId] → {storageDir}/keystore/message/{sessionId}/{msgId}.json
|
|
24
|
+
*
|
|
25
|
+
* Features:
|
|
26
|
+
* - One file per entity (O(1) read/write/delete)
|
|
27
|
+
* - Atomic writes via write-to-temp + rename
|
|
28
|
+
* - Reader-writer locks for concurrent access (reuses global RWLock)
|
|
29
|
+
* - In-memory mode for fast unit tests
|
|
30
|
+
* - Hierarchical prefix listing via readdir
|
|
31
|
+
*/
|
|
32
|
+
export declare class FileKeyStorage implements IKeyStorage {
|
|
33
|
+
private readonly baseDir;
|
|
34
|
+
private initialized;
|
|
35
|
+
private readonly inMemory;
|
|
36
|
+
private memoryStore;
|
|
37
|
+
private readonly storageDir;
|
|
38
|
+
constructor(config?: FileKeyStorageConfig);
|
|
39
|
+
/**
|
|
40
|
+
* Execute batch operations.
|
|
41
|
+
* Operations are executed sequentially with write-temp-rename per operation.
|
|
42
|
+
* Best-effort: not ACID across multiple files, but each individual
|
|
43
|
+
* file write is atomic via rename.
|
|
44
|
+
*/
|
|
45
|
+
batch(operations: BatchOperation[]): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Close the storage. No-op for file-based storage.
|
|
48
|
+
*/
|
|
49
|
+
close(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Delete a value by its composite key.
|
|
52
|
+
*/
|
|
53
|
+
delete(key: StorageKey): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a key exists.
|
|
56
|
+
*/
|
|
57
|
+
exists(key: StorageKey): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Get a value by its composite key.
|
|
60
|
+
*/
|
|
61
|
+
get<T>(key: StorageKey): Promise<T | undefined>;
|
|
62
|
+
/**
|
|
63
|
+
* Initialize the storage backend.
|
|
64
|
+
* Creates the base keystore directory.
|
|
65
|
+
*/
|
|
66
|
+
initialize(): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* List all keys matching a prefix.
|
|
69
|
+
*/
|
|
70
|
+
list(prefix: StorageKey): Promise<StorageKey[]>;
|
|
71
|
+
/**
|
|
72
|
+
* List all key-value pairs matching a prefix.
|
|
73
|
+
* More efficient than list() followed by individual get() calls.
|
|
74
|
+
*/
|
|
75
|
+
listWithValues<T>(prefix: StorageKey): Promise<Array<{
|
|
76
|
+
key: StorageKey;
|
|
77
|
+
value: T;
|
|
78
|
+
}>>;
|
|
79
|
+
/**
|
|
80
|
+
* Set a value at a composite key.
|
|
81
|
+
*/
|
|
82
|
+
set<T>(key: StorageKey, value: T): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Atomic update with optimistic locking.
|
|
85
|
+
*/
|
|
86
|
+
update<T>(key: StorageKey, updater: (current: T | undefined) => T): Promise<T>;
|
|
87
|
+
/**
|
|
88
|
+
* Deserialize a colon-separated string back to a StorageKey.
|
|
89
|
+
*/
|
|
90
|
+
private deserializeKey;
|
|
91
|
+
private ensureInitialized;
|
|
92
|
+
/**
|
|
93
|
+
* Convert a StorageKey to a filesystem path.
|
|
94
|
+
* ["message", "abc", "msg1"] → {baseDir}/message/abc/msg1.json
|
|
95
|
+
*/
|
|
96
|
+
private keyToPath;
|
|
97
|
+
/**
|
|
98
|
+
* List keys from disk by scanning the prefix directory.
|
|
99
|
+
*/
|
|
100
|
+
private listFromDisk;
|
|
101
|
+
/**
|
|
102
|
+
* List keys from in-memory store matching a prefix.
|
|
103
|
+
*/
|
|
104
|
+
private listInMemory;
|
|
105
|
+
/**
|
|
106
|
+
* List keys with values from disk.
|
|
107
|
+
*/
|
|
108
|
+
private listWithValuesFromDisk;
|
|
109
|
+
/**
|
|
110
|
+
* List keys with values from in-memory store.
|
|
111
|
+
*/
|
|
112
|
+
private listWithValuesInMemory;
|
|
113
|
+
/**
|
|
114
|
+
* Read the stored envelope for a key. Returns undefined if not found.
|
|
115
|
+
*/
|
|
116
|
+
private readEnvelope;
|
|
117
|
+
/**
|
|
118
|
+
* Remove a file for the given key. Returns true if it existed.
|
|
119
|
+
*/
|
|
120
|
+
private removeFile;
|
|
121
|
+
/**
|
|
122
|
+
* Recursively scan a directory to collect all storage keys.
|
|
123
|
+
*/
|
|
124
|
+
private scanDirectory;
|
|
125
|
+
/**
|
|
126
|
+
* Serialize a StorageKey to a string for in-memory store lookups.
|
|
127
|
+
* Uses ':' separator (same as lockKeyFromStorageKey).
|
|
128
|
+
*/
|
|
129
|
+
private serializeKey;
|
|
130
|
+
/**
|
|
131
|
+
* Validate key segments.
|
|
132
|
+
*/
|
|
133
|
+
private validateKey;
|
|
134
|
+
/**
|
|
135
|
+
* Write an envelope to disk using atomic write-to-temp + rename.
|
|
136
|
+
*/
|
|
137
|
+
private writeEnvelope;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Factory function to create FileKeyStorage with common defaults.
|
|
141
|
+
*/
|
|
142
|
+
export declare function createFileKeyStorage(config?: FileKeyStorageConfig): FileKeyStorage;
|