@compilr-dev/agents 0.0.1

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 (160) hide show
  1. package/README.md +1277 -0
  2. package/dist/agent.d.ts +1272 -0
  3. package/dist/agent.js +1912 -0
  4. package/dist/anchors/builtin.d.ts +24 -0
  5. package/dist/anchors/builtin.js +61 -0
  6. package/dist/anchors/index.d.ts +6 -0
  7. package/dist/anchors/index.js +5 -0
  8. package/dist/anchors/manager.d.ts +115 -0
  9. package/dist/anchors/manager.js +412 -0
  10. package/dist/anchors/types.d.ts +168 -0
  11. package/dist/anchors/types.js +10 -0
  12. package/dist/context/index.d.ts +12 -0
  13. package/dist/context/index.js +10 -0
  14. package/dist/context/manager.d.ts +224 -0
  15. package/dist/context/manager.js +770 -0
  16. package/dist/context/types.d.ts +377 -0
  17. package/dist/context/types.js +7 -0
  18. package/dist/costs/index.d.ts +8 -0
  19. package/dist/costs/index.js +7 -0
  20. package/dist/costs/tracker.d.ts +121 -0
  21. package/dist/costs/tracker.js +295 -0
  22. package/dist/costs/types.d.ts +157 -0
  23. package/dist/costs/types.js +8 -0
  24. package/dist/errors.d.ts +178 -0
  25. package/dist/errors.js +249 -0
  26. package/dist/guardrails/builtin.d.ts +27 -0
  27. package/dist/guardrails/builtin.js +223 -0
  28. package/dist/guardrails/index.d.ts +6 -0
  29. package/dist/guardrails/index.js +5 -0
  30. package/dist/guardrails/manager.d.ts +117 -0
  31. package/dist/guardrails/manager.js +288 -0
  32. package/dist/guardrails/types.d.ts +159 -0
  33. package/dist/guardrails/types.js +7 -0
  34. package/dist/hooks/index.d.ts +31 -0
  35. package/dist/hooks/index.js +29 -0
  36. package/dist/hooks/manager.d.ts +147 -0
  37. package/dist/hooks/manager.js +600 -0
  38. package/dist/hooks/types.d.ts +368 -0
  39. package/dist/hooks/types.js +12 -0
  40. package/dist/index.d.ts +45 -0
  41. package/dist/index.js +73 -0
  42. package/dist/mcp/client.d.ts +93 -0
  43. package/dist/mcp/client.js +287 -0
  44. package/dist/mcp/errors.d.ts +60 -0
  45. package/dist/mcp/errors.js +78 -0
  46. package/dist/mcp/index.d.ts +43 -0
  47. package/dist/mcp/index.js +45 -0
  48. package/dist/mcp/manager.d.ts +120 -0
  49. package/dist/mcp/manager.js +276 -0
  50. package/dist/mcp/tools.d.ts +54 -0
  51. package/dist/mcp/tools.js +99 -0
  52. package/dist/mcp/types.d.ts +150 -0
  53. package/dist/mcp/types.js +40 -0
  54. package/dist/memory/index.d.ts +8 -0
  55. package/dist/memory/index.js +7 -0
  56. package/dist/memory/loader.d.ts +114 -0
  57. package/dist/memory/loader.js +463 -0
  58. package/dist/memory/types.d.ts +182 -0
  59. package/dist/memory/types.js +8 -0
  60. package/dist/messages/index.d.ts +82 -0
  61. package/dist/messages/index.js +155 -0
  62. package/dist/permissions/index.d.ts +5 -0
  63. package/dist/permissions/index.js +4 -0
  64. package/dist/permissions/manager.d.ts +125 -0
  65. package/dist/permissions/manager.js +379 -0
  66. package/dist/permissions/types.d.ts +162 -0
  67. package/dist/permissions/types.js +7 -0
  68. package/dist/providers/claude.d.ts +90 -0
  69. package/dist/providers/claude.js +348 -0
  70. package/dist/providers/index.d.ts +8 -0
  71. package/dist/providers/index.js +11 -0
  72. package/dist/providers/mock.d.ts +133 -0
  73. package/dist/providers/mock.js +204 -0
  74. package/dist/providers/types.d.ts +168 -0
  75. package/dist/providers/types.js +4 -0
  76. package/dist/rate-limit/index.d.ts +45 -0
  77. package/dist/rate-limit/index.js +47 -0
  78. package/dist/rate-limit/limiter.d.ts +104 -0
  79. package/dist/rate-limit/limiter.js +326 -0
  80. package/dist/rate-limit/provider-wrapper.d.ts +112 -0
  81. package/dist/rate-limit/provider-wrapper.js +201 -0
  82. package/dist/rate-limit/retry.d.ts +108 -0
  83. package/dist/rate-limit/retry.js +287 -0
  84. package/dist/rate-limit/types.d.ts +181 -0
  85. package/dist/rate-limit/types.js +22 -0
  86. package/dist/rehearsal/file-analyzer.d.ts +22 -0
  87. package/dist/rehearsal/file-analyzer.js +351 -0
  88. package/dist/rehearsal/git-analyzer.d.ts +22 -0
  89. package/dist/rehearsal/git-analyzer.js +472 -0
  90. package/dist/rehearsal/index.d.ts +35 -0
  91. package/dist/rehearsal/index.js +36 -0
  92. package/dist/rehearsal/manager.d.ts +100 -0
  93. package/dist/rehearsal/manager.js +290 -0
  94. package/dist/rehearsal/types.d.ts +235 -0
  95. package/dist/rehearsal/types.js +8 -0
  96. package/dist/skills/index.d.ts +160 -0
  97. package/dist/skills/index.js +282 -0
  98. package/dist/state/agent-state.d.ts +41 -0
  99. package/dist/state/agent-state.js +88 -0
  100. package/dist/state/checkpointer.d.ts +110 -0
  101. package/dist/state/checkpointer.js +362 -0
  102. package/dist/state/errors.d.ts +66 -0
  103. package/dist/state/errors.js +88 -0
  104. package/dist/state/index.d.ts +35 -0
  105. package/dist/state/index.js +37 -0
  106. package/dist/state/serializer.d.ts +55 -0
  107. package/dist/state/serializer.js +172 -0
  108. package/dist/state/types.d.ts +312 -0
  109. package/dist/state/types.js +14 -0
  110. package/dist/tools/builtin/bash-output.d.ts +61 -0
  111. package/dist/tools/builtin/bash-output.js +90 -0
  112. package/dist/tools/builtin/bash.d.ts +150 -0
  113. package/dist/tools/builtin/bash.js +354 -0
  114. package/dist/tools/builtin/edit.d.ts +50 -0
  115. package/dist/tools/builtin/edit.js +215 -0
  116. package/dist/tools/builtin/glob.d.ts +62 -0
  117. package/dist/tools/builtin/glob.js +244 -0
  118. package/dist/tools/builtin/grep.d.ts +74 -0
  119. package/dist/tools/builtin/grep.js +363 -0
  120. package/dist/tools/builtin/index.d.ts +44 -0
  121. package/dist/tools/builtin/index.js +69 -0
  122. package/dist/tools/builtin/kill-shell.d.ts +44 -0
  123. package/dist/tools/builtin/kill-shell.js +80 -0
  124. package/dist/tools/builtin/read-file.d.ts +57 -0
  125. package/dist/tools/builtin/read-file.js +184 -0
  126. package/dist/tools/builtin/shell-manager.d.ts +176 -0
  127. package/dist/tools/builtin/shell-manager.js +337 -0
  128. package/dist/tools/builtin/task.d.ts +202 -0
  129. package/dist/tools/builtin/task.js +350 -0
  130. package/dist/tools/builtin/todo.d.ts +207 -0
  131. package/dist/tools/builtin/todo.js +453 -0
  132. package/dist/tools/builtin/utils.d.ts +27 -0
  133. package/dist/tools/builtin/utils.js +70 -0
  134. package/dist/tools/builtin/web-fetch.d.ts +96 -0
  135. package/dist/tools/builtin/web-fetch.js +290 -0
  136. package/dist/tools/builtin/write-file.d.ts +54 -0
  137. package/dist/tools/builtin/write-file.js +147 -0
  138. package/dist/tools/define.d.ts +60 -0
  139. package/dist/tools/define.js +65 -0
  140. package/dist/tools/index.d.ts +10 -0
  141. package/dist/tools/index.js +37 -0
  142. package/dist/tools/registry.d.ts +79 -0
  143. package/dist/tools/registry.js +151 -0
  144. package/dist/tools/types.d.ts +59 -0
  145. package/dist/tools/types.js +4 -0
  146. package/dist/tracing/hooks.d.ts +58 -0
  147. package/dist/tracing/hooks.js +377 -0
  148. package/dist/tracing/index.d.ts +51 -0
  149. package/dist/tracing/index.js +55 -0
  150. package/dist/tracing/logging.d.ts +78 -0
  151. package/dist/tracing/logging.js +310 -0
  152. package/dist/tracing/manager.d.ts +160 -0
  153. package/dist/tracing/manager.js +468 -0
  154. package/dist/tracing/otel.d.ts +102 -0
  155. package/dist/tracing/otel.js +246 -0
  156. package/dist/tracing/types.d.ts +346 -0
  157. package/dist/tracing/types.js +38 -0
  158. package/dist/utils/index.d.ts +23 -0
  159. package/dist/utils/index.js +44 -0
  160. package/package.json +79 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * ProjectMemoryLoader - Loads project-level instructions from markdown files
