memento-mcp 0.3.0 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memento-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "mcpName": "io.github.myrakrusemark/memento-protocol",
5
5
  "description": "The Memento Protocol — persistent memory for AI agents",
6
6
  "type": "module",
@@ -0,0 +1,140 @@
1
+ #!/bin/bash
2
+ # hook-toast.sh — tmux popup notifications for agent hooks.
3
+ #
4
+ # Usage:
5
+ # hook-toast.sh <system> <message> # one-shot toast (auto-closes after 2s)
6
+ # hook-toast.sh <system> --status <id> # start a multi-stage toast (poll mode)
7
+ # hook-toast.sh --update <id> <message> # update a running toast
8
+ # hook-toast.sh --close <id> # close a running toast (after delay)
9
+ #
10
+ # Built-in systems: fathom, memento
11
+ # fathom → 📝 purple (colour141)
12
+ # memento → 🧠 teal (colour37)
13
+ #
14
+ # Any other system name works too — gets a default icon and grey border.
15
+ #
16
+ # Multi-stage example (PreCompact):
17
+ # hook-toast.sh memento --status precompact
18
+ # hook-toast.sh --update precompact "⏳ Getting context..."
19
+ # hook-toast.sh --update precompact "⏳ Extracting memories..."
20
+ # hook-toast.sh --update precompact "✓ Stored 7 memories"
21
+ # hook-toast.sh --close precompact
22
+
23
+ TOAST_DIR="/tmp/hook-toast"
24
+ mkdir -p "$TOAST_DIR"
25
+
26
+ # Bail silently if not in tmux
27
+ if ! tmux info &>/dev/null; then
28
+ exit 0
29
+ fi
30
+
31
+ get_style() {
32
+ case "$1" in
33
+ memento) echo "colour37" ;;
34
+ fathom) echo "colour141" ;;
35
+ *) echo "colour245" ;;
36
+ esac
37
+ }
38
+
39
+ get_icon() {
40
+ case "$1" in
41
+ memento) echo "🧠" ;;
42
+ fathom) echo "📝" ;;
43
+ *) echo "📌" ;;
44
+ esac
45
+ }
46
+
47
+ get_title() {
48
+ case "$1" in
49
+ memento) echo "Memento" ;;
50
+ fathom) echo "Fathom" ;;
51
+ *) echo "$1" ;;
52
+ esac
53
+ }
54
+
55
+ # One-shot toast
56
+ toast_oneshot() {
57
+ local system="$1"
58
+ local message="$2"
59
+ local colour icon title
60
+ colour=$(get_style "$system")
61
+ icon=$(get_icon "$system")
62
+ title=$(get_title "$system")
63
+
64
+ (tmux display-popup -x R -y 0 -w 42 -h 3 \
65
+ -s "fg=$colour" -T " $icon $title " -E \
66
+ "echo ' $message'; sleep 2" &>/dev/null &)
67
+ }
68
+
69
+ # Start a multi-stage toast (polling status file)
70
+ toast_start() {
71
+ local system="$1"
72
+ local id="$2"
73
+ local status_file="$TOAST_DIR/$id"
74
+ local colour icon title
75
+ colour=$(get_style "$system")
76
+ icon=$(get_icon "$system")
77
+ title=$(get_title "$system")
78
+
79
+ echo "⏳ Starting..." > "$status_file"
80
+
81
+ (tmux display-popup -x R -y 0 -w 42 -h 3 \
82
+ -s "fg=$colour" -T " $icon $title " -E "
83
+ LAST=''
84
+ while [ -f '$status_file' ]; do
85
+ MSG=\$(cat '$status_file' 2>/dev/null)
86
+ if [ \"\$MSG\" != \"\$LAST\" ]; then
87
+ clear
88
+ echo \" \$MSG\"
89
+ LAST=\"\$MSG\"
90
+ fi
91
+ case \"\$MSG\" in ✓*|✗*) sleep 2; break ;; esac
92
+ sleep 0.2
93
+ done
94
+ " &>/dev/null &)
95
+ }
96
+
97
+ # Update a running toast
98
+ toast_update() {
99
+ local id="$1"
100
+ local message="$2"
101
+ echo "$message" > "$TOAST_DIR/$id"
102
+ }
103
+
104
+ # Close a running toast (remove status file — popup exits on next poll)
105
+ toast_close() {
106
+ local id="$1"
107
+ # Give the popup time to display the final message
108
+ sleep 2
109
+ rm -f "$TOAST_DIR/$id"
110
+ }
111
+
112
+ # --- Argument parsing ---
113
+ case "${1:-}" in
114
+ --update)
115
+ toast_update "$2" "$3"
116
+ ;;
117
+ --close)
118
+ toast_close "$2"
119
+ ;;
120
+ --*)
121
+ echo "Unknown option: $1" >&2
122
+ exit 1
123
+ ;;
124
+ "")
125
+ echo "Usage: hook-toast.sh <system> <message>" >&2
126
+ echo " hook-toast.sh <system> --status <id>" >&2
127
+ echo " hook-toast.sh --update <id> <message>" >&2
128
+ echo " hook-toast.sh --close <id>" >&2
129
+ exit 1
130
+ ;;
131
+ *)
132
+ SYSTEM="$1"
133
+ shift
134
+ if [ "${1:-}" = "--status" ]; then
135
+ toast_start "$SYSTEM" "$2"
136
+ else
137
+ toast_oneshot "$SYSTEM" "$*"
138
+ fi
139
+ ;;
140
+ esac
@@ -8,17 +8,27 @@
8
8
  set -o pipefail
