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 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
- ### Editor Command Installation
76
+ ### Auto-Setup (NEW in v0.8.2)
77
77
 
78
- After initial installation, `prjct` automatically installs slash commands to Claude:
78
+ After `npm install -g prjct-cli`, setup runs automatically:
79
79
 
80
- ```bash
81
- # Interactive installation (recommended)
82
- prjct install
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
- # Force update existing commands
85
- prjct install --force
86
- ```
85
+ **That's it!** No manual setup required.
86
+
87
+ If you need to reconfigure later:
87
88
 
88
- **Installation Location:**
89
+ ```bash
90
+ prjct setup # Reconfigure and sync commands
91
+ prjct setup --force # Force reinstall all commands
92
+ ```
89
93
 
90
- - **Claude Code & Claude Desktop**: `~/.claude/commands/p/`
94
+ **Installation Location**: `~/.claude/commands/p/`
91
95
 
92
- All 18 slash commands (`/p:*`) are automatically installed to Claude Code and Claude Desktop.
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
- console.log('\n🎉 Setup complete!')
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.0",
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",
@@ -1,13 +1,37 @@
1
1
  #!/bin/bash
2
2
 
3
- # prjct/cli - Turn ideas into AI-ready roadmaps
4
- # Usage: curl -fsSL https://prjct.app/install.sh | bash
5
- # Options:
6
- # --force Force reinstall even if up to date
7
- # --dev Install from development branch
8
- # --silent Silent mode (no interactive prompts)
9
- # -y, --yes Auto-accept all prompts
10
- # --help, -h Show this help message
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.3.1${NC}"
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 -->