zuppaclaude 1.3.3 → 1.3.4

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.
@@ -8,6 +8,7 @@
8
8
  const { Installer } = require('../lib/installer');
9
9
  const { Settings } = require('../lib/settings');
10
10
  const { Logger } = require('../lib/utils/logger');
11
+ const { UpdateManager } = require('../lib/components/updater');
11
12
 
12
13
  const args = process.argv.slice(2);
13
14
  const command = args[0] || 'install';
@@ -23,11 +24,26 @@ function getCloudArg(args) {
23
24
  return null;
24
25
  }
25
26
 
27
+ /**
28
+ * Check for updates at startup (non-blocking for some commands)
29
+ */
30
+ async function checkUpdates(skipCommands = ['version', 'v', '-v', '--version', 'help', 'h', '-h', '--help', 'update']) {
31
+ if (skipCommands.includes(command)) {
32
+ return;
33
+ }
34
+
35
+ const updater = new UpdateManager();
36
+ await updater.checkAndUpdate();
37
+ }
38
+
26
39
  async function main() {
27
40
  const logger = new Logger();
28
41
 
29
42
  logger.banner();
30
43
 
44
+ // Check for updates at startup
45
+ await checkUpdates();
46
+
31
47
  try {
32
48
  switch (command) {
33
49
  case 'install':
@@ -192,6 +208,37 @@ async function main() {
192
208
  }
193
209
  break;
194
210
 
211
+ case 'update':
212
+ const updateMgr = new UpdateManager();
213
+ const updateCmd = args[1] || 'check';
214
+
215
+ switch (updateCmd) {
216
+ case 'check':
217
+ await updateMgr.status();
218
+ break;
219
+ case 'now':
220
+ case 'install':
221
+ const result = await updateMgr.checkForUpdates();
222
+ if (result.hasUpdate) {
223
+ await updateMgr.update();
224
+ } else {
225
+ logger.success('You are already on the latest version');
226
+ }
227
+ break;
228
+ case 'enable':
229
+ case 'on':
230
+ updateMgr.enableAutoUpdate();
231
+ break;
232
+ case 'disable':
233
+ case 'off':
234
+ updateMgr.disableAutoUpdate();
235
+ break;
236
+ default:
237
+ logger.error(`Unknown update command: ${updateCmd}`);
238
+ showUpdateHelp();
239
+ }
240
+ break;
241
+
195
242
  case 'version':
196
243
  case 'v':
197
244
  case '-v':
@@ -233,6 +280,7 @@ Commands:
233
280
  settings, s Manage settings
234
281
  session Manage Claude Code sessions
235
282
  cloud Manage cloud remotes (rclone)
283
+ update Check for updates and manage auto-update
236
284
  version, v Show version
237
285
  help, h Show this help
238
286
 
@@ -249,6 +297,12 @@ Cloud Commands:
249
297
  cloud download <r> Download backups from remote
250
298
  cloud backups <r> List cloud backups
251
299
 
300
+ Update Commands:
301
+ update Check for updates
302
+ update now Update to latest version
303
+ update enable Enable auto-update (default)
304
+ update disable Disable auto-update
305
+
252
306
  Session Commands:
253
307
  session list List all sessions
254
308
  session backup Backup sessions only
@@ -262,6 +316,7 @@ Examples:
262
316
  npx zuppaclaude backup --cloud gdrive # Backup to Google Drive
263
317
  npx zuppaclaude restore 2026-01-05T12-00-00 # Restore from backup
264
318
  npx zuppaclaude cloud setup # Configure cloud
319
+ npx zuppaclaude update # Check for updates
265
320
  `);
266
321
  }
267
322
 
@@ -321,4 +376,20 @@ Supported providers (via rclone):
321
376
  `);
322
377
  }
323
378
 
379
+ function showUpdateHelp() {
380
+ console.log(`
381
+ Update Commands:
382
+ check Check for updates (default)
383
+ now Update to latest version immediately
384
+ enable Enable auto-update at startup
385
+ disable Disable auto-update
386
+
387
+ Examples:
388
+ zuppaclaude update # Check for updates
389
+ zuppaclaude update now # Update immediately
390
+ zuppaclaude update enable # Enable auto-update
391
+ zuppaclaude update disable # Disable auto-update
392
+ `);
393
+ }
394
+
324
395
  main();
@@ -11,6 +11,7 @@ const { SessionManager } = require('./session');
11
11
  const { CloudManager } = require('./cloud');
12
12
  const { BackupManager } = require('./backup');
13
13
  const { CommandsInstaller } = require('./commands');
14
+ const { UpdateManager } = require('./updater');
14
15
 
15
16
  module.exports = {
16
17
  SuperClaudeInstaller,
@@ -21,5 +22,6 @@ module.exports = {
21
22
  SessionManager,
22
23
  CloudManager,
23
24
  BackupManager,
24
- CommandsInstaller
25
+ CommandsInstaller,
26
+ UpdateManager
25
27
  };
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Auto-Update Manager
3
+ * Checks for updates and auto-updates if enabled
4
+ */
5
+
6
+ const { execSync } = require('child_process');
7
+ const https = require('https');
8
+ const { Logger } = require('../utils/logger');
9
+ const { Settings } = require('../settings');
10
+
11
+ class UpdateManager {
12
+ constructor() {
13
+ this.logger = new Logger();
14
+ this.settings = new Settings();
15
+ this.packageName = 'zuppaclaude';
16
+ this.currentVersion = require('../../package.json').version;
17
+ }
18
+
19
+ /**
20
+ * Get latest version from npm
21
+ */
22
+ async getLatestVersion() {
23
+ return new Promise((resolve, reject) => {
24
+ const url = `https://registry.npmjs.org/${this.packageName}/latest`;
25
+
26
+ https.get(url, (res) => {
27
+ let data = '';
28
+
29
+ res.on('data', (chunk) => {
30
+ data += chunk;
31
+ });
32
+
33
+ res.on('end', () => {
34
+ try {
35
+ const json = JSON.parse(data);
36
+ resolve(json.version);
37
+ } catch (e) {
38
+ reject(e);
39
+ }
40
+ });
41
+ }).on('error', (err) => {
42
+ reject(err);
43
+ });
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Compare versions (returns true if latest > current)
49
+ */
50
+ isNewerVersion(latest, current) {
51
+ const latestParts = latest.split('.').map(Number);
52
+ const currentParts = current.split('.').map(Number);
53
+
54
+ for (let i = 0; i < 3; i++) {
55
+ if (latestParts[i] > currentParts[i]) return true;
56
+ if (latestParts[i] < currentParts[i]) return false;
57
+ }
58
+ return false;
59
+ }
60
+
61
+ /**
62
+ * Check for updates
63
+ */
64
+ async checkForUpdates(silent = false) {
65
+ try {
66
+ const latestVersion = await this.getLatestVersion();
67
+ const hasUpdate = this.isNewerVersion(latestVersion, this.currentVersion);
68
+
69
+ if (hasUpdate && !silent) {
70
+ console.log('');
71
+ console.log('\x1b[33m╔═══════════════════════════════════════════════════════════════════╗\x1b[0m');
72
+ console.log('\x1b[33m║ Update Available! ║\x1b[0m');
73
+ console.log('\x1b[33m╚═══════════════════════════════════════════════════════════════════╝\x1b[0m');
74
+ console.log('');
75
+ console.log(` Current version: \x1b[31m${this.currentVersion}\x1b[0m`);
76
+ console.log(` Latest version: \x1b[32m${latestVersion}\x1b[0m`);
77
+ console.log('');
78
+ }
79
+
80
+ return {
81
+ hasUpdate,
82
+ currentVersion: this.currentVersion,
83
+ latestVersion
84
+ };
85
+ } catch (error) {
86
+ // Silently fail - don't interrupt user workflow
87
+ return {
88
+ hasUpdate: false,
89
+ currentVersion: this.currentVersion,
90
+ latestVersion: null,
91
+ error: error.message
92
+ };
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Update to latest version
98
+ */
99
+ async update() {
100
+ try {
101
+ this.logger.step('Updating ZuppaClaude...');
102
+
103
+ // Use npm to update globally
104
+ execSync(`npm install -g ${this.packageName}@latest`, {
105
+ stdio: 'inherit'
106
+ });
107
+
108
+ // Verify update
109
+ const newVersion = await this.getLatestVersion();
110
+ this.logger.success(`Updated to v${newVersion}`);
111
+
112
+ return true;
113
+ } catch (error) {
114
+ this.logger.error(`Update failed: ${error.message}`);
115
+ this.logger.info(`Manual update: npm install -g ${this.packageName}@latest`);
116
+ return false;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Check and auto-update if enabled
122
+ * Called at startup
123
+ */
124
+ async checkAndUpdate() {
125
+ const userSettings = this.settings.load() || {};
126
+ const autoUpdate = userSettings.autoUpdate !== false; // Default true
127
+
128
+ const result = await this.checkForUpdates(true);
129
+
130
+ if (result.hasUpdate) {
131
+ if (autoUpdate) {
132
+ console.log('');
133
+ console.log(`\x1b[36m[i]\x1b[0m New version available: v${result.latestVersion}`);
134
+ console.log('\x1b[36m[i]\x1b[0m Auto-updating...');
135
+ console.log('');
136
+
137
+ const updated = await this.update();
138
+
139
+ if (updated) {
140
+ console.log('');
141
+ console.log('\x1b[32m[✓]\x1b[0m Update complete! Please restart to use the new version.');
142
+ console.log('');
143
+ return { updated: true, version: result.latestVersion };
144
+ }
145
+ } else {
146
+ // Just notify
147
+ console.log('');
148
+ console.log(`\x1b[33m[!]\x1b[0m Update available: v${this.currentVersion} → v${result.latestVersion}`);
149
+ console.log(`\x1b[33m[!]\x1b[0m Run: npm install -g ${this.packageName}@latest`);
150
+ console.log('');
151
+ return { updated: false, version: result.latestVersion };
152
+ }
153
+ }
154
+
155
+ return { updated: false, version: this.currentVersion };
156
+ }
157
+
158
+ /**
159
+ * Enable auto-update
160
+ */
161
+ enableAutoUpdate() {
162
+ const userSettings = this.settings.load() || {};
163
+ userSettings.autoUpdate = true;
164
+ this.settings.save(userSettings);
165
+ this.logger.success('Auto-update enabled');
166
+ }
167
+
168
+ /**
169
+ * Disable auto-update
170
+ */
171
+ disableAutoUpdate() {
172
+ const userSettings = this.settings.load() || {};
173
+ userSettings.autoUpdate = false;
174
+ this.settings.save(userSettings);
175
+ this.logger.success('Auto-update disabled');
176
+ }
177
+
178
+ /**
179
+ * Show update status
180
+ */
181
+ async status() {
182
+ const userSettings = this.settings.load() || {};
183
+ const autoUpdate = userSettings.autoUpdate !== false;
184
+
185
+ console.log('');
186
+ console.log('\x1b[35m═══════════════════════════════════════════════════════════════════\x1b[0m');
187
+ console.log('\x1b[35m Update Status\x1b[0m');
188
+ console.log('\x1b[35m═══════════════════════════════════════════════════════════════════\x1b[0m');
189
+ console.log('');
190
+ console.log(` Current version: \x1b[36m${this.currentVersion}\x1b[0m`);
191
+ console.log(` Auto-update: ${autoUpdate ? '\x1b[32menabled\x1b[0m' : '\x1b[31mdisabled\x1b[0m'}`);
192
+ console.log('');
193
+
194
+ this.logger.info('Checking for updates...');
195
+ const result = await this.checkForUpdates(true);
196
+
197
+ if (result.latestVersion) {
198
+ console.log(` Latest version: \x1b[36m${result.latestVersion}\x1b[0m`);
199
+
200
+ if (result.hasUpdate) {
201
+ console.log('');
202
+ console.log(' \x1b[33mUpdate available!\x1b[0m');
203
+ console.log(` Run: \x1b[36mnpm install -g ${this.packageName}@latest\x1b[0m`);
204
+ } else {
205
+ console.log('');
206
+ console.log(' \x1b[32mYou are up to date!\x1b[0m');
207
+ }
208
+ } else {
209
+ console.log(' \x1b[31mCould not check for updates\x1b[0m');
210
+ }
211
+
212
+ console.log('');
213
+ }
214
+ }
215
+
216
+ module.exports = { UpdateManager };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuppaclaude",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "Claude Code power-up installer - SuperClaude + Spec Kit + Claude-Z + Claude HUD",
5
5
  "main": "lib/index.js",
6
6
  "bin": {