agentmemory-cli 1.0.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.
- package/dist/commands/connect.d.ts +11 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +232 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +3 -0
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/download.d.ts +5 -0
- package/dist/commands/download.d.ts.map +1 -0
- package/dist/commands/download.js +82 -0
- package/dist/commands/download.js.map +1 -0
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +3 -0
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/files.d.ts +6 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/files.js +101 -0
- package/dist/commands/files.js.map +1 -0
- package/dist/commands/heartbeat.d.ts +65 -0
- package/dist/commands/heartbeat.d.ts.map +1 -0
- package/dist/commands/heartbeat.js +176 -0
- package/dist/commands/heartbeat.js.map +1 -0
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +3 -0
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +39 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +3 -0
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +3 -0
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/secret.d.ts +25 -0
- package/dist/commands/secret.d.ts.map +1 -0
- package/dist/commands/secret.js +390 -0
- package/dist/commands/secret.js.map +1 -0
- package/dist/commands/store.d.ts.map +1 -1
- package/dist/commands/store.js +3 -0
- package/dist/commands/store.js.map +1 -1
- package/dist/commands/upload.d.ts +4 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +110 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/index.js +136 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +23 -1
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +49 -0
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/autosync.d.ts +14 -0
- package/dist/lib/autosync.d.ts.map +1 -0
- package/dist/lib/autosync.js +165 -0
- package/dist/lib/autosync.js.map +1 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/commands/connect.ts +216 -0
- package/src/commands/delete.ts +4 -0
- package/src/commands/download.ts +105 -0
- package/src/commands/export.ts +4 -0
- package/src/commands/files.ts +119 -0
- package/src/commands/heartbeat.ts +241 -0
- package/src/commands/import.ts +4 -0
- package/src/commands/init.ts +44 -1
- package/src/commands/list.ts +4 -0
- package/src/commands/search.ts +4 -0
- package/src/commands/secret.ts +438 -0
- package/src/commands/store.ts +4 -0
- package/src/commands/upload.ts +117 -0
- package/src/index.ts +158 -2
- package/src/lib/api.ts +86 -1
- package/src/lib/autosync.ts +160 -0
- package/src/types.ts +67 -0
|
@@ -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
|
+
}
|
package/src/commands/import.ts
CHANGED
|
@@ -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}`));
|
package/src/commands/init.ts
CHANGED
|
@@ -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
|
|
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
|
}
|
package/src/commands/list.ts
CHANGED
|
@@ -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;
|
package/src/commands/search.ts
CHANGED
|
@@ -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);
|