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.
- package/CHANGELOG.md +107 -0
- package/core/__tests__/agentic/prompt-builder.test.js +244 -0
- package/core/__tests__/utils/output.test.js +163 -0
- package/core/agentic/agent-router.js +45 -173
- package/core/agentic/context-builder.js +25 -15
- package/core/agentic/context-filter.js +118 -313
- package/core/agentic/prompt-builder.js +90 -46
- package/core/commands.js +121 -637
- package/core/domain/agent-generator.js +55 -4
- package/core/domain/analyzer.js +122 -0
- package/core/domain/context-estimator.js +32 -53
- package/core/domain/smart-cache.js +2 -1
- package/core/domain/task-analyzer.js +75 -146
- package/core/domain/task-stack.js +2 -1
- package/core/utils/logger.js +64 -0
- package/core/utils/output.js +54 -0
- package/package.json +1 -1
- package/templates/agentic/agent-routing.md +78 -0
- package/templates/agentic/context-filtering.md +77 -0
- package/templates/analysis/patterns.md +206 -0
- package/templates/analysis/project-analysis.md +78 -0
- package/templates/commands/sync.md +61 -7
- package/core/domain/tech-detector.js +0 -365
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
const fs = require('fs').promises
|
|
11
11
|
const path = require('path')
|
|
12
|
-
const
|
|
12
|
+
const analyzer = require('./analyzer')
|
|
13
13
|
const configManager = require('../infrastructure/config-manager')
|
|
14
14
|
const pathManager = require('../infrastructure/path-manager')
|
|
15
15
|
|
|
@@ -17,7 +17,6 @@ class TaskAnalyzer {
|
|
|
17
17
|
constructor(projectPath) {
|
|
18
18
|
this.projectPath = projectPath
|
|
19
19
|
this.projectId = null
|
|
20
|
-
this.techDetector = null
|
|
21
20
|
this.taskHistory = null
|
|
22
21
|
}
|
|
23
22
|
|
|
@@ -26,17 +25,21 @@ class TaskAnalyzer {
|
|
|
26
25
|
*/
|
|
27
26
|
async initialize() {
|
|
28
27
|
this.projectId = await configManager.getProjectId(this.projectPath)
|
|
29
|
-
|
|
28
|
+
analyzer.init(this.projectPath)
|
|
30
29
|
await this.loadTaskHistory()
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
33
|
* Deep semantic analysis of a task
|
|
34
|
+
*
|
|
35
|
+
* 100% AGENTIC: No hardcoded patterns. Uses task description
|
|
36
|
+
* and historical patterns only. Claude decides domain relevance.
|
|
37
|
+
*
|
|
35
38
|
* @param {Object} task - Task object {description, type}
|
|
36
39
|
* @returns {Promise<Object>} Analysis result
|
|
37
40
|
*/
|
|
38
41
|
async analyzeTask(task) {
|
|
39
|
-
if (!this.
|
|
42
|
+
if (!this.projectId) {
|
|
40
43
|
await this.initialize()
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -44,109 +47,68 @@ class TaskAnalyzer {
|
|
|
44
47
|
const type = (task.type || '').toLowerCase()
|
|
45
48
|
const fullText = `${description} ${type}`.trim()
|
|
46
49
|
|
|
47
|
-
// Get project
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
// Get raw project data (no categorization)
|
|
51
|
+
const projectData = {
|
|
52
|
+
packageJson: await analyzer.readPackageJson(),
|
|
53
|
+
extensions: await analyzer.getFileExtensions(),
|
|
54
|
+
directories: await analyzer.listDirectories(),
|
|
55
|
+
configFiles: await analyzer.listConfigFiles()
|
|
56
|
+
}
|
|
52
57
|
|
|
53
|
-
// Semantic understanding
|
|
54
|
-
const semantic = this.analyzeSemantics(fullText
|
|
58
|
+
// Semantic understanding (intent-based, not keyword-based)
|
|
59
|
+
const semantic = this.analyzeSemantics(fullText)
|
|
55
60
|
|
|
56
61
|
// Historical patterns
|
|
57
62
|
const historical = await this.analyzeHistory(fullText)
|
|
58
63
|
|
|
59
64
|
// Complexity estimation
|
|
60
|
-
const complexity = this.estimateComplexity(fullText
|
|
65
|
+
const complexity = this.estimateComplexity(fullText)
|
|
61
66
|
|
|
62
|
-
//
|
|
63
|
-
const primaryDomain = this.selectPrimaryDomain(
|
|
64
|
-
const confidence = this.calculateConfidence(
|
|
67
|
+
// Primary domain from history and intent (not hardcoded patterns)
|
|
68
|
+
const primaryDomain = this.selectPrimaryDomain(semantic, historical)
|
|
69
|
+
const confidence = this.calculateConfidence(semantic, historical)
|
|
65
70
|
|
|
66
71
|
return {
|
|
67
72
|
primaryDomain,
|
|
68
|
-
domains, // All detected domains
|
|
69
73
|
confidence,
|
|
70
74
|
semantic,
|
|
71
75
|
historical,
|
|
72
76
|
complexity,
|
|
73
|
-
|
|
74
|
-
matchedKeywords:
|
|
75
|
-
reason: this.buildReason(primaryDomain,
|
|
76
|
-
alternatives:
|
|
77
|
+
projectData, // Raw data for Claude to analyze
|
|
78
|
+
matchedKeywords: [], // No keyword matching - Claude decides
|
|
79
|
+
reason: this.buildReason(primaryDomain, semantic, historical),
|
|
80
|
+
alternatives: ['full-stack', 'generalist']
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
/**
|
|
81
|
-
*
|
|
85
|
+
* Domain detection removed - 100% AGENTIC
|
|
86
|
+
*
|
|
87
|
+
* NO hardcoded keyword lists or framework categorization.
|
|
88
|
+
* Claude analyzes the task description and project context
|
|
89
|
+
* to determine the appropriate domain.
|
|
90
|
+
*
|
|
91
|
+
* This method is kept for backward compatibility but returns empty.
|
|
92
|
+
* Use analyzeTask() which provides raw data for Claude.
|
|
82
93
|
*/
|
|
83
|
-
detectDomains(text
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// Enhanced patterns with project context
|
|
87
|
-
const patterns = {
|
|
88
|
-
frontend: [
|
|
89
|
-
'component', 'ui', 'user interface', 'frontend', 'client',
|
|
90
|
-
'style', 'css', 'layout', 'responsive', 'design',
|
|
91
|
-
'page', 'view', 'template', 'render', 'display',
|
|
92
|
-
'button', 'form', 'input', 'modal', 'dialog',
|
|
93
|
-
...(projectTech.frameworks.filter(f => ['react', 'vue', 'angular', 'svelte', 'next', 'nuxt'].includes(f.toLowerCase())).map(f => f.toLowerCase()))
|
|
94
|
-
],
|
|
95
|
-
backend: [
|
|
96
|
-
'api', 'server', 'endpoint', 'route', 'middleware',
|
|
97
|
-
'auth', 'authentication', 'authorization', 'jwt', 'session',
|
|
98
|
-
'backend', 'service', 'controller', 'handler',
|
|
99
|
-
'database', 'query', 'model', 'schema',
|
|
100
|
-
...(projectTech.frameworks.filter(f => ['express', 'fastify', 'django', 'flask', 'rails', 'phoenix'].includes(f.toLowerCase())).map(f => f.toLowerCase()))
|
|
101
|
-
],
|
|
102
|
-
database: [
|
|
103
|
-
'database', 'db', 'query', 'migration', 'schema', 'model',
|
|
104
|
-
'sql', 'data', 'table', 'collection', 'index', 'relation',
|
|
105
|
-
'postgres', 'mysql', 'mongodb', 'redis'
|
|
106
|
-
],
|
|
107
|
-
devops: [
|
|
108
|
-
'deploy', 'deployment', 'docker', 'kubernetes', 'k8s',
|
|
109
|
-
'ci/cd', 'pipeline', 'build', 'ship', 'release',
|
|
110
|
-
'production', 'infrastructure', 'container', 'orchestration'
|
|
111
|
-
],
|
|
112
|
-
qa: [
|
|
113
|
-
'test', 'testing', 'bug', 'error', 'fix', 'debug', 'issue',
|
|
114
|
-
'quality', 'coverage', 'unit test', 'integration test',
|
|
115
|
-
'e2e', 'spec', 'assertion', 'validation'
|
|
116
|
-
],
|
|
117
|
-
architecture: [
|
|
118
|
-
'design', 'architecture', 'pattern', 'structure',
|
|
119
|
-
'refactor', 'refactoring', 'organize', 'plan',
|
|
120
|
-
'feature', 'system', 'module', 'component design'
|
|
121
|
-
]
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Score each domain
|
|
125
|
-
for (const [domain, keywords] of Object.entries(patterns)) {
|
|
126
|
-
const matches = keywords.filter(keyword => text.includes(keyword))
|
|
127
|
-
if (matches.length > 0) {
|
|
128
|
-
domains[domain] = {
|
|
129
|
-
keywords: matches,
|
|
130
|
-
count: matches.length,
|
|
131
|
-
score: matches.length + (matches.length > 2 ? 1 : 0) // Bonus for multiple matches
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return domains
|
|
94
|
+
detectDomains(text) {
|
|
95
|
+
// No hardcoded patterns - Claude decides domain
|
|
96
|
+
return {}
|
|
137
97
|
}
|
|
138
98
|
|
|
139
99
|
/**
|
|
140
|
-
* Semantic analysis - understand intent
|
|
100
|
+
* Semantic analysis - understand intent
|
|
101
|
+
*
|
|
102
|
+
* Only detects basic intent (create, fix, improve, test).
|
|
103
|
+
* Claude handles detailed domain analysis.
|
|
141
104
|
*/
|
|
142
|
-
analyzeSemantics(text
|
|
105
|
+
analyzeSemantics(text) {
|
|
143
106
|
const semantic = {
|
|
144
107
|
intent: null,
|
|
145
|
-
requiresMultipleAgents: false
|
|
146
|
-
complexity: 'medium'
|
|
108
|
+
requiresMultipleAgents: false
|
|
147
109
|
}
|
|
148
110
|
|
|
149
|
-
// Detect intent patterns
|
|
111
|
+
// Detect basic intent patterns (these are universal, not tech-specific)
|
|
150
112
|
if (text.match(/\b(create|add|build|implement|make)\b/)) {
|
|
151
113
|
semantic.intent = 'create'
|
|
152
114
|
} else if (text.match(/\b(fix|repair|debug|resolve)\b/)) {
|
|
@@ -157,18 +119,8 @@ class TaskAnalyzer {
|
|
|
157
119
|
semantic.intent = 'test'
|
|
158
120
|
}
|
|
159
121
|
|
|
160
|
-
//
|
|
161
|
-
if
|
|
162
|
-
text.match(/\b(test|spec).*\b(api|endpoint)\b/)) {
|
|
163
|
-
semantic.requiresMultipleAgents = true
|
|
164
|
-
semantic.agents = ['backend', 'qa']
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (text.match(/\b(component|ui).*\b(test|spec)\b/) ||
|
|
168
|
-
text.match(/\b(test|spec).*\b(component|ui)\b/)) {
|
|
169
|
-
semantic.requiresMultipleAgents = true
|
|
170
|
-
semantic.agents = ['frontend', 'qa']
|
|
171
|
-
}
|
|
122
|
+
// No hardcoded multi-agent detection
|
|
123
|
+
// Claude decides if multiple agents are needed based on context
|
|
172
124
|
|
|
173
125
|
return semantic
|
|
174
126
|
}
|
|
@@ -210,71 +162,61 @@ class TaskAnalyzer {
|
|
|
210
162
|
}
|
|
211
163
|
|
|
212
164
|
/**
|
|
213
|
-
* Estimate task complexity
|
|
165
|
+
* Estimate task complexity based on intent words
|
|
214
166
|
*/
|
|
215
|
-
estimateComplexity(text
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const simpleIndicators = ['add', 'create', 'simple', 'basic']
|
|
220
|
-
const complexIndicators = ['refactor', 'optimize', 'architecture', 'migration', 'redesign']
|
|
167
|
+
estimateComplexity(text) {
|
|
168
|
+
// Simple complexity indicators (universal, not tech-specific)
|
|
169
|
+
const simpleIndicators = ['add', 'create', 'simple', 'basic', 'small']
|
|
170
|
+
const complexIndicators = ['refactor', 'optimize', 'architecture', 'migration', 'redesign', 'overhaul']
|
|
221
171
|
|
|
222
172
|
const simpleCount = simpleIndicators.filter(ind => text.includes(ind)).length
|
|
223
173
|
const complexCount = complexIndicators.filter(ind => text.includes(ind)).length
|
|
224
174
|
|
|
225
175
|
if (complexCount > simpleCount) {
|
|
226
|
-
|
|
176
|
+
return 'high'
|
|
227
177
|
} else if (simpleCount > 0 && complexCount === 0) {
|
|
228
|
-
|
|
178
|
+
return 'low'
|
|
229
179
|
}
|
|
230
180
|
|
|
231
|
-
|
|
232
|
-
if (Object.keys(domains).length > 1) {
|
|
233
|
-
complexity = 'high'
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return complexity
|
|
181
|
+
return 'medium'
|
|
237
182
|
}
|
|
238
183
|
|
|
239
184
|
/**
|
|
240
|
-
* Select primary domain from
|
|
185
|
+
* Select primary domain from history and semantics
|
|
186
|
+
*
|
|
187
|
+
* 100% AGENTIC: No keyword matching. Uses only:
|
|
188
|
+
* - Historical patterns from past tasks
|
|
189
|
+
* - Basic intent detection
|
|
190
|
+
* Claude decides actual domain based on project context.
|
|
241
191
|
*/
|
|
242
|
-
selectPrimaryDomain(
|
|
243
|
-
// Priority: historical >
|
|
244
|
-
if (historical.suggestedDomain && historical.confidence > 0.7) {
|
|
192
|
+
selectPrimaryDomain(semantic, historical) {
|
|
193
|
+
// Priority: historical > default
|
|
194
|
+
if (historical && historical.suggestedDomain && historical.confidence > 0.7) {
|
|
245
195
|
return historical.suggestedDomain
|
|
246
196
|
}
|
|
247
197
|
|
|
248
|
-
|
|
249
|
-
|
|
198
|
+
// Map intent to suggested domain (loose mapping, Claude refines)
|
|
199
|
+
if (semantic && semantic.intent === 'test') {
|
|
200
|
+
return 'qa'
|
|
250
201
|
}
|
|
251
202
|
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
.sort((a, b) => b[1].score - a[1].score)
|
|
255
|
-
|
|
256
|
-
return sorted.length > 0 ? sorted[0][0] : 'generalist'
|
|
203
|
+
// Default: generalist (Claude decides based on context)
|
|
204
|
+
return 'generalist'
|
|
257
205
|
}
|
|
258
206
|
|
|
259
207
|
/**
|
|
260
|
-
* Calculate confidence
|
|
208
|
+
* Calculate confidence based on available signals
|
|
261
209
|
*/
|
|
262
|
-
calculateConfidence(
|
|
210
|
+
calculateConfidence(semantic, historical) {
|
|
263
211
|
let confidence = 0.5 // Base confidence
|
|
264
212
|
|
|
265
|
-
// Boost from keyword matches
|
|
266
|
-
const primaryDomain = this.selectPrimaryDomain(domains, semantic, historical)
|
|
267
|
-
if (domains[primaryDomain]) {
|
|
268
|
-
confidence += domains[primaryDomain].score * 0.1
|
|
269
|
-
}
|
|
270
|
-
|
|
271
213
|
// Boost from historical patterns
|
|
272
|
-
if (historical.confidence > 0) {
|
|
214
|
+
if (historical && historical.confidence > 0) {
|
|
273
215
|
confidence += historical.confidence * 0.3
|
|
274
216
|
}
|
|
275
217
|
|
|
276
218
|
// Boost from semantic understanding
|
|
277
|
-
if (semantic.intent) {
|
|
219
|
+
if (semantic && semantic.intent) {
|
|
278
220
|
confidence += 0.1
|
|
279
221
|
}
|
|
280
222
|
|
|
@@ -284,31 +226,18 @@ class TaskAnalyzer {
|
|
|
284
226
|
/**
|
|
285
227
|
* Build human-readable reason
|
|
286
228
|
*/
|
|
287
|
-
buildReason(primaryDomain,
|
|
229
|
+
buildReason(primaryDomain, semantic, historical) {
|
|
288
230
|
const parts = []
|
|
289
231
|
|
|
290
|
-
if (historical.suggestedDomain && historical.confidence > 0.7) {
|
|
291
|
-
parts.push(`Historical
|
|
232
|
+
if (historical && historical.suggestedDomain && historical.confidence > 0.7) {
|
|
233
|
+
parts.push(`Historical: similar tasks used ${primaryDomain}`)
|
|
292
234
|
}
|
|
293
235
|
|
|
294
|
-
if (
|
|
295
|
-
parts.push(`Keywords: ${domains[primaryDomain].keywords.join(', ')}`)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (semantic.intent) {
|
|
236
|
+
if (semantic && semantic.intent) {
|
|
299
237
|
parts.push(`Intent: ${semantic.intent}`)
|
|
300
238
|
}
|
|
301
239
|
|
|
302
|
-
return parts.join(' | ') ||
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Get alternative domains
|
|
307
|
-
*/
|
|
308
|
-
getAlternatives(primaryDomain, domains) {
|
|
309
|
-
return Object.keys(domains)
|
|
310
|
-
.filter(d => d !== primaryDomain)
|
|
311
|
-
.sort((a, b) => domains[b].score - domains[a].score)
|
|
240
|
+
return parts.join(' | ') || 'Claude will analyze task in context'
|
|
312
241
|
}
|
|
313
242
|
|
|
314
243
|
/**
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const fs = require('fs').promises;
|
|
8
|
+
const log = require('../utils/logger');
|
|
8
9
|
|
|
9
10
|
class TaskStack {
|
|
10
11
|
constructor(projectPath) {
|
|
@@ -168,7 +169,7 @@ class TaskStack {
|
|
|
168
169
|
try {
|
|
169
170
|
entries.push(JSON.parse(line));
|
|
170
171
|
} catch (error) {
|
|
171
|
-
|
|
172
|
+
log.error('Error parsing stack line:', error.message);
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
175
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger - Centralized logging with levels
|
|
3
|
+
*
|
|
4
|
+
* Silent by default. Enable with:
|
|
5
|
+
* PRJCT_DEBUG=1 (all logs)
|
|
6
|
+
* PRJCT_DEBUG=error (errors only)
|
|
7
|
+
* PRJCT_DEBUG=warn (errors + warnings)
|
|
8
|
+
* PRJCT_DEBUG=info (errors + warnings + info)
|
|
9
|
+
* PRJCT_DEBUG=debug (everything)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* const log = require('./utils/logger')
|
|
13
|
+
* log.debug('Processing files...')
|
|
14
|
+
* log.info('Task started')
|
|
15
|
+
* log.warn('Cache miss')
|
|
16
|
+
* log.error('Failed to load', error.message)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const LEVELS = { error: 0, warn: 1, info: 2, debug: 3 }
|
|
20
|
+
|
|
21
|
+
const debugEnv = process.env.PRJCT_DEBUG || process.env.DEBUG || ''
|
|
22
|
+
const isEnabled = debugEnv === '1' || debugEnv === 'true' || debugEnv.includes('prjct')
|
|
23
|
+
|
|
24
|
+
// Determine log level
|
|
25
|
+
let currentLevel = -1 // disabled by default
|
|
26
|
+
if (isEnabled) {
|
|
27
|
+
if (debugEnv === '1' || debugEnv === 'true' || debugEnv === 'prjct') {
|
|
28
|
+
currentLevel = LEVELS.debug // all logs
|
|
29
|
+
} else if (LEVELS[debugEnv] !== undefined) {
|
|
30
|
+
currentLevel = LEVELS[debugEnv]
|
|
31
|
+
} else {
|
|
32
|
+
currentLevel = LEVELS.debug
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// No-op function for disabled logs
|
|
37
|
+
const noop = () => {}
|
|
38
|
+
|
|
39
|
+
// Create logger methods
|
|
40
|
+
const logger = {
|
|
41
|
+
error: currentLevel >= LEVELS.error
|
|
42
|
+
? (...args) => console.error('[prjct:error]', ...args)
|
|
43
|
+
: noop,
|
|
44
|
+
|
|
45
|
+
warn: currentLevel >= LEVELS.warn
|
|
46
|
+
? (...args) => console.warn('[prjct:warn]', ...args)
|
|
47
|
+
: noop,
|
|
48
|
+
|
|
49
|
+
info: currentLevel >= LEVELS.info
|
|
50
|
+
? (...args) => console.log('[prjct:info]', ...args)
|
|
51
|
+
: noop,
|
|
52
|
+
|
|
53
|
+
debug: currentLevel >= LEVELS.debug
|
|
54
|
+
? (...args) => console.log('[prjct:debug]', ...args)
|
|
55
|
+
: noop,
|
|
56
|
+
|
|
57
|
+
// Check if logging is enabled (useful for expensive log prep)
|
|
58
|
+
isEnabled: () => currentLevel >= 0,
|
|
59
|
+
|
|
60
|
+
// Get current level name
|
|
61
|
+
level: () => Object.keys(LEVELS).find(k => LEVELS[k] === currentLevel) || 'disabled'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = logger
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Output System for prjct-cli
|
|
3
|
+
* Spinner while working → Single line result
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk')
|
|
7
|
+
|
|
8
|
+
const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
|
9
|
+
const SPEED = 80
|
|
10
|
+
|
|
11
|
+
let interval = null
|
|
12
|
+
let frame = 0
|
|
13
|
+
|
|
14
|
+
const truncate = (s, max = 50) => (s && s.length > max ? s.slice(0, max - 1) + '…' : s || '')
|
|
15
|
+
const clear = () => process.stdout.write('\r' + ' '.repeat(70) + '\r')
|
|
16
|
+
|
|
17
|
+
const out = {
|
|
18
|
+
spin(msg) {
|
|
19
|
+
this.stop()
|
|
20
|
+
interval = setInterval(() => {
|
|
21
|
+
process.stdout.write(`\r${chalk.cyan(FRAMES[frame++ % 10])} ${truncate(msg, 55)}`)
|
|
22
|
+
}, SPEED)
|
|
23
|
+
return this
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
done(msg) {
|
|
27
|
+
this.stop()
|
|
28
|
+
console.log(`${chalk.green('✓')} ${truncate(msg, 65)}`)
|
|
29
|
+
return this
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
fail(msg) {
|
|
33
|
+
this.stop()
|
|
34
|
+
console.log(`${chalk.red('✗')} ${truncate(msg, 65)}`)
|
|
35
|
+
return this
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
warn(msg) {
|
|
39
|
+
this.stop()
|
|
40
|
+
console.log(`${chalk.yellow('⚠')} ${truncate(msg, 65)}`)
|
|
41
|
+
return this
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
stop() {
|
|
45
|
+
if (interval) {
|
|
46
|
+
clearInterval(interval)
|
|
47
|
+
interval = null
|
|
48
|
+
clear()
|
|
49
|
+
}
|
|
50
|
+
return this
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = out
|
package/package.json
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
allowed-tools: [Read]
|
|
3
|
+
description: 'Determine which agent should handle a task - Claude decides'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent Routing Instructions
|
|
7
|
+
|
|
8
|
+
## Objective
|
|
9
|
+
|
|
10
|
+
Determine the best agent for a task by analyzing the ACTUAL task and project context.
|
|
11
|
+
|
|
12
|
+
## Step 1: Understand the Task
|
|
13
|
+
|
|
14
|
+
Read the task description and identify:
|
|
15
|
+
|
|
16
|
+
- What files will be modified?
|
|
17
|
+
- What type of work is involved?
|
|
18
|
+
- What knowledge is required?
|
|
19
|
+
|
|
20
|
+
## Step 2: Read Project Context
|
|
21
|
+
|
|
22
|
+
If project analysis exists, read it to understand:
|
|
23
|
+
|
|
24
|
+
- What technologies are actually used
|
|
25
|
+
- How the project is structured
|
|
26
|
+
- What patterns are established
|
|
27
|
+
|
|
28
|
+
## Step 3: Match Task to Agent
|
|
29
|
+
|
|
30
|
+
Based on your analysis, determine which agent is best suited:
|
|
31
|
+
|
|
32
|
+
**DO NOT assume:**
|
|
33
|
+
- "React" = frontend agent
|
|
34
|
+
- "Express" = backend agent
|
|
35
|
+
- "Database" = database agent
|
|
36
|
+
|
|
37
|
+
**DO analyze:**
|
|
38
|
+
- What the task actually requires
|
|
39
|
+
- What files will be touched
|
|
40
|
+
- What expertise is needed
|
|
41
|
+
|
|
42
|
+
## Available Agent Types
|
|
43
|
+
|
|
44
|
+
Consider these agent specializations:
|
|
45
|
+
|
|
46
|
+
- **Coordinator**: High-level planning, task breakdown
|
|
47
|
+
- **Frontend/UX**: UI components, user experience, styling
|
|
48
|
+
- **Backend**: API endpoints, server logic, business rules
|
|
49
|
+
- **Database**: Schema design, queries, migrations
|
|
50
|
+
- **DevOps/QA**: Testing, CI/CD, deployment, infrastructure
|
|
51
|
+
- **Full-stack**: Cross-cutting concerns, multiple layers
|
|
52
|
+
|
|
53
|
+
## Decision Process
|
|
54
|
+
|
|
55
|
+
1. Read task description
|
|
56
|
+
2. Identify primary area of work
|
|
57
|
+
3. Consider secondary areas
|
|
58
|
+
4. Choose agent with best expertise match
|
|
59
|
+
|
|
60
|
+
## Output
|
|
61
|
+
|
|
62
|
+
Return the recommended agent with reasoning:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"agent": "recommended-agent-type",
|
|
67
|
+
"reasoning": "why this agent is best for the task",
|
|
68
|
+
"confidence": "high|medium|low",
|
|
69
|
+
"alternatives": ["other agents that could help"]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Rules
|
|
74
|
+
|
|
75
|
+
- **Task-driven, not tech-driven** - Focus on what needs to be done
|
|
76
|
+
- **Context matters** - Same tech can mean different things in different projects
|
|
77
|
+
- **Be flexible** - One project's "backend" might be another's "full-stack"
|
|
78
|
+
- **Explain your reasoning** - Don't just pick, justify
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
allowed-tools: [Glob, Read]
|
|
3
|
+
description: 'Filter relevant context for a task - Claude decides what matters'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context Filtering Instructions
|
|
7
|
+
|
|
8
|
+
## Objective
|
|
9
|
+
|
|
10
|
+
Determine which files and directories are relevant for a given task.
|
|
11
|
+
|
|
12
|
+
## Step 1: Get Real File Extensions
|
|
13
|
+
|
|
14
|
+
Instead of assuming extensions, get the ACTUAL extensions in the project:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Get real extensions (analyzer.getFileExtensions())
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use only extensions that EXIST in this project.
|
|
21
|
+
|
|
22
|
+
## Step 2: Identify Relevant Directories
|
|
23
|
+
|
|
24
|
+
Based on the task, identify which directories matter:
|
|
25
|
+
|
|
26
|
+
**DO NOT use hardcoded lists like:**
|
|
27
|
+
- "components" for frontend
|
|
28
|
+
- "routes" for backend
|
|
29
|
+
|
|
30
|
+
**DO analyze:**
|
|
31
|
+
- Where does this project put similar code?
|
|
32
|
+
- What directory structure does it use?
|
|
33
|
+
- What naming conventions are followed?
|
|
34
|
+
|
|
35
|
+
## Step 3: Filter by Task Requirements
|
|
36
|
+
|
|
37
|
+
For the specific task:
|
|
38
|
+
|
|
39
|
+
1. What type of files will be modified?
|
|
40
|
+
2. What related files might need updates?
|
|
41
|
+
3. What config files are relevant?
|
|
42
|
+
|
|
43
|
+
## Step 4: Exclude Non-Relevant
|
|
44
|
+
|
|
45
|
+
Always exclude:
|
|
46
|
+
- `node_modules/`, `vendor/`, etc. (dependencies)
|
|
47
|
+
- `.git/` (version control)
|
|
48
|
+
- `dist/`, `build/`, `target/` (build outputs)
|
|
49
|
+
- Generated files
|
|
50
|
+
|
|
51
|
+
## Output
|
|
52
|
+
|
|
53
|
+
Return filtering patterns:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"include": {
|
|
58
|
+
"extensions": [".actual", ".extensions", ".found"],
|
|
59
|
+
"directories": ["actual/", "directories/", "in/project/"],
|
|
60
|
+
"files": ["specific-files-if-known"]
|
|
61
|
+
},
|
|
62
|
+
"exclude": {
|
|
63
|
+
"directories": ["node_modules/", ".git/", "dist/"],
|
|
64
|
+
"patterns": ["*.min.js", "*.map"]
|
|
65
|
+
},
|
|
66
|
+
"priority": ["most-relevant-paths-first"],
|
|
67
|
+
"reasoning": "why these patterns were chosen"
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Rules
|
|
72
|
+
|
|
73
|
+
- **Use REAL extensions** - Only include extensions that exist in the project
|
|
74
|
+
- **No assumptions** - Don't assume directory names
|
|
75
|
+
- **Task-specific** - Different tasks need different context
|
|
76
|
+
- **Efficient** - Don't include everything, focus on what matters
|
|
77
|
+
- **Explain choices** - Document why certain patterns were included/excluded
|