3
+ *
4
+ * Supports various LLM-specific naming conventions:
5
+ * - CLAUDE.md, .claude.md, .claude/instructions.md (Claude/Anthropic)
6
+ * - GEMINI.md, .gemini.md, .gemini/instructions.md (Google Gemini)
7
+ * - COPILOT.md, .github/copilot-instructions.md (GitHub Copilot)
8
+ * - GPT.md, OPENAI.md (OpenAI)
9
+ * - CURSOR.md, .cursor/rules (Cursor)
10
+ * - CODEIUM.md (Codeium)
11
+ *
12
+ * Also supports generic names:
13
+ * - PROJECT.md, INSTRUCTIONS.md, AI.md, CONTEXT.md
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const loader = new ProjectMemoryLoader({
18
+ * providers: ['claude', 'gemini'],
19
+ * includeGeneric: true,
20
+ * });
21
+ *
22
+ * const memory = await loader.load('/path/to/project');
23
+ * console.log(memory.content); // Combined instructions
24
+ * ```
25
+ */
26
+ import type { LLMProviderName, ProjectMemory, FilePattern, ProjectMemoryOptions, ProjectMemoryEventHandler, MemoryDiscoveryResult, ProviderPatterns } from './types.js';
27
+ /**
28
+ * Built-in patterns for various LLM providers
29
+ */
30
+ declare const PROVIDER_PATTERNS: ProviderPatterns[];
31
+ /**
32
+ * Generic patterns that apply to any LLM
33
+ */
34
+ declare const GENERIC_PATTERNS: FilePattern[];
35
+ /**
36
+ * ProjectMemoryLoader discovers and loads project-specific instructions
37
+ */
38
+ export declare class ProjectMemoryLoader {
39
+ private readonly options;
40
+ private readonly patterns;
41
+ private readonly eventHandlers;
42
+ constructor(options?: ProjectMemoryOptions);
43
+ /**
44
+ * Build the list of patterns to search for
45
+ */
46
+ private buildPatterns;
47
+ /**
48
+ * Load project memory from a directory
49
+ *
50
+ * @param rootDir - Starting directory for search
51
+ * @returns Loaded project memory
52
+ */
53
+ load(rootDir: string): Promise<ProjectMemory>;
54
+ /**
55
+ * Discover memory files without loading content
56
+ *
57
+ * @param rootDir - Starting directory for search
58
+ * @returns Discovery result with paths
59
+ */
60
+ discover(rootDir: string): Promise<MemoryDiscoveryResult>;
61
+ /**
62
+ * Get the list of directories to search
63
+ */
64
+ private getSearchDirectories;
65
+ /**
66
+ * Combine content from multiple files
67
+ */
68
+ private combineContent;
69
+ /**
70
+ * Format the header for a file
71
+ */
72
+ private formatHeader;
73
+ /**
74
+ * Register an event handler
75
+ */
76
+ onEvent(handler: ProjectMemoryEventHandler): () => void;
77
+ /**
78
+ * Emit an event
79
+ */
80
+ private emit;
81
+ /**
82
+ * Get the patterns being used
83
+ */
84
+ getPatterns(): FilePattern[];
85
+ /**
86
+ * Get the configured options
87
+ */
88
+ getOptions(): Required<ProjectMemoryOptions>;
89
+ }
90
+ /**
91
+ * Create a ProjectMemoryLoader with default options
92
+ */
93
+ export declare function createProjectMemoryLoader(options?: ProjectMemoryOptions): ProjectMemoryLoader;
94
+ /**
95
+ * Quick utility to load project memory
96
+ */
97
+ export declare function loadProjectMemory(rootDir: string, options?: ProjectMemoryOptions): Promise<ProjectMemory>;
98
+ /**
99
+ * Quick utility to check if a directory has project memory files
100
+ */
101
+ export declare function hasProjectMemory(rootDir: string, options?: ProjectMemoryOptions): Promise<boolean>;
102
+ /**
103
+ * Get built-in patterns for a provider
104
+ */
105
+ export declare function getProviderPatterns(provider: LLMProviderName): FilePattern[];
106
+ /**
107
+ * Get all supported provider names
108
+ */
109
+ export declare function getSupportedProviders(): LLMProviderName[];
110
+ /**
111
+ * Get generic patterns
112
+ */
113
+ export declare function getGenericPatterns(): FilePattern[];
114
+ export { PROVIDER_PATTERNS, GENERIC_PATTERNS };
@@ -0,0 +1,463 @@
1
+ /**
2
+ * ProjectMemoryLoader - Loads project-level instructions from markdown files
3
+ *
4
+ * Supports various LLM-specific naming conventions:
5
+ * - CLAUDE.md, .claude.md, .claude/instructions.md (Claude/Anthropic)
6
+ * - GEMINI.md, .gemini.md, .gemini/instructions.md (Google Gemini)
7
+ * - COPILOT.md, .github/copilot-instructions.md (GitHub Copilot)
8
+ * - GPT.md, OPENAI.md (OpenAI)
9
+ * - CURSOR.md, .cursor/rules (Cursor)
10
+ * - CODEIUM.md (Codeium)
11
+ *
12
+ * Also supports generic names:
13
+ * - PROJECT.md, INSTRUCTIONS.md, AI.md, CONTEXT.md
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const loader = new ProjectMemoryLoader({
18
+ * providers: ['claude', 'gemini'],
19
+ * includeGeneric: true,
20
+ * });
21
+ *
22
+ * const memory = await loader.load('/path/to/project');
23
+ * console.log(memory.content); // Combined instructions
24
+ * ```
25
+ */
26
+ import * as fs from 'fs/promises';
27
+ import * as path from 'path';
28
+ /**
29
+ * Built-in patterns for various LLM providers
30
+ */
31
+ const PROVIDER_PATTERNS = [
32
+ {
33
+ provider: 'claude',
34
+ patterns: [
35
+ { pattern: 'CLAUDE.md', priority: 1, description: 'Claude project instructions' },
36
+ { pattern: '.claude.md', priority: 2, description: 'Hidden Claude instructions' },
37
+ {
38
+ pattern: '.claude/instructions.md',
39
+ priority: 3,
40
+ description: 'Claude directory instructions',
41
+ },
42
+ { pattern: '.claude/CLAUDE.md', priority: 4, description: 'Claude directory main file' },
43
+ ],
44
+ },
45
+ {
46
+ provider: 'anthropic',
47
+ patterns: [
48
+ { pattern: 'ANTHROPIC.md', priority: 1, description: 'Anthropic project instructions' },
49
+ { pattern: '.anthropic.md', priority: 2, description: 'Hidden Anthropic instructions' },
50
+ {
51
+ pattern: '.anthropic/instructions.md',
52
+ priority: 3,
53
+ description: 'Anthropic directory instructions',
54
+ },
55
+ ],
56
+ },
57
+ {
58
+ provider: 'gemini',
59
+ patterns: [
60
+ { pattern: 'GEMINI.md', priority: 1, description: 'Gemini project instructions' },
61
+ { pattern: '.gemini.md', priority: 2, description: 'Hidden Gemini instructions' },
62
+ {
63
+ pattern: '.gemini/instructions.md',
64
+ priority: 3,
65
+ description: 'Gemini directory instructions',
66
+ },
67
+ ],
68
+ },
69
+ {
70
+ provider: 'openai',
71
+ patterns: [
72
+ { pattern: 'OPENAI.md', priority: 1, description: 'OpenAI project instructions' },
73
+ { pattern: '.openai.md', priority: 2, description: 'Hidden OpenAI instructions' },
74
+ {
75
+ pattern: '.openai/instructions.md',
76
+ priority: 3,
77
+ description: 'OpenAI directory instructions',
78
+ },
79
+ ],
80
+ },
81
+ {
82
+ provider: 'gpt',
83
+ patterns: [
84
+ { pattern: 'GPT.md', priority: 1, description: 'GPT project instructions' },
85
+ { pattern: '.gpt.md', priority: 2, description: 'Hidden GPT instructions' },
86
+ { pattern: 'CHATGPT.md', priority: 3, description: 'ChatGPT instructions' },
87
+ ],
88
+ },
89
+ {
90
+ provider: 'copilot',
91
+ patterns: [
92
+ { pattern: 'COPILOT.md', priority: 1, description: 'Copilot project instructions' },
93
+ { pattern: '.copilot.md', priority: 2, description: 'Hidden Copilot instructions' },
94
+ {
95
+ pattern: '.github/copilot-instructions.md',
96
+ priority: 3,
97
+ description: 'GitHub Copilot instructions',
98
+ },
99
+ ],
100
+ },
101
+ {
102
+ provider: 'cursor',
103
+ patterns: [
104
+ { pattern: 'CURSOR.md', priority: 1, description: 'Cursor project instructions' },
105
+ { pattern: '.cursor.md', priority: 2, description: 'Hidden Cursor instructions' },
106
+ { pattern: '.cursor/rules', priority: 3, description: 'Cursor rules file' },
107
+ { pattern: '.cursorrules', priority: 4, description: 'Cursor rules (alt location)' },
108
+ ],
109
+ },
110
+ {
111
+ provider: 'codeium',
112
+ patterns: [
113
+ { pattern: 'CODEIUM.md', priority: 1, description: 'Codeium project instructions' },
114
+ { pattern: '.codeium.md', priority: 2, description: 'Hidden Codeium instructions' },
115
+ {
116
+ pattern: '.codeium/instructions.md',
117
+ priority: 3,
118
+ description: 'Codeium directory instructions',
119
+ },
120
+ ],
121
+ },
122
+ ];
123
+ /**
124
+ * Generic patterns that apply to any LLM
125
+ */
126
+ const GENERIC_PATTERNS = [
127
+ { pattern: 'PROJECT.md', priority: 10, description: 'Generic project instructions' },
128
+ { pattern: 'INSTRUCTIONS.md', priority: 11, description: 'Generic instructions' },
129
+ { pattern: 'AI.md', priority: 12, description: 'AI-specific instructions' },
130
+ { pattern: 'CONTEXT.md', priority: 13, description: 'Project context' },
131
+ { pattern: '.ai/instructions.md', priority: 14, description: 'AI directory instructions' },
132
+ { pattern: '.instructions.md', priority: 15, description: 'Hidden instructions' },
133
+ ];
134
+ /**
135
+ * Default options for ProjectMemoryLoader
136
+ */
137
+ const DEFAULT_OPTIONS = {
138
+ providers: 'claude',
139
+ includeGeneric: true,
140
+ customPatterns: [],
141
+ searchParents: true,
142
+ maxParentDepth: 10,
143
+ stopAtGitRoot: true,
144
+ combineStrategy: 'concat',
145
+ separator: '\n\n---\n\n',
146
+ maxContentSize: 100000,
147
+ includeHeaders: true,
148
+ headerFormat: '# From: {relativePath}\n\n',
149
+ encoding: 'utf-8',
150
+ };
151
+ /**
152
+ * ProjectMemoryLoader discovers and loads project-specific instructions
153
+ */
154
+ export class ProjectMemoryLoader {
155
+ options;
156
+ patterns;
157
+ eventHandlers = new Set();
158
+ constructor(options = {}) {
159
+ this.options = { ...DEFAULT_OPTIONS, ...options };
160
+ // Build pattern list
161
+ this.patterns = this.buildPatterns();
162
+ }
163
+ /**
164
+ * Build the list of patterns to search for
165
+ */
166
+ buildPatterns() {
167
+ const patterns = [];
168
+ // Add provider-specific patterns
169
+ const providers = Array.isArray(this.options.providers)
170
+ ? this.options.providers
171
+ : [this.options.providers];
172
+ for (const provider of providers) {
173
+ const providerPatterns = PROVIDER_PATTERNS.find((p) => p.provider.toLowerCase() === provider.toLowerCase());
174
+ if (providerPatterns) {
175
+ patterns.push(...providerPatterns.patterns);
176
+ }
177
+ else {
178
+ // Unknown provider - generate standard patterns
179
+ const name = provider.toUpperCase();
180
+ const lower = provider.toLowerCase();
181
+ patterns.push({ pattern: `${name}.md`, priority: 1, description: `${name} project instructions` }, { pattern: `.${lower}.md`, priority: 2, description: `Hidden ${name} instructions` }, {
182
+ pattern: `.${lower}/instructions.md`,
183
+ priority: 3,
184
+ description: `${name} directory instructions`,
185
+ });
186
+ }
187
+ }
188
+ // Add generic patterns if enabled
189
+ if (this.options.includeGeneric) {
190
+ patterns.push(...GENERIC_PATTERNS);
191
+ }
192
+ // Add custom patterns
193
+ if (this.options.customPatterns.length > 0) {
194
+ patterns.push(...this.options.customPatterns);
195
+ }
196
+ // Sort by priority
197
+ return patterns.sort((a, b) => a.priority - b.priority);
198
+ }
199
+ /**
200
+ * Load project memory from a directory
201
+ *
202
+ * @param rootDir - Starting directory for search
203
+ * @returns Loaded project memory
204
+ */
205
+ async load(rootDir) {
206
+ const absoluteRoot = path.resolve(rootDir);
207
+ this.emit({
208
+ type: 'memory:search_start',
209
+ rootDir: absoluteRoot,
210
+ patterns: this.patterns.map((p) => p.pattern),
211
+ });
212
+ const files = [];
213
+ let totalSize = 0;
214
+ // Get directories to search
215
+ const directories = await this.getSearchDirectories(absoluteRoot);
216
+ // Search each directory
217
+ for (const dir of directories) {
218
+ for (const pattern of this.patterns) {
219
+ // Check size limit
220
+ if (totalSize >= this.options.maxContentSize) {
221
+ break;
222
+ }
223
+ const filePath = path.join(dir, pattern.pattern);
224
+ try {
225
+ const stat = await fs.stat(filePath);
226
+ if (stat.isFile()) {
227
+ this.emit({ type: 'memory:file_found', path: filePath, pattern: pattern.pattern });
228
+ // Check if adding this file would exceed limit
229
+ if (totalSize + stat.size > this.options.maxContentSize) {
230
+ this.emit({
231
+ type: 'memory:file_skipped',
232
+ path: filePath,
233
+ reason: 'Would exceed max content size',
234
+ });
235
+ continue;
236
+ }
237
+ // Load file content
238
+ const content = await fs.readFile(filePath, this.options.encoding);
239
+ const memoryFile = {
240
+ path: filePath,
241
+ content,
242
+ relativePath: path.relative(absoluteRoot, filePath),
243
+ matchedPattern: pattern.pattern,
244
+ size: stat.size,
245
+ modifiedAt: stat.mtime,
246
+ };
247
+ files.push(memoryFile);
248
+ totalSize += stat.size;
249
+ this.emit({ type: 'memory:file_loaded', file: memoryFile });
250
+ // For 'priority' strategy, stop after first file
251
+ if (this.options.combineStrategy === 'priority') {
252
+ break;
253
+ }
254
+ }
255
+ }
256
+ catch {
257
+ // File doesn't exist, continue
258
+ }
259
+ }
260
+ // For 'priority' strategy, stop after first file found
261
+ if (this.options.combineStrategy === 'priority' && files.length > 0) {
262
+ break;
263
+ }
264
+ }
265
+ // Combine content
266
+ const content = this.combineContent(files, absoluteRoot);
267
+ const memory = {
268
+ files,
269
+ content,
270
+ rootDir: absoluteRoot,
271
+ estimatedTokens: Math.ceil(content.length / 4),
272
+ };
273
+ this.emit({ type: 'memory:search_complete', memory });
274
+ return memory;
275
+ }
276
+ /**
277
+ * Discover memory files without loading content
278
+ *
279
+ * @param rootDir - Starting directory for search
280
+ * @returns Discovery result with paths
281
+ */
282
+ async discover(rootDir) {
283
+ const absoluteRoot = path.resolve(rootDir);
284
+ const paths = [];
285
+ const matchedPatterns = [];
286
+ const directories = await this.getSearchDirectories(absoluteRoot);
287
+ for (const dir of directories) {
288
+ for (const pattern of this.patterns) {
289
+ const filePath = path.join(dir, pattern.pattern);
290
+ try {
291
+ const stat = await fs.stat(filePath);
292
+ if (stat.isFile()) {
293
+ paths.push(filePath);
294
+ if (!matchedPatterns.includes(pattern.pattern)) {
295
+ matchedPatterns.push(pattern.pattern);
296
+ }
297
+ }
298
+ }
299
+ catch {
300
+ // File doesn't exist
301
+ }
302
+ }
303
+ }
304
+ return {
305
+ paths,
306
+ found: paths.length > 0,
307
+ matchedPatterns,
308
+ };
309
+ }
310
+ /**
311
+ * Get the list of directories to search
312
+ */
313
+ async getSearchDirectories(rootDir) {
314
+ const directories = [rootDir];
315
+ if (!this.options.searchParents) {
316
+ return directories;
317
+ }
318
+ let currentDir = rootDir;
319
+ let depth = 0;
320
+ while (depth < this.options.maxParentDepth) {
321
+ const parentDir = path.dirname(currentDir);
322
+ // Stop if we've reached the filesystem root
323
+ if (parentDir === currentDir) {
324
+ break;
325
+ }
326
+ // Check for git root if configured
327
+ if (this.options.stopAtGitRoot) {
328
+ try {
329
+ await fs.access(path.join(currentDir, '.git'));
330
+ // Found git root, don't search beyond
331
+ break;
332
+ }
333
+ catch {
334
+ // Not a git root, continue
335
+ }
336
+ }
337
+ directories.push(parentDir);
338
+ currentDir = parentDir;
339
+ depth++;
340
+ }
341
+ return directories;
342
+ }
343
+ /**
344
+ * Combine content from multiple files
345
+ */
346
+ combineContent(files, rootDir) {
347
+ if (files.length === 0) {
348
+ return '';
349
+ }
350
+ if (this.options.combineStrategy === 'priority') {
351
+ // Just return first file's content
352
+ const file = files[0];
353
+ if (this.options.includeHeaders) {
354
+ const header = this.formatHeader(file, rootDir);
355
+ return header + file.content;
356
+ }
357
+ return file.content;
358
+ }
359
+ // For 'concat' and 'dedupe' strategies
360
+ const parts = [];
361
+ const seenContent = new Set();
362
+ for (const file of files) {
363
+ // Skip duplicates for 'dedupe' strategy
364
+ if (this.options.combineStrategy === 'dedupe') {
365
+ const normalized = file.content.trim();
366
+ if (seenContent.has(normalized)) {
367
+ continue;
368
+ }
369
+ seenContent.add(normalized);
370
+ }
371
+ if (this.options.includeHeaders) {
372
+ const header = this.formatHeader(file, rootDir);
373
+ parts.push(header + file.content);
374
+ }
375
+ else {
376
+ parts.push(file.content);
377
+ }
378
+ }
379
+ return parts.join(this.options.separator);
380
+ }
381
+ /**
382
+ * Format the header for a file
383
+ */
384
+ formatHeader(file, rootDir) {
385
+ return this.options.headerFormat
386
+ .replace('{path}', file.path)
387
+ .replace('{relativePath}', file.relativePath || path.relative(rootDir, file.path));
388
+ }
389
+ /**
390
+ * Register an event handler
391
+ */
392
+ onEvent(handler) {
393
+ this.eventHandlers.add(handler);
394
+ return () => this.eventHandlers.delete(handler);
395
+ }
396
+ /**
397
+ * Emit an event
398
+ */
399
+ emit(event) {
400
+ for (const handler of this.eventHandlers) {
401
+ try {
402
+ handler(event);
403
+ }
404
+ catch {
405
+ // Ignore handler errors
406
+ }
407
+ }
408
+ }
409
+ /**
410
+ * Get the patterns being used
411
+ */
412
+ getPatterns() {
413
+ return [...this.patterns];
414
+ }
415
+ /**
416
+ * Get the configured options
417
+ */
418
+ getOptions() {
419
+ return { ...this.options };
420
+ }
421
+ }
422
+ /**
423
+ * Create a ProjectMemoryLoader with default options
424
+ */
425
+ export function createProjectMemoryLoader(options) {
426
+ return new ProjectMemoryLoader(options);
427
+ }
428
+ /**
429
+ * Quick utility to load project memory
430
+ */
431
+ export async function loadProjectMemory(rootDir, options) {
432
+ const loader = new ProjectMemoryLoader(options);
433
+ return loader.load(rootDir);
434
+ }
435
+ /**
436
+ * Quick utility to check if a directory has project memory files
437
+ */
438
+ export async function hasProjectMemory(rootDir, options) {
439
+ const loader = new ProjectMemoryLoader(options);
440
+ const result = await loader.discover(rootDir);
441
+ return result.found;
442
+ }
443
+ /**
444
+ * Get built-in patterns for a provider
445
+ */
446
+ export function getProviderPatterns(provider) {
447
+ const found = PROVIDER_PATTERNS.find((p) => p.provider.toLowerCase() === provider.toLowerCase());
448
+ return found ? [...found.patterns] : [];
449
+ }
450
+ /**
451
+ * Get all supported provider names
452
+ */
453
+ export function getSupportedProviders() {
454
+ return PROVIDER_PATTERNS.map((p) => p.provider);
455
+ }
456
+ /**
457
+ * Get generic patterns
458
+ */
459
+ export function getGenericPatterns() {
460
+ return [...GENERIC_PATTERNS];
461
+ }
462
+ // Export built-in patterns for reference
463
+ export { PROVIDER_PATTERNS, GENERIC_PATTERNS };