prjct-cli 0.8.0 → 0.8.2
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 +97 -0
- package/README.md +15 -11
- package/core/commands.js +64 -1
- package/core/infrastructure/command-installer.js +209 -0
- package/package.json +4 -1
- package/scripts/install.sh +46 -10
- package/scripts/postinstall.js +205 -0
- package/templates/global/CLAUDE.md +214 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,103 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.2] - 2025-10-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **BREAKING: npm-only installation** - Simplified installation to npm-only
|
|
15
|
+
- ✅ Single command: `npm install -g prjct-cli`
|
|
16
|
+
- ✅ Automatic setup via postinstall hook
|
|
17
|
+
- ✅ Auto-migration of legacy projects
|
|
18
|
+
- ✅ Beautiful ASCII art on installation
|
|
19
|
+
- ⚠️ `curl -fsSL https://prjct.app/install.sh` now deprecated (shows migration message)
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Automatic Post-Install Setup** (`scripts/postinstall.js`)
|
|
24
|
+
- Runs automatically after `npm install -g prjct-cli`
|
|
25
|
+
- Detects global vs local installation
|
|
26
|
+
- Installs/syncs commands to `~/.claude/commands/p/`
|
|
27
|
+
- Migrates legacy projects automatically
|
|
28
|
+
- Shows beautiful ASCII art with quick start guide
|
|
29
|
+
|
|
30
|
+
- **Intelligent Command Sync** (`syncCommands()` in `command-installer.js`)
|
|
31
|
+
- Detects new commands and installs them
|
|
32
|
+
- Detects updated commands and refreshes them
|
|
33
|
+
- **Detects orphaned commands and removes them** (e.g., context.md, stuck.md)
|
|
34
|
+
- Reports: "✓ 2 nuevos, 5 actualizados, 2 eliminados"
|
|
35
|
+
|
|
36
|
+
- **Beautiful ASCII Art** (`showAsciiArt()` in `commands.js`)
|
|
37
|
+
- Displays after `prjct setup` completion
|
|
38
|
+
- Shows prjct logo with colors
|
|
39
|
+
- Includes quick start guide
|
|
40
|
+
- Links to documentation
|
|
41
|
+
|
|
42
|
+
- **Global Configuration** (`~/.claude/CLAUDE.md`)
|
|
43
|
+
- Automatically installs/updates global configuration for Claude Code
|
|
44
|
+
- Provides context for ALL `/p:*` commands across any prjct project
|
|
45
|
+
- Intelligent merge: preserves user content, updates only prjct section
|
|
46
|
+
- Includes path resolution rules, file structure, commit format, validation patterns
|
|
47
|
+
- Installed during `npm install -g prjct-cli` and `prjct setup`
|
|
48
|
+
- Single source of truth - no need to repeat in 25 command templates
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **Orphaned Commands Cleanup** - Removed deprecated commands
|
|
53
|
+
- Deleted `context.md` (replaced by context tracking in core)
|
|
54
|
+
- Deleted `stuck.md` (functionality merged into /p:ask)
|
|
55
|
+
- Total commands: 27 → 25 (cleaned up)
|
|
56
|
+
|
|
57
|
+
- **Context Preservation** - All projects now use global storage
|
|
58
|
+
- Legacy projects in `.prjct/` automatically migrated to `~/.prjct-cli/projects/{id}/`
|
|
59
|
+
- Only `prjct.config.json` (2KB) remains in project directory
|
|
60
|
+
- Prevents context loss on updates
|
|
61
|
+
|
|
62
|
+
### Documentation
|
|
63
|
+
|
|
64
|
+
- Updated README.md with new installation flow
|
|
65
|
+
- Added "Auto-Setup (NEW in v0.8.2)" section
|
|
66
|
+
- Simplified installation instructions
|
|
67
|
+
- Deprecated manual installation methods
|
|
68
|
+
|
|
69
|
+
## [0.8.1] - 2025-10-05
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- **Critical Installation Bug** - Fixed incorrect path in `install.sh` line 315
|
|
74
|
+
- Changed `./core/command-installer` → `./core/infrastructure/command-installer`
|
|
75
|
+
- Resolves "Cannot find module" error during installation
|
|
76
|
+
|
|
77
|
+
- **Missing Method Error** - Added `installToAll()` method to command-installer
|
|
78
|
+
- Implements method called by install.sh line 316
|
|
79
|
+
- Acts as alias for `installCommands()` for backward compatibility
|
|
80
|
+
|
|
81
|
+
- **Commands Not Auto-Updating** - Implemented automatic command synchronization
|
|
82
|
+
- After `git pull`, commands in `~/.claude/commands/p/` now update automatically
|
|
83
|
+
- Added visual confirmation: "Commands synchronized ✓"
|
|
84
|
+
|
|
85
|
+
- **Missing Visual Confirmation** - Added ASCII confirmation in setup.sh
|
|
86
|
+
- Displays "✨ Setup Complete! ✨" after successful npm install
|
|
87
|
+
- Clear feedback that installation succeeded
|
|
88
|
+
|
|
89
|
+
### Added
|
|
90
|
+
|
|
91
|
+
- **Update Script** - New `scripts/update.sh` for easy updates
|
|
92
|
+
- Single command to update prjct-cli: `npm run update`
|
|
93
|
+
- Handles: git pull → npm install → command updates
|
|
94
|
+
- Visual progress indicators and confirmation
|
|
95
|
+
|
|
96
|
+
- **Enhanced Logging** - Improved updateCommands() with visual feedback
|
|
97
|
+
- Shows "🔄 Updating commands with latest templates..."
|
|
98
|
+
- Displays "✅ Updated X commands" on success
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
|
|
102
|
+
- **Installation Flow** - Simplified and more reliable
|
|
103
|
+
- Auto-updates commands after git pull (no manual reinstall needed)
|
|
104
|
+
- Single npm install (eliminated duplication)
|
|
105
|
+
- Clear visual feedback at each step
|
|
106
|
+
|
|
10
107
|
## [0.8.0] - 2025-10-05
|
|
11
108
|
|
|
12
109
|
### Added
|
package/README.md
CHANGED
|
@@ -73,23 +73,27 @@ For easier installation from GitHub Packages, see [GitHub Packages Setup](docs/G
|
|
|
73
73
|
|
|
74
74
|
> **Note**: The CLI automatically detects updates and notifies you when a new version is available. Simply run `npm update -g prjct-cli` to upgrade.
|
|
75
75
|
|
|
76
|
-
###
|
|
76
|
+
### Auto-Setup (NEW in v0.8.2)
|
|
77
77
|
|
|
78
|
-
After
|
|
78
|
+
After `npm install -g prjct-cli`, setup runs automatically:
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
- ✅ Installs `/p:*` commands to `~/.claude`
|
|
81
|
+
- ✅ Migrates legacy projects to global storage
|
|
82
|
+
- ✅ Syncs commands (removes orphans, adds new ones)
|
|
83
|
+
- ✅ Shows beautiful ASCII art with quick start
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
**That's it!** No manual setup required.
|
|
86
|
+
|
|
87
|
+
If you need to reconfigure later:
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
```bash
|
|
90
|
+
prjct setup # Reconfigure and sync commands
|
|
91
|
+
prjct setup --force # Force reinstall all commands
|
|
92
|
+
```
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
**Installation Location**: `~/.claude/commands/p/`
|
|
91
95
|
|
|
92
|
-
All
|
|
96
|
+
All 25+ slash commands (`/p:*`) are automatically installed to Claude Code and Claude Desktop.
|
|
93
97
|
|
|
94
98
|
### Version Management
|
|
95
99
|
|
package/core/commands.js
CHANGED
|
@@ -2593,7 +2593,26 @@ Agent: ${agent}
|
|
|
2593
2593
|
result.errors.forEach((e) => console.log(` - ${e.file}: ${e.error}`))
|
|
2594
2594
|
}
|
|
2595
2595
|
|
|
2596
|
-
|
|
2596
|
+
// Install global configuration
|
|
2597
|
+
console.log('\n📝 Installing global configuration...')
|
|
2598
|
+
const configResult = await commandInstaller.installGlobalConfig()
|
|
2599
|
+
|
|
2600
|
+
if (configResult.success) {
|
|
2601
|
+
if (configResult.action === 'created') {
|
|
2602
|
+
console.log('✅ Created ~/.claude/CLAUDE.md')
|
|
2603
|
+
} else if (configResult.action === 'updated') {
|
|
2604
|
+
console.log('✅ Updated ~/.claude/CLAUDE.md')
|
|
2605
|
+
} else if (configResult.action === 'appended') {
|
|
2606
|
+
console.log('✅ Added prjct config to ~/.claude/CLAUDE.md')
|
|
2607
|
+
}
|
|
2608
|
+
} else {
|
|
2609
|
+
console.log(`⚠️ ${configResult.error}`)
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
console.log('\n🎉 Setup complete!\n')
|
|
2613
|
+
|
|
2614
|
+
// Show beautiful ASCII art
|
|
2615
|
+
this.showAsciiArt()
|
|
2597
2616
|
|
|
2598
2617
|
return {
|
|
2599
2618
|
success: true,
|
|
@@ -2601,6 +2620,50 @@ Agent: ${agent}
|
|
|
2601
2620
|
}
|
|
2602
2621
|
}
|
|
2603
2622
|
|
|
2623
|
+
/**
|
|
2624
|
+
* Show beautiful ASCII art with quick start
|
|
2625
|
+
*/
|
|
2626
|
+
showAsciiArt() {
|
|
2627
|
+
const chalk = require('chalk')
|
|
2628
|
+
|
|
2629
|
+
console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))
|
|
2630
|
+
console.log('')
|
|
2631
|
+
console.log(chalk.bold.cyan(' ██████╗ ██████╗ ██╗ ██████╗████████╗'))
|
|
2632
|
+
console.log(chalk.bold.cyan(' ██╔══██╗██╔══██╗ ██║██╔════╝╚══██╔══╝'))
|
|
2633
|
+
console.log(chalk.bold.cyan(' ██████╔╝██████╔╝ ██║██║ ██║'))
|
|
2634
|
+
console.log(chalk.bold.cyan(' ██╔═══╝ ██╔══██╗██ ██║██║ ██║'))
|
|
2635
|
+
console.log(chalk.bold.cyan(' ██║ ██║ ██║╚█████╔╝╚██████╗ ██║'))
|
|
2636
|
+
console.log(chalk.bold.cyan(' ╚═╝ ╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═╝'))
|
|
2637
|
+
console.log('')
|
|
2638
|
+
console.log(` ${chalk.bold.cyan('prjct')}${chalk.magenta('/')}${chalk.green('cli')} ${chalk.dim.white('v' + VERSION + ' installed')}`)
|
|
2639
|
+
console.log('')
|
|
2640
|
+
console.log(` ${chalk.yellow('⚡')} Ship faster with zero friction`)
|
|
2641
|
+
console.log(` ${chalk.green('📝')} From idea to technical tasks in minutes`)
|
|
2642
|
+
console.log(` ${chalk.cyan('🤖')} Perfect context for AI agents`)
|
|
2643
|
+
console.log('')
|
|
2644
|
+
console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))
|
|
2645
|
+
console.log('')
|
|
2646
|
+
console.log(chalk.bold.cyan('🚀 Quick Start'))
|
|
2647
|
+
console.log(chalk.dim('─────────────────────────────────────────────────'))
|
|
2648
|
+
console.log('')
|
|
2649
|
+
console.log(` ${chalk.bold('1.')} Initialize your project:`)
|
|
2650
|
+
console.log(` ${chalk.green('cd your-project && prjct init')}`)
|
|
2651
|
+
console.log('')
|
|
2652
|
+
console.log(` ${chalk.bold('2.')} Set your current focus:`)
|
|
2653
|
+
console.log(` ${chalk.green('prjct now "build auth"')}`)
|
|
2654
|
+
console.log('')
|
|
2655
|
+
console.log(` ${chalk.bold('3.')} Ship & celebrate:`)
|
|
2656
|
+
console.log(` ${chalk.green('prjct ship "user login"')}`)
|
|
2657
|
+
console.log('')
|
|
2658
|
+
console.log(chalk.dim('─────────────────────────────────────────────────'))
|
|
2659
|
+
console.log('')
|
|
2660
|
+
console.log(` ${chalk.dim('Documentation:')} ${chalk.cyan('https://prjct.app')}`)
|
|
2661
|
+
console.log(` ${chalk.dim('Report issues:')} ${chalk.cyan('https://github.com/jlopezlira/prjct-cli/issues')}`)
|
|
2662
|
+
console.log('')
|
|
2663
|
+
console.log(chalk.bold.magenta('Happy shipping! 🚀'))
|
|
2664
|
+
console.log('')
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2604
2667
|
/**
|
|
2605
2668
|
* Migrate all legacy projects
|
|
2606
2669
|
*/
|
|
@@ -200,6 +200,20 @@ class CommandInstaller {
|
|
|
200
200
|
*/
|
|
201
201
|
async updateCommands() {
|
|
202
202
|
// Simply reinstall - will overwrite with latest templates
|
|
203
|
+
console.log('🔄 Updating commands with latest templates...')
|
|
204
|
+
const result = await this.installCommands()
|
|
205
|
+
if (result.success) {
|
|
206
|
+
console.log(`✅ Updated ${result.installed.length} commands`)
|
|
207
|
+
}
|
|
208
|
+
return result
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Install to all detected editors (alias for installCommands)
|
|
213
|
+
* @param {boolean} interactive - Whether to show interactive prompts
|
|
214
|
+
* @returns {Promise<Object>} Installation results
|
|
215
|
+
*/
|
|
216
|
+
async installToAll(interactive = false) {
|
|
203
217
|
return await this.installCommands()
|
|
204
218
|
}
|
|
205
219
|
|
|
@@ -225,6 +239,201 @@ class CommandInstaller {
|
|
|
225
239
|
return false
|
|
226
240
|
}
|
|
227
241
|
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Sync commands - intelligent update that detects and removes orphans
|
|
245
|
+
* @returns {Promise<Object>} Sync results with added, updated, removed counts
|
|
246
|
+
*/
|
|
247
|
+
async syncCommands() {
|
|
248
|
+
const claudeDetected = await this.detectClaude()
|
|
249
|
+
|
|
250
|
+
if (!claudeDetected) {
|
|
251
|
+
return {
|
|
252
|
+
success: false,
|
|
253
|
+
error: 'Claude not detected',
|
|
254
|
+
added: 0,
|
|
255
|
+
updated: 0,
|
|
256
|
+
removed: 0,
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
// Ensure commands directory exists
|
|
262
|
+
await fs.mkdir(this.claudeCommandsPath, { recursive: true })
|
|
263
|
+
|
|
264
|
+
// Get current state
|
|
265
|
+
const templateFiles = await this.getCommandFiles()
|
|
266
|
+
let installedFiles = []
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
installedFiles = await fs.readdir(this.claudeCommandsPath)
|
|
270
|
+
installedFiles = installedFiles.filter((f) => f.endsWith('.md'))
|
|
271
|
+
} catch {
|
|
272
|
+
// Directory doesn't exist yet
|
|
273
|
+
installedFiles = []
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const results = {
|
|
277
|
+
success: true,
|
|
278
|
+
added: 0,
|
|
279
|
+
updated: 0,
|
|
280
|
+
removed: 0,
|
|
281
|
+
errors: [],
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Detect new and updated files
|
|
285
|
+
for (const file of templateFiles) {
|
|
286
|
+
try {
|
|
287
|
+
const sourcePath = path.join(this.templatesDir, file)
|
|
288
|
+
const destPath = path.join(this.claudeCommandsPath, file)
|
|
289
|
+
|
|
290
|
+
// Check if file exists in installed location
|
|
291
|
+
const exists = installedFiles.includes(file)
|
|
292
|
+
|
|
293
|
+
if (!exists) {
|
|
294
|
+
// New file
|
|
295
|
+
const content = await fs.readFile(sourcePath, 'utf-8')
|
|
296
|
+
await fs.writeFile(destPath, content, 'utf-8')
|
|
297
|
+
results.added++
|
|
298
|
+
} else {
|
|
299
|
+
// Check if updated (compare modification time or content)
|
|
300
|
+
const sourceStats = await fs.stat(sourcePath)
|
|
301
|
+
const destStats = await fs.stat(destPath)
|
|
302
|
+
|
|
303
|
+
if (sourceStats.mtime > destStats.mtime) {
|
|
304
|
+
// Updated file
|
|
305
|
+
const content = await fs.readFile(sourcePath, 'utf-8')
|
|
306
|
+
await fs.writeFile(destPath, content, 'utf-8')
|
|
307
|
+
results.updated++
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
results.errors.push({ file, error: error.message })
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Detect and remove orphaned files
|
|
316
|
+
const orphans = installedFiles.filter((file) => !templateFiles.includes(file))
|
|
317
|
+
|
|
318
|
+
for (const orphan of orphans) {
|
|
319
|
+
try {
|
|
320
|
+
const orphanPath = path.join(this.claudeCommandsPath, orphan)
|
|
321
|
+
await fs.unlink(orphanPath)
|
|
322
|
+
results.removed++
|
|
323
|
+
} catch (error) {
|
|
324
|
+
results.errors.push({ file: orphan, error: error.message })
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return results
|
|
329
|
+
} catch (error) {
|
|
330
|
+
return {
|
|
331
|
+
success: false,
|
|
332
|
+
error: error.message,
|
|
333
|
+
added: 0,
|
|
334
|
+
updated: 0,
|
|
335
|
+
removed: 0,
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Install or update global CLAUDE.md configuration
|
|
342
|
+
* @returns {Promise<Object>} Result with success status and action taken
|
|
343
|
+
*/
|
|
344
|
+
async installGlobalConfig() {
|
|
345
|
+
const claudeDetected = await this.detectClaude()
|
|
346
|
+
|
|
347
|
+
if (!claudeDetected) {
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
error: 'Claude not detected',
|
|
351
|
+
action: 'skipped',
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
// Ensure ~/.claude directory exists
|
|
357
|
+
const claudeDir = path.join(require('os').homedir(), '.claude')
|
|
358
|
+
await fs.mkdir(claudeDir, { recursive: true })
|
|
359
|
+
|
|
360
|
+
const globalConfigPath = path.join(claudeDir, 'CLAUDE.md')
|
|
361
|
+
const templatePath = path.join(__dirname, '../../templates/global/CLAUDE.md')
|
|
362
|
+
|
|
363
|
+
// Read template content
|
|
364
|
+
const templateContent = await fs.readFile(templatePath, 'utf-8')
|
|
365
|
+
|
|
366
|
+
// Check if global config already exists
|
|
367
|
+
let existingContent = ''
|
|
368
|
+
let fileExists = false
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
existingContent = await fs.readFile(globalConfigPath, 'utf-8')
|
|
372
|
+
fileExists = true
|
|
373
|
+
} catch {
|
|
374
|
+
// File doesn't exist, will create new
|
|
375
|
+
fileExists = false
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (!fileExists) {
|
|
379
|
+
// Create new file with full template
|
|
380
|
+
await fs.writeFile(globalConfigPath, templateContent, 'utf-8')
|
|
381
|
+
return {
|
|
382
|
+
success: true,
|
|
383
|
+
action: 'created',
|
|
384
|
+
path: globalConfigPath,
|
|
385
|
+
}
|
|
386
|
+
} else {
|
|
387
|
+
// File exists - perform intelligent merge
|
|
388
|
+
const startMarker = '<!-- prjct:start - DO NOT REMOVE THIS MARKER -->'
|
|
389
|
+
const endMarker = '<!-- prjct:end - DO NOT REMOVE THIS MARKER -->'
|
|
390
|
+
|
|
391
|
+
// Check if markers exist in existing file
|
|
392
|
+
const hasMarkers =
|
|
393
|
+
existingContent.includes(startMarker) && existingContent.includes(endMarker)
|
|
394
|
+
|
|
395
|
+
if (!hasMarkers) {
|
|
396
|
+
// No markers - append prjct section at the end
|
|
397
|
+
const updatedContent = existingContent + '\n\n' + templateContent
|
|
398
|
+
await fs.writeFile(globalConfigPath, updatedContent, 'utf-8')
|
|
399
|
+
return {
|
|
400
|
+
success: true,
|
|
401
|
+
action: 'appended',
|
|
402
|
+
path: globalConfigPath,
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
// Markers exist - replace content between markers
|
|
406
|
+
const beforeMarker = existingContent.substring(
|
|
407
|
+
0,
|
|
408
|
+
existingContent.indexOf(startMarker)
|
|
409
|
+
)
|
|
410
|
+
const afterMarker = existingContent.substring(
|
|
411
|
+
existingContent.indexOf(endMarker) + endMarker.length
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
// Extract prjct section from template
|
|
415
|
+
const prjctSection = templateContent.substring(
|
|
416
|
+
templateContent.indexOf(startMarker),
|
|
417
|
+
templateContent.indexOf(endMarker) + endMarker.length
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
const updatedContent = beforeMarker + prjctSection + afterMarker
|
|
421
|
+
await fs.writeFile(globalConfigPath, updatedContent, 'utf-8')
|
|
422
|
+
return {
|
|
423
|
+
success: true,
|
|
424
|
+
action: 'updated',
|
|
425
|
+
path: globalConfigPath,
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
} catch (error) {
|
|
430
|
+
return {
|
|
431
|
+
success: false,
|
|
432
|
+
error: error.message,
|
|
433
|
+
action: 'failed',
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
228
437
|
}
|
|
229
438
|
|
|
230
439
|
module.exports = new CommandInstaller()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prjct-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
|
|
5
5
|
"main": "core/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"registry": "https://registry.npmjs.org"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
+
"postinstall": "node scripts/postinstall.js",
|
|
14
15
|
"install-global": "./scripts/install.sh",
|
|
16
|
+
"update": "./scripts/update.sh",
|
|
15
17
|
"test": "vitest run --workspace=vitest.workspace.js",
|
|
16
18
|
"test:watch": "vitest --workspace=vitest.workspace.js",
|
|
17
19
|
"test:coverage": "vitest run --coverage --workspace=vitest.workspace.js",
|
|
@@ -73,6 +75,7 @@
|
|
|
73
75
|
"bin/",
|
|
74
76
|
"core/",
|
|
75
77
|
"templates/",
|
|
78
|
+
"scripts/postinstall.js",
|
|
76
79
|
"scripts/install.sh",
|
|
77
80
|
"LICENSE",
|
|
78
81
|
"README.md",
|
package/scripts/install.sh
CHANGED
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
# ⚠️ DEPRECATED: This installation method is deprecated
|
|
4
|
+
# Use npm instead: npm install -g prjct-cli
|
|
5
|
+
#
|
|
6
|
+
# This script is kept for backward compatibility only.
|
|
7
|
+
|
|
8
|
+
# Colors
|
|
9
|
+
YELLOW='\033[1;33m'
|
|
10
|
+
CYAN='\033[0;36m'
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
NC='\033[0m'
|
|
13
|
+
|
|
14
|
+
echo ""
|
|
15
|
+
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
16
|
+
echo -e "${YELLOW}⚠️ This installation method is DEPRECATED${NC}"
|
|
17
|
+
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
18
|
+
echo ""
|
|
19
|
+
echo -e "Please use npm instead:"
|
|
20
|
+
echo ""
|
|
21
|
+
echo -e " ${GREEN}npm install -g prjct-cli${NC}"
|
|
22
|
+
echo ""
|
|
23
|
+
echo -e "Benefits of npm installation:"
|
|
24
|
+
echo -e " • ${CYAN}Automatic setup${NC} - No manual configuration needed"
|
|
25
|
+
echo -e " • ${CYAN}Auto-migration${NC} - Legacy projects migrated automatically"
|
|
26
|
+
echo -e " • ${CYAN}Beautiful ASCII art${NC} - See the installation success"
|
|
27
|
+
echo -e " • ${CYAN}Easy updates${NC} - Just npm update -g prjct-cli"
|
|
28
|
+
echo ""
|
|
29
|
+
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
30
|
+
echo ""
|
|
31
|
+
exit 1
|
|
32
|
+
|
|
33
|
+
# Original install.sh preserved below (not executed)
|
|
34
|
+
# ------------------------------------------------
|
|
11
35
|
|
|
12
36
|
set -e
|
|
13
37
|
|
|
@@ -105,7 +129,7 @@ echo -e " ${BOLD}${CYAN}██████╔╝██████╔╝
|
|
|
105
129
|
echo -e " ${BOLD}${CYAN}██╔═══╝ ██╔══██╗██ ██║██║ ██║${NC}"
|
|
106
130
|
echo -e " ${BOLD}${CYAN}██║ ██║ ██║╚█████╔╝╚██████╗ ██║${NC}"
|
|
107
131
|
echo -e " ${BOLD}${CYAN}╚═╝ ╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═╝${NC}"
|
|
108
|
-
echo -e " ${BOLD}${CYAN}prjct${NC}${MAGENTA}/${NC}${GREEN}cli${NC} ${DIM}${WHITE}v0.
|
|
132
|
+
echo -e " ${BOLD}${CYAN}prjct${NC}${MAGENTA}/${NC}${GREEN}cli${NC} ${DIM}${WHITE}v0.8.1${NC}"
|
|
109
133
|
echo ""
|
|
110
134
|
echo -e " ${DIM}Turn ideas into AI-ready roadmaps${NC}"
|
|
111
135
|
echo ""
|
|
@@ -244,6 +268,18 @@ if [ -d "$INSTALL_DIR" ]; then
|
|
|
244
268
|
) &
|
|
245
269
|
spin $!
|
|
246
270
|
echo -e " ${GREEN}${CHECK}${NC} Updated to v${REMOTE_VERSION}"
|
|
271
|
+
|
|
272
|
+
# Auto-update commands after git pull
|
|
273
|
+
printf " ${ARROW} Updating commands"
|
|
274
|
+
(
|
|
275
|
+
cd "$INSTALL_DIR"
|
|
276
|
+
node -e "
|
|
277
|
+
const installer = require('./core/infrastructure/command-installer');
|
|
278
|
+
installer.updateCommands();
|
|
279
|
+
" > /dev/null 2>&1
|
|
280
|
+
) &
|
|
281
|
+
spin $!
|
|
282
|
+
echo -e " ${GREEN}${CHECK}${NC} Commands synchronized"
|
|
247
283
|
else
|
|
248
284
|
printf " ${ARROW} Cloning repository"
|
|
249
285
|
(
|
|
@@ -312,7 +348,7 @@ else
|
|
|
312
348
|
printf " ${ARROW} Auto-installing to all detected editors...\n"
|
|
313
349
|
|
|
314
350
|
INSTALL_RESULT=$(node -e "
|
|
315
|
-
const installer = require('./core/command-installer');
|
|
351
|
+
const installer = require('./core/infrastructure/command-installer');
|
|
316
352
|
installer.installToAll(false).then(result => {
|
|
317
353
|
console.log('__RESULT_START__');
|
|
318
354
|
console.log(JSON.stringify(result));
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-install hook for prjct-cli
|
|
5
|
+
*
|
|
6
|
+
* Runs automatically after npm install -g prjct-cli
|
|
7
|
+
*
|
|
8
|
+
* 1. Detects if global install
|
|
9
|
+
* 2. Installs/syncs commands to ~/.claude/commands/p/
|
|
10
|
+
* 3. Installs/updates global config to ~/.claude/CLAUDE.md
|
|
11
|
+
* 4. Migrates legacy projects automatically
|
|
12
|
+
* 5. Shows beautiful ASCII art
|
|
13
|
+
*
|
|
14
|
+
* @version 0.8.2
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('fs')
|
|
18
|
+
const path = require('path')
|
|
19
|
+
const installer = require('../core/infrastructure/command-installer')
|
|
20
|
+
const migrator = require('../core/infrastructure/migrator')
|
|
21
|
+
const { VERSION } = require('../core/utils/version')
|
|
22
|
+
|
|
23
|
+
// Colors for terminal output
|
|
24
|
+
const CYAN = '\x1b[36m'
|
|
25
|
+
const GREEN = '\x1b[32m'
|
|
26
|
+
const YELLOW = '\x1b[33m'
|
|
27
|
+
const MAGENTA = '\x1b[35m'
|
|
28
|
+
const WHITE = '\x1b[37m'
|
|
29
|
+
const BOLD = '\x1b[1m'
|
|
30
|
+
const DIM = '\x1b[2m'
|
|
31
|
+
const NC = '\x1b[0m' // No Color
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
try {
|
|
35
|
+
// Detect if this is a global install
|
|
36
|
+
const isGlobal = await detectGlobalInstall()
|
|
37
|
+
|
|
38
|
+
if (!isGlobal) {
|
|
39
|
+
// Skip postinstall for local development installs
|
|
40
|
+
console.log(`${DIM}Skipping post-install (local development)${NC}`)
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log('')
|
|
45
|
+
console.log(`${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`)
|
|
46
|
+
console.log(`${BOLD}${CYAN}🚀 Setting up prjct-cli...${NC}`)
|
|
47
|
+
console.log(`${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`)
|
|
48
|
+
console.log('')
|
|
49
|
+
|
|
50
|
+
// Step 1: Detect Claude Code
|
|
51
|
+
console.log(`${BOLD}[1/5]${NC} Detecting Claude Code...`)
|
|
52
|
+
const claudeDetected = await installer.detectClaude()
|
|
53
|
+
|
|
54
|
+
if (!claudeDetected) {
|
|
55
|
+
console.log(`${YELLOW}⚠️ Claude Code not detected${NC}`)
|
|
56
|
+
console.log(`${DIM}Install Claude Code from: https://claude.ai/code${NC}`)
|
|
57
|
+
console.log(`${DIM}Then run: prjct setup${NC}`)
|
|
58
|
+
console.log('')
|
|
59
|
+
} else {
|
|
60
|
+
console.log(`${GREEN}✓${NC} Claude Code found`)
|
|
61
|
+
console.log('')
|
|
62
|
+
|
|
63
|
+
// Step 2: Install/sync commands
|
|
64
|
+
console.log(`${BOLD}[2/5]${NC} Installing commands to ~/.claude...`)
|
|
65
|
+
const syncResult = await installer.syncCommands()
|
|
66
|
+
|
|
67
|
+
if (syncResult.success) {
|
|
68
|
+
const { added, updated, removed } = syncResult
|
|
69
|
+
const changes = []
|
|
70
|
+
if (added > 0) changes.push(`${added} nuevos`)
|
|
71
|
+
if (updated > 0) changes.push(`${updated} actualizados`)
|
|
72
|
+
if (removed > 0) changes.push(`${removed} eliminados`)
|
|
73
|
+
|
|
74
|
+
if (changes.length > 0) {
|
|
75
|
+
console.log(`${GREEN}✓${NC} ${changes.join(', ')}`)
|
|
76
|
+
} else {
|
|
77
|
+
console.log(`${GREEN}✓${NC} All commands up to date`)
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
console.log(`${YELLOW}⚠️ ${syncResult.error}${NC}`)
|
|
81
|
+
}
|
|
82
|
+
console.log('')
|
|
83
|
+
|
|
84
|
+
// Step 3: Install global configuration
|
|
85
|
+
console.log(`${BOLD}[3/5]${NC} Installing global configuration...`)
|
|
86
|
+
const configResult = await installer.installGlobalConfig()
|
|
87
|
+
|
|
88
|
+
if (configResult.success) {
|
|
89
|
+
if (configResult.action === 'created') {
|
|
90
|
+
console.log(`${GREEN}✓${NC} Created ~/.claude/CLAUDE.md`)
|
|
91
|
+
} else if (configResult.action === 'updated') {
|
|
92
|
+
console.log(`${GREEN}✓${NC} Updated ~/.claude/CLAUDE.md`)
|
|
93
|
+
} else if (configResult.action === 'appended') {
|
|
94
|
+
console.log(`${GREEN}✓${NC} Added prjct config to ~/.claude/CLAUDE.md`)
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
console.log(`${YELLOW}⚠️ ${configResult.error}${NC}`)
|
|
98
|
+
}
|
|
99
|
+
console.log('')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Step 4: Migrate legacy projects
|
|
103
|
+
console.log(`${BOLD}[4/5]${NC} Checking for legacy projects...`)
|
|
104
|
+
const migrationResult = await migrator.migrateAll({
|
|
105
|
+
deepScan: false, // Only search common directories
|
|
106
|
+
cleanupLegacy: true, // Remove legacy directories, keep config
|
|
107
|
+
dryRun: false
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
if (migrationResult.successfullyMigrated > 0) {
|
|
111
|
+
console.log(`${GREEN}✓${NC} ${migrationResult.successfullyMigrated} projects migrated to global storage`)
|
|
112
|
+
} else if (migrationResult.totalFound === 0) {
|
|
113
|
+
console.log(`${DIM}No legacy projects found${NC}`)
|
|
114
|
+
} else {
|
|
115
|
+
console.log(`${DIM}All projects already migrated${NC}`)
|
|
116
|
+
}
|
|
117
|
+
console.log('')
|
|
118
|
+
|
|
119
|
+
// Step 5: Show ASCII art and quick start
|
|
120
|
+
console.log(`${BOLD}[5/5]${NC} Installation complete!`)
|
|
121
|
+
console.log('')
|
|
122
|
+
showAsciiArt()
|
|
123
|
+
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(`${YELLOW}⚠️ Post-install error: ${error.message}${NC}`)
|
|
126
|
+
console.error(`${DIM}You can run 'prjct setup' manually later${NC}`)
|
|
127
|
+
// Don't fail the install if post-install has issues
|
|
128
|
+
process.exit(0)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Detect if this is a global npm install
|
|
134
|
+
*/
|
|
135
|
+
async function detectGlobalInstall() {
|
|
136
|
+
// Check if we're being installed globally
|
|
137
|
+
const npmConfig = process.env.npm_config_global
|
|
138
|
+
if (npmConfig === 'true') {
|
|
139
|
+
return true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check if install location is in global node_modules
|
|
143
|
+
const installPath = __dirname
|
|
144
|
+
const globalPaths = [
|
|
145
|
+
'/usr/local/lib/node_modules',
|
|
146
|
+
'/usr/lib/node_modules',
|
|
147
|
+
path.join(process.env.HOME || '', '.npm-global', 'lib', 'node_modules'),
|
|
148
|
+
path.join(process.env.HOME || '', '.nvm'),
|
|
149
|
+
path.join(process.env.APPDATA || '', 'npm', 'node_modules')
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
return globalPaths.some(globalPath => installPath.includes(globalPath))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Show beautiful ASCII art with quick start
|
|
157
|
+
*/
|
|
158
|
+
function showAsciiArt() {
|
|
159
|
+
console.log(`${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`)
|
|
160
|
+
console.log('')
|
|
161
|
+
console.log(` ${BOLD}${CYAN}██████╗ ██████╗ ██╗ ██████╗████████╗${NC}`)
|
|
162
|
+
console.log(` ${BOLD}${CYAN}██╔══██╗██╔══██╗ ██║██╔════╝╚══██╔══╝${NC}`)
|
|
163
|
+
console.log(` ${BOLD}${CYAN}██████╔╝██████╔╝ ██║██║ ██║${NC}`)
|
|
164
|
+
console.log(` ${BOLD}${CYAN}██╔═══╝ ██╔══██╗██ ██║██║ ██║${NC}`)
|
|
165
|
+
console.log(` ${BOLD}${CYAN}██║ ██║ ██║╚█████╔╝╚██████╗ ██║${NC}`)
|
|
166
|
+
console.log(` ${BOLD}${CYAN}╚═╝ ╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═╝${NC}`)
|
|
167
|
+
console.log('')
|
|
168
|
+
console.log(` ${BOLD}${CYAN}prjct${NC}${MAGENTA}/${NC}${GREEN}cli${NC} ${DIM}${WHITE}v${VERSION} installed${NC}`)
|
|
169
|
+
console.log('')
|
|
170
|
+
console.log(` ${YELLOW}⚡${NC} Ship faster with zero friction`)
|
|
171
|
+
console.log(` ${GREEN}📝${NC} From idea to technical tasks in minutes`)
|
|
172
|
+
console.log(` ${CYAN}🤖${NC} Perfect context for AI agents`)
|
|
173
|
+
console.log('')
|
|
174
|
+
console.log(`${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`)
|
|
175
|
+
console.log('')
|
|
176
|
+
console.log(`${BOLD}${CYAN}🚀 Quick Start${NC}`)
|
|
177
|
+
console.log(`${DIM}─────────────────────────────────────────────────${NC}`)
|
|
178
|
+
console.log('')
|
|
179
|
+
console.log(` ${BOLD}1.${NC} Initialize your project:`)
|
|
180
|
+
console.log(` ${GREEN}cd your-project && prjct init${NC}`)
|
|
181
|
+
console.log('')
|
|
182
|
+
console.log(` ${BOLD}2.${NC} Set your current focus:`)
|
|
183
|
+
console.log(` ${GREEN}prjct now "build auth"${NC}`)
|
|
184
|
+
console.log('')
|
|
185
|
+
console.log(` ${BOLD}3.${NC} Ship & celebrate:`)
|
|
186
|
+
console.log(` ${GREEN}prjct ship "user login"${NC}`)
|
|
187
|
+
console.log('')
|
|
188
|
+
console.log(`${DIM}─────────────────────────────────────────────────${NC}`)
|
|
189
|
+
console.log('')
|
|
190
|
+
console.log(` ${DIM}Documentation:${NC} ${CYAN}https://prjct.app${NC}`)
|
|
191
|
+
console.log(` ${DIM}Report issues:${NC} ${CYAN}https://github.com/jlopezlira/prjct-cli/issues${NC}`)
|
|
192
|
+
console.log('')
|
|
193
|
+
console.log(`${BOLD}${MAGENTA}Happy shipping! 🚀${NC}`)
|
|
194
|
+
console.log('')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Run if executed directly
|
|
198
|
+
if (require.main === module) {
|
|
199
|
+
main().catch(error => {
|
|
200
|
+
console.error('Fatal error:', error.message)
|
|
201
|
+
process.exit(0) // Don't fail npm install
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
module.exports = main
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<!-- prjct:start - DO NOT REMOVE THIS MARKER -->
|
|
2
|
+
# prjct Configuration
|
|
3
|
+
|
|
4
|
+
This section provides global context for all `/p:*` commands across any prjct project.
|
|
5
|
+
|
|
6
|
+
**Auto-managed by prjct-cli** - This section is automatically updated when you install or update prjct.
|
|
7
|
+
|
|
8
|
+
## 🎯 Path Resolution for ALL /p:* Commands
|
|
9
|
+
|
|
10
|
+
**CRITICAL**: Every `/p:*` command operates on **global storage**, NOT local files.
|
|
11
|
+
|
|
12
|
+
### Resolution Steps:
|
|
13
|
+
|
|
14
|
+
1. **Detect prjct project**: Check if `.prjct/prjct.config.json` exists in current working directory
|
|
15
|
+
2. **Read config**: Extract `projectId` from `.prjct/prjct.config.json`
|
|
16
|
+
3. **Construct base path**: `~/.prjct-cli/projects/{projectId}/`
|
|
17
|
+
4. **Resolve all file operations**: All paths in command templates are relative to base path
|
|
18
|
+
|
|
19
|
+
### Examples:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Template says: "Write: core/now.md"
|
|
23
|
+
Actual path: ~/.prjct-cli/projects/{projectId}/core/now.md
|
|
24
|
+
|
|
25
|
+
Template says: "Read: memory/context.jsonl"
|
|
26
|
+
Actual path: ~/.prjct-cli/projects/{projectId}/memory/context.jsonl
|
|
27
|
+
|
|
28
|
+
Template says: "Update: progress/shipped.md"
|
|
29
|
+
Actual path: ~/.prjct-cli/projects/{projectId}/progress/shipped.md
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Validation Rules:
|
|
33
|
+
|
|
34
|
+
- ❌ **NEVER** write to `.prjct/core/now.md` (local project directory)
|
|
35
|
+
- ❌ **NEVER** write to `./core/now.md` (current working directory)
|
|
36
|
+
- ✅ **ALWAYS** write to `~/.prjct-cli/projects/{projectId}/core/now.md` (global storage)
|
|
37
|
+
|
|
38
|
+
### When NOT in prjct Project:
|
|
39
|
+
|
|
40
|
+
If `.prjct/prjct.config.json` doesn't exist in current directory:
|
|
41
|
+
- Respond: "No prjct project detected. Initialize first with `/p:init`"
|
|
42
|
+
- Do NOT execute the command
|
|
43
|
+
- Do NOT create files
|
|
44
|
+
|
|
45
|
+
## 📁 File Structure
|
|
46
|
+
|
|
47
|
+
All prjct data lives in global storage with session-based architecture:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
~/.prjct-cli/projects/{projectId}/
|
|
51
|
+
├── core/ # Current focus (always small)
|
|
52
|
+
│ ├── now.md # Single current task
|
|
53
|
+
│ ├── next.md # Priority queue (max 100 tasks)
|
|
54
|
+
│ └── context.md # Project context summary
|
|
55
|
+
├── progress/ # Completed work
|
|
56
|
+
│ ├── shipped.md # Recent ships (last 30 days)
|
|
57
|
+
│ ├── metrics.md # Aggregated metrics
|
|
58
|
+
│ ├── sessions/ # Daily session logs (JSONL)
|
|
59
|
+
│ │ └── 2025-10/
|
|
60
|
+
│ │ └── 2025-10-05.jsonl
|
|
61
|
+
│ └── archive/ # Monthly archives
|
|
62
|
+
│ └── shipped-2025-10.md
|
|
63
|
+
├── planning/ # Future planning
|
|
64
|
+
│ ├── ideas.md # Active ideas (last 30 days)
|
|
65
|
+
│ ├── roadmap.md # Active roadmap (lightweight)
|
|
66
|
+
│ ├── sessions/ # Daily planning sessions (JSONL)
|
|
67
|
+
│ │ └── 2025-10/
|
|
68
|
+
│ │ └── 2025-10-05.jsonl
|
|
69
|
+
│ └── archive/ # Monthly archives
|
|
70
|
+
│ └── roadmap-2025-10.md
|
|
71
|
+
├── analysis/ # Technical analysis
|
|
72
|
+
│ └── repo-summary.md
|
|
73
|
+
├── memory/ # Decision history
|
|
74
|
+
│ ├── context.jsonl # Global decisions (append-only)
|
|
75
|
+
│ └── sessions/ # Daily context (structured)
|
|
76
|
+
│ └── 2025-10/
|
|
77
|
+
│ └── 2025-10-05.jsonl
|
|
78
|
+
└── agents/ # Dynamic AI agents
|
|
79
|
+
├── coordinator.md
|
|
80
|
+
├── ux.md
|
|
81
|
+
├── fe.md
|
|
82
|
+
├── be.md
|
|
83
|
+
├── qa.md
|
|
84
|
+
└── scribe.md
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Session Format (JSONL):
|
|
88
|
+
|
|
89
|
+
One JSON object per line, append-only:
|
|
90
|
+
|
|
91
|
+
```jsonl
|
|
92
|
+
{"ts":"2025-10-05T14:30:00Z","type":"feature_add","name":"auth","tasks":5,"impact":"high","effort":"6h"}
|
|
93
|
+
{"ts":"2025-10-05T15:00:00Z","type":"task_start","task":"JWT middleware","agent":"be","estimate":"2h"}
|
|
94
|
+
{"ts":"2025-10-05T17:15:00Z","type":"task_complete","task":"JWT middleware","duration":"2h15m"}
|
|
95
|
+
{"ts":"2025-10-05T18:00:00Z","type":"feature_ship","name":"auth","tasks_done":5,"total_time":"6h"}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 🤖 Git Commit Format
|
|
99
|
+
|
|
100
|
+
**ALL commits made by prjct MUST use this footer:**
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
🤖 Generated with [p/](https://www.prjct.app/)
|
|
104
|
+
Designed for [Claude](https://www.anthropic.com/claude)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Never use:**
|
|
108
|
+
- ❌ "Generated with Claude Code"
|
|
109
|
+
- ❌ "Co-Authored-By: Claude"
|
|
110
|
+
|
|
111
|
+
**Always use:**
|
|
112
|
+
- ✅ The prjct footer format above
|
|
113
|
+
|
|
114
|
+
## 👤 Author Detection
|
|
115
|
+
|
|
116
|
+
All operations include author information. Detection order:
|
|
117
|
+
|
|
118
|
+
1. **GitHub CLI**: `gh api user` (preferred)
|
|
119
|
+
- Provides: name, email, username, avatarUrl
|
|
120
|
+
2. **Git Config**: Fallback if GitHub CLI not available
|
|
121
|
+
- `git config user.name`
|
|
122
|
+
- `git config user.email`
|
|
123
|
+
3. **Default**: If both fail
|
|
124
|
+
- name: "Unknown"
|
|
125
|
+
- email: "unknown@localhost"
|
|
126
|
+
|
|
127
|
+
Every log entry in `memory/context.jsonl` includes author field.
|
|
128
|
+
|
|
129
|
+
## ⚠️ Common Validation Patterns
|
|
130
|
+
|
|
131
|
+
### Before Executing /p:done:
|
|
132
|
+
```javascript
|
|
133
|
+
// Check if there's an active task
|
|
134
|
+
const nowContent = await Read('~/.prjct-cli/projects/{projectId}/core/now.md')
|
|
135
|
+
if (!nowContent || nowContent.trim() === '') {
|
|
136
|
+
return "Not working on anything. Use /p:now to start a task."
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Before Executing /p:ship:
|
|
141
|
+
```javascript
|
|
142
|
+
// Check if there's something to ship
|
|
143
|
+
const shippedContent = await Read('~/.prjct-cli/projects/{projectId}/progress/shipped.md')
|
|
144
|
+
const nowContent = await Read('~/.prjct-cli/projects/{projectId}/core/now.md')
|
|
145
|
+
if ((!nowContent || nowContent.trim() === '') &&
|
|
146
|
+
(!shippedContent || shippedContent.trim() === '')) {
|
|
147
|
+
return "Nothing to ship yet. Build something first with /p:now."
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Reading Project Config:
|
|
152
|
+
```javascript
|
|
153
|
+
// Always read config first
|
|
154
|
+
const configPath = '.prjct/prjct.config.json'
|
|
155
|
+
const configContent = await Read(configPath)
|
|
156
|
+
const config = JSON.parse(configContent)
|
|
157
|
+
const projectId = config.projectId
|
|
158
|
+
const basePath = `~/.prjct-cli/projects/${projectId}/`
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 🔧 Error Handling
|
|
162
|
+
|
|
163
|
+
### File Not Found:
|
|
164
|
+
- If `core/now.md` doesn't exist when reading → return empty state
|
|
165
|
+
- If `core/next.md` doesn't exist → return "No tasks in queue"
|
|
166
|
+
- Always check file existence before operations
|
|
167
|
+
|
|
168
|
+
### Invalid JSON:
|
|
169
|
+
- If config file is corrupted → suggest running `/p:init` again
|
|
170
|
+
- Log error to `memory/context.jsonl` for debugging
|
|
171
|
+
|
|
172
|
+
### Permission Issues:
|
|
173
|
+
- If can't write to `~/.prjct-cli/` → check directory permissions
|
|
174
|
+
- Suggest: `chmod -R u+w ~/.prjct-cli/`
|
|
175
|
+
|
|
176
|
+
## 📊 Performance Guidelines
|
|
177
|
+
|
|
178
|
+
### Archive Rules:
|
|
179
|
+
- Index files (roadmap.md, shipped.md) keep only last 30 days
|
|
180
|
+
- Sessions older than 30 days → automatically moved to archive/
|
|
181
|
+
- When querying across time: read relevant session files from archive/
|
|
182
|
+
- Commands only read current index + today's session for performance
|
|
183
|
+
|
|
184
|
+
### File Size Limits:
|
|
185
|
+
- `core/now.md`: Single task only (< 1KB)
|
|
186
|
+
- `core/next.md`: Max 100 tasks (< 50KB)
|
|
187
|
+
- `progress/shipped.md`: Last 30 days only (auto-archive older)
|
|
188
|
+
- Session files: One file per day, JSONL format for efficient appending
|
|
189
|
+
|
|
190
|
+
## 🎯 Command Execution Flow
|
|
191
|
+
|
|
192
|
+
Standard pattern for all `/p:*` commands:
|
|
193
|
+
|
|
194
|
+
1. **Validate environment**: Check `.prjct/prjct.config.json` exists
|
|
195
|
+
2. **Read config**: Extract projectId
|
|
196
|
+
3. **Construct paths**: Build all file paths using base path
|
|
197
|
+
4. **Execute operations**: Read/write files in global storage
|
|
198
|
+
5. **Log action**: Append to `memory/context.jsonl` with timestamp and author
|
|
199
|
+
6. **Return response**: Formatted response with next action suggestions
|
|
200
|
+
|
|
201
|
+
## 📚 Additional Context
|
|
202
|
+
|
|
203
|
+
- **Website**: https://prjct.app
|
|
204
|
+
- **Documentation**: https://prjct.app/docs
|
|
205
|
+
- **Repository**: Private (proprietary software)
|
|
206
|
+
- **Support**: jlopezlira@gmail.com
|
|
207
|
+
- **Version**: Auto-updated with prjct-cli
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
**Last updated**: Auto-managed by prjct-cli
|
|
212
|
+
**Config version**: 0.8.2
|
|
213
|
+
|
|
214
|
+
<!-- prjct:end - DO NOT REMOVE THIS MARKER -->
|