@jcyamacho/agent-memory 0.0.15 → 0.0.18

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 (3) hide show
  1. package/README.md +37 -109
  2. package/dist/index.js +128 -42
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -3,16 +3,16 @@
3
3
  Persistent memory for MCP-powered coding agents.
4
4
 
5
5
  `agent-memory` is a stdio MCP server that gives your LLM durable memory backed
6
- by SQLite. It exposes four tools:
6
+ by SQLite. It helps your agent remember preferences, project context, and prior
7
+ decisions across sessions.
8
+
9
+ It exposes four tools:
7
10
 
8
11
  - `remember` -> save facts, decisions, preferences, and project context
9
12
  - `recall` -> retrieve the most relevant memories later
10
13
  - `revise` -> update an existing memory when it becomes outdated
11
14
  - `forget` -> delete a memory that is no longer relevant
12
15
 
13
- Use it when your agent should remember preferences, project facts, and prior
14
- decisions across sessions.
15
-
16
16
  ## Quick Start
17
17
 
18
18
  Claude CLI:
@@ -27,104 +27,56 @@ Codex CLI:
27
27
  codex mcp add memory -- npx -y @jcyamacho/agent-memory
28
28
  ```
29
29
 
30
- Example MCP server config:
31
-
32
- ```json
33
- {
34
- "mcpServers": {
35
- "memory": {
36
- "command": "npx",
37
- "args": [
38
- "-y",
39
- "@jcyamacho/agent-memory"
40
- ]
41
- }
42
- }
43
- }
44
- ```
45
-
46
- With a custom database path:
30
+ OpenCode:
47
31
 
48
- ```json
32
+ ```jsonc
49
33
  {
50
- "mcpServers": {
34
+ "$schema": "https://opencode.ai/config.json",
35
+ "mcp": {
51
36
  "memory": {
52
- "command": "npx",
53
- "args": [
54
- "-y",
55
- "@jcyamacho/agent-memory"
56
- ],
57
- "env": {
58
- "AGENT_MEMORY_DB_PATH": "/absolute/path/to/memory.db"
59
- }
37
+ "type": "local",
38
+ "command": ["npx", "-y", "@jcyamacho/agent-memory"]
60
39
  }
61
40
  }
62
41
  }
63
42
  ```
64
43
 
65
- With a custom model cache path:
66
-
67
- ```json
68
- {
69
- "mcpServers": {
70
- "memory": {
71
- "command": "npx",
72
- "args": [
73
- "-y",
74
- "@jcyamacho/agent-memory"
75
- ],
76
- "env": {
77
- "AGENT_MEMORY_MODELS_CACHE_PATH": "/absolute/path/to/models"
78
- }
79
- }
80
- }
81
- }
82
- ```
44
+ ## Optional LLM Instructions
83
45
 
84
46
  Optional LLM instructions to reinforce the MCP's built-in guidance:
85
47
 
86
- ```text
87
- Use `recall` at conversation start and before design choices, conventions, or
88
- edge cases. Query with 2-5 short anchor-heavy terms or exact phrases, not
89
- questions or sentences. `recall` is lexical-first; if it misses, retry once
90
- with overlapping alternate terms. Use `remember` for one durable fact, then
91
- use `revise` instead of duplicates and `forget` for wrong or obsolete
92
- memories. Always pass workspace unless the memory is truly global.
48
+ ```md
49
+ ## Agent Memory
50
+
51
+ - Use `memory_recall` at conversation start and before design choices,
52
+ conventions, or edge cases.
53
+ - Query `memory_recall` with 2-5 short anchor-heavy terms or exact phrases,
54
+ not full questions or sentences.
55
+ - Pass `workspace` for project-scoped memory. Omit it only for truly global memories.
56
+ - Use `memory_remember` to save one durable fact when the user states a stable
57
+ preference, correction, or reusable project decision.
58
+ - If the fact already exists, use `memory_revise` instead of creating a duplicate.
59
+ - Use `memory_forget` to remove a wrong or obsolete memory.
60
+ - Do not store secrets or temporary task state in memory.
93
61
  ```
94
62
 
95
- ## What It Stores
96
-
97
- This MCP is useful for context that should survive across turns and sessions:
98
-
99
- - User preferences like response style, formatting, and workflow habits
100
- - Project facts like paths, architecture choices, and conventions
101
- - Important decisions and constraints that should not be rediscovered
102
- - Project-scoped notes that still matter later
103
-
104
63
  ## Web UI
105
64
 
106
65
  Browse, edit, and delete memories in a local web interface:
107
66
 
108
67
  ```bash
