prjct-cli 0.4.1 → 0.4.3

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,60 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Coming Soon
11
+ - **Windows Compatibility** - Native Windows support
12
+ - PowerShell and CMD command execution
13
+ - Windows path handling (`%USERPROFILE%\.prjct-cli\`)
14
+ - Windows-specific installation scripts
15
+ - Cross-platform file operations
16
+ - Windows Terminal integration
17
+
18
+ ## [0.4.3] - 2025-10-02
19
+
20
+ ### Added
21
+ - **Automatic Editor Command Updates** - Commands auto-update when npm package is updated
22
+ - New `core/editors-config.js` tracks which editors user has installed commands to
23
+ - Stores editor selections in `~/.prjct-cli/config/installed-editors.json`
24
+ - Post-install hook (`scripts/post-install.js`) auto-updates commands after `npm update -g prjct-cli`
25
+ - Ensures version consistency across all configured editors (Claude, Cursor, Windsurf, Codex)
26
+ - No manual reinstallation needed - updates happen automatically
27
+ - Respects user's original editor choices from initial setup
28
+
29
+ - **GitHub Packages Support** - Dual registry publication for better reliability
30
+ - Package now published to both npm and GitHub Packages automatically
31
+ - GitHub Actions workflow updated to publish to both registries in parallel
32
+ - Added comprehensive GitHub Packages documentation (`docs/GITHUB_PACKAGES.md`)
33
+ - Includes `.npmrc.example` for easy local configuration
34
+ - Provides fallback option if npm registry is unavailable
35
+ - Free hosting for public repositories with automatic authentication
36
+
37
+ ### Changed
38
+ - **Installation Documentation** - Updated README with dual installation options
39
+ - Primary: npm registry (recommended for most users)
40
+ - Alternative: GitHub Packages (for advanced users or npm fallback)
41
+ - Clear instructions for both installation methods
42
+
43
+ ### Technical Details
44
+ - **Editor Tracking**: Configuration saved after successful command installation
45
+ - **Post-Install Hook**: Runs only for global installations, skips for local/dev installs
46
+ - **Version Detection**: Compares current version with last installed version
47
+ - **Force Update**: Automatically updates commands when version changes
48
+ - **Parallel Publication**: npm and GitHub Packages jobs run simultaneously for faster releases
49
+
50
+ ## [0.4.2] - 2025-10-02
51
+
52
+ ### Fixed
53
+ - **Analyzer Compatibility** - Fixed ENOENT error when running `/p:init` in non-prjct projects
54
+ - Added validation to check if `bin/prjct` exists before reading
55
+ - Analyzer now works correctly in any project type (React, Vue, etc.)
56
+ - No longer throws "no such file or directory" error for normal projects
57
+ - Maintains full functionality for prjct-cli development projects
58
+
59
+ - **Website Build Process** - Improved build script and component imports
60
+ - Fixed Badge component import casing (badge → Badge)
61
+ - Removed obsolete install.sh and setup.sh copying from build script
62
+ - Cleaner and faster website builds
63
+
10
64
  ## [0.4.1] - 2025-10-01
11
65
 
12
66
  ### Added
package/README.md CHANGED
@@ -46,6 +46,8 @@ Each agent gets optimized output:
46
46
 
47
47
  ## ⚡ Installation
48
48
 
49
+ ### From npm (Recommended)
50
+
49
51
  Install prjct-cli globally using npm:
50
52
 
51
53
  ```bash
@@ -65,6 +67,16 @@ pnpm add -g prjct-cli
65
67
  bun install -g prjct-cli
66
68
  ```
67
69
 
70
+ ### From GitHub Packages
71
+
72
+ You can also install from GitHub Packages:
73
+
74
+ ```bash
75
+ npm install -g @jlopezlira/prjct-cli --registry=https://npm.pkg.github.com
76
+ ```
77
+
78
+ For easier installation from GitHub Packages, see [GitHub Packages Setup](docs/GITHUB_PACKAGES.md).
79
+
68
80
  **Requirements**: Node.js 18 or higher
69
81
 
70
82
  > **Note**: The CLI automatically detects updates and notifies you when a new version is available. Simply run `npm update -g prjct-cli` to upgrade.
package/core/analyzer.js CHANGED
@@ -48,11 +48,15 @@ class CodebaseAnalyzer {
48
48
 
49
49
  try {
50
50
  const binPath = path.join(this.projectPath, 'bin', 'prjct')
51
- const content = await fs.readFile(binPath, 'utf-8')
52
51
 
53
- const caseMatches = content.matchAll(/case\s+'([^']+)':/g)
54
- for (const match of caseMatches) {
55
- commands.push(match[1])
52
+ // Only try to read bin/prjct if it exists (for prjct-cli projects)
53
+ if (await this.fileExists(binPath)) {
54
+ const content = await fs.readFile(binPath, 'utf-8')
55
+
56
+ const caseMatches = content.matchAll(/case\s+'([^']+)':/g)
57
+ for (const match of caseMatches) {
58
+ commands.push(match[1])
59
+ }
56
60
  }
57
61
 
58
62
  const commandsPath = path.join(this.projectPath, 'core', 'commands.js')
@@ -403,6 +403,7 @@ For detailed implementation, see prjct-cli documentation.
403
403
 
404
404
  const results = {}
405
405
  const installedTo = []
406
+ const successfulEditors = []
406
407
 
407
408
  for (const editorKey of selectedEditors) {
408
409
  const editor = this.editors[editorKey]
@@ -426,6 +427,7 @@ For detailed implementation, see prjct-cli documentation.
426
427
  results[editorKey] = await this.installToEditor(editorKey, forceUpdate)
427
428
  if (results[editorKey].success) {
428
429
  installedTo.push(editor.name)
430
+ successfulEditors.push(editorKey)
429
431
  }
430
432
  }
431
433
 
@@ -442,6 +444,11 @@ For detailed implementation, see prjct-cli documentation.
442
444
  const totalUpdated = Object.values(results)
443
445
  .reduce((sum, r) => sum + (r.updated || 0), 0)
444
446
 
447
+ // Save editor selections to config (only on successful new installations, not updates)
448
+ if (!forceUpdate && successfulEditors.length > 0) {
449
+ await this.saveEditorConfig(successfulEditors)
450
+ }
451
+
445
452
  return {
446
453
  success: true,
447
454
  editors: installedTo,
@@ -667,6 +674,36 @@ This command uses the global prjct architecture:
667
674
  return lines.join('\n')
668
675
  }
669
676
 
677
+ /**
678
+ * Save editor configuration to track installed editors
679
+ * @param {string[]} editors - Array of successfully installed editor keys
680
+ * @returns {Promise<void>}
681
+ */
682
+ async saveEditorConfig(editors) {
683
+ try {
684
+ const editorsConfig = require('./editors-config')
685
+ const packageJson = require('../package.json')
686
+
687
+ // Build paths object
688
+ const paths = {}
689
+ for (const editorKey of editors) {
690
+ const editor = this.editors[editorKey]
691
+ if (editor) {
692
+ paths[editorKey] = editor.commandsPath
693
+ }
694
+ }
695
+
696
+ await editorsConfig.saveConfig(
697
+ editors,
698
+ paths,
699
+ packageJson.version,
700
+ )
701
+ } catch (error) {
702
+ // Don't fail installation if config save fails
703
+ console.error('[command-installer] Error saving editor config:', error.message)
704
+ }
705
+ }
706
+
670
707
  /**
671
708
  * Install Context7 MCP configuration for all detected editors
672
709
  * @returns {Promise<Object>} Installation results
@@ -0,0 +1,160 @@
1
+ const fs = require('fs').promises
2
+ const path = require('path')
3
+ const os = require('os')
4
+
5
+ /**
6
+ * EditorsConfig - Manages installed editors tracking configuration
7
+ *
8
+ * Tracks which AI editors user has installed prjct commands to,
9
+ * enabling automatic updates when npm package is updated.
10
+ *
11
+ * Config location: ~/.prjct-cli/config/installed-editors.json
12
+ *
13
+ * @version 0.4.2
14
+ */
15
+ class EditorsConfig {
16
+ constructor() {
17
+ this.homeDir = os.homedir()
18
+ this.configDir = path.join(this.homeDir, '.prjct-cli', 'config')
19
+ this.configFile = path.join(this.configDir, 'installed-editors.json')
20
+ }
21
+
22
+ /**
23
+ * Ensure config directory exists
24
+ */
25
+ async ensureConfigDir() {
26
+ try {
27
+ await fs.mkdir(this.configDir, { recursive: true })
28
+ } catch (error) {
29
+ console.error('[editors-config] Error creating config directory:', error.message)
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Load installed editors configuration
35
+ * @returns {Promise<Object|null>} Configuration object or null if not found
36
+ */
37
+ async loadConfig() {
38
+ try {
39
+ const content = await fs.readFile(this.configFile, 'utf-8')
40
+ return JSON.parse(content)
41
+ } catch (error) {
42
+ if (error.code === 'ENOENT') {
43
+ return null
44
+ }
45
+ console.error('[editors-config] Error loading config:', error.message)
46
+ return null
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Save installed editors configuration
52
+ * @param {string[]} editors - Array of editor keys (e.g., ['claude', 'cursor'])
53
+ * @param {Object} paths - Object mapping editor keys to installation paths
54
+ * @param {string} version - Current prjct-cli version
55
+ * @returns {Promise<boolean>} Success status
56
+ */
57
+ async saveConfig(editors, paths, version) {
58
+ try {
59
+ await this.ensureConfigDir()
60
+
61
+ const config = {
62
+ version,
63
+ editors,
64
+ lastInstall: new Date().toISOString(),
65
+ paths,
66
+ }
67
+
68
+ await fs.writeFile(
69
+ this.configFile,
70
+ JSON.stringify(config, null, 2),
71
+ 'utf-8',
72
+ )
73
+
74
+ return true
75
+ } catch (error) {
76
+ console.error('[editors-config] Error saving config:', error.message)
77
+ return false
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Get tracked editors from configuration
83
+ * @returns {Promise<string[]>} Array of editor keys
84
+ */
85
+ async getTrackedEditors() {
86
+ const config = await this.loadConfig()
87
+ return config ? config.editors : []
88
+ }
89
+
90
+ /**
91
+ * Get editor paths from configuration
92
+ * @returns {Promise<Object>} Object mapping editor keys to paths
93
+ */
94
+ async getEditorPaths() {
95
+ const config = await this.loadConfig()
96
+ return config ? config.paths : {}
97
+ }
98
+
99
+ /**
100
+ * Get last installed version
101
+ * @returns {Promise<string|null>} Version string or null
102
+ */
103
+ async getLastVersion() {
104
+ const config = await this.loadConfig()
105
+ return config ? config.version : null
106
+ }
107
+
108
+ /**
109
+ * Check if version has changed since last install
110
+ * @param {string} currentVersion - Current version to compare
111
+ * @returns {Promise<boolean>} True if version has changed
112
+ */
113
+ async hasVersionChanged(currentVersion) {
114
+ const lastVersion = await this.getLastVersion()
115
+ return lastVersion !== null && lastVersion !== currentVersion
116
+ }
117
+
118
+ /**
119
+ * Update version in configuration
120
+ * @param {string} version - New version to save
121
+ * @returns {Promise<boolean>} Success status
122
+ */
123
+ async updateVersion(version) {
124
+ try {
125
+ const config = await this.loadConfig()
126
+ if (!config) {
127
+ return false
128
+ }
129
+
130
+ config.version = version
131
+ config.lastInstall = new Date().toISOString()
132
+
133
+ await fs.writeFile(
134
+ this.configFile,
135
+ JSON.stringify(config, null, 2),
136
+ 'utf-8',
137
+ )
138
+
139
+ return true
140
+ } catch (error) {
141
+ console.error('[editors-config] Error updating version:', error.message)
142
+ return false
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Check if config file exists
148
+ * @returns {Promise<boolean>} True if config exists
149
+ */
150
+ async configExists() {
151
+ try {
152
+ await fs.access(this.configFile)
153
+ return true
154
+ } catch {
155
+ return false
156
+ }
157
+ }
158
+ }
159
+
160
+ module.exports = new EditorsConfig()
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "AI-integrated project management for indie hackers - works with Claude Code, Cursor, and Warp",
5
5
  "main": "core/index.js",
6
6
  "bin": {
7
7
  "prjct": "./bin/prjct"
8
8
  },
9
9
  "publishConfig": {
10
- "access": "public"
10
+ "access": "public",
11
+ "registry": "https://registry.npmjs.org"
11
12
  },
12
13
  "scripts": {
14
+ "postinstall": "node scripts/post-install.js",
13
15
  "install-global": "./scripts/install.sh",
14
16
  "test": "echo 'No tests configured'",
15
17
  "lint": "eslint \"**/*.js\" --ignore-pattern \"node_modules/**\" --ignore-pattern \"website/**\"",
@@ -66,6 +68,7 @@
66
68
  "templates/",
67
69
  "scripts/install.sh",
68
70
  "scripts/verify-installation.sh",
71
+ "scripts/post-install.js",
69
72
  "LICENSE",
70
73
  "README.md",
71
74
  "CHANGELOG.md",
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Post-Install Script
5
+ *
6
+ * Runs automatically after `npm install -g prjct-cli` or `npm update -g prjct-cli`.
7
+ * Auto-updates slash commands in all previously configured editors.
8
+ *
9
+ * Flow:
10
+ * 1. Check if running as global install
11
+ * 2. Read tracked editors from ~/.prjct-cli/config/installed-editors.json
12
+ * 3. If config exists and version changed, force-update commands in tracked editors
13
+ * 4. Update version in config
14
+ *
15
+ * @version 0.4.2
16
+ */
17
+
18
+ const path = require('path')
19
+ const chalk = require('chalk')
20
+ const { execSync } = require('child_process')
21
+
22
+ async function main() {
23
+ try {
24
+ // Check if this is a global installation
25
+ const isGlobal = await checkIfGlobalInstall()
26
+
27
+ if (!isGlobal) {
28
+ // Skip post-install for local/dev installations
29
+ return
30
+ }
31
+
32
+ // Load editors config
33
+ const editorsConfig = require('../core/editors-config')
34
+ const configExists = await editorsConfig.configExists()
35
+
36
+ if (!configExists) {
37
+ // First-time install, no editors tracked yet
38
+ // User will configure editors during `prjct init` or `prjct install`
39
+ return
40
+ }
41
+
42
+ // Get current package version
43
+ const packageJson = require('../package.json')
44
+ const currentVersion = packageJson.version
45
+
46
+ // Check if version has changed
47
+ const versionChanged = await editorsConfig.hasVersionChanged(currentVersion)
48
+
49
+ if (!versionChanged) {
50
+ // Same version, no update needed
51
+ return
52
+ }
53
+
54
+ // Get tracked editors and paths
55
+ const trackedEditors = await editorsConfig.getTrackedEditors()
56
+ const editorPaths = await editorsConfig.getEditorPaths()
57
+
58
+ if (trackedEditors.length === 0) {
59
+ // No editors tracked yet
60
+ return
61
+ }
62
+
63
+ console.log(chalk.cyan('\n🔄 Updating prjct commands in configured editors...\n'))
64
+
65
+ // Load command installer
66
+ const commandInstaller = require('../core/command-installer')
67
+
68
+ // Force-update commands in all tracked editors
69
+ const results = await commandInstaller.installToSelected(trackedEditors, true)
70
+
71
+ if (results.success) {
72
+ console.log(chalk.green(`✅ Updated commands in: ${results.editors.join(', ')}`))
73
+ console.log(chalk.gray(` Commands updated: ${results.totalUpdated}`))
74
+ } else {
75
+ console.log(chalk.yellow('⚠️ Some editors could not be updated'))
76
+ }
77
+
78
+ // Update version in config
79
+ await editorsConfig.updateVersion(currentVersion)
80
+
81
+ console.log(chalk.cyan(`\n✨ prjct-cli ${currentVersion} is ready!\n`))
82
+
83
+ } catch (error) {
84
+ // Silently fail - don't block npm install
85
+ // Only log if explicitly debugging
86
+ if (process.env.DEBUG) {
87
+ console.error(chalk.red('[post-install] Error:'), error.message)
88
+ }
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Check if package is being installed globally
94
+ * @returns {Promise<boolean>} True if global install
95
+ */
96
+ async function checkIfGlobalInstall() {
97
+ try {
98
+ // Get npm global root directory
99
+ const globalRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim()
100
+
101
+ // Get current package directory
102
+ const currentDir = path.resolve(__dirname, '..')
103
+
104
+ // Check if current directory is under global node_modules
105
+ return currentDir.startsWith(globalRoot)
106
+ } catch {
107
+ return false
108
+ }
109
+ }
110
+
111
+ // Run main function
112
+ main().catch(error => {
113
+ // Silently fail - don't block npm install
114
+ if (process.env.DEBUG) {
115
+ console.error('[post-install] Fatal error:', error)
116
+ }
117
+ process.exit(0) // Exit with success to not block npm install
118
+ })