gitmem-mcp 1.0.13 → 1.0.14

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.
@@ -104,6 +104,11 @@ function buildHooks() {
104
104
  {
105
105
  matcher: "Bash",
106
106
  hooks: [
107
+ {
108
+ type: "command",
109
+ command: `bash ${relScripts}/credential-guard.sh`,
110
+ timeout: 3000,
111
+ },
107
112
  {
108
113
  type: "command",
109
114
  command: `bash ${relScripts}/recall-check.sh`,
@@ -111,6 +116,16 @@ function buildHooks() {
111
116
  },
112
117
  ],
113
118
  },
119
+ {
120
+ matcher: "Read",
121
+ hooks: [
122
+ {
123
+ type: "command",
124
+ command: `bash ${relScripts}/credential-guard.sh`,
125
+ timeout: 3000,
126
+ },
127
+ ],
128
+ },
114
129
  {
115
130
  matcher: "Write",
116
131
  hooks: [
@@ -0,0 +1,48 @@
1
+ ---
2
+ description: Show GitMem session status, hook activity, and recall state
3
+ allowed-tools: ["Bash", "Read", "mcp__gitmem__gitmem-cache-status"]
4
+ ---
5
+
6
+ # GitMem Status
7
+
8
+ Check the current state of the GitMem hooks plugin and active session.
9
+
10
+ ## Instructions
11
+
12
+ 1. **Check if gitmem MCP is connected:**
13
+ Call the `mcp__gitmem__gitmem-cache-status` tool. If it returns a response, the server is connected. Report scar count and cache age from the response.
14
+ Do NOT use `claude mcp list` — its health check returns false negatives.
15
+
16
+ 2. **Check active session:**
17
+ Read `.gitmem/active-session.json` if it exists. Report:
18
+ - Session ID
19
+ - Agent identity
20
+ - Start time
21
+ - Whether scars have been surfaced (surfaced_scars timestamp)
22
+
23
+ 3. **Check hook state:**
24
+ Look for `/tmp/gitmem-hooks-*` directories. Report:
25
+ - Session start time
26
+ - Tool call count
27
+ - Last nag time
28
+ - Whether stop_hook_active guard is set
29
+
30
+ 4. **Check audit trail:**
31
+ Read `/tmp/gitmem-hooks-*/audit.jsonl` if it exists. Report:
32
+ - Total LOOKED events (recall/search calls)
33
+ - Total ACTION events (consequential actions)
34
+ - Whether any ACTION was taken without a prior LOOKED (potential gap)
35
+ - Last 5 audit entries
36
+
37
+ 5. **Summary:**
38
+ Present a concise status block:
39
+ ```
40
+ GitMem Status
41
+ ├── MCP Server: connected/disconnected
42
+ ├── Active Session: <id> (started <time>)
43
+ ├── Recall: last called <time> / never called
44
+ ├── Tool Calls: <count>
45
+ ├── Audit Trail: <looked> LOOKED / <action> ACTION events
46
+ │ └── Look-before-act: <yes/gap detected>
47
+ └── Hooks: session-start ✓ | recall-check ✓ | post-tool-use ✓ | close-check ✓
48
+ ```
@@ -0,0 +1,141 @@
1
+ #!/bin/bash
2
+ # GitMem Hooks Plugin — PostToolUse Display Hook
3
+ #
4
+ # PURPOSE: Deterministic MCP tool output display.
5
+ # Routes formatted display directly to the terminal (bypassing the LLM)
6
+ # and replaces the LLM's view with machine-readable data only.
7
+ #
8
+ # Architecture:
9
+ # Channel 1 (stdout, exit 0) → User sees in terminal, LLM does NOT
10
+ # Channel 2 (updatedMCPToolOutput) → LLM sees, user does NOT directly
11
+ #
12
+ # The gitmem MCP server returns responses with an optional separator:
13
+ # [formatted display]
14
+ # ═══ GITMEM_DATA ═══
15
+ # {"machine": "data"}
16
+ #
17
+ # This hook splits on that separator. If no separator exists, the entire
18
+ # response is treated as display-only.
19
+ #
20
+ # Input: JSON via stdin with tool_name, tool_input, tool_response
21
+ # Output: JSON with hookSpecificOutput.updatedMCPToolOutput (or exit 0)
22
+
23
+ set -e
24
+
25
+ # Read hook input from stdin
26
+ HOOK_INPUT=$(cat -)
27
+
28
+ # Extract tool name
29
+ TOOL_NAME=""
30
+ if command -v jq &>/dev/null; then
31
+ TOOL_NAME=$(echo "$HOOK_INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
32
+ else
33
+ TOOL_NAME=$(echo "$HOOK_INPUT" | node -e "
34
+ let d='';
35
+ process.stdin.on('data',c=>d+=c);
36
+ process.stdin.on('end',()=>{
37
+ try { process.stdout.write(JSON.parse(d).tool_name||''); }
38
+ catch(e) { process.stdout.write(''); }
39
+ });
40
+ " 2>/dev/null)
41
+ fi
42
+
43
+ # Only process gitmem MCP tools
44
+ case "$TOOL_NAME" in
45
+ mcp__gitmem__*) ;;
46
+ *) exit 0 ;;
47
+ esac
48
+
49
+ # Extract tool response — try both field names Claude Code might use
50
+ TOOL_RESPONSE=""
51
+ if command -v jq &>/dev/null; then
52
+ TOOL_RESPONSE=$(echo "$HOOK_INPUT" | jq -r '(.tool_response // .tool_output // empty)' 2>/dev/null)
53
+ else
54
+ TOOL_RESPONSE=$(echo "$HOOK_INPUT" | node -e "
55
+ let d='';
56
+ process.stdin.on('data',c=>d+=c);
57
+ process.stdin.on('end',()=>{
58
+ try {
59
+ const j=JSON.parse(d);
60
+ process.stdout.write(String(j.tool_response||j.tool_output||''));
61
+ } catch(e) { process.stdout.write(''); }
62
+ });
63
+ " 2>/dev/null)
64
+ fi
65
+
66
+ # No response to process
67
+ if [ -z "$TOOL_RESPONSE" ] || [ "$TOOL_RESPONSE" = "null" ]; then
68
+ exit 0
69
+ fi
70
+
71
+ # ============================================================================
72
+ # Split response into DISPLAY and MACHINE DATA
73
+ # ============================================================================
74
+
75
+ SEPARATOR="═══ GITMEM_DATA ═══"
76
+
77
+ # Check if separator exists in response
78
+ if echo "$TOOL_RESPONSE" | grep -qF "$SEPARATOR"; then
79
+ # Split: display = everything before separator, data = everything after
80
+ DISPLAY_PART=$(echo "$TOOL_RESPONSE" | awk -v sep="$SEPARATOR" '{if ($0 == sep) exit; print}')
81
+ MACHINE_PART=$(echo "$TOOL_RESPONSE" | awk -v sep="$SEPARATOR" 'found{print} $0==sep{found=1}')
82
+ else
83
+ # No separator — entire response is display-only
84
+ DISPLAY_PART="$TOOL_RESPONSE"
85
+ MACHINE_PART=""
86
+ fi
87
+
88
+ # ============================================================================
89
+ # Strip DISPLAY PROTOCOL suffix from display portion
90
+ # ============================================================================
91
+
92
+ # Remove the separator line and everything after it (DISPLAY PROTOCOL instructions)
93
+ DISPLAY_CLEAN=$(echo "$DISPLAY_PART" | awk '/^───────────────────────────────────────────────────$/{exit} {print}')
94
+
95
+ # If stripping removed everything (shouldn't happen), fall back to full display
96
+ if [ -z "$DISPLAY_CLEAN" ]; then
97
+ DISPLAY_CLEAN="$DISPLAY_PART"
98
+ fi
99
+
100
+ # ============================================================================
101
+ # Channel 1: Print display to stdout (user sees, LLM does not)
102
+ # ============================================================================
103
+
104
+ echo "$DISPLAY_CLEAN"
105
+
106
+ # ============================================================================
107
+ # Channel 2: Return updatedMCPToolOutput (LLM sees, user does not directly)
108
+ # ============================================================================
109
+
110
+ # Build the LLM-facing replacement
111
+ SHORT_NAME=$(echo "$TOOL_NAME" | sed 's/^mcp__gitmem__//')
112
+
113
+ if [ -n "$MACHINE_PART" ]; then
114
+ # Has machine data — give LLM the structured data
115
+ LLM_TEXT="gitmem ${SHORT_NAME} · output displayed to user\n${MACHINE_PART}"
116
+ else
117
+ # Display-only — give LLM a brief summary
118
+ # Include the display text so LLM can still reference the content
119
+ LLM_TEXT="gitmem ${SHORT_NAME} · output displayed to user\n${DISPLAY_CLEAN}"
120
+ fi
121
+
122
+ # Escape for JSON embedding (handle newlines, quotes, backslashes)
123
+ if command -v jq &>/dev/null; then
124
+ LLM_JSON=$(printf '%s' "$LLM_TEXT" | jq -Rs '.')
125
+ else
126
+ LLM_JSON=$(printf '%s' "$LLM_TEXT" | node -e "
127
+ let d='';
128
+ process.stdin.on('data',c=>d+=c);
129
+ process.stdin.on('end',()=>process.stdout.write(JSON.stringify(d)));
130
+ " 2>/dev/null)
131
+ fi
132
+
133
+ # Return the hook response with updatedMCPToolOutput
134
+ cat <<HOOKJSON
135
+ {
136
+ "hookSpecificOutput": {
137
+ "hookEventName": "PostToolUse",
138
+ "updatedMCPToolOutput": ${LLM_JSON}
139
+ }
140
+ }
141
+ HOOKJSON
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitmem-mcp",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Institutional memory for AI coding agents. Memory that compounds.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",