agentmemory-cli 1.0.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 (68) hide show
  1. package/README.md +198 -0
  2. package/dist/commands/delete.d.ts +7 -0
  3. package/dist/commands/delete.d.ts.map +1 -0
  4. package/dist/commands/delete.js +67 -0
  5. package/dist/commands/delete.js.map +1 -0
  6. package/dist/commands/export.d.ts +7 -0
  7. package/dist/commands/export.d.ts.map +1 -0
  8. package/dist/commands/export.js +79 -0
  9. package/dist/commands/export.js.map +1 -0
  10. package/dist/commands/import.d.ts +6 -0
  11. package/dist/commands/import.d.ts.map +1 -0
  12. package/dist/commands/import.js +107 -0
  13. package/dist/commands/import.js.map +1 -0
  14. package/dist/commands/init.d.ts +2 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +65 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/list.d.ts +8 -0
  19. package/dist/commands/list.d.ts.map +1 -0
  20. package/dist/commands/list.js +55 -0
  21. package/dist/commands/list.js.map +1 -0
  22. package/dist/commands/search.d.ts +7 -0
  23. package/dist/commands/search.d.ts.map +1 -0
  24. package/dist/commands/search.js +47 -0
  25. package/dist/commands/search.js.map +1 -0
  26. package/dist/commands/store.d.ts +8 -0
  27. package/dist/commands/store.d.ts.map +1 -0
  28. package/dist/commands/store.js +51 -0
  29. package/dist/commands/store.js.map +1 -0
  30. package/dist/commands/sync.d.ts +9 -0
  31. package/dist/commands/sync.d.ts.map +1 -0
  32. package/dist/commands/sync.js +90 -0
  33. package/dist/commands/sync.js.map +1 -0
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +106 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/lib/api.d.ts +14 -0
  39. package/dist/lib/api.d.ts.map +1 -0
  40. package/dist/lib/api.js +98 -0
  41. package/dist/lib/api.js.map +1 -0
  42. package/dist/lib/config.d.ts +13 -0
  43. package/dist/lib/config.d.ts.map +1 -0
  44. package/dist/lib/config.js +123 -0
  45. package/dist/lib/config.js.map +1 -0
  46. package/dist/lib/sync.d.ts +43 -0
  47. package/dist/lib/sync.d.ts.map +1 -0
  48. package/dist/lib/sync.js +184 -0
  49. package/dist/lib/sync.js.map +1 -0
  50. package/dist/types.d.ts +41 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +3 -0
  53. package/dist/types.js.map +1 -0
  54. package/package.json +44 -0
  55. package/src/commands/delete.ts +72 -0
  56. package/src/commands/export.ts +46 -0
  57. package/src/commands/import.ts +87 -0
  58. package/src/commands/init.ts +71 -0
  59. package/src/commands/list.ts +61 -0
  60. package/src/commands/search.ts +52 -0
  61. package/src/commands/store.ts +58 -0
  62. package/src/commands/sync.ts +102 -0
  63. package/src/index.ts +114 -0
  64. package/src/lib/api.ts +139 -0
  65. package/src/lib/config.ts +95 -0
  66. package/src/lib/sync.ts +186 -0
  67. package/src/types.ts +47 -0
  68. package/tsconfig.json +20 -0
