gitmem-mcp 1.0.2 → 1.0.4
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/CHANGELOG.md +20 -6
- package/README.md +30 -9
- package/dist/commands/check.d.ts +1 -1
- package/dist/commands/check.js +4 -3
- package/dist/diagnostics/anonymizer.d.ts +1 -1
- package/dist/diagnostics/anonymizer.js +1 -1
- package/dist/diagnostics/channels.d.ts +1 -1
- package/dist/diagnostics/channels.js +1 -1
- package/dist/diagnostics/collector.d.ts +1 -1
- package/dist/diagnostics/collector.js +1 -1
- package/dist/diagnostics/index.d.ts +1 -1
- package/dist/diagnostics/index.js +1 -1
- package/dist/hooks/quick-retrieve.js +2 -1
- package/dist/index.js +0 -0
- package/dist/schemas/active-sessions.d.ts +9 -9
- package/dist/schemas/active-sessions.js +1 -1
- package/dist/schemas/common.d.ts +2 -5
- package/dist/schemas/common.js +13 -7
- package/dist/schemas/create-learning.d.ts +4 -4
- package/dist/schemas/create-learning.js +1 -1
- package/dist/schemas/session-close.d.ts +5 -8
- package/dist/schemas/session-close.js +7 -3
- package/dist/schemas/session-start.d.ts +4 -4
- package/dist/schemas/session-start.js +1 -1
- package/dist/schemas/thread.d.ts +1 -1
- package/dist/schemas/thread.js +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +21 -10
- package/dist/services/active-sessions.js +3 -2
- package/dist/services/agent-briefing.d.ts +12 -0
- package/dist/services/agent-briefing.js +81 -0
- package/dist/services/agent-detection.d.ts +2 -1
- package/dist/services/agent-detection.js +23 -14
- package/dist/services/analytics.d.ts +1 -1
- package/dist/services/analytics.js +3 -3
- package/dist/services/behavioral-decay.js +2 -2
- package/dist/services/cache.d.ts +1 -1
- package/dist/services/cache.js +1 -1
- package/dist/services/compliance-validator.d.ts +1 -1
- package/dist/services/compliance-validator.js +5 -5
- package/dist/services/config.d.ts +1 -1
- package/dist/services/config.js +1 -1
- package/dist/services/file-lock.js +12 -0
- package/dist/services/gitmem-dir.d.ts +17 -4
- package/dist/services/gitmem-dir.js +43 -9
- package/dist/services/local-file-storage.d.ts +1 -1
- package/dist/services/local-file-storage.js +16 -10
- package/dist/services/local-vector-search.d.ts +1 -1
- package/dist/services/local-vector-search.js +2 -2
- package/dist/services/metrics.d.ts +6 -6
- package/dist/services/metrics.js +8 -8
- package/dist/services/session-state.d.ts +7 -7
- package/dist/services/session-state.js +19 -7
- package/dist/services/startup.d.ts +1 -1
- package/dist/services/startup.js +3 -2
- package/dist/services/supabase-client.d.ts +17 -6
- package/dist/services/supabase-client.js +44 -8
- package/dist/services/thread-manager.d.ts +1 -1
- package/dist/services/thread-manager.js +5 -5
- package/dist/services/thread-supabase.d.ts +1 -1
- package/dist/services/thread-supabase.js +2 -2
- package/dist/services/tier.d.ts +2 -0
- package/dist/services/tier.js +4 -0
- package/dist/services/transcript-chunker.d.ts +1 -1
- package/dist/services/transcript-chunker.js +1 -1
- package/dist/services/triple-writer.d.ts +4 -4
- package/dist/services/triple-writer.js +11 -20
- package/dist/services/variant-assignment.d.ts +6 -6
- package/dist/services/variant-assignment.js +9 -8
- package/dist/tools/analyze.d.ts +2 -2
- package/dist/tools/analyze.js +2 -2
- package/dist/tools/archive-learning.js +36 -22
- package/dist/tools/confirm-scars.js +4 -0
- package/dist/tools/create-decision.d.ts +1 -1
- package/dist/tools/create-decision.js +2 -2
- package/dist/tools/create-learning.d.ts +1 -1
- package/dist/tools/create-learning.js +4 -4
- package/dist/tools/create-linear-issue.d.ts +18 -0
- package/dist/tools/create-linear-issue.js +197 -0
- package/dist/tools/create-thread.d.ts +1 -1
- package/dist/tools/create-thread.js +2 -2
- package/dist/tools/definitions.d.ts +280 -58
- package/dist/tools/definitions.js +127 -87
- package/dist/tools/get-transcript.d.ts +1 -1
- package/dist/tools/get-transcript.js +1 -1
- package/dist/tools/graph-traverse.d.ts +1 -1
- package/dist/tools/graph-traverse.js +20 -17
- package/dist/tools/list-threads.d.ts +2 -2
- package/dist/tools/list-threads.js +4 -4
- package/dist/tools/log.d.ts +1 -1
- package/dist/tools/log.js +1 -1
- package/dist/tools/prepare-context.d.ts +1 -1
- package/dist/tools/prepare-context.js +2 -2
- package/dist/tools/recall.d.ts +5 -4
- package/dist/tools/recall.js +37 -28
- package/dist/tools/record-scar-usage-batch.js +2 -2
- package/dist/tools/record-scar-usage.d.ts +1 -1
- package/dist/tools/record-scar-usage.js +3 -3
- package/dist/tools/resolve-thread.d.ts +2 -2
- package/dist/tools/resolve-thread.js +3 -3
- package/dist/tools/save-transcript.d.ts +1 -1
- package/dist/tools/save-transcript.js +1 -1
- package/dist/tools/search.d.ts +1 -1
- package/dist/tools/search.js +1 -1
- package/dist/tools/session-close.d.ts +1 -1
- package/dist/tools/session-close.js +58 -57
- package/dist/tools/session-start.d.ts +5 -5
- package/dist/tools/session-start.js +63 -61
- package/dist/types/index.d.ts +17 -13
- package/hooks/.claude-plugin/plugin.json +1 -1
- package/hooks/scripts/post-tool-use.sh +1 -1
- package/hooks/scripts/recall-check.sh +1 -1
- package/hooks/scripts/session-close-check.sh +1 -1
- package/hooks/scripts/session-start.sh +1 -1
- package/package.json +6 -3
- package/schema/starter-scars.json +3 -153
- package/dist/commands/check.d.ts.map +0 -1
- package/dist/commands/check.js.map +0 -1
- package/dist/constants/closing-questions.d.ts.map +0 -1
- package/dist/constants/closing-questions.js.map +0 -1
- package/dist/diagnostics/anonymizer.d.ts.map +0 -1
- package/dist/diagnostics/anonymizer.js.map +0 -1
- package/dist/diagnostics/channels.d.ts.map +0 -1
- package/dist/diagnostics/channels.js.map +0 -1
- package/dist/diagnostics/collector.d.ts.map +0 -1
- package/dist/diagnostics/collector.js.map +0 -1
- package/dist/diagnostics/index.d.ts.map +0 -1
- package/dist/diagnostics/index.js.map +0 -1
- package/dist/hooks/format-utils.d.ts.map +0 -1
- package/dist/hooks/format-utils.js.map +0 -1
- package/dist/hooks/quick-retrieve.d.ts.map +0 -1
- package/dist/hooks/quick-retrieve.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/schemas/absorb-observations.d.ts.map +0 -1
- package/dist/schemas/absorb-observations.js.map +0 -1
- package/dist/schemas/active-sessions.d.ts.map +0 -1
- package/dist/schemas/active-sessions.js.map +0 -1
- package/dist/schemas/analyze.d.ts.map +0 -1
- package/dist/schemas/analyze.js.map +0 -1
- package/dist/schemas/common.d.ts.map +0 -1
- package/dist/schemas/common.js.map +0 -1
- package/dist/schemas/create-decision.d.ts.map +0 -1
- package/dist/schemas/create-decision.js.map +0 -1
- package/dist/schemas/create-learning.d.ts.map +0 -1
- package/dist/schemas/create-learning.js.map +0 -1
- package/dist/schemas/get-transcript.d.ts.map +0 -1
- package/dist/schemas/get-transcript.js.map +0 -1
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/log.d.ts.map +0 -1
- package/dist/schemas/log.js.map +0 -1
- package/dist/schemas/prepare-context.d.ts.map +0 -1
- package/dist/schemas/prepare-context.js.map +0 -1
- package/dist/schemas/recall.d.ts.map +0 -1
- package/dist/schemas/recall.js.map +0 -1
- package/dist/schemas/record-scar-usage-batch.d.ts.map +0 -1
- package/dist/schemas/record-scar-usage-batch.js.map +0 -1
- package/dist/schemas/record-scar-usage.d.ts.map +0 -1
- package/dist/schemas/record-scar-usage.js.map +0 -1
- package/dist/schemas/registry.d.ts.map +0 -1
- package/dist/schemas/registry.js.map +0 -1
- package/dist/schemas/save-transcript.d.ts.map +0 -1
- package/dist/schemas/save-transcript.js.map +0 -1
- package/dist/schemas/search-transcripts.d.ts.map +0 -1
- package/dist/schemas/search-transcripts.js.map +0 -1
- package/dist/schemas/search.d.ts.map +0 -1
- package/dist/schemas/search.js.map +0 -1
- package/dist/schemas/session-close.d.ts.map +0 -1
- package/dist/schemas/session-close.js.map +0 -1
- package/dist/schemas/session-start.d.ts.map +0 -1
- package/dist/schemas/session-start.js.map +0 -1
- package/dist/schemas/thread.d.ts.map +0 -1
- package/dist/schemas/thread.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/services/active-sessions.d.ts.map +0 -1
- package/dist/services/active-sessions.js.map +0 -1
- package/dist/services/agent-detection.d.ts.map +0 -1
- package/dist/services/agent-detection.js.map +0 -1
- package/dist/services/analytics.d.ts.map +0 -1
- package/dist/services/analytics.js.map +0 -1
- package/dist/services/behavioral-decay.d.ts.map +0 -1
- package/dist/services/behavioral-decay.js.map +0 -1
- package/dist/services/bm25.d.ts.map +0 -1
- package/dist/services/bm25.js.map +0 -1
- package/dist/services/cache.d.ts.map +0 -1
- package/dist/services/cache.js.map +0 -1
- package/dist/services/cache.test.d.ts +0 -8
- package/dist/services/cache.test.d.ts.map +0 -1
- package/dist/services/cache.test.js +0 -267
- package/dist/services/cache.test.js.map +0 -1
- package/dist/services/compliance-validator.d.ts.map +0 -1
- package/dist/services/compliance-validator.js.map +0 -1
- package/dist/services/config.d.ts.map +0 -1
- package/dist/services/config.js.map +0 -1
- package/dist/services/display-protocol.d.ts.map +0 -1
- package/dist/services/display-protocol.js.map +0 -1
- package/dist/services/effect-tracker.d.ts.map +0 -1
- package/dist/services/effect-tracker.js.map +0 -1
- package/dist/services/embedding.d.ts.map +0 -1
- package/dist/services/embedding.js.map +0 -1
- package/dist/services/file-lock.d.ts.map +0 -1
- package/dist/services/file-lock.js.map +0 -1
- package/dist/services/gitmem-dir.d.ts.map +0 -1
- package/dist/services/gitmem-dir.js.map +0 -1
- package/dist/services/local-file-storage.d.ts.map +0 -1
- package/dist/services/local-file-storage.js.map +0 -1
- package/dist/services/local-vector-search.d.ts.map +0 -1
- package/dist/services/local-vector-search.js.map +0 -1
- package/dist/services/metrics.d.ts.map +0 -1
- package/dist/services/metrics.js.map +0 -1
- package/dist/services/session-state.d.ts.map +0 -1
- package/dist/services/session-state.js.map +0 -1
- package/dist/services/startup.d.ts.map +0 -1
- package/dist/services/startup.js.map +0 -1
- package/dist/services/storage.d.ts.map +0 -1
- package/dist/services/storage.js.map +0 -1
- package/dist/services/supabase-client.d.ts.map +0 -1
- package/dist/services/supabase-client.js.map +0 -1
- package/dist/services/thread-dedup.d.ts.map +0 -1
- package/dist/services/thread-dedup.js.map +0 -1
- package/dist/services/thread-manager.d.ts.map +0 -1
- package/dist/services/thread-manager.js.map +0 -1
- package/dist/services/thread-suggestions.d.ts.map +0 -1
- package/dist/services/thread-suggestions.js.map +0 -1
- package/dist/services/thread-supabase.d.ts.map +0 -1
- package/dist/services/thread-supabase.js.map +0 -1
- package/dist/services/thread-vitality.d.ts.map +0 -1
- package/dist/services/thread-vitality.js.map +0 -1
- package/dist/services/tier.d.ts.map +0 -1
- package/dist/services/tier.js.map +0 -1
- package/dist/services/timezone.d.ts.map +0 -1
- package/dist/services/timezone.js.map +0 -1
- package/dist/services/transcript-chunker.d.ts.map +0 -1
- package/dist/services/transcript-chunker.js.map +0 -1
- package/dist/services/triple-writer.d.ts.map +0 -1
- package/dist/services/triple-writer.js.map +0 -1
- package/dist/services/variant-assignment.d.ts.map +0 -1
- package/dist/services/variant-assignment.js.map +0 -1
- package/dist/services/variant-generation.d.ts.map +0 -1
- package/dist/services/variant-generation.js.map +0 -1
- package/dist/tools/absorb-observations.d.ts.map +0 -1
- package/dist/tools/absorb-observations.js.map +0 -1
- package/dist/tools/analyze.d.ts.map +0 -1
- package/dist/tools/analyze.js.map +0 -1
- package/dist/tools/archive-learning.d.ts.map +0 -1
- package/dist/tools/archive-learning.js.map +0 -1
- package/dist/tools/cleanup-threads.d.ts.map +0 -1
- package/dist/tools/cleanup-threads.js.map +0 -1
- package/dist/tools/confirm-scars.d.ts.map +0 -1
- package/dist/tools/confirm-scars.js.map +0 -1
- package/dist/tools/create-decision.d.ts.map +0 -1
- package/dist/tools/create-decision.js.map +0 -1
- package/dist/tools/create-learning.d.ts.map +0 -1
- package/dist/tools/create-learning.js.map +0 -1
- package/dist/tools/create-thread.d.ts.map +0 -1
- package/dist/tools/create-thread.js.map +0 -1
- package/dist/tools/definitions.d.ts.map +0 -1
- package/dist/tools/definitions.js.map +0 -1
- package/dist/tools/dismiss-suggestion.d.ts.map +0 -1
- package/dist/tools/dismiss-suggestion.js.map +0 -1
- package/dist/tools/get-transcript.d.ts.map +0 -1
- package/dist/tools/get-transcript.js.map +0 -1
- package/dist/tools/graph-traverse.d.ts.map +0 -1
- package/dist/tools/graph-traverse.js.map +0 -1
- package/dist/tools/list-threads.d.ts.map +0 -1
- package/dist/tools/list-threads.js.map +0 -1
- package/dist/tools/log.d.ts.map +0 -1
- package/dist/tools/log.js.map +0 -1
- package/dist/tools/prepare-context.d.ts.map +0 -1
- package/dist/tools/prepare-context.js.map +0 -1
- package/dist/tools/promote-suggestion.d.ts.map +0 -1
- package/dist/tools/promote-suggestion.js.map +0 -1
- package/dist/tools/recall.d.ts.map +0 -1
- package/dist/tools/recall.js.map +0 -1
- package/dist/tools/recall.test.d.ts +0 -5
- package/dist/tools/recall.test.d.ts.map +0 -1
- package/dist/tools/recall.test.js +0 -155
- package/dist/tools/recall.test.js.map +0 -1
- package/dist/tools/record-scar-usage-batch.d.ts.map +0 -1
- package/dist/tools/record-scar-usage-batch.js.map +0 -1
- package/dist/tools/record-scar-usage.d.ts.map +0 -1
- package/dist/tools/record-scar-usage.js.map +0 -1
- package/dist/tools/resolve-thread.d.ts.map +0 -1
- package/dist/tools/resolve-thread.js.map +0 -1
- package/dist/tools/save-transcript.d.ts.map +0 -1
- package/dist/tools/save-transcript.js.map +0 -1
- package/dist/tools/search-transcripts.d.ts.map +0 -1
- package/dist/tools/search-transcripts.js.map +0 -1
- package/dist/tools/search.d.ts.map +0 -1
- package/dist/tools/search.js.map +0 -1
- package/dist/tools/session-close.d.ts.map +0 -1
- package/dist/tools/session-close.js.map +0 -1
- package/dist/tools/session-start.d.ts.map +0 -1
- package/dist/tools/session-start.js.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/hooks/tests/test-hooks.sh +0 -577
package/dist/server.js
CHANGED
|
@@ -43,7 +43,7 @@ import { validateToolArgs } from "./schemas/registry.js";
|
|
|
43
43
|
export function createServer() {
|
|
44
44
|
const server = new Server({
|
|
45
45
|
name: "gitmem-mcp",
|
|
46
|
-
version: "
|
|
46
|
+
version: "1.0.3",
|
|
47
47
|
}, {
|
|
48
48
|
capabilities: {
|
|
49
49
|
tools: {},
|
|
@@ -207,6 +207,7 @@ export function createServer() {
|
|
|
207
207
|
{ alias: "gitmem-r", full: "recall", description: "Check scars before taking action" },
|
|
208
208
|
{ alias: "gitmem-cs", full: "confirm_scars", description: "Confirm recalled scars (APPLYING/N_A/REFUTED)" },
|
|
209
209
|
{ alias: "gitmem-ss", full: "session_start", description: "Initialize session with context" },
|
|
210
|
+
{ alias: "gitmem-sr", full: "session_refresh", description: "Refresh context for active session" },
|
|
210
211
|
{ alias: "gitmem-sc", full: "session_close", description: "Close session with compliance validation" },
|
|
211
212
|
{ alias: "gitmem-cl", full: "create_learning", description: "Create scar/win/pattern entry" },
|
|
212
213
|
{ alias: "gitmem-cd", full: "create_decision", description: "Log architectural/operational decision" },
|
|
@@ -223,6 +224,7 @@ export function createServer() {
|
|
|
223
224
|
{ alias: "gitmem-cleanup", full: "cleanup_threads", description: "Triage threads by lifecycle health" },
|
|
224
225
|
{ alias: "gitmem-health", full: "health", description: "Show write health for fire-and-forget operations" },
|
|
225
226
|
{ alias: "gitmem-al", full: "archive_learning", description: "Archive a scar/win/pattern (is_active=false)" },
|
|
227
|
+
{ alias: "gitmem-graph", full: "graph_traverse", description: "Traverse knowledge graph over institutional memory" },
|
|
226
228
|
];
|
|
227
229
|
if (hasBatchOperations()) {
|
|
228
230
|
commands.push({ alias: "gitmem-rsb", full: "record_scar_usage_batch", description: "Track multiple scars (batch)" });
|
|
@@ -233,10 +235,12 @@ export function createServer() {
|
|
|
233
235
|
if (hasCacheManagement()) {
|
|
234
236
|
commands.push({ alias: "gitmem-cache-status", full: "cache_status", description: "Show cache status" }, { alias: "gitmem-cache-health", full: "cache_health", description: "Compare local vs remote" }, { alias: "gitmem-cache-flush", full: "cache_flush", description: "Force reload from Supabase" });
|
|
235
237
|
}
|
|
238
|
+
// Filter to only show commands whose canonical tool is actually registered
|
|
239
|
+
const visibleCommands = commands.filter(c => registeredToolNames.has(c.full));
|
|
236
240
|
// Build command table for display
|
|
237
|
-
const cmdLines =
|
|
241
|
+
const cmdLines = visibleCommands.map(c => ` ${c.alias.padEnd(22)} ${c.description}`).join("\n");
|
|
238
242
|
const display = [
|
|
239
|
-
`gitmem
|
|
243
|
+
`gitmem v1.0.3 · ${tier} · ${registeredTools.length} tools · ${hasSupabase() ? "supabase" : "local (.gitmem/)"}`,
|
|
240
244
|
"Memory that compounds.",
|
|
241
245
|
"",
|
|
242
246
|
cmdLines,
|
|
@@ -248,11 +252,11 @@ export function createServer() {
|
|
|
248
252
|
"Tool results are collapsed in the CLI — the user cannot see them unless you echo them.",
|
|
249
253
|
].join("\n");
|
|
250
254
|
result = {
|
|
251
|
-
version: "
|
|
255
|
+
version: "1.0.3",
|
|
252
256
|
tier,
|
|
253
257
|
tools_registered: registeredTools.length,
|
|
254
258
|
storage: hasSupabase() ? "supabase" : "local (.gitmem/)",
|
|
255
|
-
commands,
|
|
259
|
+
commands: visibleCommands,
|
|
256
260
|
display,
|
|
257
261
|
};
|
|
258
262
|
break;
|
|
@@ -277,7 +281,7 @@ export function createServer() {
|
|
|
277
281
|
case "gm-graph":
|
|
278
282
|
result = await graphTraverse(toolArgs);
|
|
279
283
|
break;
|
|
280
|
-
// Cache management tools
|
|
284
|
+
// Cache management tools
|
|
281
285
|
case "gitmem-cache-status":
|
|
282
286
|
case "gm-cache-s":
|
|
283
287
|
result = getCacheStatus(toolArgs.project || getProject() || "default");
|
|
@@ -319,12 +323,19 @@ export function createServer() {
|
|
|
319
323
|
};
|
|
320
324
|
}
|
|
321
325
|
catch (error) {
|
|
322
|
-
const
|
|
326
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
327
|
+
// Redact internal details: file paths, SQL errors, stack traces
|
|
328
|
+
const safeMessage = rawMessage
|
|
329
|
+
.replace(/\/[^\s:]+/g, "[path]") // redact file paths
|
|
330
|
+
.replace(/\b\d{5}\b/g, "[code]") // redact PG error codes
|
|
331
|
+
.replace(/at\s+\S+\s+\(.+\)/g, "") // strip stack frames
|
|
332
|
+
.slice(0, 200); // cap length
|
|
333
|
+
console.error(`[server] Tool error:`, rawMessage);
|
|
323
334
|
return {
|
|
324
335
|
content: [
|
|
325
336
|
{
|
|
326
337
|
type: "text",
|
|
327
|
-
text: JSON.stringify({ error:
|
|
338
|
+
text: JSON.stringify({ error: safeMessage }),
|
|
328
339
|
},
|
|
329
340
|
],
|
|
330
341
|
isError: true,
|
|
@@ -336,8 +347,8 @@ export function createServer() {
|
|
|
336
347
|
/**
|
|
337
348
|
* Run the server with stdio transport
|
|
338
349
|
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
350
|
+
* Initializes local vector search in background for fast startup.
|
|
351
|
+
* Uses direct Supabase queries to get embeddings for local cache.
|
|
341
352
|
*
|
|
342
353
|
* Server starts immediately; cache loads in background.
|
|
343
354
|
* First few queries may use Supabase fallback until cache is ready.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import * as fs from "fs";
|
|
14
14
|
import * as path from "path";
|
|
15
15
|
import * as os from "os";
|
|
16
|
-
import { getGitmemDir, getSessionPath } from "./gitmem-dir.js";
|
|
16
|
+
import { getGitmemDir, getSessionPath, sanitizePathComponent } from "./gitmem-dir.js";
|
|
17
17
|
import { ActiveSessionsRegistrySchema } from "../schemas/active-sessions.js";
|
|
18
18
|
import { withLockSync } from "./file-lock.js";
|
|
19
19
|
const REGISTRY_FILENAME = "active-sessions.json";
|
|
@@ -276,6 +276,7 @@ function pruneOrphanedDirs(gitmemDir, registry) {
|
|
|
276
276
|
*/
|
|
277
277
|
function cleanupSessionDir(gitmemDir, sessionId) {
|
|
278
278
|
try {
|
|
279
|
+
sanitizePathComponent(sessionId, "sessionId");
|
|
279
280
|
const sessionDir = path.join(gitmemDir, "sessions", sessionId);
|
|
280
281
|
if (fs.existsSync(sessionDir)) {
|
|
281
282
|
fs.rmSync(sessionDir, { recursive: true, force: true });
|
|
@@ -328,7 +329,7 @@ export function migrateFromLegacy() {
|
|
|
328
329
|
// 2. Create registry with single entry
|
|
329
330
|
const entry = {
|
|
330
331
|
session_id: old.session_id,
|
|
331
|
-
agent: old.agent || "
|
|
332
|
+
agent: old.agent || "cli",
|
|
332
333
|
started_at: old.started_at || new Date().toISOString(),
|
|
333
334
|
hostname: old.hostname || os.hostname(),
|
|
334
335
|
pid: old.pid || process.pid,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Briefing Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates `.gitmem/agent-briefing.md` at session close with a
|
|
5
|
+
* compact summary of memory state. Designed for inclusion in
|
|
6
|
+
* MEMORY.md to bridge PMEM <-> GitMem.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Generate and write agent-briefing.md to .gitmem/
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeAgentBriefing(newLearnings: number, newDecisions: number): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=agent-briefing.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Briefing Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates `.gitmem/agent-briefing.md` at session close with a
|
|
5
|
+
* compact summary of memory state. Designed for inclusion in
|
|
6
|
+
* MEMORY.md to bridge PMEM <-> GitMem.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import { getGitmemDir } from "./gitmem-dir.js";
|
|
11
|
+
import { getStorage } from "./storage.js";
|
|
12
|
+
/**
|
|
13
|
+
* Generate and write agent-briefing.md to .gitmem/
|
|
14
|
+
*/
|
|
15
|
+
export async function writeAgentBriefing(newLearnings, newDecisions) {
|
|
16
|
+
try {
|
|
17
|
+
const gitmemDir = getGitmemDir();
|
|
18
|
+
if (!gitmemDir || !fs.existsSync(gitmemDir))
|
|
19
|
+
return;
|
|
20
|
+
const storage = getStorage();
|
|
21
|
+
const sessions = await storage.query("sessions");
|
|
22
|
+
const learnings = await storage.query("learnings");
|
|
23
|
+
const threads = await storage.query("threads");
|
|
24
|
+
// Count by severity
|
|
25
|
+
const severityCounts = {};
|
|
26
|
+
const domainCounts = {};
|
|
27
|
+
for (const l of learnings) {
|
|
28
|
+
const sev = l.severity || "medium";
|
|
29
|
+
severityCounts[sev] = (severityCounts[sev] || 0) + 1;
|
|
30
|
+
const domains = l.domain || [];
|
|
31
|
+
for (const d of domains) {
|
|
32
|
+
domainCounts[d] = (domainCounts[d] || 0) + 1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Active threads
|
|
36
|
+
const activeThreads = threads.filter((t) => t.status === "open").length;
|
|
37
|
+
// Top domains (top 5)
|
|
38
|
+
const topDomains = Object.entries(domainCounts)
|
|
39
|
+
.sort((a, b) => b[1] - a[1])
|
|
40
|
+
.slice(0, 5)
|
|
41
|
+
.map(([d]) => d);
|
|
42
|
+
// Severity breakdown
|
|
43
|
+
const sevParts = [];
|
|
44
|
+
if (severityCounts.critical)
|
|
45
|
+
sevParts.push(`${severityCounts.critical} critical`);
|
|
46
|
+
if (severityCounts.high)
|
|
47
|
+
sevParts.push(`${severityCounts.high} high`);
|
|
48
|
+
if (severityCounts.medium)
|
|
49
|
+
sevParts.push(`${severityCounts.medium} medium`);
|
|
50
|
+
if (severityCounts.low)
|
|
51
|
+
sevParts.push(`${severityCounts.low} low`);
|
|
52
|
+
// Recent activity
|
|
53
|
+
const recentParts = [];
|
|
54
|
+
if (newLearnings > 0)
|
|
55
|
+
recentParts.push(`+${newLearnings} scars`);
|
|
56
|
+
if (newDecisions > 0)
|
|
57
|
+
recentParts.push(`+${newDecisions} decisions`);
|
|
58
|
+
const today = new Date().toISOString().split("T")[0];
|
|
59
|
+
const lines = [
|
|
60
|
+
"<!-- Generated by GitMem at session close. Include in MEMORY.md for cross-session context. -->",
|
|
61
|
+
"## GitMem Status",
|
|
62
|
+
`- **Sessions:** ${sessions.length} total, last: ${today}`,
|
|
63
|
+
`- **Active threads:** ${activeThreads}`,
|
|
64
|
+
`- **Scars earned:** ${learnings.length}${sevParts.length > 0 ? ` (${sevParts.join(", ")})` : ""}`,
|
|
65
|
+
];
|
|
66
|
+
if (recentParts.length > 0) {
|
|
67
|
+
lines.push(`- **Recent:** ${recentParts.join(", ")} this session`);
|
|
68
|
+
}
|
|
69
|
+
if (topDomains.length > 0) {
|
|
70
|
+
lines.push(`- **Top domains:** ${topDomains.join(", ")}`);
|
|
71
|
+
}
|
|
72
|
+
const briefingPath = path.join(gitmemDir, "agent-briefing.md");
|
|
73
|
+
fs.writeFileSync(briefingPath, lines.join("\n") + "\n");
|
|
74
|
+
console.error(`[agent-briefing] Written to ${briefingPath}`);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// Non-fatal — don't break session close
|
|
78
|
+
console.warn("[agent-briefing] Failed to write:", error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=agent-briefing.js.map
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* | ENTRYPOINT | Docker | Hostname | Identity |
|
|
9
9
|
* |------------|--------|----------|----------|
|
|
10
10
|
* | cli | YES | (any) | CLI |
|
|
11
|
-
* | cli | NO |
|
|
11
|
+
* | cli | NO | (server hostname) | CODA-1 |
|
|
12
12
|
* | claude-desktop | NO | (any) | DAC |
|
|
13
13
|
* | (empty) | NO | (local) | Brain_Local |
|
|
14
14
|
* | (empty) | NO | (no fs) | Brain_Cloud |
|
|
@@ -18,6 +18,7 @@ import type { AgentIdentity, DetectedEnvironment } from "../types/index.js";
|
|
|
18
18
|
* Detect the current agent identity based on environment
|
|
19
19
|
*/
|
|
20
20
|
export declare function detectAgent(): DetectedEnvironment;
|
|
21
|
+
export declare function normalizeAgent(input: string): AgentIdentity;
|
|
21
22
|
/**
|
|
22
23
|
* Get just the agent identity (convenience function)
|
|
23
24
|
*/
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* | ENTRYPOINT | Docker | Hostname | Identity |
|
|
9
9
|
* |------------|--------|----------|----------|
|
|
10
10
|
* | cli | YES | (any) | CLI |
|
|
11
|
-
* | cli | NO |
|
|
11
|
+
* | cli | NO | (server hostname) | CODA-1 |
|
|
12
12
|
* | claude-desktop | NO | (any) | DAC |
|
|
13
13
|
* | (empty) | NO | (local) | Brain_Local |
|
|
14
14
|
* | (empty) | NO | (no fs) | Brain_Cloud |
|
|
@@ -48,33 +48,27 @@ export function detectAgent() {
|
|
|
48
48
|
let agent;
|
|
49
49
|
if (entrypoint === "cli") {
|
|
50
50
|
if (docker) {
|
|
51
|
-
|
|
52
|
-
agent = "CLI";
|
|
51
|
+
agent = "cli";
|
|
53
52
|
}
|
|
54
|
-
else if (
|
|
55
|
-
|
|
56
|
-
agent = "CODA-1";
|
|
53
|
+
else if (process.env.GITMEM_AGENT_HOSTNAME && (hostname === process.env.GITMEM_AGENT_HOSTNAME)) {
|
|
54
|
+
agent = "autonomous";
|
|
57
55
|
}
|
|
58
56
|
else {
|
|
59
|
-
|
|
60
|
-
agent = "CLI";
|
|
57
|
+
agent = "cli";
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
else if (entrypoint === "claude-desktop") {
|
|
64
|
-
|
|
65
|
-
agent = "DAC";
|
|
61
|
+
agent = "desktop";
|
|
66
62
|
}
|
|
67
63
|
else if (!entrypoint) {
|
|
68
|
-
// No entrypoint - could be Brain Local or Brain Cloud
|
|
69
64
|
if (hasFilesystemAccess()) {
|
|
70
|
-
agent = "
|
|
65
|
+
agent = "local";
|
|
71
66
|
}
|
|
72
67
|
else {
|
|
73
|
-
agent = "
|
|
68
|
+
agent = "cloud";
|
|
74
69
|
}
|
|
75
70
|
}
|
|
76
71
|
else {
|
|
77
|
-
// Unknown entrypoint
|
|
78
72
|
agent = "Unknown";
|
|
79
73
|
}
|
|
80
74
|
return {
|
|
@@ -84,6 +78,21 @@ export function detectAgent() {
|
|
|
84
78
|
agent,
|
|
85
79
|
};
|
|
86
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Normalize legacy agent names to new generic names.
|
|
83
|
+
* Accepts both old (CLI, DAC, CODA-1, Brain_Local, Brain_Cloud)
|
|
84
|
+
* and new (cli, desktop, autonomous, local, cloud) formats.
|
|
85
|
+
*/
|
|
86
|
+
const LEGACY_MAP = {
|
|
87
|
+
"CLI": "cli",
|
|
88
|
+
"DAC": "desktop",
|
|
89
|
+
"CODA-1": "autonomous",
|
|
90
|
+
"Brain_Local": "local",
|
|
91
|
+
"Brain_Cloud": "cloud",
|
|
92
|
+
};
|
|
93
|
+
export function normalizeAgent(input) {
|
|
94
|
+
return LEGACY_MAP[input] || input;
|
|
95
|
+
}
|
|
87
96
|
/**
|
|
88
97
|
* Get just the agent identity (convenience function)
|
|
89
98
|
*/
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Analytics Service
|
|
2
|
+
* Analytics Service
|
|
3
3
|
*
|
|
4
4
|
* Shared analytics engine for session insights. Powers both the
|
|
5
5
|
* gitmem-analyze MCP tool (CLI) and the GitMem Console dashboard.
|
|
6
6
|
*
|
|
7
7
|
* Uses directQuery for raw Supabase REST access (no ww-mcp dependency).
|
|
8
8
|
*/
|
|
9
|
-
import { directQuery, directQueryAll } from "./supabase-client.js";
|
|
9
|
+
import { directQuery, directQueryAll, safeInFilter } from "./supabase-client.js";
|
|
10
10
|
import { getCache } from "./cache.js";
|
|
11
11
|
// --- Query Layer ---
|
|
12
12
|
/**
|
|
@@ -97,7 +97,7 @@ export async function enrichScarUsageTitles(usages) {
|
|
|
97
97
|
const learnings = await directQuery("orchestra_learnings", {
|
|
98
98
|
select: "id,title,severity",
|
|
99
99
|
filters: {
|
|
100
|
-
id:
|
|
100
|
+
id: safeInFilter(ids),
|
|
101
101
|
},
|
|
102
102
|
});
|
|
103
103
|
// Build lookup map
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 2. fetchDismissalCounts() — queries scar_usage for inline archival hints
|
|
11
11
|
* (called from recall to annotate frequently-dismissed scars)
|
|
12
12
|
*/
|
|
13
|
-
import { isConfigured } from "./supabase-client.js";
|
|
13
|
+
import { isConfigured, safeInFilter } from "./supabase-client.js";
|
|
14
14
|
const SUPABASE_URL = process.env.SUPABASE_URL || "";
|
|
15
15
|
const SUPABASE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_KEY || "";
|
|
16
16
|
const SUPABASE_REST_URL = SUPABASE_URL ? `${SUPABASE_URL}/rest/v1` : "";
|
|
@@ -76,7 +76,7 @@ export async function fetchDismissalCounts(scarIds) {
|
|
|
76
76
|
// Query scar_usage for the given scar IDs (last 90 days)
|
|
77
77
|
const url = new URL(`${SUPABASE_REST_URL}/scar_usage`);
|
|
78
78
|
url.searchParams.set("select", "scar_id,reference_type");
|
|
79
|
-
url.searchParams.set("scar_id",
|
|
79
|
+
url.searchParams.set("scar_id", safeInFilter(scarIds));
|
|
80
80
|
url.searchParams.set("surfaced_at", `gte.${new Date(Date.now() - 90 * 86400000).toISOString()}`);
|
|
81
81
|
url.searchParams.set("limit", "1000");
|
|
82
82
|
const response = await fetch(url.toString(), {
|
package/dist/services/cache.d.ts
CHANGED
package/dist/services/cache.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Caches search results to avoid repeated ww-mcp calls.
|
|
6
6
|
*
|
|
7
7
|
* Design: docs/systems/gitmem-caching.md
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
9
|
*/
|
|
10
10
|
import { createHash } from "crypto";
|
|
11
11
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, unlinkSync, statSync } from "fs";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Validates session close compliance based on close type.
|
|
5
5
|
*
|
|
6
|
-
* Standard close requires
|
|
6
|
+
* Standard close requires:
|
|
7
7
|
* - task_completion object with timestamps proving each step was done
|
|
8
8
|
* - All 6 closing questions answered
|
|
9
9
|
* - human_corrections field present (even if empty string)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Validates session close compliance based on close type.
|
|
5
5
|
*
|
|
6
|
-
* Standard close requires
|
|
6
|
+
* Standard close requires:
|
|
7
7
|
* - task_completion object with timestamps proving each step was done
|
|
8
8
|
* - All 6 closing questions answered
|
|
9
9
|
* - human_corrections field present (even if empty string)
|
|
@@ -17,7 +17,7 @@ import { CLOSING_QUESTIONS } from "../constants/closing-questions.js";
|
|
|
17
17
|
/** Minimum time (ms) between asking human and receiving response */
|
|
18
18
|
const MIN_HUMAN_RESPONSE_GAP_MS = 3000;
|
|
19
19
|
/**
|
|
20
|
-
* Validate task_completion timestamps
|
|
20
|
+
* Validate task_completion timestamps
|
|
21
21
|
*
|
|
22
22
|
* Ensures:
|
|
23
23
|
* 1. All timestamps are valid ISO strings
|
|
@@ -83,14 +83,14 @@ function validateTaskCompletion(tc) {
|
|
|
83
83
|
/**
|
|
84
84
|
* Validate standard close parameters
|
|
85
85
|
*
|
|
86
|
-
*
|
|
86
|
+
* Now requires task_completion with timestamps proving each step was done.
|
|
87
87
|
*/
|
|
88
88
|
function validateStandardClose(params) {
|
|
89
89
|
const errors = [];
|
|
90
90
|
const warnings = [];
|
|
91
|
-
//
|
|
91
|
+
// task_completion is REQUIRED for standard close
|
|
92
92
|
if (!params.task_completion) {
|
|
93
|
-
errors.push("Standard close requires task_completion object
|
|
93
|
+
errors.push("Standard close requires task_completion object. " +
|
|
94
94
|
"You must complete each step: display questions → answer → ask human → wait for response");
|
|
95
95
|
}
|
|
96
96
|
else {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - GITMEM_STALE_CHECK: "true" | "false" - Check for stale data (default: "true")
|
|
11
11
|
* - SUPABASE_URL: Supabase project URL
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
*/
|
|
15
15
|
import type { GitMemTier } from "./tier.js";
|
|
16
16
|
export type SearchMode = "local" | "remote" | "auto";
|
package/dist/services/config.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - GITMEM_STALE_CHECK: "true" | "false" - Check for stale data (default: "true")
|
|
11
11
|
* - SUPABASE_URL: Supabase project URL
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
*/
|
|
15
15
|
import { getTier, hasSupabase, getTablePrefix } from "./tier.js";
|
|
16
16
|
// Private IP patterns for on-prem detection
|
|
@@ -66,6 +66,18 @@ export function acquireLockSync(lockPath, timeoutMs = DEFAULT_TIMEOUT_MS, retryM
|
|
|
66
66
|
if (error.code !== "EEXIST") {
|
|
67
67
|
throw new Error(`[file-lock] Failed to create lock file ${lockPath}: ${error.message}`);
|
|
68
68
|
}
|
|
69
|
+
// Lock file exists — check if we already hold it (reentrance detection)
|
|
70
|
+
try {
|
|
71
|
+
const raw = fs.readFileSync(lockPath, "utf-8");
|
|
72
|
+
const holder = JSON.parse(raw);
|
|
73
|
+
if (holder.pid === process.pid && holder.hostname === os.hostname()) {
|
|
74
|
+
// Same process already holds the lock — reentrant call, allow through
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Can't read lock — fall through to stale check
|
|
80
|
+
}
|
|
69
81
|
// Lock file exists — check if stale
|
|
70
82
|
if (isLockStale(lockPath)) {
|
|
71
83
|
try {
|
|
@@ -2,20 +2,33 @@
|
|
|
2
2
|
* Resolved .gitmem directory path
|
|
3
3
|
*
|
|
4
4
|
* Solves: process.cwd() changes when agents cd into other repos (e.g., /workspace/gitmem),
|
|
5
|
-
* but .gitmem/ was created in the project root
|
|
5
|
+
* but .gitmem/ was created in the project root.
|
|
6
6
|
* The MCP server is long-running, so we resolve the path once and cache it.
|
|
7
7
|
*
|
|
8
8
|
* Resolution order:
|
|
9
|
-
* 1.
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
9
|
+
* 1. GITMEM_DIR env var (explicit override)
|
|
10
|
+
* 2. Cached path from session_start (most reliable — session_start created the directory)
|
|
11
|
+
* 3. Walk up from process.cwd() looking for existing .gitmem/ sentinels (backward compat)
|
|
12
|
+
* 4. Fall back to ~/.gitmem (developer-scoped, survives across projects/containers)
|
|
12
13
|
*/
|
|
14
|
+
/**
|
|
15
|
+
* Validate a string intended for use as a single path component (directory name or filename).
|
|
16
|
+
* Rejects path traversal sequences, directory separators, and null bytes.
|
|
17
|
+
* Throws on invalid input — callers should validate before reaching this layer.
|
|
18
|
+
*/
|
|
19
|
+
export declare function sanitizePathComponent(value: string, label: string): string;
|
|
13
20
|
/**
|
|
14
21
|
* Set the .gitmem directory path (called by session_start after creating it)
|
|
15
22
|
*/
|
|
16
23
|
export declare function setGitmemDir(dir: string): void;
|
|
17
24
|
/**
|
|
18
25
|
* Get the resolved .gitmem directory path
|
|
26
|
+
*
|
|
27
|
+
* Resolution order:
|
|
28
|
+
* 1. GITMEM_DIR env var (explicit override)
|
|
29
|
+
* 2. Cached path from session_start (most reliable)
|
|
30
|
+
* 3. Walk up from CWD looking for existing .gitmem/ sentinels (backward compat)
|
|
31
|
+
* 4. Fall back to ~/.gitmem (developer-scoped, survives across projects/containers)
|
|
19
32
|
*/
|
|
20
33
|
export declare function getGitmemDir(): string;
|
|
21
34
|
/**
|
|
@@ -2,16 +2,32 @@
|
|
|
2
2
|
* Resolved .gitmem directory path
|
|
3
3
|
*
|
|
4
4
|
* Solves: process.cwd() changes when agents cd into other repos (e.g., /workspace/gitmem),
|
|
5
|
-
* but .gitmem/ was created in the project root
|
|
5
|
+
* but .gitmem/ was created in the project root.
|
|
6
6
|
* The MCP server is long-running, so we resolve the path once and cache it.
|
|
7
7
|
*
|
|
8
8
|
* Resolution order:
|
|
9
|
-
* 1.
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
9
|
+
* 1. GITMEM_DIR env var (explicit override)
|
|
10
|
+
* 2. Cached path from session_start (most reliable — session_start created the directory)
|
|
11
|
+
* 3. Walk up from process.cwd() looking for existing .gitmem/ sentinels (backward compat)
|
|
12
|
+
* 4. Fall back to ~/.gitmem (developer-scoped, survives across projects/containers)
|
|
12
13
|
*/
|
|
13
14
|
import * as path from "path";
|
|
14
15
|
import * as fs from "fs";
|
|
16
|
+
import * as os from "os";
|
|
17
|
+
/**
|
|
18
|
+
* Validate a string intended for use as a single path component (directory name or filename).
|
|
19
|
+
* Rejects path traversal sequences, directory separators, and null bytes.
|
|
20
|
+
* Throws on invalid input — callers should validate before reaching this layer.
|
|
21
|
+
*/
|
|
22
|
+
export function sanitizePathComponent(value, label) {
|
|
23
|
+
if (!value || typeof value !== "string") {
|
|
24
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
25
|
+
}
|
|
26
|
+
if (value.includes("..") || value.includes("/") || value.includes("\\") || value.includes("\0")) {
|
|
27
|
+
throw new Error(`${label} contains invalid characters (path traversal rejected)`);
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
15
31
|
let cachedGitmemDir = null;
|
|
16
32
|
/**
|
|
17
33
|
* Set the .gitmem directory path (called by session_start after creating it)
|
|
@@ -22,13 +38,29 @@ export function setGitmemDir(dir) {
|
|
|
22
38
|
}
|
|
23
39
|
/**
|
|
24
40
|
* Get the resolved .gitmem directory path
|
|
41
|
+
*
|
|
42
|
+
* Resolution order:
|
|
43
|
+
* 1. GITMEM_DIR env var (explicit override)
|
|
44
|
+
* 2. Cached path from session_start (most reliable)
|
|
45
|
+
* 3. Walk up from CWD looking for existing .gitmem/ sentinels (backward compat)
|
|
46
|
+
* 4. Fall back to ~/.gitmem (developer-scoped, survives across projects/containers)
|
|
25
47
|
*/
|
|
26
48
|
export function getGitmemDir() {
|
|
27
|
-
// 1.
|
|
49
|
+
// 1. GITMEM_DIR env var (explicit override, highest priority)
|
|
50
|
+
const envDir = process.env.GITMEM_DIR;
|
|
51
|
+
if (envDir) {
|
|
52
|
+
if (!cachedGitmemDir || cachedGitmemDir !== envDir) {
|
|
53
|
+
cachedGitmemDir = envDir;
|
|
54
|
+
console.error(`[gitmem-dir] Using GITMEM_DIR env var: ${envDir}`);
|
|
55
|
+
}
|
|
56
|
+
return envDir;
|
|
57
|
+
}
|
|
58
|
+
// 2. Use cached path from session_start
|
|
28
59
|
if (cachedGitmemDir && fs.existsSync(cachedGitmemDir)) {
|
|
29
60
|
return cachedGitmemDir;
|
|
30
61
|
}
|
|
31
|
-
//
|
|
62
|
+
// 3. Walk up from CWD looking for existing .gitmem directory
|
|
63
|
+
// Backward compat: finds project-scoped .gitmem/ from older installations.
|
|
32
64
|
// Sentinel files checked in priority order:
|
|
33
65
|
// - active-sessions.json (multi-session registry, GIT-19)
|
|
34
66
|
// - config.json (project-level gitmem config)
|
|
@@ -46,9 +78,9 @@ export function getGitmemDir() {
|
|
|
46
78
|
}
|
|
47
79
|
dir = path.dirname(dir);
|
|
48
80
|
}
|
|
49
|
-
//
|
|
50
|
-
const fallback = path.join(
|
|
51
|
-
console.error(`[gitmem-dir] Falling back to
|
|
81
|
+
// 4. Fall back to ~/.gitmem (developer-scoped — survives across projects and containers)
|
|
82
|
+
const fallback = path.join(os.homedir(), ".gitmem");
|
|
83
|
+
console.error(`[gitmem-dir] Falling back to home dir: ${fallback}`);
|
|
52
84
|
return fallback;
|
|
53
85
|
}
|
|
54
86
|
/**
|
|
@@ -62,6 +94,7 @@ export function getGitmemPath(filename) {
|
|
|
62
94
|
* Creates the directory if it doesn't exist.
|
|
63
95
|
*/
|
|
64
96
|
export function getSessionDir(sessionId) {
|
|
97
|
+
sanitizePathComponent(sessionId, "sessionId");
|
|
65
98
|
const sessionsDir = path.join(getGitmemDir(), "sessions", sessionId);
|
|
66
99
|
if (!fs.existsSync(sessionsDir)) {
|
|
67
100
|
fs.mkdirSync(sessionsDir, { recursive: true });
|
|
@@ -73,6 +106,7 @@ export function getSessionDir(sessionId) {
|
|
|
73
106
|
* Get a file path within a per-session directory.
|
|
74
107
|
*/
|
|
75
108
|
export function getSessionPath(sessionId, filename) {
|
|
109
|
+
sanitizePathComponent(filename, "filename");
|
|
76
110
|
return path.join(getSessionDir(sessionId), filename);
|
|
77
111
|
}
|
|
78
112
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Local File Storage — Free Tier Backend
|
|
3
3
|
*
|
|
4
4
|
* Stores scars, sessions, decisions, and scar usage as JSON files
|
|
5
|
-
* in the .gitmem/ directory
|
|
5
|
+
* in the .gitmem/ directory (defaults to ~/.gitmem, overridable via GITMEM_DIR).
|
|
6
6
|
*
|
|
7
7
|
* Provides keyword-based search (no embeddings needed).
|
|
8
8
|
*/
|