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.
- package/bin/init-wizard.js +15 -0
- package/hooks/commands/gitmem-status.md +48 -0
- package/hooks/scripts/display-hook.sh +141 -0
- package/package.json +1 -1
package/bin/init-wizard.js
CHANGED
|
@@ -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
|