@lifestreamdynamics/vault-cli 1.1.0 → 1.2.0

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.
@@ -154,4 +154,227 @@ EXAMPLES
154
154
  handleError(out, err, 'Failed to import vault key');
155
155
  }
156
156
  });
157
+ // vault tree
158
+ addGlobalFlags(vaults.command('tree')
159
+ .description('Show vault file tree')
160
+ .argument('<vaultId>', 'Vault ID'))
161
+ .action(async (vaultId, _opts) => {
162
+ const flags = resolveFlags(_opts);
163
+ const out = createOutput(flags);
164
+ out.startSpinner('Fetching vault tree...');
165
+ try {
166
+ const client = await getClientAsync();
167
+ const tree = await client.vaults.getTree(vaultId);
168
+ out.stopSpinner();
169
+ if (flags.output === 'json') {
170
+ out.raw(JSON.stringify(tree, null, 2) + '\n');
171
+ }
172
+ else {
173
+ function printNode(node, depth) {
174
+ const indent = ' '.repeat(depth);
175
+ const icon = node.type === 'directory' ? chalk.yellow('📁') : chalk.cyan('📄');
176
+ process.stdout.write(`${indent}${icon} ${node.name}\n`);
177
+ if (node.children) {
178
+ for (const child of node.children)
179
+ printNode(child, depth + 1);
180
+ }
181
+ }
182
+ for (const node of tree)
183
+ printNode(node, 0);
184
+ }
185
+ }
186
+ catch (err) {
187
+ handleError(out, err, 'Failed to fetch vault tree');
188
+ }
189
+ });
190
+ // vault archive
191
+ addGlobalFlags(vaults.command('archive')
192
+ .description('Archive a vault')
193
+ .argument('<vaultId>', 'Vault ID'))
194
+ .action(async (vaultId, _opts) => {
195
+ const flags = resolveFlags(_opts);
196
+ const out = createOutput(flags);
197
+ out.startSpinner('Archiving vault...');
198
+ try {
199
+ const client = await getClientAsync();
200
+ const vault = await client.vaults.archive(vaultId);
201
+ out.success(`Vault archived: ${vault.name}`, { id: vault.id, name: vault.name, isArchived: vault.isArchived });
202
+ }
203
+ catch (err) {
204
+ handleError(out, err, 'Failed to archive vault');
205
+ }
206
+ });
207
+ // vault unarchive
208
+ addGlobalFlags(vaults.command('unarchive')
209
+ .description('Unarchive a vault')
210
+ .argument('<vaultId>', 'Vault ID'))
211
+ .action(async (vaultId, _opts) => {
212
+ const flags = resolveFlags(_opts);
213
+ const out = createOutput(flags);
214
+ out.startSpinner('Unarchiving vault...');
215
+ try {
216
+ const client = await getClientAsync();
217
+ const vault = await client.vaults.unarchive(vaultId);
218
+ out.success(`Vault unarchived: ${vault.name}`, { id: vault.id, name: vault.name, isArchived: vault.isArchived });
219
+ }
220
+ catch (err) {
221
+ handleError(out, err, 'Failed to unarchive vault');
222
+ }
223
+ });
224
+ // vault transfer
225
+ addGlobalFlags(vaults.command('transfer')
226
+ .description('Transfer vault ownership to another user')
227
+ .argument('<vaultId>', 'Vault ID')
228
+ .argument('<targetEmail>', 'Email of the user to transfer to'))
229
+ .action(async (vaultId, targetEmail, _opts) => {
230
+ const flags = resolveFlags(_opts);
231
+ const out = createOutput(flags);
232
+ out.startSpinner('Transferring vault...');
233
+ try {
234
+ const client = await getClientAsync();
235
+ const vault = await client.vaults.transfer(vaultId, targetEmail);
236
+ out.success(`Vault transferred to ${targetEmail}`, { id: vault.id, name: vault.name });
237
+ }
238
+ catch (err) {
239
+ handleError(out, err, 'Failed to transfer vault');
240
+ }
241
+ });
242
+ // vault export-vault subgroup
243
+ const exportVault = vaults.command('export-vault').description('Vault export operations');
244
+ addGlobalFlags(exportVault.command('create')
245
+ .description('Create a vault export')
246
+ .argument('<vaultId>', 'Vault ID')
247
+ .option('--metadata', 'Include metadata in export')
248
+ .option('--format <fmt>', 'Export format', 'zip'))
249
+ .action(async (vaultId, _opts) => {
250
+ const flags = resolveFlags(_opts);
251
+ const out = createOutput(flags);
252
+ out.startSpinner('Creating export...');
253
+ try {
254
+ const client = await getClientAsync();
255
+ const exp = await client.vaults.createExport(vaultId, {
256
+ includeMetadata: _opts.metadata === true,
257
+ format: _opts.format || 'zip',
258
+ });
259
+ out.success('Export created', { id: exp.id, status: exp.status, format: exp.format });
260
+ }
261
+ catch (err) {
262
+ handleError(out, err, 'Failed to create export');
263
+ }
264
+ });
265
+ addGlobalFlags(exportVault.command('list')
266
+ .description('List vault exports')
267
+ .argument('<vaultId>', 'Vault ID'))
268
+ .action(async (vaultId, _opts) => {
269
+ const flags = resolveFlags(_opts);
270
+ const out = createOutput(flags);
271
+ out.startSpinner('Fetching exports...');
272
+ try {
273
+ const client = await getClientAsync();
274
+ const exports = await client.vaults.listExports(vaultId);
275
+ out.stopSpinner();
276
+ out.list(exports.map(e => ({ id: e.id, status: e.status, format: e.format, createdAt: e.createdAt, completedAt: e.completedAt || '' })), {
277
+ emptyMessage: 'No exports found.',
278
+ columns: [
279
+ { key: 'id', header: 'ID' },
280
+ { key: 'status', header: 'Status' },
281
+ { key: 'format', header: 'Format' },
282
+ { key: 'createdAt', header: 'Created' },
283
+ { key: 'completedAt', header: 'Completed' },
284
+ ],
285
+ textFn: (e) => `${chalk.cyan(String(e.id))} [${String(e.status)}] ${String(e.format)} created: ${String(e.createdAt)}`,
286
+ });
287
+ }
288
+ catch (err) {
289
+ handleError(out, err, 'Failed to list exports');
290
+ }
291
+ });
292
+ addGlobalFlags(exportVault.command('download')
293
+ .description('Download a vault export')
294
+ .argument('<vaultId>', 'Vault ID')
295
+ .argument('<exportId>', 'Export ID')
296
+ .requiredOption('--file <path>', 'Output file path'))
297
+ .action(async (vaultId, exportId, _opts) => {
298
+ const flags = resolveFlags(_opts);
299
+ const out = createOutput(flags);
300
+ out.startSpinner('Downloading export...');
301
+ try {
302
+ const { writeFile } = await import('node:fs/promises');
303
+ const client = await getClientAsync();
304
+ const blob = await client.vaults.downloadExport(vaultId, exportId);
305
+ const buffer = Buffer.from(await blob.arrayBuffer());
306
+ await writeFile(_opts.file, buffer);
307
+ out.success(`Export downloaded to ${String(_opts.file)}`, { path: _opts.file, size: buffer.length });
308
+ }
309
+ catch (err) {
310
+ handleError(out, err, 'Failed to download export');
311
+ }
312
+ });
313
+ // vault mfa subgroup
314
+ const mfa = vaults.command('mfa').description('Vault MFA configuration');
315
+ addGlobalFlags(mfa.command('get')
316
+ .description('Get vault MFA configuration')
317
+ .argument('<vaultId>', 'Vault ID'))
318
+ .action(async (vaultId, _opts) => {
319
+ const flags = resolveFlags(_opts);
320
+ const out = createOutput(flags);
321
+ out.startSpinner('Fetching MFA config...');
322
+ try {
323
+ const client = await getClientAsync();
324
+ const config = await client.vaults.getMfaConfig(vaultId);
325
+ out.stopSpinner();
326
+ out.record({
327
+ mfaRequired: config.mfaRequired,
328
+ sessionWindowMinutes: config.sessionWindowMinutes,
329
+ userVerified: config.userVerified,
330
+ verificationExpiresAt: config.verificationExpiresAt,
331
+ });
332
+ }
333
+ catch (err) {
334
+ handleError(out, err, 'Failed to fetch MFA config');
335
+ }
336
+ });
337
+ addGlobalFlags(mfa.command('set')
338
+ .description('Set vault MFA configuration')
339
+ .argument('<vaultId>', 'Vault ID')
340
+ .option('--require', 'Require MFA for vault access')
341
+ .option('--no-require', 'Disable MFA requirement')
342
+ .option('--window <minutes>', 'Session window in minutes', '60'))
343
+ .action(async (vaultId, _opts) => {
344
+ const flags = resolveFlags(_opts);
345
+ const out = createOutput(flags);
346
+ out.startSpinner('Updating MFA config...');
347
+ try {
348
+ const client = await getClientAsync();
349
+ const config = await client.vaults.setMfaConfig(vaultId, {
350
+ mfaRequired: _opts.require !== false,
351
+ sessionWindowMinutes: parseInt(String(_opts.window || '60'), 10),
352
+ });
353
+ out.success('MFA config updated', { mfaRequired: config.mfaRequired, sessionWindowMinutes: config.sessionWindowMinutes });
354
+ }
355
+ catch (err) {
356
+ handleError(out, err, 'Failed to update MFA config');
357
+ }
358
+ });
359
+ addGlobalFlags(mfa.command('verify')
360
+ .description('Verify MFA for vault access')
361
+ .argument('<vaultId>', 'Vault ID')
362
+ .requiredOption('--method <totp|backup_code>', 'MFA method')
363
+ .requiredOption('--code <code>', 'MFA code'))
364
+ .action(async (vaultId, _opts) => {
365
+ const flags = resolveFlags(_opts);
366
+ const out = createOutput(flags);
367
+ out.startSpinner('Verifying MFA...');
368
+ try {
369
+ const client = await getClientAsync();
370
+ const result = await client.vaults.verifyMfa(vaultId, {
371
+ method: _opts.method,
372
+ code: _opts.code,
373
+ });
374
+ out.success('MFA verified', { verified: result.verified, expiresAt: result.expiresAt });
375
+ }
376
+ catch (err) {
377
+ handleError(out, err, 'Failed to verify MFA');
378
+ }
379
+ });
157
380
  }
