agentmemory-cli 1.1.0 → 1.3.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.
Files changed (72) hide show
  1. package/dist/commands/connect.d.ts +11 -0
  2. package/dist/commands/connect.d.ts.map +1 -0
  3. package/dist/commands/connect.js +232 -0
  4. package/dist/commands/connect.js.map +1 -0
  5. package/dist/commands/delete.d.ts.map +1 -1
  6. package/dist/commands/delete.js +3 -0
  7. package/dist/commands/delete.js.map +1 -1
  8. package/dist/commands/download.d.ts.map +1 -1
  9. package/dist/commands/download.js +3 -0
  10. package/dist/commands/download.js.map +1 -1
  11. package/dist/commands/export.d.ts.map +1 -1
  12. package/dist/commands/export.js +3 -0
  13. package/dist/commands/export.js.map +1 -1
  14. package/dist/commands/files.d.ts.map +1 -1
  15. package/dist/commands/files.js +3 -0
  16. package/dist/commands/files.js.map +1 -1
  17. package/dist/commands/heartbeat.d.ts +65 -0
  18. package/dist/commands/heartbeat.d.ts.map +1 -0
  19. package/dist/commands/heartbeat.js +176 -0
  20. package/dist/commands/heartbeat.js.map +1 -0
  21. package/dist/commands/import.d.ts.map +1 -1
  22. package/dist/commands/import.js +3 -0
  23. package/dist/commands/import.js.map +1 -1
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +39 -1
  26. package/dist/commands/init.js.map +1 -1
  27. package/dist/commands/list.d.ts.map +1 -1
  28. package/dist/commands/list.js +3 -0
  29. package/dist/commands/list.js.map +1 -1
  30. package/dist/commands/search.d.ts.map +1 -1
  31. package/dist/commands/search.js +3 -0
  32. package/dist/commands/search.js.map +1 -1
  33. package/dist/commands/secret.d.ts +25 -0
  34. package/dist/commands/secret.d.ts.map +1 -0
  35. package/dist/commands/secret.js +390 -0
  36. package/dist/commands/secret.js.map +1 -0
  37. package/dist/commands/store.d.ts.map +1 -1
  38. package/dist/commands/store.js +3 -0
  39. package/dist/commands/store.js.map +1 -1
  40. package/dist/commands/upload.d.ts.map +1 -1
  41. package/dist/commands/upload.js +3 -0
  42. package/dist/commands/upload.js.map +1 -1
  43. package/dist/index.js +105 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/lib/api.d.ts +23 -1
  46. package/dist/lib/api.d.ts.map +1 -1
  47. package/dist/lib/api.js +49 -0
  48. package/dist/lib/api.js.map +1 -1
  49. package/dist/lib/autosync.d.ts +14 -0
  50. package/dist/lib/autosync.d.ts.map +1 -0
  51. package/dist/lib/autosync.js +165 -0
  52. package/dist/lib/autosync.js.map +1 -0
  53. package/dist/types.d.ts +59 -0
  54. package/dist/types.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/src/commands/connect.ts +216 -0
  57. package/src/commands/delete.ts +4 -0
  58. package/src/commands/download.ts +4 -0
  59. package/src/commands/export.ts +4 -0
  60. package/src/commands/files.ts +4 -0
  61. package/src/commands/heartbeat.ts +241 -0
  62. package/src/commands/import.ts +4 -0
  63. package/src/commands/init.ts +44 -1
  64. package/src/commands/list.ts +4 -0
  65. package/src/commands/search.ts +4 -0
  66. package/src/commands/secret.ts +438 -0
  67. package/src/commands/store.ts +4 -0
  68. package/src/commands/upload.ts +4 -0
  69. package/src/index.ts +124 -2
  70. package/src/lib/api.ts +86 -1
  71. package/src/lib/autosync.ts +160 -0
  72. package/src/types.ts +67 -0
