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 +37 -0
- package/README.md +12 -25
- package/core/commands.js +28 -0
- package/core/update-checker.js +222 -0
- package/package.json +1 -1
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
|
-
|
|
50
|
-
|
|
51
|
-
### npm/Node.js
|
|
49
|
+
Install prjct-cli globally using npm:
|
|
52
50
|
|
|
53
51
|
```bash
|
|
54
|
-
npm install -g
|
|
52
|
+
npm install -g prjct-cli
|
|
55
53
|
```
|
|
56
54
|
|
|
57
|
-
**
|
|
58
|
-
|
|
59
|
-
### Quick Install Script (Cross-platform)
|
|
55
|
+
**Alternative package managers**:
|
|
60
56
|
|
|
61
57
|
```bash
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
# Using yarn
|
|
59
|
+
yarn global add prjct-cli
|
|
64
60
|
|
|
65
|
-
|
|
61
|
+
# Using pnpm
|
|
62
|
+
pnpm add -g prjct-cli
|
|
66
63
|
|
|
67
|
-
|
|
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
|
-
|
|
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;
|