@rubytech/create-maxy 1.0.883 → 1.0.885

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.
Files changed (42) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-mcp/dist/index.js +45 -0
  3. package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
  4. package/payload/platform/lib/graph-mcp/src/index.ts +47 -0
  5. package/payload/platform/lib/mcp-eager/dist/index.d.ts +61 -0
  6. package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -0
  7. package/payload/platform/lib/mcp-eager/dist/index.js +49 -0
  8. package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -0
  9. package/payload/platform/lib/mcp-eager/src/index.ts +78 -0
  10. package/payload/platform/lib/mcp-eager/tsconfig.json +8 -0
  11. package/payload/platform/package.json +2 -2
  12. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  13. package/payload/platform/plugins/admin/mcp/dist/index.js +48 -76
  14. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  15. package/payload/platform/plugins/contacts/mcp/dist/index.js +10 -9
  16. package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
  17. package/payload/platform/plugins/docs/references/internals.md +13 -0
  18. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  19. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  20. package/payload/platform/plugins/email/mcp/dist/index.js +10 -9
  21. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  22. package/payload/platform/plugins/memory/mcp/dist/index.js +9 -8
  23. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  24. package/payload/platform/plugins/scheduling/mcp/dist/index.js +9 -8
  25. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  26. package/payload/platform/plugins/tasks/mcp/dist/index.js +15 -14
  27. package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
  28. package/payload/platform/plugins/telegram/mcp/dist/index.js +4 -3
  29. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
  30. package/payload/platform/plugins/workflows/mcp/dist/index.js +9 -8
  31. package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
  32. package/payload/platform/scripts/__tests__/logs-read-prefix.sh +85 -240
  33. package/payload/platform/scripts/log-adherence-check.sh +100 -0
  34. package/payload/platform/scripts/logs-read.sh +71 -141
  35. package/payload/platform/scripts/logs-read.test.sh +47 -104
  36. package/payload/premium-plugins/real-agency/BUNDLE.md +1 -1
  37. package/payload/server/chunk-5PQU2HW2.js +11672 -0
  38. package/payload/server/chunk-NPKQWE3S.js +1431 -0
  39. package/payload/server/chunk-ZVO5ASQA.js +11660 -0
  40. package/payload/server/client-pool-QUMX7OUT.js +34 -0
  41. package/payload/server/maxy-edge.js +2 -2
  42. package/payload/server/server.js +123 -121
@@ -1,19 +1,18 @@
1
1
  #!/usr/bin/env bash
2
- # Task 998bash harness for logs-read.sh prefix-match resolution.
2
+ # Task 1006prefix-match harness for logs-read.sh.
3
3
  #
4
- # Covers the contract from the task brief:
5
- # 1. 8-char prefix resolves full-UUID file (the original bug)
6
- # 2. Multiple matches reason=ambiguous-prefix, exit 1, never picks
7
- # 3. More-specific prefix disambiguates
8
- # 4. Zero matches → reason=file-not-found-in-either-shape with glob patterns
9
- # 5. Full 36-char UUID still resolves (regression boundary)
10
- # 6. Preflush prefix match
11
- # 7. Preflush ambiguity (Pass 1 zero, Pass 2 multiple)
12
- # 8. Every per-conversation type (agent-stream, session, error, public)
13
- # resolves under prefix-match
4
+ # Task 998 introduced 8-char-prefix resolution; Task 1006 collapses the
5
+ # writer's two-shape contract to one (`claude-agent-stream-<sessionKey>.log`).
6
+ # The prefix match still applies, now against a single basename shape.
14
7
  #
15
- # Companion to platform/scripts/logs-read.test.sh (Task 671's two-shape
16
- # resolution harness).
8
+ # Cases:
9
+ # 1. 8-char prefix resolves a full sessionKey-named file.
10
+ # 2. Multiple matches → ambiguous-prefix, exit 1, never picks silently.
11
+ # 3. More-specific prefix disambiguates.
12
+ # 4. Zero matches → exit 1 with file-not-found trailer.
13
+ # 5. Full 36-char sessionKey still resolves (regression boundary).
14
+ # 6. Every per-session type (agent-stream, session, error, public)
15
+ # resolves under prefix-match.
17
16
  set -euo pipefail
