byterover-cli 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +17 -3
  2. package/dist/agent/core/domain/tools/constants.d.ts +0 -15
  3. package/dist/agent/core/domain/tools/constants.js +0 -15
  4. package/dist/agent/core/interfaces/i-cipher-agent.d.ts +6 -0
  5. package/dist/agent/core/interfaces/i-curate-service.d.ts +12 -0
  6. package/dist/agent/infra/llm/internal-llm-service.d.ts +13 -0
  7. package/dist/agent/infra/llm/internal-llm-service.js +61 -21
  8. package/dist/agent/infra/tools/implementations/curate-tool.d.ts +133 -0
  9. package/dist/agent/infra/tools/implementations/curate-tool.js +14 -0
  10. package/dist/agent/infra/tools/implementations/search-knowledge-service.js +91 -14
  11. package/dist/agent/infra/tools/index.d.ts +0 -4
  12. package/dist/agent/infra/tools/index.js +0 -4
  13. package/dist/agent/infra/tools/tool-registry.js +0 -113
  14. package/dist/agent/resources/prompts/curate-detail-preservation.yml +73 -0
  15. package/dist/agent/resources/prompts/system-prompt.yml +69 -3
  16. package/dist/server/core/domain/knowledge/markdown-writer.d.ts +13 -0
  17. package/dist/server/core/domain/knowledge/markdown-writer.js +116 -8
  18. package/dist/server/infra/executor/curate-executor.js +1 -1
  19. package/dist/server/infra/executor/direct-search-responder.d.ts +45 -0
  20. package/dist/server/infra/executor/direct-search-responder.js +86 -0
  21. package/dist/server/infra/executor/folder-pack-executor.d.ts +13 -5
  22. package/dist/server/infra/executor/folder-pack-executor.js +739 -39
  23. package/dist/server/infra/executor/query-executor.d.ts +49 -3
  24. package/dist/server/infra/executor/query-executor.js +194 -9
  25. package/dist/server/infra/executor/query-result-cache.d.ts +87 -0
  26. package/dist/server/infra/executor/query-result-cache.js +127 -0
  27. package/dist/server/infra/executor/query-similarity.d.ts +28 -0
  28. package/dist/server/infra/executor/query-similarity.js +41 -0
  29. package/dist/server/infra/process/agent-worker.js +9 -2
  30. package/dist/server/infra/process/inline-agent-executor.js +16 -5
  31. package/dist/server/infra/usecase/curate-use-case.js +6 -1
  32. package/dist/server/infra/usecase/query-use-case.js +10 -0
  33. package/dist/server/utils/file-validator.js +78 -1
  34. package/dist/tui/hooks/use-slash-completion.js +25 -4
  35. package/oclif.manifest.json +1 -1
  36. package/package.json +1 -1
  37. package/dist/agent/infra/tools/implementations/bash-exec-tool.d.ts +0 -13
  38. package/dist/agent/infra/tools/implementations/bash-exec-tool.js +0 -110
  39. package/dist/agent/infra/tools/implementations/bash-output-tool.d.ts +0 -12
  40. package/dist/agent/infra/tools/implementations/bash-output-tool.js +0 -43
  41. package/dist/agent/infra/tools/implementations/batch-tool.d.ts +0 -12
  42. package/dist/agent/infra/tools/implementations/batch-tool.js +0 -142
  43. package/dist/agent/infra/tools/implementations/create-knowledge-topic-tool.d.ts +0 -11
  44. package/dist/agent/infra/tools/implementations/create-knowledge-topic-tool.js +0 -149
  45. package/dist/agent/infra/tools/implementations/delete-memory-tool.d.ts +0 -12
  46. package/dist/agent/infra/tools/implementations/delete-memory-tool.js +0 -37
  47. package/dist/agent/infra/tools/implementations/edit-file-tool.d.ts +0 -13
  48. package/dist/agent/infra/tools/implementations/edit-file-tool.js +0 -50
  49. package/dist/agent/infra/tools/implementations/edit-memory-tool.d.ts +0 -13
  50. package/dist/agent/infra/tools/implementations/edit-memory-tool.js +0 -53
  51. package/dist/agent/infra/tools/implementations/kill-process-tool.d.ts +0 -12
  52. package/dist/agent/infra/tools/implementations/kill-process-tool.js +0 -55
  53. package/dist/agent/infra/tools/implementations/list-memories-tool.d.ts +0 -12
  54. package/dist/agent/infra/tools/implementations/list-memories-tool.js +0 -63
  55. package/dist/agent/infra/tools/implementations/read-memory-tool.d.ts +0 -12
  56. package/dist/agent/infra/tools/implementations/read-memory-tool.js +0 -39
  57. package/dist/agent/infra/tools/implementations/read-todos-tool.d.ts +0 -11
  58. package/dist/agent/infra/tools/implementations/read-todos-tool.js +0 -39
  59. package/dist/agent/infra/tools/implementations/search-history-tool.d.ts +0 -10
  60. package/dist/agent/infra/tools/implementations/search-history-tool.js +0 -36
  61. package/dist/agent/infra/tools/implementations/spec-analyze-tool.d.ts +0 -7
  62. package/dist/agent/infra/tools/implementations/spec-analyze-tool.js +0 -78
  63. package/dist/agent/infra/tools/implementations/write-memory-tool.d.ts +0 -13
  64. package/dist/agent/infra/tools/implementations/write-memory-tool.js +0 -52
  65. package/dist/agent/infra/tools/implementations/write-todos-tool.d.ts +0 -13
  66. package/dist/agent/infra/tools/implementations/write-todos-tool.js +0 -121