9
9
 
10
10
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
11
+ TOAST="$SCRIPT_DIR/hook-toast.sh"
12
+
13
+ # Toast: start multi-stage
14
+ "$TOAST" memento --status distill &>/dev/null
15
+ "$TOAST" --update distill "⏳ Getting context..." &>/dev/null
16
+
11
17
  INPUT=$(cat)
12
18
 
13
19
  TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path' | sed "s|~|$HOME|")
14
20
 
15
21
  # Only distill if transcript exists and has content
16
22
  if [ ! -f "$TRANSCRIPT_PATH" ]; then
23
+ "$TOAST" --update distill "✗ No transcript found" &>/dev/null
24
+ ("$TOAST" --close distill &>/dev/null &)
17
25
  exit 0
18
26
  fi
19
27
 
20
28
  LINE_COUNT=$(wc -l < "$TRANSCRIPT_PATH")
21
29
  if [ "$LINE_COUNT" -lt 2 ]; then
30
+ "$TOAST" --update distill "✓ Skipped (tiny conversation)" &>/dev/null
31
+ ("$TOAST" --close distill &>/dev/null &)
22
32
  exit 0
23
33
  fi
24
34
 
@@ -79,9 +89,14 @@ else
79
89
  fi
80
90
 
81
91
  if [ ${#TRANSCRIPT_TEXT} -lt 200 ]; then
92
+ "$TOAST" --update distill "✓ Skipped (too short)" &>/dev/null
93
+ ("$TOAST" --close distill &>/dev/null &)
82
94
  exit 0 # Too short to distill anything useful
83
95
  fi
84
96
 
97
+ # Toast: extracting
98
+ "$TOAST" --update distill "⏳ Extracting memories..." &>/dev/null
99
+
85
100
  DISTILL_MODEL="${DISTILL_MODEL:-llama}"
86
101
 
87
102
  # claude-code path: run extraction locally via claude -p, push to /v1/memories/ingest
@@ -166,9 +181,15 @@ print(json.dumps({'memories': parsed, 'source': 'distill:claude-code'}))
166
181
  -d "$INGEST_PAYLOAD" \
167
182
  "$MEMENTO_API/v1/memories/ingest" > /dev/null 2>&1
168
183
 
184
+ "$TOAST" --update distill "✓ Stored ${MEMORY_COUNT} memories" &>/dev/null
185
+ ("$TOAST" --close distill &>/dev/null &)
186
+
169
187
  python3 -c "import json,sys; print(json.dumps({'systemMessage': sys.argv[1]}))" \
170
188
  "Memento Distill (claude-code): ${MEMORY_COUNT} memories — ${TYPE_BREAKDOWN}"
171
189
  else
190
+ "$TOAST" --update distill "✓ No memories extracted" &>/dev/null
191
+ ("$TOAST" --close distill &>/dev/null &)
192
+
172
193
  python3 -c "import json,sys; print(json.dumps({'systemMessage': sys.argv[1]}))" \
173
194
  "Memento Distill (claude-code): no memories extracted"
174
195
  fi
@@ -206,9 +227,15 @@ MEMORY_COUNT=$(echo "$DISTILL_SUMMARY" | cut -d'|' -f1)
206
227
  TYPE_BREAKDOWN=$(echo "$DISTILL_SUMMARY" | cut -d'|' -f2)
207
228
 
208
229
  if [ "${MEMORY_COUNT:-0}" -gt 0 ] 2>/dev/null; then
230
+ "$TOAST" --update distill "✓ Stored ${MEMORY_COUNT} memories" &>/dev/null
231
+ ("$TOAST" --close distill &>/dev/null &)
232
+
209
233
  python3 -c "import json,sys; print(json.dumps({'systemMessage': sys.argv[1]}))" \
210
234
  "Memento Distill: ${MEMORY_COUNT} memories — ${TYPE_BREAKDOWN}"
211
235
  else
236
+ "$TOAST" --update distill "✓ No memories extracted" &>/dev/null
237
+ ("$TOAST" --close distill &>/dev/null &)
238
+
212
239
  python3 -c "import json,sys; print(json.dumps({'systemMessage': sys.argv[1]}))" \
213
240
  "Memento Distill: no memories extracted"
214
241
  fi
@@ -10,6 +10,7 @@
10
10
  set -o pipefail
11
11
 
12
12
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
13
+ TOAST="$SCRIPT_DIR/hook-toast.sh"
13
14
 
14
15
  # --- Config from .memento.json (if present) ---
15
16
  CONFIG_JSON=$(python3 -c "
@@ -80,6 +81,9 @@ ACTIVE_TMP=$(mktemp)
80
81
  SKIP_TMP=$(mktemp)
81
82
  trap 'rm -f "$IDENTITY_TMP" "$ACTIVE_TMP" "$SKIP_TMP"' EXIT
82
83
 
84
+ # Toast: loading identity
85
+ "$TOAST" memento "⏳ Loading identity..." &>/dev/null
86
+
83
87
  # Fetch all three endpoints in parallel
84
88
  curl -s --max-time 3 -H "$AUTH_HEADER" -H "$WS_HEADER" \
85
89
  "$MEMENTO_API/v1/identity" > "$IDENTITY_TMP" 2>/dev/null &
@@ -159,4 +163,7 @@ print(json.dumps({
159
163
  }))
160
164
  " "$IDENTITY_TMP" "$ACTIVE_TMP" "$SKIP_TMP" 2>/dev/null
161
165
 
166
+ # Toast: done
167
+ "$TOAST" memento "✓ Identity loaded" &>/dev/null
168
+
162
169
  exit 0
@@ -6,6 +6,7 @@
6
6
  set -o pipefail
7
7
 
8
8
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
9
+ TOAST="$SCRIPT_DIR/hook-toast.sh"
9
10
 
10
11
  # --- Config from .memento.json (if present) ---
11
12
  CONFIG_JSON=$(python3 -c "
@@ -74,6 +75,9 @@ fi
74
75
  # Truncate to first 500 chars for the query
75
76
  QUERY="${ASSISTANT_MSG:0:500}"
76
77
 
78
+ # Toast: start retrieving
79
+ "$TOAST" memento "⏳ Autonomous recall..." &>/dev/null
80
+
77
81
  # Call Memento /v1/context
78
82
  RESULT=$(curl -s --max-time 3 \
79
83
  -X POST \
@@ -122,9 +126,13 @@ if [ -n "$REMAINING" ]; then
122
126
  fi
123
127
 
124
128
  if [ -z "$SAAS_COUNT" ] || [ "$SAAS_COUNT" = "0" ]; then
129
+ "$TOAST" memento "✓ No memories matched" &>/dev/null
125
130
  exit 0
126
131
  fi
127
132
 
133
+ # Toast: result
134
+ "$TOAST" memento "✓ ${SAAS_COUNT} memories recalled" &>/dev/null
135
+
128
136
  # Block the Stop so Claude continues — the reason becomes Claude's next instruction.
129
137
  REASON="Autonomous Recall: ${SAAS_COUNT} memories surfaced from your last response.
130
138
  ${SAAS_DETAIL}
@@ -7,6 +7,7 @@
7
7
  set -o pipefail
8
8
 
9
9
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
+ TOAST="$SCRIPT_DIR/hook-toast.sh"
10
11
 
11
12
  # --- Config from .memento.json (if present) ---
12
13
  CONFIG_JSON=$(python3 -c "
@@ -66,6 +67,9 @@ fi
66
67
 
67
68
  QUERY="${USER_MESSAGE:0:500}"
68
69
 
70
+ # Toast: start retrieving
71
+ "$TOAST" memento "⏳ Retrieving memories..." &>/dev/null
72
+
69
73
  # Call Memento SaaS /v1/context
70
74
  SAAS_OUTPUT=$(curl -s --max-time 3 \
71
75
  -X POST \
@@ -118,9 +122,13 @@ if [ -n "$REMAINING" ]; then
118
122
  fi
119
123
 
120
124
  if [ -z "$SAAS_COUNT" ] || [ "$SAAS_COUNT" = "0" ]; then
125
+ "$TOAST" memento "✓ No memories matched" &>/dev/null
121
126
  exit 0
122
127
  fi
123
128
 
129
+ # Toast: result
130
+ "$TOAST" memento "✓ ${SAAS_COUNT} memories recalled" &>/dev/null
131
+
124
132
  DETAIL_TEXT="Memento Recall: ${SAAS_COUNT} memories"
125
133
  DETAIL_TEXT="$DETAIL_TEXT"$'\n'"$SAAS_DETAIL"
126
134
  DETAIL_TEXT="$DETAIL_TEXT"$'\n'$'\n'"REMINDER: If Memento MCP tools are not loaded, run: ToolSearch query=\"+memento\" max_results=20"
package/src/cli.js CHANGED
@@ -403,6 +403,7 @@ async function runInit() {
403
403
  fs.mkdirSync(localScriptsDir, { recursive: true });
404
404
 
405
405
  const scriptFiles = [
406
+ "hook-toast.sh",
406
407
  enableUserPrompt && "memento-userprompt-recall.sh",
407
408
  enableStop && "memento-stop-recall.sh",
408
409
  enablePreCompact && "memento-precompact-distill.sh",