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
@@ -1,5 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { getApiKey, getApiUrl } from '../lib/config.js';
3
+ import { autoSync } from '../lib/autosync.js';
3
4
 
4
5
  interface FileMemory {
5
6
  id: string;
@@ -31,6 +32,9 @@ export async function filesCommand(options: {
31
32
  process.exit(1);
32
33
  }
33
34
 
35
+ // Auto-sync in background (silent)
36
+ autoSync();
37
+
34
38
  try {
35
39
  const apiUrl = getApiUrl();
36
40
  const params = new URLSearchParams();
@@ -0,0 +1,241 @@
1
+ import chalk from 'chalk';
2
+ import { getApiKey, getApiUrl, getMemoryFilePath } from '../lib/config.js';
3
+ import { writeMemoryFile } from '../lib/sync.js';
4
+
5
+ interface HeartbeatResponse {
6
+ status: string;
7
+ agent: {
8
+ id: string;
9
+ name: string;
10
+ memory_count: number;
11
+ is_online: boolean;
12
+ last_active: string;
13
+ };
14
+ plan: {
15
+ name: string;
16
+ activated: boolean;
17
+ };
18
+ heartbeat: {
19
+ received_at: string;
20
+ next_heartbeat: string;
21
+ interval_seconds: number;
22
+ };
23
+ sync?: {
24
+ memories: {
25
+ items: Array<{
26
+ id: string;
27
+ content: string;
28
+ metadata?: Record<string, unknown>;
29
+ created_at: string;
30
+ updated_at?: string;
31
+ }>;
32
+ count: number;
33
+ has_more: boolean;
34
+ };
35
+ secrets: {
36
+ items: Array<{
37
+ id: string;
38
+ name: string;
39
+ type: string;
40
+ description?: string;
41
+ }>;
42
+ count: number;
43
+ has_more: boolean;
44
+ };
45
+ synced_at: string;
46
+ };
47
+ error?: string;
48
+ }
49
+
50
+ // Send a single heartbeat
51
+ export async function sendHeartbeat(options: {
52
+ sync?: boolean;
53
+ memoriesLimit?: number;
54
+ secretsLimit?: number;
55
+ } = {}): Promise<HeartbeatResponse | null> {
56
+ const apiKey = getApiKey();
57
+ const apiUrl = getApiUrl();
58
+
59
+ if (!apiKey) {
60
+ return null;
61
+ }
62
+
63
+ try {
64
+ const body: Record<string, unknown> = {};
65
+ if (options.sync !== undefined) body.sync = options.sync;
66
+ if (options.memoriesLimit) body.memories_limit = options.memoriesLimit;
67
+ if (options.secretsLimit) body.secrets_limit = options.secretsLimit;
68
+
69
+ const response = await fetch(`${apiUrl}/heartbeat`, {
70
+ method: 'POST',
71
+ headers: {
72
+ 'Authorization': `Bearer ${apiKey}`,
73
+ 'Content-Type': 'application/json',
74
+ },
75
+ body: JSON.stringify(body),
76
+ });
77
+
78
+ return await response.json() as HeartbeatResponse;
79
+ } catch (error) {
80
+ console.error('Heartbeat error:', error);
81
+ return null;
82
+ }
83
+ }
84
+
85
+ // Send disconnect signal
86
+ export async function sendDisconnect(): Promise<boolean> {
87
+ const apiKey = getApiKey();
88
+ const apiUrl = getApiUrl();
89
+
90
+ if (!apiKey) {
91
+ return false;
92
+ }
93
+
94
+ try {
95
+ const response = await fetch(`${apiUrl}/heartbeat`, {
96
+ method: 'DELETE',
97
+ headers: {
98
+ 'Authorization': `Bearer ${apiKey}`,
99
+ },
100
+ });
101
+
102
+ return response.ok;
103
+ } catch {
104
+ return false;
105
+ }
106
+ }
107
+
108
+ // Heartbeat command - single heartbeat with optional sync
109
+ export async function heartbeatCommand(options: {
110
+ sync?: boolean;
111
+ continuous?: boolean;
112
+ interval?: string;
113
+ json?: boolean;
114
+ }): Promise<void> {
115
+ const apiKey = getApiKey();
116
+
117
+ if (!apiKey) {
118
+ if (options.json) {
119
+ console.log(JSON.stringify({ error: 'Not configured' }));
120
+ } else {
121
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
122
+ }
123
+ process.exit(1);
124
+ }
125
+
126
+ // Continuous heartbeat mode
127
+ if (options.continuous) {
128
+ const interval = parseInt(options.interval || '60') * 1000;
129
+
130
+ if (!options.json) {
131
+ console.log(chalk.cyan('Starting continuous heartbeat...'));
132
+ console.log(chalk.gray(`Interval: ${interval / 1000}s | Press Ctrl+C to stop`));
133
+ console.log();
134
+ }
135
+
136
+ // Handle graceful shutdown
137
+ process.on('SIGINT', async () => {
138
+ if (!options.json) {
139
+ console.log(chalk.yellow('\nDisconnecting...'));
140
+ }
141
+ await sendDisconnect();
142
+ if (!options.json) {
143
+ console.log(chalk.green('Disconnected.'));
144
+ }
145
+ process.exit(0);
146
+ });
147
+
148
+ // Initial heartbeat
149
+ await doHeartbeat(options);
150
+
151
+ // Continuous heartbeats
152
+ setInterval(async () => {
153
+ await doHeartbeat(options);
154
+ }, interval);
155
+
156
+ return;
157
+ }
158
+
159
+ // Single heartbeat
160
+ await doHeartbeat(options);
161
+ }
162
+
163
+ async function doHeartbeat(options: { sync?: boolean; json?: boolean }): Promise<void> {
164
+ const syncEnabled = options.sync !== false;
165
+
166
+ const response = await sendHeartbeat({ sync: syncEnabled });
167
+
168
+ if (!response || response.error) {
169
+ if (options.json) {
170
+ console.log(JSON.stringify({ error: response?.error || 'Heartbeat failed' }));
171
+ } else {
172
+ console.error(chalk.red(`Heartbeat failed: ${response?.error || 'Unknown error'}`));
173
+ }
174
+ return;
175
+ }
176
+
177
+ if (options.json) {
178
+ console.log(JSON.stringify(response, null, 2));
179
+ return;
180
+ }
181
+
182
+ // Display heartbeat info
183
+ const time = new Date().toLocaleTimeString();
184
+ console.log(chalk.green(`💓 [${time}] Heartbeat sent`));
185
+ console.log(chalk.gray(` Agent: ${response.agent.name} | Online: ${response.agent.is_online}`));
186
+
187
+ // Sync data if available
188
+ if (response.sync) {
189
+ const { memories, secrets } = response.sync;
190
+ console.log(chalk.gray(` Synced: ${memories.count} memories, ${secrets.count} secrets`));
191
+
192
+ // Save memories to local file
193
+ if (memories.items.length > 0) {
194
+ try {
195
+ const memoryFilePath = getMemoryFilePath();
196
+ writeMemoryFile(memoryFilePath, memories.items.map(m => ({
197
+ ...m,
198
+ updated_at: m.updated_at || m.created_at,
199
+ })));
200
+ } catch {
201
+ // Silently ignore file write errors in heartbeat
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ // Watch command - continuous heartbeat with auto-sync
208
+ export async function watchCommand(options: {
209
+ interval?: string;
210
+ json?: boolean;
211
+ }): Promise<void> {
212
+ return heartbeatCommand({
213
+ ...options,
214
+ continuous: true,
215
+ sync: true,
216
+ });
217
+ }
218
+
219
+ // Disconnect command
220
+ export async function disconnectCommand(options: { json?: boolean }): Promise<void> {
221
+ const apiKey = getApiKey();
222
+
223
+ if (!apiKey) {
224
+ if (options.json) {
225
+ console.log(JSON.stringify({ error: 'Not configured' }));
226
+ } else {
227
+ console.error(chalk.red('Error: Not configured. Run "agentmemory init" first.'));
228
+ }
229
+ process.exit(1);
230
+ }
231
+
232
+ const success = await sendDisconnect();
233
+
234
+ if (options.json) {
235
+ console.log(JSON.stringify({ success, disconnected: success }));
236
+ } else if (success) {
237
+ console.log(chalk.green('✓ Disconnected from AgentMemory'));
238
+ } else {
239
+ console.error(chalk.red('Failed to disconnect'));
240
+ }
241
+ }
@@ -2,6 +2,7 @@ import chalk from 'chalk';
2
2
  import * as fs from 'fs';
3
3
  import { storeMemory } from '../lib/api.js';
4
4
  import { isConfigured } from '../lib/config.js';
5
+ import { autoSync } from '../lib/autosync.js';
5
6
  import type { Memory } from '../types.js';
6
7
 
7
8
  interface ImportOptions {
@@ -24,6 +25,9 @@ export async function importCommand(
24
25
  process.exit(1);
25
26
  }
26
27
 
28
+ // Auto-sync in background (silent)
29
+ autoSync();
30
+
27
31
  // Check if file exists
28
32
  if (!fs.existsSync(file)) {
29
33
  console.log(chalk.red(`❌ File not found: ${file}`));
@@ -1,6 +1,9 @@
1
1
  import chalk from 'chalk';
2
2
  import { createInterface } from 'readline';
3
3
  import { saveConfig, loadConfig, getConfigPath, isConfigured } from '../lib/config.js';
4
+ import { syncConnect } from '../lib/api.js';
5
+ import { writeMemoryFile } from '../lib/sync.js';
6
+ import { getMemoryFilePath } from '../lib/config.js';
4
7
 
5
8
  async function prompt(question: string): Promise<string> {
6
9
  const rl = createInterface({
@@ -63,9 +66,49 @@ export async function initCommand(): Promise<void> {
63
66
  console.log(chalk.green('\n✅ Configuration saved!'));
64
67
  console.log(chalk.dim(` Config file: ${getConfigPath()}\n`));
65
68
 
69
+ // Auto-sync on first setup
70
+ console.log(chalk.cyan('Connecting and syncing data...'));
71
+
72
+ try {
73
+ const response = await syncConnect({
74
+ include_files: true,
75
+ memories_limit: 1000,
76
+ secrets_limit: 100,
77
+ });
78
+
79
+ console.log(chalk.green('✓ Connected successfully!'));
80
+ console.log();
81
+ console.log(chalk.cyan('Agent:'), response.agent.name);
82
+ console.log(chalk.cyan('Plan:'), response.plan.name);
83
+ console.log();
84
+
85
+ // Save memories to local file
86
+ if (response.sync.memories.items.length > 0) {
87
+ const memoryFilePath = getMemoryFilePath();
88
+ writeMemoryFile(memoryFilePath, response.sync.memories.items.map(m => ({
89
+ ...m,
90
+ updated_at: m.updated_at || m.created_at,
91
+ })));
92
+ console.log(chalk.green(`✓ Synced ${response.sync.memories.items.length} memories to ${memoryFilePath}`));
93
+ }
94
+
95
+ // Show secrets count
96
+ if (response.sync.secrets.items.length > 0) {
97
+ console.log(chalk.green(`✓ Found ${response.sync.secrets.items.length} secrets in vault`));
98
+ }
99
+
100
+ console.log();
101
+ } catch (error) {
102
+ console.log(chalk.yellow(`⚠ Could not sync: ${error instanceof Error ? error.message : 'Unknown error'}`));
103
+ console.log(chalk.dim(' You can try again later with: agentmemory connect'));
104
+ console.log();
105
+ }
106
+
66
107
  console.log(chalk.cyan('You can now use AgentMemory CLI:'));
67
108
  console.log(chalk.dim(' agentmemory store "Your memory content"'));
68
109
  console.log(chalk.dim(' agentmemory search "query"'));
69
110
  console.log(chalk.dim(' agentmemory list'));
70
- console.log(chalk.dim(' agentmemory sync\n'));
111
+ console.log(chalk.dim(' agentmemory sync'));
112
+ console.log(chalk.dim(' agentmemory connect # Sync all data'));
113
+ console.log(chalk.dim(' agentmemory secret set KEY val # Store secrets\n'));
71
114
  }
@@ -1,6 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import { listMemories } from '../lib/api.js';
3
3
  import { isConfigured } from '../lib/config.js';
4
+ import { autoSync } from '../lib/autosync.js';
4
5
 
5
6
  interface ListOptions {
6
7
  limit?: string;
@@ -14,6 +15,9 @@ export async function listCommand(options: ListOptions): Promise<void> {
14
15
  process.exit(1);
15
16
  }
16
17
 
18
+ // Auto-sync in background (silent)
19
+ autoSync();
20
+
17
21
  try {
18
22
  const limit = options.limit ? parseInt(options.limit, 10) : 50;
19
23
  const offset = options.offset ? parseInt(options.offset, 10) : 0;
@@ -1,6 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import { searchMemories } from '../lib/api.js';
3
3
  import { isConfigured } from '../lib/config.js';
4
+ import { autoSync } from '../lib/autosync.js';
4
5
 
5
6
  interface SearchOptions {
6
7
  limit?: string;
@@ -16,6 +17,9 @@ export async function searchCommand(
16
17
  process.exit(1);
17
18
  }
18
19
 
20
+ // Auto-sync in background (silent)
21
+ autoSync();
22
+
19
23
  try {
20
24
  const limit = options.limit ? parseInt(options.limit, 10) : 10;
21
25
  const memories = await searchMemories(query, limit);