prjct-cli 0.10.5 → 0.10.8

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.
@@ -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,49 @@ 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('\nSTATE:\n')
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
- // Enforcement (Strict Mode)
94
- parts.push(this.buildEnforcement());
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 now, done, ship, recap, next don't need full patterns
117
+ const codeCommands = ['build', 'feature', 'design', 'cleanup', 'fix', 'bug', 'test', 'init']
118
+ const commandName = template.frontmatter?.name?.replace('p:', '') || ''
119
+ const needsPatterns = codeCommands.includes(commandName)
120
+
121
+ const analysisContent = state?.analysis || ''
122
+ if (needsPatterns && analysisContent && analysisContent.trim()) {
123
+ // Extract stack info compactly
124
+ const stackMatch = analysisContent.match(/Stack[:\s]+([^\n]+)/i) ||
125
+ analysisContent.match(/Technology[:\s]+([^\n]+)/i)
126
+ const stack = stackMatch ? stackMatch[1].trim() : 'detected'
127
+
128
+ parts.push(`\n## PATTERNS\nStack: ${stack}\n`)
129
+ parts.push('Read analysis/repo-summary.md + similar files before coding. Match patterns exactly.\n')
130
+ }
131
+
132
+ // CRITICAL: Compressed rules (replaces 78 lines with 12)
133
+ parts.push(this.buildCriticalRules());
95
134
 
96
135
  // P1.1: Learned Patterns (avoid asking user questions we already know)
97
136
  if (learnedPatterns && Object.keys(learnedPatterns).some(k => learnedPatterns[k])) {
@@ -126,37 +165,13 @@ class PromptBuilder {
126
165
  }
127
166
  }
128
167
 
129
- // P3.4: Plan Mode instructions
130
- if (planInfo) {
131
- if (planInfo.isPlanning) {
132
- parts.push('\n## PLAN MODE ACTIVE\n')
133
- parts.push('You are in PLANNING mode. Follow these constraints:\n')
134
- parts.push('1. **READ-ONLY**: Only use read tools (Read, Glob, Grep)\n')
135
- parts.push('2. **GATHER INFO**: Collect all necessary information\n')
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
- }
168
+ // P3.4: Plan Mode (OPTIMIZED: 30 lines → 5 lines)
169
+ if (planInfo?.isPlanning) {
170
+ parts.push(`\n## PLAN MODE\nRead-only. Gather info → Analyze → Propose plan → Wait for approval.\n`)
171
+ if (planInfo.allowedTools) parts.push(`Tools: ${planInfo.allowedTools.join(', ')}\n`)
172
+ }
173
+ if (planInfo?.requiresApproval) {
174
+ parts.push(`\n## APPROVAL REQUIRED\nShow changes, list affected files, ask for confirmation.\n`)
160
175
  }
161
176
 
162
177
  // Simple execution directive
@@ -167,18 +182,33 @@ class PromptBuilder {
167
182
 
168
183
  /**
169
184
  * Filter only relevant state data
185
+ * IMPROVED: Include more context, don't truncate critical info
170
186
  */
171
187
  filterRelevantState(state) {
172
188
  if (!state || Object.keys(state).length === 0) return null
173
189
 
174
190
  const relevant = []
175
191
  for (const [key, content] of Object.entries(state)) {
176
- if (content && content.trim() && content.length < 500) {
177
- relevant.push(`${key}: ${content.substring(0, 200)}`)
192
+ if (content && content.trim()) {
193
+ // Include full content for critical files (now, next, context)
194
+ const criticalFiles = ['now', 'next', 'context', 'analysis']
195
+ if (criticalFiles.includes(key)) {
196
+ // Include full content for critical files (up to 2000 chars)
197
+ const display = content.length > 2000
198
+ ? content.substring(0, 2000) + '\n... (truncated)'
199
+ : content
200
+ relevant.push(`### ${key}\n${display}`)
201
+ } else if (content.length < 1000) {
202
+ // Include full content for small files
203
+ relevant.push(`### ${key}\n${content}`)
204
+ } else {
205
+ // Truncate large files but show more context
206
+ relevant.push(`### ${key}\n${content.substring(0, 500)}... (truncated, use Read tool for full content)`)
207
+ }
178
208
  }
179
209
  }
180
210
 
181
- return relevant.length > 0 ? relevant.join('\n') : null
211
+ return relevant.length > 0 ? relevant.join('\n\n') : null
182
212
  }
183
213
 
184
214
  /**
@@ -203,19 +233,22 @@ class PromptBuilder {
203
233
  }
204
234
 
205
235
  /**
206
- * Build enforcement section
207
- * Forces Claude to follow the process strictly
236
+ * Build critical rules - compressed anti-hallucination
237
+ * OPTIMIZED: From 66 lines to 12 lines (~82% reduction)
208
238
  */
209
- buildEnforcement() {
239
+ buildCriticalRules() {
240
+ const fileCount = this._currentContext?.files?.length || this._currentContext?.filteredSize || 0
210
241
  return `
211
- ## PROCESS ENFORCEMENT
212
- 1. FOLLOW the Flow strictly. Do not skip steps.
213
- 2. USE the allowed tools only.
214
- 3. IF you are stuck, use the "Ask" tool or stop.
215
- 4. DO NOT hallucinate files or commands.
216
- 5. ALWAYS verify your changes.
242
+ ## RULES (CRITICAL)
243
+ 1. **READ FIRST**: Use Read tool BEFORE modifying any file. Never assume code structure.
244
+ 2. **MATCH PATTERNS**: Follow existing style, architecture, naming, imports exactly.
245
+ 3. **NO HALLUCINATIONS**: Don't invent files, functions, or paths. If unsure, READ first.
246
+ 4. **GIT SAFETY**: Never use checkout/reset --hard/clean. Always check status first.
247
+ 5. **VERIFY**: After writing, confirm code matches project patterns.
248
+ Context: ${fileCount} files available. Read what you need.
217
249
  `;
218
250
  }
251
+
219
252
  }
220
253
 
221
254
  module.exports = new PromptBuilder()