prjct-cli 0.4.0 → 0.4.1

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,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.1] - 2025-10-01
11
+
12
+ ### Added
13
+ - **Automatic Update Detection** - Built-in update checker that notifies users of new versions
14
+ - Checks npm registry every 24 hours for new versions
15
+ - Non-blocking background check during command execution
16
+ - Formatted notification with update command
17
+ - Shows only once per session to avoid notification spam
18
+ - Respects 24-hour cache to minimize npm registry requests
19
+
20
+ - **Automated npm Publication** - GitHub Actions workflow for automatic npm publishing
21
+ - Triggered on version tags (v*)
22
+ - Automatic version verification against package.json
23
+ - Provenance publishing with npm attestation
24
+ - Post-publication verification
25
+ - Publication summary in GitHub Actions
26
+
27
+ ### Changed
28
+ - **Installation Method** - npm is now the primary and recommended installation method
29
+ - Simplified to single installation method: `npm install -g prjct-cli`
30
+ - Removed Homebrew and Bun installation scripts
31
+ - Cleaner package with optimized file inclusion
32
+ - Reduced package size: 104.6 KB (71 files)
33
+
34
+ ### Fixed
35
+ - **Package Structure** - Improved npm package configuration
36
+ - Added `files` field to control package contents
37
+ - Created `.npmignore` for development file exclusion
38
+ - Proper global data directory separation (`~/.prjct-cli/` for data only)
39
+ - Fixed CI/CD tests to verify CLI functionality instead of individual modules
40
+
41
+ ### Technical Details
42
+ - **Update Checker**: `core/update-checker.js` with semantic version comparison
43
+ - **Cache Management**: Update checks cached for 24 hours in `~/.prjct-cli/config/update-cache.json`
44
+ - **Architecture**: Clean separation between npm installation (`/opt/homebrew/lib/node_modules/prjct-cli/`) and user data (`~/.prjct-cli/`)
45
+ - **GitHub Actions**: `.github/workflows/publish-npm.yml` for automated npm publication
46
+
10
47
  ## [0.4.0] - 2025-10-01
11
48
 
12
49
  ### 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/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.1",
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": {