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
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const { execSync } = require('child_process')
|
|
2
|
+
const installer = require('./command-installer')
|
|
3
|
+
const migrator = require('./migrator')
|
|
4
|
+
const legacyDetector = require('./legacy-installer-detector')
|
|
5
|
+
const editorsConfig = require('./editors-config')
|
|
6
|
+
const { VERSION } = require('../utils/version')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Setup Module - Core installation logic
|
|
10
|
+
*
|
|
11
|
+
* Executes ALL setup needed for prjct-cli:
|
|
12
|
+
* 1. Detect and clean legacy installation (curl-based)
|
|
13
|
+
* 2. Install Claude Code CLI if missing
|
|
14
|
+
* 3. Sync commands to ~/.claude/commands/p/
|
|
15
|
+
* 4. Install global config ~/.claude/CLAUDE.md
|
|
16
|
+
* 5. Migrate legacy projects automatically
|
|
17
|
+
* 6. Save version in editors-config
|
|
18
|
+
*
|
|
19
|
+
* This module is called from:
|
|
20
|
+
* - core/index.js (on first CLI use)
|
|
21
|
+
* - scripts/postinstall.js (if npm scripts are enabled)
|
|
22
|
+
*
|
|
23
|
+
* @version 0.8.8
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// Colors
|
|
27
|
+
const GREEN = '\x1b[32m'
|
|
28
|
+
const YELLOW = '\x1b[33m'
|
|
29
|
+
const MAGENTA = '\x1b[35m'
|
|
30
|
+
const BOLD = '\x1b[1m'
|
|
31
|
+
const DIM = '\x1b[2m'
|
|
32
|
+
const NC = '\x1b[0m'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if Claude Code CLI is installed
|
|
36
|
+
*/
|
|
37
|
+
async function hasClaudeCodeCLI() {
|
|
38
|
+
try {
|
|
39
|
+
execSync('which claude', { stdio: 'ignore' })
|
|
40
|
+
return true
|
|
41
|
+
} catch {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Install Claude Code CLI
|
|
48
|
+
*/
|
|
49
|
+
async function installClaudeCode() {
|
|
50
|
+
try {
|
|
51
|
+
console.log(`${YELLOW}π¦ Claude Code not found. Installing...${NC}`)
|
|
52
|
+
console.log('')
|
|
53
|
+
execSync('npm install -g @anthropic-ai/claude-code', { stdio: 'inherit' })
|
|
54
|
+
console.log('')
|
|
55
|
+
console.log(`${GREEN}β${NC} Claude Code installed successfully`)
|
|
56
|
+
console.log('')
|
|
57
|
+
return true
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.log(`${YELLOW}β οΈ Failed to install Claude Code: ${error.message}${NC}`)
|
|
60
|
+
console.log(`${DIM}Please install manually: npm install -g @anthropic-ai/claude-code${NC}`)
|
|
61
|
+
console.log('')
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Main setup function
|
|
68
|
+
*/
|
|
69
|
+
async function run() {
|
|
70
|
+
const results = {
|
|
71
|
+
legacyCleaned: false,
|
|
72
|
+
legacyProjectsMigrated: 0,
|
|
73
|
+
claudeInstalled: false,
|
|
74
|
+
commandsAdded: 0,
|
|
75
|
+
commandsUpdated: 0,
|
|
76
|
+
configAction: null,
|
|
77
|
+
projectsMigrated: 0
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Step 0: Detect and clean legacy curl installation
|
|
81
|
+
const needsLegacyCleanup = await legacyDetector.needsCleanup()
|
|
82
|
+
if (needsLegacyCleanup) {
|
|
83
|
+
const cleanupResult = await legacyDetector.performCleanup({ verbose: true })
|
|
84
|
+
results.legacyCleaned = cleanupResult.success
|
|
85
|
+
results.legacyProjectsMigrated = cleanupResult.steps.projectsMigrated
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Step 1: Ensure Claude Code CLI is installed
|
|
89
|
+
const hasClaude = await hasClaudeCodeCLI()
|
|
90
|
+
|
|
91
|
+
if (!hasClaude) {
|
|
92
|
+
const installed = await installClaudeCode()
|
|
93
|
+
if (installed) {
|
|
94
|
+
results.claudeInstalled = true
|
|
95
|
+
} else {
|
|
96
|
+
throw new Error('Claude Code installation failed')
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Step 2: Detect Claude directory (for commands)
|
|
101
|
+
const claudeDetected = await installer.detectClaude()
|
|
102
|
+
|
|
103
|
+
if (claudeDetected) {
|
|
104
|
+
// Step 3: Sync commands
|
|
105
|
+
const syncResult = await installer.syncCommands()
|
|
106
|
+
|
|
107
|
+
if (syncResult.success) {
|
|
108
|
+
results.commandsAdded = syncResult.added
|
|
109
|
+
results.commandsUpdated = syncResult.updated
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Step 4: Install global configuration
|
|
113
|
+
const configResult = await installer.installGlobalConfig()
|
|
114
|
+
|
|
115
|
+
if (configResult.success) {
|
|
116
|
+
results.configAction = configResult.action
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Step 5: Migrate legacy projects automatically
|
|
120
|
+
const migrationResult = await migrator.migrateAll({
|
|
121
|
+
deepScan: false,
|
|
122
|
+
cleanupLegacy: true,
|
|
123
|
+
dryRun: false
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
if (migrationResult.successfullyMigrated > 0) {
|
|
127
|
+
results.projectsMigrated = migrationResult.successfullyMigrated
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Step 6: Save version in editors-config
|
|
132
|
+
await editorsConfig.saveConfig(VERSION, installer.getInstallPath())
|
|
133
|
+
|
|
134
|
+
// Show results
|
|
135
|
+
showResults(results)
|
|
136
|
+
|
|
137
|
+
return results
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Show setup results
|
|
142
|
+
*/
|
|
143
|
+
function showResults(results) {
|
|
144
|
+
console.log('')
|
|
145
|
+
|
|
146
|
+
// Show what was done
|
|
147
|
+
if (results.legacyCleaned) {
|
|
148
|
+
console.log(` ${GREEN}β${NC} Legacy curl installation cleaned up`)
|
|
149
|
+
if (results.legacyProjectsMigrated > 0) {
|
|
150
|
+
console.log(` ${GREEN}β${NC} ${results.legacyProjectsMigrated} project(s) migrated from legacy`)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (results.claudeInstalled) {
|
|
155
|
+
console.log(` ${GREEN}β${NC} Claude Code CLI installed`)
|
|
156
|
+
} else {
|
|
157
|
+
console.log(` ${GREEN}β${NC} Claude Code CLI found`)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const totalCommands = results.commandsAdded + results.commandsUpdated
|
|
161
|
+
if (totalCommands > 0) {
|
|
162
|
+
const parts = []
|
|
163
|
+
if (results.commandsAdded > 0) parts.push(`${results.commandsAdded} new`)
|
|
164
|
+
if (results.commandsUpdated > 0) parts.push(`${results.commandsUpdated} updated`)
|
|
165
|
+
console.log(` ${GREEN}β${NC} Commands synced (${parts.join(', ')})`)
|
|
166
|
+
} else {
|
|
167
|
+
console.log(` ${GREEN}β${NC} Commands up to date`)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (results.configAction === 'created') {
|
|
171
|
+
console.log(` ${GREEN}β${NC} Global config created`)
|
|
172
|
+
} else if (results.configAction === 'updated') {
|
|
173
|
+
console.log(` ${GREEN}β${NC} Global config updated`)
|
|
174
|
+
} else if (results.configAction === 'appended') {
|
|
175
|
+
console.log(` ${GREEN}β${NC} Global config merged`)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (results.projectsMigrated > 0) {
|
|
179
|
+
console.log(` ${GREEN}β${NC} ${results.projectsMigrated} projects migrated to global storage`)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
console.log('')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = { run }
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
const fs = require('fs').promises
|
|
2
|
+
const fsSync = require('fs')
|
|
3
|
+
const readline = require('readline')
|
|
4
|
+
const path = require('path')
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* JSONL Helper - Centralized JSONL parsing and writing
|
|
@@ -190,6 +193,134 @@ async function isJsonLinesEmpty(filePath) {
|
|
|
190
193
|
return count === 0
|
|
191
194
|
}
|
|
192
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Read JSONL file with streaming (memory-efficient for large files)
|
|
198
|
+
* Only reads last N lines instead of loading entire file
|
|
199
|
+
*
|
|
200
|
+
* @param {string} filePath - Path to JSONL file
|
|
201
|
+
* @param {number} maxLines - Maximum lines to read (default: 1000)
|
|
202
|
+
* @returns {Promise<Array<Object>>} - Array of parsed objects (last N lines)
|
|
203
|
+
*/
|
|
204
|
+
async function readJsonLinesStreaming(filePath, maxLines = 1000) {
|
|
205
|
+
try {
|
|
206
|
+
const fileStream = fsSync.createReadStream(filePath)
|
|
207
|
+
const rl = readline.createInterface({
|
|
208
|
+
input: fileStream,
|
|
209
|
+
crlfDelay: Infinity,
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
const lines = []
|
|
213
|
+
|
|
214
|
+
for await (const line of rl) {
|
|
215
|
+
if (line.trim()) {
|
|
216
|
+
try {
|
|
217
|
+
lines.push(JSON.parse(line))
|
|
218
|
+
} catch {
|
|
219
|
+
// Skip malformed lines
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Keep only last maxLines
|
|
223
|
+
if (lines.length > maxLines) {
|
|
224
|
+
lines.shift()
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return lines
|
|
230
|
+
} catch (error) {
|
|
231
|
+
if (error.code === 'ENOENT') {
|
|
232
|
+
return []
|
|
233
|
+
}
|
|
234
|
+
throw error
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get file size in MB
|
|
240
|
+
*
|
|
241
|
+
* @param {string} filePath - Path to file
|
|
242
|
+
* @returns {Promise<number>} - File size in MB
|
|
243
|
+
*/
|
|
244
|
+
async function getFileSizeMB(filePath) {
|
|
245
|
+
try {
|
|
246
|
+
const stats = await fs.stat(filePath)
|
|
247
|
+
return stats.size / (1024 * 1024)
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (error.code === 'ENOENT') {
|
|
250
|
+
return 0
|
|
251
|
+
}
|
|
252
|
+
throw error
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Rotate JSONL file if it exceeds size limit
|
|
258
|
+
* Moves large file to archive with timestamp
|
|
259
|
+
*
|
|
260
|
+
* @param {string} filePath - Path to JSONL file
|
|
261
|
+
* @param {number} maxSizeMB - Maximum size in MB before rotation (default: 10)
|
|
262
|
+
* @returns {Promise<boolean>} - True if rotated, false if not needed
|
|
263
|
+
*/
|
|
264
|
+
async function rotateJsonLinesIfNeeded(filePath, maxSizeMB = 10) {
|
|
265
|
+
const sizeMB = await getFileSizeMB(filePath)
|
|
266
|
+
|
|
267
|
+
if (sizeMB < maxSizeMB) {
|
|
268
|
+
return false // No rotation needed
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Generate archive filename with timestamp
|
|
272
|
+
const timestamp = new Date().toISOString().split('T')[0] // YYYY-MM-DD
|
|
273
|
+
const dir = path.dirname(filePath)
|
|
274
|
+
const ext = path.extname(filePath)
|
|
275
|
+
const base = path.basename(filePath, ext)
|
|
276
|
+
const archivePath = path.join(dir, `${base}-${timestamp}${ext}`)
|
|
277
|
+
|
|
278
|
+
// Move file to archive
|
|
279
|
+
await fs.rename(filePath, archivePath)
|
|
280
|
+
|
|
281
|
+
console.log(`π¦ Rotated ${path.basename(filePath)} (${sizeMB.toFixed(1)}MB) β ${path.basename(archivePath)}`)
|
|
282
|
+
|
|
283
|
+
return true
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Append JSON line with automatic rotation
|
|
288
|
+
* Checks file size before append and rotates if needed
|
|
289
|
+
*
|
|
290
|
+
* @param {string} filePath - Path to JSONL file
|
|
291
|
+
* @param {Object} object - Object to append
|
|
292
|
+
* @param {number} maxSizeMB - Maximum size before rotation (default: 10)
|
|
293
|
+
* @returns {Promise<void>}
|
|
294
|
+
*/
|
|
295
|
+
async function appendJsonLineWithRotation(filePath, object, maxSizeMB = 10) {
|
|
296
|
+
// Rotate if needed (before appending)
|
|
297
|
+
await rotateJsonLinesIfNeeded(filePath, maxSizeMB)
|
|
298
|
+
|
|
299
|
+
// Append normally
|
|
300
|
+
await appendJsonLine(filePath, object)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Warn if file is large before reading
|
|
305
|
+
* Returns size and whether it's considered large
|
|
306
|
+
*
|
|
307
|
+
* @param {string} filePath - Path to file
|
|
308
|
+
* @param {number} warnThresholdMB - Threshold in MB to warn (default: 50)
|
|
309
|
+
* @returns {Promise<{sizeMB: number, isLarge: boolean}>}
|
|
310
|
+
*/
|
|
311
|
+
async function checkFileSizeWarning(filePath, warnThresholdMB = 50) {
|
|
312
|
+
const sizeMB = await getFileSizeMB(filePath)
|
|
313
|
+
const isLarge = sizeMB > warnThresholdMB
|
|
314
|
+
|
|
315
|
+
if (isLarge) {
|
|
316
|
+
console.warn(
|
|
317
|
+
`β οΈ Large file detected: ${path.basename(filePath)} (${sizeMB.toFixed(1)}MB). Reading may use significant memory.`
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return { sizeMB, isLarge }
|
|
322
|
+
}
|
|
323
|
+
|
|
193
324
|
module.exports = {
|
|
194
325
|
parseJsonLines,
|
|
195
326
|
stringifyJsonLines,
|
|
@@ -203,4 +334,10 @@ module.exports = {
|
|
|
203
334
|
getFirstJsonLines,
|
|
204
335
|
mergeJsonLines,
|
|
205
336
|
isJsonLinesEmpty,
|
|
337
|
+
// NEW: Memory-efficient functions
|
|
338
|
+
readJsonLinesStreaming,
|
|
339
|
+
getFileSizeMB,
|
|
340
|
+
rotateJsonLinesIfNeeded,
|
|
341
|
+
appendJsonLineWithRotation,
|
|
342
|
+
checkFileSizeWarning,
|
|
206
343
|
}
|
package/package.json
CHANGED
package/scripts/install.sh
CHANGED
|
@@ -9,22 +9,59 @@
|
|
|
9
9
|
YELLOW='\033[1;33m'
|
|
10
10
|
CYAN='\033[0;36m'
|
|
11
11
|
GREEN='\033[0;32m'
|
|
12
|
+
RED='\033[0;31m'
|
|
13
|
+
BOLD='\033[1m'
|
|
14
|
+
DIM='\033[2m'
|
|
12
15
|
NC='\033[0m'
|
|
13
16
|
|
|
17
|
+
# Check if legacy installation exists
|
|
18
|
+
LEGACY_DIR="$HOME/.prjct-cli"
|
|
19
|
+
HAS_LEGACY=false
|
|
20
|
+
LEGACY_VERSION="unknown"
|
|
21
|
+
|
|
22
|
+
if [ -d "$LEGACY_DIR" ]; then
|
|
23
|
+
# Check if it's a git clone (legacy curl install)
|
|
24
|
+
if [ -d "$LEGACY_DIR/.git" ]; then
|
|
25
|
+
HAS_LEGACY=true
|
|
26
|
+
if [ -f "$LEGACY_DIR/package.json" ]; then
|
|
27
|
+
LEGACY_VERSION=$(grep -o '"version":[[:space:]]*"[^"]*"' "$LEGACY_DIR/package.json" | head -1 | cut -d'"' -f4)
|
|
28
|
+
fi
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
14
32
|
echo ""
|
|
15
33
|
echo -e "${YELLOW}ββββββββββββββββββββββββββββββββββββββββ${NC}"
|
|
16
34
|
echo -e "${YELLOW}β οΈ This installation method is DEPRECATED${NC}"
|
|
17
35
|
echo -e "${YELLOW}ββββββββββββββββββββββββββββββββββββββββ${NC}"
|
|
18
36
|
echo ""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
echo -e "
|
|
22
|
-
echo ""
|
|
23
|
-
echo -e "
|
|
24
|
-
echo -e "
|
|
25
|
-
echo
|
|
26
|
-
echo -e "
|
|
37
|
+
|
|
38
|
+
if [ "$HAS_LEGACY" = true ]; then
|
|
39
|
+
echo -e "${RED}β οΈ Legacy curl installation detected!${NC}"
|
|
40
|
+
echo ""
|
|
41
|
+
echo -e " ${DIM}Version: ${LEGACY_VERSION}${NC}"
|
|
42
|
+
echo -e " ${DIM}Location: ~/.prjct-cli/${NC}"
|
|
43
|
+
echo ""
|
|
44
|
+
echo -e "${CYAN}Migration Required:${NC}"
|
|
45
|
+
echo ""
|
|
46
|
+
echo -e " 1. ${BOLD}Install via npm:${NC}"
|
|
47
|
+
echo -e " ${GREEN}npm install -g prjct-cli${NC}"
|
|
48
|
+
echo ""
|
|
49
|
+
echo -e " 2. ${BOLD}Automatic cleanup:${NC}"
|
|
50
|
+
echo -e " ${DIM}Legacy installation will be cleaned automatically${NC}"
|
|
51
|
+
echo -e " ${DIM}Your project data will be preserved${NC}"
|
|
52
|
+
echo ""
|
|
53
|
+
else
|
|
54
|
+
echo -e "${CYAN}Please install using npm:${NC}"
|
|
55
|
+
echo ""
|
|
56
|
+
echo -e " ${GREEN}npm install -g prjct-cli${NC}"
|
|
57
|
+
echo ""
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo -e "${BOLD}Benefits of npm installation:${NC}"
|
|
61
|
+
echo -e " β’ ${CYAN}Automatic cleanup${NC} - Removes old curl installations"
|
|
62
|
+
echo -e " β’ ${CYAN}Data preservation${NC} - Your projects are migrated safely"
|
|
27
63
|
echo -e " β’ ${CYAN}Easy updates${NC} - Just npm update -g prjct-cli"
|
|
64
|
+
echo -e " β’ ${CYAN}Proper versioning${NC} - npm handles everything"
|
|
28
65
|
echo ""
|
|
29
66
|
echo -e "${YELLOW}ββββββββββββββββββββββββββββββββββββββββ${NC}"
|
|
30
67
|
echo ""
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,114 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Post-install hook for prjct-cli
|
|
4
|
+
* Post-install hook for prjct-cli (OPTIONAL)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Attempts to run setup if npm scripts are enabled.
|
|
7
|
+
* If it fails or doesn't run, no problem - setup will run
|
|
8
|
+
* automatically on first CLI use (like Astro, Vite, etc.)
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
* 2. Installs Claude Code CLI if not found (automatic)
|
|
10
|
-
* 3. Installs/syncs commands to ~/.claude/commands/p/
|
|
11
|
-
* 4. Installs/updates global config to ~/.claude/CLAUDE.md
|
|
12
|
-
* 5. Migrates all legacy projects automatically
|
|
13
|
-
* 6. Shows success message with results
|
|
10
|
+
* This hook is an optimization but NOT critical.
|
|
14
11
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @version 0.8.4
|
|
12
|
+
* @version 0.8.8
|
|
18
13
|
*/
|
|
19
14
|
|
|
20
15
|
const path = require('path')
|
|
21
|
-
const
|
|
22
|
-
const installer = require('../core/infrastructure/command-installer')
|
|
23
|
-
const migrator = require('../core/infrastructure/migrator')
|
|
24
|
-
const { VERSION } = require('../core/utils/version')
|
|
25
|
-
|
|
26
|
-
// Colors for terminal output
|
|
27
|
-
const CYAN = '\x1b[36m'
|
|
28
|
-
const GREEN = '\x1b[32m'
|
|
29
|
-
const YELLOW = '\x1b[33m'
|
|
30
|
-
const MAGENTA = '\x1b[35m'
|
|
31
|
-
const WHITE = '\x1b[37m'
|
|
32
|
-
const BOLD = '\x1b[1m'
|
|
33
|
-
const DIM = '\x1b[2m'
|
|
34
|
-
const NC = '\x1b[0m' // No Color
|
|
16
|
+
const setup = require('../core/infrastructure/setup')
|
|
35
17
|
|
|
36
18
|
async function main() {
|
|
37
19
|
try {
|
|
38
20
|
// Detect if this is a global install
|
|
39
|
-
const isGlobal =
|
|
21
|
+
const isGlobal = detectGlobalInstall()
|
|
40
22
|
|
|
41
23
|
if (!isGlobal) {
|
|
42
24
|
// Skip postinstall for local development installs
|
|
43
|
-
console.log(`${DIM}Skipping post-install (local development)${NC}`)
|
|
44
25
|
return
|
|
45
26
|
}
|
|
46
27
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
console.log(`${BOLD}${CYAN}π Setting up prjct-cli v${VERSION}${NC}`)
|
|
50
|
-
console.log(`${CYAN}ββββββββββββββββββββββββββββββββββββββββ${NC}`)
|
|
51
|
-
console.log('')
|
|
52
|
-
|
|
53
|
-
const results = {
|
|
54
|
-
claudeInstalled: false,
|
|
55
|
-
commandsAdded: 0,
|
|
56
|
-
commandsUpdated: 0,
|
|
57
|
-
configAction: null,
|
|
58
|
-
projectsMigrated: 0
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Step 1: Ensure Claude Code CLI is installed
|
|
62
|
-
const hasClaude = await hasClaudeCodeCLI()
|
|
63
|
-
|
|
64
|
-
if (!hasClaude) {
|
|
65
|
-
const installed = await installClaudeCode()
|
|
66
|
-
if (installed) {
|
|
67
|
-
results.claudeInstalled = true
|
|
68
|
-
} else {
|
|
69
|
-
// Cannot continue without Claude Code
|
|
70
|
-
showFailureMessage()
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Step 2: Detect Claude directory (for commands)
|
|
76
|
-
const claudeDetected = await installer.detectClaude()
|
|
77
|
-
|
|
78
|
-
if (claudeDetected) {
|
|
79
|
-
// Step 3: Sync commands
|
|
80
|
-
const syncResult = await installer.syncCommands()
|
|
81
|
-
|
|
82
|
-
if (syncResult.success) {
|
|
83
|
-
results.commandsAdded = syncResult.added
|
|
84
|
-
results.commandsUpdated = syncResult.updated
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Step 4: Install global configuration
|
|
88
|
-
const configResult = await installer.installGlobalConfig()
|
|
89
|
-
|
|
90
|
-
if (configResult.success) {
|
|
91
|
-
results.configAction = configResult.action
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Step 5: Migrate legacy projects automatically
|
|
95
|
-
const migrationResult = await migrator.migrateAll({
|
|
96
|
-
deepScan: false,
|
|
97
|
-
cleanupLegacy: true,
|
|
98
|
-
dryRun: false
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
if (migrationResult.successfullyMigrated > 0) {
|
|
102
|
-
results.projectsMigrated = migrationResult.successfullyMigrated
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Show final success message
|
|
107
|
-
showSuccessMessage(results)
|
|
28
|
+
// Run setup (all logic is in core/infrastructure/setup.js)
|
|
29
|
+
await setup.run()
|
|
108
30
|
|
|
109
31
|
} catch (error) {
|
|
110
|
-
|
|
111
|
-
console.error(`${DIM}You can run 'prjct setup' manually later${NC}`)
|
|
32
|
+
// Silent failure - setup will run on first use anyway
|
|
112
33
|
// Don't fail the install if post-install has issues
|
|
113
34
|
process.exit(0)
|
|
114
35
|
}
|
|
@@ -117,7 +38,7 @@ async function main() {
|
|
|
117
38
|
/**
|
|
118
39
|
* Detect if this is a global npm install
|
|
119
40
|
*/
|
|
120
|
-
|
|
41
|
+
function detectGlobalInstall() {
|
|
121
42
|
// Check if we're being installed globally
|
|
122
43
|
const npmConfig = process.env.npm_config_global
|
|
123
44
|
if (npmConfig === 'true') {
|
|
@@ -137,118 +58,6 @@ async function detectGlobalInstall() {
|
|
|
137
58
|
return globalPaths.some(globalPath => installPath.includes(globalPath))
|
|
138
59
|
}
|
|
139
60
|
|
|
140
|
-
/**
|
|
141
|
-
* Check if Claude Code CLI is installed
|
|
142
|
-
*/
|
|
143
|
-
async function hasClaudeCodeCLI() {
|
|
144
|
-
try {
|
|
145
|
-
execSync('which claude', { stdio: 'ignore' })
|
|
146
|
-
return true
|
|
147
|
-
} catch {
|
|
148
|
-
return false
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Install Claude Code CLI
|
|
154
|
-
*/
|
|
155
|
-
async function installClaudeCode() {
|
|
156
|
-
try {
|
|
157
|
-
console.log(`${YELLOW}π¦ Claude Code not found. Installing...${NC}`)
|
|
158
|
-
console.log('')
|
|
159
|
-
execSync('npm install -g @anthropic-ai/claude-code', { stdio: 'inherit' })
|
|
160
|
-
console.log('')
|
|
161
|
-
console.log(`${GREEN}β${NC} Claude Code installed successfully`)
|
|
162
|
-
console.log('')
|
|
163
|
-
return true
|
|
164
|
-
} catch (error) {
|
|
165
|
-
console.log(`${YELLOW}β οΈ Failed to install Claude Code: ${error.message}${NC}`)
|
|
166
|
-
console.log(`${DIM}Please install manually: npm install -g @anthropic-ai/claude-code${NC}`)
|
|
167
|
-
console.log('')
|
|
168
|
-
return false
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Show success message with results
|
|
174
|
-
*/
|
|
175
|
-
function showSuccessMessage(results) {
|
|
176
|
-
console.log('')
|
|
177
|
-
console.log(`${CYAN}ββββββββββββββββββββββββββββββββββββββββ${NC}`)
|
|
178
|
-
console.log('')
|
|
179
|
-
console.log(` ${BOLD}${CYAN}βββββββ βββββββ βββ ββββββββββββββββ${NC}`)
|
|
180
|
-
console.log(` ${BOLD}${CYAN}ββββββββββββββββ ββββββββββββββββββββ${NC}`)
|
|
181
|
-
console.log(` ${BOLD}${CYAN}ββββββββββββββββ ββββββ βββ${NC}`)
|
|
182
|
-
console.log(` ${BOLD}${CYAN}βββββββ ββββββββββ ββββββ βββ${NC}`)
|
|
183
|
-
console.log(` ${BOLD}${CYAN}βββ βββ βββββββββββββββββββ βββ${NC}`)
|
|
184
|
-
console.log(` ${BOLD}${CYAN}βββ βββ βββ ββββββ βββββββ βββ${NC}`)
|
|
185
|
-
console.log('')
|
|
186
|
-
console.log(` ${BOLD}${GREEN}v${VERSION} READY!${NC}`)
|
|
187
|
-
console.log('')
|
|
188
|
-
console.log(`${CYAN}ββββββββββββββββββββββββββββββββββββββββ${NC}`)
|
|
189
|
-
console.log('')
|
|
190
|
-
|
|
191
|
-
// Show what was done
|
|
192
|
-
if (results.claudeInstalled) {
|
|
193
|
-
console.log(` ${GREEN}β${NC} Claude Code CLI installed`)
|
|
194
|
-
} else {
|
|
195
|
-
console.log(` ${GREEN}β${NC} Claude Code CLI found`)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const totalCommands = results.commandsAdded + results.commandsUpdated
|
|
199
|
-
if (totalCommands > 0) {
|
|
200
|
-
const parts = []
|
|
201
|
-
if (results.commandsAdded > 0) parts.push(`${results.commandsAdded} new`)
|
|
202
|
-
if (results.commandsUpdated > 0) parts.push(`${results.commandsUpdated} updated`)
|
|
203
|
-
console.log(` ${GREEN}β${NC} Commands synced (${parts.join(', ')})`)
|
|
204
|
-
} else {
|
|
205
|
-
console.log(` ${GREEN}β${NC} Commands up to date`)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (results.configAction === 'created') {
|
|
209
|
-
console.log(` ${GREEN}β${NC} Global config created`)
|
|
210
|
-
} else if (results.configAction === 'updated') {
|
|
211
|
-
console.log(` ${GREEN}β${NC} Global config updated`)
|
|
212
|
-
} else if (results.configAction === 'appended') {
|
|
213
|
-
console.log(` ${GREEN}β${NC} Global config merged`)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (results.projectsMigrated > 0) {
|
|
217
|
-
console.log(` ${GREEN}β${NC} ${results.projectsMigrated} projects migrated to global storage`)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
console.log('')
|
|
221
|
-
console.log(`${CYAN}ββββββββββββββββββββββββββββββββββββββββ${NC}`)
|
|
222
|
-
console.log('')
|
|
223
|
-
console.log(`${BOLD}Next steps:${NC}`)
|
|
224
|
-
console.log(` ${DIM}cd your-project${NC}`)
|
|
225
|
-
console.log(` ${GREEN}/p:init${NC}`)
|
|
226
|
-
console.log('')
|
|
227
|
-
console.log(`${BOLD}${MAGENTA}Happy shipping! π${NC}`)
|
|
228
|
-
console.log('')
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Show failure message
|
|
233
|
-
*/
|
|
234
|
-
function showFailureMessage() {
|
|
235
|
-
console.log('')
|
|
236
|
-
console.log(`${CYAN}ββββββββββββββββββββββββββββββββββββββββ${NC}`)
|
|
237
|
-
console.log('')
|
|
238
|
-
console.log(`${YELLOW}β οΈ Setup incomplete${NC}`)
|
|
239
|
-
console.log('')
|
|
240
|
-
console.log(`Claude Code is required for prjct-cli.`)
|
|
241
|
-
console.log('')
|
|
242
|
-
console.log(`Please install manually:`)
|
|
243
|
-
console.log(` ${GREEN}npm install -g @anthropic-ai/claude-code${NC}`)
|
|
244
|
-
console.log('')
|
|
245
|
-
console.log(`Then run:`)
|
|
246
|
-
console.log(` ${GREEN}prjct setup${NC}`)
|
|
247
|
-
console.log('')
|
|
248
|
-
console.log(`${CYAN}ββββββββββββββββββββββββββββββββββββββββ${NC}`)
|
|
249
|
-
console.log('')
|
|
250
|
-
}
|
|
251
|
-
|
|
252
61
|
// Run if executed directly
|
|
253
62
|
if (require.main === module) {
|
|
254
63
|
main().catch(error => {
|
|
@@ -167,13 +167,13 @@ Semantic understanding, not pattern matching.
|
|
|
167
167
|
|
|
168
168
|
| Intent | Command | Examples |
|
|
169
169
|
| ---------- | ---------- | -------------------------------------------- |
|
|
170
|
-
| Start task | `/p:now` | "work on X", "starting API", "
|
|
171
|
-
| Finish | `/p:done` | "done", "finished", "
|
|
170
|
+
| Start task | `/p:now` | "work on X", "starting API", "begin auth" |
|
|
171
|
+
| Finish | `/p:done` | "done", "finished", "completed", "all set" |
|
|
172
172
|
| Ship | `/p:ship` | "ship this", "deploy X", "it's ready" |
|
|
173
173
|
| Idea | `/p:idea` | "I have an idea", "what if we..." |
|
|
174
174
|
| Progress | `/p:recap` | "show progress", "how am I doing" |
|
|
175
175
|
| Stuck | `/p:stuck` | "I'm stuck", "help with X" |
|
|
176
|
-
| Next | `/p:next` | "what's next", "
|
|
176
|
+
| Next | `/p:next` | "what's next", "show queue", "priority list" |
|
|
177
177
|
|
|
178
178
|
**Any language works** - if you understand intent, execute the command.
|
|
179
179
|
|