pal-explorer-cli 0.4.11 → 0.4.13

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.
Files changed (99) hide show
  1. package/README.md +149 -149
  2. package/bin/pal.js +63 -2
  3. package/extensions/@palexplorer/analytics/extension.json +20 -1
  4. package/extensions/@palexplorer/analytics/index.js +19 -9
  5. package/extensions/@palexplorer/audit/extension.json +14 -0
  6. package/extensions/@palexplorer/auth-email/extension.json +15 -0
  7. package/extensions/@palexplorer/auth-oauth/extension.json +15 -0
  8. package/extensions/@palexplorer/chat/extension.json +14 -0
  9. package/extensions/@palexplorer/discovery/extension.json +17 -0
  10. package/extensions/@palexplorer/discovery/index.js +1 -1
  11. package/extensions/@palexplorer/email-notifications/extension.json +23 -0
  12. package/extensions/@palexplorer/groups/extension.json +15 -0
  13. package/extensions/@palexplorer/share-links/extension.json +15 -0
  14. package/extensions/@palexplorer/sync/extension.json +16 -0
  15. package/extensions/@palexplorer/user-mgmt/extension.json +15 -0
  16. package/lib/capabilities.js +24 -24
  17. package/lib/commands/analytics.js +175 -175
  18. package/lib/commands/api-keys.js +131 -131
  19. package/lib/commands/audit.js +235 -235
  20. package/lib/commands/auth.js +137 -137
  21. package/lib/commands/backup.js +76 -76
  22. package/lib/commands/billing.js +148 -148
  23. package/lib/commands/chat.js +217 -217
  24. package/lib/commands/cloud-backup.js +231 -231
  25. package/lib/commands/comment.js +99 -99
  26. package/lib/commands/completion.js +203 -203
  27. package/lib/commands/compliance.js +218 -218
  28. package/lib/commands/config.js +136 -136
  29. package/lib/commands/connect.js +44 -44
  30. package/lib/commands/dept.js +294 -294
  31. package/lib/commands/device.js +146 -146
  32. package/lib/commands/download.js +240 -226
  33. package/lib/commands/explorer.js +178 -178
  34. package/lib/commands/extension.js +1060 -970
  35. package/lib/commands/favorite.js +90 -90
  36. package/lib/commands/federation.js +270 -270
  37. package/lib/commands/file.js +533 -533
  38. package/lib/commands/group.js +271 -271
  39. package/lib/commands/gui-share.js +29 -29
  40. package/lib/commands/init.js +61 -61
  41. package/lib/commands/invite.js +59 -59
  42. package/lib/commands/list.js +58 -58
  43. package/lib/commands/log.js +116 -116
  44. package/lib/commands/nearby.js +108 -108
  45. package/lib/commands/network.js +251 -251
  46. package/lib/commands/notify.js +198 -198
  47. package/lib/commands/org.js +273 -273
  48. package/lib/commands/pal.js +403 -180
  49. package/lib/commands/permissions.js +216 -216
  50. package/lib/commands/pin.js +97 -97
  51. package/lib/commands/protocol.js +357 -357
  52. package/lib/commands/rbac.js +147 -147
  53. package/lib/commands/recover.js +36 -36
  54. package/lib/commands/register.js +171 -171
  55. package/lib/commands/relay.js +131 -131
  56. package/lib/commands/remote.js +368 -368
  57. package/lib/commands/revoke.js +50 -50
  58. package/lib/commands/scanner.js +280 -280
  59. package/lib/commands/schedule.js +344 -344
  60. package/lib/commands/scim.js +203 -203
  61. package/lib/commands/search.js +181 -181
  62. package/lib/commands/serve.js +438 -438
  63. package/lib/commands/server.js +350 -350
  64. package/lib/commands/share-link.js +199 -199
  65. package/lib/commands/share.js +336 -323
  66. package/lib/commands/sso.js +200 -200
  67. package/lib/commands/status.js +145 -145
  68. package/lib/commands/stream.js +562 -562
  69. package/lib/commands/su.js +187 -187
  70. package/lib/commands/sync.js +979 -979
  71. package/lib/commands/transfers.js +152 -152
  72. package/lib/commands/uninstall.js +188 -188
  73. package/lib/commands/update.js +204 -204
  74. package/lib/commands/user.js +276 -276
  75. package/lib/commands/vfs.js +84 -84
  76. package/lib/commands/web-login.js +79 -79
  77. package/lib/commands/web.js +52 -52
  78. package/lib/commands/webhook.js +180 -180
  79. package/lib/commands/whoami.js +59 -59
  80. package/lib/commands/workspace.js +121 -121
  81. package/lib/core/billing.js +16 -5
  82. package/lib/core/dhtDiscovery.js +9 -2
  83. package/lib/core/discoveryClient.js +13 -7
  84. package/lib/core/extensions.js +142 -1
  85. package/lib/core/identity.js +33 -2
  86. package/lib/core/imageProcessor.js +109 -0
  87. package/lib/core/imageTorrent.js +167 -0
  88. package/lib/core/permissions.js +1 -1
  89. package/lib/core/pro.js +11 -4
  90. package/lib/core/serverList.js +4 -1
  91. package/lib/core/shares.js +12 -1
  92. package/lib/core/signalingServer.js +14 -2
  93. package/lib/core/su.js +1 -1
  94. package/lib/core/users.js +1 -1
  95. package/lib/protocol/messages.js +12 -3
  96. package/lib/utils/explorer.js +1 -1
  97. package/lib/utils/help.js +357 -357
  98. package/lib/utils/torrent.js +1 -0
  99. package/package.json +4 -3
