prjct-cli 0.10.13 → 0.11.0
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 +58 -0
- package/CLAUDE.md +47 -2
- package/bin/dev.js +217 -0
- package/bin/prjct +10 -0
- package/bin/serve.js +78 -0
- package/core/agentic/command-executor.js +38 -112
- package/core/agentic/prompt-builder.js +72 -0
- package/core/bus/index.js +322 -0
- package/core/command-registry.js +65 -0
- package/core/domain/snapshot-manager.js +375 -0
- package/core/plugin/hooks.js +313 -0
- package/core/plugin/index.js +52 -0
- package/core/plugin/loader.js +331 -0
- package/core/plugin/registry.js +325 -0
- package/core/plugins/webhook.js +143 -0
- package/core/session/index.js +449 -0
- package/core/session/metrics.js +293 -0
- package/package.json +18 -4
- 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/done.md +176 -54
- package/templates/commands/feature.md +38 -1
- package/templates/commands/history.md +176 -0
- package/templates/commands/init.md +28 -1
- package/templates/commands/now.md +191 -9
- package/templates/commands/pause.md +176 -12
- package/templates/commands/redo.md +142 -0
- package/templates/commands/resume.md +166 -62
- package/templates/commands/serve.md +121 -0
- package/templates/commands/ship.md +45 -1
- package/templates/commands/sync.md +34 -1
- package/templates/commands/task.md +27 -1
- package/templates/commands/undo.md +152 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.11.0] - 2025-12-08
|
|
4
|
+
|
|
5
|
+
### Added - Web Application & Server Components
|
|
6
|
+
|
|
7
|
+
Major release introducing the prjct web application with Next.js.
|
|
8
|
+
|
|
9
|
+
- **Web Application** - Full Next.js web interface for prjct
|
|
10
|
+
- Project stats API implementation
|
|
11
|
+
- Enhanced UI components
|
|
12
|
+
- Terminal functionality in browser
|
|
13
|
+
|
|
14
|
+
- **Server Components** - New server infrastructure
|
|
15
|
+
- Project management endpoints
|
|
16
|
+
- Stats API for metrics and analytics
|
|
17
|
+
|
|
18
|
+
- **UI Enhancements**
|
|
19
|
+
- Improved project management interface
|
|
20
|
+
- Enhanced terminal integration
|
|
21
|
+
|
|
22
|
+
## [0.10.14] - 2025-11-29
|
|
23
|
+
|
|
24
|
+
### Refactored - 100% Agentic Subagent Delegation via Task Tool
|
|
25
|
+
|
|
26
|
+
Claude now delegates to specialist agents using the Task tool with efficient reference passing.
|
|
27
|
+
|
|
28
|
+
- **`command-executor.js`** - Eliminated all if/else agent assignment logic
|
|
29
|
+
- Removed: `MandatoryAgentRouter`, `ContextFilter`, `ContextEstimator`
|
|
30
|
+
- Removed: `isTaskCommand()`, `shouldUseAgent()` methods
|
|
31
|
+
- JS only loads templates and context, Claude decides everything
|
|
32
|
+
- Added: `agentsPath` and `agentRoutingPath` to context for Claude
|
|
33
|
+
|
|
34
|
+
- **Templates updated with Agent Delegation section**:
|
|
35
|
+
- `feature.md` - Added Task + Glob tools, agent delegation instructions
|
|
36
|
+
- `bug.md` - Added Task + Glob tools, agent delegation instructions
|
|
37
|
+
- `task.md` - Added Task + Glob tools, agent delegation instructions
|
|
38
|
+
|
|
39
|
+
- **`agent-routing.md`** - Added efficient Task tool invocation
|
|
40
|
+
- Pass file PATH (~200 bytes), not content (3-5KB)
|
|
41
|
+
- Subagent reads agent file itself
|
|
42
|
+
- Reduced context bloat by 95%
|
|
43
|
+
|
|
44
|
+
### Architecture
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
Usuario: "p. feature mejorar UX"
|
|
48
|
+
↓
|
|
49
|
+
Claude lee agent-routing.md → decide: "ux-ui"
|
|
50
|
+
↓
|
|
51
|
+
Claude: Task(prompt='Read: path/agents/ux-ui.md + Task: mejorar UX')
|
|
52
|
+
↓
|
|
53
|
+
Subagente: Lee archivo → aplica expertise → ejecuta
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Benefits:**
|
|
57
|
+
- 95% reduction in prompt size for delegation
|
|
58
|
+
- Lower hallucination risk
|
|
59
|
+
- True 100% agentic - JS is pure orchestration
|
|
60
|
+
|
|
3
61
|
## [0.10.12] - 2025-11-29
|
|
4
62
|
|
|
5
63
|
### 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
|
+
```
|
package/bin/dev.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* prjct dev - Start prjct web development environment
|
|
5
|
+
*
|
|
6
|
+
* Launches Next.js fullstack app on port 9472
|
|
7
|
+
* - Frontend + API routes + WebSocket for PTY
|
|
8
|
+
*
|
|
9
|
+
* Usage: prjct dev [--no-open]
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { spawn, exec } = require('child_process')
|
|
13
|
+
const path = require('path')
|
|
14
|
+
const os = require('os')
|
|
15
|
+
|
|
16
|
+
// Configuration
|
|
17
|
+
const PORT = process.env.PRJCT_PORT || 9472
|
|
18
|
+
const WEB_URL = `http://localhost:${PORT}`
|
|
19
|
+
|
|
20
|
+
// Colors for terminal output
|
|
21
|
+
const colors = {
|
|
22
|
+
reset: '\x1b[0m',
|
|
23
|
+
bright: '\x1b[1m',
|
|
24
|
+
dim: '\x1b[2m',
|
|
25
|
+
cyan: '\x1b[36m',
|
|
26
|
+
green: '\x1b[32m',
|
|
27
|
+
yellow: '\x1b[33m',
|
|
28
|
+
red: '\x1b[31m',
|
|
29
|
+
magenta: '\x1b[35m'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Find prjct-cli root (where packages/ lives)
|
|
33
|
+
function findPrjctRoot() {
|
|
34
|
+
const locations = [
|
|
35
|
+
path.join(__dirname, '..'),
|
|
36
|
+
path.join(os.homedir(), 'Apps', 'prjct', 'prjct-cli'),
|
|
37
|
+
path.join(os.homedir(), '.prjct-cli', 'source'),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
for (const loc of locations) {
|
|
41
|
+
const pkgPath = path.join(loc, 'packages')
|
|
42
|
+
try {
|
|
43
|
+
require('fs').accessSync(pkgPath)
|
|
44
|
+
return loc
|
|
45
|
+
} catch {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return locations[0]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const PRJCT_ROOT = findPrjctRoot()
|
|
52
|
+
const WEB_PATH = path.join(PRJCT_ROOT, 'packages', 'web')
|
|
53
|
+
|
|
54
|
+
// Print banner
|
|
55
|
+
function printBanner() {
|
|
56
|
+
console.log(`
|
|
57
|
+
${colors.cyan}${colors.bright}╔═══════════════════════════════════════════════╗
|
|
58
|
+
║ ║
|
|
59
|
+
║ ⚡ prjct dev ║
|
|
60
|
+
║ ║
|
|
61
|
+
║ App: ${colors.green}http://localhost:${PORT}${colors.cyan} ║
|
|
62
|
+
║ ║
|
|
63
|
+
║ ${colors.dim}Press Ctrl+C to stop${colors.cyan}${colors.bright} ║
|
|
64
|
+
║ ║
|
|
65
|
+
╚═══════════════════════════════════════════════╝${colors.reset}
|
|
66
|
+
`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Open browser based on OS
|
|
70
|
+
function openBrowser(url) {
|
|
71
|
+
const platform = os.platform()
|
|
72
|
+
let command
|
|
73
|
+
|
|
74
|
+
switch (platform) {
|
|
75
|
+
case 'darwin':
|
|
76
|
+
command = `open "${url}"`
|
|
77
|
+
break
|
|
78
|
+
case 'win32':
|
|
79
|
+
command = `start "" "${url}"`
|
|
80
|
+
break
|
|
81
|
+
default:
|
|
82
|
+
command = `xdg-open "${url}"`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
exec(command, (err) => {
|
|
86
|
+
if (err) {
|
|
87
|
+
console.log(`${colors.yellow}Could not open browser automatically. Visit: ${url}${colors.reset}`)
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check if port is available
|
|
93
|
+
function checkPort(port) {
|
|
94
|
+
return new Promise((resolve) => {
|
|
95
|
+
const net = require('net')
|
|
96
|
+
const server = net.createServer()
|
|
97
|
+
|
|
98
|
+
server.once('error', () => resolve(false))
|
|
99
|
+
server.once('listening', () => {
|
|
100
|
+
server.close()
|
|
101
|
+
resolve(true)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
server.listen(port)
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Wait for server to be ready
|
|
109
|
+
function waitForServer(port, maxAttempts = 60) {
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
111
|
+
let attempts = 0
|
|
112
|
+
|
|
113
|
+
const check = () => {
|
|
114
|
+
const http = require('http')
|
|
115
|
+
const req = http.get(`http://localhost:${port}`, (res) => {
|
|
116
|
+
resolve(true)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
req.on('error', () => {
|
|
120
|
+
attempts++
|
|
121
|
+
if (attempts >= maxAttempts) {
|
|
122
|
+
reject(new Error(`Server on port ${port} did not start`))
|
|
123
|
+
} else {
|
|
124
|
+
setTimeout(check, 500)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
req.end()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
check()
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Main function
|
|
136
|
+
async function main() {
|
|
137
|
+
const args = process.argv.slice(2)
|
|
138
|
+
const noOpen = args.includes('--no-open')
|
|
139
|
+
|
|
140
|
+
// Check port
|
|
141
|
+
const portAvailable = await checkPort(PORT)
|
|
142
|
+
|
|
143
|
+
if (!portAvailable) {
|
|
144
|
+
console.log(`${colors.red}Port ${PORT} is already in use. Stop other services or set PRJCT_PORT.${colors.reset}`)
|
|
145
|
+
process.exit(1)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
printBanner()
|
|
149
|
+
|
|
150
|
+
// Start Next.js with custom server
|
|
151
|
+
console.log(`${colors.cyan}Starting prjct...${colors.reset}`)
|
|
152
|
+
const webProc = spawn('npm', ['run', 'dev'], {
|
|
153
|
+
cwd: WEB_PATH,
|
|
154
|
+
env: { ...process.env, PORT: PORT.toString() },
|
|
155
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
156
|
+
shell: true
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
webProc.stdout.on('data', (data) => {
|
|
160
|
+
const lines = data.toString().split('\n').filter(Boolean)
|
|
161
|
+
lines.forEach(line => {
|
|
162
|
+
// Show relevant output
|
|
163
|
+
if (line.includes('ready') || line.includes('Ready') || line.includes('[WS]')) {
|
|
164
|
+
console.log(`${colors.green}${line}${colors.reset}`)
|
|
165
|
+
} else if (!line.includes('╔') && !line.includes('║') && !line.includes('╚')) {
|
|
166
|
+
console.log(`${colors.dim}${line}${colors.reset}`)
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
webProc.stderr.on('data', (data) => {
|
|
172
|
+
const msg = data.toString().trim()
|
|
173
|
+
// Filter out common non-error messages
|
|
174
|
+
if (!msg.includes('ExperimentalWarning') && !msg.includes('punycode')) {
|
|
175
|
+
console.log(`${colors.red}${msg}${colors.reset}`)
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// Wait for server and open browser
|
|
180
|
+
try {
|
|
181
|
+
console.log(`${colors.dim}Waiting for server to start...${colors.reset}`)
|
|
182
|
+
await waitForServer(PORT)
|
|
183
|
+
|
|
184
|
+
console.log(`${colors.green}${colors.bright}Ready!${colors.reset}\n`)
|
|
185
|
+
|
|
186
|
+
if (!noOpen) {
|
|
187
|
+
setTimeout(() => openBrowser(WEB_URL), 500)
|
|
188
|
+
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
console.log(`${colors.red}${err.message}${colors.reset}`)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Handle shutdown
|
|
194
|
+
const cleanup = () => {
|
|
195
|
+
console.log(`\n${colors.yellow}Shutting down...${colors.reset}`)
|
|
196
|
+
webProc.kill()
|
|
197
|
+
process.exit(0)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
process.on('SIGINT', cleanup)
|
|
201
|
+
process.on('SIGTERM', cleanup)
|
|
202
|
+
|
|
203
|
+
webProc.on('error', (err) => {
|
|
204
|
+
console.log(`${colors.red}Error: ${err.message}${colors.reset}`)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
webProc.on('exit', (code) => {
|
|
208
|
+
if (code !== 0 && code !== null) {
|
|
209
|
+
console.log(`${colors.red}Exited with code ${code}${colors.reset}`)
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
main().catch((err) => {
|
|
215
|
+
console.error(`${colors.red}Error: ${err.message}${colors.reset}`)
|
|
216
|
+
process.exit(1)
|
|
217
|
+
})
|
package/bin/prjct
CHANGED
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
const { VERSION } = require('../core/utils/version')
|
|
10
10
|
const editorsConfig = require('../core/infrastructure/editors-config')
|
|
11
11
|
|
|
12
|
+
// Check for special subcommands that bypass normal CLI
|
|
13
|
+
const args = process.argv.slice(2)
|
|
14
|
+
if (args[0] === 'dev') {
|
|
15
|
+
// Launch prjct dev environment
|
|
16
|
+
require('./dev.js')
|
|
17
|
+
process.exitCode = 0
|
|
18
|
+
} else {
|
|
19
|
+
|
|
12
20
|
// Ensure setup has run for this version
|
|
13
21
|
;(async function ensureSetup() {
|
|
14
22
|
try {
|
|
@@ -32,3 +40,5 @@ const editorsConfig = require('../core/infrastructure/editors-config')
|
|
|
32
40
|
// Continue to main CLI logic
|
|
33
41
|
require('../core/index')
|
|
34
42
|
})()
|
|
43
|
+
|
|
44
|
+
} // end else
|
package/bin/serve.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* prjct serve - Start the web server
|
|
5
|
+
*
|
|
6
|
+
* Launches the prjct web interface with Claude Code CLI integration.
|
|
7
|
+
* Uses your existing Claude subscription via PTY - no API costs!
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { spawn } = require('child_process')
|
|
11
|
+
const path = require('path')
|
|
12
|
+
const fs = require('fs')
|
|
13
|
+
|
|
14
|
+
const serverDir = path.join(__dirname, '..', 'packages', 'server')
|
|
15
|
+
const webDir = path.join(__dirname, '..', 'packages', 'web')
|
|
16
|
+
|
|
17
|
+
// Parse arguments
|
|
18
|
+
const args = process.argv.slice(2)
|
|
19
|
+
const portArg = args.find(a => a.startsWith('--port='))
|
|
20
|
+
const port = portArg ? portArg.split('=')[1] : '3333'
|
|
21
|
+
const webPort = '3000'
|
|
22
|
+
|
|
23
|
+
// Check if packages exist
|
|
24
|
+
if (!fs.existsSync(serverDir) || !fs.existsSync(webDir)) {
|
|
25
|
+
console.error('❌ Web packages not found. Run from prjct-cli directory.')
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log(`
|
|
30
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
31
|
+
║ ║
|
|
32
|
+
║ ⚡ prjct - Developer Momentum ║
|
|
33
|
+
║ ║
|
|
34
|
+
║ Starting web server... ║
|
|
35
|
+
║ ║
|
|
36
|
+
║ API: http://localhost:${port} ║
|
|
37
|
+
║ Web: http://localhost:${webPort} ║
|
|
38
|
+
║ Claude: ws://localhost:${port}/ws/claude ║
|
|
39
|
+
║ ║
|
|
40
|
+
║ Using your Claude subscription - $0 API costs ║
|
|
41
|
+
║ ║
|
|
42
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
43
|
+
`)
|
|
44
|
+
|
|
45
|
+
// Start server
|
|
46
|
+
const server = spawn('npm', ['run', 'dev'], {
|
|
47
|
+
cwd: serverDir,
|
|
48
|
+
stdio: 'inherit',
|
|
49
|
+
shell: true,
|
|
50
|
+
env: { ...process.env, PORT: port }
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Start web dev server
|
|
54
|
+
const web = spawn('npm', ['run', 'dev'], {
|
|
55
|
+
cwd: webDir,
|
|
56
|
+
stdio: 'inherit',
|
|
57
|
+
shell: true
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// Handle shutdown
|
|
61
|
+
const cleanup = () => {
|
|
62
|
+
console.log('\n👋 Shutting down prjct server...')
|
|
63
|
+
server.kill()
|
|
64
|
+
web.kill()
|
|
65
|
+
process.exit(0)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
process.on('SIGINT', cleanup)
|
|
69
|
+
process.on('SIGTERM', cleanup)
|
|
70
|
+
|
|
71
|
+
// Handle errors
|
|
72
|
+
server.on('error', (err) => {
|
|
73
|
+
console.error('Server error:', err.message)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
web.on('error', (err) => {
|
|
77
|
+
console.error('Web error:', err.message)
|
|
78
|
+
})
|
|
@@ -1,16 +1,19 @@
|
|
|
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
|
*/
|
|
@@ -22,9 +25,8 @@ const templateLoader = require('./template-loader')
|
|
|
22
25
|
const contextBuilder = require('./context-builder')
|
|
23
26
|
const promptBuilder = require('./prompt-builder')
|
|
24
27
|
const toolRegistry = require('./tool-registry')
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const ContextEstimator = require('../domain/context-estimator')
|
|
28
|
+
// REMOVED: MandatoryAgentRouter, ContextFilter, ContextEstimator
|
|
29
|
+
// Agent assignment is 100% agentic - Claude decides via templates
|
|
28
30
|
const { validate, formatError } = require('./validation-rules')
|
|
29
31
|
const loopDetector = require('./loop-detector')
|
|
30
32
|
const chainOfThought = require('./chain-of-thought')
|
|
@@ -45,9 +47,8 @@ const RUNNING_FILE = path.join(os.homedir(), '.prjct-cli', '.running')
|
|
|
45
47
|
|
|
46
48
|
class CommandExecutor {
|
|
47
49
|
constructor() {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.contextEstimator = null
|
|
50
|
+
// 100% AGENTIC: No agent router here
|
|
51
|
+
// Claude decides agent assignment via templates and Task tool
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -173,72 +174,18 @@ class CommandExecutor {
|
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
// 3.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
this.isTaskCommand(commandName) ||
|
|
180
|
-
this.shouldUseAgent(commandName))
|
|
181
|
-
|
|
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
|
|
182
180
|
let context = metadataContext
|
|
183
|
-
let assignedAgent = null
|
|
184
|
-
|
|
185
|
-
// MANDATORY: Assign specialized agent for task commands
|
|
186
|
-
if (requiresAgent) {
|
|
187
|
-
// 4. Create task object for analysis
|
|
188
|
-
const task = {
|
|
189
|
-
description: params.task || params.description || commandName,
|
|
190
|
-
type: commandName
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 5. LAZY CONTEXT: Analyze task FIRST, then estimate files needed
|
|
194
|
-
// This avoids reading all files before knowing what we need
|
|
195
|
-
const agentAssignment = await this.agentRouter.executeTask(
|
|
196
|
-
task,
|
|
197
|
-
metadataContext, // Only metadata, no files yet
|
|
198
|
-
projectPath
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
assignedAgent = agentAssignment.agent
|
|
202
|
-
const taskAnalysis = agentAssignment.taskAnalysis
|
|
203
|
-
|
|
204
|
-
// Validate agent was assigned
|
|
205
|
-
if (!assignedAgent || !assignedAgent.name) {
|
|
206
|
-
throw new Error(
|
|
207
|
-
`CRITICAL: Failed to assign agent for command "${commandName}". ` +
|
|
208
|
-
`System requires ALL task commands to use specialized agents.`
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// 6. PRE-FILTER: Estimate which files are needed BEFORE reading
|
|
213
|
-
if (!this.contextEstimator) {
|
|
214
|
-
this.contextEstimator = new ContextEstimator()
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const estimatedFiles = await this.contextEstimator.estimateFiles(
|
|
218
|
-
taskAnalysis,
|
|
219
|
-
projectPath
|
|
220
|
-
)
|
|
221
181
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
estimatedFiles, // Pre-filtered file list
|
|
230
|
-
fileCount: estimatedFiles.length
|
|
231
|
-
}
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
context = {
|
|
235
|
-
...filtered,
|
|
236
|
-
agent: assignedAgent,
|
|
237
|
-
originalSize: estimatedFiles.length, // Estimated, not actual full size
|
|
238
|
-
filteredSize: filtered.files?.length || 0,
|
|
239
|
-
reduction: filtered.metrics?.reductionPercent || 0,
|
|
240
|
-
lazyLoaded: true // Flag indicating lazy loading was used
|
|
241
|
-
}
|
|
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
|
|
242
189
|
}
|
|
243
190
|
|
|
244
191
|
// 6. Load state with filtered context
|
|
@@ -285,7 +232,7 @@ class CommandExecutor {
|
|
|
285
232
|
)
|
|
286
233
|
}
|
|
287
234
|
|
|
288
|
-
// 9. Build prompt
|
|
235
|
+
// 9. Build prompt - NO agent assignment here, Claude decides via templates
|
|
289
236
|
const planInfo = {
|
|
290
237
|
isPlanning: requiresPlanning || isInPlanningMode,
|
|
291
238
|
requiresApproval: isDestructive && !params.approved,
|
|
@@ -295,13 +242,11 @@ class CommandExecutor {
|
|
|
295
242
|
template.frontmatter['allowed-tools'] || []
|
|
296
243
|
)
|
|
297
244
|
}
|
|
298
|
-
|
|
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)
|
|
299
247
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
console.log(`🤖 Task assigned to: ${assignedAgent.name}`)
|
|
303
|
-
console.log(`📉 Context reduced by: ${context.reduction}%`)
|
|
304
|
-
}
|
|
248
|
+
// Log agentic mode
|
|
249
|
+
console.log(`🤖 Agentic delegation enabled - Claude will assign agent via Task tool`)
|
|
305
250
|
|
|
306
251
|
// Record successful attempt
|
|
307
252
|
loopDetector.recordSuccess(commandName, loopContext)
|
|
@@ -315,8 +260,10 @@ class CommandExecutor {
|
|
|
315
260
|
context,
|
|
316
261
|
state,
|
|
317
262
|
prompt,
|
|
318
|
-
|
|
319
|
-
|
|
263
|
+
// AGENTIC: No pre-assigned agent - Claude delegates via Task tool
|
|
264
|
+
agenticDelegation: true,
|
|
265
|
+
agentsPath: context.agentsPath,
|
|
266
|
+
agentRoutingPath: context.agentRoutingPath,
|
|
320
267
|
reasoning, // Chain of thought results
|
|
321
268
|
thinkBlock, // Think blocks (P3.1)
|
|
322
269
|
groundTruth: groundTruthResult, // Ground truth verification (P1.3)
|
|
@@ -406,30 +353,9 @@ class CommandExecutor {
|
|
|
406
353
|
}
|
|
407
354
|
}
|
|
408
355
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
isTaskCommand(commandName) {
|
|
413
|
-
const taskCommands = [
|
|
414
|
-
'work', 'now', 'build', 'feature', 'bug', 'done',
|
|
415
|
-
'task', 'design', 'cleanup', 'fix', 'test'
|
|
416
|
-
]
|
|
417
|
-
return taskCommands.includes(commandName)
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Determine if command should use an agent
|
|
422
|
-
* Expanded list of commands that benefit from agent specialization
|
|
423
|
-
*/
|
|
424
|
-
shouldUseAgent(commandName) {
|
|
425
|
-
// Commands that should ALWAYS use agents
|
|
426
|
-
const agentCommands = [
|
|
427
|
-
'work', 'now', 'build', 'feature', 'bug', 'done',
|
|
428
|
-
'task', 'design', 'cleanup', 'fix', 'test',
|
|
429
|
-
'sync', 'analyze' // These analyze/modify code, need specialization
|
|
430
|
-
]
|
|
431
|
-
return agentCommands.includes(commandName)
|
|
432
|
-
}
|
|
356
|
+
// REMOVED: isTaskCommand() and shouldUseAgent()
|
|
357
|
+
// Agent assignment is now 100% agentic - Claude decides via templates
|
|
358
|
+
// See templates/agentic/agent-routing.md
|
|
433
359
|
|
|
434
360
|
/**
|
|
435
361
|
* Execute tool with permission check
|