@onlooker-community/ecosystem 0.22.0 → 0.23.0

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.
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env bats
2
+ #
3
+ # Exercises the substrate-level memory.recalled emitter. The hook fires
4
+ # on SessionStart and emits one canonical memory.recalled event per
5
+ # typed memory file in the project's typed memory store at
6
+ # ~/.claude/projects/<encoded>/memory/.
7
+ #
8
+ # Curator's usage tracker depends on this signal; without it,
9
+ # zero-recall findings can't be generated. The tests below pin both the
10
+ # happy path (correct count and provenance) and the skip cases (no git
11
+ # context, no memory store, compact source).
12
+
13
+ setup() {
14
+ source "${BATS_TEST_DIRNAME}/../helpers/setup.bash"
15
+ setup_test_env
16
+
17
+ export CLAUDE_PLUGIN_ROOT="$REPO_ROOT"
18
+
19
+ PROJECT_REPO="${BATS_TEST_TMPDIR}/repo"
20
+ mkdir -p "$PROJECT_REPO"
21
+ git -C "$PROJECT_REPO" init -q
22
+ git -C "$PROJECT_REPO" config user.email t@example.com
23
+ git -C "$PROJECT_REPO" config user.name "Test"
24
+ git -C "$PROJECT_REPO" remote add origin git@github.com:org/memory-recall-test.git
25
+
26
+ # Derive the encoded project dir under CLAUDE_HOME so the hook resolves
27
+ # via the path-encoding fallback (CLAUDE_PROJECT_ENCODED unset).
28
+ ABS_CWD=$(cd "$PROJECT_REPO" && pwd -P)
29
+ ENCODED=$(printf '%s' "$ABS_CWD" | sed -E 's#/#-#g')
30
+ MEM_DIR="${TEST_HOME}/.claude/projects/${ENCODED}/memory"
31
+ mkdir -p "$MEM_DIR"
32
+
33
+ ONLOOKER_EVENTS_LOG="${ONLOOKER_DIR}/logs/onlooker-events.jsonl"
34
+ HOOK="${REPO_ROOT}/scripts/hooks/memory-recall-tracker.sh"
35
+ }
36
+
37
+ _input() {
38
+ local source="${1:-startup}"
39
+ jq -cn --arg cwd "$PROJECT_REPO" --arg sid "sess-mem-test" --arg source "$source" \
40
+ '{cwd:$cwd, session_id:$sid, source:$source, hook_event_name:"SessionStart"}'
41
+ }
42
+
43
+ _seed_memory() {
44
+ local fname="$1" type="$2" name="${3:-$fname}"
45
+ printf -- '---\nname: %s\ndescription: test\ntype: %s\n---\n\nBody.\n' \
46
+ "$name" "$type" > "${MEM_DIR}/${fname}"
47
+ }
48
+
49
+ @test "memory-recall emits one event per typed memory file" {
50
+ _seed_memory "user_role.md" "user"
51
+ _seed_memory "feedback_no_summaries.md" "feedback"
52
+ _seed_memory "project_auth_rewrite.md" "project"
53
+ _seed_memory "reference_dashboards.md" "reference"
54
+
55
+ run bash -c "printf '%s' '$(_input)' | '$HOOK'"
56
+ [ "$status" -eq 0 ]
57
+
58
+ local count
59
+ count=$(grep -c '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG")
60
+ [ "$count" -eq 4 ]
61
+
62
+ # One event per memory_type, with the right filename.
63
+ grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
64
+ | jq -e 'select(.payload.memory_type == "user" and .payload.memory_file == "user_role.md")' >/dev/null
65
+ grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
66
+ | jq -e 'select(.payload.memory_type == "feedback")' >/dev/null
67
+ grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
68
+ | jq -e 'select(.payload.memory_type == "project")' >/dev/null
69
+ grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
70
+ | jq -e 'select(.payload.memory_type == "reference")' >/dev/null
71
+
72
+ # recall_position values are 0..N-1, distinct.
73
+ local positions
74
+ positions=$(grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
75
+ | jq -r '.payload.recall_position' | sort -n | paste -sd, -)
76
+ [ "$positions" = "0,1,2,3" ]
77
+ }
78
+
79
+ @test "memory-recall skips MEMORY.md itself" {
80
+ _seed_memory "feedback_one.md" "feedback"
81
+ printf '%s\n' '- [One](feedback_one.md) — one' > "${MEM_DIR}/MEMORY.md"
82
+
83
+ run bash -c "printf '%s' '$(_input)' | '$HOOK'"
84
+ [ "$status" -eq 0 ]
85
+
86
+ # MEMORY.md is not its own memory; should NOT appear as a memory_file.
87
+ ! grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
88
+ | jq -e 'select(.payload.memory_file == "MEMORY.md")' >/dev/null
89
+ local count
90
+ count=$(grep -c '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG")
91
+ [ "$count" -eq 1 ]
92
+ }
93
+
94
+ @test "memory-recall skips memories without a recognized type" {
95
+ _seed_memory "feedback_valid.md" "feedback"
96
+ # Memory with an unrecognized type field — should be silently dropped.
97
+ printf -- '---\nname: weird\ntype: unknown\n---\n\nBody.\n' \
98
+ > "${MEM_DIR}/weird.md"
99
+ # Memory with no frontmatter at all — also dropped.
100
+ printf '%s\n' 'just a body, no metadata' > "${MEM_DIR}/raw.md"
101
+
102
+ run bash -c "printf '%s' '$(_input)' | '$HOOK'"
103
+ [ "$status" -eq 0 ]
104
+
105
+ local count
106
+ count=$(grep -c '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG")
107
+ [ "$count" -eq 1 ]
108
+ grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
109
+ | jq -e '.payload.memory_file == "feedback_valid.md"' >/dev/null
110
+ }
111
+
112
+ @test "memory-recall emits nothing when the memory store is empty" {
113
+ # MEM_DIR exists (created in setup) but contains no *.md files. The
114
+ # hook walks the glob, finds zero matches, and emits no events.
115
+ run bash -c "printf '%s' '$(_input)' | '$HOOK'"
116
+ [ "$status" -eq 0 ]
117
+ [ ! -f "$ONLOOKER_EVENTS_LOG" ] || ! grep -q '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG"
118
+ }
119
+
120
+ @test "memory-recall emits nothing when the memory store directory does not exist" {
121
+ # This is the genuinely-missing-directory branch — the dir check at
122
+ # the top of the hook short-circuits before any file walk.
123
+ rm -rf "$MEM_DIR"
124
+ [ ! -d "$MEM_DIR" ]
125
+
126
+ run bash -c "printf '%s' '$(_input)' | '$HOOK'"
127
+ [ "$status" -eq 0 ]
128
+ [ ! -f "$ONLOOKER_EVENTS_LOG" ] || ! grep -q '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG"
129
+ }
130
+
131
+ @test "memory-recall is a no-op when cwd is not a git repo" {
132
+ local non_git="${BATS_TEST_TMPDIR}/no-git"
133
+ mkdir -p "$non_git"
134
+ _seed_memory "user_x.md" "user"
135
+
136
+ local input
137
+ input=$(jq -cn --arg cwd "$non_git" --arg sid "s" --arg source "startup" \
138
+ '{cwd:$cwd, session_id:$sid, source:$source}')
139
+
140
+ run bash -c "printf '%s' '$input' | '$HOOK'"
141
+ [ "$status" -eq 0 ]
142
+ [ ! -f "$ONLOOKER_EVENTS_LOG" ] || ! grep -q '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG"
143
+ }
144
+
145
+ @test "memory-recall skips compact source to avoid double-counting" {
146
+ _seed_memory "user_x.md" "user"
147
+
148
+ run bash -c "printf '%s' '$(_input compact)' | '$HOOK'"
149
+ [ "$status" -eq 0 ]
150
+ [ ! -f "$ONLOOKER_EVENTS_LOG" ] || ! grep -q '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG"
151
+ }
152
+
153
+ @test "memory-recall payload carries the same project_key for two clones" {
154
+ _seed_memory "user_x.md" "user"
155
+
156
+ run bash -c "printf '%s' '$(_input)' | '$HOOK'"
157
+ [ "$status" -eq 0 ]
158
+
159
+ local key
160
+ key=$(grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
161
+ | jq -r '.payload.project_key' | head -1)
162
+
163
+ # Second clone of the same remote at a different path. The key should
164
+ # match (SHA256 of remote URL, path-independent).
165
+ local clone2="${BATS_TEST_TMPDIR}/clone2"
166
+ mkdir -p "$clone2"
167
+ git -C "$clone2" init -q
168
+ git -C "$clone2" remote add origin git@github.com:org/memory-recall-test.git
169
+
170
+ local ABS_CWD2 ENCODED2 MEM_DIR2
171
+ ABS_CWD2=$(cd "$clone2" && pwd -P)
172
+ ENCODED2=$(printf '%s' "$ABS_CWD2" | sed -E 's#/#-#g')
173
+ MEM_DIR2="${TEST_HOME}/.claude/projects/${ENCODED2}/memory"
174
+ mkdir -p "$MEM_DIR2"
175
+ printf -- '---\nname: x\ntype: user\n---\n\nBody.\n' > "${MEM_DIR2}/user_x.md"
176
+
177
+ rm -f "$ONLOOKER_EVENTS_LOG"
178
+ local input2
179
+ input2=$(jq -cn --arg cwd "$clone2" --arg sid "s" --arg source "startup" \
180
+ '{cwd:$cwd, session_id:$sid, source:$source}')
181
+ run bash -c "printf '%s' '$input2' | '$HOOK'"
182
+ [ "$status" -eq 0 ]
183
+
184
+ local key2
185
+ key2=$(grep '"event_type":"memory.recalled"' "$ONLOOKER_EVENTS_LOG" \
186
+ | jq -r '.payload.project_key' | head -1)
187
+
188
+ [ "$key" = "$key2" ]
189
+ }