@lotargo/memory_plugin 1.2.1 → 1.2.3

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/mcp-server/cli.js CHANGED
@@ -1109,13 +1109,26 @@ export async function runCli() {
1109
1109
  break;
1110
1110
  }
1111
1111
 
1112
- const docItems = docs.map((doc) => ({
1113
- label: doc.title || doc.path || "Untitled Document",
1114
- badge: doc.created_at ? doc.created_at.substring(0, 16) : "",
1115
- hint: doc.id ? `ID: ${doc.id.substring(0, 8)}...` : "",
1116
- info: `Path: ${doc.path || "N/A"}`,
1117
- value: doc,
1118
- }));
1112
+ const docItems = docs.map((doc) => {
1113
+ const rawDate = doc.created_at || doc.updated_at || "";
1114
+ let formattedDate = "";
1115
+ if (rawDate) {
1116
+ try {
1117
+ const d = typeof rawDate === "number" ? new Date(rawDate) : new Date(String(rawDate));
1118
+ formattedDate = isNaN(d.getTime()) ? String(rawDate).substring(0, 16) : d.toISOString().replace("T", " ").substring(0, 16);
1119
+ } catch (e) {
1120
+ formattedDate = String(rawDate).substring(0, 16);
1121
+ }
1122
+ }
1123
+ const docIdStr = doc.id != null ? String(doc.id) : "";
1124
+ return {
1125
+ label: doc.title || doc.path || "Untitled Document",
1126
+ badge: formattedDate,
1127
+ hint: docIdStr ? `ID: ${docIdStr.substring(0, 8)}...` : "",
1128
+ info: `Path: ${doc.path || "N/A"}`,
1129
+ value: doc,
1130
+ };
1131
+ });
1119
1132
  docItems.push({ label: "< Back to Main Menu", value: "back" });
1120
1133
 