109
- npx -y @jcyamacho/agent-memory --ui
68
+ npx -y @jcyamacho/agent-memory@latest --ui
110
69
  ```
111
70
 
112
71
  Opens at `http://localhost:6580`. Use `--port` to change:
113
72
 
114
73
  ```bash
115
- npx -y @jcyamacho/agent-memory --ui --port 9090
74
+ npx -y @jcyamacho/agent-memory@latest --ui --port 9090
116
75
  ```
117
76
 
118
77
  The web UI uses the same database as the MCP server.
119
78
 
120
- ## Tools
121
-
122
- - `remember` saves durable facts, preferences, decisions, and project context.
123
- - `recall` retrieves the most relevant saved memories.
124
- - `revise` updates an existing memory when it becomes outdated.
125
- - `forget` deletes a memory that is no longer relevant.
126
-
127
- ## How Ranking Works
79
+ ## How Recall Finds Memories
128
80
 
129
81
  `recall` uses a multi-signal ranking system to surface the most relevant
130
82
  memories:
@@ -147,7 +99,13 @@ If you omit `workspace`, recall still uses text relevance, embedding similarity,
147
99
  and recency. For best results, pass `workspace` whenever you have one. Save
148
100
  memories without a workspace only when they apply across all projects.
149
101
 
150
- ## Database location
102
+ When you save a memory from a git worktree, `agent-memory` stores the main repo
103
+ root as the workspace. `recall` applies the same normalization to incoming
104
+ workspace queries so linked worktrees still match repo-scoped memories exactly.
105
+
106
+ ## Configuration
107
+
108
+ ### Database Location
151
109
 
152
110
  By default, the SQLite database is created at:
153
111
 
@@ -167,7 +125,7 @@ Set `AGENT_MEMORY_DB_PATH` when you want to:
167
125
  - share a memory DB across multiple clients
168
126
  - store the DB somewhere easier to back up or inspect
169
127
 
170
- ## Model cache location
128
+ ### Model Cache Location
171
129
 
172
130
  By default, downloaded embedding model files are cached at:
173
131
 
@@ -187,38 +145,8 @@ Set `AGENT_MEMORY_MODELS_CACHE_PATH` when you want to:
187
145
  - share the model cache across reinstalls or multiple clients
188
146
  - store model downloads somewhere easier to inspect or manage
189
147
 
190
- Beta note: schema changes are not migrated. If you are upgrading from an older
191
- beta, delete the existing memory DB and let the server create a new one.
192
-
193
- ## Development
194
-
195
- For working on the project itself or running from source. Requires Bun and
196
- Node.js.
197
-
198
- ```bash
199
- bun install
200
- bun run build
201
- ```
202
-
203
- To use a local build as your MCP server:
204
-
205
- ```json
206
- {
207
- "mcpServers": {
208
- "memory": {
209
- "command": "node",
210
- "args": [
211
- "/absolute/path/to/agent-memory/dist/index.js"
212
- ]
213
- }
214
- }
215
- }
216
- ```
217
-
218
- ```bash
219
- bun lint
220
- bun test
221
- ```
148
+ Schema changes are migrated automatically, including workspace normalization for
149
+ existing git worktree memories when the original path can still be resolved.
222
150
 
223
151
  ## License
224
152
 
package/dist/index.js CHANGED
@@ -12464,7 +12464,7 @@ class StdioServerTransport {
12464
12464
  }
12465
12465
  }
12466
12466
  // package.json
