prjct-cli 0.8.4 → 0.8.8
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 +115 -0
- package/CLAUDE.md +34 -0
- package/bin/prjct +19 -166
- package/core/agentic/context-builder.js +4 -3
- package/core/agentic/tool-registry.js +35 -0
- package/core/commands.js +84 -0
- package/core/index.js +178 -0
- package/core/infrastructure/command-installer.js +9 -26
- package/core/infrastructure/legacy-installer-detector.js +546 -0
- package/core/infrastructure/session-manager.js +14 -2
- package/core/infrastructure/setup.js +185 -0
- package/core/utils/jsonl-helper.js +137 -0
- package/package.json +1 -1
- package/scripts/install.sh +45 -8
- package/scripts/postinstall.js +12 -203
- package/templates/agents/AGENTS.md +3 -3
- package/templates/commands/ask.md +25 -338
- package/templates/commands/build.md +7 -4
- package/templates/commands/feature.md +19 -160
- package/templates/commands/help.md +41 -299
- package/templates/commands/idea.md +7 -4
- package/templates/commands/init.md +15 -112
- package/templates/commands/migrate-all.md +25 -84
- package/templates/commands/now.md +4 -3
- package/templates/commands/ship.md +20 -86
- package/templates/commands/suggest.md +36 -495
package/core/index.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prjct CLI - Main Entry Point
|
|
3
|
+
*
|
|
4
|
+
* This file is required by bin/prjct after setup verification
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const PrjctCommands = require('./commands')
|
|
8
|
+
const registry = require('./command-registry')
|
|
9
|
+
|
|
10
|
+
async function main() {
|
|
11
|
+
const [commandName, ...rawArgs] = process.argv.slice(2)
|
|
12
|
+
|
|
13
|
+
// === SPECIAL COMMANDS (version, help) ===
|
|
14
|
+
|
|
15
|
+
if (['-v', '--version', 'version'].includes(commandName)) {
|
|
16
|
+
const packageJson = require('../package.json')
|
|
17
|
+
console.log(`prjct-cli v${packageJson.version}`)
|
|
18
|
+
process.exit(0)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (['-h', '--help', 'help', undefined].includes(commandName)) {
|
|
22
|
+
displayHelp()
|
|
23
|
+
process.exit(0)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// === DYNAMIC COMMAND EXECUTION ===
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// 1. Find command in registry
|
|
30
|
+
const cmd = registry.getByName(commandName)
|
|
31
|
+
|
|
32
|
+
if (!cmd) {
|
|
33
|
+
console.error(`Unknown command: ${commandName}`)
|
|
34
|
+
console.error(`\nUse 'prjct --help' to see available commands.`)
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. Check if deprecated
|
|
39
|
+
if (cmd.deprecated) {
|
|
40
|
+
console.error(`Command '${commandName}' is deprecated.`)
|
|
41
|
+
if (cmd.replacedBy) {
|
|
42
|
+
console.error(`Use 'prjct ${cmd.replacedBy}' instead.`)
|
|
43
|
+
}
|
|
44
|
+
process.exit(1)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 3. Check if implemented
|
|
48
|
+
if (!cmd.implemented) {
|
|
49
|
+
console.error(`Command '${commandName}' exists but is not yet implemented.`)
|
|
50
|
+
console.error(`Check the roadmap or contribute: https://github.com/jlopezlira/prjct-cli`)
|
|
51
|
+
console.error(`\nUse 'prjct --help' to see available commands.`)
|
|
52
|
+
process.exit(1)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 4. Parse arguments
|
|
56
|
+
const { parsedArgs, options } = parseCommandArgs(cmd, rawArgs)
|
|
57
|
+
|
|
58
|
+
// 5. Instantiate commands handler
|
|
59
|
+
const commands = new PrjctCommands()
|
|
60
|
+
|
|
61
|
+
// 6. Execute command
|
|
62
|
+
let result
|
|
63
|
+
|
|
64
|
+
// Commands with special option handling
|
|
65
|
+
if (commandName === 'design') {
|
|
66
|
+
const target = parsedArgs.join(' ')
|
|
67
|
+
result = await commands.design(target, options)
|
|
68
|
+
} else if (commandName === 'analyze') {
|
|
69
|
+
result = await commands.analyze(options)
|
|
70
|
+
} else if (commandName === 'cleanup') {
|
|
71
|
+
result = await commands.cleanup(options)
|
|
72
|
+
} else if (commandName === 'setup') {
|
|
73
|
+
result = await commands.setup(options)
|
|
74
|
+
} else if (commandName === 'migrate-all') {
|
|
75
|
+
result = await commands.migrateAll(options)
|
|
76
|
+
} else if (commandName === 'progress') {
|
|
77
|
+
const period = parsedArgs[0] || 'week'
|
|
78
|
+
result = await commands.progress(period)
|
|
79
|
+
} else if (commandName === 'build') {
|
|
80
|
+
const taskOrNumber = parsedArgs.join(' ')
|
|
81
|
+
result = await commands.build(taskOrNumber)
|
|
82
|
+
} else {
|
|
83
|
+
// Standard commands
|
|
84
|
+
const param = parsedArgs.join(' ') || null
|
|
85
|
+
result = await commands[commandName](param)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 7. Display result
|
|
89
|
+
if (result && result.message) {
|
|
90
|
+
console.log(result.message)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
process.exit(result && result.success ? 0 : 1)
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error('Error:', error.message)
|
|
96
|
+
if (process.env.DEBUG) {
|
|
97
|
+
console.error(error.stack)
|
|
98
|
+
}
|
|
99
|
+
process.exit(1)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Parse command arguments dynamically
|
|
105
|
+
*/
|
|
106
|
+
function parseCommandArgs(cmd, rawArgs) {
|
|
107
|
+
const parsedArgs = []
|
|
108
|
+
const options = {}
|
|
109
|
+
|
|
110
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
111
|
+
const arg = rawArgs[i]
|
|
112
|
+
|
|
113
|
+
if (arg.startsWith('--')) {
|
|
114
|
+
// Handle flags
|
|
115
|
+
const flagName = arg.slice(2)
|
|
116
|
+
|
|
117
|
+
// Check if next arg is a value
|
|
118
|
+
if (i + 1 < rawArgs.length && !rawArgs[i + 1].startsWith('--')) {
|
|
119
|
+
options[flagName] = rawArgs[++i]
|
|
120
|
+
} else {
|
|
121
|
+
options[flagName] = true
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
parsedArgs.push(arg)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { parsedArgs, options }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Display help using registry
|
|
133
|
+
*/
|
|
134
|
+
function displayHelp() {
|
|
135
|
+
const categories = registry.getCategories()
|
|
136
|
+
const categorizedCommands = {}
|
|
137
|
+
|
|
138
|
+
// Group commands by category (exclude deprecated)
|
|
139
|
+
registry.getTerminalCommands().forEach((cmd) => {
|
|
140
|
+
if (cmd.deprecated) return
|
|
141
|
+
|
|
142
|
+
if (!categorizedCommands[cmd.category]) {
|
|
143
|
+
categorizedCommands[cmd.category] = []
|
|
144
|
+
}
|
|
145
|
+
categorizedCommands[cmd.category].push(cmd)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
console.log('prjct - Developer momentum tool for solo builders')
|
|
149
|
+
console.log('\nAvailable commands:\n')
|
|
150
|
+
|
|
151
|
+
// Display commands by category
|
|
152
|
+
Object.entries(categorizedCommands).forEach(([categoryKey, cmds]) => {
|
|
153
|
+
const categoryInfo = categories[categoryKey]
|
|
154
|
+
console.log(` ${categoryInfo.title}:`)
|
|
155
|
+
|
|
156
|
+
cmds.forEach((cmd) => {
|
|
157
|
+
const params = cmd.params ? ` ${cmd.params}` : ''
|
|
158
|
+
const spacing = ' '.repeat(Math.max(20 - cmd.name.length - params.length, 1))
|
|
159
|
+
const impl = cmd.implemented ? '' : ' (not implemented)'
|
|
160
|
+
console.log(` ${cmd.name}${params}${spacing}${cmd.description}${impl}`)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
console.log('')
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
const stats = registry.getStats()
|
|
167
|
+
console.log(`Total: ${stats.implemented} implemented / ${stats.total} commands`)
|
|
168
|
+
console.log('\nFor more info: https://prjct.app')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Run CLI
|
|
172
|
+
main().catch((error) => {
|
|
173
|
+
console.error('Fatal error:', error.message)
|
|
174
|
+
if (process.env.DEBUG) {
|
|
175
|
+
console.error(error.stack)
|
|
176
|
+
}
|
|
177
|
+
process.exit(1)
|
|
178
|
+
})
|
|
@@ -280,7 +280,7 @@ class CommandInstaller {
|
|
|
280
280
|
errors: [],
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
//
|
|
283
|
+
// Install/update all template files (always overwrite)
|
|
284
284
|
for (const file of templateFiles) {
|
|
285
285
|
try {
|
|
286
286
|
const sourcePath = path.join(this.templatesDir, file)
|
|
@@ -289,40 +289,23 @@ class CommandInstaller {
|
|
|
289
289
|
// Check if file exists in installed location
|
|
290
290
|
const exists = installedFiles.includes(file)
|
|
291
291
|
|
|
292
|
+
// Read and write (always overwrite to ensure latest version)
|
|
293
|
+
const content = await fs.readFile(sourcePath, 'utf-8')
|
|
294
|
+
await fs.writeFile(destPath, content, 'utf-8')
|
|
295
|
+
|
|
292
296
|
if (!exists) {
|
|
293
|
-
// New file
|
|
294
|
-
const content = await fs.readFile(sourcePath, 'utf-8')
|
|
295
|
-
await fs.writeFile(destPath, content, 'utf-8')
|
|
296
297
|
results.added++
|
|
297
298
|
} else {
|
|
298
|
-
|
|
299
|
-
const sourceStats = await fs.stat(sourcePath)
|
|
300
|
-
const destStats = await fs.stat(destPath)
|
|
301
|
-
|
|
302
|
-
if (sourceStats.mtime > destStats.mtime) {
|
|
303
|
-
// Updated file
|
|
304
|
-
const content = await fs.readFile(sourcePath, 'utf-8')
|
|
305
|
-
await fs.writeFile(destPath, content, 'utf-8')
|
|
306
|
-
results.updated++
|
|
307
|
-
}
|
|
299
|
+
results.updated++
|
|
308
300
|
}
|
|
309
301
|
} catch (error) {
|
|
310
302
|
results.errors.push({ file, error: error.message })
|
|
311
303
|
}
|
|
312
304
|
}
|
|
313
305
|
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
for (const orphan of orphans) {
|
|
318
|
-
try {
|
|
319
|
-
const orphanPath = path.join(this.claudeCommandsPath, orphan)
|
|
320
|
-
await fs.unlink(orphanPath)
|
|
321
|
-
results.removed++
|
|
322
|
-
} catch (error) {
|
|
323
|
-
results.errors.push({ file: orphan, error: error.message })
|
|
324
|
-
}
|
|
325
|
-
}
|
|
306
|
+
// Note: We do NOT remove orphaned files
|
|
307
|
+
// Legacy commands from older versions are preserved
|
|
308
|
+
// to avoid breaking existing workflows
|
|
326
309
|
|
|
327
310
|
return results
|
|
328
311
|
} catch (error) {
|