prjct-cli 0.10.6 → 0.10.9

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.
@@ -10,17 +10,14 @@
10
10
  const fs = require('fs').promises;
11
11
  const path = require('path');
12
12
  const { glob } = require('glob');
13
+ const log = require('../utils/logger');
13
14
 
14
15
  class ContextFilter {
15
16
  constructor() {
16
- // Technology-specific file patterns
17
- this.techPatterns = this.initializeTechPatterns();
18
-
19
- // Task-based filtering rules
20
- this.taskPatterns = this.initializeTaskPatterns();
21
-
22
17
  // Cache for file analysis
23
18
  this.fileCache = new Map();
19
+ // NO HARDCODED PATTERNS - Everything is agentic
20
+ // Claude decides what files are needed based on analysis
24
21
  }
25
22
 
26
23
  /**
@@ -63,330 +60,121 @@ class ContextFilter {
63
60
  relevantPatterns
64
61
  );
65
62
 
66
- // Calculate reduction metrics
67
- const metrics = this.calculateMetrics(
68
- fullContext.fileCount || 1000, // estimate if not provided
69
- filteredFiles.length,
70
- startTime
71
- );
72
-
73
- return {
74
- files: filteredFiles,
75
- patterns: relevantPatterns,
76
- metrics,
77
- agent: agent.name,
78
- filtered: true
79
- };
80
- }
63
+ // Calculate reduction metrics
64
+ const metrics = this.calculateMetrics(
65
+ fullContext.fileCount || 1000, // estimate if not provided
66
+ filteredFiles.length,
67
+ startTime
68
+ );
81
69
 
82
- /**
83
- * Initialize technology-specific patterns
84
- */
85
- initializeTechPatterns() {
86
- return {
87
- // Languages
88
- javascript: {
89
- extensions: ['.js', '.mjs', '.cjs'],
90
- directories: ['src', 'lib', 'utils'],
91
- exclude: ['node_modules', 'dist', 'build']
92
- },
93
- typescript: {
94
- extensions: ['.ts', '.tsx', '.d.ts'],
95
- directories: ['src', 'lib', 'types'],
96
- exclude: ['node_modules', 'dist', 'build']
97
- },
98
- python: {
99
- extensions: ['.py', '.pyx'],
100
- directories: ['src', 'lib', 'app'],
101
- exclude: ['__pycache__', 'venv', '.env']
102
- },
103
- ruby: {
104
- extensions: ['.rb', '.rake'],
105
- directories: ['app', 'lib', 'config'],
106
- exclude: ['vendor', 'tmp', 'log']
107
- },
108
- go: {
109
- extensions: ['.go'],
110
- directories: ['pkg', 'cmd', 'internal'],
111
- exclude: ['vendor', 'bin']
112
- },
113
- rust: {
114
- extensions: ['.rs'],
115
- directories: ['src', 'lib'],
116
- exclude: ['target', 'dist']
117
- },
118
- java: {
119
- extensions: ['.java'],
120
- directories: ['src/main/java', 'src/test/java'],
121
- exclude: ['target', 'build', '.gradle']
122
- },
123
- php: {
124
- extensions: ['.php'],
125
- directories: ['src', 'app', 'lib'],
126
- exclude: ['vendor', 'cache']
127
- },
128
- elixir: {
129
- extensions: ['.ex', '.exs'],
130
- directories: ['lib', 'web', 'apps'],
131
- exclude: ['_build', 'deps', 'cover']
132
- },
133
-
134
- // Frameworks
135
- react: {
136
- extensions: ['.jsx', '.tsx', '.js', '.ts'],
137
- directories: ['components', 'pages', 'hooks', 'contexts'],
138
- patterns: ['**/components/**', '**/pages/**', '**/hooks/**'],
139
- exclude: ['node_modules', 'build', 'dist']
140
- },
141
- vue: {
142
- extensions: ['.vue', '.js', '.ts'],
143
- directories: ['components', 'views', 'stores'],
144
- patterns: ['**/*.vue', '**/components/**'],
145
- exclude: ['node_modules', 'dist']
146
- },
147
- angular: {
148
- extensions: ['.ts', '.html', '.scss'],
149
- directories: ['src/app'],
150
- patterns: ['**/*.component.ts', '**/*.service.ts'],
151
- exclude: ['node_modules', 'dist']
152
- },
153
- rails: {
154
- extensions: ['.rb', '.erb', '.haml'],
155
- directories: ['app', 'config', 'db'],
156
- patterns: ['app/**/*.rb', 'config/**/*.rb'],
157
- exclude: ['tmp', 'log', 'vendor']
158
- },
159
- django: {
160
- extensions: ['.py', '.html'],
161
- directories: ['apps', 'templates', 'static'],
162
- patterns: ['**/*.py', 'templates/**'],
163
- exclude: ['venv', '__pycache__', 'media']
164
- },
165
- express: {
166
- extensions: ['.js', '.ts'],
167
- directories: ['routes', 'controllers', 'middleware'],
168
- patterns: ['routes/**', 'controllers/**'],
169
- exclude: ['node_modules', 'public']
170
- },
171
- fastapi: {
172
- extensions: ['.py'],
173
- directories: ['app', 'api', 'routers'],
174
- patterns: ['app/**/*.py', 'api/**/*.py'],
175
- exclude: ['venv', '__pycache__']
176
- },
177
-
178
- // Databases
179
- postgres: {
180
- extensions: ['.sql', '.plpgsql'],
181
- directories: ['migrations', 'schemas', 'functions'],
182
- patterns: ['**/*.sql', 'migrations/**'],
183
- exclude: []
184
- },
185
- mongodb: {
186
- extensions: ['.js', '.ts', '.json'],
187
- directories: ['models', 'schemas'],
188
- patterns: ['models/**', 'schemas/**'],
189
- exclude: []
190
- },
191
- mysql: {
192
- extensions: ['.sql'],
193
- directories: ['migrations', 'schemas'],
194
- patterns: ['**/*.sql'],
195
- exclude: []
196
- }
197
- };
70
+ return {
71
+ files: filteredFiles,
72
+ patterns: {
73
+ detectedTech: relevantPatterns.detectedTech,
74
+ projectStructure: relevantPatterns.projectStructure,
75
+ agentic: true // Flag indicating this was agentic, not hardcoded
76
+ },
77
+ metrics,
78
+ agent: agent.name,
79
+ filtered: true
80
+ };
198
81
  }
199
82
 
200
83
  /**
201
- * Initialize task-based patterns
84
+ * REMOVED: initializeTechPatterns() and initializeTaskPatterns()
85
+ *
86
+ * These were hardcoded patterns that limited Claude's knowledge.
87
+ * Now everything is agentic - Claude decides what files are needed
88
+ * based on the actual project analysis, not predetermined patterns.
89
+ *
90
+ * The ContextEstimator provides file suggestions, and Claude
91
+ * uses those along with the project analysis to decide what to load.
202
92
  */
203
- initializeTaskPatterns() {
204
- return {
205
- api: {
206
- include: ['routes', 'controllers', 'middleware', 'api'],
207
- patterns: ['**/api/**', '**/routes/**', '**/controllers/**'],
208
- focus: 'backend logic and endpoints'
209
- },
210
- ui: {
211
- include: ['components', 'pages', 'views', 'styles'],
212
- patterns: ['**/components/**', '**/pages/**', '**/*.css', '**/*.scss'],
213
- focus: 'user interface and styling'
214
- },
215
- database: {
216
- include: ['models', 'migrations', 'schemas', 'db'],
217
- patterns: ['**/models/**', '**/migrations/**', '**/*.sql'],
218
- focus: 'data layer and persistence'
219
- },
220
- testing: {
221
- include: ['test', 'tests', 'spec', '__tests__'],
222
- patterns: ['**/*.test.*', '**/*.spec.*', '**/test/**'],
223
- focus: 'test files and test utilities'
224
- },
225
- configuration: {
226
- include: ['config', 'env', 'settings'],
227
- patterns: ['**/config/**', '**/.env*', '**/*config.*'],
228
- focus: 'configuration and environment'
229
- },
230
- deployment: {
231
- include: ['.github', '.gitlab', 'docker', 'k8s'],
232
- patterns: ['Dockerfile*', '**/*.yml', '**/*.yaml', '.github/**'],
233
- focus: 'CI/CD and deployment'
234
- },
235
- documentation: {
236
- include: ['docs', 'README'],
237
- patterns: ['**/*.md', 'docs/**', 'README*'],
238
- focus: 'documentation files'
239
- }
240
- };
241
- }
242
93
 
243
94
  /**
244
95
  * Determine which patterns to use based on agent and task
96
+ *
97
+ * 100% AGENTIC: Uses analyzer for I/O, no hardcoded tech detection.
98
+ * Claude decides what files matter based on actual project analysis.
245
99
  */
246
100
  async determineRelevantPatterns(agent, task, projectPath) {
247
- const patterns = {
248
- include: [],
249
- exclude: [],
250
- extensions: [],
251
- specific: []
252
- };
101
+ const analyzer = require('../domain/analyzer');
102
+ analyzer.init(projectPath);
253
103
 
254
- // Detect technologies in the project
255
- const detectedTech = await this.detectProjectTechnologies(projectPath);
256
-
257
- // Add patterns based on detected technologies
258
- detectedTech.forEach(tech => {
259
- if (this.techPatterns[tech]) {
260
- const techPattern = this.techPatterns[tech];
261
- patterns.extensions.push(...(techPattern.extensions || []));
262
- patterns.include.push(...(techPattern.directories || []));
263
- patterns.exclude.push(...(techPattern.exclude || []));
264
- patterns.specific.push(...(techPattern.patterns || []));
265
- }
266
- });
267
-
268
- // Add patterns based on task type
269
- const taskType = this.detectTaskType(task);
270
- if (this.taskPatterns[taskType]) {
271
- const taskPattern = this.taskPatterns[taskType];
272
- patterns.include.push(...(taskPattern.include || []));
273
- patterns.specific.push(...(taskPattern.patterns || []));
274
- }
104
+ // Get REAL file extensions from project (not assumed)
105
+ const realExtensions = await analyzer.getFileExtensions();
275
106
 
276
- // Add agent-specific patterns
277
- const agentPatterns = this.getAgentSpecificPatterns(agent);
278
- patterns.include.push(...agentPatterns.include);
279
- patterns.exclude.push(...agentPatterns.exclude);
107
+ // Get REAL directory structure (not assumed)
108
+ const projectStructure = await analyzer.listDirectories();
280
109
 
281
- // Remove duplicates
282
- patterns.include = [...new Set(patterns.include)];
283
- patterns.exclude = [...new Set(patterns.exclude)];
284
- patterns.extensions = [...new Set(patterns.extensions)];
285
- patterns.specific = [...new Set(patterns.specific)];
110
+ // Get config files that exist (not hardcoded list)
111
+ const configFiles = await analyzer.listConfigFiles();
112
+
113
+ // Build patterns from ACTUAL project data
114
+ const patterns = {
115
+ include: [],
116
+ exclude: ['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.nuxt', 'target', 'vendor'],
117
+ realExtensions, // Actual extensions found in project
118
+ projectStructure, // Actual directories
119
+ configFiles // Actual config files
120
+ };
286
121
 
287
122
  return patterns;
288
123
  }
289
124
 
290
125
  /**
291
- * Detect technologies used in the project
292
- * NOW USES TechDetector - NO HARDCODING
126
+ * Detect actual project structure (no assumptions)
293
127
  */
294
- async detectProjectTechnologies(projectPath) {
128
+ async detectProjectStructure(projectPath) {
295
129
  try {
296
- const TechDetector = require('../domain/tech-detector');
297
- const detector = new TechDetector(projectPath);
298
- const tech = await detector.detectAll();
299
-
300
- // Convert to array of all detected technologies
301
- const all = [
302
- ...tech.languages,
303
- ...tech.frameworks,
304
- ...tech.tools,
305
- ...tech.databases,
306
- ...tech.buildTools,
307
- ...tech.testFrameworks
308
- ];
309
-
310
- return Array.from(new Set(all)); // Remove duplicates
311
- } catch (error) {
312
- console.error('Error detecting technologies:', error.message);
130
+ const entries = await fs.readdir(projectPath, { withFileTypes: true });
131
+ const directories = entries
132
+ .filter(e => e.isDirectory() && !e.name.startsWith('.'))
133
+ .map(e => e.name);
134
+ return directories;
135
+ } catch {
313
136
  return [];
314
137
  }
315
138
  }
316
139
 
317
140
  /**
318
- * Detect task type from description
141
+ * Detect technologies used in the project
142
+ *
143
+ * 100% AGENTIC: Uses analyzer for raw data.
144
+ * No categorization - Claude decides what's relevant.
319
145
  */
320
- detectTaskType(task) {
321
- const description = (task.description || '').toLowerCase();
146
+ async detectProjectTechnologies(projectPath) {
147
+ try {
148
+ const analyzer = require('../domain/analyzer');
149
+ analyzer.init(projectPath);
322
150
 
323
- if (description.includes('api') || description.includes('endpoint')) {
324
- return 'api';
325
- }
326
- if (description.includes('ui') || description.includes('component') || description.includes('style')) {
327
- return 'ui';
328
- }
329
- if (description.includes('database') || description.includes('migration') || description.includes('schema')) {
330
- return 'database';
331
- }
332
- if (description.includes('test') || description.includes('spec')) {
333
- return 'testing';
334
- }
335
- if (description.includes('deploy') || description.includes('docker') || description.includes('ci')) {
336
- return 'deployment';
337
- }
338
- if (description.includes('config') || description.includes('env')) {
339
- return 'configuration';
340
- }
341
- if (description.includes('docs') || description.includes('readme')) {
342
- return 'documentation';
151
+ // Return raw data for Claude to analyze
152
+ return {
153
+ extensions: await analyzer.getFileExtensions(),
154
+ directories: await analyzer.listDirectories(),
155
+ configFiles: await analyzer.listConfigFiles()
156
+ };
157
+ } catch (error) {
158
+ log.error('Error detecting project data:', error.message);
159
+ return { extensions: {}, directories: [], configFiles: [] };
343
160
  }
344
-
345
- return 'general';
346
161
  }
347
162
 
348
163
  /**
349
- * Get agent-specific patterns
164
+ * REMOVED: detectTaskType() - was hardcoded pattern matching
165
+ *
166
+ * Task type detection is now agentic - Claude analyzes the task
167
+ * description and project context to determine what files are needed.
168
+ * No hardcoded keyword matching.
350
169
  */
351
- getAgentSpecificPatterns(agent) {
352
- const agentType = (agent.type || agent.name || '').toLowerCase();
353
170
 
354
- const patterns = {
355
- 'frontend': {
356
- include: ['components', 'pages', 'views', 'styles', 'public'],
357
- exclude: ['backend', 'api', 'server', 'database']
358
- },
359
- 'backend': {
360
- include: ['api', 'routes', 'controllers', 'services', 'middleware'],
361
- exclude: ['components', 'styles', 'public']
362
- },
363
- 'database': {
364
- include: ['models', 'schemas', 'migrations', 'db'],
365
- exclude: ['components', 'styles', 'public', 'static']
366
- },
367
- 'devops': {
368
- include: ['.github', '.gitlab', 'docker', 'k8s', 'terraform'],
369
- exclude: ['src', 'app', 'components']
370
- },
371
- 'qa': {
372
- include: ['test', 'tests', 'spec', '__tests__', 'cypress'],
373
- exclude: ['src', 'app', 'public']
374
- }
375
- };
376
-
377
- // Find matching pattern
378
- for (const [key, pattern] of Object.entries(patterns)) {
379
- if (agentType.includes(key)) {
380
- return pattern;
381
- }
382
- }
383
-
384
- // Default pattern
385
- return {
386
- include: [],
387
- exclude: ['node_modules', 'vendor', 'dist', 'build', '.git']
388
- };
389
- }
171
+ /**
172
+ * REMOVED: getAgentSpecificPatterns() - was hardcoded agent patterns
173
+ *
174
+ * Agent-specific file selection is now agentic - each agent
175
+ * has instructions in its template that tell Claude what files
176
+ * are relevant. No hardcoded assumptions about agent types.
177
+ */
390
178
 
391
179
  /**
392
180
  * Load only relevant files based on patterns
@@ -422,7 +210,7 @@ class ContextFilter {
422
210
  // Limit to reasonable number
423
211
  const maxFiles = 300;
424
212
  if (uniqueFiles.length > maxFiles) {
425
- console.log(`Limiting context to ${maxFiles} most relevant files`);
213
+ log.debug(`Limiting context to ${maxFiles} files`);
426
214
  return uniqueFiles.slice(0, maxFiles);
427
215
  }
428
216
 
@@ -432,34 +220,52 @@ class ContextFilter {
432
220
  return expandedFiles.slice(0, maxFiles);
433
221
 
434
222
  } catch (error) {
435
- console.error('Error loading files:', error.message);
223
+ log.error('Error loading files:', error.message);
436
224
  return [];
437
225
  }
438
226
  }
439
227
 
440
228
  /**
441
229
  * Build glob patterns from pattern configuration
230
+ *
231
+ * 100% AGENTIC: Uses REAL extensions from project, not hardcoded mapping.
232
+ * No language→extension assumptions.
442
233
  */
443
234
  buildGlobPatterns(patterns) {
444
235
  const globs = [];
445
236
 
446
- // Add specific patterns
447
- globs.push(...patterns.specific);
237
+ // Use REAL extensions found in project (no hardcoded mapping)
238
+ if (patterns.realExtensions && Object.keys(patterns.realExtensions).length > 0) {
239
+ // Get extensions that actually exist in this project
240
+ const extensions = Object.keys(patterns.realExtensions)
241
+ .filter(ext => ext.startsWith('.')) // Only valid extensions
242
+ .slice(0, 20); // Limit to top 20 most common
448
243
 
449
- // Add extension-based patterns
450
- if (patterns.extensions.length > 0) {
451
- const extPattern = `**/*{${patterns.extensions.join(',')}}`;
452
- globs.push(extPattern);
244
+ if (extensions.length > 0) {
245
+ globs.push(`**/*{${extensions.join(',')}}`);
246
+ }
453
247
  }
454
248
 
455
- // Add directory patterns
456
- patterns.include.forEach(dir => {
457
- globs.push(`${dir}/**/*`);
458
- });
249
+ // Use REAL project structure (no assumptions)
250
+ if (patterns.projectStructure && patterns.projectStructure.length > 0) {
251
+ patterns.projectStructure.forEach(dir => {
252
+ // Exclude universal noise directories
253
+ if (!patterns.exclude.includes(dir)) {
254
+ globs.push(`${dir}/**/*`);
255
+ }
256
+ });
257
+ }
258
+
259
+ // Include REAL config files that exist (not hardcoded list)
260
+ if (patterns.configFiles && patterns.configFiles.length > 0) {
261
+ patterns.configFiles.forEach(file => {
262
+ globs.push(file);
263
+ });
264
+ }
459
265
 
460
- // Default pattern if none specified
266
+ // Fallback: if no patterns detected, include all source-like files
461
267
  if (globs.length === 0) {
462
- globs.push('**/*.{js,ts,jsx,tsx,py,rb,go,java,php}');
268
+ globs.push('**/*');
463
269
  }
464
270
 
465
271
  return globs;
@@ -540,8 +346,7 @@ class ContextFilter {
540
346
  getStatistics() {
541
347
  return {
542
348
  cachedFiles: this.fileCache.size,
543
- supportedTechnologies: Object.keys(this.techPatterns).length,
544
- taskTypes: Object.keys(this.taskPatterns).length
349
+ agentic: true // All filtering is now agentic, no hardcoded patterns
545
350
  };
546
351
  }
547
352
  }