zuppaclaude 1.3.2 → 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.
- package/bin/zuppaclaude.js +71 -0
- package/lib/components/cloud.js +122 -0
- package/lib/components/index.js +3 -1
- package/lib/components/updater.js +216 -0
- package/lib/installer.js +15 -0
- package/package.json +1 -1
package/bin/zuppaclaude.js
CHANGED
|
@@ -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();
|
package/lib/components/cloud.js
CHANGED
|
@@ -4,15 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
|
+
const { execSync, spawn } = require('child_process');
|
|
7
8
|
const { Logger } = require('../utils/logger');
|
|
8
9
|
const { Platform } = require('../utils/platform');
|
|
10
|
+
const { Prompts } = require('../utils/prompts');
|
|
9
11
|
|
|
10
12
|
class CloudManager {
|
|
11
13
|
constructor() {
|
|
12
14
|
this.platform = new Platform();
|
|
13
15
|
this.logger = new Logger();
|
|
16
|
+
this.prompts = new Prompts();
|
|
14
17
|
this.backupDir = path.join(this.platform.zuppaconfigDir, 'backups');
|
|
15
18
|
this.cloudPath = 'zuppaclaude-backups';
|
|
19
|
+
|
|
20
|
+
// Supported providers
|
|
21
|
+
this.providers = [
|
|
22
|
+
{ name: 'Google Drive', type: 'drive', remoteName: 'gdrive' },
|
|
23
|
+
{ name: 'Dropbox', type: 'dropbox', remoteName: 'dropbox' },
|
|
24
|
+
{ name: 'OneDrive', type: 'onedrive', remoteName: 'onedrive' },
|
|
25
|
+
{ name: 'Amazon S3', type: 's3', remoteName: 's3' },
|
|
26
|
+
{ name: 'SFTP', type: 'sftp', remoteName: 'sftp' },
|
|
27
|
+
{ name: 'Skip (configure later)', type: null, remoteName: null }
|
|
28
|
+
];
|
|
16
29
|
}
|
|
17
30
|
|
|
18
31
|
/**
|
|
@@ -76,6 +89,115 @@ class CloudManager {
|
|
|
76
89
|
}
|
|
77
90
|
}
|
|
78
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Configure a cloud provider
|
|
94
|
+
*/
|
|
95
|
+
async configureProvider() {
|
|
96
|
+
if (!this.isRcloneInstalled()) {
|
|
97
|
+
this.logger.error('rclone is not installed');
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log('\x1b[35m═══════════════════════════════════════════════════════════════════\x1b[0m');
|
|
103
|
+
console.log('\x1b[35m Cloud Provider Setup\x1b[0m');
|
|
104
|
+
console.log('\x1b[35m═══════════════════════════════════════════════════════════════════\x1b[0m');
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
// Show provider options
|
|
108
|
+
const providerNames = this.providers.map(p => p.name);
|
|
109
|
+
const selectedIndex = await this.prompts.select('Select a cloud provider:', providerNames);
|
|
110
|
+
const provider = this.providers[selectedIndex];
|
|
111
|
+
|
|
112
|
+
if (!provider.type) {
|
|
113
|
+
this.logger.info('Skipping cloud provider configuration');
|
|
114
|
+
this.logger.info('Run "rclone config" later to set up manually');
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log('');
|
|
119
|
+
this.logger.step(`Configuring ${provider.name}...`);
|
|
120
|
+
|
|
121
|
+
// Check if remote already exists
|
|
122
|
+
const existingRemotes = this.getRemotes();
|
|
123
|
+
if (existingRemotes.includes(provider.remoteName)) {
|
|
124
|
+
this.logger.warning(`Remote "${provider.remoteName}" already exists`);
|
|
125
|
+
const overwrite = await this.prompts.confirm('Overwrite existing configuration?', false);
|
|
126
|
+
if (!overwrite) {
|
|
127
|
+
return provider.remoteName;
|
|
128
|
+
}
|
|
129
|
+
// Delete existing remote
|
|
130
|
+
try {
|
|
131
|
+
this.platform.exec(`rclone config delete ${provider.remoteName}`, { silent: true });
|
|
132
|
+
} catch (e) {
|
|
133
|
+
// Ignore
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Run rclone config create
|
|
138
|
+
try {
|
|
139
|
+
await this.runProviderAuth(provider);
|
|
140
|
+
|
|
141
|
+
// Verify configuration
|
|
142
|
+
if (this.getRemotes().includes(provider.remoteName)) {
|
|
143
|
+
this.logger.success(`${provider.name} configured successfully`);
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log(' Backup path: \x1b[36m' + provider.remoteName + ':zuppaclaude-backups/\x1b[0m');
|
|
146
|
+
console.log(' ├── sessions/');
|
|
147
|
+
console.log(' └── settings/');
|
|
148
|
+
console.log('');
|
|
149
|
+
return provider.remoteName;
|
|
150
|
+
} else {
|
|
151
|
+
this.logger.error('Configuration failed');
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
this.logger.error(`Failed to configure ${provider.name}: ${error.message}`);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Run provider-specific authentication
|
|
162
|
+
*/
|
|
163
|
+
async runProviderAuth(provider) {
|
|
164
|
+
return new Promise((resolve, reject) => {
|
|
165
|
+
console.log('');
|
|
166
|
+
|
|
167
|
+
if (provider.type === 'drive' || provider.type === 'dropbox' || provider.type === 'onedrive') {
|
|
168
|
+
// OAuth providers - need browser auth
|
|
169
|
+
this.logger.info('A browser window will open for authentication...');
|
|
170
|
+
this.logger.info('Please authorize ZuppaClaude to access your ' + provider.name);
|
|
171
|
+
console.log('');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Use spawn for interactive rclone config
|
|
175
|
+
const args = ['config', 'create', provider.remoteName, provider.type];
|
|
176
|
+
|
|
177
|
+
// Add provider-specific defaults
|
|
178
|
+
if (provider.type === 'drive') {
|
|
179
|
+
args.push('scope', 'drive');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const rclone = spawn('rclone', args, {
|
|
183
|
+
stdio: 'inherit',
|
|
184
|
+
shell: true
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
rclone.on('close', (code) => {
|
|
188
|
+
if (code === 0) {
|
|
189
|
+
resolve();
|
|
190
|
+
} else {
|
|
191
|
+
reject(new Error(`rclone exited with code ${code}`));
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
rclone.on('error', (err) => {
|
|
196
|
+
reject(err);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
79
201
|
/**
|
|
80
202
|
* Verify rclone installation
|
|
81
203
|
*/
|
package/lib/components/index.js
CHANGED
|
@@ -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/lib/installer.js
CHANGED
|
@@ -130,6 +130,7 @@ class Installer {
|
|
|
130
130
|
this.logger.step('Step 7/9: Cloud Backup Setup (rclone)');
|
|
131
131
|
let installRclone = false;
|
|
132
132
|
let rcloneInstalled = this.cloud.isRcloneInstalled();
|
|
133
|
+
let configuredRemote = null;
|
|
133
134
|
|
|
134
135
|
if (rcloneInstalled) {
|
|
135
136
|
this.logger.success('rclone is already installed');
|
|
@@ -147,6 +148,19 @@ class Installer {
|
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
150
|
|
|
151
|
+
// Configure cloud provider if rclone is installed
|
|
152
|
+
if (rcloneInstalled) {
|
|
153
|
+
const existingRemotes = this.cloud.getRemotes();
|
|
154
|
+
if (existingRemotes.length === 0) {
|
|
155
|
+
const configureNow = await this.prompts.confirm('Configure a cloud provider now?', true);
|
|
156
|
+
if (configureNow) {
|
|
157
|
+
configuredRemote = await this.cloud.configureProvider();
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
this.logger.info(`Existing remotes: ${existingRemotes.join(', ')}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
150
164
|
// Step 8: Install ZuppaClaude Commands
|
|
151
165
|
this.logger.step('Step 8/9: Installing ZuppaClaude Slash Commands');
|
|
152
166
|
const cmdsInstalled = await this.commands.install();
|
|
@@ -170,6 +184,7 @@ class Installer {
|
|
|
170
184
|
claudeZ: installClaudeZ,
|
|
171
185
|
claudeHUD: installClaudeHUD,
|
|
172
186
|
rclone: rcloneInstalled,
|
|
187
|
+
cloudRemote: configuredRemote,
|
|
173
188
|
zaiApiKey: zaiApiKey ? this.settings.encodeApiKey(zaiApiKey) : null,
|
|
174
189
|
installedAt: new Date().toISOString(),
|
|
175
190
|
version: require('../package.json').version
|