local-agent-memory 1.0.3 → 1.0.5

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 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
@@ -44,7 +45,16 @@ Comprueba el estado de sincronización del proyecto de memoria actual, mostrando
44
45
  memory status
45
46
  ```
46
47
 
47
- ### 4. `reindex` (o `prune`)
48
+ ### 4. `list` (o `projects`)
49
+ Muestra de forma interactiva una lista de todos los proyectos registrados globalmente en tu máquina. Permite seleccionar un proyecto y ver detalles como el total de archivos indexados, los registros de decisiones (ADRs) y los resúmenes de sesión (Ledgers) para ese proyecto.
50
+
51
+ ```bash
52
+ memory list
53
+ # o
54
+ memory projects
55
+ ```
56
+
57
+ ### 5. `reindex` (o `prune`)
48
58
  Reconstruye los índices FTS (texto completo) y vectoriales desde cero. Útil si sospechas que hay corrupción o desincronización en la base de datos local.
49
59
 
50
60
  ```bash
@@ -53,7 +63,7 @@ memory reindex
53
63
  memory prune
54
64
  ```
55
65
 
56
- ### 5. `record-session`
66
+ ### 6. `record-session`
57
67
  Registra un resumen de tu sesión de trabajo actual en el "ledger" (libro mayor) de memoria, documentando las tareas completadas y el contexto para retomarlo más adelante.
58
68
 
59
69
  **Opciones:**
@@ -63,14 +73,14 @@ Registra un resumen de tu sesión de trabajo actual en el "ledger" (libro mayor)
63
73
  memory record-session -s "Implementación del comando sync y corrección de bugs en SQLite"
64
74
  ```
65
75
 
66
- ### 6. `install-hook`
76
+ ### 7. `install-hook`
67
77
  Instala ganchos de Git (Git hooks) en tu repositorio local para recordar automáticamente a los desarrolladores registrar sesiones al hacer commits, o para automatizar el registro.
68
78
 
69
79
  ```bash
70
80
  memory install-hook
71
81
  ```
72
82
 
73
- ### 7. `template <action>`
83
+ ### 8. `template <action>`
74
84
  Gestiona las plantillas de memoria (permite listar, crear o exportar plantillas desde el proyecto).
75
85
 
76
86
  **Opciones:**
@@ -2,4 +2,5 @@ export declare function initProject(options?: {
2
2
  force?: boolean;
3
3
  rules?: string;
4
4
  docs?: string;
5
+ log?: boolean;
5
6
  }): Promise<void>;
@@ -47,6 +47,7 @@ async function initProject(options = {}) {
47
47
  project_id: projectId,
48
48
  created_at: new Date().toISOString(),
49
49
  include_paths: [".memory"],
50
+ log_usage: options.log !== false,
50
51
  };
