prjct-cli 0.10.12 → 0.10.14
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 +39 -0
- package/CLAUDE.md +47 -2
- package/core/agentic/command-executor.js +83 -112
- package/core/agentic/prompt-builder.js +72 -0
- package/core/commands.js +72 -0
- package/core/index.js +11 -0
- package/core/utils/branding.js +47 -0
- package/core/utils/output.js +19 -4
- package/package.json +1 -1
- package/templates/agentic/agent-routing.md +42 -9
- package/templates/agentic/checklist-routing.md +98 -0
- package/templates/checklists/accessibility.md +33 -0
- package/templates/checklists/architecture.md +28 -0
- package/templates/checklists/code-quality.md +28 -0
- package/templates/checklists/data.md +33 -0
- package/templates/checklists/documentation.md +33 -0
- package/templates/checklists/infrastructure.md +33 -0
- package/templates/checklists/performance.md +33 -0
- package/templates/checklists/security.md +33 -0
- package/templates/checklists/testing.md +33 -0
- package/templates/checklists/ux-ui.md +37 -0
- package/templates/commands/bug.md +27 -1
- package/templates/commands/feature.md +38 -1
- package/templates/commands/task.md +27 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.14] - 2025-11-29
|
|
4
|
+
|
|
5
|
+
### Refactored - 100% Agentic Subagent Delegation via Task Tool
|
|
6
|
+
|
|
7
|
+
Claude now delegates to specialist agents using the Task tool with efficient reference passing.
|
|
8
|
+
|
|
9
|
+
- **`command-executor.js`** - Eliminated all if/else agent assignment logic
|
|
10
|
+
- Removed: `MandatoryAgentRouter`, `ContextFilter`, `ContextEstimator`
|
|
11
|
+
- Removed: `isTaskCommand()`, `shouldUseAgent()` methods
|
|
12
|
+
- JS only loads templates and context, Claude decides everything
|
|
13
|
+
- Added: `agentsPath` and `agentRoutingPath` to context for Claude
|
|
14
|
+
|
|
15
|
+
- **Templates updated with Agent Delegation section**:
|
|
16
|
+
- `feature.md` - Added Task + Glob tools, agent delegation instructions
|
|
17
|
+
- `bug.md` - Added Task + Glob tools, agent delegation instructions
|
|
18
|
+
- `task.md` - Added Task + Glob tools, agent delegation instructions
|
|
19
|
+
|
|
20
|
+
- **`agent-routing.md`** - Added efficient Task tool invocation
|
|
21
|
+
- Pass file PATH (~200 bytes), not content (3-5KB)
|
|
22
|
+
- Subagent reads agent file itself
|
|
23
|
+
- Reduced context bloat by 95%
|
|
24
|
+
|
|
25
|
+
### Architecture
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Usuario: "p. feature mejorar UX"
|
|
29
|
+
↓
|
|
30
|
+
Claude lee agent-routing.md → decide: "ux-ui"
|
|
31
|
+
↓
|
|
32
|
+
Claude: Task(prompt='Read: path/agents/ux-ui.md + Task: mejorar UX')
|
|
33
|
+
↓
|
|
34
|
+
Subagente: Lee archivo → aplica expertise → ejecuta
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Benefits:**
|
|
38
|
+
- 95% reduction in prompt size for delegation
|
|
39
|
+
- Lower hallucination risk
|
|
40
|
+
- True 100% agentic - JS is pure orchestration
|
|
41
|
+
|
|
3
42
|
## [0.10.12] - 2025-11-29
|
|
4
43
|
|
|
5
44
|
### Refactored - Mandatory Agent Assignment (100% Agentic)
|
package/CLAUDE.md
CHANGED
|
@@ -55,8 +55,14 @@ p. ship → Lint/test/commit/push
|
|
|
55
55
|
|
|
56
56
|
When message starts with `p.`:
|
|
57
57
|
1. Check `.prjct/prjct.config.json` exists
|
|
58
|
-
2.
|
|
59
|
-
3.
|
|
58
|
+
2. Detect intent from message
|
|
59
|
+
3. **USE SlashCommand tool** to execute the command
|
|
60
|
+
|
|
61
|
+
⚠️ **CRITICAL** - Always use SlashCommand, never work directly:
|
|
62
|
+
- ✅ `SlashCommand("/p:feature add dark mode")`
|
|
63
|
+
- ❌ Directly creating files without the command
|
|
64
|
+
|
|
65
|
+
If no project: "No prjct project. Run /p:init first."
|
|
60
66
|
|
|
61
67
|
### Intent Map
|
|
62
68
|
|
|
@@ -201,3 +207,42 @@ Use: `generator.generateDynamicAgent(name, config)`
|
|
|
201
207
|
4. **Confirm before executing** - Always show plan first
|
|
202
208
|
5. **Log actions** - Append to memory/context.jsonl
|
|
203
209
|
6. **Suggest next actions** - Maintain user momentum
|
|
210
|
+
|
|
211
|
+
## Output Philosophy
|
|
212
|
+
|
|
213
|
+
**Task completion responses MUST be concise (< 4 lines):**
|
|
214
|
+
|
|
215
|
+
Format:
|
|
216
|
+
```
|
|
217
|
+
✅ [What was done]
|
|
218
|
+
|
|
219
|
+
Files: [count] | Modified: [key file]
|
|
220
|
+
Next: [action]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**NEVER include in task summaries:**
|
|
224
|
+
- Tables listing files
|
|
225
|
+
- "Created Files" / "Modified Files" sections
|
|
226
|
+
- "How It Works" explanations
|
|
227
|
+
- Code snippets or implementation details
|
|
228
|
+
- Detailed breakdowns of what was done
|
|
229
|
+
|
|
230
|
+
**Example (GOOD):**
|
|
231
|
+
```
|
|
232
|
+
✅ Agentic checklists integrated
|
|
233
|
+
|
|
234
|
+
Files: 11 created | Modified: prompt-builder.js
|
|
235
|
+
Next: /p:ship or test with /p:now
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Example (BAD):**
|
|
239
|
+
```
|
|
240
|
+
Created Files:
|
|
241
|
+
| File | Purpose |
|
|
242
|
+
|------|---------|
|
|
243
|
+
| x.md | Does X |
|
|
244
|
+
...
|
|
245
|
+
|
|
246
|
+
How It Works:
|
|
247
|
+
Claude reads → decides → applies...
|
|
248
|
+
```
|
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Command Executor
|
|
3
|
-
*
|
|
4
|
-
* Every task MUST use a specialized agent
|
|
3
|
+
* 100% AGENTIC - Claude decides agent assignment via Task tool
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - Specific error messages, never generic failures
|
|
9
|
-
* - Actionable suggestions in every error
|
|
5
|
+
* NO if/else logic for agent selection here.
|
|
6
|
+
* Claude reads templates/agentic/agent-routing.md and delegates via Task tool.
|
|
10
7
|
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
8
|
+
* JS only:
|
|
9
|
+
* - Loads templates
|
|
10
|
+
* - Builds context
|
|
11
|
+
* - Returns prompt for Claude
|
|
12
|
+
*
|
|
13
|
+
* Claude:
|
|
14
|
+
* - Reads agent-routing.md
|
|
15
|
+
* - Decides best agent for task
|
|
16
|
+
* - Delegates via Task(subagent_type='general-purpose', prompt='Read: path/to/agent.md...')
|
|
14
17
|
*
|
|
15
18
|
* Source: Claude Code, Devin, Augment Code patterns
|
|
16
19
|
*/
|
|
17
20
|
|
|
21
|
+
const fs = require('fs')
|
|
22
|
+
const path = require('path')
|
|
23
|
+
const os = require('os')
|
|
18
24
|
const templateLoader = require('./template-loader')
|
|
19
25
|
const contextBuilder = require('./context-builder')
|
|
20
26
|
const promptBuilder = require('./prompt-builder')
|
|
21
27
|
const toolRegistry = require('./tool-registry')
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const ContextEstimator = require('../domain/context-estimator')
|
|
28
|
+
// REMOVED: MandatoryAgentRouter, ContextFilter, ContextEstimator
|
|
29
|
+
// Agent assignment is 100% agentic - Claude decides via templates
|
|
25
30
|
const { validate, formatError } = require('./validation-rules')
|
|
26
31
|
const loopDetector = require('./loop-detector')
|
|
27
32
|
const chainOfThought = require('./chain-of-thought')
|
|
@@ -32,6 +37,9 @@ const groundTruth = require('./ground-truth')
|
|
|
32
37
|
const thinkBlocks = require('./think-blocks')
|
|
33
38
|
const parallelTools = require('./parallel-tools')
|
|
34
39
|
const planMode = require('./plan-mode')
|
|
40
|
+
|
|
41
|
+
// Running file for status line integration
|
|
42
|
+
const RUNNING_FILE = path.join(os.homedir(), '.prjct-cli', '.running')
|
|
35
43
|
// P3.5, P3.6, P3.7: DELEGATED TO CLAUDE CODE
|
|
36
44
|
// - semantic-search → Claude Code has Grep/Glob with semantic understanding
|
|
37
45
|
// - code-intelligence → Claude Code has native LSP integration
|
|
@@ -39,21 +47,52 @@ const planMode = require('./plan-mode')
|
|
|
39
47
|
|
|
40
48
|
class CommandExecutor {
|
|
41
49
|
constructor() {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
// 100% AGENTIC: No agent router here
|
|
51
|
+
// Claude decides agent assignment via templates and Task tool
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Signal that a command is running (for status line)
|
|
56
|
+
*/
|
|
57
|
+
signalStart(commandName) {
|
|
58
|
+
try {
|
|
59
|
+
const dir = path.dirname(RUNNING_FILE)
|
|
60
|
+
if (!fs.existsSync(dir)) {
|
|
61
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
62
|
+
}
|
|
63
|
+
fs.writeFileSync(RUNNING_FILE, `/p:${commandName}`)
|
|
64
|
+
} catch {
|
|
65
|
+
// Silently ignore - status line is optional
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Signal that command has finished (for status line)
|
|
71
|
+
*/
|
|
72
|
+
signalEnd() {
|
|
73
|
+
try {
|
|
74
|
+
if (fs.existsSync(RUNNING_FILE)) {
|
|
75
|
+
fs.unlinkSync(RUNNING_FILE)
|
|
76
|
+
}
|
|
77
|
+
} catch {
|
|
78
|
+
// Silently ignore - status line is optional
|
|
79
|
+
}
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
/**
|
|
48
83
|
* Execute command with MANDATORY agent assignment
|
|
49
84
|
*/
|
|
50
85
|
async execute(commandName, params, projectPath) {
|
|
86
|
+
// Signal start for status line
|
|
87
|
+
this.signalStart(commandName)
|
|
88
|
+
|
|
51
89
|
// Context for loop detection
|
|
52
90
|
const loopContext = params.task || params.description || ''
|
|
53
91
|
|
|
54
92
|
// Check if we're in a loop BEFORE attempting
|
|
55
93
|
if (loopDetector.shouldEscalate(commandName, loopContext)) {
|
|
56
94
|
const escalation = loopDetector.getEscalationInfo(commandName, loopContext)
|
|
95
|
+
this.signalEnd()
|
|
57
96
|
return {
|
|
58
97
|
success: false,
|
|
59
98
|
error: escalation.message,
|
|
@@ -73,6 +112,7 @@ class CommandExecutor {
|
|
|
73
112
|
// 2.5. VALIDATE: Pre-flight checks with specific errors
|
|
74
113
|
const validation = await validate(commandName, metadataContext)
|
|
75
114
|
if (!validation.valid) {
|
|
115
|
+
this.signalEnd()
|
|
76
116
|
return {
|
|
77
117
|
success: false,
|
|
78
118
|
error: formatError(validation),
|
|
@@ -134,72 +174,18 @@ class CommandExecutor {
|
|
|
134
174
|
}
|
|
135
175
|
}
|
|
136
176
|
|
|
137
|
-
// 3.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
this.isTaskCommand(commandName) ||
|
|
141
|
-
this.shouldUseAgent(commandName))
|
|
142
|
-
|
|
177
|
+
// 3. AGENTIC: Claude decides agent assignment via templates
|
|
178
|
+
// NO if/else logic here - templates instruct Claude to use Task tool
|
|
179
|
+
// See templates/agentic/agent-routing.md for routing rules
|
|
143
180
|
let context = metadataContext
|
|
144
|
-
let assignedAgent = null
|
|
145
|
-
|
|
146
|
-
// MANDATORY: Assign specialized agent for task commands
|
|
147
|
-
if (requiresAgent) {
|
|
148
|
-
// 4. Create task object for analysis
|
|
149
|
-
const task = {
|
|
150
|
-
description: params.task || params.description || commandName,
|
|
151
|
-
type: commandName
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// 5. LAZY CONTEXT: Analyze task FIRST, then estimate files needed
|
|
155
|
-
// This avoids reading all files before knowing what we need
|
|
156
|
-
const agentAssignment = await this.agentRouter.executeTask(
|
|
157
|
-
task,
|
|
158
|
-
metadataContext, // Only metadata, no files yet
|
|
159
|
-
projectPath
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
assignedAgent = agentAssignment.agent
|
|
163
|
-
const taskAnalysis = agentAssignment.taskAnalysis
|
|
164
181
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
// 6. PRE-FILTER: Estimate which files are needed BEFORE reading
|
|
174
|
-
if (!this.contextEstimator) {
|
|
175
|
-
this.contextEstimator = new ContextEstimator()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const estimatedFiles = await this.contextEstimator.estimateFiles(
|
|
179
|
-
taskAnalysis,
|
|
180
|
-
projectPath
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
// 7. Build context ONLY with estimated files (lazy loading)
|
|
184
|
-
const filtered = await this.contextFilter.filterForAgent(
|
|
185
|
-
assignedAgent,
|
|
186
|
-
task,
|
|
187
|
-
projectPath,
|
|
188
|
-
{
|
|
189
|
-
...metadataContext,
|
|
190
|
-
estimatedFiles, // Pre-filtered file list
|
|
191
|
-
fileCount: estimatedFiles.length
|
|
192
|
-
}
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
context = {
|
|
196
|
-
...filtered,
|
|
197
|
-
agent: assignedAgent,
|
|
198
|
-
originalSize: estimatedFiles.length, // Estimated, not actual full size
|
|
199
|
-
filteredSize: filtered.files?.length || 0,
|
|
200
|
-
reduction: filtered.metrics?.reductionPercent || 0,
|
|
201
|
-
lazyLoaded: true // Flag indicating lazy loading was used
|
|
202
|
-
}
|
|
182
|
+
// Provide agent info to context so Claude can delegate
|
|
183
|
+
context = {
|
|
184
|
+
...context,
|
|
185
|
+
agentsPath: path.join(os.homedir(), '.prjct-cli', 'projects', metadataContext.projectId || '', 'agents'),
|
|
186
|
+
agentRoutingPath: path.join(__dirname, '..', '..', 'templates', 'agentic', 'agent-routing.md'),
|
|
187
|
+
// Flag: Claude must delegate to subagent via Task tool
|
|
188
|
+
agenticDelegation: true
|
|
203
189
|
}
|
|
204
190
|
|
|
205
191
|
// 6. Load state with filtered context
|
|
@@ -246,7 +232,7 @@ class CommandExecutor {
|
|
|
246
232
|
)
|
|
247
233
|
}
|
|
248
234
|
|
|
249
|
-
// 9. Build prompt
|
|
235
|
+
// 9. Build prompt - NO agent assignment here, Claude decides via templates
|
|
250
236
|
const planInfo = {
|
|
251
237
|
isPlanning: requiresPlanning || isInPlanningMode,
|
|
252
238
|
requiresApproval: isDestructive && !params.approved,
|
|
@@ -256,25 +242,28 @@ class CommandExecutor {
|
|
|
256
242
|
template.frontmatter['allowed-tools'] || []
|
|
257
243
|
)
|
|
258
244
|
}
|
|
259
|
-
|
|
245
|
+
// Agent is null - Claude assigns via Task tool using agent-routing.md
|
|
246
|
+
const prompt = promptBuilder.build(template, context, state, null, learnedPatterns, thinkBlock, relevantMemories, planInfo)
|
|
260
247
|
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
console.log(`🤖 Task assigned to: ${assignedAgent.name}`)
|
|
264
|
-
console.log(`📉 Context reduced by: ${context.reduction}%`)
|
|
265
|
-
}
|
|
248
|
+
// Log agentic mode
|
|
249
|
+
console.log(`🤖 Agentic delegation enabled - Claude will assign agent via Task tool`)
|
|
266
250
|
|
|
267
251
|
// Record successful attempt
|
|
268
252
|
loopDetector.recordSuccess(commandName, loopContext)
|
|
269
253
|
|
|
254
|
+
// Signal end for status line
|
|
255
|
+
this.signalEnd()
|
|
256
|
+
|
|
270
257
|
return {
|
|
271
258
|
success: true,
|
|
272
259
|
template,
|
|
273
260
|
context,
|
|
274
261
|
state,
|
|
275
262
|
prompt,
|
|
276
|
-
|
|
277
|
-
|
|
263
|
+
// AGENTIC: No pre-assigned agent - Claude delegates via Task tool
|
|
264
|
+
agenticDelegation: true,
|
|
265
|
+
agentsPath: context.agentsPath,
|
|
266
|
+
agentRoutingPath: context.agentRoutingPath,
|
|
278
267
|
reasoning, // Chain of thought results
|
|
279
268
|
thinkBlock, // Think blocks (P3.1)
|
|
280
269
|
groundTruth: groundTruthResult, // Ground truth verification (P1.3)
|
|
@@ -334,6 +323,9 @@ class CommandExecutor {
|
|
|
334
323
|
// - Native LSP for code intelligence
|
|
335
324
|
}
|
|
336
325
|
} catch (error) {
|
|
326
|
+
// Signal end for status line
|
|
327
|
+
this.signalEnd()
|
|
328
|
+
|
|
337
329
|
// Record failed attempt for loop detection
|
|
338
330
|
const attemptInfo = loopDetector.recordAttempt(commandName, loopContext, {
|
|
339
331
|
success: false,
|
|
@@ -361,30 +353,9 @@ class CommandExecutor {
|
|
|
361
353
|
}
|
|
362
354
|
}
|
|
363
355
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
isTaskCommand(commandName) {
|
|
368
|
-
const taskCommands = [
|
|
369
|
-
'work', 'now', 'build', 'feature', 'bug', 'done',
|
|
370
|
-
'task', 'design', 'cleanup', 'fix', 'test'
|
|
371
|
-
]
|
|
372
|
-
return taskCommands.includes(commandName)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Determine if command should use an agent
|
|
377
|
-
* Expanded list of commands that benefit from agent specialization
|
|
378
|
-
*/
|
|
379
|
-
shouldUseAgent(commandName) {
|
|
380
|
-
// Commands that should ALWAYS use agents
|
|
381
|
-
const agentCommands = [
|
|
382
|
-
'work', 'now', 'build', 'feature', 'bug', 'done',
|
|
383
|
-
'task', 'design', 'cleanup', 'fix', 'test',
|
|
384
|
-
'sync', 'analyze' // These analyze/modify code, need specialization
|
|
385
|
-
]
|
|
386
|
-
return agentCommands.includes(commandName)
|
|
387
|
-
}
|
|
356
|
+
// REMOVED: isTaskCommand() and shouldUseAgent()
|
|
357
|
+
// Agent assignment is now 100% agentic - Claude decides via templates
|
|
358
|
+
// See templates/agentic/agent-routing.md
|
|
388
359
|
|
|
389
360
|
/**
|
|
390
361
|
* Execute tool with permission check
|
|
@@ -7,9 +7,65 @@
|
|
|
7
7
|
* P3.1: Includes think blocks for anti-hallucination
|
|
8
8
|
* P3.3: Includes relevant memories from semantic database
|
|
9
9
|
* P3.4: Includes plan mode instructions
|
|
10
|
+
* P4.1: Includes quality checklists (Claude decides which to apply)
|
|
10
11
|
*/
|
|
11
12
|
|
|
13
|
+
const fs = require('fs')
|
|
14
|
+
const path = require('path')
|
|
15
|
+
|
|
12
16
|
class PromptBuilder {
|
|
17
|
+
constructor() {
|
|
18
|
+
this._checklistsCache = null
|
|
19
|
+
this._checklistRoutingCache = null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Load quality checklists from templates/checklists/
|
|
24
|
+
* Returns checklist content - Claude decides which to apply
|
|
25
|
+
* NO if/else logic here - just load and provide
|
|
26
|
+
*/
|
|
27
|
+
loadChecklists() {
|
|
28
|
+
if (this._checklistsCache) return this._checklistsCache
|
|
29
|
+
|
|
30
|
+
const checklistsDir = path.join(__dirname, '..', '..', 'templates', 'checklists')
|
|
31
|
+
const checklists = {}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (fs.existsSync(checklistsDir)) {
|
|
35
|
+
const files = fs.readdirSync(checklistsDir).filter(f => f.endsWith('.md'))
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
const name = file.replace('.md', '')
|
|
38
|
+
const content = fs.readFileSync(path.join(checklistsDir, file), 'utf-8')
|
|
39
|
+
checklists[name] = content
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
// Silent fail - checklists are optional enhancement
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this._checklistsCache = checklists
|
|
47
|
+
return checklists
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Load checklist routing template
|
|
52
|
+
* Claude reads this to decide which checklists to apply
|
|
53
|
+
*/
|
|
54
|
+
loadChecklistRouting() {
|
|
55
|
+
if (this._checklistRoutingCache) return this._checklistRoutingCache
|
|
56
|
+
|
|
57
|
+
const routingPath = path.join(__dirname, '..', '..', 'templates', 'agentic', 'checklist-routing.md')
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
if (fs.existsSync(routingPath)) {
|
|
61
|
+
this._checklistRoutingCache = fs.readFileSync(routingPath, 'utf-8')
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
// Silent fail
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return this._checklistRoutingCache || null
|
|
68
|
+
}
|
|
13
69
|
/**
|
|
14
70
|
* Build concise prompt - only essentials
|
|
15
71
|
* CRITICAL: Includes full agent content if agent is provided
|
|
@@ -154,6 +210,22 @@ class PromptBuilder {
|
|
|
154
210
|
parts.push(`\n## APPROVAL REQUIRED\nShow changes, list affected files, ask for confirmation.\n`)
|
|
155
211
|
}
|
|
156
212
|
|
|
213
|
+
// P4.1: Quality Checklists (Claude decides which to apply)
|
|
214
|
+
// Only for code-modifying commands that benefit from quality gates
|
|
215
|
+
const checklistCommands = ['now', 'build', 'feature', 'design', 'fix', 'bug', 'cleanup', 'spec', 'work']
|
|
216
|
+
if (checklistCommands.includes(commandName)) {
|
|
217
|
+
const routing = this.loadChecklistRouting()
|
|
218
|
+
const checklists = this.loadChecklists()
|
|
219
|
+
|
|
220
|
+
if (routing && Object.keys(checklists).length > 0) {
|
|
221
|
+
parts.push('\n## QUALITY CHECKLISTS\n')
|
|
222
|
+
parts.push('Apply relevant checklists based on task. Read checklist-routing.md for guidance.\n')
|
|
223
|
+
parts.push(`Available: ${Object.keys(checklists).join(', ')}\n`)
|
|
224
|
+
parts.push('Path: templates/checklists/{name}.md\n')
|
|
225
|
+
parts.push('Use Read tool to load checklists you determine are relevant.\n')
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
157
229
|
// Simple execution directive
|
|
158
230
|
parts.push('\nEXECUTE: Follow flow. Use tools. Decide.\n')
|
|
159
231
|
|
package/core/commands.js
CHANGED
|
@@ -1925,6 +1925,15 @@ Agent: ${agent} (${Math.round(confidence * 100)}% confidence)
|
|
|
1925
1925
|
console.log(`⚠️ ${configResult.error}`)
|
|
1926
1926
|
}
|
|
1927
1927
|
|
|
1928
|
+
// Install status line for Claude Code
|
|
1929
|
+
console.log('\n⚡ Installing status line...')
|
|
1930
|
+
const statusLineResult = await this.installStatusLine()
|
|
1931
|
+
if (statusLineResult.success) {
|
|
1932
|
+
console.log('✅ Status line configured')
|
|
1933
|
+
} else {
|
|
1934
|
+
console.log(`⚠️ ${statusLineResult.error}`)
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1928
1937
|
console.log('\n🎉 Setup complete!\n')
|
|
1929
1938
|
|
|
1930
1939
|
// Show beautiful ASCII art
|
|
@@ -1936,6 +1945,69 @@ Agent: ${agent} (${Math.round(confidence * 100)}% confidence)
|
|
|
1936
1945
|
}
|
|
1937
1946
|
}
|
|
1938
1947
|
|
|
1948
|
+
/**
|
|
1949
|
+
* Install status line script and configure settings.json
|
|
1950
|
+
*/
|
|
1951
|
+
async installStatusLine() {
|
|
1952
|
+
const fs = require('fs')
|
|
1953
|
+
const path = require('path')
|
|
1954
|
+
const os = require('os')
|
|
1955
|
+
|
|
1956
|
+
try {
|
|
1957
|
+
const claudeDir = path.join(os.homedir(), '.claude')
|
|
1958
|
+
const settingsPath = path.join(claudeDir, 'settings.json')
|
|
1959
|
+
const statusLinePath = path.join(claudeDir, 'prjct-statusline.sh')
|
|
1960
|
+
|
|
1961
|
+
// Copy status line script
|
|
1962
|
+
const scriptContent = `#!/bin/bash
|
|
1963
|
+
# prjct Status Line for Claude Code
|
|
1964
|
+
# Shows ⚡ prjct with animated spinner when command is running
|
|
1965
|
+
|
|
1966
|
+
# Read JSON context from stdin (provided by Claude Code)
|
|
1967
|
+
read -r json
|
|
1968
|
+
|
|
1969
|
+
# Spinner frames
|
|
1970
|
+
frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
|
1971
|
+
|
|
1972
|
+
# Calculate frame based on time (changes every 80ms)
|
|
1973
|
+
frame=$(($(date +%s%N 2>/dev/null || echo 0) / 80000000 % 10))
|
|
1974
|
+
|
|
1975
|
+
# Check if prjct command is running
|
|
1976
|
+
running_file="$HOME/.prjct-cli/.running"
|
|
1977
|
+
|
|
1978
|
+
if [ -f "$running_file" ]; then
|
|
1979
|
+
task=$(cat "$running_file" 2>/dev/null || echo "working")
|
|
1980
|
+
echo "⚡ prjct \${frames[$frame]} $task"
|
|
1981
|
+
else
|
|
1982
|
+
echo "⚡ prjct"
|
|
1983
|
+
fi
|
|
1984
|
+
`
|
|
1985
|
+
fs.writeFileSync(statusLinePath, scriptContent, { mode: 0o755 })
|
|
1986
|
+
|
|
1987
|
+
// Update settings.json
|
|
1988
|
+
let settings = {}
|
|
1989
|
+
if (fs.existsSync(settingsPath)) {
|
|
1990
|
+
try {
|
|
1991
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'))
|
|
1992
|
+
} catch {
|
|
1993
|
+
// Invalid JSON, start fresh
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
// Set status line configuration
|
|
1998
|
+
settings.statusLine = {
|
|
1999
|
+
type: 'command',
|
|
2000
|
+
command: statusLinePath
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2))
|
|
2004
|
+
|
|
2005
|
+
return { success: true }
|
|
2006
|
+
} catch (error) {
|
|
2007
|
+
return { success: false, error: error.message }
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
|
|
1939
2011
|
/**
|
|
1940
2012
|
* Show beautiful ASCII art with quick start
|
|
1941
2013
|
*/
|
package/core/index.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const { PrjctCommands } = require('./commands')
|
|
8
8
|
const registry = require('./command-registry')
|
|
9
|
+
const out = require('./utils/output')
|
|
9
10
|
|
|
10
11
|
async function main() {
|
|
11
12
|
const [commandName, ...rawArgs] = process.argv.slice(2)
|
|
@@ -25,6 +26,9 @@ async function main() {
|
|
|
25
26
|
|
|
26
27
|
// === DYNAMIC COMMAND EXECUTION ===
|
|
27
28
|
|
|
29
|
+
// Show branding header
|
|
30
|
+
out.start()
|
|
31
|
+
|
|
28
32
|
try {
|
|
29
33
|
// 1. Find command in registry
|
|
30
34
|
const cmd = registry.getByName(commandName)
|
|
@@ -32,6 +36,7 @@ async function main() {
|
|
|
32
36
|
if (!cmd) {
|
|
33
37
|
console.error(`Unknown command: ${commandName}`)
|
|
34
38
|
console.error(`\nUse 'prjct --help' to see available commands.`)
|
|
39
|
+
out.end()
|
|
35
40
|
process.exit(1)
|
|
36
41
|
}
|
|
37
42
|
|
|
@@ -41,6 +46,7 @@ async function main() {
|
|
|
41
46
|
if (cmd.replacedBy) {
|
|
42
47
|
console.error(`Use 'prjct ${cmd.replacedBy}' instead.`)
|
|
43
48
|
}
|
|
49
|
+
out.end()
|
|
44
50
|
process.exit(1)
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -49,6 +55,7 @@ async function main() {
|
|
|
49
55
|
console.error(`Command '${commandName}' exists but is not yet implemented.`)
|
|
50
56
|
console.error(`Check the roadmap or contribute: https://github.com/jlopezlira/prjct-cli`)
|
|
51
57
|
console.error(`\nUse 'prjct --help' to see available commands.`)
|
|
58
|
+
out.end()
|
|
52
59
|
process.exit(1)
|
|
53
60
|
}
|
|
54
61
|
|
|
@@ -90,12 +97,16 @@ async function main() {
|
|
|
90
97
|
console.log(result.message)
|
|
91
98
|
}
|
|
92
99
|
|
|
100
|
+
// Show branding footer
|
|
101
|
+
out.end()
|
|
93
102
|
process.exit(result && result.success ? 0 : 1)
|
|
94
103
|
} catch (error) {
|
|
95
104
|
console.error('Error:', error.message)
|
|
96
105
|
if (process.env.DEBUG) {
|
|
97
106
|
console.error(error.stack)
|
|
98
107
|
}
|
|
108
|
+
// Show branding footer even on error
|
|
109
|
+
out.end()
|
|
99
110
|
process.exit(1)
|
|
100
111
|
}
|
|
101
112
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branding Configuration for prjct-cli
|
|
3
|
+
* Single source of truth for all branding across CLI and Claude Code
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk')
|
|
7
|
+
|
|
8
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
|
9
|
+
const SPINNER_SPEED = 80
|
|
10
|
+
|
|
11
|
+
const branding = {
|
|
12
|
+
// Core identity
|
|
13
|
+
name: 'prjct',
|
|
14
|
+
icon: '⚡',
|
|
15
|
+
signature: '⚡ prjct',
|
|
16
|
+
|
|
17
|
+
// Spinner config
|
|
18
|
+
spinner: {
|
|
19
|
+
frames: SPINNER_FRAMES,
|
|
20
|
+
speed: SPINNER_SPEED
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// CLI output (with chalk colors)
|
|
24
|
+
cli: {
|
|
25
|
+
header: () => chalk.cyan.bold('⚡') + ' ' + chalk.cyan('prjct'),
|
|
26
|
+
footer: () => chalk.dim('⚡ prjct'),
|
|
27
|
+
spin: (frame, msg) => chalk.cyan('⚡') + ' ' + chalk.cyan('prjct') + ' ' + chalk.cyan(SPINNER_FRAMES[frame % 10]) + ' ' + chalk.dim(msg || '')
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
// Template/Claude (plain text)
|
|
31
|
+
template: {
|
|
32
|
+
header: '⚡ prjct',
|
|
33
|
+
footer: '⚡ prjct'
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// Git commit footer
|
|
37
|
+
commitFooter: `🤖 Generated with [p/](https://www.prjct.app/)
|
|
38
|
+
Designed for [Claude](https://www.anthropic.com/claude)`,
|
|
39
|
+
|
|
40
|
+
// URLs
|
|
41
|
+
urls: {
|
|
42
|
+
website: 'https://prjct.app',
|
|
43
|
+
docs: 'https://prjct.app/docs'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = branding
|