@@ -0,0 +1,438 @@
1
+ import chalk from 'chalk';
2
+ import * as fs from 'fs';
3
+ import { createInterface } from 'readline';
4
+ import { getApiKey } from '../lib/config.js';
5
+ import { listSecrets, getSecret, setSecret, deleteSecret, getAllSecrets } from '../lib/api.js';
6
+ import { autoSync } from '../lib/autosync.js';
7
+ import type { SecretType, SecretListItem } from '../types.js';
8
+
9
+ // Prompt helper
10
+ async function prompt(question: string): Promise<string> {
11
+ const rl = createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout,
14
+ });
15
+
16
+ return new Promise((resolve) => {
17
+ rl.question(question, (answer) => {
18
+ rl.close();
19
+ resolve(answer.trim());
20
+ });
21
+ });
22
+ }
23
+
24
+ async function confirm(question: string): Promise<boolean> {
25
+ const answer = await prompt(question);
26
+ return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
27
+ }
28
+
29
+ async function promptPassword(question: string): Promise<string> {
30
+ // Simple password prompt (in production, use a library that masks input)
31
+ return prompt(question);
32
+ }
33
+
34
+ const VALID_TYPES: SecretType[] = ['api_key', 'credential', 'connection_string', 'env_var', 'generic'];
35
+
36
+ // Helper to mask secret values
37
+ function maskValue(value: string): string {
38
+ if (value.length <= 8) {
39
+ return '*'.repeat(value.length);
40
+ }
41
+ return value.slice(0, 4) + '*'.repeat(value.length - 8) + value.slice(-4);
42
+ }
43
+
44
+ // Format secret type with icon
45
+ function formatType(type: SecretType): string {
46
+ const icons: Record<SecretType, string> = {
47
+ api_key: '🔑',
48
+ credential: '🔐',
49
+ connection_string: '🔗',
50
+ env_var: '📦',
51
+ generic: '📄',
52
+ };
53
+ return `${icons[type] || '📄'} ${type}`;
54
+ }
55
+
56
+ // Set a secret
57
+ export async function secretSetCommand(
58
+ name: string,
59
+ value: string,
60
+ options: {
61
+ type?: string;
62
+ description?: string;
63
+ json?: boolean;
64
+ }
65
+ ): Promise<void> {
66
+ const apiKey = getApiKey();
67
+
68
+ // Auto-sync in background (silent)
69
+ autoSync();
70
+
71
+ if (!apiKey) {
72
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
73
+ process.exit(1);
74
+ }
75
+
76
+ // Validate type
77
+ const type = (options.type || 'generic') as SecretType;
78
+ if (!VALID_TYPES.includes(type)) {
79
+ console.error(chalk.red(`Error: Invalid type. Must be one of: ${VALID_TYPES.join(', ')}`));
80
+ process.exit(1);
81
+ }
82
+
83
+ try {
84
+ const response = await setSecret(name, value, type, options.description);
85
+
86
+ if (options.json) {
87
+ console.log(JSON.stringify(response, null, 2));
88
+ } else {
89
+ const action = response.message?.includes('updated') ? 'updated' : 'created';
90
+ console.log(chalk.green(`✓ Secret "${name}" ${action} successfully`));
91
+ console.log(chalk.gray(` Type: ${formatType(type)}`));
92
+ if (options.description) {
93
+ console.log(chalk.gray(` Description: ${options.description}`));
94
+ }
95
+ }
96
+ } catch (error) {
97
+ if (options.json) {
98
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
99
+ } else {
100
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
101
+ }
102
+ process.exit(1);
103
+ }
104
+ }
105
+
106
+ // Get a secret value
107
+ export async function secretGetCommand(
108
+ name: string,
109
+ options: {
110
+ show?: boolean;
111
+ json?: boolean;
112
+ }
113
+ ): Promise<void> {
114
+ const apiKey = getApiKey();
115
+
116
+ // Auto-sync in background (silent)
117
+ autoSync();
118
+
119
+ if (!apiKey) {
120
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
121
+ process.exit(1);
122
+ }
123
+
124
+ try {
125
+ const secret = await getSecret(name);
126
+
127
+ if (options.json) {
128
+ // In JSON mode, always show full value
129
+ console.log(JSON.stringify(secret, null, 2));
130
+ } else {
131
+ console.log(chalk.cyan(`Secret: ${secret.name}`));
132
+ console.log(chalk.gray(`Type: ${formatType(secret.type)}`));
133
+ if (secret.description) {
134
+ console.log(chalk.gray(`Description: ${secret.description}`));
135
+ }
136
+ console.log();
137
+
138
+ // Show value (masked by default)
139
+ if (options.show) {
140
+ console.log(chalk.yellow('Value:'), secret.value);
141
+ } else {
142
+ console.log(chalk.yellow('Value:'), maskValue(secret.value || ''));
143
+ console.log(chalk.gray(' (use --show to reveal full value)'));
144
+ }
145
+ }
146
+ } catch (error) {
147
+ if (options.json) {
148
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
149
+ } else {
150
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
151
+ }
152
+ process.exit(1);
153
+ }
154
+ }
155
+
156
+ // List all secrets
157
+ export async function secretListCommand(
158
+ options: {
159
+ type?: string;
160
+ json?: boolean;
161
+ }
162
+ ): Promise<void> {
163
+ const apiKey = getApiKey();
164
+
165
+ // Auto-sync in background (silent)
166
+ autoSync();
167
+
168
+ if (!apiKey) {
169
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
170
+ process.exit(1);
171
+ }
172
+
173
+ try {
174
+ const type = options.type as SecretType | undefined;
175
+ if (type && !VALID_TYPES.includes(type)) {
176
+ console.error(chalk.red(`Error: Invalid type. Must be one of: ${VALID_TYPES.join(', ')}`));
177
+ process.exit(1);
178
+ }
179
+
180
+ const response = await listSecrets(500, type);
181
+
182
+ if (options.json) {
183
+ console.log(JSON.stringify(response, null, 2));
184
+ } else {
185
+ if (response.secrets.length === 0) {
186
+ console.log(chalk.yellow('No secrets found.'));
187
+ return;
188
+ }
189
+
190
+ console.log(chalk.cyan(`\nSecrets (${response.total} total):\n`));
191
+
192
+ for (const secret of response.secrets) {
193
+ console.log(` ${chalk.white(secret.name)}`);
194
+ console.log(` ${formatType(secret.type)}`);
195
+ if (secret.description) {
196
+ console.log(` ${chalk.gray(secret.description)}`);
197
+ }
198
+ console.log();
199
+ }
200
+ }
201
+ } catch (error) {
202
+ if (options.json) {
203
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
204
+ } else {
205
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
206
+ }
207
+ process.exit(1);
208
+ }
209
+ }
210
+
211
+ // Delete a secret
212
+ export async function secretDeleteCommand(
213
+ name: string,
214
+ options: {
215
+ force?: boolean;
216
+ json?: boolean;
217
+ }
218
+ ): Promise<void> {
219
+ const apiKey = getApiKey();
220
+
221
+ // Auto-sync in background (silent)
222
+ autoSync();
223
+
224
+ if (!apiKey) {
225
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
226
+ process.exit(1);
227
+ }
228
+
229
+ // Confirmation (unless --force)
230
+ if (!options.force && !options.json) {
231
+ const confirmed = await confirm(`Are you sure you want to delete secret "${name}"? (y/N): `);
232
+
233
+ if (!confirmed) {
234
+ console.log(chalk.yellow('Cancelled.'));
235
+ return;
236
+ }
237
+ }
238
+
239
+ try {
240
+ await deleteSecret(name);
241
+
242
+ if (options.json) {
243
+ console.log(JSON.stringify({ success: true, deleted: name }));
244
+ } else {
245
+ console.log(chalk.green(`✓ Secret "${name}" deleted successfully`));
246
+ }
247
+ } catch (error) {
248
+ if (options.json) {
249
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
250
+ } else {
251
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
252
+ }
253
+ process.exit(1);
254
+ }
255
+ }
256
+
257
+ // Export secrets to file (encrypted with password)
258
+ export async function secretsExportCommand(
259
+ options: {
260
+ output?: string;
261
+ json?: boolean;
262
+ }
263
+ ): Promise<void> {
264
+ const apiKey = getApiKey();
265
+
266
+ // Auto-sync in background (silent)
267
+ autoSync();
268
+
269
+ if (!apiKey) {
270
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
271
+ process.exit(1);
272
+ }
273
+
274
+ try {
275
+ // Fetch all secrets with values
276
+ const secretsList = await getAllSecrets();
277
+
278
+ // Get full values for each secret
279
+ const secretsWithValues: Array<{
280
+ name: string;
281
+ value: string;
282
+ type: string;
283
+ description?: string;
284
+ }> = [];
285
+
286
+ for (const secretItem of secretsList) {
287
+ const fullSecret = await getSecret(secretItem.name);
288
+ secretsWithValues.push({
289
+ name: fullSecret.name,
290
+ value: fullSecret.value || '',
291
+ type: fullSecret.type,
292
+ description: fullSecret.description,
293
+ });
294
+ }
295
+
296
+ // Ask for password for encryption
297
+ const password = await promptPassword('Enter password to encrypt secrets (min 8 chars): ');
298
+
299
+ if (!password || password.length < 8) {
300
+ console.error(chalk.red('Error: Password must be at least 8 characters'));
301
+ process.exit(1);
302
+ }
303
+
304
+ // Simple XOR encryption (for demonstration - in production use proper crypto)
305
+ const exportData = {
306
+ version: 1,
307
+ encrypted: true,
308
+ secrets: secretsWithValues.map(s => ({
309
+ ...s,
310
+ value: simpleEncrypt(s.value, password),
311
+ })),
312
+ exported_at: new Date().toISOString(),
313
+ };
314
+
315
+ const outputPath = options.output || 'secrets-export.json';
316
+ fs.writeFileSync(outputPath, JSON.stringify(exportData, null, 2));
317
+
318
+ if (options.json) {
319
+ console.log(JSON.stringify({ success: true, file: outputPath, count: secretsWithValues.length }));
320
+ } else {
321
+ console.log(chalk.green(`✓ Exported ${secretsWithValues.length} secrets to ${outputPath}`));
322
+ console.log(chalk.yellow('⚠ Keep this file secure! It contains encrypted secrets.'));
323
+ }
324
+ } catch (error) {
325
+ if (options.json) {
326
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
327
+ } else {
328
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
329
+ }
330
+ process.exit(1);
331
+ }
332
+ }
333
+
334
+ // Import secrets from file
335
+ export async function secretsImportCommand(
336
+ file: string,
337
+ options: {
338
+ json?: boolean;
339
+ }
340
+ ): Promise<void> {
341
+ const apiKey = getApiKey();
342
+
343
+ // Auto-sync in background (silent)
344
+ autoSync();
345
+
346
+ if (!apiKey) {
347
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
348
+ process.exit(1);
349
+ }
350
+
351
+ if (!fs.existsSync(file)) {
352
+ console.error(chalk.red(`Error: File not found: ${file}`));
353
+ process.exit(1);
354
+ }
355
+
356
+ try {
357
+ const content = fs.readFileSync(file, 'utf-8');
358
+ const data = JSON.parse(content) as {
359
+ version: number;
360
+ encrypted: boolean;
361
+ secrets: Array<{
362
+ name: string;
363
+ value: string;
364
+ type: string;
365
+ description?: string;
366
+ }>;
367
+ };
368
+
369
+ let secrets = data.secrets;
370
+
371
+ // Decrypt if encrypted
372
+ if (data.encrypted) {
373
+ const password = await promptPassword('Enter password to decrypt secrets: ');
374
+
375
+ secrets = secrets.map(s => ({
376
+ ...s,
377
+ value: simpleDecrypt(s.value, password),
378
+ }));
379
+ }
380
+
381
+ // Import secrets
382
+ let imported = 0;
383
+ let errors = 0;
384
+
385
+ for (const secret of secrets) {
386
+ try {
387
+ await setSecret(
388
+ secret.name,
389
+ secret.value,
390
+ secret.type as SecretType,
391
+ secret.description
392
+ );
393
+ imported++;
394
+ if (!options.json) {
395
+ console.log(chalk.green(`✓ Imported: ${secret.name}`));
396
+ }
397
+ } catch (err) {
398
+ errors++;
399
+ if (!options.json) {
400
+ console.log(chalk.red(`✗ Failed: ${secret.name} - ${err instanceof Error ? err.message : 'Unknown error'}`));
401
+ }
402
+ }
403
+ }
404
+
405
+ if (options.json) {
406
+ console.log(JSON.stringify({ success: true, imported, errors, total: secrets.length }));
407
+ } else {
408
+ console.log();
409
+ console.log(chalk.cyan(`Import complete: ${imported} imported, ${errors} errors`));
410
+ }
411
+ } catch (error) {
412
+ if (options.json) {
413
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
414
+ } else {
415
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
416
+ }
417
+ process.exit(1);
418
+ }
419
+ }
420
+
421
+ // Simple XOR-based encryption (for demonstration)
422
+ // In production, use Node.js crypto module with AES-256-GCM
423
+ function simpleEncrypt(text: string, password: string): string {
424
+ const result: number[] = [];
425
+ for (let i = 0; i < text.length; i++) {
426
+ result.push(text.charCodeAt(i) ^ password.charCodeAt(i % password.length));
427
+ }
428
+ return Buffer.from(result).toString('base64');
429
+ }
430
+
431
+ function simpleDecrypt(encoded: string, password: string): string {
432
+ const data = Buffer.from(encoded, 'base64');
433
+ const result: string[] = [];
434
+ for (let i = 0; i < data.length; i++) {
435
+ result.push(String.fromCharCode(data[i] ^ password.charCodeAt(i % password.length)));
436
+ }
437
+ return result.join('');
438
+ }
@@ -1,6 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import { storeMemory } from '../lib/api.js';
3
3
  import { isConfigured } from '../lib/config.js';