1121
1134
  const docRes = await selectSimpleMenu({
@@ -148,13 +148,17 @@ export async function getExtractor(modelName = null, progressCallback = null) {
148
148
 
149
149
  if (targetModel !== "Xenova/multilingual-e5-small") {
150
150
  console.warn(`[Fallback] Reverting to standard default model "Xenova/multilingual-e5-small"...`);
151
+ resetExtractor();
151
152
  try {
152
- extractorInstance = await pipeline("feature-extraction", "Xenova/multilingual-e5-small", {
153
+ const fallbackOpts = {
153
154
  quantized: true,
154
155
  dtype: "q8",
155
156
  device: "cpu",
156
157
  session_options: { graphOptimizationLevel: "all", executionMode: "sequential" },
157
- });
158
+ };
159
+ if (progressCallback) fallbackOpts.progress_callback = progressCallback;
160
+
161
+ extractorInstance = await pipeline("feature-extraction", "Xenova/multilingual-e5-small", fallbackOpts);
158
162
  loadedModelName = "Xenova/multilingual-e5-small";
159
163
  loadedDevice = "cpu";
160
164
  } catch (err3) {
@@ -175,6 +179,38 @@ export function resetExtractor() {
175
179
  loadedDevice = null;
176
180
  }
177
181
 
182
+ export function deleteModelCache(modelName) {
183
+ const info = getModelStorageInfo(modelName);
184
+ if (info.status === "not_downloaded" || !fs.existsSync(info.dir)) {
185
+ return { deleted: false, reason: "Model directory not found" };
186
+ }
187
+
188
+ resetExtractor();
189
+ if (global.gc) {
190
+ try { global.gc(); } catch (e) {}
191
+ }
192
+
193
+ try {
194
+ fs.rmSync(info.dir, { recursive: true, force: true });
195
+ const parentDir = path.dirname(info.dir);
196
+ if (fs.existsSync(parentDir) && fs.readdirSync(parentDir).length === 0) {
197
+ fs.rmdirSync(parentDir);
198
+ }
199
+ return { deleted: true, modelName, freedMB: info.sizeMB };
200
+ } catch (err) {
201
+ try {
202
+ const corruptPath = `${info.dir}.corrupt_${Date.now()}`;
203
+ fs.renameSync(info.dir, corruptPath);
204
+ setTimeout(() => {
205
+ try { fs.rmSync(corruptPath, { recursive: true, force: true }); } catch (e) {}
206
+ }, 1000);
207
+ return { deleted: true, modelName, freedMB: info.sizeMB };
208
+ } catch (renameErr) {
209
+ return { deleted: false, reason: `${err.message} (Rename fallback: ${renameErr.message})` };
210
+ }
211
+ }
212
+ }
213
+
178
214
  export function formatInputText(text, isQuery = false, modelName = null, instruction = null) {
179
215
  if (!text) return "";
180
216
  const targetModel = modelName || getConfig().embeddingModel || "Xenova/multilingual-e5-small";
@@ -510,25 +546,6 @@ export function getModelStorageInfo(modelName) {
510
546
  return { status: "partial", sizeMB, bytes: totalBytes, dir: modelDir };
511
547
  }
512
548
 
513
- export function deleteModelCache(modelName) {
514
- const info = getModelStorageInfo(modelName);
515
- if (info.status === "not_downloaded" || !fs.existsSync(info.dir)) {
516
- return { deleted: false, reason: "Model directory not found" };
517
- }
518
-
519
- try {
520
- fs.rmSync(info.dir, { recursive: true, force: true });
521
- const parentDir = path.dirname(info.dir);
522
- if (fs.existsSync(parentDir) && fs.readdirSync(parentDir).length === 0) {
523
- fs.rmdirSync(parentDir);
524
- }
525
- resetExtractor();
526
- return { deleted: true, modelName, freedMB: info.sizeMB };
527
- } catch (err) {
528
- return { deleted: false, reason: err.message };
529
- }
530
- }
531
-
532
549
  export function listAllCachedModels() {
533
550
  const result = [];
534
551
  if (!fs.existsSync(MODELS_DIR)) return result;
@@ -8,7 +8,9 @@ const END_MARKER = "<!-- END MEMORY AGENT PROMPT -->";
8
8
 
9
9
  export const PROMPT_BLOCK = `${START_MARKER}
10
10
  [SYSTEM INSTRUCTION: PERSONAL CONTEXT & MEMORY AGENT]
11
- When starting a session or when personal/project context is relevant, use \`recall\` from \`memory-agent\` to load saved facts, user preferences, and project guidelines. Use \`remember\` to save any durable high-signal facts provided by the user.
11
+ 1. MANDATORY FIRST STEP (SESSION INITIALIZATION): At the very start of every session or conversation, your VERY FIRST ACTION MUST BE to execute \`recall\` from \`memory-agent\` to load all saved facts, user preferences, personal context, and project guidelines BEFORE performing any other tasks or reading code.
12
+ 2. PROACTIVE SAVING DIRECTIVE: You MUST automatically and proactively call \`remember\` from \`memory-agent\` whenever the user shares durable facts, personal preferences, coding guidelines, technology choices, or project architecture decisions. Do NOT wait for explicit user commands like "remember this".
13
+ 3. SIGNAL FILTER: Save only high-signal facts (name, language, roles, constraints, tech stack preferences, architecture decisions, conventions). Translate facts into clear, concise English when saving. Do NOT save transient details or one-off conversation turns.
12
14
  ${END_MARKER}`;
13
15
 
14
16
  export function getGlobalPromptTargets() {
@@ -115,9 +115,12 @@ export async function runSetup() {
115
115
  };
116
116
  await writeFile(geminiConfigFile, JSON.stringify(config, null, 2));
117
117
 
118
- // Local workspace config (.agents/mcp_config.json) if in project
118
+ // Local workspace config (.agents/mcp_config.json) only if .agents exists or --local flag is set
119
119
  const cwd = process.cwd();
120
- if (existsSync(join(cwd, ".agents")) || existsSync(join(cwd, "package.json")) || existsSync(join(cwd, ".git"))) {
120
+ const hasAgentsDir = existsSync(join(cwd, ".agents"));
121
+ const isLocalRequested = args.includes("--local");
122
+
123
+ if (hasAgentsDir || isLocalRequested) {
121
124
  const localAgentsDir = join(cwd, ".agents");
122
125
  await mkdir(localAgentsDir, { recursive: true });
123
126
  const localMcpFile = join(localAgentsDir, "mcp_config.json");
@@ -133,9 +136,10 @@ export async function runSetup() {
133
136
  args: ["-y", "@lotargo/memory_plugin"],
134
137
  };
135
138
  await writeFile(localMcpFile, JSON.stringify(localConfig, null, 2));
139
+ console.log(" [OK] Antigravity: configured MCP server in ~/.gemini/config/mcp_config.json and .agents/mcp_config.json");
140
+ } else {
141
+ console.log(" [OK] Antigravity: configured MCP server in ~/.gemini/config/mcp_config.json");
136
142
  }
137
-
138
- console.log(" [OK] Antigravity: configured MCP server in ~/.gemini/config/mcp_config.json and .agents/mcp_config.json");
139
143
  configuredCount++;
140
144
  } catch (err) {
141
145
  console.log(" [SKIP] Antigravity setup skipped:", err.message);
@@ -74,12 +74,15 @@ async function notify(client, message, variant = "success") {
74
74
  }
75
75
 
76
76
  const MEMORY_INSTRUCTION =
77
+ "MANDATORY FIRST STEP (READ MEMORIES FIRST):\n" +
78
+ "At the start of every session, you MUST thoroughly review all saved memories provided below BEFORE performing any user task or editing code.\n" +
79
+ "PROACTIVE MEMORY DIRECTIVE:\n" +
80
+ "You MUST automatically and proactively call `remember` whenever the user shares durable facts, personal preferences, coding guidelines, tech stack choices, architecture decisions, or project conventions.\n" +
81
+ "Do NOT wait for explicit user commands like \"remember this\". Automatically capture high-signal facts in real time.\n" +
77
82
  "Use `remember` only for important, durable facts about the user and project.\n" +
78
- "Save high-signal things like: name, language, role/goals, constraints, tech\n" +
79
- "stack preferences, architecture decisions, project conventions.\n" +
80
- "DO NOT save: transient details, one-off statements, full conversation turns,\n" +
81
- "or anything unlikely to be useful in future sessions.\n" +
82
- "When saving, translate the fact into English and keep it concise.\n" +
83
+ "Save high-signal items: user role, goals, constraints, tech stack preferences, architecture decisions, project conventions.\n" +
84
+ "DO NOT save: transient details, one-off statements, full conversation turns, or anything unlikely to be useful in future sessions.\n" +
85
+ "When saving, translate the fact into clear, concise English.\n" +
83
86
  "Use `scope: \"global\"` for personal facts, `scope: \"project\"` for project-specific facts.";
84
87
 
85
88
  function buildMemoryContext(globalFacts, projectFacts, projectKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotargo/memory_plugin",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Persistent memory agent for coding AI tools — remembers user preferences and project context across sessions. Works with Antigravity, OpenCode, Claude Code, and Codex.",
5
5
  "type": "module",
6
6
  "main": "opencode-plugin/index.js",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: using-memory
3
- description: Comprehensive guide for using the Memory & Hybrid RAG Knowledge Engine tools (remember, recall, forget, ingest_document, query_knowledge_base, manage_knowledge_base). Trigger whenever remembering user preferences/conventions, querying ingested documentation, indexing files/repos, or managing persistent knowledge.
3
+ description: Comprehensive guide for using the Memory & Hybrid RAG Knowledge Engine tools (remember, recall, forget, link_knowledge, ingest_document, query_knowledge_base, manage_knowledge_base). Trigger proactively whenever user preferences, project conventions, technology stack choices, or architecture decisions are introduced, or when querying ingested documentation, indexing files/repos, or managing persistent knowledge.
4
4
  ---
5
5
 
6
6
  # Using Memory & Hybrid RAG Knowledge Engine
@@ -116,7 +116,8 @@ In such cases, use the **Full Raw Document Reading** mechanism:
116
116
 
117
117
  ## 4. Core Directives for AI Agents
118
118
 
119
- 1. **Be Proactive**: When the user mentions a durable preference or constraint, save it immediately using `remember`.
120
- 2. **Check Knowledge Base First**: If a user asks how a specific module, API, or project architecture works, call `query_knowledge_base` using concept-dense search phrases.
121
- 3. **Inspect Ambiguous Docs Directly**: If querying produces low relevance scores on abstractly-named documents, call `manage_knowledge_base(action: "read_document")` to inspect the full text directly.
122
- 4. **Keep Memory Clean**: If a preference changes, call `forget` on the outdated entry before saving the new one.
119
+ 1. **Read Memories First (MANDATORY)**: At the very start of any session or conversation, your VERY FIRST STEP MUST BE to execute `recall` to load all saved facts, user context, and project guidelines BEFORE performing any other task or code analysis.
120
+ 2. **Be Proactive**: When the user mentions a durable preference, personal fact, or constraint, save it immediately using `remember`. Do not wait for explicit user commands.
121
+ 3. **Check Knowledge Base First**: If a user asks how a specific module, API, or project architecture works, call `query_knowledge_base` using concept-dense search phrases.
122
+ 4. **Inspect Ambiguous Docs Directly**: If querying produces low relevance scores on abstractly-named documents, call `manage_knowledge_base(action: "read_document")` to inspect the full text directly.
123
+ 5. **Keep Memory Clean**: If a preference changes, call `forget` on the outdated entry before saving the new one.