51
52
  if (options.docs) {
52
53
  configData.include_paths.push(options.docs);
@@ -0,0 +1 @@
1
+ export declare function listProjects(): Promise<void>;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listProjects = listProjects;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const ora_1 = __importDefault(require("ora"));
11
+ const project_1 = require("../../db/project");
12
+ const registry_1 = require("../../db/registry");
13
+ async function listProjects() {
14
+ const spinner = (0, ora_1.default)("Cargando proyectos registrados...").start();
15
+ try {
16
+ const projects = await (0, registry_1.getAllProjectsFromRegistry)();
17
+ if (!projects || projects.length === 0) {
18
+ spinner.info("No hay proyectos registrados en la memoria global.");
19
+ return;
20
+ }
21
+ spinner.stop();
22
+ const { selectedPath } = await inquirer_1.default.prompt([
23
+ {
24
+ type: "list",
25
+ name: "selectedPath",
26
+ message: "Selecciona un proyecto para ver sus detalles:",
27
+ choices: projects.map((p) => ({
28
+ name: `${p.project_id} (${p.file_path}) - Creado: ${new Date(p.created_at).toLocaleString()}`,
29
+ value: p.file_path,
30
+ })),
31
+ },
32
+ ]);
33
+ console.log(`\nCargando datos para el proyecto en: ${selectedPath}`);
34
+ const memoryDir = node_path_1.default.join(selectedPath, ".memory");
35
+ if (!node_fs_1.default.existsSync(memoryDir)) {
36
+ console.log(`❌ La carpeta .memory no existe en el proyecto seleccionado (${memoryDir}).`);
37
+ return;
38
+ }
39
+ const localDbPath = (0, project_1.getLocalDbPath)(selectedPath);
40
+ let manifests = [];
41
+ if (node_fs_1.default.existsSync(localDbPath)) {
42
+ manifests = await (0, project_1.getAllManifests)(localDbPath);
43
+ }
44
+ console.log(`\n=== Registros del Proyecto ===`);
45
+ console.log(`Total de archivos Markdown registrados en la base de datos local: ${manifests.length}`);
46
+ if (manifests.length > 0) {
47
+ console.log(`\nArchivos registrados:`);
48
+ manifests.forEach((m) => {
49
+ console.log(` - ${m.file_path}`);
50
+ });
51
+ }
52
+ // You could also list recent decisions or ledgers specifically if needed
53
+ const decisionsDir = node_path_1.default.join(memoryDir, "decisions");
54
+ if (node_fs_1.default.existsSync(decisionsDir)) {
55
+ const decisions = node_fs_1.default
56
+ .readdirSync(decisionsDir)
57
+ .filter((f) => f.endsWith(".md"));
58
+ if (decisions.length > 0) {
59
+ console.log(`\nDecisiones Arquitectónicas (ADRs):`);
60
+ decisions.forEach((d) => console.log(` - decisions/${d}`));
61
+ }
62
+ }
63
+ const ledgerDir = node_path_1.default.join(memoryDir, "ledger");
64
+ if (node_fs_1.default.existsSync(ledgerDir)) {
65
+ const ledgers = node_fs_1.default
66
+ .readdirSync(ledgerDir)
67
+ .filter((f) => f.endsWith(".md"));
68
+ if (ledgers.length > 0) {
69
+ console.log(`\nRegistros de Sesión (Ledger):`);
70
+ ledgers.forEach((l) => console.log(` - ledger/${l}`));
71
+ }
72
+ }
73
+ console.log("\n==============================");
74
+ }
75
+ catch (err) {
76
+ spinner.fail("Error al listar proyectos.");
77
+ console.error(err.message);
78
+ process.exit(1);
79
+ }
80
+ }
@@ -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
@@ -19,16 +19,23 @@ program
19
19
  .version(require("../../package.json").version);
20
20
  const hook_1 = require("./commands/hook");
21
21
  const init_1 = require("./commands/init");
22
+ const list_1 = require("./commands/list");
22
23
  const record_1 = require("./commands/record");
23
24
  const status_1 = require("./commands/status");
24
25
  const sync_1 = require("./commands/sync");
25
26
  const template_1 = require("./commands/template");
27
+ program
28
+ .command("list")
29
+ .alias("projects")
30
+ .description("List registered projects and view their records")
31
+ .action(list_1.listProjects);
26
32
  program
27
33
  .command("init")
28
34
  .description("Initialize a new memory project")
29
35
  .option("-f, --force", "Force initialization even if already exists")
30
36
  .option("-r, --rules <rules>", "Comma-separated IDE rules to inject (cursor,claude,copilot,antigravity-ide,antigravity-cli,all)")
31
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")
32
39
  .action(init_1.initProject);
33
40
  program
34
41
  .command("template <action>")
@@ -7,3 +7,9 @@ export declare function getProjectRootFromRegistry(activePath: string, dbPath?:
7
7
  path: string;
8
8
  fallback: boolean;
9
9
  } | null>;
10
+ export interface RegistryProject {
11
+ project_id: string;
12
+ file_path: string;
13
+ created_at: string;
14
+ }
15
+ export declare function getAllProjectsFromRegistry(dbPath?: string): Promise<RegistryProject[]>;
@@ -8,6 +8,7 @@ exports.initRegistryDb = initRegistryDb;
8
8
  exports.registerProject = registerProject;
9
9
  exports.getProjectByPath = getProjectByPath;
10
10
  exports.getProjectRootFromRegistry = getProjectRootFromRegistry;
11
+ exports.getAllProjectsFromRegistry = getAllProjectsFromRegistry;
11
12
  const node_fs_1 = __importDefault(require("node:fs"));
12
13
  const node_path_1 = __importDefault(require("node:path"));
13
14
  const sqlite3_1 = __importDefault(require("sqlite3"));
@@ -90,3 +91,15 @@ async function getProjectRootFromRegistry(activePath, dbPath = getRegistryDbPath
90
91
  });
91
92
  });
92
93
  }
94
+ async function getAllProjectsFromRegistry(dbPath = getRegistryDbPath()) {
95
+ return new Promise((resolve, reject) => {
96
+ const db = initRegistryDb(dbPath);
97
+ db.all("SELECT project_id, file_path, created_at FROM projects ORDER BY created_at DESC", [], (err, rows) => {
98
+ db.close();
99
+ if (err) {
100
+ return reject(err);
101
+ }
102
+ resolve(rows);
103
+ });
104
+ });
105
+ }
@@ -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
+ }
@@ -38,6 +38,7 @@ const fs = __importStar(require("node:fs"));
38
38
  const path = __importStar(require("node:path"));
39
39
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
40
40
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
41
+ const logger_1 = require("./logger");
41
42
  const tools_1 = require("./tools");
42
43
  const utils_1 = require("./utils");
43
44
  async function setupMCPServer() {
@@ -57,6 +58,9 @@ async function setupMCPServer() {
57
58
  });
58
59
  server.resource("agent-guidelines", "memory://agent-guidelines", { description: "Agent guidelines and memory core rules" }, async (uri) => {
59
60
  const { cwd: resolvedCwd } = await (0, utils_1.resolveCwd)();
61
+ (0, logger_1.logUsage)(resolvedCwd, "RESOURCE_READ: agent-guidelines", {
62
+ uri: uri.href,
63
+ });
60
64
  const corePath = path.join(resolvedCwd, ".memory", "core.md");
61
65
  const text = fs.existsSync(corePath)
62
66
  ? fs.readFileSync(corePath, "utf8")
@@ -73,6 +77,7 @@ async function setupMCPServer() {
73
77
  });
74
78
  server.prompt("agent-guidelines", "Get the agent guidelines and memory core rules", async () => {
75
79
  const { cwd: resolvedCwd } = await (0, utils_1.resolveCwd)();
80
+ (0, logger_1.logUsage)(resolvedCwd, "PROMPT_GET: agent-guidelines");
76
81
  const corePath = path.join(resolvedCwd, ".memory", "core.md");
77
82
  const text = fs.existsSync(corePath)
78
83
  ? fs.readFileSync(corePath, "utf8")
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-agent-memory",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",