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.
- 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.map +1 -1
- package/dist/commands/download.js +3 -0
- package/dist/commands/download.js.map +1 -1
- 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.map +1 -1
- package/dist/commands/files.js +3 -0
- package/dist/commands/files.js.map +1 -1
- 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.map +1 -1
- package/dist/commands/upload.js +3 -0
- package/dist/commands/upload.js.map +1 -1
- package/dist/index.js +105 -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 +1 -1
- package/src/commands/connect.ts +216 -0
- package/src/commands/delete.ts +4 -0
- package/src/commands/download.ts +4 -0
- package/src/commands/export.ts +4 -0
- package/src/commands/files.ts +4 -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 +4 -0
- package/src/index.ts +124 -2
- package/src/lib/api.ts +86 -1
- package/src/lib/autosync.ts +160 -0
- package/src/types.ts +67 -0
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
|
+
}
|