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
package/src/index.ts
CHANGED
|
@@ -10,13 +10,26 @@ import { deleteCommand } from './commands/delete.js';
|
|
|
10
10
|
import { syncCommand } from './commands/sync.js';
|
|
11
11
|
import { exportCommand } from './commands/export.js';
|
|
12
12
|
import { importCommand } from './commands/import.js';
|
|
13
|
+
import { uploadCommand } from './commands/upload.js';
|
|
14
|
+
import { filesCommand } from './commands/files.js';
|
|
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';
|
|
13
26
|
|
|
14
27
|
const program = new Command();
|
|
15
28
|
|
|
16
29
|
program
|
|
17
30
|
.name('agentmemory')
|
|
18
31
|
.description('CLI tool for AgentMemory - persistent cloud memory for AI agents')
|
|
19
|
-
.version('1.
|
|
32
|
+
.version('1.3.0');
|
|
20
33
|
|
|
21
34
|
// Init command
|
|
22
35
|
program
|
|
@@ -24,6 +37,48 @@ program
|
|
|
24
37
|
.description('Initialize AgentMemory CLI with your API key')
|
|
25
38
|
.action(initCommand);
|
|
26
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
|
+
|
|
27
82
|
// Store command
|
|
28
83
|
program
|
|
29
84
|
.command('store <content>')
|
|
@@ -83,6 +138,83 @@ program
|
|
|
83
138
|
.option('--json', 'Output as JSON')
|
|
84
139
|
.action(importCommand);
|
|
85
140
|
|
|
141
|
+
// Upload command (files)
|
|
142
|
+
program
|
|
143
|
+
.command('upload <file>')
|
|
144
|
+
.description('Upload a file (images, PDFs, docs, audio, video, etc.)')
|
|
145
|
+
.option('-d, --description <text>', 'Description for the file')
|
|
146
|
+
.action(uploadCommand);
|
|
147
|
+
|
|
148
|
+
// Files command (list files)
|
|
149
|
+
program
|
|
150
|
+
.command('files')
|
|
151
|
+
.description('List uploaded files')
|
|
152
|
+
.option('-l, --limit <number>', 'Maximum number of results', '50')
|
|
153
|
+
.option('-t, --type <type>', 'Filter by type (image, audio, video, pdf, document)')
|
|
154
|
+
.option('--json', 'Output as JSON')
|
|
155
|
+
.action(filesCommand);
|
|
156
|
+
|
|
157
|
+
// Download command
|
|
158
|
+
program
|
|
159
|
+
.command('download <id>')
|
|
160
|
+
.description('Download a file by ID')
|
|
161
|
+
.option('-o, --output <path>', 'Output file path')
|
|
162
|
+
.option('-i, --info', 'Show file info without downloading')
|
|
163
|
+
.action(downloadCommand);
|
|
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
|
+
|
|
86
218
|
// Custom help
|
|
87
219
|
program.addHelpText('after', `
|
|
88
220
|
${chalk.cyan('Examples:')}
|
|
@@ -92,6 +224,30 @@ ${chalk.cyan('Examples:')}
|
|
|
92
224
|
$ agentmemory list --limit 10
|
|
93
225
|
$ agentmemory sync # Sync with MEMORY.md
|
|
94
226
|
$ agentmemory export > backup.json
|
|
227
|
+
|
|
228
|
+
${chalk.cyan('File Operations:')}
|
|
229
|
+
$ agentmemory upload photo.jpg # Upload any file
|
|
230
|
+
$ agentmemory upload doc.pdf -d "Meeting notes"
|
|
231
|
+
$ agentmemory files # List uploaded files
|
|
232
|
+
$ agentmemory files --type image # Filter by type
|
|
233
|
+
$ agentmemory download <id> # Download a file
|
|
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
|
|
95
251
|
|
|
96
252
|
${chalk.cyan('Documentation:')}
|
|
97
253
|
https://agentmemory.cloud/docs
|
|
@@ -106,7 +262,7 @@ program.parse();
|
|
|
106
262
|
// Show help if no command provided
|
|
107
263
|
if (!process.argv.slice(2).length) {
|
|
108
264
|
console.log(chalk.cyan(`
|
|
109
|
-
🧠 AgentMemory CLI v1.
|
|
265
|
+
🧠 AgentMemory CLI v1.3.0
|
|
110
266
|
|
|
111
267
|
Persistent cloud memory for AI agents.
|
|
112
268
|
`));
|
package/src/lib/api.ts
CHANGED
|
@@ -4,7 +4,13 @@ import type {
|
|
|
4
4
|
MemoriesListResponse,
|
|
5
5
|
MemoryCreateResponse,
|
|
6
6
|
MemorySearchResponse,
|
|
7
|
-
MemorySearchResult
|
|
7
|
+
MemorySearchResult,
|
|
8
|
+
Secret,
|
|
9
|
+
SecretListItem,
|
|
10
|
+
SecretsListResponse,
|
|
11
|
+
SecretResponse,
|
|
12
|
+
SecretType,
|
|
13
|
+
SyncConnectResponse
|
|
8
14
|
} from '../types.js';
|
|
9
15
|
|
|
10
16
|
class ApiError extends Error {
|
|
@@ -136,4 +142,83 @@ export async function getAllMemories(): Promise<Memory[]> {
|
|
|
136
142
|
return allMemories;
|
|
137
143
|
}
|
|
138
144
|
|
|
145
|
+
// Secrets API functions
|
|
146
|
+
|
|
147
|
+
export async function listSecrets(
|
|
148
|
+
limit: number = 100,
|
|
149
|
+
type?: SecretType
|
|
150
|
+
): Promise<SecretsListResponse> {
|
|
151
|
+
let endpoint = `/secrets?limit=${limit}`;
|
|
152
|
+
if (type) {
|
|
153
|
+
endpoint += `&type=${type}`;
|
|
154
|
+
}
|
|
155
|
+
return request<SecretsListResponse>(endpoint);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export async function getSecret(name: string): Promise<Secret> {
|
|
159
|
+
const response = await request<{ secret: Secret }>(`/secrets/${encodeURIComponent(name)}`);
|
|
160
|
+
return response.secret;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export async function setSecret(
|
|
164
|
+
name: string,
|
|
165
|
+
value: string,
|
|
166
|
+
type: SecretType = 'generic',
|
|
167
|
+
description?: string,
|
|
168
|
+
metadata?: Record<string, unknown>
|
|
169
|
+
): Promise<SecretResponse> {
|
|
170
|
+
const body: {
|
|
171
|
+
name: string;
|
|
172
|
+
value: string;
|
|
173
|
+
type: SecretType;
|
|
174
|
+
description?: string;
|
|
175
|
+
metadata?: Record<string, unknown>;
|
|
176
|
+
} = { name, value, type };
|
|
177
|
+
|
|
178
|
+
if (description) {
|
|
179
|
+
body.description = description;
|
|
180
|
+
}
|
|
181
|
+
if (metadata) {
|
|
182
|
+
body.metadata = metadata;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return request<SecretResponse>('/secrets', {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
body: JSON.stringify(body),
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export async function deleteSecret(name: string): Promise<void> {
|
|
192
|
+
await request<{ message: string; name: string }>(
|
|
193
|
+
`/secrets/${encodeURIComponent(name)}`,
|
|
194
|
+
{ method: 'DELETE' }
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function getAllSecrets(): Promise<SecretListItem[]> {
|
|
199
|
+
const response = await listSecrets(500);
|
|
200
|
+
return response.secrets;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Sync connect API
|
|
204
|
+
export async function syncConnect(options?: {
|
|
205
|
+
include_files?: boolean;
|
|
206
|
+
memories_limit?: number;
|
|
207
|
+
secrets_limit?: number;
|
|
208
|
+
}): Promise<SyncConnectResponse> {
|
|
209
|
+
return request<SyncConnectResponse>('/sync/connect', {
|
|
210
|
+
method: 'POST',
|
|
211
|
+
body: JSON.stringify(options || {}),
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export async function checkConnection(): Promise<{
|
|
216
|
+
connected: boolean;
|
|
217
|
+
agent: { id: string; name: string };
|
|
218
|
+
counts: { memories: number; secrets: number };
|
|
219
|
+
server_time: string;
|
|
220
|
+
}> {
|
|
221
|
+
return request('/sync/connect');
|
|
222
|
+
}
|
|
223
|
+
|
|
139
224
|
export { ApiError };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { getApiKey, getApiUrl, getMemoryFilePath } from './config.js';
|
|
5
|
+
|
|
6
|
+
const CONFIG_DIR = path.join(os.homedir(), '.agentmemory');
|
|
7
|
+
const SYNC_CACHE_FILE = path.join(CONFIG_DIR, 'sync-cache.json');
|
|
8
|
+
const SYNC_INTERVAL_MS = 30000; // Only sync if last sync was 30+ seconds ago
|
|
9
|
+
|
|
10
|
+
interface SyncCache {
|
|
11
|
+
last_sync: string;
|
|
12
|
+
last_sync_ms: number;
|
|
13
|
+
memory_count: number;
|
|
14
|
+
secret_count: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function loadSyncCache(): SyncCache | null {
|
|
18
|
+
try {
|
|
19
|
+
if (fs.existsSync(SYNC_CACHE_FILE)) {
|
|
20
|
+
return JSON.parse(fs.readFileSync(SYNC_CACHE_FILE, 'utf-8'));
|
|
21
|
+
}
|
|
22
|
+
} catch {
|
|
23
|
+
// Ignore errors
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function saveSyncCache(cache: SyncCache): void {
|
|
29
|
+
try {
|
|
30
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
31
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
fs.writeFileSync(SYNC_CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
34
|
+
} catch {
|
|
35
|
+
// Ignore errors
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Silent auto-sync - runs at the start of every command
|
|
41
|
+
* - Sends heartbeat to mark agent as online
|
|
42
|
+
* - Syncs memories to local MEMORY.md file
|
|
43
|
+
* - Caches results to avoid syncing too frequently
|
|
44
|
+
* - Never throws errors or prints output (silent)
|
|
45
|
+
*/
|
|
46
|
+
export async function autoSync(): Promise<void> {
|
|
47
|
+
const apiKey = getApiKey();
|
|
48
|
+
if (!apiKey) return; // Not configured yet
|
|
49
|
+
|
|
50
|
+
// Check if we synced recently (within 30 seconds)
|
|
51
|
+
const cache = loadSyncCache();
|
|
52
|
+
if (cache && Date.now() - cache.last_sync_ms < SYNC_INTERVAL_MS) {
|
|
53
|
+
return; // Skip sync, too recent
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const apiUrl = getApiUrl();
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// Send heartbeat with sync
|
|
60
|
+
const response = await fetch(`${apiUrl}/heartbeat`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
64
|
+
'Content-Type': 'application/json',
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify({ sync: true }),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (!response.ok) return;
|
|
70
|
+
|
|
71
|
+
const data = await response.json() as {
|
|
72
|
+
sync?: {
|
|
73
|
+
memories: {
|
|
74
|
+
items: Array<{
|
|
75
|
+
id: string;
|
|
76
|
+
content: string;
|
|
77
|
+
metadata?: Record<string, unknown>;
|
|
78
|
+
created_at: string;
|
|
79
|
+
updated_at?: string;
|
|
80
|
+
}>;
|
|
81
|
+
count: number;
|
|
82
|
+
};
|
|
83
|
+
secrets: {
|
|
84
|
+
count: number;
|
|
85
|
+
};
|
|
86
|
+
synced_at: string;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (!data.sync) return;
|
|
91
|
+
|
|
92
|
+
// Save memories to local MEMORY.md file (silently)
|
|
93
|
+
if (data.sync.memories.items.length > 0) {
|
|
94
|
+
try {
|
|
95
|
+
const memoryFilePath = getMemoryFilePath();
|
|
96
|
+
const dir = path.dirname(memoryFilePath);
|
|
97
|
+
if (!fs.existsSync(dir)) {
|
|
98
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const lines: string[] = [
|
|
102
|
+
'# Agent Memory',
|
|
103
|
+
'',
|
|
104
|
+
`> Last synced: ${data.sync.synced_at}`,
|
|
105
|
+
`> Total memories: ${data.sync.memories.count}`,
|
|
106
|
+
'',
|
|
107
|
+
'---',
|
|
108
|
+
'',
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
for (const memory of data.sync.memories.items) {
|
|
112
|
+
lines.push(`<!-- id: ${memory.id} -->`);
|
|
113
|
+
if (memory.metadata && Object.keys(memory.metadata).length > 0) {
|
|
114
|
+
lines.push(`<!-- metadata: ${JSON.stringify(memory.metadata)} -->`);
|
|
115
|
+
}
|
|
116
|
+
lines.push(memory.content);
|
|
117
|
+
lines.push('');
|
|
118
|
+
lines.push('---');
|
|
119
|
+
lines.push('');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fs.writeFileSync(memoryFilePath, lines.join('\n'));
|
|
123
|
+
} catch {
|
|
124
|
+
// Silently ignore file write errors
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Update cache
|
|
129
|
+
saveSyncCache({
|
|
130
|
+
last_sync: data.sync.synced_at,
|
|
131
|
+
last_sync_ms: Date.now(),
|
|
132
|
+
memory_count: data.sync.memories.count,
|
|
133
|
+
secret_count: data.sync.secrets.count,
|
|
134
|
+
});
|
|
135
|
+
} catch {
|
|
136
|
+
// Silently ignore all errors - auto-sync should never break commands
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Quick heartbeat - just marks agent as online, no sync
|
|
142
|
+
* Use this for commands that don't need fresh data
|
|
143
|
+
*/
|
|
144
|
+
export async function quickHeartbeat(): Promise<void> {
|
|
145
|
+
const apiKey = getApiKey();
|
|
146
|
+
if (!apiKey) return;
|
|
147
|
+
|
|
148
|
+
const apiUrl = getApiUrl();
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
await fetch(`${apiUrl}/heartbeat`, {
|
|
152
|
+
method: 'GET',
|
|
153
|
+
headers: {
|
|
154
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
} catch {
|
|
158
|
+
// Silently ignore
|
|
159
|
+
}
|
|
160
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -45,3 +45,70 @@ export interface SyncStatus {
|
|
|
45
45
|
cloud: Memory;
|
|
46
46
|
}>;
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
// Secrets types
|
|
50
|
+
export type SecretType = 'api_key' | 'credential' | 'connection_string' | 'env_var' | 'generic';
|
|
51
|
+
|
|
52
|
+
export interface Secret {
|
|
53
|
+
id: string;
|
|
54
|
+
name: string;
|
|
55
|
+
value?: string;
|
|
56
|
+
type: SecretType;
|
|
57
|
+
description?: string;
|
|
58
|
+
metadata?: Record<string, unknown>;
|
|
59
|
+
created_at: string;
|
|
60
|
+
updated_at: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface SecretListItem {
|
|
64
|
+
id: string;
|
|
65
|
+
name: string;
|
|
66
|
+
type: SecretType;
|
|
67
|
+
description?: string;
|
|
68
|
+
metadata?: Record<string, unknown>;
|
|
69
|
+
created_at: string;
|
|
70
|
+
updated_at: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface SecretsListResponse {
|
|
74
|
+
secrets: SecretListItem[];
|
|
75
|
+
total: number;
|
|
76
|
+
limit: number;
|
|
77
|
+
offset: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface SecretResponse {
|
|
81
|
+
secret: Secret;
|
|
82
|
+
message?: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Sync connect types
|
|
86
|
+
export interface SyncConnectResponse {
|
|
87
|
+
agent: {
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
memory_count: number;
|
|
91
|
+
created_at: string;
|
|
92
|
+
};
|
|
93
|
+
plan: {
|
|
94
|
+
name: string;
|
|
95
|
+
activated: boolean;
|
|
96
|
+
limits: {
|
|
97
|
+
memories: number;
|
|
98
|
+
secrets: number;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
sync: {
|
|
102
|
+
memories: {
|
|
103
|
+
items: Memory[];
|
|
104
|
+
total: number;
|
|
105
|
+
has_more: boolean;
|
|
106
|
+
};
|
|
107
|
+
secrets: {
|
|
108
|
+
items: SecretListItem[];
|
|
109
|
+
total: number;
|
|
110
|
+
has_more: boolean;
|
|
111
|
+
};
|
|
112
|
+
synced_at: string;
|
|
113
|
+
};
|
|
114
|
+
}
|