package/dist/index.js CHANGED
@@ -21,6 +21,10 @@ import { registerSyncCommands } from './commands/sync.js';
21
21
  import { registerVersionCommands } from './commands/versions.js';
22
22
  import { registerLinkCommands } from './commands/links.js';
23
23
  import { registerCalendarCommands } from './commands/calendar.js';
24
+ import { registerAiCommands } from './commands/ai.js';
25
+ import { registerAnalyticsCommands } from './commands/analytics.js';
26
+ import { registerCustomDomainCommands } from './commands/custom-domains.js';
27
+ import { registerPublishVaultCommands } from './commands/publish-vault.js';
24
28
  const program = new Command();
25
29
  program
26
30
  .name('lsvault')
@@ -66,4 +70,8 @@ registerSyncCommands(program);
66
70
  registerVersionCommands(program);
67
71
  registerLinkCommands(program);
68
72
  registerCalendarCommands(program);
73
+ registerAiCommands(program);
74
+ registerAnalyticsCommands(program);
75
+ registerCustomDomainCommands(program);
76
+ registerPublishVaultCommands(program);
69
77
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifestreamdynamics/vault-cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Command-line interface for Lifestream Vault",
5
5
  "engines": {
6
6
  "node": ">=20"
@@ -44,7 +44,7 @@
44
44
  "prepublishOnly": "npm run build && npm test"
45
45
  },
46
46
  "dependencies": {
47
- "@lifestreamdynamics/vault-sdk": "^1.1.0",
47
+ "@lifestreamdynamics/vault-sdk": "^1.2.0",
48
48
  "chalk": "^5.4.0",
49
49
  "chokidar": "^4.0.3",
50
50
  "commander": "^13.0.0",