4
+ import { autoSync } from '../lib/autosync.js';
4
5
 
5
6
  interface StoreOptions {
6
7
  category?: string;
@@ -17,6 +18,9 @@ export async function storeCommand(
17
18
  process.exit(1);
18
19
  }
19
20
 
21
+ // Auto-sync in background (silent)
22
+ autoSync();
23
+
20
24
  try {
21
25
  // Build metadata
22
26
  let metadata: Record<string, unknown> = {};
@@ -2,6 +2,7 @@ import chalk from 'chalk';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import { getApiKey, getApiUrl } from '../lib/config.js';
5
+ import { autoSync } from '../lib/autosync.js';
5
6
 
6
7
  export async function uploadCommand(
7
8
  filePath: string,
@@ -13,6 +14,9 @@ export async function uploadCommand(
13
14
  process.exit(1);
14
15
  }
15
16
 
17
+ // Auto-sync in background (silent)
18
+ autoSync();
19
+
16
20
  // Check if file exists
17
21
  if (!fs.existsSync(filePath)) {
18
22
  console.error(chalk.red(`File not found: ${filePath}`));
package/src/index.ts CHANGED
@@ -13,13 +13,23 @@ import { importCommand } from './commands/import.js';
13
13
  import { uploadCommand } from './commands/upload.js';
14
14
  import { filesCommand } from './commands/files.js';
15
15
  import { downloadCommand } from './commands/download.js';
16
+ import {
17
+ secretSetCommand,
18
+ secretGetCommand,
19
+ secretListCommand,
20
+ secretDeleteCommand,
21
+ secretsExportCommand,
22
+ secretsImportCommand
23
+ } from './commands/secret.js';
24
+ import { connectCommand, statusCommand } from './commands/connect.js';
25
+ import { heartbeatCommand, watchCommand, disconnectCommand } from './commands/heartbeat.js';
16
26
 
17
27
  const program = new Command();
18
28
 
19
29
  program
20
30
  .name('agentmemory')
21
31
  .description('CLI tool for AgentMemory - persistent cloud memory for AI agents')
22
- .version('1.0.0');
32
+ .version('1.3.0');
23
33
 
24
34
  // Init command
25
35
  program
@@ -27,6 +37,48 @@ program
27
37
  .description('Initialize AgentMemory CLI with your API key')
28
38
  .action(initCommand);
29
39
 
40
+ // Connect command (auto-sync)
41
+ program
42
+ .command('connect')
43
+ .description('Connect and sync all data from cloud')
44
+ .option('--offline', 'Use cached data (no network)')
45
+ .option('--no-memories', 'Skip syncing memories to MEMORY.md')
46
+ .option('--no-secrets', 'Skip showing secrets list')
47
+ .option('--json', 'Output as JSON')
48
+ .action(connectCommand);
49
+
50
+ // Status command
51
+ program
52
+ .command('status')
53
+ .description('Check connection status and data counts')
54
+ .option('--json', 'Output as JSON')
55
+ .action(statusCommand);
56
+
57
+ // Heartbeat command
58
+ program
59
+ .command('heartbeat')
60
+ .description('Send heartbeat signal (marks agent as online)')
61
+ .option('--no-sync', 'Skip syncing data')
62
+ .option('-c, --continuous', 'Run continuous heartbeat')
63
+ .option('-i, --interval <seconds>', 'Heartbeat interval in seconds', '60')
64
+ .option('--json', 'Output as JSON')
65
+ .action(heartbeatCommand);
66
+
67
+ // Watch command (continuous heartbeat with auto-sync)
68
+ program
69
+ .command('watch')
70
+ .description('Keep agent online with continuous heartbeat and auto-sync')
71
+ .option('-i, --interval <seconds>', 'Heartbeat interval in seconds', '60')
72
+ .option('--json', 'Output as JSON')
73
+ .action(watchCommand);
74
+
75
+ // Disconnect command
76
+ program
77
+ .command('disconnect')
78
+ .description('Mark agent as offline')
79
+ .option('--json', 'Output as JSON')
80
+ .action(disconnectCommand);
81
+
30
82
  // Store command
31
83
  program
32
84
  .command('store <content>')
@@ -110,6 +162,59 @@ program
110
162
  .option('-i, --info', 'Show file info without downloading')
111
163
  .action(downloadCommand);
112
164
 
165
+ // Secret commands (grouped)
166
+ const secretCmd = program
167
+ .command('secret')
168
+ .description('Manage secrets vault');
169
+
170
+ // secret set
171
+ secretCmd
172
+ .command('set <name> <value>')
173
+ .description('Store a secret')
174
+ .option('-t, --type <type>', 'Secret type (api_key, credential, connection_string, env_var, generic)', 'generic')
175
+ .option('-d, --description <text>', 'Description for the secret')
176
+ .option('--json', 'Output as JSON')
177
+ .action(secretSetCommand);
178
+
179
+ // secret get
180
+ secretCmd
181
+ .command('get <name>')
182
+ .description('Retrieve a secret')
183
+ .option('-s, --show', 'Show full value (not masked)')
184
+ .option('--json', 'Output as JSON')
185
+ .action(secretGetCommand);
186
+
187
+ // secret list
188
+ secretCmd
189
+ .command('list')
190
+ .description('List all secret names')
191
+ .option('-t, --type <type>', 'Filter by type')
192
+ .option('--json', 'Output as JSON')
193
+ .action(secretListCommand);
194
+
195
+ // secret delete
196
+ secretCmd
197
+ .command('delete <name>')
198
+ .description('Delete a secret')
199
+ .option('-f, --force', 'Skip confirmation')
200
+ .option('--json', 'Output as JSON')
201
+ .action(secretDeleteCommand);
202
+
203
+ // secrets export (note: "secrets" plural for bulk operations)
204
+ program
205
+ .command('secrets-export')
206
+ .description('Export all secrets (encrypted with password)')
207
+ .option('-o, --output <file>', 'Output file path', 'secrets-export.json')
208
+ .option('--json', 'Output as JSON')
209
+ .action(secretsExportCommand);
210
+
211
+ // secrets import
212
+ program
213
+ .command('secrets-import <file>')
214
+ .description('Import secrets from encrypted file')
215
+ .option('--json', 'Output as JSON')
216
+ .action(secretsImportCommand);
217
+
113
218
  // Custom help
114
219
  program.addHelpText('after', `
115
220
  ${chalk.cyan('Examples:')}
@@ -127,6 +232,23 @@ ${chalk.cyan('Examples:')}
127
232
  $ agentmemory files --type image # Filter by type
128
233
  $ agentmemory download <id> # Download a file
129
234
 
235
+ ${chalk.cyan('Secrets Vault:')}
236
+ $ agentmemory secret set OPENAI_KEY sk-xxx --type api_key
237
+ $ agentmemory secret get OPENAI_KEY # Shows masked value
238
+ $ agentmemory secret get OPENAI_KEY --show # Shows full value
239
+ $ agentmemory secret list # List all secrets
240
+ $ agentmemory secret delete OPENAI_KEY # Delete a secret
241
+ $ agentmemory secrets-export # Export encrypted backup
242
+ $ agentmemory secrets-import backup.json # Import from backup
243
+
244
+ ${chalk.cyan('Auto-Sync & Heartbeat:')}
245
+ $ agentmemory connect # Sync all data from cloud
246
+ $ agentmemory status # Check connection status
247
+ $ agentmemory heartbeat # Send single heartbeat with sync
248
+ $ agentmemory watch # Continuous heartbeat (keeps online)
249
+ $ agentmemory watch -i 30 # Heartbeat every 30 seconds
250
+ $ agentmemory disconnect # Mark agent as offline
251
+
130
252
  ${chalk.cyan('Documentation:')}
131
253
  https://agentmemory.cloud/docs
132
254
 
@@ -140,7 +262,7 @@ program.parse();
140
262
  // Show help if no command provided
141
263
  if (!process.argv.slice(2).length) {
142
264
  console.log(chalk.cyan(`
143
- 🧠 AgentMemory CLI v1.0.0
265
+ 🧠 AgentMemory CLI v1.3.0
144
266
 
145
267
  Persistent cloud memory for AI agents.
146
268
  `));