@@ -1,231 +1,231 @@
1
- import chalk from 'chalk';
2
-
3
- const VALID_PROVIDERS = ['s3', 'azure', 'gcs', 'b2'];
4
-
5
- export default function cloudBackupCommand(program) {
6
- const cmd = program
7
- .command('cloud-backup')
8
- .description('encrypted cloud backup (Pro)')
9
- .addHelpText('after', `
10
- Examples:
11
- $ pe cloud-backup configure --provider s3 --bucket my-backups --region us-east-1
12
- $ pe cloud-backup create Create a backup now
13
- $ pe cloud-backup list List available backups
14
- $ pe cloud-backup restore <id> Restore from a backup
15
- $ pe cloud-backup delete <id> Delete a backup
16
- $ pe cloud-backup status Show backup status
17
- `)
18
- .action(() => { cmd.outputHelp(); });
19
-
20
- cmd
21
- .command('configure')
22
- .description('set cloud backup provider')
23
- .requiredOption('--provider <provider>', 'cloud provider (s3|azure|gcs|b2)')
24
- .option('--bucket <name>', 'bucket name')
25
- .option('--region <region>', 'AWS region (for S3)')
26
- .option('--access-key <key>', 'access key')
27
- .option('--secret-key <key>', 'secret key')
28
- .option('--prefix <prefix>', 'key prefix')
29
- .option('--encrypt', 'enable encryption (default)', true)
30
- .action(async (opts) => {
31
- try {
32
- if (!VALID_PROVIDERS.includes(opts.provider)) {
33
- console.log(chalk.red(`Invalid provider. Must be one of: ${VALID_PROVIDERS.join(', ')}`));
34
- process.exitCode = 1;
35
- return;
36
- }
37
-
38
- const extConfig = (await import('../utils/config.js')).default;
39
- const existing = extConfig.get('ext.backup-cloud') || {};
40
- const config = {
41
- ...existing,
42
- provider: opts.provider,
43
- encryptBackups: opts.encrypt !== false,
44
- };
45
- if (opts.bucket) config.bucket = opts.bucket;
46
- if (opts.region) config.region = opts.region;
47
- if (opts.accessKey) config.accessKey = opts.accessKey;
48
- if (opts.secretKey) {
49
- try {
50
- const keytar = (await import('keytar')).default;
51
- await keytar.setPassword('palexplorer', 'cloudBackup.secretKey', opts.secretKey);
52
- } catch {
53
- config.secretKey = opts.secretKey;
54
- }
55
- }
56
- if (opts.prefix) config.prefix = opts.prefix;
57
-
58
- extConfig.set('ext.backup-cloud', config);
59
- console.log(chalk.green(`✔ Cloud backup configured: ${opts.provider}`));
60
- if (config.bucket) console.log(` Bucket: ${chalk.white(config.bucket)}`);
61
- if (config.region) console.log(` Region: ${chalk.white(config.region)}`);
62
- if (config.prefix) console.log(` Prefix: ${chalk.white(config.prefix)}`);
63
- console.log(` Encryption: ${config.encryptBackups ? chalk.green('enabled') : chalk.yellow('disabled')}`);
64
- } catch (err) {
65
- console.log(chalk.red(`Configure failed: ${err.message}`));
66
- process.exitCode = 1;
67
- }
68
- });
69
-
70
- cmd
71
- .command('create')
72
- .description('create a backup now')
73
- .action(async () => {
74
- try {
75
- const extConfig = (await import('../utils/config.js')).default;
76
- const config = extConfig.get('ext.backup-cloud') || {};
77
- if (!config.provider) {
78
- console.log(chalk.red('No provider configured. Run: pe cloud-backup configure --provider <provider>'));
79
- process.exitCode = 1;
80
- return;
81
- }
82
-
83
- const backupId = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
84
- const backup = {
85
- id: backupId,
86
- provider: config.provider,
87
- bucket: config.bucket,
88
- encrypted: config.encryptBackups !== false,
89
- createdAt: new Date().toISOString(),
90
- size: 0,
91
- status: 'completed',
92
- };
93
-
94
- console.log(chalk.cyan(`Creating backup to ${config.provider}://${config.bucket || 'default'}...`));
95
-
96
- const store = extConfig.get('ext_store.backup-cloud') || {};
97
- const history = store.backupHistory || [];
98
- history.push(backup);
99
- store.backupHistory = history;
100
- store.lastBackup = backup;
101
- extConfig.set('ext_store.backup-cloud', store);
102
-
103
- console.log(chalk.green(`✔ Backup created: ${backupId}`));
104
- console.log(` Provider: ${chalk.white(config.provider)}`);
105
- console.log(` Encrypted: ${backup.encrypted ? chalk.green('yes') : chalk.yellow('no')}`);
106
- console.log(` Time: ${chalk.dim(backup.createdAt)}`);
107
- } catch (err) {
108
- console.log(chalk.red(`Backup failed: ${err.message}`));
109
- process.exitCode = 1;
110
- }
111
- });
112
-
113
- cmd
114
- .command('restore <id>')
115
- .description('restore from a backup')
116
- .action(async (id) => {
117
- try {
118
- const extConfig = (await import('../utils/config.js')).default;
119
- const store = extConfig.get('ext_store.backup-cloud') || {};
120
- const history = store.backupHistory || [];
121
- const backup = history.find(b => b.id === id);
122
- if (!backup) {
123
- console.log(chalk.red(`Backup not found: ${id}`));
124
- process.exitCode = 1;
125
- return;
126
- }
127
-
128
- console.log(chalk.cyan(`Restoring from backup ${id}...`));
129
- console.log(` Provider: ${chalk.white(backup.provider)}`);
130
- console.log(` Created: ${chalk.dim(backup.createdAt)}`);
131
- console.log(chalk.green('✔ Backup restored successfully.'));
132
- console.log(chalk.dim(' Note: Restart palexplorer to apply restored settings.'));
133
- } catch (err) {
134
- console.log(chalk.red(`Restore failed: ${err.message}`));
135
- process.exitCode = 1;
136
- }
137
- });
138
-
139
- cmd
140
- .command('list')
141
- .description('list available backups')
142
- .action(async () => {
143
- try {
144
- const extConfig = (await import('../utils/config.js')).default;
145
- const store = extConfig.get('ext_store.backup-cloud') || {};
146
- const history = store.backupHistory || [];
147
- if (history.length === 0) {
148
- console.log(chalk.dim('No backups found.'));
149
- console.log(chalk.dim(' pe cloud-backup create'));
150
- return;
151
- }
152
- console.log(chalk.bold(`Cloud Backups (${history.length})\n`));
153
- for (const b of history) {
154
- const statusColor = b.status === 'completed' ? chalk.green : b.status === 'failed' ? chalk.red : chalk.yellow;
155
- const encrypted = b.encrypted ? chalk.green('🔒') : '';
156
- console.log(` ${chalk.white(b.id)} ${statusColor(b.status)} ${encrypted}`);
157
- console.log(` Provider: ${chalk.dim(b.provider)} Created: ${chalk.dim(b.createdAt)}`);
158
- }
159
- } catch (err) {
160
- console.log(chalk.red(`List failed: ${err.message}`));
161
- process.exitCode = 1;
162
- }
163
- });
164
-
165
- cmd
166
- .command('delete <id>')
167
- .description('delete a backup')
168
- .action(async (id) => {
169
- try {
170
- const extConfig = (await import('../utils/config.js')).default;
171
- const store = extConfig.get('ext_store.backup-cloud') || {};
172
- const history = store.backupHistory || [];
173
- const idx = history.findIndex(b => b.id === id);
174
- if (idx === -1) {
175
- console.log(chalk.red(`Backup not found: ${id}`));
176
- process.exitCode = 1;
177
- return;
178
- }
179
- const removed = history.splice(idx, 1)[0];
180
- store.backupHistory = history;
181
- if (store.lastBackup?.id === id) {
182
- store.lastBackup = history.length > 0 ? history[history.length - 1] : null;
183
- }
184
- extConfig.set('ext_store.backup-cloud', store);
185
- console.log(chalk.green(`✔ Backup deleted: ${id}`));
186
- console.log(` Provider: ${chalk.dim(removed.provider)} Created: ${chalk.dim(removed.createdAt)}`);
187
- } catch (err) {
188
- console.log(chalk.red(`Delete failed: ${err.message}`));
189
- process.exitCode = 1;
190
- }
191
- });
192
-
193
- cmd
194
- .command('status')
195
- .description('show last backup info, provider, schedule')
196
- .action(async () => {
197
- try {
198
- const extConfig = (await import('../utils/config.js')).default;
199
- const config = extConfig.get('ext.backup-cloud') || {};
200
- const store = extConfig.get('ext_store.backup-cloud') || {};
201
-
202
- if (!config.provider) {
203
- console.log(chalk.dim('Cloud backup not configured.'));
204
- console.log(chalk.dim(' pe cloud-backup configure --provider <provider>'));
205
- return;
206
- }
207
-
208
- console.log(chalk.bold('Cloud Backup Status\n'));
209
- console.log(` Provider: ${chalk.cyan(config.provider)}`);
210
- console.log(` Bucket: ${chalk.white(config.bucket || 'not set')}`);
211
- if (config.region) console.log(` Region: ${chalk.white(config.region)}`);
212
- if (config.prefix) console.log(` Prefix: ${chalk.white(config.prefix)}`);
213
- console.log(` Encryption: ${config.encryptBackups !== false ? chalk.green('enabled') : chalk.yellow('disabled')}`);
214
- console.log(` Schedule: ${chalk.white(config.schedule || 'manual')}`);
215
-
216
- const history = store.backupHistory || [];
217
- console.log(` Backups: ${chalk.white(history.length)}`);
218
-
219
- if (store.lastBackup) {
220
- console.log('');
221
- console.log(chalk.cyan(' Last Backup:'));
222
- console.log(` ID: ${chalk.white(store.lastBackup.id)}`);
223
- console.log(` Status: ${store.lastBackup.status === 'completed' ? chalk.green('completed') : chalk.red(store.lastBackup.status)}`);
224
- console.log(` Created: ${chalk.dim(store.lastBackup.createdAt)}`);
225
- }
226
- } catch (err) {
227
- console.log(chalk.red(`Status failed: ${err.message}`));
228
- process.exitCode = 1;
229
- }
230
- });
231
- }
1
+ import chalk from 'chalk';
2
+
3
+ const VALID_PROVIDERS = ['s3', 'azure', 'gcs', 'b2'];
4
+
5
+ export default function cloudBackupCommand(program) {
6
+ const cmd = program
7
+ .command('cloud-backup')
8
+ .description('encrypted cloud backup (Pro)')
9
+ .addHelpText('after', `
10
+ Examples:
11
+ $ pal cloud-backup configure --provider s3 --bucket my-backups --region us-east-1
12
+ $ pal cloud-backup create Create a backup now
13
+ $ pal cloud-backup list List available backups
14
+ $ pal cloud-backup restore <id> Restore from a backup
15
+ $ pal cloud-backup delete <id> Delete a backup
16
+ $ pal cloud-backup status Show backup status
17
+ `)
18
+ .action(() => { cmd.outputHelp(); });
19
+
20
+ cmd
21
+ .command('configure')
22
+ .description('set cloud backup provider')
23
+ .requiredOption('--provider <provider>', 'cloud provider (s3|azure|gcs|b2)')
24
+ .option('--bucket <name>', 'bucket name')
25
+ .option('--region <region>', 'AWS region (for S3)')
26
+ .option('--access-key <key>', 'access key')
27
+ .option('--secret-key <key>', 'secret key')
28
+ .option('--prefix <prefix>', 'key prefix')
29
+ .option('--encrypt', 'enable encryption (default)', true)
30
+ .action(async (opts) => {
31
+ try {
32
+ if (!VALID_PROVIDERS.includes(opts.provider)) {
33
+ console.log(chalk.red(`Invalid provider. Must be one of: ${VALID_PROVIDERS.join(', ')}`));
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+
38
+ const extConfig = (await import('../utils/config.js')).default;
39
+ const existing = extConfig.get('ext.backup-cloud') || {};
40
+ const config = {
41
+ ...existing,
42
+ provider: opts.provider,
43
+ encryptBackups: opts.encrypt !== false,
44
+ };
45
+ if (opts.bucket) config.bucket = opts.bucket;
46
+ if (opts.region) config.region = opts.region;
47
+ if (opts.accessKey) config.accessKey = opts.accessKey;
48
+ if (opts.secretKey) {
49
+ try {
50
+ const keytar = (await import('keytar')).default;
51
+ await keytar.setPassword('palexplorer', 'cloudBackup.secretKey', opts.secretKey);
52
+ } catch {
53
+ config.secretKey = opts.secretKey;
54
+ }
55
+ }
56
+ if (opts.prefix) config.prefix = opts.prefix;
57
+
58
+ extConfig.set('ext.backup-cloud', config);
59
+ console.log(chalk.green(`✔ Cloud backup configured: ${opts.provider}`));
60
+ if (config.bucket) console.log(` Bucket: ${chalk.white(config.bucket)}`);
61
+ if (config.region) console.log(` Region: ${chalk.white(config.region)}`);
62
+ if (config.prefix) console.log(` Prefix: ${chalk.white(config.prefix)}`);
63
+ console.log(` Encryption: ${config.encryptBackups ? chalk.green('enabled') : chalk.yellow('disabled')}`);
64
+ } catch (err) {
65
+ console.log(chalk.red(`Configure failed: ${err.message}`));
66
+ process.exitCode = 1;
67
+ }
68
+ });
69
+
70
+ cmd
71
+ .command('create')
72
+ .description('create a backup now')
73
+ .action(async () => {
74
+ try {
75
+ const extConfig = (await import('../utils/config.js')).default;
76
+ const config = extConfig.get('ext.backup-cloud') || {};
77
+ if (!config.provider) {
78
+ console.log(chalk.red('No provider configured. Run: pal cloud-backup configure --provider <provider>'));
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+
83
+ const backupId = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
84
+ const backup = {
85
+ id: backupId,
86
+ provider: config.provider,
87
+ bucket: config.bucket,
88
+ encrypted: config.encryptBackups !== false,
89
+ createdAt: new Date().toISOString(),
90
+ size: 0,
91
+ status: 'completed',
92
+ };
93
+
94
+ console.log(chalk.cyan(`Creating backup to ${config.provider}://${config.bucket || 'default'}...`));
95
+
96
+ const store = extConfig.get('ext_store.backup-cloud') || {};
97
+ const history = store.backupHistory || [];
98
+ history.push(backup);
99
+ store.backupHistory = history;
100
+ store.lastBackup = backup;
101
+ extConfig.set('ext_store.backup-cloud', store);
102
+
103
+ console.log(chalk.green(`✔ Backup created: ${backupId}`));
104
+ console.log(` Provider: ${chalk.white(config.provider)}`);
105
+ console.log(` Encrypted: ${backup.encrypted ? chalk.green('yes') : chalk.yellow('no')}`);
106
+ console.log(` Time: ${chalk.dim(backup.createdAt)}`);
107
+ } catch (err) {
108
+ console.log(chalk.red(`Backup failed: ${err.message}`));
109
+ process.exitCode = 1;
110
+ }
111
+ });
112
+
113
+ cmd
114
+ .command('restore <id>')
115
+ .description('restore from a backup')
116
+ .action(async (id) => {
117
+ try {
118
+ const extConfig = (await import('../utils/config.js')).default;
119
+ const store = extConfig.get('ext_store.backup-cloud') || {};
120
+ const history = store.backupHistory || [];
121
+ const backup = history.find(b => b.id === id);
122
+ if (!backup) {
123
+ console.log(chalk.red(`Backup not found: ${id}`));
124
+ process.exitCode = 1;
125
+ return;
126
+ }
127
+
128
+ console.log(chalk.cyan(`Restoring from backup ${id}...`));
129
+ console.log(` Provider: ${chalk.white(backup.provider)}`);
130
+ console.log(` Created: ${chalk.dim(backup.createdAt)}`);
131
+ console.log(chalk.green('✔ Backup restored successfully.'));
132
+ console.log(chalk.dim(' Note: Restart palexplorer to apply restored settings.'));
133
+ } catch (err) {
134
+ console.log(chalk.red(`Restore failed: ${err.message}`));
135
+ process.exitCode = 1;
136
+ }
137
+ });
138
+
139
+ cmd
140
+ .command('list')
141
+ .description('list available backups')
142
+ .action(async () => {
143
+ try {
144
+ const extConfig = (await import('../utils/config.js')).default;
145
+ const store = extConfig.get('ext_store.backup-cloud') || {};
146
+ const history = store.backupHistory || [];
147
+ if (history.length === 0) {
148
+ console.log(chalk.dim('No backups found.'));
149
+ console.log(chalk.dim(' pal cloud-backup create'));
150
+ return;
151
+ }
152
+ console.log(chalk.bold(`Cloud Backups (${history.length})\n`));
153
+ for (const b of history) {
154
+ const statusColor = b.status === 'completed' ? chalk.green : b.status === 'failed' ? chalk.red : chalk.yellow;
155
+ const encrypted = b.encrypted ? chalk.green('🔒') : '';
156
+ console.log(` ${chalk.white(b.id)} ${statusColor(b.status)} ${encrypted}`);
157
+ console.log(` Provider: ${chalk.dim(b.provider)} Created: ${chalk.dim(b.createdAt)}`);
158
+ }
159
+ } catch (err) {
160
+ console.log(chalk.red(`List failed: ${err.message}`));
161
+ process.exitCode = 1;
162
+ }
163
+ });
164
+
165
+ cmd
166
+ .command('delete <id>')
167
+ .description('delete a backup')
168
+ .action(async (id) => {
169
+ try {
170
+ const extConfig = (await import('../utils/config.js')).default;
171
+ const store = extConfig.get('ext_store.backup-cloud') || {};
172
+ const history = store.backupHistory || [];
173
+ const idx = history.findIndex(b => b.id === id);
174
+ if (idx === -1) {
175
+ console.log(chalk.red(`Backup not found: ${id}`));
176
+ process.exitCode = 1;
177
+ return;
178
+ }
179
+ const removed = history.splice(idx, 1)[0];
180
+ store.backupHistory = history;
181
+ if (store.lastBackup?.id === id) {
182
+ store.lastBackup = history.length > 0 ? history[history.length - 1] : null;
183
+ }
184
+ extConfig.set('ext_store.backup-cloud', store);
185
+ console.log(chalk.green(`✔ Backup deleted: ${id}`));
186
+ console.log(` Provider: ${chalk.dim(removed.provider)} Created: ${chalk.dim(removed.createdAt)}`);
187
+ } catch (err) {
188
+ console.log(chalk.red(`Delete failed: ${err.message}`));
189
+ process.exitCode = 1;
190
+ }
191
+ });
192
+
193
+ cmd
194
+ .command('status')
195
+ .description('show last backup info, provider, schedule')
196
+ .action(async () => {
197
+ try {
198
+ const extConfig = (await import('../utils/config.js')).default;
199
+ const config = extConfig.get('ext.backup-cloud') || {};
200
+ const store = extConfig.get('ext_store.backup-cloud') || {};
201
+
202
+ if (!config.provider) {
203
+ console.log(chalk.dim('Cloud backup not configured.'));
204
+ console.log(chalk.dim(' pal cloud-backup configure --provider <provider>'));
205
+ return;
206
+ }
207
+
208
+ console.log(chalk.bold('Cloud Backup Status\n'));
209
+ console.log(` Provider: ${chalk.cyan(config.provider)}`);
210
+ console.log(` Bucket: ${chalk.white(config.bucket || 'not set')}`);
211
+ if (config.region) console.log(` Region: ${chalk.white(config.region)}`);
212
+ if (config.prefix) console.log(` Prefix: ${chalk.white(config.prefix)}`);
213
+ console.log(` Encryption: ${config.encryptBackups !== false ? chalk.green('enabled') : chalk.yellow('disabled')}`);
214
+ console.log(` Schedule: ${chalk.white(config.schedule || 'manual')}`);
215
+
216
+ const history = store.backupHistory || [];
217
+ console.log(` Backups: ${chalk.white(history.length)}`);
218
+
219
+ if (store.lastBackup) {
220
+ console.log('');
221
+ console.log(chalk.cyan(' Last Backup:'));
222
+ console.log(` ID: ${chalk.white(store.lastBackup.id)}`);
223
+ console.log(` Status: ${store.lastBackup.status === 'completed' ? chalk.green('completed') : chalk.red(store.lastBackup.status)}`);
224
+ console.log(` Created: ${chalk.dim(store.lastBackup.createdAt)}`);
225
+ }
226
+ } catch (err) {
227
+ console.log(chalk.red(`Status failed: ${err.message}`));
228
+ process.exitCode = 1;
229
+ }
230
+ });
231
+ }
@@ -1,99 +1,99 @@
1
- import chalk from 'chalk';
2
- import config from '../utils/config.js';
3
- import {
4
- getShareComments,
5
- addShareComment,
6
- deleteShareComment
7
- } from '../core/groups.js';
8
- import { checkLimit } from '../core/pro.js';
9
-
10
- export default function commentCommand(program) {
11
- const cmd = program
12
- .command('comment')
13
- .description('manage comments on shares')
14
- .addHelpText('after', `
15
- Examples:
16
- $ pe comment list <shareId> List comments on a share
17
- $ pe comment add <shareId> "nice files!" Add a comment
18
- $ pe comment delete <shareId> <commentId> Delete a comment
19
- `);
20
-
21
- cmd
22
- .command('list <shareId>')
23
- .description('list comments on a share')
24
- .action((shareId) => {
25
- const comments = getShareComments(shareId);
26
- if (comments.length === 0) {
27
- console.log(chalk.gray('No comments on this share.'));
28
- return;
29
- }
30
- console.log('');
31
- console.log(chalk.cyan(`Comments on ${shareId}:`));
32
- for (const c of comments) {
33
- const time = new Date(c.createdAt).toLocaleString();
34
- const author = c.authorHandle ? `@${c.authorHandle}` : c.authorName || 'unknown';
35
- console.log(` ${chalk.gray(c.id.slice(0, 8))} ${chalk.white(author)} ${chalk.gray(time)}`);
36
- console.log(` ${c.text}`);
37
- }
38
- console.log('');
39
- });
40
-
41
- cmd
42
- .command('add <shareId> <text>')
43
- .description('add a comment to a share')
44
- .action((shareId, text) => {
45
- if (!text || !text.trim()) {
46
- console.log(chalk.red('Error: comment text cannot be empty.'));
47
- process.exitCode = 1;
48
- return;
49
- }
50
- try {
51
- const comments = getShareComments(shareId);
52
- checkLimit('maxCommentsPerShare', comments.length);
53
-
54
- const identity = config.get('identity');
55
- const comment = addShareComment(shareId, {
56
- authorHandle: identity?.handle || null,
57
- authorName: identity?.name || 'Anonymous',
58
- text,
59
- });
60
- console.log(chalk.green(`Comment added.`));
61
- console.log(chalk.gray(`ID: ${comment.id}`));
62
- } catch (err) {
63
- console.log(chalk.red(err.message));
64
- process.exitCode = 1;
65
- }
66
- });
67
-
68
- cmd
69
- .command('delete <shareId> <commentId>')
70
- .description('delete a comment from a share')
71
- .action((shareId, commentId) => {
72
- try {
73
- const identity = config.get('identity');
74
- const comments = getShareComments(shareId);
75
- const comment = comments.find(c => c.id === commentId);
76
- if (!comment) {
77
- console.log(chalk.red('Comment not found.'));
78
- process.exitCode = 1;
79
- return;
80
- }
81
- const myHandle = identity?.handle || null;
82
- const myName = identity?.name || 'Anonymous';
83
- if (comment.authorHandle !== myHandle && comment.authorName !== myName) {
84
- console.log(chalk.red('Error: you can only delete your own comments.'));
85
- process.exitCode = 1;
86
- return;
87
- }
88
- deleteShareComment(shareId, commentId);
89
- console.log(chalk.green('Comment deleted.'));
90
- } catch (err) {
91
- console.log(chalk.red(err.message));
92
- process.exitCode = 1;
93
- }
94
- });
95
-
96
- cmd.action(() => {
97
- console.log(chalk.gray('Use `pe comment list <shareId>` to view comments.'));
98
- });
99
- }
1
+ import chalk from 'chalk';
2
+ import config from '../utils/config.js';
3
+ import {
4
+ getShareComments,
5
+ addShareComment,
6
+ deleteShareComment
7
+ } from '../core/groups.js';
8
+ import { checkLimit } from '../core/pro.js';
9
+
10
+ export default function commentCommand(program) {
11
+ const cmd = program
12
+ .command('comment')
13
+ .description('manage comments on shares')
14
+ .addHelpText('after', `
15
+ Examples:
16
+ $ pal comment list <shareId> List comments on a share
17
+ $ pal comment add <shareId> "nice files!" Add a comment
18
+ $ pal comment delete <shareId> <commentId> Delete a comment
19
+ `);
20
+
21
+ cmd
22
+ .command('list <shareId>')
23
+ .description('list comments on a share')
24
+ .action((shareId) => {
25
+ const comments = getShareComments(shareId);
26
+ if (comments.length === 0) {
27
+ console.log(chalk.gray('No comments on this share.'));
28
+ return;
29
+ }
30
+ console.log('');
31
+ console.log(chalk.cyan(`Comments on ${shareId}:`));
32
+ for (const c of comments) {
33
+ const time = new Date(c.createdAt).toLocaleString();
34
+ const author = c.authorHandle ? `@${c.authorHandle}` : c.authorName || 'unknown';
35
+ console.log(` ${chalk.gray(c.id.slice(0, 8))} ${chalk.white(author)} ${chalk.gray(time)}`);
36
+ console.log(` ${c.text}`);
37
+ }
38
+ console.log('');
39
+ });
40
+
41
+ cmd
42
+ .command('add <shareId> <text>')
43
+ .description('add a comment to a share')
44
+ .action((shareId, text) => {
45
+ if (!text || !text.trim()) {
46
+ console.log(chalk.red('Error: comment text cannot be empty.'));
47
+ process.exitCode = 1;
48
+ return;
49
+ }
50
+ try {
51
+ const comments = getShareComments(shareId);
52
+ checkLimit('maxCommentsPerShare', comments.length);
53
+
54
+ const identity = config.get('identity');
55
+ const comment = addShareComment(shareId, {
56
+ authorHandle: identity?.handle || null,
57
+ authorName: identity?.name || 'Anonymous',
58
+ text,
59
+ });
60
+ console.log(chalk.green(`Comment added.`));
61
+ console.log(chalk.gray(`ID: ${comment.id}`));
62
+ } catch (err) {
63
+ console.log(chalk.red(err.message));
64
+ process.exitCode = 1;
65
+ }
66
+ });
67
+
68
+ cmd
69
+ .command('delete <shareId> <commentId>')
70
+ .description('delete a comment from a share')
71
+ .action((shareId, commentId) => {
72
+ try {
73
+ const identity = config.get('identity');
74
+ const comments = getShareComments(shareId);
75
+ const comment = comments.find(c => c.id === commentId);
76
+ if (!comment) {
77
+ console.log(chalk.red('Comment not found.'));
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+ const myHandle = identity?.handle || null;
82
+ const myName = identity?.name || 'Anonymous';
83
+ if (comment.authorHandle !== myHandle && comment.authorName !== myName) {
84
+ console.log(chalk.red('Error: you can only delete your own comments.'));
85
+ process.exitCode = 1;
86
+ return;
87
+ }
88
+ deleteShareComment(shareId, commentId);
89
+ console.log(chalk.green('Comment deleted.'));
90
+ } catch (err) {
91
+ console.log(chalk.red(err.message));
92
+ process.exitCode = 1;
93
+ }
94
+ });
95
+
96
+ cmd.action(() => {
97
+ console.log(chalk.gray('Use `pal comment list <shareId>` to view comments.'));
98
+ });
99
+ }