12467
- var version2 = "0.0.15";
12467
+ var version2 = "0.0.18";
12468
12468
 
12469
12469
  // src/config.ts
12470
12470
  import { homedir } from "node:os";
@@ -20058,11 +20058,17 @@ function parseOptionalDate(value, fieldName) {
20058
20058
 
20059
20059
  // src/mcp/tools/forget.ts
20060
20060
  var forgetInputSchema = {
20061
- id: string2().describe("The memory id to delete. Use an id returned by `recall`.")
20061
+ id: string2().describe("Memory id to delete. Use an id returned by `recall`.")
20062
20062
  };
20063
20063
  function registerForgetTool(server, memory) {
20064
20064
  server.registerTool("forget", {
20065
- description: 'Permanently delete a wrong or obsolete memory. Use `revise` instead when the fact still exists and only needs correction. Returns `<memory id="..." deleted="true" />`.',
20065
+ annotations: {
20066
+ title: "Forget",
20067
+ destructiveHint: true,
20068
+ idempotentHint: true,
20069
+ openWorldHint: false
20070
+ },
20071
+ description: 'Delete a memory that is wrong or obsolete. Use after `recall` when you have the memory id. Use `revise` instead if the fact should remain with corrected wording. Returns `<memory id="..." deleted="true" />`.',
20066
20072
  inputSchema: forgetInputSchema
20067
20073
  }, async ({ id }) => {
20068
20074
  try {
@@ -20146,19 +20152,22 @@ var MAX_LIST_LIMIT = 100;
20146
20152
  class MemoryService {
20147
20153
  repository;
20148
20154
  embeddingService;
20149
- constructor(repository, embeddingService) {
20155
+ workspaceResolver;
20156
+ constructor(repository, embeddingService, workspaceResolver) {
20150
20157
  this.repository = repository;
20151
20158
  this.embeddingService = embeddingService;
20159
+ this.workspaceResolver = workspaceResolver;
20152
20160
  }
20153
20161
  async create(input) {
20154
20162
  const content = input.content.trim();
20155
20163
  if (!content) {
20156
20164
  throw new ValidationError("Memory content is required.");
20157
20165
  }
20166
+ const workspace = await this.workspaceResolver.resolve(input.workspace);
20158
20167
  const memory = await this.repository.create({
20159
20168
  content,
20160
20169
  embedding: await this.embeddingService.createVector(content),
20161
- workspace: normalizeOptionalString(input.workspace)
20170
+ workspace
20162
20171
  });
20163
20172
  return toPublicMemoryRecord(memory);
20164
20173
  }
@@ -20184,7 +20193,7 @@ class MemoryService {
20184
20193
  return memory ? toPublicMemoryRecord(memory) : undefined;
20185
20194
  }
20186
20195
  async list(input) {
20187
- const workspace = normalizeOptionalString(input.workspace);
20196
+ const workspace = await this.workspaceResolver.resolve(input.workspace);
20188
20197
  const page = await this.repository.list({
20189
20198
  workspace,
20190
20199
  workspaceIsNull: workspace ? false : Boolean(input.workspaceIsNull),
@@ -20202,7 +20211,7 @@ class MemoryService {
20202
20211
  throw new ValidationError("At least one search term is required.");
20203
20212
  }
20204
20213
  const requestedLimit = normalizeLimit(input.limit);
20205
- const workspace = normalizeOptionalString(input.workspace);
20214
+ const workspace = await this.workspaceResolver.resolve(input.workspace);
20206
20215
  const normalizedQuery = {
20207
20216
  terms,
20208
20217
  limit: requestedLimit * RECALL_CANDIDATE_LIMIT_MULTIPLIER,
@@ -20259,10 +20268,6 @@ function normalizeListLimit(value) {
20259
20268
  }
20260
20269
  return Math.min(Math.max(value, 1), MAX_LIST_LIMIT);
20261
20270
  }
20262
- function normalizeOptionalString(value) {
20263
- const trimmed = value?.trim();
20264
- return trimmed ? trimmed : undefined;
20265
- }
20266
20271
  function normalizeTerms(terms) {
20267
20272
  const normalizedTerms = terms.map((term) => term.trim()).filter(Boolean);
20268
20273
  return [...new Set(normalizedTerms)];
@@ -20270,11 +20275,11 @@ function normalizeTerms(terms) {
20270
20275
 
20271
20276
  // src/mcp/tools/recall.ts
20272
20277
  var recallInputSchema = {
20273
- terms: array(string2()).min(1).describe("Search terms for lexical memory lookup. Pass 2-5 short anchor-heavy terms or exact phrases as separate entries. Prefer identifiers, commands, file paths, package names, and conventions likely to appear verbatim in the memory. Avoid vague words, full sentences, and repeating the workspace name. If recall misses, retry once with overlapping alternate terms."),
20278
+ terms: array(string2()).min(1).describe("Pass 2-5 short anchor-heavy terms or exact phrases as separate entries. Prefer identifiers, commands, file paths, package names, and conventions likely to appear verbatim. Avoid vague words, full questions, and repeating the workspace name."),
20274
20279
  limit: number2().int().min(1).max(MAX_RECALL_LIMIT).optional().describe("Maximum matches to return. Keep this small when you only need the strongest hits."),
20275
- workspace: string2().optional().describe("Pass the current working directory. This strongly boosts memories from the active project while still allowing global and cross-workspace matches."),
20276
- updated_after: string2().optional().describe("Only return memories updated at or after this ISO 8601 timestamp."),
20277
- updated_before: string2().optional().describe("Only return memories updated at or before this ISO 8601 timestamp.")
20280
+ workspace: string2().optional().describe("Pass the current working directory to prefer memories from the active project. Git worktree paths are normalized to the main repo root for matching."),
20281
+ updated_after: string2().optional().describe("Only return memories updated on or after this ISO 8601 timestamp."),
20282
+ updated_before: string2().optional().describe("Only return memories updated on or before this ISO 8601 timestamp.")
20278
20283
  };
20279
20284
  function toMemoryXml(r) {
20280
20285
  const workspace = r.workspace ? ` workspace="${escapeXml(r.workspace)}"` : "";
@@ -20286,7 +20291,12 @@ ${content}
20286
20291
  }
20287
20292
  function registerRecallTool(server, memory) {
20288
20293
  server.registerTool("recall", {
20289
- description: "Retrieve relevant memories for the current task. Use at conversation start and before design choices, conventions, or edge cases. Query with 2-5 short anchor-heavy terms or exact phrases, not questions or full sentences. `recall` is lexical-first; semantic reranking only reorders lexical matches. If it misses, retry once with overlapping alternate terms. Pass workspace. Returns `<memories>...</memories>` or a no-match hint.",
20294
+ annotations: {
20295
+ title: "Recall",
20296
+ readOnlyHint: true,
20297
+ openWorldHint: false
20298
+ },
20299
+ description: "Find memories relevant to the current task or check whether a fact already exists before saving. Use at conversation start and before design choices. Pass short anchor-heavy `terms` and `workspace` when available. Returns `<memories>...</memories>` or a no-match hint.",
20290
20300
  inputSchema: recallInputSchema
20291
20301
  }, async ({ terms, limit, workspace, updated_after, updated_before }) => {
20292
20302
  try {
@@ -20297,7 +20307,7 @@ function registerRecallTool(server, memory) {
20297
20307
  updatedAfter: parseOptionalDate(updated_after, "updated_after"),
20298
20308
  updatedBefore: parseOptionalDate(updated_before, "updated_before")
20299
20309
  });
20300
- const text = results.length === 0 ? "No matching memories found. Retry once with 1-3 alternate overlapping terms or an exact phrase likely to appear in the memory text. Recall is lexical-first, so semantic reranking cannot rescue a query with no wording overlap." : `<memories>
20310
+ const text = results.length === 0 ? "No matching memories found. Retry once with 1-3 overlapping alternate terms or an exact identifier, command, file path, or phrase likely to appear in the memory." : `<memories>
20301
20311
  ${results.map(toMemoryXml).join(`
20302
20312
  `)}
20303
20313
  </memories>`;
@@ -20312,12 +20322,18 @@ ${results.map(toMemoryXml).join(`
20312
20322
 
20313
20323
  // src/mcp/tools/remember.ts
20314
20324
  var rememberInputSchema = {
20315
- content: string2().describe("One durable fact to save. Use a single self-contained sentence or short note with concrete nouns, identifiers, commands, file paths, or exact phrases the agent is likely to reuse."),
20316
- workspace: string2().optional().describe("Pass the current working directory for project-specific memories. Omit only for truly global memories.")
20325
+ content: string2().describe("One new durable fact to save. Use a self-contained sentence or short note."),
20326
+ workspace: string2().optional().describe("Pass the current working directory for project-scoped memory. Git worktree paths are saved as the main repo root. Omit for truly global memory.")
20317
20327
  };
20318
20328
  function registerRememberTool(server, memory) {
20319
20329
  server.registerTool("remember", {
20320
- description: 'Save one durable memory for later recall. Use when the user states a stable preference, corrects you, or establishes reusable project context not obvious from code or git history. Save one fact per memory. Call `recall` first; use `revise` instead of creating duplicates. Do not store secrets, temporary task state, or codebase facts. Returns `<memory id="..." />`.',
20330
+ annotations: {
20331
+ title: "Remember",
20332
+ destructiveHint: false,
20333
+ idempotentHint: false,
20334
+ openWorldHint: false
20335
+ },
20336
+ description: 'Save one new durable fact for later recall. Use for stable preferences, corrections, reusable decisions, and project context not obvious from code or git history. Save exactly one fact. If the memory already exists, use `revise` instead. Do not store secrets, temporary task state, or facts obvious from code or git history. Returns `<memory id="..." />`.',
20321
20337
  inputSchema: rememberInputSchema
20322
20338
  }, async ({ content, workspace }) => {
20323
20339
  try {
@@ -20336,12 +20352,18 @@ function registerRememberTool(server, memory) {
20336
20352
 
20337
20353
  // src/mcp/tools/revise.ts
20338
20354
  var reviseInputSchema = {
20339
- id: string2().describe("The memory id to update. Use an id returned by `recall`."),
20340
- content: string2().describe("The corrected replacement for that same fact. Keep it to one durable fact.")
20355
+ id: string2().describe("Memory id to update. Use an id returned by `recall`."),
20356
+ content: string2().describe("Corrected replacement text for that memory. Keep it to one durable fact.")
20341
20357
  };
20342
20358
  function registerReviseTool(server, memory) {
20343
20359
  server.registerTool("revise", {
20344
- description: 'Replace one existing memory with corrected wording. Use after `recall` when the same fact still applies but details changed. Do not append unrelated facts or merge memories. Returns `<memory id="..." updated_at="..." />`.',
20360
+ annotations: {
20361
+ title: "Revise",
20362
+ destructiveHint: false,
20363
+ idempotentHint: false,
20364
+ openWorldHint: false
20365
+ },
20366
+ description: 'Update one existing memory when the same fact still applies but its wording or details changed. Use after `recall` when you already have the memory id. Keep it to one fact and do not merge unrelated facts. Returns `<memory id="..." updated_at="..." />`.',
20345
20367
  inputSchema: reviseInputSchema
20346
20368
  }, async ({ id, content }) => {
20347
20369
  try {
@@ -20362,15 +20384,12 @@ function registerReviseTool(server, memory) {
20362
20384
 
20363
20385
  // src/mcp/server.ts
20364
20386
  var SERVER_INSTRUCTIONS = [
20365
- "Use this server for durable memory: user preferences, corrections, decisions, and project context not obvious from code or git history.",
20366
- "Use `recall` at conversation start and before design choices, conventions, or edge cases.",
20367
- "Query `recall` with 2-5 short anchor-heavy terms or exact phrases likely to appear verbatim in memory text: identifiers, commands, file paths, and conventions.",
20368
- "`recall` is lexical-first; semantic reranking only reorders lexical matches.",
20369
- "If `recall` misses, retry once with overlapping alternate terms.",
20370
- "Use `remember` for one durable fact when the user states a preference, corrects you, or a reusable project decision becomes clear.",
20371
- "Call `recall` before `remember`; if the fact already exists, use `revise` instead of creating a duplicate.",
20372
- "Use `revise` to correct an existing memory and `forget` to remove a wrong or obsolete one.",
20373
- "Pass workspace for project-scoped calls. Omit it only for truly global memories."
20387
+ "Use this server only for durable memory that should survive across turns: stable preferences, corrections, reusable decisions, and project context not obvious from code or git history.",
20388
+ "Use `recall` at conversation start, before design choices, and before saving memory.",
20389
+ "Use `remember` only for a new durable fact. Use `revise` when the fact already exists but needs correction.",
20390
+ "Use `forget` only when a memory is wrong or no longer relevant.",
20391
+ "Pass workspace for project-scoped memory. Omit it only for truly global memory.",
20392
+ "Do not store secrets or temporary task state in memory."
20374
20393
  ].join(" ");
20375
20394
  function createMcpServer(memory, version3) {
20376
20395
  const server = new McpServer({
@@ -20502,7 +20521,7 @@ function toUint8Array(value) {
20502
20521
  }
20503
20522
 
20504
20523
  // src/sqlite/migrations/002-add-memory-embedding.ts
20505
- function createAddMemoryEmbeddingMigration(embeddingService = new EmbeddingService) {
20524
+ function createAddMemoryEmbeddingMigration(embeddingService) {
20506
20525
  return {
20507
20526
  version: 2,
20508
20527
  async up(database) {
@@ -20531,13 +20550,33 @@ function createAddMemoryEmbeddingMigration(embeddingService = new EmbeddingServi
20531
20550
  }
20532
20551
  };
20533
20552
  }
20534
- var addMemoryEmbeddingMigration = createAddMemoryEmbeddingMigration();
20553
+
20554
+ // src/sqlite/migrations/003-normalize-workspaces.ts
20555
+ function createNormalizeWorkspaceMigration(workspaceResolver) {
20556
+ return {
20557
+ version: 3,
20558
+ async up(database) {
20559
+ const rows = database.prepare("SELECT DISTINCT workspace FROM memories WHERE workspace IS NOT NULL ORDER BY workspace").all();
20560
+ const updateStatement = database.prepare("UPDATE memories SET workspace = ? WHERE workspace = ?");
20561
+ for (const row of rows) {
20562
+ const normalizedWorkspace = await workspaceResolver.resolve(row.workspace);
20563
+ if (!normalizedWorkspace || normalizedWorkspace === row.workspace) {
20564
+ continue;
20565
+ }
20566
+ updateStatement.run(normalizedWorkspace, row.workspace);
20567
+ }
20568
+ }
20569
+ };
20570
+ }
20535
20571
 
20536
20572
  // src/sqlite/migrations/index.ts
20537
- function createMemoryMigrations(embeddingService = new EmbeddingService) {
20538
- return [createMemorySchemaMigration, createAddMemoryEmbeddingMigration(embeddingService)];
20573
+ function createMemoryMigrations(options) {
20574
+ return [
20575
+ createMemorySchemaMigration,
20576
+ createAddMemoryEmbeddingMigration(options.embeddingService),
20577
+ createNormalizeWorkspaceMigration(options.workspaceResolver)
20578
+ ];
20539
20579
  }
20540
- var MEMORY_MIGRATIONS = createMemoryMigrations();
20541
20580
 
20542
20581
  // src/sqlite/db.ts
20543
20582
  var PRAGMA_STATEMENTS = [
@@ -20546,12 +20585,12 @@ var PRAGMA_STATEMENTS = [
20546
20585
  "foreign_keys = ON",
20547
20586
  "busy_timeout = 5000"
20548
20587
  ];
20549
- async function openMemoryDatabase(databasePath, options = {}) {
20588
+ async function openMemoryDatabase(databasePath, options) {
20550
20589
  let database;
20551
20590
  try {
20552
20591
  mkdirSync2(dirname(databasePath), { recursive: true });
20553
20592
  database = new Database(databasePath);
20554
- await initializeMemoryDatabase(database, createMemoryMigrations(options.embeddingService));
20593
+ await initializeMemoryDatabase(database, createMemoryMigrations(options));
20555
20594
  return database;
20556
20595
  } catch (error2) {
20557
20596
  database?.close();
@@ -20563,7 +20602,7 @@ async function openMemoryDatabase(databasePath, options = {}) {
20563
20602
  });
20564
20603
  }
20565
20604
  }
20566
- async function initializeMemoryDatabase(database, migrations = MEMORY_MIGRATIONS) {
20605
+ async function initializeMemoryDatabase(database, migrations) {
20567
20606
  try {
20568
20607
  applyPragmas(database);
20569
20608
  await runSqliteMigrations(database, migrations);
@@ -24195,12 +24234,59 @@ function startWebServer(memory, options) {
24195
24234
  return serve({ fetch: app.fetch, port: options.port });
24196
24235
  }
24197
24236
 
24237
+ // src/workspace-resolver.ts
24238
+ import { execFile } from "node:child_process";
24239
+ import { basename, dirname as dirname2 } from "node:path";
24240
+ import { promisify } from "node:util";
24241
+ var execFileAsync = promisify(execFile);
24242
+ function createGitWorkspaceResolver(options = {}) {
24243
+ const getGitCommonDir = options.getGitCommonDir ?? defaultGetGitCommonDir;
24244
+ const cache = new Map;
24245
+ return {
24246
+ async resolve(workspace) {
24247
+ const trimmed = normalizeOptionalString(workspace);
24248
+ if (!trimmed) {
24249
+ return;
24250
+ }
24251
+ const cached2 = cache.get(trimmed);
24252
+ if (cached2) {
24253
+ return cached2;
24254
+ }
24255
+ const pending = resolveWorkspace(trimmed, getGitCommonDir);
24256
+ cache.set(trimmed, pending);
24257
+ return pending;
24258
+ }
24259
+ };
24260
+ }
24261
+ async function resolveWorkspace(workspace, getGitCommonDir) {
24262
+ try {
24263
+ const gitCommonDir = (await getGitCommonDir(workspace)).trim();
24264
+ if (basename(gitCommonDir) !== ".git") {
24265
+ return workspace;
24266
+ }
24267
+ return dirname2(gitCommonDir);
24268
+ } catch {
24269
+ return workspace;
24270
+ }
24271
+ }
24272
+ async function defaultGetGitCommonDir(cwd) {
24273
+ const { stdout } = await execFileAsync("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
24274
+ cwd
24275
+ });
24276
+ return stdout.trim();
24277
+ }
24278
+ function normalizeOptionalString(value) {
24279
+ const trimmed = value?.trim();
24280
+ return trimmed ? trimmed : undefined;
24281
+ }
24282
+
24198
24283
  // src/index.ts
24199
24284
  var config2 = resolveConfig();
24200
24285
  var embeddingService = new EmbeddingService({ modelsCachePath: config2.modelsCachePath });
24201
- var database = await openMemoryDatabase(config2.databasePath, { embeddingService });
24286
+ var workspaceResolver = createGitWorkspaceResolver();
24287
+ var database = await openMemoryDatabase(config2.databasePath, { embeddingService, workspaceResolver });
24202
24288
  var repository2 = new SqliteMemoryRepository(database);
24203
- var memoryService = new MemoryService(repository2, embeddingService);
24289
+ var memoryService = new MemoryService(repository2, embeddingService, workspaceResolver);
24204
24290
  if (config2.uiMode) {
24205
24291
  let shutdown = function() {
24206
24292
  server.close();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jcyamacho/agent-memory",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.15",
4
+ "version": "0.0.18",
5
5
  "bin": {
6
6
  "agent-memory": "dist/index.js"
7
7
  },