prjct-cli 0.10.9 → 0.10.11

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.
@@ -143,7 +143,9 @@ describe('PromptBuilder', () => {
143
143
 
144
144
  const prompt = builder.build(template, context, state)
145
145
 
146
- expect(prompt).toContain('AVAILABLE PROJECT FILES')
146
+ // OPTIMIZED: New compressed format uses ## FILES:
147
+ expect(prompt).toContain('## FILES:')
148
+ expect(prompt).toContain('3 available')
147
149
  expect(prompt).toContain('file1.js')
148
150
  expect(prompt).toContain('Read')
149
151
  })
@@ -159,7 +161,8 @@ describe('PromptBuilder', () => {
159
161
 
160
162
  const prompt = builder.build(template, context, state)
161
163
 
162
- expect(prompt).toContain('PROJECT FILES')
164
+ // OPTIMIZED: New compressed format uses ## PROJECT:
165
+ expect(prompt).toContain('## PROJECT:')
163
166
  expect(prompt).toContain('/test/project')
164
167
  })
165
168
  })
@@ -188,7 +191,8 @@ describe('PromptBuilder', () => {
188
191
  expect(prompt).toContain('TOOLS:')
189
192
  expect(prompt).toContain('Flow')
190
193
  expect(prompt).toContain('RULES (CRITICAL)')
191
- expect(prompt).toContain('AVAILABLE PROJECT FILES')
194
+ // OPTIMIZED: New compressed format uses ## FILES:
195
+ expect(prompt).toContain('## FILES:')
192
196
  })
193
197
 
194
198
  it('should be concise (under 2000 chars for simple prompt)', () => {
@@ -24,41 +24,18 @@ class PromptBuilder {
24
24
  // Store context for use in helper methods
25
25
  this._currentContext = context
26
26
 
27
- // Agent assignment (if applicable)
28
- // CRITICAL: Include full agent content, not just name
29
- if (agent) {
30
- parts.push(`# AGENT ASSIGNMENT\n`)
31
- parts.push(`Agent: ${agent.name}\n`)
32
-
33
- // Include role if available
34
- if (agent.role) {
35
- parts.push(`Role: ${agent.role}\n`)
36
- }
37
-
38
- // Include domain if available
39
- if (agent.domain) {
40
- parts.push(`Domain: ${agent.domain}\n`)
41
- }
42
-
43
- // Include skills if available
44
- if (agent.skills && agent.skills.length > 0) {
45
- parts.push(`Skills: ${agent.skills.join(', ')}\n`)
46
- }
47
-
48
- parts.push(`\n## AGENT INSTRUCTIONS\n`)
49
-
50
- // CRITICAL: Include full agent content
51
- // This is the specialized knowledge for this project
52
- if (agent.content) {
53
- parts.push(agent.content)
54
- parts.push(`\n`)
55
- } else if (agent.name) {
56
- // Fallback if content not loaded
57
- parts.push(`You are the ${agent.name} agent for this project.\n`)
58
- parts.push(`Apply your specialized expertise to complete the task.\n\n`)
59
- }
60
-
61
- parts.push(`CONTEXT: ${context.filteredSize || 'all'} files (${context.reduction || 0}% reduced)\n\n`)
27
+ // Agent assignment (CONDITIONAL - only for code-modifying commands)
28
+ // Commands like done, ship, recap, next don't need specialized agents
29
+ const commandName = template.frontmatter?.name?.replace('p:', '') || ''
30
+ const agentCommands = ['now', 'build', 'feature', 'design', 'fix', 'bug', 'test', 'work', 'cleanup', 'spec']
31
+ const needsAgent = agentCommands.includes(commandName)
32
+
33
+ if (agent && needsAgent) {
34
+ // COMPRESSED: Only essential agent info (500 bytes vs 3-5KB)
35
+ parts.push(`# AGENT: ${agent.name}\n`)
36
+ if (agent.role) parts.push(`Role: ${agent.role}\n`)
37
+ if (agent.skills?.length) parts.push(`Skills: ${agent.skills.join(', ')}\n`)
38
+ parts.push(`\nApply specialized expertise. Read agent file for details if needed.\n\n`)
62
39
  }
63
40
 
64
41
  // Core instruction (concise)
@@ -93,38 +70,30 @@ class PromptBuilder {
93
70
  parts.push('\n')
94
71
  }
95
72
 
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')
73
+ // COMPRESSED: File list (5 files vs 20, saves ~400 bytes)
74
+ if (context.files?.length > 0) {
75
+ const top5 = context.files.slice(0, 5).join(', ')
76
+ parts.push(`\n## FILES: ${context.files.length} available. Top: ${top5}\n`)
77
+ parts.push('Read BEFORE modifying. Use Glob/Grep to find more.\n\n')
108
78
  } 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')
79
+ parts.push(`\n## PROJECT: ${context.projectPath}\nRead files before modifying.\n\n`)
113
80
  }
114
81
 
115
82
  // OPTIMIZED: Only include patterns for code-modifying commands
116
83
  // Commands like done, ship, recap, next don't need full patterns
117
84
  const codeCommands = ['now', 'build', 'feature', 'design', 'cleanup', 'fix', 'bug', 'test', 'init', 'spec', 'work']
118
- const commandName = template.frontmatter?.name?.replace('p:', '') || ''
119
85
  const needsPatterns = codeCommands.includes(commandName)
120
86
 
121
87
  // Include code patterns analysis for code-modifying commands
88
+ // COMPRESSED: Extract only conventions and anti-patterns (800 bytes max vs 6KB)
122
89
  const codePatternsContent = state?.codePatterns || ''
123
90
  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')
91
+ const patternSummary = this.extractPatternSummary(codePatternsContent)
92
+ if (patternSummary) {
93
+ parts.push('\n## CODE PATTERNS\n')
94
+ parts.push(patternSummary)
95
+ parts.push('\nFull patterns: Read analysis/patterns.md\n')
96
+ }
128
97
  }
129
98
 
130
99
  const analysisContent = state?.analysis || ''
@@ -243,6 +212,38 @@ class PromptBuilder {
243
212
  return parts.join('')
244
213
  }
245
214
 
215
+ /**
216
+ * Extract pattern summary from full patterns content
217
+ * OPTIMIZED: Returns only conventions + high-priority anti-patterns (800 bytes max)
218
+ */
219
+ extractPatternSummary(content) {
220
+ if (!content) return null
221
+
222
+ const parts = []
223
+
224
+ // Extract conventions section
225
+ const conventionsMatch = content.match(/## Conventions[\s\S]*?(?=##|$)/i)
226
+ if (conventionsMatch) {
227
+ // Compress to key lines only
228
+ const conventions = conventionsMatch[0]
229
+ .split('\n')
230
+ .filter(line => line.includes(':') || line.startsWith('-'))
231
+ .slice(0, 6)
232
+ .join('\n')
233
+ if (conventions) parts.push(conventions)
234
+ }
235
+
236
+ // Extract high priority anti-patterns only
237
+ const antiPatternsMatch = content.match(/### High Priority[\s\S]*?(?=###|##|$)/i)
238
+ if (antiPatternsMatch) {
239
+ const antiPatterns = antiPatternsMatch[0].substring(0, 300)
240
+ parts.push('\nAvoid:\n' + antiPatterns)
241
+ }
242
+
243
+ const result = parts.join('\n').substring(0, 800)
244
+ return result || null
245
+ }
246
+
246
247
  /**
247
248
  * Build critical rules - compressed anti-hallucination
248
249
  * OPTIMIZED: From 66 lines to 12 lines (~82% reduction)