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
|
@@ -20,6 +20,9 @@ class PromptBuilder {
|
|
|
20
20
|
*/
|
|
21
21
|
build(template, context, state, agent = null, learnedPatterns = null, thinkBlock = null, relevantMemories = null, planInfo = null) {
|
|
22
22
|
const parts = []
|
|
23
|
+
|
|
24
|
+
// Store context for use in helper methods
|
|
25
|
+
this._currentContext = context
|
|
23
26
|
|
|
24
27
|
// Agent assignment (if applicable)
|
|
25
28
|
// CRITICAL: Include full agent content, not just name
|
|
@@ -85,13 +88,60 @@ class PromptBuilder {
|
|
|
85
88
|
// Current state (only if exists and relevant)
|
|
86
89
|
const relevantState = this.filterRelevantState(state)
|
|
87
90
|
if (relevantState) {
|
|
88
|
-
parts.push('\
|
|
91
|
+
parts.push('\n## PRJCT STATE (Project Management Data)\n')
|
|
89
92
|
parts.push(relevantState)
|
|
90
93
|
parts.push('\n')
|
|
91
94
|
}
|
|
92
95
|
|
|
93
|
-
//
|
|
94
|
-
|
|
96
|
+
// CRITICAL: Include available project files for context
|
|
97
|
+
if (context.files && context.files.length > 0) {
|
|
98
|
+
parts.push('\n## AVAILABLE PROJECT FILES\n')
|
|
99
|
+
parts.push(`You have ${context.files.length} relevant files available in this project.\n`)
|
|
100
|
+
parts.push('**USE Read TOOL TO LOAD FILES BEFORE MODIFYING THEM.**\n')
|
|
101
|
+
parts.push('\nTop relevant files:\n')
|
|
102
|
+
const topFiles = context.files.slice(0, 20).map(f => `- ${f}`).join('\n')
|
|
103
|
+
parts.push(topFiles)
|
|
104
|
+
if (context.files.length > 20) {
|
|
105
|
+
parts.push(`\n... and ${context.files.length - 20} more files. Use Read tool to access them.\n`)
|
|
106
|
+
}
|
|
107
|
+
parts.push('\n')
|
|
108
|
+
} else if (context.projectPath) {
|
|
109
|
+
parts.push('\n## PROJECT FILES\n')
|
|
110
|
+
parts.push(`Project path: ${context.projectPath}\n`)
|
|
111
|
+
parts.push('**USE Read TOOL TO LOAD FILES YOU NEED TO UNDERSTAND OR MODIFY.**\n')
|
|
112
|
+
parts.push('**NEVER MODIFY CODE WITHOUT READING IT FIRST.**\n\n')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// OPTIMIZED: Only include patterns for code-modifying commands
|
|
116
|
+
// Commands like done, ship, recap, next don't need full patterns
|
|
117
|
+
const codeCommands = ['now', 'build', 'feature', 'design', 'cleanup', 'fix', 'bug', 'test', 'init', 'spec', 'work']
|
|
118
|
+
const commandName = template.frontmatter?.name?.replace('p:', '') || ''
|
|
119
|
+
const needsPatterns = codeCommands.includes(commandName)
|
|
120
|
+
|
|
121
|
+
// Include code patterns analysis for code-modifying commands
|
|
122
|
+
const codePatternsContent = state?.codePatterns || ''
|
|
123
|
+
if (needsPatterns && codePatternsContent && codePatternsContent.trim()) {
|
|
124
|
+
parts.push('\n## CODE PATTERNS (MUST FOLLOW)\n')
|
|
125
|
+
// Include the full patterns file - it contains critical conventions
|
|
126
|
+
parts.push(codePatternsContent)
|
|
127
|
+
parts.push('\n**ALL new code MUST respect these patterns. NO anti-patterns allowed.**\n')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const analysisContent = state?.analysis || ''
|
|
131
|
+
if (needsPatterns && analysisContent && analysisContent.trim()) {
|
|
132
|
+
// Extract stack info compactly
|
|
133
|
+
const stackMatch = analysisContent.match(/Stack[:\s]+([^\n]+)/i) ||
|
|
134
|
+
analysisContent.match(/Technology[:\s]+([^\n]+)/i)
|
|
135
|
+
const stack = stackMatch ? stackMatch[1].trim() : 'detected'
|
|
136
|
+
|
|
137
|
+
parts.push(`\n## STACK\nStack: ${stack}\n`)
|
|
138
|
+
if (!codePatternsContent) {
|
|
139
|
+
parts.push('Read analysis/repo-summary.md + similar files before coding. Match patterns exactly.\n')
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// CRITICAL: Compressed rules (replaces 78 lines with 12)
|
|
144
|
+
parts.push(this.buildCriticalRules());
|
|
95
145
|
|
|
96
146
|
// P1.1: Learned Patterns (avoid asking user questions we already know)
|
|
97
147
|
if (learnedPatterns && Object.keys(learnedPatterns).some(k => learnedPatterns[k])) {
|
|
@@ -126,37 +176,13 @@ class PromptBuilder {
|
|
|
126
176
|
}
|
|
127
177
|
}
|
|
128
178
|
|
|
129
|
-
// P3.4: Plan Mode
|
|
130
|
-
if (planInfo) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
parts.push('3. **ANALYZE**: Understand the context and implications\n')
|
|
137
|
-
parts.push('4. **PROPOSE**: Generate a plan with clear steps\n')
|
|
138
|
-
parts.push('5. **WAIT FOR APPROVAL**: Do NOT execute until user approves\n')
|
|
139
|
-
|
|
140
|
-
if (planInfo.active) {
|
|
141
|
-
parts.push(`\nCurrent Status: ${planInfo.active.status}\n`)
|
|
142
|
-
if (planInfo.active.gatheredInfo?.length > 0) {
|
|
143
|
-
parts.push(`Info gathered: ${planInfo.active.gatheredInfo.length} items\n`)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (planInfo.requiresApproval) {
|
|
149
|
-
parts.push('\n## APPROVAL REQUIRED\n')
|
|
150
|
-
parts.push('This command is DESTRUCTIVE. You MUST:\n')
|
|
151
|
-
parts.push('1. Show exactly what will change\n')
|
|
152
|
-
parts.push('2. List affected files/resources\n')
|
|
153
|
-
parts.push('3. Ask for explicit user confirmation (y/n)\n')
|
|
154
|
-
parts.push('4. Only proceed after approval\n')
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (planInfo.allowedTools) {
|
|
158
|
-
parts.push(`\nAllowed tools: ${planInfo.allowedTools.join(', ')}\n`)
|
|
159
|
-
}
|
|
179
|
+
// P3.4: Plan Mode (OPTIMIZED: 30 lines → 5 lines)
|
|
180
|
+
if (planInfo?.isPlanning) {
|
|
181
|
+
parts.push(`\n## PLAN MODE\nRead-only. Gather info → Analyze → Propose plan → Wait for approval.\n`)
|
|
182
|
+
if (planInfo.allowedTools) parts.push(`Tools: ${planInfo.allowedTools.join(', ')}\n`)
|
|
183
|
+
}
|
|
184
|
+
if (planInfo?.requiresApproval) {
|
|
185
|
+
parts.push(`\n## APPROVAL REQUIRED\nShow changes, list affected files, ask for confirmation.\n`)
|
|
160
186
|
}
|
|
161
187
|
|
|
162
188
|
// Simple execution directive
|
|
@@ -167,18 +193,33 @@ class PromptBuilder {
|
|
|
167
193
|
|
|
168
194
|
/**
|
|
169
195
|
* Filter only relevant state data
|
|
196
|
+
* IMPROVED: Include more context, don't truncate critical info
|
|
170
197
|
*/
|
|
171
198
|
filterRelevantState(state) {
|
|
172
199
|
if (!state || Object.keys(state).length === 0) return null
|
|
173
200
|
|
|
174
201
|
const relevant = []
|
|
175
202
|
for (const [key, content] of Object.entries(state)) {
|
|
176
|
-
if (content && content.trim()
|
|
177
|
-
|
|
203
|
+
if (content && content.trim()) {
|
|
204
|
+
// Include full content for critical files (now, next, context, patterns)
|
|
205
|
+
const criticalFiles = ['now', 'next', 'context', 'analysis', 'codePatterns']
|
|
206
|
+
if (criticalFiles.includes(key)) {
|
|
207
|
+
// Include full content for critical files (up to 2000 chars)
|
|
208
|
+
const display = content.length > 2000
|
|
209
|
+
? content.substring(0, 2000) + '\n... (truncated)'
|
|
210
|
+
: content
|
|
211
|
+
relevant.push(`### ${key}\n${display}`)
|
|
212
|
+
} else if (content.length < 1000) {
|
|
213
|
+
// Include full content for small files
|
|
214
|
+
relevant.push(`### ${key}\n${content}`)
|
|
215
|
+
} else {
|
|
216
|
+
// Truncate large files but show more context
|
|
217
|
+
relevant.push(`### ${key}\n${content.substring(0, 500)}... (truncated, use Read tool for full content)`)
|
|
218
|
+
}
|
|
178
219
|
}
|
|
179
220
|
}
|
|
180
221
|
|
|
181
|
-
return relevant.length > 0 ? relevant.join('\n') : null
|
|
222
|
+
return relevant.length > 0 ? relevant.join('\n\n') : null
|
|
182
223
|
}
|
|
183
224
|
|
|
184
225
|
/**
|
|
@@ -203,19 +244,22 @@ class PromptBuilder {
|
|
|
203
244
|
}
|
|
204
245
|
|
|
205
246
|
/**
|
|
206
|
-
* Build
|
|
207
|
-
*
|
|
247
|
+
* Build critical rules - compressed anti-hallucination
|
|
248
|
+
* OPTIMIZED: From 66 lines to 12 lines (~82% reduction)
|
|
208
249
|
*/
|
|
209
|
-
|
|
250
|
+
buildCriticalRules() {
|
|
251
|
+
const fileCount = this._currentContext?.files?.length || this._currentContext?.filteredSize || 0
|
|
210
252
|
return `
|
|
211
|
-
##
|
|
212
|
-
1.
|
|
213
|
-
2.
|
|
214
|
-
3.
|
|
215
|
-
4.
|
|
216
|
-
5.
|
|
253
|
+
## RULES (CRITICAL)
|
|
254
|
+
1. **READ FIRST**: Use Read tool BEFORE modifying any file. Never assume code structure.
|
|
255
|
+
2. **MATCH PATTERNS**: Follow existing style, architecture, naming, imports exactly.
|
|
256
|
+
3. **NO HALLUCINATIONS**: Don't invent files, functions, or paths. If unsure, READ first.
|
|
257
|
+
4. **GIT SAFETY**: Never use checkout/reset --hard/clean. Always check status first.
|
|
258
|
+
5. **VERIFY**: After writing, confirm code matches project patterns.
|
|
259
|
+
Context: ${fileCount} files available. Read what you need.
|
|
217
260
|
`;
|
|
218
261
|
}
|
|
262
|
+
|
|
219
263
|
}
|
|
220
264
|
|
|
221
265
|
module.exports = new PromptBuilder()
|