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
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import { randomUUID } from 'node:crypto';
|
|
54
|
+
import * as fs from 'node:fs/promises';
|
|
55
|
+
import { join } from 'node:path';
|
|
56
|
+
import { lockKeyFromStorageKey, RWLock } from '../llm/context/rw-lock.js';
|
|
57
|
+
/**
|
|
58
|
+
* File-based key storage implementation.
|
|
59
|
+
*
|
|
60
|
+
* Stores key-value pairs as individual JSON files on the filesystem.
|
|
61
|
+
* Composite keys map to directory paths:
|
|
62
|
+
* ["message", sessionId, msgId] → {storageDir}/keystore/message/{sessionId}/{msgId}.json
|
|
63
|
+
*
|
|
64
|
+
* Features:
|
|
65
|
+
* - One file per entity (O(1) read/write/delete)
|
|
66
|
+
* - Atomic writes via write-to-temp + rename
|
|
67
|
+
* - Reader-writer locks for concurrent access (reuses global RWLock)
|
|
68
|
+
* - In-memory mode for fast unit tests
|
|
69
|
+
* - Hierarchical prefix listing via readdir
|
|
70
|
+
*/
|
|
71
|
+
export class FileKeyStorage {
|
|
72
|
+
baseDir;
|
|
73
|
+
initialized = false;
|
|
74
|
+
inMemory;
|
|
75
|
+
memoryStore = null;
|
|
76
|
+
storageDir;
|
|
77
|
+
constructor(config) {
|
|
78
|
+
this.inMemory = config?.inMemory ?? false;
|
|
79
|
+
this.storageDir = config?.storageDir ?? '';
|
|
80
|
+
if (!this.inMemory && !this.storageDir) {
|
|
81
|
+
throw new Error('FileKeyStorage: storageDir is required when inMemory is false');
|
|
82
|
+
}
|
|
83
|
+
this.baseDir = join(this.storageDir, 'keystore');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Execute batch operations.
|
|
87
|
+
* Operations are executed sequentially with write-temp-rename per operation.
|
|
88
|
+
* Best-effort: not ACID across multiple files, but each individual
|
|
89
|
+
* file write is atomic via rename.
|
|
90
|
+
*/
|
|
91
|
+
async batch(operations) {
|
|
92
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
93
|
+
try {
|
|
94
|
+
this.ensureInitialized();
|
|
95
|
+
if (operations.length === 0) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const lockKey = 'batch:global';
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
100
|
+
const _lock = __addDisposableResource(env_1, await RWLock.write(lockKey), false);
|
|
101
|
+
try {
|
|
102
|
+
for (const op of operations) {
|
|
103
|
+
if (op.type === 'set') {
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
// eslint-disable-next-line no-await-in-loop
|
|
106
|
+
const existing = await this.readEnvelope(op.key);
|
|
107
|
+
const envelope = {
|
|
108
|
+
createdAt: existing?.createdAt ?? now,
|
|
109
|
+
updatedAt: now,
|
|
110
|
+
value: op.value,
|
|
111
|
+
};
|
|
112
|
+
// eslint-disable-next-line no-await-in-loop
|
|
113
|
+
await this.writeEnvelope(op.key, envelope);
|
|
114
|
+
}
|
|
115
|
+
else if (op.type === 'delete') {
|
|
116
|
+
// eslint-disable-next-line no-await-in-loop
|
|
117
|
+
await this.removeFile(op.key);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
throw new Error(`Batch operation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (e_1) {
|
|
126
|
+
env_1.error = e_1;
|
|
127
|
+
env_1.hasError = true;
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
__disposeResources(env_1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Close the storage. No-op for file-based storage.
|
|
135
|
+
*/
|
|
136
|
+
close() {
|
|
137
|
+
if (this.inMemory) {
|
|
138
|
+
this.memoryStore = null;
|
|
139
|
+
}
|
|
140
|
+
this.initialized = false;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Delete a value by its composite key.
|
|
144
|
+
*/
|
|
145
|
+
async delete(key) {
|
|
146
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
147
|
+
try {
|
|
148
|
+
this.ensureInitialized();
|
|
149
|
+
this.validateKey(key);
|
|
150
|
+
const lockKey = lockKeyFromStorageKey(key);
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
152
|
+
const _lock = __addDisposableResource(env_2, await RWLock.write(lockKey), false);
|
|
153
|
+
return this.removeFile(key);
|
|
154
|
+
}
|
|
155
|
+
catch (e_2) {
|
|
156
|
+
env_2.error = e_2;
|
|
157
|
+
env_2.hasError = true;
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
__disposeResources(env_2);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check if a key exists.
|
|
165
|
+
*/
|
|
166
|
+
async exists(key) {
|
|
167
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
168
|
+
try {
|
|
169
|
+
this.ensureInitialized();
|
|
170
|
+
this.validateKey(key);
|
|
171
|
+
const lockKey = lockKeyFromStorageKey(key);
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
173
|
+
const _lock = __addDisposableResource(env_3, await RWLock.read(lockKey), false);
|
|
174
|
+
if (this.inMemory) {
|
|
175
|
+
return this.memoryStore.has(this.serializeKey(key));
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
await fs.access(this.keyToPath(key));
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (e_3) {
|
|
186
|
+
env_3.error = e_3;
|
|
187
|
+
env_3.hasError = true;
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
__disposeResources(env_3);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get a value by its composite key.
|
|
195
|
+
*/
|
|
196
|
+
async get(key) {
|
|
197
|
+
const env_4 = { stack: [], error: void 0, hasError: false };
|
|
198
|
+
try {
|
|
199
|
+
this.ensureInitialized();
|
|
200
|
+
this.validateKey(key);
|
|
201
|
+
const lockKey = lockKeyFromStorageKey(key);
|
|
202
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
203
|
+
const _lock = __addDisposableResource(env_4, await RWLock.read(lockKey), false);
|
|
204
|
+
try {
|
|
205
|
+
const envelope = await this.readEnvelope(key);
|
|
206
|
+
return envelope?.value;
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
throw new Error(`Failed to get key ${this.serializeKey(key)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (e_4) {
|
|
213
|
+
env_4.error = e_4;
|
|
214
|
+
env_4.hasError = true;
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
__disposeResources(env_4);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Initialize the storage backend.
|
|
222
|
+
* Creates the base keystore directory.
|
|
223
|
+
*/
|
|
224
|
+
async initialize() {
|
|
225
|
+
if (this.initialized) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
if (this.inMemory) {
|
|
230
|
+
this.memoryStore = new Map();
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
await fs.mkdir(this.baseDir, { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
this.initialized = true;
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
throw new Error(`Failed to initialize file key storage: ${error instanceof Error ? error.message : String(error)}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* List all keys matching a prefix.
|
|
243
|
+
*/
|
|
244
|
+
async list(prefix) {
|
|
245
|
+
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
246
|
+
try {
|
|
247
|
+
this.ensureInitialized();
|
|
248
|
+
const lockKey = lockKeyFromStorageKey(prefix);
|
|
249
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
250
|
+
const _lock = __addDisposableResource(env_5, await RWLock.read(lockKey), false);
|
|
251
|
+
try {
|
|
252
|
+
if (this.inMemory) {
|
|
253
|
+
return this.listInMemory(prefix);
|
|
254
|
+
}
|
|
255
|
+
return this.listFromDisk(prefix);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
throw new Error(`Failed to list keys with prefix ${this.serializeKey(prefix)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (e_5) {
|
|
262
|
+
env_5.error = e_5;
|
|
263
|
+
env_5.hasError = true;
|
|
264
|
+
}
|
|
265
|
+
finally {
|
|
266
|
+
__disposeResources(env_5);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* List all key-value pairs matching a prefix.
|
|
271
|
+
* More efficient than list() followed by individual get() calls.
|
|
272
|
+
*/
|
|
273
|
+
async listWithValues(prefix) {
|
|
274
|
+
const env_6 = { stack: [], error: void 0, hasError: false };
|
|
275
|
+
try {
|
|
276
|
+
this.ensureInitialized();
|
|
277
|
+
const lockKey = lockKeyFromStorageKey(prefix);
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
279
|
+
const _lock = __addDisposableResource(env_6, await RWLock.read(lockKey), false);
|
|
280
|
+
try {
|
|
281
|
+
if (this.inMemory) {
|
|
282
|
+
return this.listWithValuesInMemory(prefix);
|
|
283
|
+
}
|
|
284
|
+
return this.listWithValuesFromDisk(prefix);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
throw new Error(`Failed to list keys with values for prefix ${this.serializeKey(prefix)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch (e_6) {
|
|
291
|
+
env_6.error = e_6;
|
|
292
|
+
env_6.hasError = true;
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
__disposeResources(env_6);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Set a value at a composite key.
|
|
300
|
+
*/
|
|
301
|
+
async set(key, value) {
|
|
302
|
+
const env_7 = { stack: [], error: void 0, hasError: false };
|
|
303
|
+
try {
|
|
304
|
+
this.ensureInitialized();
|
|
305
|
+
this.validateKey(key);
|
|
306
|
+
const lockKey = lockKeyFromStorageKey(key);
|
|
307
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
308
|
+
const _lock = __addDisposableResource(env_7, await RWLock.write(lockKey), false);
|
|
309
|
+
const now = Date.now();
|
|
310
|
+
try {
|
|
311
|
+
// Preserve createdAt if key already exists
|
|
312
|
+
const existing = await this.readEnvelope(key);
|
|
313
|
+
const envelope = {
|
|
314
|
+
createdAt: existing?.createdAt ?? now,
|
|
315
|
+
updatedAt: now,
|
|
316
|
+
value,
|
|
317
|
+
};
|
|
318
|
+
await this.writeEnvelope(key, envelope);
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
throw new Error(`Failed to set key ${this.serializeKey(key)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
catch (e_7) {
|
|
325
|
+
env_7.error = e_7;
|
|
326
|
+
env_7.hasError = true;
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
__disposeResources(env_7);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Atomic update with optimistic locking.
|
|
334
|
+
*/
|
|
335
|
+
async update(key, updater) {
|
|
336
|
+
const env_8 = { stack: [], error: void 0, hasError: false };
|
|
337
|
+
try {
|
|
338
|
+
this.ensureInitialized();
|
|
339
|
+
this.validateKey(key);
|
|
340
|
+
const lockKey = lockKeyFromStorageKey(key);
|
|
341
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
342
|
+
const _lock = __addDisposableResource(env_8, await RWLock.write(lockKey), false);
|
|
343
|
+
try {
|
|
344
|
+
const existing = await this.readEnvelope(key);
|
|
345
|
+
const currentValue = existing?.value;
|
|
346
|
+
const newValue = updater(currentValue);
|
|
347
|
+
const now = Date.now();
|
|
348
|
+
const envelope = {
|
|
349
|
+
createdAt: existing?.createdAt ?? now,
|
|
350
|
+
updatedAt: now,
|
|
351
|
+
value: newValue,
|
|
352
|
+
};
|
|
353
|
+
await this.writeEnvelope(key, envelope);
|
|
354
|
+
return newValue;
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
throw new Error(`Failed to update key ${this.serializeKey(key)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
catch (e_8) {
|
|
361
|
+
env_8.error = e_8;
|
|
362
|
+
env_8.hasError = true;
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
__disposeResources(env_8);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
// Private helpers
|
|
370
|
+
// ---------------------------------------------------------------------------
|
|
371
|
+
/**
|
|
372
|
+
* Deserialize a colon-separated string back to a StorageKey.
|
|
373
|
+
*/
|
|
374
|
+
deserializeKey(keyStr) {
|
|
375
|
+
return keyStr.split(':');
|
|
376
|
+
}
|
|
377
|
+
ensureInitialized() {
|
|
378
|
+
if (!this.initialized) {
|
|
379
|
+
throw new Error('FileKeyStorage not initialized. Call initialize() first.');
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Convert a StorageKey to a filesystem path.
|
|
384
|
+
* ["message", "abc", "msg1"] → {baseDir}/message/abc/msg1.json
|
|
385
|
+
*/
|
|
386
|
+
keyToPath(key) {
|
|
387
|
+
const segments = [...key];
|
|
388
|
+
const last = segments.pop();
|
|
389
|
+
const dir = segments.length > 0 ? join(this.baseDir, ...segments) : this.baseDir;
|
|
390
|
+
return join(dir, `${last}.json`);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* List keys from disk by scanning the prefix directory.
|
|
394
|
+
*/
|
|
395
|
+
async listFromDisk(prefix) {
|
|
396
|
+
const prefixDir = join(this.baseDir, ...prefix);
|
|
397
|
+
const results = [];
|
|
398
|
+
try {
|
|
399
|
+
await fs.access(prefixDir);
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
return results;
|
|
403
|
+
}
|
|
404
|
+
await this.scanDirectory(prefixDir, prefix, results);
|
|
405
|
+
results.sort((a, b) => this.serializeKey(a).localeCompare(this.serializeKey(b)));
|
|
406
|
+
return results;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* List keys from in-memory store matching a prefix.
|
|
410
|
+
*/
|
|
411
|
+
listInMemory(prefix) {
|
|
412
|
+
const prefixStr = this.serializeKey(prefix);
|
|
413
|
+
const results = [];
|
|
414
|
+
for (const storedKey of this.memoryStore.keys()) {
|
|
415
|
+
if (storedKey.startsWith(prefixStr)) {
|
|
416
|
+
results.push(this.deserializeKey(storedKey));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
results.sort((a, b) => this.serializeKey(a).localeCompare(this.serializeKey(b)));
|
|
420
|
+
return results;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* List keys with values from disk.
|
|
424
|
+
*/
|
|
425
|
+
async listWithValuesFromDisk(prefix) {
|
|
426
|
+
const keys = await this.listFromDisk(prefix);
|
|
427
|
+
const results = [];
|
|
428
|
+
for (const key of keys) {
|
|
429
|
+
try {
|
|
430
|
+
// eslint-disable-next-line no-await-in-loop
|
|
431
|
+
const envelope = await this.readEnvelope(key);
|
|
432
|
+
if (envelope) {
|
|
433
|
+
results.push({ key, value: envelope.value });
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
// Skip corrupt or unreadable files
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return results;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* List keys with values from in-memory store.
|
|
444
|
+
*/
|
|
445
|
+
listWithValuesInMemory(prefix) {
|
|
446
|
+
const prefixStr = this.serializeKey(prefix);
|
|
447
|
+
const results = [];
|
|
448
|
+
for (const [storedKey, envelope] of this.memoryStore.entries()) {
|
|
449
|
+
if (storedKey.startsWith(prefixStr)) {
|
|
450
|
+
results.push({ key: this.deserializeKey(storedKey), value: envelope.value });
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
results.sort((a, b) => this.serializeKey(a.key).localeCompare(this.serializeKey(b.key)));
|
|
454
|
+
return results;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Read the stored envelope for a key. Returns undefined if not found.
|
|
458
|
+
*/
|
|
459
|
+
async readEnvelope(key) {
|
|
460
|
+
if (this.inMemory) {
|
|
461
|
+
return this.memoryStore.get(this.serializeKey(key));
|
|
462
|
+
}
|
|
463
|
+
const filePath = this.keyToPath(key);
|
|
464
|
+
try {
|
|
465
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
466
|
+
return JSON.parse(content);
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
if (error.code === 'ENOENT') {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
throw error;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Remove a file for the given key. Returns true if it existed.
|
|
477
|
+
*/
|
|
478
|
+
async removeFile(key) {
|
|
479
|
+
if (this.inMemory) {
|
|
480
|
+
return this.memoryStore.delete(this.serializeKey(key));
|
|
481
|
+
}
|
|
482
|
+
const filePath = this.keyToPath(key);
|
|
483
|
+
try {
|
|
484
|
+
await fs.unlink(filePath);
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
catch (error) {
|
|
488
|
+
if (error.code === 'ENOENT') {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Recursively scan a directory to collect all storage keys.
|
|
496
|
+
*/
|
|
497
|
+
async scanDirectory(dir, prefix, results) {
|
|
498
|
+
let entries;
|
|
499
|
+
try {
|
|
500
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
for (const entry of entries) {
|
|
506
|
+
// Skip temp files from atomic writes
|
|
507
|
+
if (entry.name.includes('.tmp.')) {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
const fullPath = join(dir, entry.name);
|
|
511
|
+
if (entry.isDirectory()) {
|
|
512
|
+
// eslint-disable-next-line no-await-in-loop
|
|
513
|
+
await this.scanDirectory(fullPath, [...prefix, entry.name], results);
|
|
514
|
+
}
|
|
515
|
+
else if (entry.isFile() && entry.name.endsWith('.json')) {
|
|
516
|
+
const segment = entry.name.slice(0, -5); // Remove .json
|
|
517
|
+
results.push([...prefix, segment]);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Serialize a StorageKey to a string for in-memory store lookups.
|
|
523
|
+
* Uses ':' separator (same as lockKeyFromStorageKey).
|
|
524
|
+
*/
|
|
525
|
+
serializeKey(key) {
|
|
526
|
+
return key.join(':');
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Validate key segments.
|
|
530
|
+
*/
|
|
531
|
+
validateKey(key) {
|
|
532
|
+
if (key.length === 0) {
|
|
533
|
+
throw new Error('Storage key cannot be empty');
|
|
534
|
+
}
|
|
535
|
+
for (const segment of key) {
|
|
536
|
+
if (!segment) {
|
|
537
|
+
throw new Error('Key segment cannot be empty');
|
|
538
|
+
}
|
|
539
|
+
if (segment.includes(':')) {
|
|
540
|
+
throw new Error(`Key segment cannot contain ':': ${segment}`);
|
|
541
|
+
}
|
|
542
|
+
if (segment.includes('/') || segment.includes('\\')) {
|
|
543
|
+
throw new Error(`Key segment cannot contain path separators: ${segment}`);
|
|
544
|
+
}
|
|
545
|
+
if (segment === '..' || segment === '.') {
|
|
546
|
+
throw new Error(`Key segment cannot be '${segment}'`);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Write an envelope to disk using atomic write-to-temp + rename.
|
|
552
|
+
*/
|
|
553
|
+
async writeEnvelope(key, envelope) {
|
|
554
|
+
if (this.inMemory) {
|
|
555
|
+
this.memoryStore.set(this.serializeKey(key), envelope);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const filePath = this.keyToPath(key);
|
|
559
|
+
const dir = join(filePath, '..');
|
|
560
|
+
await fs.mkdir(dir, { recursive: true });
|
|
561
|
+
const tmpPath = `${filePath}.tmp.${randomUUID()}`;
|
|
562
|
+
const content = JSON.stringify(envelope, null, 2);
|
|
563
|
+
await fs.writeFile(tmpPath, content, 'utf8');
|
|
564
|
+
await fs.rename(tmpPath, filePath);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Factory function to create FileKeyStorage with common defaults.
|
|
569
|
+
*/
|
|
570
|
+
export function createFileKeyStorage(config) {
|
|
571
|
+
return new FileKeyStorage(config);
|
|
572
|
+
}
|
|
@@ -10,7 +10,7 @@ import { MessageStorageService } from './message-storage-service.js';
|
|
|
10
10
|
* - Selective tool output pruning
|
|
11
11
|
* - Compaction boundary markers
|
|
12
12
|
*
|
|
13
|
-
* This is
|
|
13
|
+
* This is the primary history storage implementation.
|
|
14
14
|
*/
|
|
15
15
|
export declare class GranularHistoryStorage implements IHistoryStorage {
|
|
16
16
|
private readonly messageStorage;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - Selective tool output pruning
|
|
7
7
|
* - Compaction boundary markers
|
|
8
8
|
*
|
|
9
|
-
* This is
|
|
9
|
+
* This is the primary history storage implementation.
|
|
10
10
|
*/
|
|
11
11
|
export class GranularHistoryStorage {
|
|
12
12
|
messageStorage;
|
|
@@ -63,5 +63,9 @@ export declare class ContextTreeStructureContributor implements SystemPromptCont
|
|
|
63
63
|
* @returns Instructions for using search_knowledge tool
|
|
64
64
|
*/
|
|
65
65
|
private buildSearchKnowledgeInstructions;
|
|
66
|
+
/**
|
|
67
|
+
* Count .stub.md files inside an _archived/ directory (recursive).
|
|
68
|
+
*/
|
|
69
|
+
private countArchivedEntries;
|
|
66
70
|
private traverseContextTree;
|
|
67
71
|
}
|
|
@@ -92,7 +92,7 @@ export class ContextTreeStructureContributor {
|
|
|
92
92
|
if (truncatedCount.value > 0) {
|
|
93
93
|
parts.push('', `[${truncatedCount.value} additional entries not shown]`);
|
|
94
94
|
}
|
|
95
|
-
parts.push('', '## Structure Guide', '- Each top-level folder is a **domain** (dynamically created based on content)', '- Inside domains are **topics** as `.md` files or subfolders with `context.md`', '- `context.md` files contain the curated knowledge content', '', '## Dynamic Domains', '- Domains are created dynamically based on the semantics of curated content', '- Domain names should be descriptive, use snake_case (e.g., `architecture`, `market_trends`, `risk_analysis`)', '- Before creating a new domain, check if existing domains could accommodate the content', '', '## Usage', '- **Query commands**: Search ONLY within this context tree structure', '- **Curate commands**: Check existing domains/topics before creating new ones', '</context-tree-structure>');
|
|
95
|
+
parts.push('', '## Structure Guide', '- Each top-level folder is a **domain** (dynamically created based on content)', '- Inside domains are **topics** as `.md` files or subfolders with `context.md`', '- `context.md` files contain the curated knowledge content', '- `_index.md` files are auto-generated summaries at each directory level', '- `_archived/` contains archived low-importance entries (use `expand_knowledge` to drill into them)', '', '## Dynamic Domains', '- Domains are created dynamically based on the semantics of curated content', '- Domain names should be descriptive, use snake_case (e.g., `architecture`, `market_trends`, `risk_analysis`)', '- Before creating a new domain, check if existing domains could accommodate the content', '', '## Usage', '- **Query commands**: Search ONLY within this context tree structure', '- **Curate commands**: Check existing domains/topics before creating new ones', '</context-tree-structure>');
|
|
96
96
|
return parts.join('\n');
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
@@ -168,6 +168,18 @@ export class ContextTreeStructureContributor {
|
|
|
168
168
|
'</context-tree-structure>',
|
|
169
169
|
].join('\n');
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Count .stub.md files inside an _archived/ directory (recursive).
|
|
173
|
+
*/
|
|
174
|
+
async countArchivedEntries(archivedDir) {
|
|
175
|
+
try {
|
|
176
|
+
const entries = await fs.readdir(archivedDir, { recursive: true });
|
|
177
|
+
return entries.filter((e) => String(e).endsWith('.stub.md')).length;
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
171
183
|
async traverseContextTree(options) {
|
|
172
184
|
const { currentDepth, dir, entriesCount, lines, maxDepth, maxEntries, relativePath, truncatedCount } = options;
|
|
173
185
|
if (currentDepth >= maxDepth) {
|
|
@@ -198,21 +210,37 @@ export class ContextTreeStructureContributor {
|
|
|
198
210
|
entriesCount.value++;
|
|
199
211
|
const entryRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
200
212
|
if (entry.isDirectory()) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
// For _archived/ directories, show entry count instead of recursing
|
|
214
|
+
if (entry.name === '_archived') {
|
|
215
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential traversal required for ordered output
|
|
216
|
+
const archivedCount = await this.countArchivedEntries(path.join(dir, entry.name));
|
|
217
|
+
if (archivedCount > 0) {
|
|
218
|
+
lines.push(`${indent}_archived/ (${archivedCount} archived entries)`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
lines.push(`${indent}${entry.name}/`);
|
|
223
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential traversal required for ordered output
|
|
224
|
+
await this.traverseContextTree({
|
|
225
|
+
currentDepth: currentDepth + 1,
|
|
226
|
+
dir: path.join(dir, entry.name),
|
|
227
|
+
entriesCount,
|
|
228
|
+
lines,
|
|
229
|
+
maxDepth,
|
|
230
|
+
maxEntries,
|
|
231
|
+
relativePath: entryRelativePath,
|
|
232
|
+
truncatedCount,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
213
235
|
}
|
|
214
236
|
else {
|
|
215
|
-
|
|
237
|
+
let annotation = '';
|
|
238
|
+
if (entry.name === 'context.md') {
|
|
239
|
+
annotation = ' (knowledge content)';
|
|
240
|
+
}
|
|
241
|
+
else if (entry.name === '_index.md') {
|
|
242
|
+
annotation = ' (summary)';
|
|
243
|
+
}
|
|
216
244
|
lines.push(`${indent}${entry.name}${annotation}`);
|
|
217
245
|
}
|
|
218
246
|
}
|