prjct-cli 0.6.0 → 0.7.1
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 +67 -6
- package/CLAUDE.md +442 -36
- package/README.md +47 -54
- package/bin/prjct +174 -240
- package/core/agentic/command-executor.js +113 -0
- package/core/agentic/context-builder.js +85 -0
- package/core/agentic/prompt-builder.js +86 -0
- package/core/agentic/template-loader.js +104 -0
- package/core/agentic/tool-registry.js +117 -0
- package/core/command-registry.js +109 -65
- package/core/commands.js +2213 -2173
- package/core/domain/agent-generator.js +118 -0
- package/core/domain/analyzer.js +211 -0
- package/core/domain/architect-session.js +300 -0
- package/core/{agents → infrastructure/agents}/claude-agent.js +16 -13
- package/core/{author-detector.js → infrastructure/author-detector.js} +3 -1
- package/core/{capability-installer.js → infrastructure/capability-installer.js} +3 -6
- package/core/{command-installer.js → infrastructure/command-installer.js} +5 -3
- package/core/{config-manager.js → infrastructure/config-manager.js} +4 -4
- package/core/{editors-config.js → infrastructure/editors-config.js} +2 -10
- package/core/{migrator.js → infrastructure/migrator.js} +34 -19
- package/core/{path-manager.js → infrastructure/path-manager.js} +20 -44
- package/core/{session-manager.js → infrastructure/session-manager.js} +45 -105
- package/core/{update-checker.js → infrastructure/update-checker.js} +67 -67
- package/core/{animations-simple.js → utils/animations.js} +3 -23
- package/core/utils/date-helper.js +238 -0
- package/core/utils/file-helper.js +327 -0
- package/core/utils/jsonl-helper.js +206 -0
- package/core/{project-capabilities.js → utils/project-capabilities.js} +21 -22
- package/core/utils/session-helper.js +277 -0
- package/core/{version.js → utils/version.js} +1 -1
- package/package.json +4 -12
- package/templates/agents/AGENTS.md +101 -27
- package/templates/analysis/analyze.md +84 -0
- package/templates/commands/analyze.md +9 -2
- package/templates/commands/bug.md +79 -0
- package/templates/commands/build.md +5 -2
- package/templates/commands/cleanup.md +5 -2
- package/templates/commands/design.md +5 -2
- package/templates/commands/done.md +4 -2
- package/templates/commands/feature.md +113 -0
- package/templates/commands/fix.md +41 -10
- package/templates/commands/git.md +7 -2
- package/templates/commands/help.md +2 -2
- package/templates/commands/idea.md +14 -5
- package/templates/commands/init.md +62 -7
- package/templates/commands/next.md +4 -2
- package/templates/commands/now.md +4 -2
- package/templates/commands/progress.md +27 -5
- package/templates/commands/recap.md +39 -10
- package/templates/commands/roadmap.md +19 -5
- package/templates/commands/ship.md +118 -16
- package/templates/commands/status.md +4 -2
- package/templates/commands/sync.md +19 -15
- package/templates/commands/task.md +4 -2
- package/templates/commands/test.md +5 -2
- package/templates/commands/workflow.md +4 -2
- package/core/agent-generator.js +0 -525
- package/core/analyzer.js +0 -600
- package/core/animations.js +0 -277
- package/core/ascii-graphics.js +0 -433
- package/core/git-integration.js +0 -401
- package/core/task-schema.js +0 -342
- package/core/workflow-engine.js +0 -213
- package/core/workflow-prompts.js +0 -192
- package/core/workflow-rules.js +0 -147
- package/scripts/post-install.js +0 -121
- package/scripts/preuninstall.js +0 -94
- package/scripts/verify-installation.sh +0 -158
- package/templates/agents/be.template.md +0 -27
- package/templates/agents/coordinator.template.md +0 -34
- package/templates/agents/data.template.md +0 -27
- package/templates/agents/devops.template.md +0 -27
- package/templates/agents/fe.template.md +0 -27
- package/templates/agents/mobile.template.md +0 -27
- package/templates/agents/qa.template.md +0 -27
- package/templates/agents/scribe.template.md +0 -29
- package/templates/agents/security.template.md +0 -27
- package/templates/agents/ux.template.md +0 -27
- package/templates/commands/context.md +0 -36
- package/templates/commands/stuck.md +0 -36
- package/templates/examples/natural-language-examples.md +0 -532
- /package/core/{agent-detector.js → infrastructure/agent-detector.js} +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Builder
|
|
3
|
+
* Builds prompts for Claude based on templates and context
|
|
4
|
+
* Claude decides what to do - NO if/else logic here
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class PromptBuilder {
|
|
8
|
+
/**
|
|
9
|
+
* Build execution prompt for Claude
|
|
10
|
+
* @param {Object} template - Template from template-loader
|
|
11
|
+
* @param {Object} context - Context from context-builder
|
|
12
|
+
* @param {Object} state - Current state from context-builder
|
|
13
|
+
* @returns {string} Prompt for Claude
|
|
14
|
+
*/
|
|
15
|
+
build(template, context, state) {
|
|
16
|
+
const parts = []
|
|
17
|
+
|
|
18
|
+
// 1. Command instructions from template
|
|
19
|
+
parts.push('# Command Instructions\n')
|
|
20
|
+
parts.push(template.content)
|
|
21
|
+
parts.push('\n')
|
|
22
|
+
|
|
23
|
+
// 2. Allowed tools
|
|
24
|
+
if (template.frontmatter['allowed-tools']) {
|
|
25
|
+
parts.push('## Allowed Tools\n')
|
|
26
|
+
parts.push(`You can use: ${template.frontmatter['allowed-tools'].join(', ')}\n\n`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 3. Project context
|
|
30
|
+
parts.push('## Project Context\n')
|
|
31
|
+
parts.push(`- Project ID: ${context.projectId}\n`)
|
|
32
|
+
parts.push(`- Timestamp: ${context.timestamp}\n`)
|
|
33
|
+
parts.push('\n')
|
|
34
|
+
|
|
35
|
+
// 4. Current state (only non-null files)
|
|
36
|
+
parts.push('## Current State\n')
|
|
37
|
+
for (const [key, content] of Object.entries(state)) {
|
|
38
|
+
if (content && content.trim()) {
|
|
39
|
+
parts.push(`### ${key}\n`)
|
|
40
|
+
parts.push('```\n')
|
|
41
|
+
parts.push(content)
|
|
42
|
+
parts.push('\n```\n\n')
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 5. Command parameters
|
|
47
|
+
if (Object.keys(context.params).length > 0) {
|
|
48
|
+
parts.push('## Parameters\n')
|
|
49
|
+
for (const [key, value] of Object.entries(context.params)) {
|
|
50
|
+
parts.push(`- ${key}: ${value}\n`)
|
|
51
|
+
}
|
|
52
|
+
parts.push('\n')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 6. Final instruction
|
|
56
|
+
parts.push('## Execute\n')
|
|
57
|
+
parts.push('Based on the instructions above, execute the command.\n')
|
|
58
|
+
parts.push('Use ONLY the allowed tools.\n')
|
|
59
|
+
parts.push('Make decisions based on context - do not follow rigid if/else rules.\n')
|
|
60
|
+
|
|
61
|
+
return parts.join('')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Build analysis prompt
|
|
66
|
+
* Used for tasks that need Claude to analyze before acting
|
|
67
|
+
* @param {string} analysisType - Type of analysis
|
|
68
|
+
* @param {Object} context - Context
|
|
69
|
+
* @returns {string} Analysis prompt
|
|
70
|
+
*/
|
|
71
|
+
buildAnalysis(analysisType, context) {
|
|
72
|
+
const parts = []
|
|
73
|
+
|
|
74
|
+
parts.push(`# Analyze: ${analysisType}\n\n`)
|
|
75
|
+
parts.push('Read the project context and provide your analysis.\n')
|
|
76
|
+
parts.push('No predetermined patterns - decide based on what you find.\n\n')
|
|
77
|
+
|
|
78
|
+
parts.push('## Project Context\n')
|
|
79
|
+
parts.push(`- Path: ${context.projectPath}\n`)
|
|
80
|
+
parts.push(`- ID: ${context.projectId}\n\n`)
|
|
81
|
+
|
|
82
|
+
return parts.join('')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = new PromptBuilder()
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Loader
|
|
3
|
+
* Loads command templates with frontmatter parsing
|
|
4
|
+
* Templates define what Claude should do - NO if/else logic
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs').promises
|
|
8
|
+
const path = require('path')
|
|
9
|
+
|
|
10
|
+
class TemplateLoader {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.templatesDir = path.join(__dirname, '..', '..', 'templates', 'commands')
|
|
13
|
+
this.cache = new Map()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Load template with frontmatter
|
|
18
|
+
* @param {string} commandName - Command name (e.g., 'now', 'done', 'ship')
|
|
19
|
+
* @returns {Promise<{frontmatter: Object, content: string}>}
|
|
20
|
+
*/
|
|
21
|
+
async load(commandName) {
|
|
22
|
+
// Check cache first
|
|
23
|
+
if (this.cache.has(commandName)) {
|
|
24
|
+
return this.cache.get(commandName)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const templatePath = path.join(this.templatesDir, `${commandName}.md`)
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const rawContent = await fs.readFile(templatePath, 'utf-8')
|
|
31
|
+
const parsed = this.parseFrontmatter(rawContent)
|
|
32
|
+
|
|
33
|
+
// Cache result
|
|
34
|
+
this.cache.set(commandName, parsed)
|
|
35
|
+
|
|
36
|
+
return parsed
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw new Error(`Template not found: ${commandName}.md`)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Parse frontmatter from markdown
|
|
44
|
+
* @param {string} content - Raw markdown content
|
|
45
|
+
* @returns {Object} Parsed template with frontmatter and content
|
|
46
|
+
*/
|
|
47
|
+
parseFrontmatter(content) {
|
|
48
|
+
const frontmatterRegex = /^---\n([\s\S]+?)\n---\n([\s\S]*)$/
|
|
49
|
+
const match = content.match(frontmatterRegex)
|
|
50
|
+
|
|
51
|
+
if (!match) {
|
|
52
|
+
return {
|
|
53
|
+
frontmatter: {},
|
|
54
|
+
content: content.trim(),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const [, frontmatterText, mainContent] = match
|
|
59
|
+
const frontmatter = {}
|
|
60
|
+
|
|
61
|
+
// Parse frontmatter lines
|
|
62
|
+
frontmatterText.split('\n').forEach((line) => {
|
|
63
|
+
const [key, ...valueParts] = line.split(':')
|
|
64
|
+
if (key && valueParts.length > 0) {
|
|
65
|
+
const value = valueParts.join(':').trim()
|
|
66
|
+
|
|
67
|
+
// Parse arrays
|
|
68
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
69
|
+
frontmatter[key.trim()] = value
|
|
70
|
+
.slice(1, -1)
|
|
71
|
+
.split(',')
|
|
72
|
+
.map((v) => v.trim())
|
|
73
|
+
} else {
|
|
74
|
+
// Remove quotes if present
|
|
75
|
+
frontmatter[key.trim()] = value.replace(/^["']|["']$/g, '')
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
frontmatter,
|
|
82
|
+
content: mainContent.trim(),
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get allowed tools for a command
|
|
88
|
+
* @param {string} commandName - Command name
|
|
89
|
+
* @returns {Promise<string[]>}
|
|
90
|
+
*/
|
|
91
|
+
async getAllowedTools(commandName) {
|
|
92
|
+
const template = await this.load(commandName)
|
|
93
|
+
return template.frontmatter['allowed-tools'] || []
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Clear cache (useful for testing)
|
|
98
|
+
*/
|
|
99
|
+
clearCache() {
|
|
100
|
+
this.cache.clear()
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = new TemplateLoader()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry
|
|
3
|
+
* Maps allowed-tools from templates to actual functions
|
|
4
|
+
* Simple I/O operations - NO business logic, NO if/else
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs').promises
|
|
8
|
+
const path = require('path')
|
|
9
|
+
const { promisify } = require('util')
|
|
10
|
+
const { exec: execCallback } = require('child_process')
|
|
11
|
+
const exec = promisify(execCallback)
|
|
12
|
+
|
|
13
|
+
class ToolRegistry {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.tools = {
|
|
16
|
+
Read: this.read.bind(this),
|
|
17
|
+
Write: this.write.bind(this),
|
|
18
|
+
Bash: this.bash.bind(this),
|
|
19
|
+
Exec: this.bash.bind(this), // Alias
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get tool function by name
|
|
25
|
+
* @param {string} toolName - Tool name (e.g., 'Read', 'Write')
|
|
26
|
+
* @returns {Function}
|
|
27
|
+
*/
|
|
28
|
+
get(toolName) {
|
|
29
|
+
const tool = this.tools[toolName]
|
|
30
|
+
if (!tool) {
|
|
31
|
+
throw new Error(`Unknown tool: ${toolName}`)
|
|
32
|
+
}
|
|
33
|
+
return tool
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check if tool is allowed
|
|
38
|
+
* @param {string} toolName - Tool name
|
|
39
|
+
* @param {string[]} allowedTools - List of allowed tools
|
|
40
|
+
* @returns {boolean}
|
|
41
|
+
*/
|
|
42
|
+
isAllowed(toolName, allowedTools) {
|
|
43
|
+
return allowedTools.includes(toolName)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Read file
|
|
48
|
+
* @param {string} filePath - File path
|
|
49
|
+
* @returns {Promise<string>}
|
|
50
|
+
*/
|
|
51
|
+
async read(filePath) {
|
|
52
|
+
try {
|
|
53
|
+
return await fs.readFile(filePath, 'utf-8')
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return null
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Write file
|
|
61
|
+
* @param {string} filePath - File path
|
|
62
|
+
* @param {string} content - Content to write
|
|
63
|
+
* @returns {Promise<void>}
|
|
64
|
+
*/
|
|
65
|
+
async write(filePath, content) {
|
|
66
|
+
// Ensure directory exists
|
|
67
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
68
|
+
await fs.writeFile(filePath, content, 'utf-8')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Execute bash command
|
|
73
|
+
* @param {string} command - Command to execute
|
|
74
|
+
* @returns {Promise<{stdout: string, stderr: string}>}
|
|
75
|
+
*/
|
|
76
|
+
async bash(command) {
|
|
77
|
+
try {
|
|
78
|
+
const { stdout, stderr } = await exec(command)
|
|
79
|
+
return { stdout, stderr }
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return {
|
|
82
|
+
stdout: '',
|
|
83
|
+
stderr: error.message,
|
|
84
|
+
error: true,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if file exists
|
|
91
|
+
* @param {string} filePath - File path
|
|
92
|
+
* @returns {Promise<boolean>}
|
|
93
|
+
*/
|
|
94
|
+
async exists(filePath) {
|
|
95
|
+
try {
|
|
96
|
+
await fs.access(filePath)
|
|
97
|
+
return true
|
|
98
|
+
} catch {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* List directory
|
|
105
|
+
* @param {string} dirPath - Directory path
|
|
106
|
+
* @returns {Promise<string[]>}
|
|
107
|
+
*/
|
|
108
|
+
async list(dirPath) {
|
|
109
|
+
try {
|
|
110
|
+
return await fs.readdir(dirPath)
|
|
111
|
+
} catch {
|
|
112
|
+
return []
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = new ToolRegistry()
|
package/core/command-registry.js
CHANGED
|
@@ -20,48 +20,67 @@ const COMMANDS = [
|
|
|
20
20
|
category: 'core',
|
|
21
21
|
description: 'Deep project analysis and initialization',
|
|
22
22
|
usage: {
|
|
23
|
-
claude: '/p:init',
|
|
24
|
-
terminal: 'prjct init',
|
|
23
|
+
claude: '/p:init "[idea]"',
|
|
24
|
+
terminal: 'prjct init "[idea]"',
|
|
25
25
|
},
|
|
26
|
-
params:
|
|
26
|
+
params: '[idea]',
|
|
27
27
|
implemented: true,
|
|
28
28
|
hasTemplate: true,
|
|
29
29
|
icon: 'Zap',
|
|
30
30
|
requiresInit: false,
|
|
31
31
|
blockingRules: null,
|
|
32
32
|
features: [
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
33
|
+
'Architect mode for blank projects',
|
|
34
|
+
'Auto tech stack recommendation',
|
|
35
|
+
'Project structure generation',
|
|
36
|
+
'Initial roadmap creation',
|
|
37
|
+
'Analyzes existing codebases',
|
|
37
38
|
],
|
|
38
39
|
},
|
|
39
40
|
|
|
40
|
-
// 2.
|
|
41
|
+
// 2. Feature with Roadmap (NEW - replaces idea)
|
|
41
42
|
{
|
|
42
|
-
name: '
|
|
43
|
+
name: 'feature',
|
|
43
44
|
category: 'core',
|
|
44
|
-
description: '
|
|
45
|
+
description: 'Add feature with value analysis, roadmap, and task breakdown',
|
|
45
46
|
usage: {
|
|
46
|
-
claude: '/p:
|
|
47
|
-
terminal: 'prjct
|
|
47
|
+
claude: '/p:feature "add unit testing"',
|
|
48
|
+
terminal: 'prjct feature "add unit testing"',
|
|
48
49
|
},
|
|
49
|
-
params: '<
|
|
50
|
-
implemented:
|
|
50
|
+
params: '<description>',
|
|
51
|
+
implemented: true,
|
|
51
52
|
hasTemplate: true,
|
|
52
|
-
icon: '
|
|
53
|
+
icon: 'Package',
|
|
53
54
|
requiresInit: true,
|
|
54
55
|
blockingRules: null,
|
|
55
56
|
features: [
|
|
56
|
-
'
|
|
57
|
-
'
|
|
57
|
+
'Value analysis (impact/effort/timing)',
|
|
58
|
+
'Auto roadmap generation',
|
|
58
59
|
'Task breakdown',
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'Interactive keep/discard',
|
|
60
|
+
'Auto-start first task',
|
|
61
|
+
'Timing recommendations',
|
|
62
62
|
],
|
|
63
63
|
},
|
|
64
64
|
|
|
65
|
+
// DEPRECATED: Use /p:feature instead
|
|
66
|
+
{
|
|
67
|
+
name: 'idea',
|
|
68
|
+
category: 'deprecated',
|
|
69
|
+
description: '[DEPRECATED] Use /p:feature instead',
|
|
70
|
+
usage: {
|
|
71
|
+
claude: null,
|
|
72
|
+
terminal: null,
|
|
73
|
+
},
|
|
74
|
+
params: '<text>',
|
|
75
|
+
implemented: false,
|
|
76
|
+
hasTemplate: true,
|
|
77
|
+
icon: 'Lightbulb',
|
|
78
|
+
requiresInit: true,
|
|
79
|
+
blockingRules: null,
|
|
80
|
+
deprecated: true,
|
|
81
|
+
replacedBy: 'feature',
|
|
82
|
+
},
|
|
83
|
+
|
|
65
84
|
// 3. Strategic Roadmap
|
|
66
85
|
{
|
|
67
86
|
name: 'roadmap',
|
|
@@ -72,7 +91,7 @@ const COMMANDS = [
|
|
|
72
91
|
terminal: 'prjct roadmap',
|
|
73
92
|
},
|
|
74
93
|
params: null,
|
|
75
|
-
implemented:
|
|
94
|
+
implemented: true,
|
|
76
95
|
hasTemplate: true,
|
|
77
96
|
icon: 'Map',
|
|
78
97
|
requiresInit: true,
|
|
@@ -95,7 +114,7 @@ const COMMANDS = [
|
|
|
95
114
|
terminal: 'prjct status',
|
|
96
115
|
},
|
|
97
116
|
params: null,
|
|
98
|
-
implemented:
|
|
117
|
+
implemented: true,
|
|
99
118
|
hasTemplate: true,
|
|
100
119
|
icon: 'BarChart3',
|
|
101
120
|
requiresInit: true,
|
|
@@ -136,7 +155,7 @@ const COMMANDS = [
|
|
|
136
155
|
terminal: 'prjct build "implement auth"',
|
|
137
156
|
},
|
|
138
157
|
params: '<task> | [1-5]',
|
|
139
|
-
implemented:
|
|
158
|
+
implemented: true,
|
|
140
159
|
hasTemplate: true,
|
|
141
160
|
icon: 'Play',
|
|
142
161
|
requiresInit: true,
|
|
@@ -209,36 +228,87 @@ const COMMANDS = [
|
|
|
209
228
|
terminal: 'prjct ship "user authentication"',
|
|
210
229
|
},
|
|
211
230
|
params: '<feature>',
|
|
212
|
-
implemented:
|
|
231
|
+
implemented: true, // Complete automated workflow
|
|
213
232
|
hasTemplate: true,
|
|
214
233
|
icon: 'Rocket',
|
|
215
234
|
requiresInit: true,
|
|
216
235
|
blockingRules: null,
|
|
217
236
|
features: [
|
|
218
|
-
'
|
|
219
|
-
'
|
|
220
|
-
'
|
|
221
|
-
'
|
|
222
|
-
'
|
|
237
|
+
'Lint checks (non-blocking)',
|
|
238
|
+
'Run tests (non-blocking)',
|
|
239
|
+
'Update docs',
|
|
240
|
+
'Update version',
|
|
241
|
+
'Update CHANGELOG',
|
|
242
|
+
'Git commit + push',
|
|
243
|
+
'Recommend compact',
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
// 10. Bug Tracking
|
|
248
|
+
{
|
|
249
|
+
name: 'bug',
|
|
250
|
+
category: 'core',
|
|
251
|
+
description: 'Report and track bugs with priority',
|
|
252
|
+
usage: {
|
|
253
|
+
claude: '/p:bug "login button not working"',
|
|
254
|
+
terminal: 'prjct bug "login button not working"',
|
|
255
|
+
},
|
|
256
|
+
params: '<description>',
|
|
257
|
+
implemented: true,
|
|
258
|
+
hasTemplate: true,
|
|
259
|
+
icon: 'Bug',
|
|
260
|
+
requiresInit: true,
|
|
261
|
+
blockingRules: null,
|
|
262
|
+
features: [
|
|
263
|
+
'Auto-detect severity (critical/high/medium/low)',
|
|
264
|
+
'Priority placement in next.md',
|
|
265
|
+
'Bug tracking in memory',
|
|
266
|
+
'Quick bug resolution workflow',
|
|
267
|
+
],
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
// 11. Architect Execute
|
|
271
|
+
{
|
|
272
|
+
name: 'architect',
|
|
273
|
+
category: 'core',
|
|
274
|
+
description: 'Execute architect plan and generate code',
|
|
275
|
+
usage: {
|
|
276
|
+
claude: '/p:architect execute',
|
|
277
|
+
terminal: 'prjct architect execute',
|
|
278
|
+
},
|
|
279
|
+
params: 'execute',
|
|
280
|
+
implemented: true,
|
|
281
|
+
hasTemplate: false,
|
|
282
|
+
icon: 'Hammer',
|
|
283
|
+
requiresInit: true,
|
|
284
|
+
blockingRules: null,
|
|
285
|
+
features: [
|
|
286
|
+
'Reads architect-session.md plan',
|
|
287
|
+
'Generates code structure',
|
|
288
|
+
'Uses Context7 for documentation',
|
|
289
|
+
'Language-agnostic implementation',
|
|
223
290
|
],
|
|
224
291
|
},
|
|
225
292
|
|
|
226
293
|
// ===== OPTIONAL COMMANDS (Advanced features) =====
|
|
294
|
+
|
|
295
|
+
// DEPRECATED: Workflow is now automatic in /p:ship
|
|
227
296
|
{
|
|
228
297
|
name: 'workflow',
|
|
229
|
-
category: '
|
|
230
|
-
description: '
|
|
298
|
+
category: 'deprecated',
|
|
299
|
+
description: '[DEPRECATED] Workflow is now automatic in /p:ship',
|
|
231
300
|
usage: {
|
|
232
|
-
claude:
|
|
233
|
-
terminal:
|
|
301
|
+
claude: null,
|
|
302
|
+
terminal: null,
|
|
234
303
|
},
|
|
235
304
|
params: null,
|
|
236
|
-
implemented:
|
|
305
|
+
implemented: false,
|
|
237
306
|
hasTemplate: true,
|
|
238
307
|
icon: 'GitBranch',
|
|
239
308
|
requiresInit: true,
|
|
240
309
|
blockingRules: null,
|
|
241
|
-
|
|
310
|
+
deprecated: true,
|
|
311
|
+
replacedBy: 'ship',
|
|
242
312
|
},
|
|
243
313
|
{
|
|
244
314
|
name: 'design',
|
|
@@ -459,7 +529,7 @@ const registry = {
|
|
|
459
529
|
const notImplemented = COMMANDS.filter((c) => c.hasTemplate && !c.implemented)
|
|
460
530
|
if (notImplemented.length > 0) {
|
|
461
531
|
issues.push(
|
|
462
|
-
`Commands with templates but not implemented: ${notImplemented.map((c) => c.name).join(', ')}
|
|
532
|
+
`Commands with templates but not implemented: ${notImplemented.map((c) => c.name).join(', ')}`
|
|
463
533
|
)
|
|
464
534
|
}
|
|
465
535
|
|
|
@@ -468,7 +538,7 @@ const registry = {
|
|
|
468
538
|
const invalidCategories = COMMANDS.filter((c) => !validCategories.includes(c.category))
|
|
469
539
|
if (invalidCategories.length > 0) {
|
|
470
540
|
issues.push(
|
|
471
|
-
`Invalid categories: ${invalidCategories.map((c) => `${c.name}:${c.category}`).join(', ')}
|
|
541
|
+
`Invalid categories: ${invalidCategories.map((c) => `${c.name}:${c.category}`).join(', ')}`
|
|
472
542
|
)
|
|
473
543
|
}
|
|
474
544
|
|
|
@@ -495,36 +565,10 @@ const registry = {
|
|
|
495
565
|
|
|
496
566
|
/**
|
|
497
567
|
* Get commands with blocking rules
|
|
568
|
+
* NOTE: Blocking rules are now handled by Claude reading templates, not deterministic code
|
|
498
569
|
*/
|
|
499
570
|
getWithBlockingRules: () => COMMANDS.filter((c) => c.blockingRules !== null),
|
|
500
571
|
|
|
501
|
-
/**
|
|
502
|
-
* Check if command can execute based on blocking rules
|
|
503
|
-
*/
|
|
504
|
-
canExecute: (commandName, context = {}) => {
|
|
505
|
-
const command = COMMANDS.find((c) => c.name === commandName)
|
|
506
|
-
if (!command) return { allowed: false, message: 'Command not found' }
|
|
507
|
-
if (!command.blockingRules) return { allowed: true }
|
|
508
|
-
|
|
509
|
-
// Example context checks - should be implemented per command
|
|
510
|
-
const { hasActiveTask, hasContent } = context
|
|
511
|
-
|
|
512
|
-
if (commandName === 'build' && hasActiveTask) {
|
|
513
|
-
return { allowed: false, message: command.blockingRules.message }
|
|
514
|
-
}
|
|
515
|
-
if (commandName === 'done' && !hasContent) {
|
|
516
|
-
return { allowed: false, message: command.blockingRules.message }
|
|
517
|
-
}
|
|
518
|
-
if (commandName === 'next' && hasActiveTask) {
|
|
519
|
-
return {
|
|
520
|
-
allowed: true,
|
|
521
|
-
warning: 'You have an active task. Complete it with /p:done first.',
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
return { allowed: true }
|
|
526
|
-
},
|
|
527
|
-
|
|
528
572
|
/**
|
|
529
573
|
* Get statistics
|
|
530
574
|
*/
|
|
@@ -545,7 +589,7 @@ const registry = {
|
|
|
545
589
|
...acc,
|
|
546
590
|
[cat]: COMMANDS.filter((c) => c.category === cat).length,
|
|
547
591
|
}),
|
|
548
|
-
{}
|
|
592
|
+
{}
|
|
549
593
|
),
|
|
550
594
|
}),
|
|
551
595
|
}
|