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,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Rules
|
|
3
|
+
* Explicit pre-flight checks for each command
|
|
4
|
+
* Returns SPECIFIC error messages, never generic failures
|
|
5
|
+
*
|
|
6
|
+
* OPTIMIZATION (P0.2): Anti-Hallucination Pattern
|
|
7
|
+
* - Ground truth verification before actions
|
|
8
|
+
* - Specific error messages for each failure mode
|
|
9
|
+
* - Actionable suggestions in every error
|
|
10
|
+
*
|
|
11
|
+
* Source: Claude Code, Devin, Augment Code patterns
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const contextBuilder = require('./context-builder')
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Validation result structure
|
|
18
|
+
* @typedef {Object} ValidationResult
|
|
19
|
+
* @property {boolean} valid - Whether validation passed
|
|
20
|
+
* @property {string|null} error - Specific error message if invalid
|
|
21
|
+
* @property {string|null} suggestion - Actionable next step
|
|
22
|
+
* @property {Object} state - Pre-loaded state for command execution
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Command-specific validation rules
|
|
27
|
+
* Each rule returns { valid, error, suggestion, state }
|
|
28
|
+
*/
|
|
29
|
+
const validationRules = {
|
|
30
|
+
/**
|
|
31
|
+
* /p:done - Complete current task
|
|
32
|
+
*/
|
|
33
|
+
async done(context) {
|
|
34
|
+
const state = await contextBuilder.loadStateForCommand(context, 'done')
|
|
35
|
+
|
|
36
|
+
// Check 1: now.md exists and has content
|
|
37
|
+
if (!state.now || state.now.trim() === '') {
|
|
38
|
+
return {
|
|
39
|
+
valid: false,
|
|
40
|
+
error: 'No active task to complete',
|
|
41
|
+
suggestion: 'Start a task first with /p:now "task description"',
|
|
42
|
+
state
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Check 2: Task is not a placeholder/comment
|
|
47
|
+
const content = state.now.trim()
|
|
48
|
+
if (content.startsWith('#') && content.split('\n').length === 1) {
|
|
49
|
+
return {
|
|
50
|
+
valid: false,
|
|
51
|
+
error: 'now.md contains only a header, no task description',
|
|
52
|
+
suggestion: 'Add task details or start fresh with /p:now "task"',
|
|
53
|
+
state
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check 3: Task is not blocked
|
|
58
|
+
if (content.toLowerCase().includes('blocked') ||
|
|
59
|
+
content.toLowerCase().includes('waiting for')) {
|
|
60
|
+
return {
|
|
61
|
+
valid: false,
|
|
62
|
+
error: 'Task appears to be blocked',
|
|
63
|
+
suggestion: 'Resolve the blocker first or use /p:pause to save progress',
|
|
64
|
+
state
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* /p:ship - Ship a feature
|
|
73
|
+
*/
|
|
74
|
+
async ship(context) {
|
|
75
|
+
const state = await contextBuilder.loadStateForCommand(context, 'ship')
|
|
76
|
+
|
|
77
|
+
// Check 1: Has something to ship (now.md or recent shipped items)
|
|
78
|
+
const hasCurrentTask = state.now && state.now.trim() !== ''
|
|
79
|
+
const hasRecentShips = state.shipped && state.shipped.trim() !== ''
|
|
80
|
+
|
|
81
|
+
if (!hasCurrentTask && !hasRecentShips) {
|
|
82
|
+
return {
|
|
83
|
+
valid: false,
|
|
84
|
+
error: 'Nothing to ship yet',
|
|
85
|
+
suggestion: 'Build something first with /p:now "feature name"',
|
|
86
|
+
state
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check 2: Feature name provided (from params)
|
|
91
|
+
if (!context.params.feature && !context.params.description) {
|
|
92
|
+
// Try to extract from now.md
|
|
93
|
+
if (hasCurrentTask) {
|
|
94
|
+
// Auto-extract feature name - this is OK
|
|
95
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
valid: false,
|
|
99
|
+
error: 'No feature name specified',
|
|
100
|
+
suggestion: 'Specify what to ship: /p:ship "feature name"',
|
|
101
|
+
state
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* /p:now - Set or show current task
|
|
110
|
+
*/
|
|
111
|
+
async now(context) {
|
|
112
|
+
const state = await contextBuilder.loadStateForCommand(context, 'now')
|
|
113
|
+
|
|
114
|
+
// If no task param, this is a "show" request - always valid
|
|
115
|
+
if (!context.params.task && !context.params.description) {
|
|
116
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check: If setting new task, warn if one exists
|
|
120
|
+
if (state.now && state.now.trim() !== '') {
|
|
121
|
+
return {
|
|
122
|
+
valid: true, // Still valid, but with warning
|
|
123
|
+
error: null,
|
|
124
|
+
suggestion: `Note: Replacing current task. Use /p:done first to track completion.`,
|
|
125
|
+
state
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* /p:next - Show priority queue
|
|
134
|
+
*/
|
|
135
|
+
async next(context) {
|
|
136
|
+
const state = await contextBuilder.loadStateForCommand(context, 'next')
|
|
137
|
+
|
|
138
|
+
if (!state.next || state.next.trim() === '' ||
|
|
139
|
+
!state.next.includes('- [')) {
|
|
140
|
+
return {
|
|
141
|
+
valid: true, // Valid but empty
|
|
142
|
+
error: null,
|
|
143
|
+
suggestion: 'Queue is empty. Add tasks with /p:feature or /p:idea',
|
|
144
|
+
state
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* /p:idea - Capture an idea
|
|
153
|
+
*/
|
|
154
|
+
async idea(context) {
|
|
155
|
+
const state = await contextBuilder.loadStateForCommand(context, 'idea')
|
|
156
|
+
|
|
157
|
+
// Check: Idea text provided
|
|
158
|
+
if (!context.params.text && !context.params.description) {
|
|
159
|
+
return {
|
|
160
|
+
valid: false,
|
|
161
|
+
error: 'No idea text provided',
|
|
162
|
+
suggestion: 'Provide your idea: /p:idea "your idea here"',
|
|
163
|
+
state
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* /p:feature - Add a new feature
|
|
172
|
+
*/
|
|
173
|
+
async feature(context) {
|
|
174
|
+
const state = await contextBuilder.loadStateForCommand(context, 'feature')
|
|
175
|
+
|
|
176
|
+
// If no description, show interactive template - valid
|
|
177
|
+
if (!context.params.description && !context.params.feature) {
|
|
178
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* /p:pause - Pause current task
|
|
186
|
+
*/
|
|
187
|
+
async pause(context) {
|
|
188
|
+
const state = await contextBuilder.loadStateForCommand(context, 'now')
|
|
189
|
+
|
|
190
|
+
if (!state.now || state.now.trim() === '') {
|
|
191
|
+
return {
|
|
192
|
+
valid: false,
|
|
193
|
+
error: 'No active task to pause',
|
|
194
|
+
suggestion: 'Start a task first with /p:now "task"',
|
|
195
|
+
state
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* /p:resume - Resume paused task
|
|
204
|
+
*/
|
|
205
|
+
async resume(context) {
|
|
206
|
+
const state = await contextBuilder.loadState(context, ['now'])
|
|
207
|
+
|
|
208
|
+
// Check if there's a paused state to resume
|
|
209
|
+
// This would need to check a paused.md or similar
|
|
210
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* /p:recap - Show project overview
|
|
215
|
+
*/
|
|
216
|
+
async recap(context) {
|
|
217
|
+
const state = await contextBuilder.loadStateForCommand(context, 'recap')
|
|
218
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* /p:progress - Show progress metrics
|
|
223
|
+
*/
|
|
224
|
+
async progress(context) {
|
|
225
|
+
const state = await contextBuilder.loadStateForCommand(context, 'progress')
|
|
226
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* /p:analyze - Analyze repository
|
|
231
|
+
*/
|
|
232
|
+
async analyze(context) {
|
|
233
|
+
const state = await contextBuilder.loadStateForCommand(context, 'analyze')
|
|
234
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* /p:sync - Sync project state
|
|
239
|
+
*/
|
|
240
|
+
async sync(context) {
|
|
241
|
+
const state = await contextBuilder.loadStateForCommand(context, 'sync')
|
|
242
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* /p:bug - Report a bug
|
|
247
|
+
*/
|
|
248
|
+
async bug(context) {
|
|
249
|
+
const state = await contextBuilder.loadState(context, ['next'])
|
|
250
|
+
|
|
251
|
+
if (!context.params.description && !context.params.bug) {
|
|
252
|
+
return {
|
|
253
|
+
valid: false,
|
|
254
|
+
error: 'No bug description provided',
|
|
255
|
+
suggestion: 'Describe the bug: /p:bug "description of the issue"',
|
|
256
|
+
state
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* /p:help - Show help
|
|
265
|
+
*/
|
|
266
|
+
async help(context) {
|
|
267
|
+
const state = await contextBuilder.loadStateForCommand(context, 'now')
|
|
268
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* /p:ask - Intent translator
|
|
273
|
+
*/
|
|
274
|
+
async ask(context) {
|
|
275
|
+
if (!context.params.query && !context.params.question) {
|
|
276
|
+
return {
|
|
277
|
+
valid: false,
|
|
278
|
+
error: 'No question provided',
|
|
279
|
+
suggestion: 'Ask what you want to do: /p:ask "how do I..."',
|
|
280
|
+
state: {}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return { valid: true, error: null, suggestion: null, state: {} }
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* /p:suggest - Smart suggestions
|
|
289
|
+
*/
|
|
290
|
+
async suggest(context) {
|
|
291
|
+
const state = await contextBuilder.loadState(context, ['now', 'next', 'shipped', 'metrics'])
|
|
292
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* /p:spec - Spec-driven development
|
|
297
|
+
*/
|
|
298
|
+
async spec(context) {
|
|
299
|
+
const state = await contextBuilder.loadState(context, ['roadmap', 'next'])
|
|
300
|
+
|
|
301
|
+
// If no feature name, this is a "show template" request - always valid
|
|
302
|
+
if (!context.params.feature && !context.params.name && !context.params.description) {
|
|
303
|
+
return {
|
|
304
|
+
valid: true,
|
|
305
|
+
error: null,
|
|
306
|
+
suggestion: 'Provide a feature name to create a spec',
|
|
307
|
+
state
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Check queue capacity for new tasks
|
|
312
|
+
const queueContent = state.next || ''
|
|
313
|
+
const taskCount = (queueContent.match(/- \[[ x]\]/g) || []).length
|
|
314
|
+
if (taskCount >= 95) {
|
|
315
|
+
return {
|
|
316
|
+
valid: false,
|
|
317
|
+
error: 'Queue almost full (95+ tasks)',
|
|
318
|
+
suggestion: 'Complete some tasks before creating a new spec. Use /p:done',
|
|
319
|
+
state
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return { valid: true, error: null, suggestion: null, state }
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Validate command before execution
|
|
329
|
+
*
|
|
330
|
+
* @param {string} commandName - Command to validate
|
|
331
|
+
* @param {Object} context - Built context from contextBuilder
|
|
332
|
+
* @returns {Promise<ValidationResult>}
|
|
333
|
+
*/
|
|
334
|
+
async function validate(commandName, context) {
|
|
335
|
+
const validator = validationRules[commandName]
|
|
336
|
+
|
|
337
|
+
if (!validator) {
|
|
338
|
+
// No specific validation - default to valid
|
|
339
|
+
return {
|
|
340
|
+
valid: true,
|
|
341
|
+
error: null,
|
|
342
|
+
suggestion: null,
|
|
343
|
+
state: await contextBuilder.loadState(context)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
return await validator(context)
|
|
349
|
+
} catch (error) {
|
|
350
|
+
return {
|
|
351
|
+
valid: false,
|
|
352
|
+
error: `Validation error: ${error.message}`,
|
|
353
|
+
suggestion: 'Check file permissions and project configuration',
|
|
354
|
+
state: {}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Format validation error for display
|
|
361
|
+
* Minimal, actionable output
|
|
362
|
+
*
|
|
363
|
+
* @param {ValidationResult} result - Validation result
|
|
364
|
+
* @returns {string} Formatted error message
|
|
365
|
+
*/
|
|
366
|
+
function formatError(result) {
|
|
367
|
+
if (result.valid) return null
|
|
368
|
+
|
|
369
|
+
let output = `ā ${result.error}`
|
|
370
|
+
if (result.suggestion) {
|
|
371
|
+
output += `\nā ${result.suggestion}`
|
|
372
|
+
}
|
|
373
|
+
return output
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
module.exports = {
|
|
377
|
+
validate,
|
|
378
|
+
formatError,
|
|
379
|
+
validationRules
|
|
380
|
+
}
|
package/core/command-registry.js
CHANGED
|
@@ -88,6 +88,31 @@ const COMMANDS = [
|
|
|
88
88
|
],
|
|
89
89
|
},
|
|
90
90
|
|
|
91
|
+
// 3.5. Spec-Driven Development (P1.2)
|
|
92
|
+
{
|
|
93
|
+
name: 'spec',
|
|
94
|
+
category: 'core',
|
|
95
|
+
description: 'Create detailed specifications for complex features',
|
|
96
|
+
usage: {
|
|
97
|
+
claude: '/p:spec "Dark Mode"',
|
|
98
|
+
terminal: 'prjct spec "Dark Mode"',
|
|
99
|
+
},
|
|
100
|
+
params: '[feature]',
|
|
101
|
+
implemented: true,
|
|
102
|
+
hasTemplate: true,
|
|
103
|
+
icon: 'FileText',
|
|
104
|
+
requiresInit: true,
|
|
105
|
+
blockingRules: null,
|
|
106
|
+
features: [
|
|
107
|
+
'Requirements documentation',
|
|
108
|
+
'Design decisions tracking',
|
|
109
|
+
'Tasks broken into 20-30min chunks',
|
|
110
|
+
'User approval workflow',
|
|
111
|
+
'Auto-add tasks to queue on approve',
|
|
112
|
+
'Integrates with /p:feature',
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
|
|
91
116
|
// 4. Work - Unified task management (replaces now + build)
|
|
92
117
|
{
|
|
93
118
|
name: 'work',
|
|
@@ -346,6 +371,29 @@ const COMMANDS = [
|
|
|
346
371
|
blockingRules: null,
|
|
347
372
|
isOptional: true,
|
|
348
373
|
},
|
|
374
|
+
{
|
|
375
|
+
name: 'spec',
|
|
376
|
+
category: 'optional',
|
|
377
|
+
description: 'Spec-driven development for complex features',
|
|
378
|
+
usage: {
|
|
379
|
+
claude: '/p:spec "Dark Mode"',
|
|
380
|
+
terminal: 'prjct spec "Dark Mode"',
|
|
381
|
+
},
|
|
382
|
+
params: '[feature_name]',
|
|
383
|
+
implemented: true,
|
|
384
|
+
hasTemplate: true,
|
|
385
|
+
icon: 'FileText',
|
|
386
|
+
requiresInit: true,
|
|
387
|
+
blockingRules: null,
|
|
388
|
+
isOptional: true,
|
|
389
|
+
features: [
|
|
390
|
+
'Clear requirements before coding',
|
|
391
|
+
'Design decisions documented',
|
|
392
|
+
'Tasks broken into 20-30 min chunks',
|
|
393
|
+
'User approval before starting',
|
|
394
|
+
'Auto-adds tasks to queue on approval',
|
|
395
|
+
],
|
|
396
|
+
},
|
|
349
397
|
{
|
|
350
398
|
name: 'cleanup',
|
|
351
399
|
category: 'optional',
|
package/core/commands.js
CHANGED
|
@@ -21,6 +21,7 @@ const path = require('path')
|
|
|
21
21
|
const commandExecutor = require('./agentic/command-executor')
|
|
22
22
|
const contextBuilder = require('./agentic/context-builder')
|
|
23
23
|
const toolRegistry = require('./agentic/tool-registry')
|
|
24
|
+
const memorySystem = require('./agentic/memory-system')
|
|
24
25
|
const pathManager = require('./infrastructure/path-manager')
|
|
25
26
|
const configManager = require('./infrastructure/config-manager')
|
|
26
27
|
const authorDetector = require('./infrastructure/author-detector')
|
|
@@ -306,6 +307,7 @@ class PrjctCommands {
|
|
|
306
307
|
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
307
308
|
|
|
308
309
|
// Create base files
|
|
310
|
+
// P1.1: Added patterns.json for Layered Memory System
|
|
309
311
|
const baseFiles = {
|
|
310
312
|
'core/now.md': '# NOW\n\nNo current task. Use `/p:now` to set focus.\n',
|
|
311
313
|
'core/next.md': '# NEXT\n\n## Priority Queue\n\n',
|
|
@@ -314,7 +316,15 @@ class PrjctCommands {
|
|
|
314
316
|
'progress/metrics.md': '# METRICS\n\n',
|
|
315
317
|
'planning/ideas.md': '# IDEAS š”\n\n## Brain Dump\n\n',
|
|
316
318
|
'planning/roadmap.md': '# ROADMAP\n\n',
|
|
319
|
+
'planning/specs/.gitkeep': '# Specs directory - created by /p:spec\n',
|
|
317
320
|
'memory/context.jsonl': '',
|
|
321
|
+
'memory/patterns.json': JSON.stringify({
|
|
322
|
+
version: 1,
|
|
323
|
+
decisions: {},
|
|
324
|
+
preferences: {},
|
|
325
|
+
workflows: {},
|
|
326
|
+
counters: {}
|
|
327
|
+
}, null, 2),
|
|
318
328
|
}
|
|
319
329
|
|
|
320
330
|
for (const [filePath, content] of Object.entries(baseFiles)) {
|
|
@@ -379,9 +389,17 @@ class PrjctCommands {
|
|
|
379
389
|
console.log(' Custom: Describe your preferred stack\n')
|
|
380
390
|
console.log('Which option do you prefer? (Respond to continue setup)')
|
|
381
391
|
|
|
392
|
+
// Update global CLAUDE.md with latest instructions
|
|
393
|
+
const commandInstaller = require('./infrastructure/command-installer')
|
|
394
|
+
await commandInstaller.installGlobalConfig()
|
|
395
|
+
|
|
382
396
|
return { success: true, mode: 'architect', projectId, idea }
|
|
383
397
|
}
|
|
384
398
|
|
|
399
|
+
// Update global CLAUDE.md with latest instructions (fallback for any case)
|
|
400
|
+
const commandInstaller = require('./infrastructure/command-installer')
|
|
401
|
+
await commandInstaller.installGlobalConfig()
|
|
402
|
+
|
|
385
403
|
return { success: true, projectId }
|
|
386
404
|
} catch (error) {
|
|
387
405
|
console.error('ā Error:', error.message)
|
|
@@ -693,6 +711,27 @@ class PrjctCommands {
|
|
|
693
711
|
timestamp: dateHelper.getTimestamp(),
|
|
694
712
|
})
|
|
695
713
|
|
|
714
|
+
// P1.1: Learn patterns from this ship
|
|
715
|
+
const config = await configManager.getConfig(projectPath)
|
|
716
|
+
const projectId = config.projectId
|
|
717
|
+
|
|
718
|
+
// Record shipping workflow patterns
|
|
719
|
+
await memorySystem.learnDecision(projectId, 'commit_footer', 'prjct', 'ship')
|
|
720
|
+
|
|
721
|
+
// Track if tests were run (for quick_ship pattern learning)
|
|
722
|
+
if (testResult.success) {
|
|
723
|
+
await memorySystem.recordDecision(projectId, 'test_before_ship', 'true', 'ship')
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Record workflow if it's a quick ship (small changes)
|
|
727
|
+
const isQuickShip = !lintResult.success || !testResult.success
|
|
728
|
+
if (isQuickShip) {
|
|
729
|
+
await memorySystem.recordWorkflow(projectId, 'quick_ship', {
|
|
730
|
+
description: 'Ship without full checks',
|
|
731
|
+
feature_type: feature.toLowerCase().includes('doc') ? 'docs' : 'other'
|
|
732
|
+
})
|
|
733
|
+
}
|
|
734
|
+
|
|
696
735
|
console.log('\nš Feature shipped successfully!\n')
|
|
697
736
|
console.log('š” Recommendation: Compact conversation now')
|
|
698
737
|
console.log(' (Keeps context clean for next feature)\n')
|
|
@@ -2316,8 +2355,21 @@ Agent: ${agent}
|
|
|
2316
2355
|
gitCommits: analysisData.gitStats.totalCommits,
|
|
2317
2356
|
})
|
|
2318
2357
|
|
|
2358
|
+
// Generate dynamic context for Claude
|
|
2359
|
+
const contextSync = require('./context-sync')
|
|
2360
|
+
const projectId = await configManager.getProjectId(projectPath)
|
|
2361
|
+
await contextSync.generateLocalContext(projectPath, projectId)
|
|
2362
|
+
|
|
2363
|
+
// Update global CLAUDE.md with latest instructions
|
|
2364
|
+
const commandInstaller = require('./infrastructure/command-installer')
|
|
2365
|
+
const globalConfigResult = await commandInstaller.installGlobalConfig()
|
|
2366
|
+
if (globalConfigResult.success) {
|
|
2367
|
+
console.log('š Updated ~/.claude/CLAUDE.md')
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2319
2370
|
console.log('ā
Analysis complete!\n')
|
|
2320
|
-
console.log('š Full report: analysis/repo-summary.md
|
|
2371
|
+
console.log('š Full report: analysis/repo-summary.md')
|
|
2372
|
+
console.log('š Context: ~/.prjct-cli/projects/' + projectId + '/CLAUDE.md\n')
|
|
2321
2373
|
console.log('Next steps:')
|
|
2322
2374
|
console.log('⢠/p:sync ā Generate agents based on stack')
|
|
2323
2375
|
console.log('⢠/p:feature ā Add a new feature')
|
|
@@ -2482,11 +2534,23 @@ Agent: ${agent}
|
|
|
2482
2534
|
count: generatedAgents.length,
|
|
2483
2535
|
})
|
|
2484
2536
|
|
|
2537
|
+
// Generate dynamic context for Claude
|
|
2538
|
+
const contextSync = require('./context-sync')
|
|
2539
|
+
await contextSync.generateLocalContext(projectPath, projectId)
|
|
2540
|
+
|
|
2541
|
+
// Update global CLAUDE.md with latest instructions
|
|
2542
|
+
const commandInstaller = require('./infrastructure/command-installer')
|
|
2543
|
+
const globalConfigResult = await commandInstaller.installGlobalConfig()
|
|
2544
|
+
if (globalConfigResult.success) {
|
|
2545
|
+
console.log('š Updated ~/.claude/CLAUDE.md')
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2485
2548
|
console.log('\nā
Sync complete!\n')
|
|
2486
2549
|
console.log(`š¤ Agents Generated: ${generatedAgents.length}`)
|
|
2487
2550
|
generatedAgents.forEach((agent) => {
|
|
2488
2551
|
console.log(` ⢠${agent}`)
|
|
2489
2552
|
})
|
|
2553
|
+
console.log('š Context: ~/.prjct-cli/projects/' + projectId + '/CLAUDE.md')
|
|
2490
2554
|
console.log('\nš Based on: analysis/repo-summary.md')
|
|
2491
2555
|
console.log('š” See templates/agents/AGENTS.md for reference\n')
|
|
2492
2556
|
console.log('Next steps:')
|