@slorenzot/memento-cli 0.2.0 → 0.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/CLI.d.ts +12 -0
- package/dist/CLI.d.ts.map +1 -0
- package/dist/CLI.js +178 -0
- package/dist/CLI.js.map +1 -0
- package/dist/index.js +67 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/CLI.test.ts +60 -0
- package/src/CLI.ts +192 -0
- package/src/index.ts +76 -30
- package/data/memento.db +0 -0
- package/data/memento.db-shm +0 -0
- package/data/memento.db-wal +0 -0
- package/slorenzot-memento-cli-0.2.0.tgz +0 -0
package/dist/CLI.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class CLI {
|
|
2
|
+
private program;
|
|
3
|
+
private memory;
|
|
4
|
+
private activeSessionId;
|
|
5
|
+
private projectId;
|
|
6
|
+
constructor();
|
|
7
|
+
private setupCommands;
|
|
8
|
+
private getOrCreateSessionId;
|
|
9
|
+
run(argv?: string[]): Promise<void>;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=CLI.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CLI.d.ts","sourceRoot":"","sources":["../src/CLI.ts"],"names":[],"mappings":"AAKA,qBAAa,GAAG;IACd,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,SAAS,CAAS;;IAY1B,OAAO,CAAC,aAAa;YAsJP,oBAAoB;IAa5B,GAAG,CAAC,IAAI,GAAE,MAAM,EAAiB;IAIvC,KAAK;CAGN"}
|
package/dist/CLI.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CLI = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const memento_core_1 = require("@slorenzot/memento-core");
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
class CLI {
|
|
8
|
+
program;
|
|
9
|
+
memory;
|
|
10
|
+
activeSessionId = null;
|
|
11
|
+
projectId;
|
|
12
|
+
constructor() {
|
|
13
|
+
const config = (0, memento_core_1.loadConfig)();
|
|
14
|
+
const dbPath = (0, memento_core_1.resolveDbPath)(config);
|
|
15
|
+
this.projectId = (0, memento_core_1.getProjectId)(config);
|
|
16
|
+
this.program = new commander_1.Command();
|
|
17
|
+
this.memory = new memento_core_1.MemoryEngine(dbPath);
|
|
18
|
+
this.setupCommands();
|
|
19
|
+
}
|
|
20
|
+
setupCommands() {
|
|
21
|
+
this.program
|
|
22
|
+
.name('memento')
|
|
23
|
+
.description('Persistent memory system for AI coding agents')
|
|
24
|
+
.version('0.1.0');
|
|
25
|
+
this.program
|
|
26
|
+
.command('setup [agent]')
|
|
27
|
+
.description('Setup configuration for an AI agent')
|
|
28
|
+
.action((agent) => {
|
|
29
|
+
console.log(`Setup for agent: ${agent || 'default'}`);
|
|
30
|
+
console.log('Configuration saved to ~/.memento/config.json');
|
|
31
|
+
});
|
|
32
|
+
this.program
|
|
33
|
+
.command('serve [port]')
|
|
34
|
+
.description('Start API server')
|
|
35
|
+
.option('-d, --db <path>', 'Database path', './data/memento.db')
|
|
36
|
+
.action((port, options) => {
|
|
37
|
+
console.log(`Starting API server on port ${port || 3000}`);
|
|
38
|
+
console.log(`Database: ${options.db}`);
|
|
39
|
+
console.log('Note: API server not implemented in CLI mode');
|
|
40
|
+
});
|
|
41
|
+
this.program
|
|
42
|
+
.command('mcp')
|
|
43
|
+
.description('Start MCP server')
|
|
44
|
+
.option('-d, --db <path>', 'Database path', './data/memento.db')
|
|
45
|
+
.action((options) => {
|
|
46
|
+
console.log(`Starting MCP server`);
|
|
47
|
+
console.log(`Database: ${options.db}`);
|
|
48
|
+
console.log('Note: MCP server not implemented in CLI mode');
|
|
49
|
+
});
|
|
50
|
+
this.program
|
|
51
|
+
.command('search <query>')
|
|
52
|
+
.description('Search observations')
|
|
53
|
+
.option('-t, --type <type>', 'Filter by type')
|
|
54
|
+
.option('-p, --project <project>', 'Filter by project')
|
|
55
|
+
.option('--limit <number>', 'Limit results')
|
|
56
|
+
.action(async (query, options) => {
|
|
57
|
+
const result = await this.memory.search({
|
|
58
|
+
query,
|
|
59
|
+
type: options.type,
|
|
60
|
+
projectId: options.project,
|
|
61
|
+
limit: options.limit ? parseInt(options.limit) : undefined,
|
|
62
|
+
});
|
|
63
|
+
console.log(`Found ${result.total} observations:`);
|
|
64
|
+
result.observations.forEach((obs) => {
|
|
65
|
+
console.log(` [${obs.type}] ${obs.title}`);
|
|
66
|
+
console.log(` ${obs.content.substring(0, 100)}...`);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
this.program
|
|
70
|
+
.command('save <title> <content>')
|
|
71
|
+
.description('Save an observation')
|
|
72
|
+
.option('-t, --type <type>', 'Observation type', 'note')
|
|
73
|
+
.option('-k, --topic <topic>', 'Topic key')
|
|
74
|
+
.option('-p, --project <project>', 'Project ID', this.projectId)
|
|
75
|
+
.action(async (title, content, options) => {
|
|
76
|
+
const sessionId = await this.getOrCreateSessionId(options.project);
|
|
77
|
+
const observation = await this.memory.createObservation({
|
|
78
|
+
sessionId,
|
|
79
|
+
title,
|
|
80
|
+
content,
|
|
81
|
+
type: options.type,
|
|
82
|
+
topicKey: options.topic || null,
|
|
83
|
+
projectId: options.project,
|
|
84
|
+
metadata: {},
|
|
85
|
+
});
|
|
86
|
+
console.log(`Saved observation: ${observation.uuid}`);
|
|
87
|
+
});
|
|
88
|
+
this.program
|
|
89
|
+
.command('get <id>')
|
|
90
|
+
.description('Get observation by ID')
|
|
91
|
+
.action(async (id) => {
|
|
92
|
+
const observation = await this.memory.getObservation(parseInt(id));
|
|
93
|
+
if (!observation) {
|
|
94
|
+
console.error('Observation not found');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
console.log(`[${observation.type}] ${observation.title}`);
|
|
98
|
+
console.log(observation.content);
|
|
99
|
+
console.log(`Topic: ${observation.topicKey || 'none'}`);
|
|
100
|
+
console.log(`Created: ${observation.createdAt.toISOString()}`);
|
|
101
|
+
});
|
|
102
|
+
this.program
|
|
103
|
+
.command('update <id>')
|
|
104
|
+
.description('Update observation')
|
|
105
|
+
.option('-t, --title <title>', 'New title')
|
|
106
|
+
.option('-c, --content <content>', 'New content')
|
|
107
|
+
.option('-k, --topic <topic>', 'New topic key')
|
|
108
|
+
.action(async (id, options) => {
|
|
109
|
+
const updates = {};
|
|
110
|
+
if (options.title)
|
|
111
|
+
updates.title = options.title;
|
|
112
|
+
if (options.content)
|
|
113
|
+
updates.content = options.content;
|
|
114
|
+
if (options.topic)
|
|
115
|
+
updates.topicKey = options.topic;
|
|
116
|
+
const observation = await this.memory.updateObservation(parseInt(id), updates);
|
|
117
|
+
console.log(`Updated observation: ${observation.uuid}`);
|
|
118
|
+
});
|
|
119
|
+
this.program
|
|
120
|
+
.command('delete <id>')
|
|
121
|
+
.description('Delete observation')
|
|
122
|
+
.action(async (id) => {
|
|
123
|
+
await this.memory.deleteObservation(parseInt(id));
|
|
124
|
+
console.log(`Deleted observation ${id}`);
|
|
125
|
+
});
|
|
126
|
+
this.program
|
|
127
|
+
.command('timeline [project]')
|
|
128
|
+
.description('Show timeline of observations')
|
|
129
|
+
.option('-l, --limit <number>', 'Limit results', '20')
|
|
130
|
+
.action(async (project, options) => {
|
|
131
|
+
const result = await this.memory.search({
|
|
132
|
+
projectId: project,
|
|
133
|
+
limit: parseInt(options.limit),
|
|
134
|
+
});
|
|
135
|
+
console.log(`Timeline (${result.total} observations):`);
|
|
136
|
+
result.observations.forEach((obs) => {
|
|
137
|
+
const date = obs.createdAt.toLocaleDateString();
|
|
138
|
+
console.log(` ${date} [${obs.type}] ${obs.title}`);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
this.program
|
|
142
|
+
.command('stats')
|
|
143
|
+
.description('Show statistics')
|
|
144
|
+
.action(async () => {
|
|
145
|
+
const result = await this.memory.search({});
|
|
146
|
+
const byType = result.observations.reduce((acc, obs) => {
|
|
147
|
+
acc[obs.type] = (acc[obs.type] || 0) + 1;
|
|
148
|
+
return acc;
|
|
149
|
+
}, {});
|
|
150
|
+
console.log('Statistics:');
|
|
151
|
+
console.log(` Total observations: ${result.total}`);
|
|
152
|
+
console.log(' By type:');
|
|
153
|
+
Object.entries(byType).forEach(([type, count]) => {
|
|
154
|
+
console.log(` ${type}: ${count}`);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async getOrCreateSessionId(projectId) {
|
|
159
|
+
if (this.activeSessionId) {
|
|
160
|
+
return this.activeSessionId;
|
|
161
|
+
}
|
|
162
|
+
const session = await this.memory.createSession({
|
|
163
|
+
projectId,
|
|
164
|
+
endedAt: null,
|
|
165
|
+
metadata: {},
|
|
166
|
+
});
|
|
167
|
+
this.activeSessionId = session.id;
|
|
168
|
+
return session.id;
|
|
169
|
+
}
|
|
170
|
+
async run(argv = process.argv) {
|
|
171
|
+
await this.program.parseAsync(argv);
|
|
172
|
+
}
|
|
173
|
+
close() {
|
|
174
|
+
this.memory.close();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.CLI = CLI;
|
|
178
|
+
//# sourceMappingURL=CLI.js.map
|
package/dist/CLI.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CLI.js","sourceRoot":"","sources":["../src/CLI.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const memento_core_1 = require("@slorenzot/memento-core");
|
|
6
|
-
const
|
|
6
|
+
const config = (0, memento_core_1.loadConfig)();
|
|
7
|
+
const dbPath = (0, memento_core_1.resolveDbPath)(config);
|
|
8
|
+
const projectId = (0, memento_core_1.getProjectId)(config);
|
|
7
9
|
const memory = new memento_core_1.MemoryEngine(dbPath);
|
|
8
10
|
let activeSessionId = null;
|
|
9
11
|
async function getOrCreateSessionId(projectId) {
|
|
@@ -14,42 +16,68 @@ async function getOrCreateSessionId(projectId) {
|
|
|
14
16
|
return session.id;
|
|
15
17
|
}
|
|
16
18
|
const program = new commander_1.Command();
|
|
17
|
-
program
|
|
18
|
-
|
|
19
|
-
.
|
|
20
|
-
.
|
|
21
|
-
|
|
19
|
+
program
|
|
20
|
+
.name('memento')
|
|
21
|
+
.description('Persistent memory system for AI coding agents')
|
|
22
|
+
.version('0.2.0');
|
|
23
|
+
program
|
|
24
|
+
.command('search <query>')
|
|
25
|
+
.description('Search observations')
|
|
26
|
+
.option('-t, --type <type>', 'Filter by type')
|
|
27
|
+
.option('-p, --project <project>', 'Filter by project')
|
|
28
|
+
.option('--limit <number>', 'Limit results')
|
|
22
29
|
.action(async (query, options) => {
|
|
23
|
-
const result = await memory.search({
|
|
30
|
+
const result = await memory.search({
|
|
31
|
+
query,
|
|
32
|
+
type: options.type,
|
|
33
|
+
projectId: options.project,
|
|
34
|
+
limit: options.limit ? parseInt(options.limit) : undefined,
|
|
35
|
+
});
|
|
24
36
|
console.log(`Found ${result.total} observations:`);
|
|
25
|
-
result.observations.forEach((obs) => {
|
|
37
|
+
result.observations.forEach((obs) => {
|
|
38
|
+
console.log(` [${obs.type}] ${obs.title}\n ${obs.content.substring(0, 100)}...`);
|
|
39
|
+
});
|
|
26
40
|
memory.close();
|
|
27
41
|
});
|
|
28
|
-
program
|
|
29
|
-
.
|
|
30
|
-
.
|
|
31
|
-
.option(
|
|
42
|
+
program
|
|
43
|
+
.command('save <title> <content>')
|
|
44
|
+
.description('Save an observation')
|
|
45
|
+
.option('-t, --type <type>', 'Observation type', 'note')
|
|
46
|
+
.option('-k, --topic <topic>', 'Topic key')
|
|
47
|
+
.option('-p, --project <project>', 'Project ID', projectId)
|
|
32
48
|
.action(async (title, content, options) => {
|
|
33
49
|
const sessionId = await getOrCreateSessionId(options.project);
|
|
34
|
-
const observation = await memory.createObservation({
|
|
50
|
+
const observation = await memory.createObservation({
|
|
51
|
+
sessionId,
|
|
52
|
+
title,
|
|
53
|
+
content,
|
|
54
|
+
type: options.type,
|
|
55
|
+
topicKey: options.topic || null,
|
|
56
|
+
projectId: options.project,
|
|
57
|
+
metadata: {},
|
|
58
|
+
});
|
|
35
59
|
console.log(`Saved observation: ${observation.uuid}`);
|
|
36
60
|
memory.close();
|
|
37
61
|
});
|
|
38
|
-
program
|
|
62
|
+
program
|
|
63
|
+
.command('get <id>')
|
|
64
|
+
.description('Get observation by ID')
|
|
39
65
|
.action(async (id) => {
|
|
40
66
|
const observation = await memory.getObservation(parseInt(id));
|
|
41
67
|
if (!observation) {
|
|
42
|
-
console.error(
|
|
68
|
+
console.error('Observation not found');
|
|
43
69
|
memory.close();
|
|
44
70
|
return;
|
|
45
71
|
}
|
|
46
|
-
console.log(`[${observation.type}] ${observation.title}\n${observation.content}\nTopic: ${observation.topicKey ||
|
|
72
|
+
console.log(`[${observation.type}] ${observation.title}\n${observation.content}\nTopic: ${observation.topicKey || 'none'}\nCreated: ${observation.createdAt.toISOString()}`);
|
|
47
73
|
memory.close();
|
|
48
74
|
});
|
|
49
|
-
program
|
|
50
|
-
.
|
|
51
|
-
.
|
|
52
|
-
.option(
|
|
75
|
+
program
|
|
76
|
+
.command('update <id>')
|
|
77
|
+
.description('Update observation')
|
|
78
|
+
.option('-t, --title <title>', 'New title')
|
|
79
|
+
.option('-c, --content <content>', 'New content')
|
|
80
|
+
.option('-k, --topic <topic>', 'New topic key')
|
|
53
81
|
.action(async (id, options) => {
|
|
54
82
|
const updates = {};
|
|
55
83
|
if (options.title)
|
|
@@ -62,27 +90,39 @@ program.command("update <id>").description("Update observation")
|
|
|
62
90
|
console.log(`Updated observation: ${observation.uuid}`);
|
|
63
91
|
memory.close();
|
|
64
92
|
});
|
|
65
|
-
program
|
|
93
|
+
program
|
|
94
|
+
.command('delete <id>')
|
|
95
|
+
.description('Delete observation')
|
|
66
96
|
.action(async (id) => {
|
|
67
97
|
await memory.deleteObservation(parseInt(id));
|
|
68
98
|
console.log(`Deleted observation ${id}`);
|
|
69
99
|
memory.close();
|
|
70
100
|
});
|
|
71
|
-
program
|
|
72
|
-
.
|
|
101
|
+
program
|
|
102
|
+
.command('timeline [project]')
|
|
103
|
+
.description('Show timeline')
|
|
104
|
+
.option('-l, --limit <number>', 'Limit results', '20')
|
|
73
105
|
.action(async (project, options) => {
|
|
74
106
|
const result = await memory.search({ projectId: project, limit: parseInt(options.limit) });
|
|
75
107
|
console.log(`Timeline (${result.total} observations):`);
|
|
76
|
-
result.observations.forEach((obs) => {
|
|
108
|
+
result.observations.forEach((obs) => {
|
|
109
|
+
console.log(` ${obs.createdAt.toLocaleDateString()} [${obs.type}] ${obs.title}`);
|
|
110
|
+
});
|
|
77
111
|
memory.close();
|
|
78
112
|
});
|
|
79
|
-
program
|
|
113
|
+
program
|
|
114
|
+
.command('stats')
|
|
115
|
+
.description('Show statistics')
|
|
80
116
|
.action(async () => {
|
|
81
117
|
const result = await memory.search({});
|
|
82
118
|
const byType = {};
|
|
83
|
-
result.observations.forEach((obs) => {
|
|
119
|
+
result.observations.forEach((obs) => {
|
|
120
|
+
byType[obs.type] = (byType[obs.type] || 0) + 1;
|
|
121
|
+
});
|
|
84
122
|
console.log(`Statistics:\n Total observations: ${result.total}\n By type:`);
|
|
85
|
-
Object.entries(byType).forEach(([type, count]) => {
|
|
123
|
+
Object.entries(byType).forEach(([type, count]) => {
|
|
124
|
+
console.log(` ${type}: ${count}`);
|
|
125
|
+
});
|
|
86
126
|
memory.close();
|
|
87
127
|
});
|
|
88
128
|
program.parseAsync(process.argv);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slorenzot/memento-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI interface for Memento memory system",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"memento",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"prepare": "npm run build"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@slorenzot/memento-core": "
|
|
24
|
+
"@slorenzot/memento-core": "^0.6.0",
|
|
25
25
|
"commander": "^12.0.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
package/src/CLI.test.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
|
|
2
|
+
import { CLI } from './CLI';
|
|
3
|
+
|
|
4
|
+
describe('CLI', () => {
|
|
5
|
+
let cli: CLI;
|
|
6
|
+
let testDbPath: string;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
testDbPath = `/tmp/test-cli-${Date.now()}.db`;
|
|
10
|
+
cli = new CLI(testDbPath);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
cli.close();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should initialize without errors', () => {
|
|
18
|
+
expect(cli).toBeDefined();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('Commands', () => {
|
|
22
|
+
it('should have all required commands', () => {
|
|
23
|
+
const commands = cli['program'].commands;
|
|
24
|
+
|
|
25
|
+
const commandNames = commands.map((c) => c.name());
|
|
26
|
+
expect(commandNames).toContain('setup');
|
|
27
|
+
expect(commandNames).toContain('serve');
|
|
28
|
+
expect(commandNames).toContain('mcp');
|
|
29
|
+
expect(commandNames).toContain('search');
|
|
30
|
+
expect(commandNames).toContain('save');
|
|
31
|
+
expect(commandNames).toContain('get');
|
|
32
|
+
expect(commandNames).toContain('update');
|
|
33
|
+
expect(commandNames).toContain('delete');
|
|
34
|
+
expect(commandNames).toContain('timeline');
|
|
35
|
+
expect(commandNames).toContain('stats');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should have proper descriptions', () => {
|
|
39
|
+
const commands = cli['program'].commands;
|
|
40
|
+
|
|
41
|
+
const setupCommand = commands.find((c) => c.name() === 'setup');
|
|
42
|
+
expect(setupCommand).toBeDefined();
|
|
43
|
+
expect(setupCommand?.description()).toContain('Setup');
|
|
44
|
+
|
|
45
|
+
const searchCommand = commands.find((c) => c.name() === 'search');
|
|
46
|
+
expect(searchCommand).toBeDefined();
|
|
47
|
+
expect(searchCommand?.description()).toContain('Search');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('Session Management', () => {
|
|
52
|
+
it('should create and track active session', async () => {
|
|
53
|
+
const sessionId = await cli['getOrCreateSessionId']('test-project');
|
|
54
|
+
expect(sessionId).toBeDefined();
|
|
55
|
+
|
|
56
|
+
const sameSessionId = await cli['getOrCreateSessionId']('test-project');
|
|
57
|
+
expect(sameSessionId).toBe(sessionId);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
package/src/CLI.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { MemoryEngine, loadConfig, resolveDbPath, getProjectId } from '@slorenzot/memento-core';
|
|
3
|
+
import type { Observation } from '@slorenzot/memento-core';
|
|
4
|
+
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
export class CLI {
|
|
7
|
+
private program: Command;
|
|
8
|
+
private memory: MemoryEngine;
|
|
9
|
+
private activeSessionId: number | null = null;
|
|
10
|
+
private projectId: string;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
const dbPath = resolveDbPath(config);
|
|
15
|
+
this.projectId = getProjectId(config);
|
|
16
|
+
|
|
17
|
+
this.program = new Command();
|
|
18
|
+
this.memory = new MemoryEngine(dbPath);
|
|
19
|
+
this.setupCommands();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private setupCommands() {
|
|
23
|
+
this.program
|
|
24
|
+
.name('memento')
|
|
25
|
+
.description('Persistent memory system for AI coding agents')
|
|
26
|
+
.version('0.1.0');
|
|
27
|
+
|
|
28
|
+
this.program
|
|
29
|
+
.command('setup [agent]')
|
|
30
|
+
.description('Setup configuration for an AI agent')
|
|
31
|
+
.action((agent) => {
|
|
32
|
+
console.log(`Setup for agent: ${agent || 'default'}`);
|
|
33
|
+
console.log('Configuration saved to ~/.memento/config.json');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
this.program
|
|
37
|
+
.command('serve [port]')
|
|
38
|
+
.description('Start API server')
|
|
39
|
+
.option('-d, --db <path>', 'Database path', './data/memento.db')
|
|
40
|
+
.action((port, options) => {
|
|
41
|
+
console.log(`Starting API server on port ${port || 3000}`);
|
|
42
|
+
console.log(`Database: ${options.db}`);
|
|
43
|
+
console.log('Note: API server not implemented in CLI mode');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.program
|
|
47
|
+
.command('mcp')
|
|
48
|
+
.description('Start MCP server')
|
|
49
|
+
.option('-d, --db <path>', 'Database path', './data/memento.db')
|
|
50
|
+
.action((options) => {
|
|
51
|
+
console.log(`Starting MCP server`);
|
|
52
|
+
console.log(`Database: ${options.db}`);
|
|
53
|
+
console.log('Note: MCP server not implemented in CLI mode');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.program
|
|
57
|
+
.command('search <query>')
|
|
58
|
+
.description('Search observations')
|
|
59
|
+
.option('-t, --type <type>', 'Filter by type')
|
|
60
|
+
.option('-p, --project <project>', 'Filter by project')
|
|
61
|
+
.option('--limit <number>', 'Limit results')
|
|
62
|
+
.action(async (query, options) => {
|
|
63
|
+
const result = await this.memory.search({
|
|
64
|
+
query,
|
|
65
|
+
type: options.type as Observation['type'] | undefined,
|
|
66
|
+
projectId: options.project as string | undefined,
|
|
67
|
+
limit: options.limit ? parseInt(options.limit as string) : undefined,
|
|
68
|
+
});
|
|
69
|
+
console.log(`Found ${result.total} observations:`);
|
|
70
|
+
result.observations.forEach((obs) => {
|
|
71
|
+
console.log(` [${obs.type}] ${obs.title}`);
|
|
72
|
+
console.log(` ${obs.content.substring(0, 100)}...`);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.program
|
|
77
|
+
.command('save <title> <content>')
|
|
78
|
+
.description('Save an observation')
|
|
79
|
+
.option('-t, --type <type>', 'Observation type', 'note')
|
|
80
|
+
.option('-k, --topic <topic>', 'Topic key')
|
|
81
|
+
.option('-p, --project <project>', 'Project ID', this.projectId)
|
|
82
|
+
.action(async (title, content, options) => {
|
|
83
|
+
const sessionId = await this.getOrCreateSessionId(options.project as string);
|
|
84
|
+
const observation = await this.memory.createObservation({
|
|
85
|
+
sessionId,
|
|
86
|
+
title,
|
|
87
|
+
content,
|
|
88
|
+
type: options.type as Observation['type'],
|
|
89
|
+
topicKey: options.topic || null,
|
|
90
|
+
projectId: options.project as string,
|
|
91
|
+
metadata: {},
|
|
92
|
+
});
|
|
93
|
+
console.log(`Saved observation: ${observation.uuid}`);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
this.program
|
|
97
|
+
.command('get <id>')
|
|
98
|
+
.description('Get observation by ID')
|
|
99
|
+
.action(async (id) => {
|
|
100
|
+
const observation = await this.memory.getObservation(parseInt(id));
|
|
101
|
+
if (!observation) {
|
|
102
|
+
console.error('Observation not found');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
console.log(`[${observation.type}] ${observation.title}`);
|
|
106
|
+
console.log(observation.content);
|
|
107
|
+
console.log(`Topic: ${observation.topicKey || 'none'}`);
|
|
108
|
+
console.log(`Created: ${observation.createdAt.toISOString()}`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
this.program
|
|
112
|
+
.command('update <id>')
|
|
113
|
+
.description('Update observation')
|
|
114
|
+
.option('-t, --title <title>', 'New title')
|
|
115
|
+
.option('-c, --content <content>', 'New content')
|
|
116
|
+
.option('-k, --topic <topic>', 'New topic key')
|
|
117
|
+
.action(async (id, options) => {
|
|
118
|
+
const updates: Partial<Observation> = {};
|
|
119
|
+
if (options.title) updates.title = options.title;
|
|
120
|
+
if (options.content) updates.content = options.content;
|
|
121
|
+
if (options.topic) updates.topicKey = options.topic;
|
|
122
|
+
|
|
123
|
+
const observation = await this.memory.updateObservation(parseInt(id), updates);
|
|
124
|
+
console.log(`Updated observation: ${observation.uuid}`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
this.program
|
|
128
|
+
.command('delete <id>')
|
|
129
|
+
.description('Delete observation')
|
|
130
|
+
.action(async (id) => {
|
|
131
|
+
await this.memory.deleteObservation(parseInt(id));
|
|
132
|
+
console.log(`Deleted observation ${id}`);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
this.program
|
|
136
|
+
.command('timeline [project]')
|
|
137
|
+
.description('Show timeline of observations')
|
|
138
|
+
.option('-l, --limit <number>', 'Limit results', '20')
|
|
139
|
+
.action(async (project, options) => {
|
|
140
|
+
const result = await this.memory.search({
|
|
141
|
+
projectId: project,
|
|
142
|
+
limit: parseInt(options.limit as string),
|
|
143
|
+
});
|
|
144
|
+
console.log(`Timeline (${result.total} observations):`);
|
|
145
|
+
result.observations.forEach((obs) => {
|
|
146
|
+
const date = obs.createdAt.toLocaleDateString();
|
|
147
|
+
console.log(` ${date} [${obs.type}] ${obs.title}`);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
this.program
|
|
152
|
+
.command('stats')
|
|
153
|
+
.description('Show statistics')
|
|
154
|
+
.action(async () => {
|
|
155
|
+
const result = await this.memory.search({});
|
|
156
|
+
const byType = result.observations.reduce(
|
|
157
|
+
(acc, obs) => {
|
|
158
|
+
acc[obs.type] = (acc[obs.type] || 0) + 1;
|
|
159
|
+
return acc;
|
|
160
|
+
},
|
|
161
|
+
{} as Record<string, number>
|
|
162
|
+
);
|
|
163
|
+
console.log('Statistics:');
|
|
164
|
+
console.log(` Total observations: ${result.total}`);
|
|
165
|
+
console.log(' By type:');
|
|
166
|
+
Object.entries(byType).forEach(([type, count]) => {
|
|
167
|
+
console.log(` ${type}: ${count}`);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private async getOrCreateSessionId(projectId: string): Promise<number> {
|
|
173
|
+
if (this.activeSessionId) {
|
|
174
|
+
return this.activeSessionId;
|
|
175
|
+
}
|
|
176
|
+
const session = await this.memory.createSession({
|
|
177
|
+
projectId,
|
|
178
|
+
endedAt: null,
|
|
179
|
+
metadata: {},
|
|
180
|
+
});
|
|
181
|
+
this.activeSessionId = session.id;
|
|
182
|
+
return session.id;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async run(argv: string[] = process.argv) {
|
|
186
|
+
await this.program.parseAsync(argv);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
close() {
|
|
190
|
+
this.memory.close();
|
|
191
|
+
}
|
|
192
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { Command } from
|
|
4
|
-
import { MemoryEngine } from
|
|
5
|
-
import type { Observation } from
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { MemoryEngine, loadConfig, resolveDbPath, getProjectId } from '@slorenzot/memento-core';
|
|
5
|
+
import type { Observation } from '@slorenzot/memento-core';
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
const dbPath = resolveDbPath(config);
|
|
9
|
+
const projectId = getProjectId(config);
|
|
8
10
|
const memory = new MemoryEngine(dbPath);
|
|
9
11
|
let activeSessionId: number | null = null;
|
|
10
12
|
|
|
@@ -16,42 +18,74 @@ async function getOrCreateSessionId(projectId: string): Promise<number> {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
const program = new Command();
|
|
19
|
-
program
|
|
21
|
+
program
|
|
22
|
+
.name('memento')
|
|
23
|
+
.description('Persistent memory system for AI coding agents')
|
|
24
|
+
.version('0.2.0');
|
|
20
25
|
|
|
21
|
-
program
|
|
22
|
-
.
|
|
23
|
-
.
|
|
24
|
-
.option(
|
|
26
|
+
program
|
|
27
|
+
.command('search <query>')
|
|
28
|
+
.description('Search observations')
|
|
29
|
+
.option('-t, --type <type>', 'Filter by type')
|
|
30
|
+
.option('-p, --project <project>', 'Filter by project')
|
|
31
|
+
.option('--limit <number>', 'Limit results')
|
|
25
32
|
.action(async (query: string, options: any) => {
|
|
26
|
-
const result = await memory.search({
|
|
33
|
+
const result = await memory.search({
|
|
34
|
+
query,
|
|
35
|
+
type: options.type,
|
|
36
|
+
projectId: options.project,
|
|
37
|
+
limit: options.limit ? parseInt(options.limit) : undefined,
|
|
38
|
+
});
|
|
27
39
|
console.log(`Found ${result.total} observations:`);
|
|
28
|
-
result.observations.forEach((obs: Observation) => {
|
|
40
|
+
result.observations.forEach((obs: Observation) => {
|
|
41
|
+
console.log(` [${obs.type}] ${obs.title}\n ${obs.content.substring(0, 100)}...`);
|
|
42
|
+
});
|
|
29
43
|
memory.close();
|
|
30
44
|
});
|
|
31
45
|
|
|
32
|
-
program
|
|
33
|
-
.
|
|
34
|
-
.
|
|
35
|
-
.option(
|
|
46
|
+
program
|
|
47
|
+
.command('save <title> <content>')
|
|
48
|
+
.description('Save an observation')
|
|
49
|
+
.option('-t, --type <type>', 'Observation type', 'note')
|
|
50
|
+
.option('-k, --topic <topic>', 'Topic key')
|
|
51
|
+
.option('-p, --project <project>', 'Project ID', projectId)
|
|
36
52
|
.action(async (title: string, content: string, options: any) => {
|
|
37
53
|
const sessionId = await getOrCreateSessionId(options.project);
|
|
38
|
-
const observation = await memory.createObservation({
|
|
54
|
+
const observation = await memory.createObservation({
|
|
55
|
+
sessionId,
|
|
56
|
+
title,
|
|
57
|
+
content,
|
|
58
|
+
type: options.type,
|
|
59
|
+
topicKey: options.topic || null,
|
|
60
|
+
projectId: options.project,
|
|
61
|
+
metadata: {},
|
|
62
|
+
});
|
|
39
63
|
console.log(`Saved observation: ${observation.uuid}`);
|
|
40
64
|
memory.close();
|
|
41
65
|
});
|
|
42
66
|
|
|
43
|
-
program
|
|
67
|
+
program
|
|
68
|
+
.command('get <id>')
|
|
69
|
+
.description('Get observation by ID')
|
|
44
70
|
.action(async (id: string) => {
|
|
45
71
|
const observation = await memory.getObservation(parseInt(id));
|
|
46
|
-
if (!observation) {
|
|
47
|
-
|
|
72
|
+
if (!observation) {
|
|
73
|
+
console.error('Observation not found');
|
|
74
|
+
memory.close();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log(
|
|
78
|
+
`[${observation.type}] ${observation.title}\n${observation.content}\nTopic: ${observation.topicKey || 'none'}\nCreated: ${observation.createdAt.toISOString()}`
|
|
79
|
+
);
|
|
48
80
|
memory.close();
|
|
49
81
|
});
|
|
50
82
|
|
|
51
|
-
program
|
|
52
|
-
.
|
|
53
|
-
.
|
|
54
|
-
.option(
|
|
83
|
+
program
|
|
84
|
+
.command('update <id>')
|
|
85
|
+
.description('Update observation')
|
|
86
|
+
.option('-t, --title <title>', 'New title')
|
|
87
|
+
.option('-c, --content <content>', 'New content')
|
|
88
|
+
.option('-k, --topic <topic>', 'New topic key')
|
|
55
89
|
.action(async (id: string, options: any) => {
|
|
56
90
|
const updates: any = {};
|
|
57
91
|
if (options.title) updates.title = options.title;
|
|
@@ -62,29 +96,41 @@ program.command("update <id>").description("Update observation")
|
|
|
62
96
|
memory.close();
|
|
63
97
|
});
|
|
64
98
|
|
|
65
|
-
program
|
|
99
|
+
program
|
|
100
|
+
.command('delete <id>')
|
|
101
|
+
.description('Delete observation')
|
|
66
102
|
.action(async (id: string) => {
|
|
67
103
|
await memory.deleteObservation(parseInt(id));
|
|
68
104
|
console.log(`Deleted observation ${id}`);
|
|
69
105
|
memory.close();
|
|
70
106
|
});
|
|
71
107
|
|
|
72
|
-
program
|
|
73
|
-
.
|
|
108
|
+
program
|
|
109
|
+
.command('timeline [project]')
|
|
110
|
+
.description('Show timeline')
|
|
111
|
+
.option('-l, --limit <number>', 'Limit results', '20')
|
|
74
112
|
.action(async (project: string, options: any) => {
|
|
75
113
|
const result = await memory.search({ projectId: project, limit: parseInt(options.limit) });
|
|
76
114
|
console.log(`Timeline (${result.total} observations):`);
|
|
77
|
-
result.observations.forEach((obs: Observation) => {
|
|
115
|
+
result.observations.forEach((obs: Observation) => {
|
|
116
|
+
console.log(` ${obs.createdAt.toLocaleDateString()} [${obs.type}] ${obs.title}`);
|
|
117
|
+
});
|
|
78
118
|
memory.close();
|
|
79
119
|
});
|
|
80
120
|
|
|
81
|
-
program
|
|
121
|
+
program
|
|
122
|
+
.command('stats')
|
|
123
|
+
.description('Show statistics')
|
|
82
124
|
.action(async () => {
|
|
83
125
|
const result = await memory.search({});
|
|
84
126
|
const byType: Record<string, number> = {};
|
|
85
|
-
result.observations.forEach((obs: Observation) => {
|
|
127
|
+
result.observations.forEach((obs: Observation) => {
|
|
128
|
+
byType[obs.type] = (byType[obs.type] || 0) + 1;
|
|
129
|
+
});
|
|
86
130
|
console.log(`Statistics:\n Total observations: ${result.total}\n By type:`);
|
|
87
|
-
Object.entries(byType).forEach(([type, count]) => {
|
|
131
|
+
Object.entries(byType).forEach(([type, count]) => {
|
|
132
|
+
console.log(` ${type}: ${count}`);
|
|
133
|
+
});
|
|
88
134
|
memory.close();
|
|
89
135
|
});
|
|
90
136
|
|
package/data/memento.db
DELETED
|
Binary file
|
package/data/memento.db-shm
DELETED
|
Binary file
|
package/data/memento.db-wal
DELETED
|
Binary file
|
|
Binary file
|