local-agent-memory 1.0.4 → 1.0.6
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/README.md +1 -0
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.js +1 -0
- package/dist/cli/commands/list.js +12 -4
- package/dist/cli/commands/status.js +3 -0
- package/dist/cli/commands/sync.js +3 -0
- package/dist/cli/index.js +1 -0
- package/dist/core/parser.js +10 -8
- package/dist/core/sync.js +2 -0
- package/dist/mcp/logger.d.ts +10 -0
- package/dist/mcp/logger.js +78 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +34 -0
- package/dist/mcp/tools.js +19 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ Inicializa el entorno de memoria en el repositorio actual. Esto crea las bases d
|
|
|
25
25
|
- `-f, --force`: Fuerza la inicialización incluso si el proyecto ya fue inicializado.
|
|
26
26
|
- `-r, --rules <rules>`: Inyecta reglas específicas para tu IDE (opciones: `cursor`, `claude`, `copilot`, `antigravity-ide`, `antigravity-cli`, `all`).
|
|
27
27
|
- `-d, --docs <path>`: Ruta opcional a un directorio de documentación existente para mapearlo/indexarlo automáticamente.
|
|
28
|
+
- `--no-log`: Desactiva el registro automático de llamadas del agente en `.memory/usage.log` (activado por defecto vía `"log_usage": true` en `.memory/config.json`).
|
|
28
29
|
|
|
29
30
|
```bash
|
|
30
31
|
memory init --rules all --docs ./docs
|
|
@@ -52,18 +52,26 @@ async function listProjects() {
|
|
|
52
52
|
// You could also list recent decisions or ledgers specifically if needed
|
|
53
53
|
const decisionsDir = node_path_1.default.join(memoryDir, "decisions");
|
|
54
54
|
if (node_fs_1.default.existsSync(decisionsDir)) {
|
|
55
|
-
const decisions = node_fs_1.default
|
|
55
|
+
const decisions = node_fs_1.default
|
|
56
|
+
.readdirSync(decisionsDir)
|
|
57
|
+
.filter((f) => f.endsWith(".md"));
|
|
56
58
|
if (decisions.length > 0) {
|
|
57
59
|
console.log(`\nDecisiones Arquitectónicas (ADRs):`);
|
|
58
|
-
|
|
60
|
+
for (const d of decisions) {
|
|
61
|
+
console.log(` - decisions/${d}`);
|
|
62
|
+
}
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
const ledgerDir = node_path_1.default.join(memoryDir, "ledger");
|
|
62
66
|
if (node_fs_1.default.existsSync(ledgerDir)) {
|
|
63
|
-
const ledgers = node_fs_1.default
|
|
67
|
+
const ledgers = node_fs_1.default
|
|
68
|
+
.readdirSync(ledgerDir)
|
|
69
|
+
.filter((f) => f.endsWith(".md"));
|
|
64
70
|
if (ledgers.length > 0) {
|
|
65
71
|
console.log(`\nRegistros de Sesión (Ledger):`);
|
|
66
|
-
|
|
72
|
+
for (const l of ledgers) {
|
|
73
|
+
console.log(` - ledger/${l}`);
|
|
74
|
+
}
|
|
67
75
|
}
|
|
68
76
|
}
|
|
69
77
|
console.log("\n==============================");
|
|
@@ -78,6 +78,9 @@ async function getAllMarkdownFiles(dirPath, arrayOfFiles = []) {
|
|
|
78
78
|
const files = await node_fs_1.default.promises.readdir(dirPath, { withFileTypes: true });
|
|
79
79
|
for (const file of files) {
|
|
80
80
|
if (file.isDirectory()) {
|
|
81
|
+
if (file.name === "node_modules" || file.name === ".git") {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
81
84
|
arrayOfFiles = await getAllMarkdownFiles(node_path_1.default.join(dirPath, file.name), arrayOfFiles);
|
|
82
85
|
}
|
|
83
86
|
else if (file.name.endsWith(".md")) {
|
|
@@ -115,6 +115,9 @@ async function getAllMarkdownFiles(dirPath, arrayOfFiles = []) {
|
|
|
115
115
|
const files = await node_fs_1.default.promises.readdir(dirPath, { withFileTypes: true });
|
|
116
116
|
for (const file of files) {
|
|
117
117
|
if (file.isDirectory()) {
|
|
118
|
+
if (file.name === "node_modules" || file.name === ".git") {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
118
121
|
arrayOfFiles = await getAllMarkdownFiles(node_path_1.default.join(dirPath, file.name), arrayOfFiles);
|
|
119
122
|
}
|
|
120
123
|
else if (file.name.endsWith(".md")) {
|
package/dist/cli/index.js
CHANGED
|
@@ -35,6 +35,7 @@ program
|
|
|
35
35
|
.option("-f, --force", "Force initialization even if already exists")
|
|
36
36
|
.option("-r, --rules <rules>", "Comma-separated IDE rules to inject (cursor,claude,copilot,antigravity-ide,antigravity-cli,all)")
|
|
37
37
|
.option("-d, --docs <path>", "Optional path to an existing docs directory to map/index automatically")
|
|
38
|
+
.option("--no-log", "Disable automatic agent memory usage logging in .memory/usage.log")
|
|
38
39
|
.action(init_1.initProject);
|
|
39
40
|
program
|
|
40
41
|
.command("template <action>")
|
package/dist/core/parser.js
CHANGED
|
@@ -76,13 +76,15 @@ async function parseMarkdown(content, path, maxTokens = 450, overlapTokens = 50)
|
|
|
76
76
|
if (currentBlocks.length > 0) {
|
|
77
77
|
const first = currentBlocks[0];
|
|
78
78
|
const last = currentBlocks[currentBlocks.length - 1];
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
if (first && last) {
|
|
80
|
+
chunks.push({
|
|
81
|
+
path,
|
|
82
|
+
text: currentBlocks.map((b) => b.text).join("\n\n"),
|
|
83
|
+
breadcrumbs: first.breadcrumb,
|
|
84
|
+
startLine: first.startLine,
|
|
85
|
+
endLine: last.endLine,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
if (ast?.children) {
|
|
@@ -131,7 +133,7 @@ async function parseMarkdown(content, path, maxTokens = 450, overlapTokens = 50)
|
|
|
131
133
|
let overlapTokensCount = 0;
|
|
132
134
|
for (let i = currentBlocks.length - 1; i >= 0; i--) {
|
|
133
135
|
const b = currentBlocks[i];
|
|
134
|
-
if (overlapTokensCount + b.tokens <= overlapTokens) {
|
|
136
|
+
if (b && overlapTokensCount + b.tokens <= overlapTokens) {
|
|
135
137
|
overlapBlocks.unshift(b);
|
|
136
138
|
overlapTokensCount += b.tokens;
|
|
137
139
|
}
|
package/dist/core/sync.js
CHANGED
|
@@ -113,6 +113,8 @@ async function syncFile(path, content, db) {
|
|
|
113
113
|
for (let j = 0; j < batch.length; j++) {
|
|
114
114
|
const chunk = batch[j];
|
|
115
115
|
const embedding = embeddings[j];
|
|
116
|
+
if (!chunk || !embedding)
|
|
117
|
+
continue;
|
|
116
118
|
// Store in main table
|
|
117
119
|
await asyncDb.run("INSERT INTO chunks (path, text, breadcrumbs, startLine, endLine) VALUES (?, ?, ?, ?, ?)", [
|
|
118
120
|
chunk.path,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface MemoryConfig {
|
|
2
|
+
project_id?: string;
|
|
3
|
+
created_at?: string;
|
|
4
|
+
include_paths?: string[];
|
|
5
|
+
log_usage?: boolean;
|
|
6
|
+
usage_log_file?: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export declare function getMemoryConfig(cwd: string): MemoryConfig | null;
|
|
10
|
+
export declare function logUsage(cwd: string, action: string, details?: Record<string, unknown>): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getMemoryConfig = getMemoryConfig;
|
|
37
|
+
exports.logUsage = logUsage;
|
|
38
|
+
const fs = __importStar(require("node:fs"));
|
|
39
|
+
const path = __importStar(require("node:path"));
|
|
40
|
+
function getMemoryConfig(cwd) {
|
|
41
|
+
const configPath = path.join(cwd, ".memory", "config.json");
|
|
42
|
+
if (!fs.existsSync(configPath)) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const raw = fs.readFileSync(configPath, "utf8");
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function logUsage(cwd, action, details) {
|
|
54
|
+
try {
|
|
55
|
+
const config = getMemoryConfig(cwd);
|
|
56
|
+
if (!config?.log_usage) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const logRelativePath = config.usage_log_file || path.join(".memory", "usage.log");
|
|
60
|
+
const logFilePath = path.isAbsolute(logRelativePath)
|
|
61
|
+
? logRelativePath
|
|
62
|
+
: path.join(cwd, logRelativePath);
|
|
63
|
+
const logDir = path.dirname(logFilePath);
|
|
64
|
+
if (!fs.existsSync(logDir)) {
|
|
65
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
const timestamp = new Date().toISOString();
|
|
68
|
+
let detailsStr = "";
|
|
69
|
+
if (details && Object.keys(details).length > 0) {
|
|
70
|
+
detailsStr = ` | ${JSON.stringify(details)}`;
|
|
71
|
+
}
|
|
72
|
+
const entry = `[${timestamp}] ${action}${detailsStr}\n`;
|
|
73
|
+
fs.appendFileSync(logFilePath, entry, "utf8");
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Fail silently to avoid breaking any MCP operation
|
|
77
|
+
}
|
|
78
|
+
}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2
3
|
export declare function setupMCPServer(): Promise<McpServer>;
|
|
4
|
+
export declare function setupProcessLifecycle(transport: StdioServerTransport, log?: (msg: string) => void): void;
|
package/dist/mcp/server.js
CHANGED
|
@@ -34,10 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.setupMCPServer = setupMCPServer;
|
|
37
|
+
exports.setupProcessLifecycle = setupProcessLifecycle;
|
|
37
38
|
const fs = __importStar(require("node:fs"));
|
|
38
39
|
const path = __importStar(require("node:path"));
|
|
39
40
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
40
41
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
42
|
+
const logger_1 = require("./logger");
|
|
41
43
|
const tools_1 = require("./tools");
|
|
42
44
|
const utils_1 = require("./utils");
|
|
43
45
|
async function setupMCPServer() {
|
|
@@ -57,6 +59,9 @@ async function setupMCPServer() {
|
|
|
57
59
|
});
|
|
58
60
|
server.resource("agent-guidelines", "memory://agent-guidelines", { description: "Agent guidelines and memory core rules" }, async (uri) => {
|
|
59
61
|
const { cwd: resolvedCwd } = await (0, utils_1.resolveCwd)();
|
|
62
|
+
(0, logger_1.logUsage)(resolvedCwd, "RESOURCE_READ: agent-guidelines", {
|
|
63
|
+
uri: uri.href,
|
|
64
|
+
});
|
|
60
65
|
const corePath = path.join(resolvedCwd, ".memory", "core.md");
|
|
61
66
|
const text = fs.existsSync(corePath)
|
|
62
67
|
? fs.readFileSync(corePath, "utf8")
|
|
@@ -73,6 +78,7 @@ async function setupMCPServer() {
|
|
|
73
78
|
});
|
|
74
79
|
server.prompt("agent-guidelines", "Get the agent guidelines and memory core rules", async () => {
|
|
75
80
|
const { cwd: resolvedCwd } = await (0, utils_1.resolveCwd)();
|
|
81
|
+
(0, logger_1.logUsage)(resolvedCwd, "PROMPT_GET: agent-guidelines");
|
|
76
82
|
const corePath = path.join(resolvedCwd, ".memory", "core.md");
|
|
77
83
|
const text = fs.existsSync(corePath)
|
|
78
84
|
? fs.readFileSync(corePath, "utf8")
|
|
@@ -94,9 +100,37 @@ async function setupMCPServer() {
|
|
|
94
100
|
transport.onerror = (err) => {
|
|
95
101
|
log(`Transport error: ${err}`);
|
|
96
102
|
};
|
|
103
|
+
setupProcessLifecycle(transport, log);
|
|
97
104
|
await server.connect(transport);
|
|
98
105
|
log("MCP Server connected via stdio");
|
|
99
106
|
// Opcionalmente podemos exponer log para ser usado por tools si se lo pasamos,
|
|
100
107
|
// pero el servidor ya está funcionando y registrando arranque y errores.
|
|
101
108
|
return server;
|
|
102
109
|
}
|
|
110
|
+
function setupProcessLifecycle(transport, log = () => { }) {
|
|
111
|
+
let isExiting = false;
|
|
112
|
+
const exitHandler = (reason) => {
|
|
113
|
+
if (isExiting)
|
|
114
|
+
return;
|
|
115
|
+
isExiting = true;
|
|
116
|
+
log(`Shutting down MCP server: ${reason}`);
|
|
117
|
+
process.exit(0);
|
|
118
|
+
};
|
|
119
|
+
process.stdin.on("close", () => exitHandler("stdin closed"));
|
|
120
|
+
process.stdin.on("end", () => exitHandler("stdin ended"));
|
|
121
|
+
transport.onclose = () => exitHandler("transport closed");
|
|
122
|
+
process.on("SIGINT", () => exitHandler("SIGINT received"));
|
|
123
|
+
process.on("SIGTERM", () => exitHandler("SIGTERM received"));
|
|
124
|
+
if (process.ppid && process.ppid !== 1) {
|
|
125
|
+
const parentCheckInterval = setInterval(() => {
|
|
126
|
+
try {
|
|
127
|
+
process.kill(process.ppid, 0);
|
|
128
|
+
}
|
|
129
|
+
catch (_e) {
|
|
130
|
+
clearInterval(parentCheckInterval);
|
|
131
|
+
exitHandler(`parent process ${process.ppid} exited`);
|
|
132
|
+
}
|
|
133
|
+
}, 2000);
|
|
134
|
+
parentCheckInterval.unref();
|
|
135
|
+
}
|
|
136
|
+
}
|
package/dist/mcp/tools.js
CHANGED
|
@@ -39,6 +39,7 @@ const path = __importStar(require("node:path"));
|
|
|
39
39
|
const zod_1 = require("zod");
|
|
40
40
|
const search_1 = require("../core/search");
|
|
41
41
|
const project_1 = require("../db/project");
|
|
42
|
+
const logger_1 = require("./logger");
|
|
42
43
|
const middleware_1 = require("./middleware");
|
|
43
44
|
const utils_1 = require("./utils");
|
|
44
45
|
function registerTools(server) {
|
|
@@ -50,6 +51,9 @@ function registerTools(server) {
|
|
|
50
51
|
.describe("Ruta absoluta del proyecto (usar si MCP es global)"),
|
|
51
52
|
}, async (args) => {
|
|
52
53
|
const { cwd, fallbackUsed } = await (0, utils_1.resolveCwd)(args.projectRoot, server);
|
|
54
|
+
(0, logger_1.logUsage)(cwd, "TOOL_CALL: get_project_context", {
|
|
55
|
+
projectRoot: args.projectRoot,
|
|
56
|
+
});
|
|
53
57
|
await (0, middleware_1.syncMiddleware)(cwd);
|
|
54
58
|
const memoryDir = path.join(cwd, ".memory");
|
|
55
59
|
const corePath = path.join(memoryDir, "core.md");
|
|
@@ -88,6 +92,11 @@ function registerTools(server) {
|
|
|
88
92
|
.describe("Ruta absoluta del proyecto (usar si MCP es global)"),
|
|
89
93
|
}, async (args) => {
|
|
90
94
|
const { cwd, fallbackUsed } = await (0, utils_1.resolveCwd)(args.projectRoot, server);
|
|
95
|
+
(0, logger_1.logUsage)(cwd, "TOOL_CALL: search_memory", {
|
|
96
|
+
query: args.query,
|
|
97
|
+
filter: args.filter,
|
|
98
|
+
limit: args.limit,
|
|
99
|
+
});
|
|
91
100
|
await (0, middleware_1.syncMiddleware)(cwd);
|
|
92
101
|
const dbPath = (0, project_1.getLocalDbPath)(cwd);
|
|
93
102
|
const db = (0, project_1.initLocalDb)(dbPath);
|
|
@@ -138,6 +147,10 @@ function registerTools(server) {
|
|
|
138
147
|
.replace(/(^-|-$)/g, "");
|
|
139
148
|
const filename = `${date}-${slug}.md`;
|
|
140
149
|
const { cwd, fallbackUsed } = await (0, utils_1.resolveCwd)(args.projectRoot, server);
|
|
150
|
+
(0, logger_1.logUsage)(cwd, "TOOL_CALL: log_decision", {
|
|
151
|
+
title: args.title,
|
|
152
|
+
status: args.status,
|
|
153
|
+
});
|
|
141
154
|
const memoryDir = path.join(cwd, ".memory");
|
|
142
155
|
const decisionsDir = path.join(memoryDir, "decisions");
|
|
143
156
|
if (!fs.existsSync(decisionsDir)) {
|
|
@@ -186,6 +199,9 @@ ${args.consequences}
|
|
|
186
199
|
.describe("Ruta absoluta del proyecto (usar si MCP es global)"),
|
|
187
200
|
}, async (args) => {
|
|
188
201
|
const { cwd, fallbackUsed } = await (0, utils_1.resolveCwd)(args.projectRoot, server);
|
|
202
|
+
(0, logger_1.logUsage)(cwd, "TOOL_CALL: update_core_rules", {
|
|
203
|
+
charsAdded: args.changes_to_append.length,
|
|
204
|
+
});
|
|
189
205
|
const memoryDir = path.join(cwd, ".memory");
|
|
190
206
|
const corePath = path.join(memoryDir, "core.md");
|
|
191
207
|
if (!fs.existsSync(memoryDir)) {
|
|
@@ -213,6 +229,9 @@ ${args.consequences}
|
|
|
213
229
|
.describe("Ruta absoluta del proyecto (usar si MCP es global)"),
|
|
214
230
|
}, async (args) => {
|
|
215
231
|
const { cwd, fallbackUsed } = await (0, utils_1.resolveCwd)(args.projectRoot, server);
|
|
232
|
+
(0, logger_1.logUsage)(cwd, "TOOL_CALL: end_session", {
|
|
233
|
+
summaryLength: args.summary.length,
|
|
234
|
+
});
|
|
216
235
|
const memoryDir = path.join(cwd, ".memory");
|
|
217
236
|
const ledgerDir = path.join(memoryDir, "ledger");
|
|
218
237
|
const dateObj = new Date();
|