prjct-cli 0.10.0 → 0.10.3
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 +41 -0
- package/core/__tests__/agentic/memory-system.test.js +263 -0
- package/core/__tests__/agentic/plan-mode.test.js +336 -0
- package/core/agentic/chain-of-thought.js +578 -0
- package/core/agentic/command-executor.js +238 -4
- package/core/agentic/context-builder.js +208 -8
- package/core/agentic/ground-truth.js +591 -0
- package/core/agentic/loop-detector.js +406 -0
- package/core/agentic/memory-system.js +850 -0
- package/core/agentic/parallel-tools.js +366 -0
- package/core/agentic/plan-mode.js +572 -0
- package/core/agentic/prompt-builder.js +76 -1
- package/core/agentic/response-templates.js +290 -0
- package/core/agentic/semantic-compression.js +517 -0
- package/core/agentic/think-blocks.js +657 -0
- package/core/agentic/tool-registry.js +32 -0
- package/core/agentic/validation-rules.js +380 -0
- package/core/command-registry.js +48 -0
- package/core/commands.js +65 -1
- package/core/context-sync.js +183 -0
- package/package.json +7 -15
- package/templates/commands/done.md +7 -0
- package/templates/commands/feature.md +8 -0
- package/templates/commands/ship.md +8 -0
- package/templates/commands/spec.md +128 -0
- package/templates/global/CLAUDE.md +17 -0
- package/core/__tests__/agentic/agent-router.test.js +0 -398
- package/core/__tests__/agentic/command-executor.test.js +0 -223
- package/core/__tests__/agentic/context-builder.test.js +0 -160
- package/core/__tests__/agentic/context-filter.test.js +0 -494
- package/core/__tests__/agentic/prompt-builder.test.js +0 -204
- package/core/__tests__/agentic/template-loader.test.js +0 -164
- package/core/__tests__/agentic/tool-registry.test.js +0 -243
- package/core/__tests__/domain/agent-generator.test.js +0 -289
- package/core/__tests__/domain/agent-loader.test.js +0 -179
- package/core/__tests__/domain/analyzer.test.js +0 -324
- package/core/__tests__/infrastructure/author-detector.test.js +0 -103
- package/core/__tests__/infrastructure/config-manager.test.js +0 -454
- package/core/__tests__/infrastructure/path-manager.test.js +0 -412
- package/core/__tests__/setup.test.js +0 -15
- package/core/__tests__/utils/date-helper.test.js +0 -169
- package/core/__tests__/utils/file-helper.test.js +0 -258
- package/core/__tests__/utils/jsonl-helper.test.js +0 -387
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response Templates
|
|
3
|
+
* Minimal output templates for all commands
|
|
4
|
+
* Rule: < 4 lines, always actionable
|
|
5
|
+
*
|
|
6
|
+
* OPTIMIZATION (P0.3): Minimal Output
|
|
7
|
+
* - Concise responses (< 4 lines)
|
|
8
|
+
* - Always suggest next action
|
|
9
|
+
* - Use symbols for status, not words
|
|
10
|
+
*
|
|
11
|
+
* Source: Claude Code, Kiro patterns
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Format duration from milliseconds or ISO strings
|
|
16
|
+
* @param {number|string|Date} start - Start time
|
|
17
|
+
* @param {number|string|Date} end - End time (defaults to now)
|
|
18
|
+
* @returns {string} Human-readable duration
|
|
19
|
+
*/
|
|
20
|
+
function formatDuration(start, end = new Date()) {
|
|
21
|
+
const startMs = new Date(start).getTime()
|
|
22
|
+
const endMs = new Date(end).getTime()
|
|
23
|
+
const diffMs = endMs - startMs
|
|
24
|
+
|
|
25
|
+
const hours = Math.floor(diffMs / (1000 * 60 * 60))
|
|
26
|
+
const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60))
|
|
27
|
+
|
|
28
|
+
if (hours > 0) {
|
|
29
|
+
return `${hours}h ${minutes}m`
|
|
30
|
+
}
|
|
31
|
+
return `${minutes}m`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Truncate text to max length with ellipsis
|
|
36
|
+
* @param {string} text - Text to truncate
|
|
37
|
+
* @param {number} maxLength - Maximum length
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
function truncate(text, maxLength = 40) {
|
|
41
|
+
if (!text) return ''
|
|
42
|
+
if (text.length <= maxLength) return text
|
|
43
|
+
return text.substring(0, maxLength - 3) + '...'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Response templates for each command
|
|
48
|
+
* Each template is a function that returns minimal formatted output
|
|
49
|
+
*/
|
|
50
|
+
const templates = {
|
|
51
|
+
/**
|
|
52
|
+
* /p:done - Task completed
|
|
53
|
+
*/
|
|
54
|
+
done: ({ task, duration, nextTask }) => {
|
|
55
|
+
let output = `✓ '${truncate(task)}' (${duration})`
|
|
56
|
+
if (nextTask) {
|
|
57
|
+
output += `\n→ Next: '${truncate(nextTask)}'`
|
|
58
|
+
}
|
|
59
|
+
output += '\n\n/p:ship to release'
|
|
60
|
+
return output
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* /p:now - Current task set/shown
|
|
65
|
+
*/
|
|
66
|
+
now: ({ task, started, isNew }) => {
|
|
67
|
+
if (!task) {
|
|
68
|
+
return `No active task\n→ /p:now "task" to start`
|
|
69
|
+
}
|
|
70
|
+
if (isNew) {
|
|
71
|
+
return `🎯 Started: '${truncate(task)}'\n→ /p:done when complete`
|
|
72
|
+
}
|
|
73
|
+
return `🎯 Working on: '${truncate(task)}'\n⏱️ ${started || 'just now'}\n→ /p:done when complete`
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* /p:next - Priority queue
|
|
78
|
+
*/
|
|
79
|
+
next: ({ tasks, total }) => {
|
|
80
|
+
if (!tasks || tasks.length === 0) {
|
|
81
|
+
return `Queue empty\n→ /p:feature or /p:idea to add`
|
|
82
|
+
}
|
|
83
|
+
const top3 = tasks.slice(0, 3).map((t, i) =>
|
|
84
|
+
`${i + 1}. ${truncate(t.name, 35)}`
|
|
85
|
+
).join('\n')
|
|
86
|
+
const more = total > 3 ? `\n+${total - 3} more` : ''
|
|
87
|
+
return `${top3}${more}\n\n/p:now 1 to start`
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* /p:ship - Feature shipped
|
|
92
|
+
*/
|
|
93
|
+
ship: ({ feature, agent, duration, version }) => {
|
|
94
|
+
let output = `🚀 Shipped: '${truncate(feature)}'`
|
|
95
|
+
if (agent) output += ` (${agent})`
|
|
96
|
+
if (duration) output += ` | ${duration}`
|
|
97
|
+
if (version) output += ` | v${version}`
|
|
98
|
+
output += '\n→ /compact recommended'
|
|
99
|
+
return output
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* /p:idea - Idea captured
|
|
104
|
+
*/
|
|
105
|
+
idea: ({ idea, addedToQueue }) => {
|
|
106
|
+
let output = `💡 Captured: '${truncate(idea)}'`
|
|
107
|
+
if (addedToQueue) {
|
|
108
|
+
output += '\n→ Added to queue'
|
|
109
|
+
}
|
|
110
|
+
output += '\n\n/p:next to see queue'
|
|
111
|
+
return output
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* /p:feature - Feature added
|
|
116
|
+
*/
|
|
117
|
+
feature: ({ feature, tasks, impact, effort }) => {
|
|
118
|
+
let output = `📋 Feature: '${truncate(feature)}'`
|
|
119
|
+
if (tasks) output += ` (${tasks} tasks)`
|
|
120
|
+
if (impact) output += `\nImpact: ${impact}`
|
|
121
|
+
if (effort) output += ` | Effort: ${effort}`
|
|
122
|
+
output += '\n\n/p:now to start'
|
|
123
|
+
return output
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* /p:bug - Bug reported
|
|
128
|
+
*/
|
|
129
|
+
bug: ({ description, priority, addedAt }) => {
|
|
130
|
+
const priorityIcon = {
|
|
131
|
+
'critical': '🔴',
|
|
132
|
+
'high': '🟠',
|
|
133
|
+
'medium': '🟡',
|
|
134
|
+
'low': '🟢'
|
|
135
|
+
}[priority] || '🟡'
|
|
136
|
+
|
|
137
|
+
let output = `${priorityIcon} Bug: '${truncate(description)}'\nPriority: ${priority}`
|
|
138
|
+
if (addedAt) {
|
|
139
|
+
output += ` | Added: ${addedAt}`
|
|
140
|
+
}
|
|
141
|
+
output += '\n\n/p:now to fix'
|
|
142
|
+
return output
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* /p:pause - Task paused
|
|
147
|
+
*/
|
|
148
|
+
pause: ({ task, duration }) => {
|
|
149
|
+
return `⏸️ Paused: '${truncate(task)}' (${duration})\n→ /p:resume to continue`
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* /p:resume - Task resumed
|
|
154
|
+
*/
|
|
155
|
+
resume: ({ task, pausedFor }) => {
|
|
156
|
+
return `▶️ Resumed: '${truncate(task)}'\nPaused for: ${pausedFor}\n→ /p:done when complete`
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* /p:recap - Project overview
|
|
161
|
+
*/
|
|
162
|
+
recap: ({ shipped, inProgress, queued, momentum }) => {
|
|
163
|
+
const momentumIcon = {
|
|
164
|
+
'high': '🔥',
|
|
165
|
+
'medium': '✨',
|
|
166
|
+
'low': '💤'
|
|
167
|
+
}[momentum] || '✨'
|
|
168
|
+
|
|
169
|
+
return `${momentumIcon} ${shipped} shipped | ${inProgress ? '1 active' : '0 active'} | ${queued} queued`
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* /p:progress - Progress metrics
|
|
174
|
+
*/
|
|
175
|
+
progress: ({ period, shipped, velocity, trend }) => {
|
|
176
|
+
const trendIcon = trend > 0 ? '↑' : trend < 0 ? '↓' : '→'
|
|
177
|
+
return `📊 ${period}: ${shipped} shipped\nVelocity: ${velocity}/week ${trendIcon}`
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* /p:analyze - Analysis complete
|
|
182
|
+
*/
|
|
183
|
+
analyze: ({ stack, files, agents }) => {
|
|
184
|
+
return `🔍 Analyzed: ${stack}\n${files} files | ${agents} agents generated\n\n/p:sync to update`
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* /p:sync - Sync complete
|
|
189
|
+
*/
|
|
190
|
+
sync: ({ updated, agents }) => {
|
|
191
|
+
return `🔄 Synced: ${updated} files updated\n${agents} agents refreshed`
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* /p:help - Help shown
|
|
196
|
+
*/
|
|
197
|
+
help: ({ context, suggestions }) => {
|
|
198
|
+
const sugs = suggestions.slice(0, 3).map(s => `• ${s}`).join('\n')
|
|
199
|
+
return `📚 ${context}\n\n${sugs}`
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* /p:suggest - Suggestions
|
|
204
|
+
*/
|
|
205
|
+
suggest: ({ urgency, suggestion, command }) => {
|
|
206
|
+
const urgencyIcon = {
|
|
207
|
+
'high': '🔥',
|
|
208
|
+
'medium': '💡',
|
|
209
|
+
'low': '✨'
|
|
210
|
+
}[urgency] || '💡'
|
|
211
|
+
|
|
212
|
+
return `${urgencyIcon} ${suggestion}\n→ ${command}`
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* /p:spec - Spec created/updated
|
|
217
|
+
*/
|
|
218
|
+
spec: ({ name, status, tasks, requirements, isNew }) => {
|
|
219
|
+
let output = isNew
|
|
220
|
+
? `📋 Created spec: '${truncate(name)}'`
|
|
221
|
+
: `📋 Updated spec: '${truncate(name)}'`
|
|
222
|
+
|
|
223
|
+
if (requirements) output += `\n${requirements} requirements`
|
|
224
|
+
if (tasks) output += ` | ${tasks} tasks`
|
|
225
|
+
if (status) output += ` | Status: ${status}`
|
|
226
|
+
|
|
227
|
+
output += '\n\n→ Review and approve to start'
|
|
228
|
+
return output
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Generic success response
|
|
233
|
+
*/
|
|
234
|
+
success: ({ message, nextAction }) => {
|
|
235
|
+
let output = `✓ ${message}`
|
|
236
|
+
if (nextAction) {
|
|
237
|
+
output += `\n→ ${nextAction}`
|
|
238
|
+
}
|
|
239
|
+
return output
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Generic error response
|
|
244
|
+
*/
|
|
245
|
+
error: ({ error, suggestion }) => {
|
|
246
|
+
let output = `❌ ${error}`
|
|
247
|
+
if (suggestion) {
|
|
248
|
+
output += `\n→ ${suggestion}`
|
|
249
|
+
}
|
|
250
|
+
return output
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Format a response using the appropriate template
|
|
256
|
+
*
|
|
257
|
+
* @param {string} commandName - Command name
|
|
258
|
+
* @param {Object} data - Data for the template
|
|
259
|
+
* @returns {string} Formatted response
|
|
260
|
+
*/
|
|
261
|
+
function format(commandName, data) {
|
|
262
|
+
const template = templates[commandName]
|
|
263
|
+
if (!template) {
|
|
264
|
+
// Fallback to generic success/error
|
|
265
|
+
if (data.error) {
|
|
266
|
+
return templates.error(data)
|
|
267
|
+
}
|
|
268
|
+
return templates.success(data)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return template(data)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Check if response exceeds recommended length
|
|
276
|
+
* @param {string} response - Response text
|
|
277
|
+
* @returns {boolean} True if too long
|
|
278
|
+
*/
|
|
279
|
+
function isTooLong(response) {
|
|
280
|
+
const lines = response.split('\n').filter(l => l.trim())
|
|
281
|
+
return lines.length > 4
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
module.exports = {
|
|
285
|
+
format,
|
|
286
|
+
templates,
|
|
287
|
+
formatDuration,
|
|
288
|
+
truncate,
|
|
289
|
+
isTooLong
|
|
290
|
+
}
|