prjct-cli 0.4.0 → 0.4.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,65 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.2] - 2025-10-02
11
+
12
+ ### Fixed
13
+ - **Analyzer Compatibility** - Fixed ENOENT error when running `/p:init` in non-prjct projects
14
+ - Added validation to check if `bin/prjct` exists before reading
15
+ - Analyzer now works correctly in any project type (React, Vue, etc.)
16
+ - No longer throws "no such file or directory" error for normal projects
17
+ - Maintains full functionality for prjct-cli development projects
18
+
19
+ - **Website Build Process** - Improved build script and component imports
20
+ - Fixed Badge component import casing (badge → Badge)
21
+ - Removed obsolete install.sh and setup.sh copying from build script
22
+ - Cleaner and faster website builds
23
+
24
+ ### Coming Soon
25
+ - **Windows Compatibility** - Native Windows support
26
+ - PowerShell and CMD command execution
27
+ - Windows path handling (`%USERPROFILE%\.prjct-cli\`)
28
+ - Windows-specific installation scripts
29
+ - Cross-platform file operations
30
+ - Windows Terminal integration
31
+
32
+ ## [0.4.1] - 2025-10-01
33
+
34
+ ### Added
35
+ - **Automatic Update Detection** - Built-in update checker that notifies users of new versions
36
+ - Checks npm registry every 24 hours for new versions
37
+ - Non-blocking background check during command execution
38
+ - Formatted notification with update command
39
+ - Shows only once per session to avoid notification spam
40
+ - Respects 24-hour cache to minimize npm registry requests
41
+
42
+ - **Automated npm Publication** - GitHub Actions workflow for automatic npm publishing
43
+ - Triggered on version tags (v*)
44
+ - Automatic version verification against package.json
45
+ - Provenance publishing with npm attestation
46
+ - Post-publication verification
47
+ - Publication summary in GitHub Actions
48
+
49
+ ### Changed
50
+ - **Installation Method** - npm is now the primary and recommended installation method
51
+ - Simplified to single installation method: `npm install -g prjct-cli`
52
+ - Removed Homebrew and Bun installation scripts
53
+ - Cleaner package with optimized file inclusion
54
+ - Reduced package size: 104.6 KB (71 files)
55
+
56
+ ### Fixed
57
+ - **Package Structure** - Improved npm package configuration
58
+ - Added `files` field to control package contents
59
+ - Created `.npmignore` for development file exclusion
60
+ - Proper global data directory separation (`~/.prjct-cli/` for data only)
61
+ - Fixed CI/CD tests to verify CLI functionality instead of individual modules
62
+
63
+ ### Technical Details
64
+ - **Update Checker**: `core/update-checker.js` with semantic version comparison
65
+ - **Cache Management**: Update checks cached for 24 hours in `~/.prjct-cli/config/update-cache.json`
66
+ - **Architecture**: Clean separation between npm installation (`/opt/homebrew/lib/node_modules/prjct-cli/`) and user data (`~/.prjct-cli/`)
67
+ - **GitHub Actions**: `.github/workflows/publish-npm.yml` for automated npm publication
68
+
10
69
  ## [0.4.0] - 2025-10-01
11
70
 
12
71
  ### Added
package/README.md CHANGED
@@ -46,41 +46,28 @@ Each agent gets optimized output:
46
46
 
47
47
  ## ⚡ Installation
48
48
 
49
- Choose the installation method that works best for you:
50
-
51
- ### npm/Node.js
49
+ Install prjct-cli globally using npm:
52
50
 
53
51
  ```bash
54
- npm install -g @prjct/cli
52
+ npm install -g prjct-cli
55
53
  ```
56
54
 
57
- **Benefits**: Standard npm ecosystem, works everywhere Node.js runs.
58
-
59
- ### Quick Install Script (Cross-platform)
55
+ **Alternative package managers**:
60
56
 
61
57
  ```bash
62
- curl -fsSL https://prjct.app/install.sh | bash
63
- ```
58
+ # Using yarn
59
+ yarn global add prjct-cli
64
60
 
65
- **Benefits**: Works on any Unix-like system, automatic platform detection.
61
+ # Using pnpm
62
+ pnpm add -g prjct-cli
66
63
 
67
- #### Installation Options
68
-
69
- ```bash
70
- # Force reinstall (even if up to date)
71
- curl -fsSL https://prjct.app/install.sh | bash -s -- --force
72
-
73
- # Auto-accept all prompts (unattended installation)
74
- curl -fsSL https://prjct.app/install.sh | bash -s -- -y
75
-
76
- # Install from development branch
77
- curl -fsSL https://prjct.app/install.sh | bash -s -- --dev
78
-
79
- # Show help
80
- curl -fsSL https://prjct.app/install.sh | bash -s -- --help
64
+ # Using bun
65
+ bun install -g prjct-cli
81
66
  ```
82
67
 
83
- > **Note**: For detailed installation instructions, troubleshooting, and platform-specific guidance, see [INSTALL.md](docs/INSTALL.md).
68
+ **Requirements**: Node.js 18 or higher
69
+
70
+ > **Note**: The CLI automatically detects updates and notifies you when a new version is available. Simply run `npm update -g prjct-cli` to upgrade.
84
71
 
85
72
  ### Editor Command Installation
86
73
 
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')
package/core/commands.js CHANGED
@@ -11,6 +11,7 @@ const migrator = require('./migrator')
11
11
  const commandInstaller = require('./command-installer')
12
12
  const sessionManager = require('./session-manager')
13
13
  const analyzer = require('./analyzer')
14
+ const UpdateChecker = require('./update-checker')
14
15
  const { VERSION } = require('./version')
15
16
 
16
17
  let animations
@@ -34,6 +35,28 @@ class PrjctCommands {
34
35
  this.agentInfo = null
35
36
  this.currentAuthor = null
36
37
  this.prjctDir = '.prjct'
38
+ this.updateChecker = new UpdateChecker()
39
+ this.updateNotificationShown = false
40
+ }
41
+
42
+ /**
43
+ * Check for updates and show notification (non-blocking)
44
+ * Only shows once per session
45
+ */
46
+ async checkAndNotifyUpdates() {
47
+ if (this.updateNotificationShown) {
48
+ return
49
+ }
50
+
51
+ try {
52
+ const notification = await this.updateChecker.getUpdateNotification()
53
+ if (notification) {
54
+ console.log(notification)
55
+ this.updateNotificationShown = true
56
+ }
57
+ } catch (error) {
58
+ // Fail silently - don't interrupt user workflow
59
+ }
37
60
  }
38
61
 
39
62
  /**
@@ -171,6 +194,11 @@ class PrjctCommands {
171
194
 
172
195
  await this.checkAndRunAutoMigration()
173
196
 
197
+ // Check for updates in background (non-blocking)
198
+ this.checkAndNotifyUpdates().catch(() => {
199
+ // Fail silently - don't interrupt workflow
200
+ })
201
+
174
202
  return this.agent
175
203
  }
176
204
 
@@ -0,0 +1,222 @@
1
+ const https = require('https');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ class UpdateChecker {
7
+ constructor() {
8
+ this.packageName = 'prjct-cli';
9
+ this.cacheDir = path.join(os.homedir(), '.prjct-cli', 'config');
10
+ this.cacheFile = path.join(this.cacheDir, 'update-cache.json');
11
+ this.checkInterval = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
12
+ }
13
+
14
+ /**
15
+ * Get current installed version from package.json
16
+ */
17
+ getCurrentVersion() {
18
+ try {
19
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
20
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
21
+ return packageJson.version;
22
+ } catch (error) {
23
+ console.error('Error reading package version:', error.message);
24
+ return null;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Fetch latest version from npm registry
30
+ */
31
+ async getLatestVersion() {
32
+ return new Promise((resolve, reject) => {
33
+ const options = {
34
+ hostname: 'registry.npmjs.org',
35
+ path: `/${this.packageName}/latest`,
36
+ method: 'GET',
37
+ headers: {
38
+ 'User-Agent': 'prjct-cli-update-checker',
39
+ Accept: 'application/json'
40
+ }
41
+ };
42
+
43
+ const req = https.request(options, res => {
44
+ let data = '';
45
+
46
+ res.on('data', chunk => {
47
+ data += chunk;
48
+ });
49
+
50
+ res.on('end', () => {
51
+ try {
52
+ if (res.statusCode === 200) {
53
+ const packageData = JSON.parse(data);
54
+ resolve(packageData.version);
55
+ } else {
56
+ reject(new Error(`npm registry returned status ${res.statusCode}`));
57
+ }
58
+ } catch (error) {
59
+ reject(error);
60
+ }
61
+ });
62
+ });
63
+
64
+ req.on('error', error => {
65
+ reject(error);
66
+ });
67
+
68
+ req.setTimeout(5000, () => {
69
+ req.destroy();
70
+ reject(new Error('Request timeout'));
71
+ });
72
+
73
+ req.end();
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Compare two semantic versions
79
+ * Returns: 1 if v1 > v2, -1 if v1 < v2, 0 if equal
80
+ */
81
+ compareVersions(v1, v2) {
82
+ const parts1 = v1.split('.').map(Number);
83
+ const parts2 = v2.split('.').map(Number);
84
+
85
+ for (let i = 0; i < 3; i++) {
86
+ const part1 = parts1[i] || 0;
87
+ const part2 = parts2[i] || 0;
88
+
89
+ if (part1 > part2) return 1;
90
+ if (part1 < part2) return -1;
91
+ }
92
+
93
+ return 0;
94
+ }
95
+
96
+ /**
97
+ * Read cache file
98
+ */
99
+ readCache() {
100
+ try {
101
+ if (fs.existsSync(this.cacheFile)) {
102
+ const cache = JSON.parse(fs.readFileSync(this.cacheFile, 'utf8'));
103
+ return cache;
104
+ }
105
+ } catch (error) {
106
+ // Cache file doesn't exist or is corrupted, ignore
107
+ }
108
+ return null;
109
+ }
110
+
111
+ /**
112
+ * Write cache file
113
+ */
114
+ writeCache(data) {
115
+ try {
116
+ // Ensure cache directory exists
117
+ if (!fs.existsSync(this.cacheDir)) {
118
+ fs.mkdirSync(this.cacheDir, { recursive: true });
119
+ }
120
+
121
+ fs.writeFileSync(this.cacheFile, JSON.stringify(data, null, 2), 'utf8');
122
+ } catch (error) {
123
+ // Fail silently - cache is not critical
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Check if update is available (respects 24-hour cache)
129
+ * Returns: { updateAvailable: boolean, currentVersion: string, latestVersion: string } or null
130
+ */
131
+ async checkForUpdates() {
132
+ try {
133
+ const currentVersion = this.getCurrentVersion();
134
+ if (!currentVersion) {
135
+ return null;
136
+ }
137
+
138
+ // Check cache first
139
+ const cache = this.readCache();
140
+ const now = Date.now();
141
+
142
+ if (cache && cache.lastCheck && now - cache.lastCheck < this.checkInterval) {
143
+ // Cache is still valid
144
+ if (cache.latestVersion && this.compareVersions(cache.latestVersion, currentVersion) > 0) {
145
+ return {
146
+ updateAvailable: true,
147
+ currentVersion,
148
+ latestVersion: cache.latestVersion
149
+ };
150
+ }
151
+ return {
152
+ updateAvailable: false,
153
+ currentVersion,
154
+ latestVersion: currentVersion
155
+ };
156
+ }
157
+
158
+ // Cache expired or doesn't exist, fetch from npm
159
+ const latestVersion = await this.getLatestVersion();
160
+
161
+ // Update cache
162
+ this.writeCache({
163
+ lastCheck: now,
164
+ latestVersion
165
+ });
166
+
167
+ // Compare versions
168
+ const updateAvailable = this.compareVersions(latestVersion, currentVersion) > 0;
169
+
170
+ return {
171
+ updateAvailable,
172
+ currentVersion,
173
+ latestVersion
174
+ };
175
+ } catch (error) {
176
+ // Network error or other issue - fail silently
177
+ // Return null to indicate check couldn't be performed
178
+ return null;
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Get formatted update notification message
184
+ */
185
+ async getUpdateNotification() {
186
+ const result = await this.checkForUpdates();
187
+
188
+ if (!result || !result.updateAvailable) {
189
+ return null;
190
+ }
191
+
192
+ const chalk = require('chalk');
193
+
194
+ return (
195
+ '\n' +
196
+ chalk.yellow('┌───────────────────────────────────────────────────────────┐') +
197
+ '\n' +
198
+ chalk.yellow('│') +
199
+ ' ' +
200
+ chalk.bold('Update available!') +
201
+ ' ' +
202
+ chalk.dim(`${result.currentVersion} → ${result.latestVersion}`) +
203
+ ' ' +
204
+ chalk.yellow('│') +
205
+ '\n' +
206
+ chalk.yellow('│') +
207
+ ' ' +
208
+ chalk.yellow('│') +
209
+ '\n' +
210
+ chalk.yellow('│') +
211
+ ' Run: ' +
212
+ chalk.cyan('npm update -g prjct-cli') +
213
+ ' ' +
214
+ chalk.yellow('│') +
215
+ '\n' +
216
+ chalk.yellow('└───────────────────────────────────────────────────────────┘') +
217
+ '\n'
218
+ );
219
+ }
220
+ }
221
+
222
+ module.exports = UpdateChecker;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
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": {