@@ -4,11 +4,21 @@ import { removeStopwords } from 'stopword';
4
4
  import { BRV_DIR, CONTEXT_FILE_EXTENSION, CONTEXT_TREE_DIR } from '../../../../server/constants.js';
5
5
  const MAX_CONTEXT_TREE_FILES = 10_000;
6
6
  const DEFAULT_CACHE_TTL_MS = 5000;
7
+ /** Bump when MINISEARCH_OPTIONS fields/boost change to invalidate cached indexes */
8
+ const INDEX_SCHEMA_VERSION = 3;
9
+ /** Only include results whose score is at least this fraction of the top result's score */
10
+ const SCORE_GAP_RATIO = 0.2;
11
+ /** Minimum absolute score for the top result. Below this, the query is considered out-of-domain */
12
+ const MINIMUM_RELEVANCE_SCORE = 4;
13
+ /** Score threshold above which results are trusted despite unmatched query terms */
14
+ const UNMATCHED_TERM_SCORE_THRESHOLD = 8;
15
+ /** Minimum query term length to consider "significant" for OOD term-based detection */
16
+ const UNMATCHED_TERM_MIN_LENGTH = 4;
7
17
  const MINISEARCH_OPTIONS = {
8
- fields: ['title', 'content'],
18
+ fields: ['title', 'content', 'path'],
9
19
  idField: 'id',
10
20
  searchOptions: {
11
- boost: { title: 2 },
21
+ boost: { path: 1.5, title: 3 },
12
22
  fuzzy: 0.2,
13
23
  prefix: true,
14
24
  },
@@ -19,6 +29,24 @@ function filterStopWords(query) {
19
29
  const filtered = removeStopwords(words);
20
30
  return filtered.length > 0 ? filtered.join(' ') : query;
21
31
  }
32
+ /**
33
+ * Checks if any significant query term is completely unmatched across search results.
34
+ * Uses MiniSearch's queryTerms property to identify which terms actually matched.
35
+ * A "significant" term is one with length >= UNMATCHED_TERM_MIN_LENGTH (filters out
36
+ * short generic words that are noisy for OOD detection).
37
+ */
38
+ function hasUnmatchedSignificantTerms(queryTerms, searchResults) {
39
+ const significantTerms = queryTerms.filter((t) => t.length >= UNMATCHED_TERM_MIN_LENGTH);
40
+ if (significantTerms.length === 0)
41
+ return false;
42
+ const allMatchedQueryTerms = new Set();
43
+ for (const result of searchResults.slice(0, 10)) {
44
+ for (const term of result.queryTerms) {
45
+ allMatchedQueryTerms.add(term);
46
+ }
47
+ }
48
+ return significantTerms.some((t) => !allMatchedQueryTerms.has(t));
49
+ }
22
50
  function extractTitle(content, fallbackTitle) {
23
51
  const match = /^# (.+)$/m.exec(content);
24
52
  return match ? match[1].trim() : fallbackTitle;
@@ -110,6 +138,7 @@ async function buildFreshIndex(fileSystem, contextTreePath, filesWithMtime) {
110
138
  fileMtimes: new Map(),
111
139
  index,
112
140
  lastValidatedAt: now,
141
+ schemaVersion: INDEX_SCHEMA_VERSION,
113
142
  };
114
143
  }
115
144
  const documentPromises = filesWithMtime.map(async ({ mtime, path: filePath }) => {
@@ -145,6 +174,7 @@ async function buildFreshIndex(fileSystem, contextTreePath, filesWithMtime) {
145
174
  fileMtimes,
146
175
  index,
147
176
  lastValidatedAt: now,
177
+ schemaVersion: INDEX_SCHEMA_VERSION,
148
178
  };
149
179
  }
150
180
  /**
@@ -156,6 +186,7 @@ async function acquireIndex(state, fileSystem, contextTreePath, ttlMs) {
156
186
  // Fast path: TTL-based cache hit (no I/O needed)
157
187
  if (state.cachedIndex &&
158
188
  state.cachedIndex.contextTreePath === contextTreePath &&
189
+ state.cachedIndex.schemaVersion === INDEX_SCHEMA_VERSION &&
159
190
  ttlMs > 0 &&
160
191
  now - state.cachedIndex.lastValidatedAt < ttlMs) {
161
192
  return state.cachedIndex;
@@ -181,6 +212,7 @@ async function acquireIndex(state, fileSystem, contextTreePath, ttlMs) {
181
212
  fileMtimes: new Map(),
182
213
  index: emptyIndex,
183
214
  lastValidatedAt: 0,
215
+ schemaVersion: INDEX_SCHEMA_VERSION,
184
216
  };
185
217
  }
186
218
  }
@@ -188,6 +220,7 @@ async function acquireIndex(state, fileSystem, contextTreePath, ttlMs) {
188
220
  // Re-check cache validity after getting file list (another call may have finished)
189
221
  if (state.cachedIndex &&
190
222
  state.cachedIndex.contextTreePath === contextTreePath &&
223
+ state.cachedIndex.schemaVersion === INDEX_SCHEMA_VERSION &&
191
224
  isCacheValid(state.cachedIndex, currentFiles)) {
192
225
  // Update timestamp atomically by creating a new object
193
226
  const updatedCache = {
@@ -266,19 +299,63 @@ export class SearchKnowledgeService {
266
299
  };
267
300
  }
268
301
  const filteredQuery = filterStopWords(query);
269
- const searchResults = index.search(filteredQuery, { combineWith: 'OR' });
302
+ const filteredWords = filteredQuery.split(/\s+/).filter((w) => w.length >= 2);
303
+ // AND-first strategy: for multi-word queries, try AND for concentrated scores.
304
+ // If AND returns no results, fall back to OR to ensure no regression.
305
+ let searchResults;
306
+ let andSearchFailed = false;
307
+ if (filteredWords.length >= 2) {
308
+ searchResults = index.search(filteredQuery, { combineWith: 'AND' });
309
+ if (searchResults.length === 0) {
310
+ andSearchFailed = true;
311
+ searchResults = index.search(filteredQuery, { combineWith: 'OR' });
312
+ }
313
+ }
314
+ else {
315
+ searchResults = index.search(filteredQuery, { combineWith: 'OR' });
316
+ }
270
317
  const results = [];
271
- const resultLimit = Math.min(limit, searchResults.length);
272
- for (let i = 0; i < resultLimit; i++) {
273
- const result = searchResults[i];
274
- const document = documentMap.get(result.id);
275
- if (document) {
276
- results.push({
277
- excerpt: extractExcerpt(document.content, query),
278
- path: document.path,
279
- score: Math.round(result.score * 100) / 100,
280
- title: document.title,
281
- });
318
+ if (searchResults.length > 0) {
319
+ // OOD detection: if the best result scores below the minimum floor,
320
+ // the query has no meaningful match in the knowledge base.
321
+ // Only apply for corpora with enough documents for reliable BM25 scoring.
322
+ if (documentMap.size >= 50 && searchResults[0].score < MINIMUM_RELEVANCE_SCORE) {
323
+ return {
324
+ message: 'No matching knowledge found for this query. The topic may not be covered in the context tree.',
325
+ results: [],
326
+ totalFound: 0,
327
+ };
328
+ }
329
+ // Term-based OOD: when AND search failed, check if significant query terms
330
+ // are completely absent from the corpus. If unmatched terms exist and the
331
+ // score is below the trusted threshold, the query is about an uncovered topic.
332
+ if (andSearchFailed &&
333
+ documentMap.size >= 50 &&
334
+ searchResults[0].score < UNMATCHED_TERM_SCORE_THRESHOLD &&
335
+ hasUnmatchedSignificantTerms(filteredWords, searchResults)) {
336
+ return {
337
+ message: 'No matching knowledge found for this query. The topic may not be covered in the context tree.',
338
+ results: [],
339
+ totalFound: 0,
340
+ };
341
+ }
342
+ const topScore = searchResults[0].score;
343
+ const scoreFloor = topScore * SCORE_GAP_RATIO;
344
+ const resultLimit = Math.min(limit, searchResults.length);
345
+ for (let i = 0; i < resultLimit; i++) {
346
+ const result = searchResults[i];
347
+ // Score-gap filter: skip results too far below the top score
348
+ if (result.score < scoreFloor)
349
+ break;
350
+ const document = documentMap.get(result.id);
351
+ if (document) {
352
+ results.push({
353
+ excerpt: extractExcerpt(document.content, query),
354
+ path: document.path,
355
+ score: Math.round(result.score * 100) / 100,
356
+ title: document.title,
357
+ });
358
+ }
282
359
  }
283
360
  }
284
361
  return {
@@ -3,14 +3,10 @@ export { ToolName } from '../../core/domain/tools/constants.js';
3
3
  export type { KnownTool } from '../../core/domain/tools/constants.js';
4
4
  export type { JSONSchema7, Tool, ToolExecutionContext, ToolSet } from '../../core/domain/tools/types.js';
5
5
  export type { IToolProvider } from '../../core/interfaces/i-tool-provider.js';
6
- export { createCreateKnowledgeTopicTool } from './implementations/create-knowledge-topic-tool.js';
7
- export { createEditFileTool } from './implementations/edit-file-tool.js';
8
6
  export { createGlobFilesTool } from './implementations/glob-files-tool.js';
9
7
  export { createGrepContentTool } from './implementations/grep-content-tool.js';
10
8
  export { createReadFileTool } from './implementations/read-file-tool.js';
11
- export { createSearchHistoryTool } from './implementations/search-history-tool.js';
12
9
  export { createSearchKnowledgeTool } from './implementations/search-knowledge-tool.js';
13
- export { createSpecAnalyzeTool } from './implementations/spec-analyze-tool.js';
14
10
  export { createWriteFileTool } from './implementations/write-file-tool.js';
15
11
  export { ToolManager } from './tool-manager.js';
16
12
  export { ToolProvider } from './tool-provider.js';
@@ -3,14 +3,10 @@ export { ToolError, ToolExecutionError, ToolNotFoundError, ToolProviderNotInitia
3
3
  // Constants
4
4
  export { ToolName } from '../../core/domain/tools/constants.js';
5
5
  // Tool implementations (for direct access if needed)
6
- export { createCreateKnowledgeTopicTool } from './implementations/create-knowledge-topic-tool.js';
7
- export { createEditFileTool } from './implementations/edit-file-tool.js';
8
6
  export { createGlobFilesTool } from './implementations/glob-files-tool.js';
9
7
  export { createGrepContentTool } from './implementations/grep-content-tool.js';
10
8
  export { createReadFileTool } from './implementations/read-file-tool.js';
11
- export { createSearchHistoryTool } from './implementations/search-history-tool.js';
12
9
  export { createSearchKnowledgeTool } from './implementations/search-knowledge-tool.js';
13
- export { createSpecAnalyzeTool } from './implementations/spec-analyze-tool.js';
14
10
  export { createWriteFileTool } from './implementations/write-file-tool.js';
15
11
  // Registry and provider
16
12
  export { ToolManager } from './tool-manager.js';
@@ -1,30 +1,14 @@
1
1
  import { ToolName } from '../../core/domain/tools/constants.js';
2
2
  import { createCurateService } from '../sandbox/curate-service.js';
3
- import { createBashExecTool } from './implementations/bash-exec-tool.js';
4
- import { createBashOutputTool } from './implementations/bash-output-tool.js';
5
- import { createBatchTool } from './implementations/batch-tool.js';
6
3
  import { createCodeExecTool } from './implementations/code-exec-tool.js';
7
- import { createCreateKnowledgeTopicTool } from './implementations/create-knowledge-topic-tool.js';
8
4
  import { createCurateTool } from './implementations/curate-tool.js';
9
- import { createDeleteMemoryTool } from './implementations/delete-memory-tool.js';
10
- import { createEditFileTool } from './implementations/edit-file-tool.js';
11
- import { createEditMemoryTool } from './implementations/edit-memory-tool.js';
12
- // import {createFindKnowledgeTopicsTool} from './implementations/find-knowledge-topics-tool.js'
13
5
  import { createGlobFilesTool } from './implementations/glob-files-tool.js';
14
6
  import { createGrepContentTool } from './implementations/grep-content-tool.js';
15
- import { createKillProcessTool } from './implementations/kill-process-tool.js';
16
7
  import { createListDirectoryTool } from './implementations/list-directory-tool.js';
17
- import { createListMemoriesTool } from './implementations/list-memories-tool.js';
18
8
  import { createReadFileTool } from './implementations/read-file-tool.js';
19
- import { createReadMemoryTool } from './implementations/read-memory-tool.js';
20
- import { createReadTodosTool } from './implementations/read-todos-tool.js';
21
- import { createSearchHistoryTool } from './implementations/search-history-tool.js';
22
9
  import { createSearchKnowledgeService } from './implementations/search-knowledge-service.js';
23
10
  import { createSearchKnowledgeTool } from './implementations/search-knowledge-tool.js';
24
- import { createSpecAnalyzeTool } from './implementations/spec-analyze-tool.js';
25
11
  import { createWriteFileTool } from './implementations/write-file-tool.js';
26
- import { createWriteMemoryTool } from './implementations/write-memory-tool.js';
27
- import { createWriteTodosTool } from './implementations/write-todos-tool.js';
28
12
  import { ToolMarker } from './tool-markers.js';
29
13
  /**
30
14
  * Helper function to safely retrieve a required service.
@@ -51,24 +35,6 @@ function getRequiredService(service, serviceName) {
51
35
  * 3. Add entry to this registry
52
36
  */
53
37
  export const TOOL_REGISTRY = {
54
- [ToolName.BASH_EXEC]: {
55
- descriptionFile: 'bash_exec',
56
- factory: (services) => createBashExecTool(getRequiredService(services.processService, 'processService')),
57
- markers: [ToolMarker.Execution],
58
- requiredServices: ['processService'],
59
- },
60
- [ToolName.BASH_OUTPUT]: {
61
- descriptionFile: 'bash_output',
62
- factory: (services) => createBashOutputTool(getRequiredService(services.processService, 'processService')),
63
- markers: [ToolMarker.Execution, ToolMarker.Optional],
64
- requiredServices: ['processService'],
65
- },
66
- [ToolName.BATCH]: {
67
- descriptionFile: 'batch',
68
- factory: (services) => createBatchTool(getRequiredService(services.getToolProvider, 'getToolProvider')),
69
- markers: [ToolMarker.Execution, ToolMarker.Core],
70
- requiredServices: ['getToolProvider'],
71
- },
72
38
  [ToolName.CODE_EXEC]: {
73
39
  descriptionFile: 'code_exec',
74
40
  factory({ environmentContext, fileSystemService, sandboxService }) {
@@ -96,13 +62,6 @@ export const TOOL_REGISTRY = {
96
62
  markers: [ToolMarker.Execution],
97
63
  requiredServices: ['sandboxService', 'fileSystemService'],
98
64
  },
99
- [ToolName.CREATE_KNOWLEDGE_TOPIC]: {
100
- descriptionFile: 'create_knowledge_topic',
101
- factory: () => createCreateKnowledgeTopicTool(),
102
- markers: [ToolMarker.ContextBuilding],
103
- outputGuidance: 'create_knowledge_topic',
104
- requiredServices: [], // Uses DirectoryManager for file operations
105
- },
106
65
  [ToolName.CURATE]: {
107
66
  descriptionFile: 'curate',
108
67
  factory: () => createCurateTool(),
@@ -110,26 +69,6 @@ export const TOOL_REGISTRY = {
110
69
  outputGuidance: 'curate',
111
70
  requiredServices: [], // Uses DirectoryManager and MarkdownWriter for file operations
112
71
  },
113
- [ToolName.DELETE_MEMORY]: {
114
- descriptionFile: 'delete_memory',
115
- factory: (services) => createDeleteMemoryTool(getRequiredService(services.memoryManager, 'memoryManager')),
116
- markers: [ToolMarker.ContextBuilding],
117
- outputGuidance: 'delete_memory',
118
- requiredServices: ['memoryManager'],
119
- },
120
- [ToolName.EDIT_FILE]: {
121
- descriptionFile: 'edit_file',
122
- factory: (services) => createEditFileTool(getRequiredService(services.fileSystemService, 'fileSystemService')),
123
- markers: [ToolMarker.Modification],
124
- requiredServices: ['fileSystemService'],
125
- },
126
- [ToolName.EDIT_MEMORY]: {
127
- descriptionFile: 'edit_memory',
128
- factory: (services) => createEditMemoryTool(getRequiredService(services.memoryManager, 'memoryManager')),
129
- markers: [ToolMarker.ContextBuilding],
130
- outputGuidance: 'edit_memory',
131
- requiredServices: ['memoryManager'],
132
- },
133
72
  [ToolName.GLOB_FILES]: {
134
73
  descriptionFile: 'glob_files',
135
74
  factory: (services) => createGlobFilesTool(getRequiredService(services.fileSystemService, 'fileSystemService')),
@@ -142,80 +81,28 @@ export const TOOL_REGISTRY = {
142
81
  markers: [ToolMarker.Core, ToolMarker.Discovery],
143
82
  requiredServices: ['fileSystemService'],
144
83
  },
145
- [ToolName.KILL_PROCESS]: {
146
- descriptionFile: 'kill_process',
147
- factory: (services) => createKillProcessTool(getRequiredService(services.processService, 'processService')),
148
- markers: [ToolMarker.Execution, ToolMarker.Optional],
149
- requiredServices: ['processService'],
150
- },
151
84
  [ToolName.LIST_DIRECTORY]: {
152
85
  descriptionFile: 'list_directory',
153
86
  factory: (services) => createListDirectoryTool(getRequiredService(services.fileSystemService, 'fileSystemService')),
154
87
  markers: [ToolMarker.Discovery],
155
88
  requiredServices: ['fileSystemService'],
156
89
  },
157
- [ToolName.LIST_MEMORIES]: {
158
- descriptionFile: 'list_memories',
159
- factory: (services) => createListMemoriesTool(getRequiredService(services.memoryManager, 'memoryManager')),
160
- markers: [ToolMarker.ContextBuilding, ToolMarker.Discovery],
161
- outputGuidance: 'list_memories',
162
- requiredServices: ['memoryManager'],
163
- },
164
90
  [ToolName.READ_FILE]: {
165
91
  descriptionFile: 'read_file',
166
92
  factory: (services) => createReadFileTool(getRequiredService(services.fileSystemService, 'fileSystemService')),
167
93
  markers: [ToolMarker.Core, ToolMarker.Discovery],
168
94
  requiredServices: ['fileSystemService'],
169
95
  },
170
- [ToolName.READ_MEMORY]: {
171
- descriptionFile: 'read_memory',
172
- factory: (services) => createReadMemoryTool(getRequiredService(services.memoryManager, 'memoryManager')),
173
- markers: [ToolMarker.ContextBuilding, ToolMarker.Discovery],
174
- outputGuidance: 'read_memory',
175
- requiredServices: ['memoryManager'],
176
- },
177
- [ToolName.READ_TODOS]: {
178
- descriptionFile: 'read_todos',
179
- factory: (services) => createReadTodosTool(getRequiredService(services.todoStorage, 'todoStorage')),
180
- markers: [ToolMarker.Planning, ToolMarker.Core],
181
- requiredServices: ['todoStorage'],
182
- },
183
- [ToolName.SEARCH_HISTORY]: {
184
- descriptionFile: 'search_history',
185
- factory: (_services) => createSearchHistoryTool(),
186
- markers: [ToolMarker.ContextBuilding, ToolMarker.Discovery],
187
- requiredServices: [], // No services required yet (stub implementation)
188
- },
189
96
  [ToolName.SEARCH_KNOWLEDGE]: {
190
97
  descriptionFile: 'search_knowledge',
191
98
  factory: (services) => createSearchKnowledgeTool(getRequiredService(services.fileSystemService, 'fileSystemService')),
192
99
  markers: [ToolMarker.ContextBuilding, ToolMarker.Discovery],
193
100
  requiredServices: ['fileSystemService'],
194
101
  },
195
- [ToolName.SPEC_ANALYZE]: {
196
- descriptionFile: 'spec_analyze',
197
- factory: () => createSpecAnalyzeTool(),
198
- markers: [ToolMarker.ContextBuilding],
199
- outputGuidance: 'spec_analyze',
200
- requiredServices: [], // No services required (validates LLM-detected domains)
201
- },
202
102
  [ToolName.WRITE_FILE]: {
203
103
  descriptionFile: 'write_file',
204
104
  factory: (services) => createWriteFileTool(getRequiredService(services.fileSystemService, 'fileSystemService')),
205
105
  markers: [ToolMarker.Modification],
206
106
  requiredServices: ['fileSystemService'],
207
107
  },
208
- [ToolName.WRITE_MEMORY]: {
209
- descriptionFile: 'write_memory',
210
- factory: (services) => createWriteMemoryTool(getRequiredService(services.memoryManager, 'memoryManager')),
211
- markers: [ToolMarker.ContextBuilding],
212
- outputGuidance: 'write_memory',
213
- requiredServices: ['memoryManager'],
214
- },
215
- [ToolName.WRITE_TODOS]: {
216
- descriptionFile: 'write_todos',
217
- factory: (services) => createWriteTodosTool(getRequiredService(services.todoStorage, 'todoStorage')),
218
- markers: [ToolMarker.Planning, ToolMarker.Core],
219
- requiredServices: ['todoStorage'],
220
- },
221
108
  };
@@ -0,0 +1,73 @@
1
+ description: "Detail preservation instructions for curate mode"
2
+ prompt: |
3
+ <CURATE_DETAIL_PRESERVATION>
4
+ ## Diagram and Visual Content Preservation
5
+
6
+ When curating content from files or folders, actively look for and preserve:
7
+
8
+ **Diagrams (MUST PRESERVE in narrative.diagrams array):**
9
+ - Mermaid diagrams (```mermaid ... ```) - store with type: "mermaid"
10
+ - PlantUML diagrams (@startuml ... @enduml) - store with type: "plantuml"
11
+ - ASCII art diagrams (box drawings, flow charts using |, -, +, >, arrows) - store with type: "ascii"
12
+ - Sequence diagrams, state diagrams, class diagrams, ER diagrams - identify the format and store accordingly
13
+ - ALWAYS preserve diagram content EXACTLY as-is, character for character
14
+ - NEVER paraphrase or describe a diagram in text instead of storing it
15
+ - NEVER skip a diagram because "it's too complex" - store it verbatim
16
+
17
+ **Tables (MUST PRESERVE):**
18
+ - Markdown tables - preserve the full table in narrative.structure or narrative.features
19
+ - Include column headers and ALL rows - do not summarize table content
20
+ - If a table has 20 rows, store all 20 rows
21
+
22
+ **Step-by-step Procedures:**
23
+ - Numbered instructions - store in narrative.rules with original numbering
24
+ - Decision trees - store as diagrams (ascii type) or in narrative.structure
25
+ - Workflows - capture in rawConcept.flow AND as diagrams if visual representation exists
26
+
27
+ **API Signatures and Interfaces:**
28
+ - Function signatures with parameter types - store in narrative.structure
29
+ - Interface definitions - preserve exact TypeScript/language syntax in snippets
30
+ - Request/response schemas - store complete schema, not summaries
31
+
32
+ **Code Examples:**
33
+ - Inline code examples from documentation - store in narrative.examples with full code
34
+ - Configuration examples - preserve exact syntax and values
35
+ - Command-line examples - store complete commands with flags
36
+
37
+ **Detection Heuristics:**
38
+ - Lines containing box-drawing characters (U+2500-U+257F, or ASCII +--+, | |) = ASCII diagram
39
+ - Fenced blocks with language tag "mermaid", "plantuml", "dot", "graphviz" = diagram
40
+ - Content between @startuml/@enduml = PlantUML diagram
41
+ - Arrow patterns (-->, ==>, ->, =>), combined with indentation = flow/sequence diagram
42
+
43
+ **Storage Rules for Diagrams:**
44
+ - One diagram per entry in the narrative.diagrams array
45
+ - Always set the `type` field correctly (mermaid, plantuml, ascii, other)
46
+ - Use `title` field when the diagram has a caption or label nearby
47
+ - Example:
48
+ ```javascript
49
+ narrative: {
50
+ diagrams: [
51
+ {
52
+ type: "mermaid",
53
+ title: "Authentication Flow",
54
+ content: "graph TD\n A[Request] --> B{Has Token?}\n B -->|Yes| C[Validate]\n B -->|No| D[Reject]"
55
+ }
56
+ ]
57
+ }
58
+ ```
59
+
60
+ ## General Detail Preservation
61
+
62
+ **Completeness over conciseness:**
63
+ - If a document lists 15 items, store all 15
64
+ - If a config file has 30 settings, capture all relevant ones
65
+ - If there are multiple code examples, store each one
66
+ - Preserve original formatting, indentation, and structure where possible
67
+
68
+ **Do NOT:**
69
+ - Summarize detailed content into brief descriptions
70
+ - Pick "representative examples" instead of storing all items
71
+ - Omit sections because they seem "less important"
72
+ - Flatten hierarchical content into flat descriptions
73
+ </CURATE_DETAIL_PRESERVATION>
@@ -345,16 +345,33 @@ prompt: |
345
345
  When using the `curate` tool, use this structured format:
346
346
 
347
347
  **rawConcept** - Essential metadata and technical footprint:
348
+ - IMPORTANT: Before proceeding, analyze the input content for any file path references (e.g., "implemented in auth.ts", "see config.json", "refer to src/utils/helper.h")
349
+ - **Language-Specific File Path Handling**:
350
+ - **TypeScript/TSX ESM**: Import statements use `.js/.jsx` but source files are `.ts/.tsx`
351
+ - Example: `import {foo} from './bar.js'` → actual file is `bar.ts`
352
+ - ALWAYS use actual source extension (.ts, .tsx, .d.ts) NOT import extension (.js, .jsx)
353
+ - When in doubt, verify the .ts/.tsx file exists before assuming .js
354
+ - **Other Languages** (Python, Java, Go, Rust, C/C++, PHP, Ruby, etc.):
355
+ - Use the actual file paths as they appear in the filesystem
356
+ - For languages where imports match file paths (C/C++, PHP, JS), use the import path directly
357
+ - For languages with module systems (Python, Java, Go, Rust), extract the referenced module file
348
358
  - `task`: What is being documented (required - always include this)
349
359
  - `changes`: Array of changes in the codebase (e.g., ["Added Redis caching", "Created singleton client"])
350
- - `files`: Array of related files (e.g., ["services/auth.ts", "utils/cache.ts"])
360
+ - `files`: Array of actual source file paths (e.g., ["services/auth.ts", "utils/cache.ts", "include/helper.h"])
361
+ - Use the file extension that exists in the filesystem
362
+ - TypeScript ESM: Use .ts/.tsx even when imports show .js/.jsx
363
+ - All other languages: Use the actual file extension (preserve .h, .cpp, .py, .java, .go, .rs, .php, .rb, etc.)
351
364
  - `flow`: The execution flow (e.g., "request -> validate -> cache check -> process -> respond")
352
365
  - `timestamp`: When created (ISO 8601 format, e.g., "2025-03-18")
366
+ - `author`: Author or source attribution (e.g., "meowso", "Security Team") - optional
367
+ - `patterns`: Array of regex/validation patterns with {pattern, description, flags} - optional
353
368
 
354
369
  **narrative** - Descriptive and structural context:
355
370
  - `structure`: Code structure documentation (describe file organization, class hierarchy, etc.)
356
371
  - `dependencies`: Dependency management information (external libs, internal dependencies, initialization order)
357
372
  - `features`: Feature documentation (behavior, limitations, edge cases, caching TTLs, etc.)
373
+ - `rules`: Exact rules, constraints, or guidelines - preserved verbatim from source - optional
374
+ - `examples`: Concrete examples and use cases - optional
358
375
 
359
376
  **relations** - Optional cross-references to related topics:
360
377
  - Array of related topic paths (e.g., ["@structure/redis/overview.md", "@design/security/token-validation.md"])
@@ -381,12 +398,18 @@ prompt: |
381
398
  'src/utils/jwt.ts'
382
399
  ],
383
400
  flow: 'request -> extract token -> verify JWT -> check blacklist -> attach user -> proceed',
384
- timestamp: '2025-01-02'
401
+ timestamp: '2025-01-02',
402
+ author: 'Security Team',
403
+ patterns: [
404
+ { pattern: '^Bearer\\s+[A-Za-z0-9-._~+/]+=*$', description: 'Validates Bearer token format in Authorization header' }
405
+ ]
385
406
  },
386
407
  narrative: {
387
408
  structure: 'Authentication is handled by middleware in src/middleware/auth.ts which delegates to TokenService for JWT operations',
388
409
  dependencies: 'Uses jsonwebtoken library for JWT operations, Redis for token blacklist with 24h TTL',
389
- features: 'Access tokens expire in 15 minutes, refresh tokens in 7 days. Refresh token rotation invalidates old tokens immediately'
410
+ features: 'Access tokens expire in 15 minutes, refresh tokens in 7 days. Refresh token rotation invalidates old tokens immediately',
411
+ rules: 'Rule 1: Access tokens must be verified before use\nRule 2: Expired tokens return 401\nRule 3: Refresh tokens can only be used once',
412
+ examples: 'Example Authorization header: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
390
413
  },
391
414
  relations: ['@structure/redis/overview.md', '@design/security/token-validation.md']
392
415
  },
@@ -416,6 +439,49 @@ prompt: |
416
439
  - "The hook system allows registering callbacks for lifecycle events. Register hooks using `HookRegistry.register(hookName, callback)` and trigger them with `HookRegistry.trigger(hookName, context)`. Hooks support async callbacks and are commonly used for: pre/post tool execution, agent lifecycle events, and custom integrations."
417
440
  - "Error handling follows a custom error class pattern. All custom errors extend `BaseError` and include: error code, message, context object, and optional cause. Use `ErrorHandler.wrap(fn)` for consistent error boundaries across async operations."
418
441
 
442
+ ### Content Preservation Rules
443
+
444
+ When curating content that contains rules, patterns, or exact specifications, **PRESERVE DETAILS** instead of summarizing:
445
+
446
+ **PRESERVE VERBATIM:**
447
+ - Exact rule text and constraint language - DO NOT paraphrase
448
+ - Regex patterns and validation patterns - include as-is in `patterns` array
449
+ - Author/source attribution - capture in `author` field
450
+ - All enumerated items in lists - DO NOT omit any items
451
+ - Exact configuration values and technical specifications
452
+ - Metadata like version numbers, dates, identifiers
453
+
454
+ **Use appropriate fields:**
455
+ - `rawConcept.patterns` - for regex, validation patterns, matching rules with exact pattern strings
456
+ - `narrative.rules` - for exact rule text, constraints, guidelines (preserve verbatim, do not summarize)
457
+ - `narrative.examples` - for concrete examples and use cases with specific details
458
+ - `rawConcept.author` - for attribution and source info
459
+ - `snippets` - for code blocks and larger text excerpts
460
+
461
+ **When curating rules/guidelines:**
462
+ - Include the EXACT rule text in `narrative.rules`, not a summary
463
+ - Capture ALL rules, not a representative subset
464
+ - Preserve the original numbering/ordering if present
465
+ - Keep qualifiers and specific conditions (e.g., "other than what's explicitly requested")
466
+
467
+ **When curating patterns:**
468
+ - Store in `rawConcept.patterns` array with exact pattern string + description
469
+ - Include regex flags if specified (e.g., "i", "gi")
470
+ - Do not simplify or modify the pattern
471
+ - Include ALL patterns, not just examples
472
+
473
+ **Examples of GOOD preservation:**
474
+ - Original: "Rule 3: Never use apologies" → Store exactly: "Rule 3: Never use apologies" in narrative.rules
475
+ - Original: Has 16 regex patterns → Store all 16 in rawConcept.patterns array
476
+ - Original: "Author: meowso" → Capture: author: "meowso"
477
+ - Original: "Make changes file by file and give me a chance to spot mistakes" → Store complete text, not "Enforced file-by-file changes"
478
+
479
+ **Examples of BAD summarization (AVOID):**
480
+ - Original: "Rule 3: Never use apologies" → "Prohibited apologies" ❌
481
+ - Original: 16 patterns → Store only 3-5 examples ❌
482
+ - Original: Detailed rule with qualifier → Shortened version without qualifier ❌
483
+ - Original: 8 use cases → Store only 2 ❌
484
+
419
485
  ### Domain/Topic/Subtopic Context
420
486
 
421
487
  When creating NEW domains, topics, or subtopics, provide the appropriate context:
@@ -1,13 +1,26 @@
1
1
  export interface RawConcept {
2
+ author?: string;
2
3
  changes?: string[];
3
4
  files?: string[];
4
5
  flow?: string;
6
+ patterns?: Array<{
7
+ description: string;
8
+ flags?: string;
9
+ pattern: string;
10
+ }>;
5
11
  task?: string;
6
12
  timestamp?: string;
7
13
  }
8
14
  export interface Narrative {
9
15
  dependencies?: string;
16
+ diagrams?: Array<{
17
+ content: string;
18
+ title?: string;
19
+ type: string;
20
+ }>;
21
+ examples?: string;
10
22
  features?: string;
23
+ rules?: string;
11
24
  structure?: string;
12
25
  }
13
26
  export interface ContextData {