@@ -0,0 +1,52 @@
1
+ import chalk from 'chalk';
2
+ import { searchMemories } from '../lib/api.js';
3
+ import { isConfigured } from '../lib/config.js';
4
+
5
+ interface SearchOptions {
6
+ limit?: string;
7
+ json?: boolean;
8
+ }
9
+
10
+ export async function searchCommand(
11
+ query: string,
12
+ options: SearchOptions
13
+ ): Promise<void> {
14
+ if (!isConfigured()) {
15
+ console.log(chalk.red('āŒ Not configured. Run "agentmemory init" first.'));
16
+ process.exit(1);
17
+ }
18
+
19
+ try {
20
+ const limit = options.limit ? parseInt(options.limit, 10) : 10;
21
+ const memories = await searchMemories(query, limit);
22
+
23
+ if (options.json) {
24
+ console.log(JSON.stringify(memories, null, 2));
25
+ return;
26
+ }
27
+
28
+ if (memories.length === 0) {
29
+ console.log(chalk.yellow('No memories found matching your query.'));
30
+ return;
31
+ }
32
+
33
+ console.log(chalk.cyan(`\nšŸ” Found ${memories.length} memories:\n`));
34
+
35
+ for (const memory of memories) {
36
+ const similarity = (memory.similarity * 100).toFixed(1);
37
+ console.log(chalk.green(`[${similarity}%] `) + chalk.white(memory.content));
38
+ console.log(chalk.dim(` ID: ${memory.id}`));
39
+ if (memory.metadata && Object.keys(memory.metadata).length > 0) {
40
+ console.log(chalk.dim(` Metadata: ${JSON.stringify(memory.metadata)}`));
41
+ }
42
+ console.log();
43
+ }
44
+ } catch (error) {
45
+ if (error instanceof Error) {
46
+ console.log(chalk.red(`āŒ Error: ${error.message}`));
47
+ } else {
48
+ console.log(chalk.red('āŒ Unknown error occurred'));
49
+ }
50
+ process.exit(1);
51
+ }
52
+ }
@@ -0,0 +1,58 @@
1
+ import chalk from 'chalk';
2
+ import { storeMemory } from '../lib/api.js';
3
+ import { isConfigured } from '../lib/config.js';
4
+
5
+ interface StoreOptions {
6
+ category?: string;
7
+ metadata?: string;
8
+ json?: boolean;
9
+ }
10
+
11
+ export async function storeCommand(
12
+ content: string,
13
+ options: StoreOptions
14
+ ): Promise<void> {
15
+ if (!isConfigured()) {
16
+ console.log(chalk.red('āŒ Not configured. Run "agentmemory init" first.'));
17
+ process.exit(1);
18
+ }
19
+
20
+ try {
21
+ // Build metadata
22
+ let metadata: Record<string, unknown> = {};
23
+
24
+ if (options.category) {
25
+ metadata.category = options.category;
26
+ }
27
+
28
+ if (options.metadata) {
29
+ try {
30
+ const parsed = JSON.parse(options.metadata);
31
+ metadata = { ...metadata, ...parsed };
32
+ } catch {
33
+ console.log(chalk.red('āŒ Invalid metadata JSON format'));
34
+ process.exit(1);
35
+ }
36
+ }
37
+
38
+ const memory = await storeMemory(
39
+ content,
40
+ Object.keys(metadata).length > 0 ? metadata : undefined
41
+ );
42
+
43
+ if (options.json) {
44
+ console.log(JSON.stringify(memory, null, 2));
45
+ } else {
46
+ console.log(chalk.green('āœ… Memory stored successfully!'));
47
+ console.log(chalk.dim(` ID: ${memory.id}`));
48
+ console.log(chalk.dim(` Created: ${memory.created_at}`));
49
+ }
50
+ } catch (error) {
51
+ if (error instanceof Error) {
52
+ console.log(chalk.red(`āŒ Error: ${error.message}`));
53
+ } else {
54
+ console.log(chalk.red('āŒ Unknown error occurred'));
55
+ }
56
+ process.exit(1);
57
+ }
58
+ }
@@ -0,0 +1,102 @@
1
+ import chalk from 'chalk';
2
+ import { isConfigured, getMemoryFilePath } from '../lib/config.js';
3
+ import { syncMemories, getSyncStatus } from '../lib/sync.js';
4
+
5
+ interface SyncOptions {
6
+ push?: boolean;
7
+ pull?: boolean;
8
+ status?: boolean;
9
+ json?: boolean;
10
+ }
11
+
12
+ export async function syncCommand(options: SyncOptions): Promise<void> {
13
+ if (!isConfigured()) {
14
+ console.log(chalk.red('āŒ Not configured. Run "agentmemory init" first.'));
15
+ process.exit(1);
16
+ }
17
+
18
+ const memoryFile = getMemoryFilePath();
19
+
20
+ try {
21
+ // Status only mode
22
+ if (options.status) {
23
+ console.log(chalk.dim('Checking sync status...'));
24
+ const status = await getSyncStatus();
25
+
26
+ if (options.json) {
27
+ console.log(JSON.stringify(status, null, 2));
28
+ return;
29
+ }
30
+
31
+ console.log(chalk.cyan('\nšŸ“Š Sync Status:\n'));
32
+ console.log(` Memory file: ${memoryFile}`);
33
+ console.log(` Synced: ${chalk.green(status.synced)}`);
34
+ console.log(` Local only: ${chalk.yellow(status.localOnly.length)}`);
35
+ console.log(` Cloud only: ${chalk.blue(status.cloudOnly.length)}`);
36
+
37
+ if (status.localOnly.length > 0) {
38
+ console.log(chalk.yellow('\n Local memories not in cloud:'));
39
+ for (const m of status.localOnly.slice(0, 5)) {
40
+ const preview = m.content.substring(0, 50);
41
+ console.log(chalk.dim(` • ${preview}...`));
42
+ }
43
+ if (status.localOnly.length > 5) {
44
+ console.log(chalk.dim(` ... and ${status.localOnly.length - 5} more`));
45
+ }
46
+ }
47
+
48
+ if (status.cloudOnly.length > 0) {
49
+ console.log(chalk.blue('\n Cloud memories not in local file:'));
50
+ for (const m of status.cloudOnly.slice(0, 5)) {
51
+ const preview = m.content.substring(0, 50);
52
+ console.log(chalk.dim(` • ${preview}...`));
53
+ }
54
+ if (status.cloudOnly.length > 5) {
55
+ console.log(chalk.dim(` ... and ${status.cloudOnly.length - 5} more`));
56
+ }
57
+ }
58
+
59
+ console.log();
60
+ return;
61
+ }
62
+
63
+ // Determine sync direction
64
+ let direction: 'push' | 'pull' | 'both' = 'both';
65
+ if (options.push && !options.pull) {
66
+ direction = 'push';
67
+ } else if (options.pull && !options.push) {
68
+ direction = 'pull';
69
+ }
70
+
71
+ console.log(chalk.dim(`Syncing memories (${direction})...`));
72
+ console.log(chalk.dim(`Memory file: ${memoryFile}\n`));
73
+
74
+ const result = await syncMemories(direction);
75
+
76
+ if (options.json) {
77
+ console.log(JSON.stringify(result, null, 2));
78
+ return;
79
+ }
80
+
81
+ console.log(chalk.green('āœ… Sync complete!\n'));
82
+ console.log(` šŸ“¤ Uploaded: ${chalk.green(result.uploaded)}`);
83
+ console.log(` šŸ“„ Downloaded: ${chalk.blue(result.downloaded)}`);
84
+ console.log(` ā­ļø Unchanged: ${chalk.dim(result.unchanged)}`);
85
+
86
+ if (result.errors.length > 0) {
87
+ console.log(chalk.red(`\n āŒ Errors: ${result.errors.length}`));
88
+ for (const error of result.errors) {
89
+ console.log(chalk.red(` • ${error}`));
90
+ }
91
+ }
92
+
93
+ console.log();
94
+ } catch (error) {
95
+ if (error instanceof Error) {
96
+ console.log(chalk.red(`āŒ Error: ${error.message}`));
97
+ } else {
98
+ console.log(chalk.red('āŒ Unknown error occurred'));
99
+ }
100
+ process.exit(1);
101
+ }
102
+ }
package/src/index.ts ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { initCommand } from './commands/init.js';
6
+ import { storeCommand } from './commands/store.js';
7
+ import { searchCommand } from './commands/search.js';
8
+ import { listCommand } from './commands/list.js';
9
+ import { deleteCommand } from './commands/delete.js';
10
+ import { syncCommand } from './commands/sync.js';
11
+ import { exportCommand } from './commands/export.js';
12
+ import { importCommand } from './commands/import.js';
13
+
14
+ const program = new Command();
15
+
16
+ program
17
+ .name('agentmemory')
18
+ .description('CLI tool for AgentMemory - persistent cloud memory for AI agents')
19
+ .version('1.0.0');
20
+
21
+ // Init command
22
+ program
23
+ .command('init')
24
+ .description('Initialize AgentMemory CLI with your API key')
25
+ .action(initCommand);
26
+
27
+ // Store command
28
+ program
29
+ .command('store <content>')
30
+ .description('Store a new memory')
31
+ .option('-c, --category <category>', 'Category for the memory')
32
+ .option('-m, --metadata <json>', 'Additional metadata as JSON')
33
+ .option('--json', 'Output as JSON')
34
+ .action(storeCommand);
35
+
36
+ // Search command
37
+ program
38
+ .command('search <query>')
39
+ .description('Search memories semantically')
40
+ .option('-l, --limit <number>', 'Maximum number of results', '10')
41
+ .option('--json', 'Output as JSON')
42
+ .action(searchCommand);
43
+
44
+ // List command
45
+ program
46
+ .command('list')
47
+ .description('List all memories')
48
+ .option('-l, --limit <number>', 'Maximum number of results', '50')
49
+ .option('-o, --offset <number>', 'Offset for pagination', '0')
50
+ .option('--json', 'Output as JSON')
51
+ .action(listCommand);
52
+
53
+ // Delete command
54
+ program
55
+ .command('delete <id>')
56
+ .description('Delete a memory by ID')
57
+ .option('-f, --force', 'Skip confirmation')
58
+ .option('--json', 'Output as JSON')
59
+ .action(deleteCommand);
60
+
61
+ // Sync command
62
+ program
63
+ .command('sync')
64
+ .description('Sync memories with local MEMORY.md file')
65
+ .option('--push', 'Only push local to cloud')
66
+ .option('--pull', 'Only pull cloud to local')
67
+ .option('--status', 'Show sync status without making changes')
68
+ .option('--json', 'Output as JSON')
69
+ .action(syncCommand);
70
+
71
+ // Export command
72
+ program
73
+ .command('export')
74
+ .description('Export all memories as JSON')
75
+ .option('-o, --output <file>', 'Output file path')
76
+ .option('-p, --pretty', 'Pretty print JSON')
77
+ .action(exportCommand);
78
+
79
+ // Import command
80
+ program
81
+ .command('import <file>')
82
+ .description('Import memories from JSON file')
83
+ .option('--json', 'Output as JSON')
84
+ .action(importCommand);
85
+
86
+ // Custom help
87
+ program.addHelpText('after', `
88
+ ${chalk.cyan('Examples:')}
89
+ $ agentmemory init # Setup with your API key
90
+ $ agentmemory store "User prefers dark mode"
91
+ $ agentmemory search "user preferences"
92
+ $ agentmemory list --limit 10
93
+ $ agentmemory sync # Sync with MEMORY.md
94
+ $ agentmemory export > backup.json
95
+
96
+ ${chalk.cyan('Documentation:')}
97
+ https://agentmemory.cloud/docs
98
+
99
+ ${chalk.cyan('Get your API key:')}
100
+ https://agentmemory.cloud/dashboard
101
+ `);
102
+
103
+ // Parse arguments
104
+ program.parse();
105
+
106
+ // Show help if no command provided
107
+ if (!process.argv.slice(2).length) {
108
+ console.log(chalk.cyan(`
109
+ 🧠 AgentMemory CLI v1.0.0
110
+
111
+ Persistent cloud memory for AI agents.
112
+ `));
113
+ program.outputHelp();
114
+ }
package/src/lib/api.ts ADDED
@@ -0,0 +1,139 @@
1
+ import { getApiKey, getApiUrl } from './config.js';
2
+ import type {
3
+ Memory,
4
+ MemoriesListResponse,
5
+ MemoryCreateResponse,
6
+ MemorySearchResponse,
7
+ MemorySearchResult
8
+ } from '../types.js';
9
+
10
+ class ApiError extends Error {
11
+ constructor(public statusCode: number, message: string) {
12
+ super(message);
13
+ this.name = 'ApiError';
14
+ }
15
+ }
16
+
17
+ async function request<T>(
18
+ endpoint: string,
19
+ options: RequestInit = {}
20
+ ): Promise<T> {
21
+ const apiKey = getApiKey();
22
+ const apiUrl = getApiUrl();
23
+
24
+ if (!apiKey) {
25
+ throw new Error('API key not configured. Run "agentmemory init" first.');
26
+ }
27
+
28
+ const url = `${apiUrl}${endpoint}`;
29
+
30
+ const response = await fetch(url, {
31
+ ...options,
32
+ headers: {
33
+ 'Authorization': `Bearer ${apiKey}`,
34
+ 'Content-Type': 'application/json',
35
+ ...options.headers,
36
+ },
37
+ });
38
+
39
+ const data = await response.json() as { error?: string } & T;
40
+
41
+ if (!response.ok) {
42
+ throw new ApiError(
43
+ response.status,
44
+ data.error || `Request failed with status ${response.status}`
45
+ );
46
+ }
47
+
48
+ return data;
49
+ }
50
+
51
+ export async function storeMemory(
52
+ content: string,
53
+ metadata?: Record<string, unknown>
54
+ ): Promise<Memory> {
55
+ const body: { content: string; metadata?: Record<string, unknown> } = { content };
56
+ if (metadata) {
57
+ body.metadata = metadata;
58
+ }
59
+
60
+ const response = await request<MemoryCreateResponse>('/memories', {
61
+ method: 'POST',
62
+ body: JSON.stringify(body),
63
+ });
64
+
65
+ return response.memory;
66
+ }
67
+
68
+ export async function searchMemories(
69
+ query: string,
70
+ limit: number = 10
71
+ ): Promise<MemorySearchResult[]> {
72
+ const response = await request<MemorySearchResponse>('/memories/search', {
73
+ method: 'POST',
74
+ body: JSON.stringify({ query, limit }),
75
+ });
76
+
77
+ return response.memories;
78
+ }
79
+
80
+ export async function listMemories(
81
+ limit: number = 50,
82
+ offset: number = 0
83
+ ): Promise<MemoriesListResponse> {
84
+ const response = await request<MemoriesListResponse>(
85
+ `/memories?limit=${limit}&offset=${offset}`
86
+ );
87
+
88
+ return response;
89
+ }
90
+
91
+ export async function getMemory(id: string): Promise<Memory> {
92
+ const response = await request<{ memory: Memory }>(`/memories/${id}`);
93
+ return response.memory;
94
+ }
95
+
96
+ export async function updateMemory(
97
+ id: string,
98
+ content: string,
99
+ metadata?: Record<string, unknown>
100
+ ): Promise<Memory> {
101
+ const body: { content: string; metadata?: Record<string, unknown> } = { content };
102
+ if (metadata) {
103
+ body.metadata = metadata;
104
+ }
105
+
106
+ const response = await request<{ memory: Memory }>(`/memories/${id}`, {
107
+ method: 'PUT',
108
+ body: JSON.stringify(body),
109
+ });
110
+
111
+ return response.memory;
112
+ }
113
+
114
+ export async function deleteMemory(id: string): Promise<void> {
115
+ await request<{ success: boolean }>(`/memories/${id}`, {
116
+ method: 'DELETE',
117
+ });
118
+ }
119
+
120
+ export async function getAllMemories(): Promise<Memory[]> {
121
+ const allMemories: Memory[] = [];
122
+ let offset = 0;
123
+ const limit = 100;
124
+
125
+ while (true) {
126
+ const response = await listMemories(limit, offset);
127
+ allMemories.push(...response.memories);
128
+
129
+ if (response.memories.length < limit) {
130
+ break;
131
+ }
132
+
133
+ offset += limit;
134
+ }
135
+
136
+ return allMemories;
137
+ }
138
+
139
+ export { ApiError };
@@ -0,0 +1,95 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import type { Config } from '../types.js';
5
+
6
+ const CONFIG_DIR = path.join(os.homedir(), '.agentmemory');
7
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
8
+
9
+ const DEFAULT_CONFIG: Config = {
10
+ api_key: '',
11
+ api_url: 'https://agentmemory.cloud/api',
12
+ memory_file: './MEMORY.md'
13
+ };
14
+
15
+ export function getConfigDir(): string {
16
+ return CONFIG_DIR;
17
+ }
18
+
19
+ export function getConfigPath(): string {
20
+ return CONFIG_FILE;
21
+ }
22
+
23
+ export function ensureConfigDir(): void {
24
+ if (!fs.existsSync(CONFIG_DIR)) {
25
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
26
+ }
27
+ }
28
+
29
+ export function configExists(): boolean {
30
+ return fs.existsSync(CONFIG_FILE);
31
+ }
32
+
33
+ export function loadConfig(): Config {
34
+ ensureConfigDir();
35
+
36
+ if (!fs.existsSync(CONFIG_FILE)) {
37
+ return { ...DEFAULT_CONFIG };
38
+ }
39
+
40
+ try {
41
+ const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
42
+ const config = JSON.parse(content) as Partial<Config>;
43
+ return { ...DEFAULT_CONFIG, ...config };
44
+ } catch (error) {
45
+ console.error('Error reading config file:', error);
46
+ return { ...DEFAULT_CONFIG };
47
+ }
48
+ }
49
+
50
+ export function saveConfig(config: Partial<Config>): void {
51
+ ensureConfigDir();
52
+
53
+ const existingConfig = loadConfig();
54
+ const newConfig = { ...existingConfig, ...config };
55
+
56
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(newConfig, null, 2));
57
+ }
58
+
59
+ export function getApiKey(): string {
60
+ // Check environment variable first
61
+ const envKey = process.env.AGENTMEMORY_API_KEY;
62
+ if (envKey) {
63
+ return envKey;
64
+ }
65
+
66
+ // Fall back to config file
67
+ const config = loadConfig();
68
+ return config.api_key;
69
+ }
70
+
71
+ export function getApiUrl(): string {
72
+ const envUrl = process.env.AGENTMEMORY_API_URL;
73
+ if (envUrl) {
74
+ return envUrl;
75
+ }
76
+
77
+ const config = loadConfig();
78
+ return config.api_url;
79
+ }
80
+
81
+ export function getMemoryFilePath(): string {
82
+ const config = loadConfig();
83
+ return config.memory_file;
84
+ }
85
+
86
+ export function isConfigured(): boolean {
87
+ const apiKey = getApiKey();
88
+ return apiKey.length > 0 && apiKey.startsWith('am_');
89
+ }
90
+
91
+ export function clearConfig(): void {
92
+ if (fs.existsSync(CONFIG_FILE)) {
93
+ fs.unlinkSync(CONFIG_FILE);
94
+ }
95
+ }