@lifestreamdynamics/vault-cli 1.0.0 → 1.1.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.
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { getClient } from '../client.js';
2
+ import { getClientAsync } from '../client.js';
3
3
  import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
4
4
  import { createOutput, handleError } from '../utils/output.js';
5
5
  export function registerHookCommands(program) {
@@ -12,7 +12,7 @@ export function registerHookCommands(program) {
12
12
  const out = createOutput(flags);
13
13
  out.startSpinner('Fetching hooks...');
14
14
  try {
15
- const client = getClient();
15
+ const client = await getClientAsync();
16
16
  const hookList = await client.hooks.list(vaultId);
17
17
  out.stopSpinner();
18
18
  out.list(hookList.map(hook => ({
@@ -76,7 +76,7 @@ export function registerHookCommands(program) {
76
76
  }
77
77
  out.startSpinner('Creating hook...');
78
78
  try {
79
- const client = getClient();
79
+ const client = await getClientAsync();
80
80
  const params = {
81
81
  name,
82
82
  triggerEvent: String(_opts.trigger),
@@ -106,7 +106,7 @@ export function registerHookCommands(program) {
106
106
  const out = createOutput(flags);
107
107
  out.startSpinner('Deleting hook...');
108
108
  try {
109
- const client = getClient();
109
+ const client = await getClientAsync();
110
110
  await client.hooks.delete(vaultId, hookId);
111
111
  out.success('Hook deleted successfully', { id: hookId, deleted: true });
112
112
  }
@@ -123,7 +123,7 @@ export function registerHookCommands(program) {
123
123
  const out = createOutput(flags);
124
124
  out.startSpinner('Fetching executions...');
125
125
  try {
126
- const client = getClient();
126
+ const client = await getClientAsync();
127
127
  const executions = await client.hooks.listExecutions(vaultId, hookId);
128
128
  out.stopSpinner();
129
129
  out.list(executions.map(exec => ({
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { getClient } from '../client.js';
2
+ import { getClientAsync } from '../client.js';
3
3
  import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
4
4
  import { createOutput, handleError } from '../utils/output.js';
5
5
  export function registerKeyCommands(program) {
@@ -11,7 +11,7 @@ export function registerKeyCommands(program) {
11
11
  const out = createOutput(flags);
12
12
  out.startSpinner('Fetching API keys...');
13
13
  try {
14
- const client = getClient();
14
+ const client = await getClientAsync();
15
15
  const apiKeys = await client.apiKeys.list();
16
16
  out.stopSpinner();
17
17
  out.list(apiKeys.map(key => ({
@@ -54,7 +54,7 @@ export function registerKeyCommands(program) {
54
54
  const out = createOutput(flags);
55
55
  out.startSpinner('Fetching API key...');
56
56
  try {
57
- const client = getClient();
57
+ const client = await getClientAsync();
58
58
  const key = await client.apiKeys.get(keyId);
59
59
  out.stopSpinner();
60
60
  out.record({
@@ -89,7 +89,7 @@ EXAMPLES
89
89
  const out = createOutput(flags);
90
90
  out.startSpinner('Creating API key...');
91
91
  try {
92
- const client = getClient();
92
+ const client = await getClientAsync();
93
93
  const params = {
94
94
  name,
95
95
  scopes: String(_opts.scopes || 'read,write').split(',').map((s) => s.trim()),
@@ -131,7 +131,7 @@ EXAMPLES
131
131
  }
132
132
  out.startSpinner('Updating API key...');
133
133
  try {
134
- const client = getClient();
134
+ const client = await getClientAsync();
135
135
  const params = {};
136
136
  if (_opts.name)
137
137
  params.name = String(_opts.name);
@@ -154,7 +154,7 @@ EXAMPLES
154
154
  const out = createOutput(flags);
155
155
  out.startSpinner('Revoking API key...');
156
156
  try {
157
- const client = getClient();
157
+ const client = await getClientAsync();
158
158
  await client.apiKeys.delete(keyId);
159
159
  out.success('API key revoked successfully', { id: keyId, revoked: true });
160
160
  }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerLinkCommands(program: Command): void;
@@ -0,0 +1,126 @@
1
+ import chalk from 'chalk';
2
+ import { getClientAsync } from '../client.js';
3
+ import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
4
+ import { createOutput, handleError } from '../utils/output.js';
5
+ export function registerLinkCommands(program) {
6
+ const links = program.command('links').description('Manage document links and backlinks');
7
+ // lsvault links list <vaultId> <path> — forward links
8
+ addGlobalFlags(links.command('list')
9
+ .description('List forward links from a document')
10
+ .argument('<vaultId>', 'Vault ID')
11
+ .argument('<path>', 'Document path'))
12
+ .action(async (vaultId, docPath, _opts) => {
13
+ const flags = resolveFlags(_opts);
14
+ const out = createOutput(flags);
15
+ out.startSpinner('Fetching links...');
16
+ try {
17
+ const client = await getClientAsync();
18
+ const linkList = await client.documents.getLinks(vaultId, docPath);
19
+ out.stopSpinner();
20
+ out.list(linkList.map(link => ({
21
+ targetPath: link.targetPath,
22
+ linkText: link.linkText,
23
+ resolved: link.isResolved ? 'Yes' : 'No',
24
+ })), {
25
+ emptyMessage: 'No forward links found.',
26
+ columns: [
27
+ { key: 'targetPath', header: 'Target' },
28
+ { key: 'linkText', header: 'Link Text' },
29
+ { key: 'resolved', header: 'Resolved' },
30
+ ],
31
+ textFn: (link) => {
32
+ const resolved = link.resolved === 'Yes' ? chalk.green('✓') : chalk.red('✗');
33
+ return ` ${resolved} [[${String(link.linkText)}]] → ${String(link.targetPath)}`;
34
+ },
35
+ });
36
+ }
37
+ catch (err) {
38
+ handleError(out, err, 'Failed to fetch links');
39
+ }
40
+ });
41
+ // lsvault links backlinks <vaultId> <path>
42
+ addGlobalFlags(links.command('backlinks')
43
+ .description('List backlinks pointing to a document')
44
+ .argument('<vaultId>', 'Vault ID')
45
+ .argument('<path>', 'Document path'))
46
+ .action(async (vaultId, docPath, _opts) => {
47
+ const flags = resolveFlags(_opts);
48
+ const out = createOutput(flags);
49
+ out.startSpinner('Fetching backlinks...');
50
+ try {
51
+ const client = await getClientAsync();
52
+ const backlinks = await client.documents.getBacklinks(vaultId, docPath);
53
+ out.stopSpinner();
54
+ out.list(backlinks.map(bl => ({
55
+ source: bl.sourceDocument.title || bl.sourceDocument.path,
56
+ linkText: bl.linkText,
57
+ context: bl.contextSnippet || '',
58
+ })), {
59
+ emptyMessage: 'No backlinks found.',
60
+ columns: [
61
+ { key: 'source', header: 'Source' },
62
+ { key: 'linkText', header: 'Link Text' },
63
+ { key: 'context', header: 'Context' },
64
+ ],
65
+ textFn: (bl) => {
66
+ const lines = [chalk.cyan(` ${String(bl.source)}`)];
67
+ lines.push(` Link: [[${String(bl.linkText)}]]`);
68
+ if (bl.context)
69
+ lines.push(` Context: ...${String(bl.context)}...`);
70
+ return lines.join('\n');
71
+ },
72
+ });
73
+ }
74
+ catch (err) {
75
+ handleError(out, err, 'Failed to fetch backlinks');
76
+ }
77
+ });
78
+ // lsvault links graph <vaultId>
79
+ addGlobalFlags(links.command('graph')
80
+ .description('Get the link graph for a vault')
81
+ .argument('<vaultId>', 'Vault ID'))
82
+ .action(async (vaultId, _opts) => {
83
+ const flags = resolveFlags(_opts);
84
+ const out = createOutput(flags);
85
+ out.startSpinner('Fetching link graph...');
86
+ try {
87
+ const client = await getClientAsync();
88
+ const graph = await client.vaults.getGraph(vaultId);
89
+ out.stopSpinner();
90
+ // For graph, output as JSON structure
91
+ process.stdout.write(JSON.stringify({ nodes: graph.nodes, edges: graph.edges }) + '\n');
92
+ }
93
+ catch (err) {
94
+ handleError(out, err, 'Failed to fetch link graph');
95
+ }
96
+ });
97
+ // lsvault links broken <vaultId>
98
+ addGlobalFlags(links.command('broken')
99
+ .description('List unresolved (broken) links in a vault')
100
+ .argument('<vaultId>', 'Vault ID'))
101
+ .action(async (vaultId, _opts) => {
102
+ const flags = resolveFlags(_opts);
103
+ const out = createOutput(flags);
104
+ out.startSpinner('Fetching unresolved links...');
105
+ try {
106
+ const client = await getClientAsync();
107
+ const unresolved = await client.vaults.getUnresolvedLinks(vaultId);
108
+ out.stopSpinner();
109
+ if (unresolved.length === 0) {
110
+ out.success('No broken links found!');
111
+ return;
112
+ }
113
+ // Format as grouped output
114
+ for (const group of unresolved) {
115
+ process.stdout.write(chalk.red(` ✗ ${group.targetPath}`) + '\n');
116
+ for (const ref of group.references) {
117
+ process.stdout.write(` ← ${ref.sourcePath} (${chalk.dim(ref.linkText)})` + '\n');
118
+ }
119
+ }
120
+ process.stdout.write(`\n ${chalk.yellow(`${unresolved.length} broken link target(s) found`)}` + '\n');
121
+ }
122
+ catch (err) {
123
+ handleError(out, err, 'Failed to fetch unresolved links');
124
+ }
125
+ });
126
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerMfaCommands(program: Command): void;
@@ -0,0 +1,224 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { getClientAsync } from '../client.js';
4
+ export function registerMfaCommands(program) {
5
+ const mfa = program.command('mfa').description('Multi-factor authentication management');
6
+ mfa.command('status')
7
+ .description('Show MFA status and configured methods')
8
+ .action(async () => {
9
+ const spinner = ora('Fetching MFA status...').start();
10
+ try {
11
+ const client = await getClientAsync();
12
+ const status = await client.mfa.getStatus();
13
+ spinner.stop();
14
+ console.log(chalk.bold('MFA Status'));
15
+ console.log(` Enabled: ${status.mfaEnabled ? chalk.green('Yes') : chalk.dim('No')}`);
16
+ console.log(` TOTP Configured: ${status.totpConfigured ? chalk.green('Yes') : chalk.dim('No')}`);
17
+ console.log(` Passkeys Registered: ${status.passkeyCount > 0 ? chalk.cyan(status.passkeyCount) : chalk.dim('0')}`);
18
+ console.log(` Backup Codes Left: ${status.backupCodesRemaining > 0 ? chalk.cyan(status.backupCodesRemaining) : chalk.yellow('0')}`);
19
+ if (status.passkeys.length > 0) {
20
+ console.log('');
21
+ console.log(chalk.bold('Registered Passkeys:'));
22
+ for (const passkey of status.passkeys) {
23
+ const lastUsed = passkey.lastUsedAt
24
+ ? new Date(passkey.lastUsedAt).toLocaleDateString()
25
+ : chalk.dim('never');
26
+ console.log(` - ${chalk.cyan(passkey.name)} (last used: ${lastUsed})`);
27
+ }
28
+ }
29
+ }
30
+ catch (err) {
31
+ spinner.fail('Failed to fetch MFA status');
32
+ console.error(err instanceof Error ? err.message : String(err));
33
+ }
34
+ });
35
+ mfa.command('setup-totp')
36
+ .description('Set up TOTP authenticator app (Google Authenticator, Authy, etc.)')
37
+ .action(async () => {
38
+ const spinner = ora('Generating TOTP secret...').start();
39
+ try {
40
+ const client = await getClientAsync();
41
+ const setup = await client.mfa.setupTotp();
42
+ spinner.stop();
43
+ console.log(chalk.bold('TOTP Setup'));
44
+ console.log('');
45
+ console.log(`Secret: ${chalk.cyan(setup.secret)}`);
46
+ console.log('');
47
+ console.log('Add this URI to your authenticator app:');
48
+ console.log(chalk.dim(setup.otpauthUri));
49
+ console.log('');
50
+ console.log(chalk.yellow('Note: QR codes cannot be displayed in the terminal.'));
51
+ console.log(chalk.yellow(' Copy the URI above to any authenticator app that supports otpauth:// URIs.'));
52
+ console.log('');
53
+ // Prompt for verification code
54
+ const code = await promptMfaCode();
55
+ if (!code) {
56
+ console.log(chalk.yellow('Setup cancelled.'));
57
+ return;
58
+ }
59
+ const verifySpinner = ora('Verifying code and enabling TOTP...').start();
60
+ const result = await client.mfa.verifyTotp(code);
61
+ verifySpinner.succeed('TOTP enabled successfully!');
62
+ console.log('');
63
+ console.log(chalk.bold.yellow('IMPORTANT: Save these backup codes securely!'));
64
+ console.log(chalk.dim('You can use them to access your account if you lose your authenticator device.'));
65
+ console.log('');
66
+ // Display backup codes in a grid (2 columns)
67
+ const codes = result.backupCodes;
68
+ for (let i = 0; i < codes.length; i += 2) {
69
+ const left = codes[i] || '';
70
+ const right = codes[i + 1] || '';
71
+ console.log(` ${chalk.cyan(left.padEnd(20))} ${chalk.cyan(right)}`);
72
+ }
73
+ console.log('');
74
+ }
75
+ catch (err) {
76
+ spinner.fail('TOTP setup failed');
77
+ console.error(err instanceof Error ? err.message : String(err));
78
+ }
79
+ });
80
+ mfa.command('disable-totp')
81
+ .description('Disable TOTP authentication (requires password)')
82
+ .action(async () => {
83
+ const password = await promptPassword();
84
+ if (!password) {
85
+ console.log(chalk.yellow('Operation cancelled.'));
86
+ return;
87
+ }
88
+ const spinner = ora('Disabling TOTP...').start();
89
+ try {
90
+ const client = await getClientAsync();
91
+ const result = await client.mfa.disableTotp(password);
92
+ spinner.succeed(result.message);
93
+ }
94
+ catch (err) {
95
+ spinner.fail('Failed to disable TOTP');
96
+ console.error(err instanceof Error ? err.message : String(err));
97
+ }
98
+ });
99
+ mfa.command('backup-codes')
100
+ .description('Show remaining backup code count or regenerate codes')
101
+ .option('--regenerate', 'Generate new backup codes (requires password, invalidates old codes)')
102
+ .action(async (opts) => {
103
+ if (opts.regenerate) {
104
+ // Regenerate backup codes
105
+ const password = await promptPassword();
106
+ if (!password) {
107
+ console.log(chalk.yellow('Operation cancelled.'));
108
+ return;
109
+ }
110
+ const spinner = ora('Regenerating backup codes...').start();
111
+ try {
112
+ const client = await getClientAsync();
113
+ const result = await client.mfa.regenerateBackupCodes(password);
114
+ spinner.succeed('Backup codes regenerated!');
115
+ console.log('');
116
+ console.log(chalk.bold.yellow('IMPORTANT: Save these new backup codes securely!'));
117
+ console.log(chalk.dim('All previous backup codes have been invalidated.'));
118
+ console.log('');
119
+ // Display backup codes in a grid (2 columns)
120
+ const codes = result.backupCodes;
121
+ for (let i = 0; i < codes.length; i += 2) {
122
+ const left = codes[i] || '';
123
+ const right = codes[i + 1] || '';
124
+ console.log(` ${chalk.cyan(left.padEnd(20))} ${chalk.cyan(right)}`);
125
+ }
126
+ console.log('');
127
+ }
128
+ catch (err) {
129
+ spinner.fail('Failed to regenerate backup codes');
130
+ console.error(err instanceof Error ? err.message : String(err));
131
+ }
132
+ }
133
+ else {
134
+ // Show backup code count
135
+ const spinner = ora('Fetching backup code count...').start();
136
+ try {
137
+ const client = await getClientAsync();
138
+ const status = await client.mfa.getStatus();
139
+ spinner.stop();
140
+ console.log(chalk.bold('Backup Codes'));
141
+ console.log(` Remaining: ${status.backupCodesRemaining > 0 ? chalk.cyan(status.backupCodesRemaining) : chalk.yellow('0')}`);
142
+ if (status.backupCodesRemaining === 0) {
143
+ console.log('');
144
+ console.log(chalk.yellow('You have no backup codes remaining.'));
145
+ console.log(chalk.yellow('Run `lsvault mfa backup-codes --regenerate` to generate new codes.'));
146
+ }
147
+ }
148
+ catch (err) {
149
+ spinner.fail('Failed to fetch backup code count');
150
+ console.error(err instanceof Error ? err.message : String(err));
151
+ }
152
+ }
153
+ });
154
+ }
155
+ /**
156
+ * Prompt for a password from stdin (non-echoing).
157
+ * Returns the password or null if stdin is not a TTY.
158
+ */
159
+ async function promptPassword() {
160
+ if (!process.stdin.isTTY) {
161
+ return null;
162
+ }
163
+ const readline = await import('node:readline');
164
+ return new Promise((resolve) => {
165
+ const rl = readline.createInterface({
166
+ input: process.stdin,
167
+ output: process.stderr,
168
+ terminal: true,
169
+ });
170
+ process.stderr.write('Password: ');
171
+ process.stdin.setRawMode?.(true);
172
+ let password = '';
173
+ const onData = (chunk) => {
174
+ const char = chunk.toString('utf-8');
175
+ if (char === '\n' || char === '\r' || char === '\u0004') {
176
+ process.stderr.write('\n');
177
+ process.stdin.setRawMode?.(false);
178
+ process.stdin.removeListener('data', onData);
179
+ rl.close();
180
+ resolve(password);
181
+ }
182
+ else if (char === '\u0003') {
183
+ // Ctrl+C
184
+ process.stderr.write('\n');
185
+ process.stdin.setRawMode?.(false);
186
+ process.stdin.removeListener('data', onData);
187
+ rl.close();
188
+ resolve(null);
189
+ }
190
+ else if (char === '\u007F' || char === '\b') {
191
+ // Backspace
192
+ if (password.length > 0) {
193
+ password = password.slice(0, -1);
194
+ }
195
+ }
196
+ else {
197
+ password += char;
198
+ }
199
+ };
200
+ process.stdin.on('data', onData);
201
+ process.stdin.resume();
202
+ });
203
+ }
204
+ /**
205
+ * Prompt for an MFA code from stdin (6 digits, echoed for visibility).
206
+ * Returns the code or null if stdin is not a TTY.
207
+ */
208
+ async function promptMfaCode() {
209
+ if (!process.stdin.isTTY) {
210
+ return null;
211
+ }
212
+ const readline = await import('node:readline');
213
+ return new Promise((resolve) => {
214
+ const rl = readline.createInterface({
215
+ input: process.stdin,
216
+ output: process.stderr,
217
+ terminal: true,
218
+ });
219
+ rl.question('Enter 6-digit code from authenticator app: ', (answer) => {
220
+ rl.close();
221
+ resolve(answer.trim() || null);
222
+ });
223
+ });
224
+ }
@@ -1,4 +1,4 @@
1
- import { getClient } from '../client.js';
1
+ import { getClientAsync } from '../client.js';
2
2
  import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
3
3
  import { createOutput, handleError } from '../utils/output.js';
4
4
  import chalk from 'chalk';
@@ -12,7 +12,7 @@ export function registerPublishCommands(program) {
12
12
  const out = createOutput(flags);
13
13
  out.startSpinner('Fetching published documents...');
14
14
  try {
15
- const client = getClient();
15
+ const client = await getClientAsync();
16
16
  const docs = await client.publish.listMine(vaultId);
17
17
  out.stopSpinner();
18
18
  out.list(docs.map(doc => ({
@@ -60,7 +60,7 @@ export function registerPublishCommands(program) {
60
60
  const out = createOutput(flags);
61
61
  out.startSpinner('Publishing document...');
62
62
  try {
63
- const client = getClient();
63
+ const client = await getClientAsync();
64
64
  const params = {
65
65
  slug: String(_opts.slug),
66
66
  };
@@ -96,7 +96,7 @@ export function registerPublishCommands(program) {
96
96
  const out = createOutput(flags);
97
97
  out.startSpinner('Updating published document...');
98
98
  try {
99
- const client = getClient();
99
+ const client = await getClientAsync();
100
100
  const params = {
101
101
  slug: String(_opts.slug),
102
102
  };
@@ -127,7 +127,7 @@ export function registerPublishCommands(program) {
127
127
  const out = createOutput(flags);
128
128
  out.startSpinner('Unpublishing document...');
129
129
  try {
130
- const client = getClient();
130
+ const client = await getClientAsync();
131
131
  await client.publish.delete(vaultId, docPath);
132
132
  out.success('Document unpublished successfully', { path: docPath, unpublished: true });
133
133
  }
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { getClient } from '../client.js';
2
+ import { getClientAsync } from '../client.js';
3
3
  import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
4
4
  import { createOutput, handleError } from '../utils/output.js';
5
5
  export function registerSearchCommands(program) {
@@ -9,26 +9,31 @@ export function registerSearchCommands(program) {
9
9
  .option('--vault <vaultId>', 'Limit search to a specific vault')
10
10
  .option('--tags <tags>', 'Filter by tags (comma-separated)')
11
11
  .option('--limit <n>', 'Maximum number of results', '20')
12
+ .option('--mode <mode>', 'Search mode: text, semantic, hybrid', 'text')
12
13
  .addHelpText('after', `
13
14
  EXAMPLES
14
15
  lsvault search "meeting notes"
15
16
  lsvault search "project plan" --vault abc123
16
- lsvault search "typescript" --tags dev,code --limit 5`))
17
+ lsvault search "typescript" --tags dev,code --limit 5
18
+ lsvault search "machine learning" --mode semantic`))
17
19
  .action(async (query, _opts) => {
18
20
  const flags = resolveFlags(_opts);
19
21
  const out = createOutput(flags);
20
22
  out.startSpinner('Searching...');
21
23
  try {
22
- const client = getClient();
24
+ const client = await getClientAsync();
25
+ const mode = _opts.mode;
23
26
  const response = await client.search.search({
24
27
  q: query,
25
28
  vault: _opts.vault,
26
29
  tags: _opts.tags,
27
30
  limit: parseInt(String(_opts.limit || '20'), 10),
31
+ mode: mode,
28
32
  });
29
33
  out.stopSpinner();
30
34
  if (flags.output === 'text') {
31
- out.status(chalk.dim(`${response.total} result(s) for "${response.query}":\n`));
35
+ const modeInfo = mode && mode !== 'text' ? `[${mode}] ` : '';
36
+ out.status(chalk.dim(`${modeInfo}${response.total} result(s) for "${response.query}":\n`));
32
37
  }
33
38
  out.list(response.results.map(r => ({
34
39
  title: r.title || r.path,
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { getClient } from '../client.js';
2
+ import { getClientAsync } from '../client.js';
3
3
  import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
4
4
  import { createOutput, handleError } from '../utils/output.js';
5
5
  export function registerShareCommands(program) {
@@ -13,7 +13,7 @@ export function registerShareCommands(program) {
13
13
  const out = createOutput(flags);
14
14
  out.startSpinner('Fetching share links...');
15
15
  try {
16
- const client = getClient();
16
+ const client = await getClientAsync();
17
17
  const links = await client.shares.list(vaultId, docPath);
18
18
  out.stopSpinner();
19
19
  out.list(links.map(link => ({
@@ -63,7 +63,7 @@ export function registerShareCommands(program) {
63
63
  const out = createOutput(flags);
64
64
  out.startSpinner('Creating share link...');
65
65
  try {
66
- const client = getClient();
66
+ const client = await getClientAsync();
67
67
  const params = {};
68
68
  if (_opts.permission)
69
69
  params.permission = String(_opts.permission);
@@ -110,7 +110,7 @@ export function registerShareCommands(program) {
110
110
  const out = createOutput(flags);
111
111
  out.startSpinner('Revoking share link...');
112
112
  try {
113
- const client = getClient();
113
+ const client = await getClientAsync();
114
114
  await client.shares.revoke(vaultId, shareId);
115
115
  out.success('Share link revoked successfully', { id: shareId, revoked: true });
116
116
  }
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { getClient } from '../client.js';
2
+ import { getClientAsync } from '../client.js';
3
3
  import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
4
4
  import { createOutput, handleError } from '../utils/output.js';
5
5
  import { formatBytes } from '../utils/format.js';
@@ -12,7 +12,7 @@ export function registerSubscriptionCommands(program) {
12
12
  const out = createOutput(flags);
13
13
  out.startSpinner('Fetching subscription...');
14
14
  try {
15
- const client = getClient();
15
+ const client = await getClientAsync();
16
16
  const data = await client.subscription.get();
17
17
  out.stopSpinner();
18
18
  if (flags.output === 'json') {
@@ -32,7 +32,7 @@ export function registerSubscriptionCommands(program) {
32
32
  process.stdout.write(chalk.dim('Usage:') + '\n');
33
33
  process.stdout.write(` Vaults: ${data.usage.vaultCount}\n`);
34
34
  process.stdout.write(` Storage: ${formatBytes(data.usage.totalStorageBytes)}\n`);
35
- process.stdout.write(` API calls today: ${data.usage.apiCallsToday}\n`);
35
+ process.stdout.write(` API calls this month: ${data.usage.apiCallsThisMonth}\n`);
36
36
  process.stdout.write(` AI tokens: ${data.usage.aiTokens}\n`);
37
37
  process.stdout.write(` Hook executions: ${data.usage.hookExecutions}\n`);
38
38
  process.stdout.write(` Webhook deliveries: ${data.usage.webhookDeliveries}\n`);
@@ -49,7 +49,7 @@ export function registerSubscriptionCommands(program) {
49
49
  const out = createOutput(flags);
50
50
  out.startSpinner('Fetching plans...');
51
51
  try {
52
- const client = getClient();
52
+ const client = await getClientAsync();
53
53
  const plans = await client.subscription.listPlans();
54
54
  out.stopSpinner();
55
55
  out.list(plans.map(p => ({ name: p.name, tier: p.tier, ...p.limits })), {
@@ -85,7 +85,7 @@ EXAMPLES
85
85
  const out = createOutput(flags);
86
86
  out.startSpinner('Creating checkout session...');
87
87
  try {
88
- const client = getClient();
88
+ const client = await getClientAsync();
89
89
  const session = await client.subscription.createCheckoutSession(tier, String(_opts.returnUrl));
90
90
  out.success('Checkout session created', { url: session.url });
91
91
  if (flags.output === 'text') {
@@ -104,7 +104,7 @@ EXAMPLES
104
104
  const out = createOutput(flags);
105
105
  out.startSpinner('Cancelling subscription...');
106
106
  try {
107
- const client = getClient();
107
+ const client = await getClientAsync();
108
108
  await client.subscription.cancel(_opts.reason);
109
109
  out.success('Subscription cancelled', { cancelled: true });
110
110
  }
@@ -120,7 +120,7 @@ EXAMPLES
120
120
  const out = createOutput(flags);
121
121
  out.startSpinner('Creating portal session...');
122
122
  try {
123
- const client = getClient();
123
+ const client = await getClientAsync();
124
124
  const portal = await client.subscription.createPortalSession(String(_opts.returnUrl));
125
125
  out.success('Portal session created', { url: portal.url });
126
126
  if (flags.output === 'text') {
@@ -138,7 +138,7 @@ EXAMPLES
138
138
  const out = createOutput(flags);
139
139
  out.startSpinner('Fetching invoices...');
140
140
  try {
141
- const client = getClient();
141
+ const client = await getClientAsync();
142
142
  const invoices = await client.subscription.listInvoices();
143
143
  out.stopSpinner();
144
144
  out.list(invoices.map(inv => ({