18
17
 
19
18
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -26,9 +25,6 @@ fi
26
25
  PASS=0
27
26
  FAIL=0
28
27
 
29
- # logs-read.sh resolves PLATFORM_ROOT from its own location; mirror the
30
- # logs-read.test.sh convention by symlinking the script into an ephemeral
31
- # install tree per case.
32
28
  setup_install_tree() {
33
29
  local root="$1"
34
30
  mkdir -p "$root/platform/scripts"
@@ -58,281 +54,130 @@ run_case() {
58
54
  fi
59
55
  }
60
56
 
61
- # --- Case 1: 8-char prefix resolves a full-UUID file (original bug) ---
62
- case_prefix_resolves_full() {
63
- local root="/tmp/maxy-logs-read-prefix-1-$$"
57
+ case_8char_prefix_resolves_full() {
58
+ local root="/tmp/maxy-prefix-test-1-$$"
64
59
  local script
65
60
  script=$(setup_install_tree "$root")
66
61
  local logdir="$root/data/accounts/acct-test/logs"
67
- local full_uuid="3483269d-c793-4a07-98cc-556d936f2f4d"
68
- local filename="claude-agent-stream-${full_uuid}.log"
69
- echo "prefix-match-sentinel" > "$logdir/$filename"
70
-
71
- local stdout stderr rc=0
72
- stdout=$("$script" "3483269d" system 2>/tmp/logs-read-prefix-stderr-1-$$) || rc=$?
73
- stderr=$(cat /tmp/logs-read-prefix-stderr-1-$$)
74
- rm -f /tmp/logs-read-prefix-stderr-1-$$
62
+ local sk="abcd1234-5678-90ab-cdef-1234567890ab"
63
+ echo "sentinel-1" > "$logdir/claude-agent-stream-${sk}.log"
75
64
 
65
+ local rc=0
66
+ local stdout
67
+ stdout=$("$script" "abcd1234" agent-stream 2>/dev/null) || rc=$?
76
68
  cleanup_install_tree "$root"
77
69
 
78
- if [[ $rc -ne 0 ]]; then echo " expected exit 0, got $rc"; return 1; fi
79
- if [[ "$stdout" != *"prefix-match-sentinel"* ]]; then
80
- echo " stdout missing sentinel: $stdout"; return 1
81
- fi
82
- if [[ "$stderr" != *"matched_shape=full"* ]]; then
83
- echo " stderr missing matched_shape=full: $stderr"; return 1
84
- fi
85
- if [[ "$stdout" != *"$filename"* ]]; then
86
- echo " header missing matched filename: $stdout"; return 1
87
- fi
70
+ [[ $rc -eq 0 ]] || { echo " expected exit 0, got $rc"; return 1; }
71
+ [[ "$stdout" == *"sentinel-1"* ]] || { echo " missing sentinel"; return 1; }
88
72
  return 0
89
73
  }
90
74
 
91
- # --- Case 2: Multiple matches on Pass 1 → ambiguous-prefix, exit 1 ---
92
- case_ambiguous_prefix() {
93
- local root="/tmp/maxy-logs-read-prefix-2-$$"
75
+ case_ambiguous_prefix_refuses() {
76
+ local root="/tmp/maxy-prefix-test-2-$$"
94
77
  local script
95
78
  script=$(setup_install_tree "$root")
96
79
  local logdir="$root/data/accounts/acct-test/logs"
97
- echo "A" > "$logdir/claude-agent-stream-aaaaaaaa-1111-A.log"
98
- echo "B" > "$logdir/claude-agent-stream-aaaaaaaa-2222-B.log"
99
-
100
- local stdout stderr rc=0
101
- stdout=$("$script" "aaaaaaaa" system 2>/tmp/logs-read-prefix-stderr-2-$$) || rc=$?
102
- stderr=$(cat /tmp/logs-read-prefix-stderr-2-$$)
103
- rm -f /tmp/logs-read-prefix-stderr-2-$$
104
-
80
+ echo "a" > "$logdir/claude-agent-stream-abcd1111.log"
81
+ echo "b" > "$logdir/claude-agent-stream-abcd2222.log"
82
+
83
+ local rc=0
84
+ "$script" "abcd" agent-stream >/dev/null 2>/tmp/prefix-stderr-2-$$ || rc=$?
85
+ local stderr
86
+ stderr=$(cat /tmp/prefix-stderr-2-$$)
87
+ rm -f /tmp/prefix-stderr-2-$$
105
88
  cleanup_install_tree "$root"
106
89
 
107
- if [[ $rc -ne 1 ]]; then echo " expected exit 1, got $rc"; return 1; fi
108
- if [[ "$stderr" != *"reason=ambiguous-prefix"* ]]; then
109
- echo " stderr missing reason=ambiguous-prefix: $stderr"; return 1
110
- fi
111
- if [[ "$stderr" != *"matches=2"* ]]; then
112
- echo " stderr missing matches=2: $stderr"; return 1
113
- fi
114
- if [[ "$stderr" != *"claude-agent-stream-aaaaaaaa-1111-A.log"* ]]; then
115
- echo " stderr missing candidate A: $stderr"; return 1
116
- fi
117
- if [[ "$stderr" != *"claude-agent-stream-aaaaaaaa-2222-B.log"* ]]; then
118
- echo " stderr missing candidate B: $stderr"; return 1
119
- fi
120
- # Body must NOT contain either sentinel — refusal means no body emitted.
121
- if [[ -n "$stdout" ]]; then
122
- echo " stdout non-empty on ambiguous refusal: $stdout"; return 1
123
- fi
90
+ [[ $rc -eq 1 ]] || { echo " expected exit 1, got $rc"; return 1; }
91
+ [[ "$stderr" == *"ambiguous-prefix"* ]] || { echo " stderr missing ambiguous-prefix: $stderr"; return 1; }
124
92
  return 0
125
93
  }
126
94
 
127
- # --- Case 3: more-specific prefix disambiguates ---
128
- case_more_specific_disambiguates() {
129
- local root="/tmp/maxy-logs-read-prefix-3-$$"
95
+ case_more_specific_prefix_resolves() {
96
+ local root="/tmp/maxy-prefix-test-3-$$"
130
97
  local script
131
98
  script=$(setup_install_tree "$root")
132
99
  local logdir="$root/data/accounts/acct-test/logs"
133
- echo "ONE" > "$logdir/claude-agent-stream-aaaaaaaa-1111-A.log"
134
- echo "TWO" > "$logdir/claude-agent-stream-aaaaaaaa-2222-B.log"
135
-
136
- local stdout stderr rc=0
137
- stdout=$("$script" "aaaaaaaa-1111" system 2>/tmp/logs-read-prefix-stderr-3-$$) || rc=$?
138
- stderr=$(cat /tmp/logs-read-prefix-stderr-3-$$)
139
- rm -f /tmp/logs-read-prefix-stderr-3-$$
100
+ echo "a" > "$logdir/claude-agent-stream-abcd1111.log"
101
+ echo "b" > "$logdir/claude-agent-stream-abcd2222.log"
140
102
 
103
+ local rc=0
104
+ local stdout
105
+ stdout=$("$script" "abcd1111" agent-stream 2>/dev/null) || rc=$?
141
106
  cleanup_install_tree "$root"
142
107
 
143
- if [[ $rc -ne 0 ]]; then echo " expected exit 0, got $rc"; return 1; fi
144
- if [[ "$stdout" != *"ONE"* ]]; then echo " stdout missing ONE: $stdout"; return 1; fi
145
- if [[ "$stdout" == *"TWO"* ]]; then echo " stdout contained TWO: $stdout"; return 1; fi
146
- if [[ "$stderr" != *"matched_shape=full"* ]]; then
147
- echo " stderr missing matched_shape=full: $stderr"; return 1
148
- fi
108
+ [[ $rc -eq 0 ]] || { echo " expected exit 0, got $rc"; return 1; }
109
+ [[ "$stdout" == *"a"* ]] || { echo " missing sentinel"; return 1; }
149
110
  return 0
150
111
  }
151
112
 
152
- # --- Case 4: zero matches → tried=[<glob>, <glob>] file-not-found ---
153
- case_zero_matches() {
154
- local root="/tmp/maxy-logs-read-prefix-4-$$"
113
+ case_zero_match_miss() {
114
+ local root="/tmp/maxy-prefix-test-4-$$"
155
115
  local script
156
116
  script=$(setup_install_tree "$root")
157
117
 
158
- local stdout stderr rc=0
159
- stdout=$("$script" "xxxxxxxx" system 2>/tmp/logs-read-prefix-stderr-4-$$) || rc=$?
160
- stderr=$(cat /tmp/logs-read-prefix-stderr-4-$$)
161
- rm -f /tmp/logs-read-prefix-stderr-4-$$
162
-
118
+ local rc=0
119
+ "$script" "nomatch1" agent-stream >/dev/null 2>/tmp/prefix-stderr-4-$$ || rc=$?
120
+ local stderr
121
+ stderr=$(cat /tmp/prefix-stderr-4-$$)
122
+ rm -f /tmp/prefix-stderr-4-$$
163
123
  cleanup_install_tree "$root"
164
124
 
165
- if [[ $rc -ne 1 ]]; then echo " expected exit 1, got $rc"; return 1; fi
166
- if [[ "$stderr" != *"reason=file-not-found-in-either-shape"* ]]; then
167
- echo " stderr missing reason=file-not-found-in-either-shape: $stderr"; return 1
168
- fi
169
- if [[ "$stderr" != *"tried=[claude-agent-stream-xxxxxxxx*.log, claude-agent-stream-preflush-xxxxxxxx*.log]"* ]]; then
170
- echo " stderr missing tried=[<glob>, <glob>]: $stderr"; return 1
171
- fi
125
+ [[ $rc -eq 1 ]] || { echo " expected exit 1, got $rc"; return 1; }
126
+ [[ "$stderr" == *"file-not-found"* ]] || { echo " stderr missing file-not-found"; return 1; }
172
127
  return 0
173
128
  }
174
129
 
175
- # --- Case 5: full 36-char UUID still resolves (regression boundary) ---
176
- case_full_uuid_regression() {
177
- local root="/tmp/maxy-logs-read-prefix-5-$$"
130
+ case_full_sessionkey_resolves() {
131
+ local root="/tmp/maxy-prefix-test-5-$$"
178
132
  local script
179
133
  script=$(setup_install_tree "$root")
180
134
  local logdir="$root/data/accounts/acct-test/logs"
181
- local full_uuid="3483269d-c793-4a07-98cc-556d936f2f4d"
182
- local filename="claude-agent-stream-${full_uuid}.log"
183
- echo "regression-sentinel" > "$logdir/$filename"
184
-
185
- local stdout stderr rc=0
186
- stdout=$("$script" "$full_uuid" system 2>/tmp/logs-read-prefix-stderr-5-$$) || rc=$?
187
- stderr=$(cat /tmp/logs-read-prefix-stderr-5-$$)
188
- rm -f /tmp/logs-read-prefix-stderr-5-$$
135
+ local sk="11111111-2222-3333-4444-555555555555"
136
+ echo "sentinel-5" > "$logdir/claude-agent-stream-${sk}.log"
189
137
 
138
+ local rc=0
139
+ local stdout
140
+ stdout=$("$script" "$sk" agent-stream 2>/dev/null) || rc=$?
190
141
  cleanup_install_tree "$root"
191
142
 
192
- if [[ $rc -ne 0 ]]; then echo " expected exit 0, got $rc"; return 1; fi
193
- if [[ "$stdout" != *"regression-sentinel"* ]]; then
194
- echo " stdout missing sentinel: $stdout"; return 1
195
- fi
196
- if [[ "$stderr" != *"matched_shape=full"* ]]; then
197
- echo " stderr missing matched_shape=full: $stderr"; return 1
198
- fi
143
+ [[ $rc -eq 0 ]] || { echo " expected exit 0, got $rc"; return 1; }
144
+ [[ "$stdout" == *"sentinel-5"* ]] || { echo " missing sentinel"; return 1; }
199
145
  return 0
200
146
  }
201
147
 
202
- # --- Case 6: preflush-only file, prefix-match (Pass 2) ---
203
- case_preflush_prefix_match() {
204
- local root="/tmp/maxy-logs-read-prefix-6-$$"
148
+ case_every_per_session_type() {
149
+ local root="/tmp/maxy-prefix-test-6-$$"
205
150
  local script
206
151
  script=$(setup_install_tree "$root")
207
152
  local logdir="$root/data/accounts/acct-test/logs"
208
- # Preflush filename uses sessionKey:0:12; mimic with a 12-char slice.
209
- echo "preflush-prefix-sentinel" > "$logdir/claude-agent-stream-preflush-bbbbbbbb-ccc.log"
210
-
211
- local stdout stderr rc=0
212
- stdout=$("$script" "bbbbbbbb" system 2>/tmp/logs-read-prefix-stderr-6-$$) || rc=$?
213
- stderr=$(cat /tmp/logs-read-prefix-stderr-6-$$)
214
- rm -f /tmp/logs-read-prefix-stderr-6-$$
215
-
216
- cleanup_install_tree "$root"
217
-
218
- if [[ $rc -ne 0 ]]; then echo " expected exit 0, got $rc"; return 1; fi
219
- if [[ "$stdout" != *"preflush-prefix-sentinel"* ]]; then
220
- echo " stdout missing sentinel: $stdout"; return 1
221
- fi
222
- if [[ "$stderr" != *"matched_shape=preflush"* ]]; then
223
- echo " stderr missing matched_shape=preflush: $stderr"; return 1
224
- fi
225
- return 0
226
- }
227
-
228
- # --- Case 7: preflush ambiguity (Pass 1 zero, Pass 2 multiple) ---
229
- case_preflush_ambiguity() {
230
- local root="/tmp/maxy-logs-read-prefix-7-$$"
231
- local script
232
- script=$(setup_install_tree "$root")
233
- local logdir="$root/data/accounts/acct-test/logs"
234
- echo "P1" > "$logdir/claude-agent-stream-preflush-cccccccc-111.log"
235
- echo "P2" > "$logdir/claude-agent-stream-preflush-cccccccc-222.log"
236
-
237
- local stdout stderr rc=0
238
- stdout=$("$script" "cccccccc" system 2>/tmp/logs-read-prefix-stderr-7-$$) || rc=$?
239
- stderr=$(cat /tmp/logs-read-prefix-stderr-7-$$)
240
- rm -f /tmp/logs-read-prefix-stderr-7-$$
241
-
242
- cleanup_install_tree "$root"
243
-
244
- if [[ $rc -ne 1 ]]; then echo " expected exit 1, got $rc"; return 1; fi
245
- if [[ "$stderr" != *"reason=ambiguous-prefix"* ]]; then
246
- echo " stderr missing reason=ambiguous-prefix: $stderr"; return 1
247
- fi
248
- if [[ "$stderr" != *"matches=2"* ]]; then
249
- echo " stderr missing matches=2: $stderr"; return 1
250
- fi
251
- if [[ "$stderr" != *"claude-agent-stream-preflush-cccccccc-111.log"* ]]; then
252
- echo " stderr missing preflush candidate 1: $stderr"; return 1
253
- fi
254
- if [[ "$stderr" != *"claude-agent-stream-preflush-cccccccc-222.log"* ]]; then
255
- echo " stderr missing preflush candidate 2: $stderr"; return 1
256
- fi
257
- return 0
258
- }
259
-
260
- # --- Case 8: every per-conversation type resolves under prefix-match ---
261
- # Parameterised over the four prefix_for_type values:
262
- # agent-stream → claude-agent-stream-
263
- # session → sse-events-
264
- # error → claude-agent-stderr-
265
- # public → public-agent-stream-
266
- case_all_types_prefix_match() {
267
- local root="/tmp/maxy-logs-read-prefix-8-$$"
268
- local script
269
- script=$(setup_install_tree "$root")
270
- local logdir="$root/data/accounts/acct-test/logs"
271
- local full_uuid="7d49ef21-1234-4567-89ab-cdef01234567"
272
-
273
- echo "sentinel-agent-stream" > "$logdir/claude-agent-stream-${full_uuid}.log"
274
- echo "sentinel-session" > "$logdir/sse-events-${full_uuid}.log"
275
- echo "sentinel-error" > "$logdir/claude-agent-stderr-${full_uuid}.log"
276
- echo "sentinel-public" > "$logdir/public-agent-stream-${full_uuid}.log"
277
-
278
- local pairs=(
279
- "agent-stream|sentinel-agent-stream"
280
- "session|sentinel-session"
281
- "error|sentinel-error"
282
- "public|sentinel-public"
283
- )
284
- local fail=0
285
- local pair t expected_sentinel
286
- for pair in "${pairs[@]}"; do
287
- t="${pair%%|*}"
288
- expected_sentinel="${pair##*|}"
289
- local stdout stderr rc=0
290
- stdout=$("$script" "7d49ef21" "$t" 2>/tmp/logs-read-prefix-stderr-8-$$) || rc=$?
291
- stderr=$(cat /tmp/logs-read-prefix-stderr-8-$$)
292
- rm -f /tmp/logs-read-prefix-stderr-8-$$
293
- if [[ $rc -ne 0 ]]; then echo " [$t] expected exit 0, got $rc — stderr: $stderr"; fail=1; continue; fi
294
- if [[ "$stdout" != *"$expected_sentinel"* ]]; then
295
- echo " [$t] missing sentinel '$expected_sentinel': $stdout"; fail=1
296
- fi
297
- if [[ "$stderr" != *"matched_shape=full"* ]]; then
298
- echo " [$t] stderr missing matched_shape=full: $stderr"; fail=1
299
- fi
153
+ local sk="abcdef00-0000-0000-0000-000000000000"
154
+ echo "stream" > "$logdir/claude-agent-stream-${sk}.log"
155
+ echo "err" > "$logdir/claude-agent-stderr-${sk}.log"
156
+ echo "sse" > "$logdir/sse-events-${sk}.log"
157
+ echo "pub" > "$logdir/public-agent-stream-${sk}.log"
158
+
159
+ local ok=1
160
+ for type in agent-stream error session public; do
161
+ local out
162
+ out=$("$script" "abcdef00" "$type" 2>/dev/null) || ok=0
163
+ case "$type" in
164
+ agent-stream) [[ "$out" == *"stream"* ]] || ok=0 ;;
165
+ error) [[ "$out" == *"err"* ]] || ok=0 ;;
166
+ session) [[ "$out" == *"sse"* ]] || ok=0 ;;
167
+ public) [[ "$out" == *"pub"* ]] || ok=0 ;;
168
+ esac
300
169
  done
301
-
302
- cleanup_install_tree "$root"
303
- [[ $fail -eq 0 ]]
304
- }
305
-
306
- # --- Case 9: conv_id with shell metacharacters is rejected ---
307
- case_metacharacter_rejected() {
308
- local root="/tmp/maxy-logs-read-prefix-9-$$"
309
- local script
310
- script=$(setup_install_tree "$root")
311
-
312
- local stdout stderr rc=0
313
- # Use a backslash-escaped wildcard to feed it as a literal argument.
314
- stdout=$("$script" "ab*cd" system 2>/tmp/logs-read-prefix-stderr-9-$$) || rc=$?
315
- stderr=$(cat /tmp/logs-read-prefix-stderr-9-$$)
316
- rm -f /tmp/logs-read-prefix-stderr-9-$$
317
-
318
170
  cleanup_install_tree "$root"
319
-
320
- if [[ $rc -ne 2 ]]; then echo " expected exit 2 (usage), got $rc"; return 1; fi
321
- if [[ "$stderr" != *"invalid characters"* ]]; then
322
- echo " stderr missing invalid-characters guard: $stderr"; return 1
323
- fi
171
+ [[ $ok -eq 1 ]] || { echo " one or more per-session types failed to resolve"; return 1; }
324
172
  return 0
325
173
  }
326
174
 
327
- run_case "8-char prefix resolves full-UUID file" case_prefix_resolves_full
328
- run_case "ambiguous prefix refused, candidates listed" case_ambiguous_prefix
329
- run_case "more-specific prefix disambiguates" case_more_specific_disambiguates
330
- run_case "zero matches → file-not-found-in-either-shape" case_zero_matches
331
- run_case "full 36-char UUID still resolves" case_full_uuid_regression
332
- run_case "preflush file resolves by prefix" case_preflush_prefix_match
333
- run_case "preflush ambiguity refused" case_preflush_ambiguity
334
- run_case "every per-conversation type prefix-matches" case_all_types_prefix_match
335
- run_case "shell metacharacters rejected" case_metacharacter_rejected
175
+ run_case "8-char prefix resolves full sessionKey file" case_8char_prefix_resolves_full
176
+ run_case "ambiguous prefix refuses to pick" case_ambiguous_prefix_refuses
177
+ run_case "more-specific prefix disambiguates" case_more_specific_prefix_resolves
178
+ run_case "zero matches → file-not-found" case_zero_match_miss
179
+ run_case "full 36-char sessionKey resolves" case_full_sessionkey_resolves
180
+ run_case "every per-session type resolves" case_every_per_session_type
336
181
 
337
182
  echo ""
338
183
  echo "================================================"
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env bash
2
+ # log-adherence-check.sh — Task 1006 existence contract diagnostic.
3
+ #
4
+ # Reads every sessionKey under the active install's per-account logs and
5
+ # asserts that a resolvable claude-agent-stream-<sessionKey>.log exists for
6
+ # each. Runs hourly on-device in addition to the in-process timer wired
7
+ # from platform/ui/app/lib/claude-agent/logging.ts; both are intentionally
8
+ # redundant — one runs inside the server process, this one runs out of band
9
+ # so a stalled server still leaves a fresh adherence record.
10
+ #
11
+ # Emits one `[log-tee] adherence-check window=24h sessions=N misses=M ts=...`
12
+ # line to the platform server log on every run. Per-miss lines surface as
13
+ # `[log-tee] missing-on-resolve sessionKey=<8> surface=adherence-script
14
+ # reason=file-not-on-disk`. `misses=0` is the steady state.
15
+ #
16
+ # Exit codes:
17
+ # 0 No misses (steady state).
18
+ # 1 At least one miss recorded.
19
+ # 2 Usage / environment error.
20
+ set -euo pipefail
21
+
22
+ # --- Resolve install dir, the same way logs-read.sh does. ---
23
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
24
+ PLATFORM_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
25
+ INSTALL_DIR="$(dirname "$PLATFORM_ROOT")"
26
+ INSTALL_DIR_NAME=$(basename "$INSTALL_DIR")
27
+ CONFIG_DIR="$HOME/.$INSTALL_DIR_NAME"
28
+ SERVER_LOG="$CONFIG_DIR/logs/server.log"
29
+
30
+ ACCOUNTS_DIR="$INSTALL_DIR/data/accounts"
31
+ if [[ ! -d "$ACCOUNTS_DIR" ]]; then
32
+ echo "[log-adherence-check] accounts directory missing: $ACCOUNTS_DIR" >&2
33
+ exit 2
34
+ fi
35
+
36
+ # Window: only count session keys whose stream-log file was modified in the
37
+ # last 24h. This avoids fingerprinting long-archived sessions that have aged
38
+ # out via the 7-day retention purge.
39
+ WINDOW_HOURS=24
40
+
41
+ # Collect every basename-derived sessionKey from claude-agent-stream-*.log
42
+ # files across all account log directories, filtered to the active window.
43
+ declare -a KEYS=()
44
+ shopt -s nullglob
45
+ for log_dir in "$ACCOUNTS_DIR"/*/logs; do
46
+ for f in "$log_dir"/claude-agent-stream-*.log; do
47
+ if [[ -f "$f" ]]; then
48
+ # find -mmin needs minutes; 24h = 1440 min.
49
+ if find "$f" -mmin "-$((WINDOW_HOURS * 60))" -print -quit | grep -q .; then
50
+ base=$(basename "$f")
51
+ key="${base#claude-agent-stream-}"
52
+ key="${key%.log}"
53
+ KEYS+=("$key")
54
+ fi
55
+ fi
56
+ done
57
+ done
58
+ shopt -u nullglob
59
+
60
+ # De-duplicate sessionKeys (one session may emit multiple .log files via
61
+ # sibling prefixes; the existence contract is per-sessionKey).
62
+ declare -A SEEN=()
63
+ declare -a UNIQUE=()
64
+ for k in "${KEYS[@]:-}"; do
65
+ if [[ -z "${SEEN[$k]:-}" ]]; then
66
+ SEEN[$k]=1
67
+ UNIQUE+=("$k")
68
+ fi
69
+ done
70
+
71
+ SESSIONS=${#UNIQUE[@]}
72
+ MISSES=0
73
+
74
+ # For each sessionKey, verify the agent-stream file is present. Misses
75
+ # surface as a missing-on-resolve line. The file we just listed must
76
+ # exist by definition; this loop catches the case where a sessionKey was
77
+ # referenced in tee/register emissions on server.log but the file itself
78
+ # was unlinked between the scan and the check (very rare, but visible).
79
+ TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
80
+ for k in "${UNIQUE[@]:-}"; do
81
+ found=0
82
+ for log_dir in "$ACCOUNTS_DIR"/*/logs; do
83
+ if [[ -f "$log_dir/claude-agent-stream-${k}.log" ]]; then
84
+ found=1
85
+ break
86
+ fi
87
+ done
88
+ if [[ $found -eq 0 ]]; then
89
+ MISSES=$((MISSES + 1))
90
+ echo "${TS} [log-tee] missing-on-resolve sessionKey=${k:0:8} surface=adherence-script reason=file-not-on-disk" >> "$SERVER_LOG" 2>/dev/null || true
91
+ fi
92
+ done
93
+
94
+ echo "${TS} [log-tee] adherence-check window=${WINDOW_HOURS}h sessions=${SESSIONS} misses=${MISSES} surface=script ts=${TS}" >> "$SERVER_LOG" 2>/dev/null || true
95
+ echo "[log-adherence-check] sessions=${SESSIONS} misses=${MISSES} window=${WINDOW_HOURS}h"
96
+
97
+ if [[ $MISSES -gt 0 ]]; then
98
+ exit 1
99
+ fi
100
+ exit 0