@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.
- package/package.json +1 -1
- package/payload/platform/lib/graph-mcp/dist/index.js +45 -0
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +47 -0
- package/payload/platform/lib/mcp-eager/dist/index.d.ts +61 -0
- package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/mcp-eager/dist/index.js +49 -0
- package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -0
- package/payload/platform/lib/mcp-eager/src/index.ts +78 -0
- package/payload/platform/lib/mcp-eager/tsconfig.json +8 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +48 -76
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/index.js +10 -9
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/docs/references/internals.md +13 -0
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/plugins/email/mcp/dist/index.js +10 -9
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +9 -8
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +9 -8
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/tasks/mcp/dist/index.js +15 -14
- package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/index.js +4 -3
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/index.js +9 -8
- package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
- package/payload/platform/scripts/__tests__/logs-read-prefix.sh +85 -240
- package/payload/platform/scripts/log-adherence-check.sh +100 -0
- package/payload/platform/scripts/logs-read.sh +71 -141
- package/payload/platform/scripts/logs-read.test.sh +47 -104
- package/payload/premium-plugins/real-agency/BUNDLE.md +1 -1
- package/payload/server/chunk-5PQU2HW2.js +11672 -0
- package/payload/server/chunk-NPKQWE3S.js +1431 -0
- package/payload/server/chunk-ZVO5ASQA.js +11660 -0
- package/payload/server/client-pool-QUMX7OUT.js +34 -0
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/server.js +123 -121
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# logs-read.sh — Shell counterpart to the logs-read MCP tool.
|
|
3
3
|
#
|
|
4
|
-
# Task
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# [process-exit] without
|
|
8
|
-
#
|
|
9
|
-
# Task 671: first-turn sessions (pre 1→2-user-turn flush per Task 650) land
|
|
10
|
-
# at {prefix}preflush-{sessionKey:0:12}.log. The per-conversation mode
|
|
11
|
-
# resolves either shape from the same identifier — full first, preflush as
|
|
12
|
-
# fallback.
|
|
4
|
+
# Task 1006: stream logs are per-session, not per-day or per-conversation.
|
|
5
|
+
# The primary mode reads a single {prefix}-{sessionKey}.log file — the
|
|
6
|
+
# operator types a sessionKey prefix and the surface returns the bytes from
|
|
7
|
+
# first [spawn] to final [process-exit] without filtering. sessionKey is
|
|
8
|
+
# the single identifier on disk; the earlier full vs preflush split is gone.
|
|
13
9
|
#
|
|
14
10
|
# Modes:
|
|
15
|
-
# logs-read.sh <
|
|
16
|
-
# logs-read.sh --tail [type] [lines]
|
|
17
|
-
# logs-read.sh --grep <sessionKey> [type]
|
|
11
|
+
# logs-read.sh <sessionKey-or-prefix> [type] Read {prefix}-{sessionKey}.log
|
|
12
|
+
# logs-read.sh --tail [type] [lines] Tail most recent file of type
|
|
13
|
+
# logs-read.sh --grep <sessionKey> [type] Legacy grep across log files
|
|
18
14
|
#
|
|
19
|
-
# Types: agent-stream (canonical, per-
|
|
15
|
+
# Types: agent-stream (canonical, per-session tool-use/tool-result archive;
|
|
20
16
|
# `system` is kept as a backwards-compatible alias), session, error,
|
|
21
17
|
# heartbeat, public, server, mcp, vnc
|
|
22
|
-
# For per-
|
|
23
|
-
# required in the first mode. For platform-scoped types (server/vnc/
|
|
24
|
-
#
|
|
18
|
+
# For per-session types (agent-stream/system/session/error/public): sessionKey
|
|
19
|
+
# is required in the first mode. For platform-scoped types (server/vnc/
|
|
20
|
+
# heartbeat): the id is ignored.
|
|
25
21
|
#
|
|
26
22
|
# Every invocation writes a one-line trailer describing files searched,
|
|
27
23
|
# matches returned, and files rejected — empty output never leaves a reader
|
|
28
|
-
# guessing why.
|
|
24
|
+
# guessing why. On a miss the script appends a one-line
|
|
25
|
+
# `[log-tee] missing-on-resolve sessionKey=<8> surface=logs-read-sh
|
|
26
|
+
# reason=...` entry to server.log so the writer-side existence contract is
|
|
27
|
+
# the authoritative signal.
|
|
29
28
|
#
|
|
30
29
|
# Exit codes:
|
|
31
30
|
# 0 Success (output produced)
|
|
@@ -122,16 +121,16 @@ VALID_TYPES="agent-stream, system, session, error, heartbeat, public, server, mc
|
|
|
122
121
|
usage() {
|
|
123
122
|
cat >&2 <<EOF
|
|
124
123
|
Usage:
|
|
125
|
-
logs-read.sh <
|
|
126
|
-
logs-read.sh --tail [type] [lines]
|
|
127
|
-
logs-read.sh --grep <sessionKey> [type]
|
|
124
|
+
logs-read.sh <sessionKey-or-prefix> [type] Read {prefix}-{sessionKey}.log
|
|
125
|
+
logs-read.sh --tail [type] [lines] Tail most recent log of type
|
|
126
|
+
logs-read.sh --grep <sessionKey> [type] Legacy grep across log files
|
|
128
127
|
|
|
129
128
|
Types: $VALID_TYPES
|
|
130
129
|
Default type: agent-stream | Default lines: 50
|
|
131
130
|
|
|
132
|
-
Per-
|
|
133
|
-
in the first mode — the log file is named {prefix}-{
|
|
134
|
-
Platform-scoped types (server, vnc, heartbeat) ignore
|
|
131
|
+
Per-session types (agent-stream, system, session, error, public) require
|
|
132
|
+
sessionKey in the first mode — the log file is named {prefix}-{sessionKey}.log.
|
|
133
|
+
Platform-scoped types (server, vnc, heartbeat) ignore the id.
|
|
135
134
|
EOF
|
|
136
135
|
exit 2
|
|
137
136
|
}
|
|
@@ -144,65 +143,48 @@ validate_type() {
|
|
|
144
143
|
esac
|
|
145
144
|
}
|
|
146
145
|
|
|
147
|
-
# --- Per-
|
|
146
|
+
# --- Per-session mode: prefix-match {prefix}{sessionKey-prefix}*.log ---
|
|
148
147
|
#
|
|
149
|
-
# Task
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
#
|
|
148
|
+
# Task 1006 — one filename shape per session: {prefix}{sessionKey}.log.
|
|
149
|
+
# The operator types an 8-char-or-greater sessionKey prefix; we glob
|
|
150
|
+
# `${prefix}${session_key}*.log` across every account log dir. The earlier
|
|
151
|
+
# full vs preflush two-shape contract is gone: sessionKey is the single
|
|
152
|
+
# identifier on disk, mounted from turn 1.
|
|
153
153
|
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
# zero hits → exit 1 + reason=file-not-found-in-either-shape (existing miss)
|
|
154
|
+
# Three trailer outcomes:
|
|
155
|
+
# single hit → exit 0 (success)
|
|
156
|
+
# zero hits → exit 1 + appends `[log-tee] missing-on-resolve sessionKey=<8>
|
|
157
|
+
# surface=logs-read-sh reason=...` to server.log so
|
|
158
|
+
# the writer-side existence contract is the
|
|
159
|
+
# authoritative signal.
|
|
161
160
|
# 2+ hits → exit 1 + reason=ambiguous-prefix candidates=[...]; never picks
|
|
162
161
|
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
# server.log is unwritable.
|
|
167
|
-
#
|
|
168
|
-
# Identity note: the preflush fallback exists for the abrupt-exit case where
|
|
169
|
-
# the operator passes the sessionKey (no conversationId was ever assigned).
|
|
170
|
-
# For post-flush retrievals the operator passes the conversationId (or any
|
|
171
|
-
# unambiguous prefix of it) and the FULL file is expected to exist.
|
|
172
|
-
#
|
|
173
|
-
# MIRROR — intentional divergence (Task 998):
|
|
174
|
-
# - platform/ui/app/lib/logs-read-resolve.ts (canonical TS helper) —
|
|
175
|
-
# EXACT-MATCH on `${prefix}${conversationId}.log`.
|
|
176
|
-
# - platform/plugins/admin/mcp/src/index.ts (conversationId branch) —
|
|
177
|
-
# EXACT-MATCH, same shape.
|
|
178
|
-
# Both serve agents that always hold the full conversationId. This shell
|
|
179
|
-
# counterpart is the operator surface; operators read 8-char ids from agent
|
|
180
|
-
# lines and type them at the SSH prompt. Do not "fix" the divergence by
|
|
181
|
-
# adding prefix-match to TS/MCP — it would mask agent bugs that pass
|
|
182
|
-
# partial ids.
|
|
162
|
+
# MIRROR — keep these three sites in lockstep:
|
|
163
|
+
# - platform/ui/app/lib/logs-read-resolve.ts (TS helper, exact-match)
|
|
164
|
+
# - platform/plugins/admin/mcp/src/index.ts (MCP tool, exact-match)
|
|
183
165
|
per_conversation_mode() {
|
|
184
|
-
local
|
|
166
|
+
local session_key="$1"
|
|
185
167
|
local filter_type="${2:-agent-stream}"
|
|
186
168
|
|
|
187
|
-
if [[ -z "$
|
|
188
|
-
echo "Error:
|
|
169
|
+
if [[ -z "$session_key" ]]; then
|
|
170
|
+
echo "Error: sessionKey cannot be empty" >&2
|
|
189
171
|
exit 2
|
|
190
172
|
fi
|
|
191
173
|
|
|
192
|
-
# Reject shell metacharacters in
|
|
193
|
-
# would otherwise turn user input into a shell pattern.
|
|
194
|
-
#
|
|
195
|
-
if [[ ! "$
|
|
196
|
-
echo "Error:
|
|
174
|
+
# Reject shell metacharacters in session_key — the prefix-match glob below
|
|
175
|
+
# would otherwise turn user input into a shell pattern. SessionKeys only
|
|
176
|
+
# contain [a-zA-Z0-9-].
|
|
177
|
+
if [[ ! "$session_key" =~ ^[a-zA-Z0-9-]+$ ]]; then
|
|
178
|
+
echo "Error: sessionKey contains invalid characters (allowed: a-z, A-Z, 0-9, -)" >&2
|
|
197
179
|
exit 2
|
|
198
180
|
fi
|
|
199
181
|
|
|
200
182
|
validate_type "$filter_type"
|
|
201
183
|
|
|
202
|
-
# Platform-scoped types shortcut to their fixed files regardless of
|
|
184
|
+
# Platform-scoped types shortcut to their fixed files regardless of id.
|
|
203
185
|
case "$filter_type" in
|
|
204
186
|
server|vnc|heartbeat|mcp)
|
|
205
|
-
echo "# note: type=$filter_type is platform-scoped;
|
|
187
|
+
echo "# note: type=$filter_type is platform-scoped; sessionKey ignored — showing fixed file" >&2
|
|
206
188
|
tail_mode "$filter_type" "50"
|
|
207
189
|
return
|
|
208
190
|
;;
|
|
@@ -215,103 +197,51 @@ per_conversation_mode() {
|
|
|
215
197
|
exit 2
|
|
216
198
|
fi
|
|
217
199
|
|
|
218
|
-
|
|
219
|
-
local full_glob="${prefix}${conv_id}*.log"
|
|
220
|
-
local preflush_glob="${prefix}preflush-${conv_id:0:12}*.log"
|
|
221
|
-
|
|
200
|
+
local glob="${prefix}${session_key}*.log"
|
|
222
201
|
local searched=0
|
|
223
|
-
local matched_shape=""
|
|
224
202
|
|
|
225
|
-
|
|
226
|
-
local -a
|
|
227
|
-
local -a full_dirs=()
|
|
203
|
+
local -a hits=()
|
|
204
|
+
local -a hit_dirs=()
|
|
228
205
|
shopt -s nullglob
|
|
229
206
|
for log_dir in "${ACCOUNT_LOG_DIRS[@]}"; do
|
|
230
207
|
searched=$((searched + 1))
|
|
231
|
-
for f in "$log_dir"/${prefix}${
|
|
232
|
-
|
|
233
|
-
|
|
208
|
+
for f in "$log_dir"/${prefix}${session_key}*.log; do
|
|
209
|
+
hits+=("$f")
|
|
210
|
+
hit_dirs+=("$log_dir")
|
|
234
211
|
done
|
|
235
212
|
done
|
|
236
213
|
shopt -u nullglob
|
|
237
214
|
|
|
238
|
-
#
|
|
239
|
-
if [[ ${#full_hits[@]} -gt 1 ]]; then
|
|
215
|
+
if [[ ${#hits[@]} -gt 1 ]]; then
|
|
240
216
|
local -a candidate_names=()
|
|
241
217
|
local cf
|
|
242
|
-
for cf in "${
|
|
218
|
+
for cf in "${hits[@]}"; do
|
|
243
219
|
candidate_names+=("$(basename "$cf")")
|
|
244
220
|
done
|
|
245
221
|
local joined
|
|
246
222
|
joined=$(IFS=','; printf '%s' "${candidate_names[*]}")
|
|
247
|
-
echo "-- trailer:
|
|
223
|
+
echo "-- trailer: sessionKey=$session_key type=$filter_type searched=$searched matches=${#hits[@]} reason=ambiguous-prefix candidates=[${joined}]" >&2
|
|
248
224
|
exit 1
|
|
249
225
|
fi
|
|
250
226
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
echo "
|
|
258
|
-
|
|
259
|
-
found=1
|
|
260
|
-
matched_shape="full"
|
|
261
|
-
|
|
262
|
-
shopt -s nullglob
|
|
263
|
-
local stale_path
|
|
264
|
-
for stale_path in "$match_dir"/${prefix}preflush-${conv_id:0:12}*.log; do
|
|
265
|
-
local stale_ts
|
|
266
|
-
stale_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
267
|
-
echo "${stale_ts} [logs-read] stale-preflush-detected path=${stale_path}" >> "$SERVER_LOG" 2>/dev/null || true
|
|
268
|
-
done
|
|
269
|
-
shopt -u nullglob
|
|
227
|
+
if [[ ${#hits[@]} -eq 1 ]]; then
|
|
228
|
+
local hit_path="${hits[0]}"
|
|
229
|
+
local match_dir="${hit_dirs[0]}"
|
|
230
|
+
echo "## $(basename "$hit_path") ($filter_type)$(account_suffix "$match_dir")"
|
|
231
|
+
cat "$hit_path"
|
|
232
|
+
echo "" >&2
|
|
233
|
+
echo "-- trailer: sessionKey=$session_key type=$filter_type searched=$searched matched=1" >&2
|
|
234
|
+
exit 0
|
|
270
235
|
fi
|
|
271
236
|
|
|
272
|
-
#
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
for log_dir in "${ACCOUNT_LOG_DIRS[@]}"; do
|
|
278
|
-
searched=$((searched + 1))
|
|
279
|
-
for f in "$log_dir"/${prefix}preflush-${conv_id:0:12}*.log; do
|
|
280
|
-
preflush_hits+=("$f")
|
|
281
|
-
preflush_dirs+=("$log_dir")
|
|
282
|
-
done
|
|
283
|
-
done
|
|
284
|
-
shopt -u nullglob
|
|
285
|
-
|
|
286
|
-
if [[ ${#preflush_hits[@]} -gt 1 ]]; then
|
|
287
|
-
local -a candidate_names=()
|
|
288
|
-
local pf
|
|
289
|
-
for pf in "${preflush_hits[@]}"; do
|
|
290
|
-
candidate_names+=("$(basename "$pf")")
|
|
291
|
-
done
|
|
292
|
-
local joined
|
|
293
|
-
joined=$(IFS=','; printf '%s' "${candidate_names[*]}")
|
|
294
|
-
echo "-- trailer: conversationId=$conv_id type=$filter_type searched=$searched matches=${#preflush_hits[@]} reason=ambiguous-prefix candidates=[${joined}]" >&2
|
|
295
|
-
exit 1
|
|
296
|
-
fi
|
|
237
|
+
# Task 1006 — missing-on-resolve emission. Best-effort; never fails the
|
|
238
|
+
# invocation when server.log is unwritable.
|
|
239
|
+
local miss_ts
|
|
240
|
+
miss_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
241
|
+
echo "${miss_ts} [log-tee] missing-on-resolve sessionKey=${session_key:0:8} surface=logs-read-sh reason=\"file-not-found type=${filter_type}\"" >> "$SERVER_LOG" 2>/dev/null || true
|
|
297
242
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
echo "## $(basename "$preflush_path") ($filter_type)$(account_suffix "${preflush_dirs[0]}")"
|
|
301
|
-
cat "$preflush_path"
|
|
302
|
-
found=1
|
|
303
|
-
matched_shape="preflush"
|
|
304
|
-
fi
|
|
305
|
-
fi
|
|
306
|
-
|
|
307
|
-
# Trailer: empty output never leaves the reader guessing why.
|
|
308
|
-
if [[ $found -eq 0 ]]; then
|
|
309
|
-
echo "-- trailer: conversationId=$conv_id type=$filter_type searched=$searched found=0 tried=[${full_glob}, ${preflush_glob}] reason=file-not-found-in-either-shape" >&2
|
|
310
|
-
exit 1
|
|
311
|
-
fi
|
|
312
|
-
echo "" >&2
|
|
313
|
-
echo "-- trailer: conversationId=$conv_id type=$filter_type searched=$searched matched=$found matched_shape=$matched_shape" >&2
|
|
314
|
-
exit 0
|
|
243
|
+
echo "-- trailer: sessionKey=$session_key type=$filter_type searched=$searched found=0 tried=[${glob}] reason=file-not-found" >&2
|
|
244
|
+
exit 1
|
|
315
245
|
}
|
|
316
246
|
|
|
317
247
|
# --- Legacy grep mode (backward compatibility with sessionKey-tagged lines) ---
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Task
|
|
2
|
+
# Task 1006 — bash harness for logs-read.sh single-shape resolution.
|
|
3
3
|
#
|
|
4
|
-
# Covers the
|
|
5
|
-
# 1.
|
|
6
|
-
# 2.
|
|
7
|
-
# 3.
|
|
8
|
-
# 4. Both present (promotion race) → full wins + stale-preflush signal to server.log
|
|
4
|
+
# Covers the three cases the new contract demands:
|
|
5
|
+
# 1. sessionKey-named file present → bytes returned, exit 0.
|
|
6
|
+
# 2. No file → exit 1 + missing-on-resolve appended to server.log.
|
|
7
|
+
# 3. Ambiguous prefix (multiple matches) → exit 1, never picks silently.
|
|
9
8
|
#
|
|
10
9
|
# MIRROR: see platform/ui/app/lib/logs-read-resolve.ts for the canonical
|
|
11
|
-
#
|
|
10
|
+
# single-shape contract and its TS unit tests.
|
|
12
11
|
set -euo pipefail
|
|
13
12
|
|
|
14
13
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
@@ -18,28 +17,17 @@ if [[ ! -x "$LOGS_READ" ]]; then
|
|
|
18
17
|
exit 1
|
|
19
18
|
fi
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
FULL_NAME="claude-agent-stream-${CONV_ID}.log"
|
|
24
|
-
PREFLUSH_NAME="claude-agent-stream-preflush-${PREFLUSH_SLICE}.log"
|
|
25
|
-
# Task 998 — miss trailer now lists glob patterns, not literal filenames,
|
|
26
|
-
# because Pass 1 / Pass 2 prefix-glob `${prefix}${conv_id}*.log`.
|
|
27
|
-
FULL_GLOB="claude-agent-stream-${CONV_ID}*.log"
|
|
28
|
-
PREFLUSH_GLOB="claude-agent-stream-preflush-${PREFLUSH_SLICE}*.log"
|
|
20
|
+
SESSION_KEY="8c264cfb-441f-48bf-9811-9fa3ad3b51dc"
|
|
21
|
+
FILE_NAME="claude-agent-stream-${SESSION_KEY}.log"
|
|
29
22
|
|
|
30
23
|
PASS=0
|
|
31
24
|
FAIL=0
|
|
32
25
|
|
|
33
|
-
# logs-read.sh resolves PLATFORM_ROOT from the script location, and uses
|
|
34
|
-
# INSTALL_DIR = $PLATFORM_ROOT/.. and ACCOUNTS_DIR = $INSTALL_DIR/data/accounts.
|
|
35
|
-
# The test creates a fake install tree with the real script symlinked in.
|
|
36
26
|
setup_install_tree() {
|
|
37
27
|
local root="$1"
|
|
38
28
|
mkdir -p "$root/platform/scripts"
|
|
39
29
|
mkdir -p "$root/data/accounts/acct-test/logs"
|
|
40
30
|
mkdir -p "$HOME/.$(basename "$root")/logs"
|
|
41
|
-
# Symlink the script under test into the fake tree so PLATFORM_ROOT resolves
|
|
42
|
-
# to $root/platform and the account logs are discovered.
|
|
43
31
|
ln -sf "$LOGS_READ" "$root/platform/scripts/logs-read.sh"
|
|
44
32
|
echo "$root/platform/scripts/logs-read.sh"
|
|
45
33
|
}
|
|
@@ -50,8 +38,6 @@ cleanup_install_tree() {
|
|
|
50
38
|
rm -rf "$HOME/.$(basename "$root")"
|
|
51
39
|
}
|
|
52
40
|
|
|
53
|
-
# Each case uses its own ephemeral install tree. Install-tree basename is
|
|
54
|
-
# unique so configDir (~/.{installDir}) does not collide.
|
|
55
41
|
run_case() {
|
|
56
42
|
local name="$1"
|
|
57
43
|
shift
|
|
@@ -66,16 +52,16 @@ run_case() {
|
|
|
66
52
|
fi
|
|
67
53
|
}
|
|
68
54
|
|
|
69
|
-
# --- Case 1:
|
|
70
|
-
|
|
55
|
+
# --- Case 1: sessionKey-named file present → exit 0 ---
|
|
56
|
+
case_file_present() {
|
|
71
57
|
local root="/tmp/maxy-logs-read-test-1-$$"
|
|
72
58
|
local script
|
|
73
59
|
script=$(setup_install_tree "$root")
|
|
74
60
|
local logdir="$root/data/accounts/acct-test/logs"
|
|
75
|
-
echo "
|
|
61
|
+
echo "sessionkey-content-sentinel" > "$logdir/$FILE_NAME"
|
|
76
62
|
|
|
77
63
|
local stdout stderr rc
|
|
78
|
-
stdout=$("$script" "$
|
|
64
|
+
stdout=$("$script" "$SESSION_KEY" system 2>/tmp/maxy-logs-read-stderr-1-$$) || rc=$?
|
|
79
65
|
rc=${rc:-0}
|
|
80
66
|
stderr=$(cat /tmp/maxy-logs-read-stderr-1-$$)
|
|
81
67
|
rm -f /tmp/maxy-logs-read-stderr-1-$$
|
|
@@ -86,56 +72,66 @@ case_full_only() {
|
|
|
86
72
|
echo " expected exit 0, got $rc"
|
|
87
73
|
return 1
|
|
88
74
|
fi
|
|
89
|
-
if [[ "$stdout" != *"
|
|
75
|
+
if [[ "$stdout" != *"sessionkey-content-sentinel"* ]]; then
|
|
90
76
|
echo " stdout missing sentinel"
|
|
91
77
|
return 1
|
|
92
78
|
fi
|
|
93
|
-
if [[ "$stderr" != *"
|
|
94
|
-
echo " stderr missing
|
|
79
|
+
if [[ "$stderr" != *"matched=1"* ]]; then
|
|
80
|
+
echo " stderr missing matched=1: $stderr"
|
|
95
81
|
return 1
|
|
96
82
|
fi
|
|
97
83
|
return 0
|
|
98
84
|
}
|
|
99
85
|
|
|
100
|
-
# --- Case 2:
|
|
101
|
-
|
|
86
|
+
# --- Case 2: no file → exit 1 + missing-on-resolve in server.log ---
|
|
87
|
+
case_missing() {
|
|
102
88
|
local root="/tmp/maxy-logs-read-test-2-$$"
|
|
103
89
|
local script
|
|
104
90
|
script=$(setup_install_tree "$root")
|
|
105
|
-
local
|
|
106
|
-
|
|
91
|
+
local server_log="$HOME/.$(basename "$root")/logs/server.log"
|
|
92
|
+
: > "$server_log"
|
|
107
93
|
|
|
108
|
-
local
|
|
109
|
-
|
|
110
|
-
|
|
94
|
+
local rc=0
|
|
95
|
+
"$script" "$SESSION_KEY" system >/dev/null 2>/tmp/maxy-logs-read-stderr-2-$$ || rc=$?
|
|
96
|
+
local stderr
|
|
111
97
|
stderr=$(cat /tmp/maxy-logs-read-stderr-2-$$)
|
|
112
98
|
rm -f /tmp/maxy-logs-read-stderr-2-$$
|
|
99
|
+
local server_log_contents
|
|
100
|
+
server_log_contents=$(cat "$server_log" 2>/dev/null || echo "")
|
|
113
101
|
|
|
114
102
|
cleanup_install_tree "$root"
|
|
115
103
|
|
|
116
|
-
if [[ $rc -ne
|
|
117
|
-
echo " expected exit
|
|
104
|
+
if [[ $rc -ne 1 ]]; then
|
|
105
|
+
echo " expected exit 1, got $rc"
|
|
118
106
|
return 1
|
|
119
107
|
fi
|
|
120
|
-
if [[ "$
|
|
121
|
-
echo "
|
|
108
|
+
if [[ "$stderr" != *"reason=file-not-found"* ]]; then
|
|
109
|
+
echo " stderr missing reason=file-not-found: $stderr"
|
|
122
110
|
return 1
|
|
123
111
|
fi
|
|
124
|
-
if [[ "$
|
|
125
|
-
echo "
|
|
112
|
+
if [[ "$server_log_contents" != *"missing-on-resolve"* ]]; then
|
|
113
|
+
echo " server.log missing missing-on-resolve emission: $server_log_contents"
|
|
114
|
+
return 1
|
|
115
|
+
fi
|
|
116
|
+
if [[ "$server_log_contents" != *"surface=logs-read-sh"* ]]; then
|
|
117
|
+
echo " server.log emission missing surface tag"
|
|
126
118
|
return 1
|
|
127
119
|
fi
|
|
128
120
|
return 0
|
|
129
121
|
}
|
|
130
122
|
|
|
131
|
-
# --- Case 3:
|
|
132
|
-
|
|
123
|
+
# --- Case 3: ambiguous prefix → exit 1 without picking ---
|
|
124
|
+
case_ambiguous() {
|
|
133
125
|
local root="/tmp/maxy-logs-read-test-3-$$"
|
|
134
126
|
local script
|
|
135
127
|
script=$(setup_install_tree "$root")
|
|
128
|
+
local logdir="$root/data/accounts/acct-test/logs"
|
|
129
|
+
echo "a" > "$logdir/claude-agent-stream-deadbeef-aaaa.log"
|
|
130
|
+
echo "b" > "$logdir/claude-agent-stream-deadbeef-bbbb.log"
|
|
136
131
|
|
|
137
|
-
local
|
|
138
|
-
|
|
132
|
+
local rc=0
|
|
133
|
+
"$script" "deadbeef" system >/dev/null 2>/tmp/maxy-logs-read-stderr-3-$$ || rc=$?
|
|
134
|
+
local stderr
|
|
139
135
|
stderr=$(cat /tmp/maxy-logs-read-stderr-3-$$)
|
|
140
136
|
rm -f /tmp/maxy-logs-read-stderr-3-$$
|
|
141
137
|
|
|
@@ -145,69 +141,16 @@ case_neither() {
|
|
|
145
141
|
echo " expected exit 1, got $rc"
|
|
146
142
|
return 1
|
|
147
143
|
fi
|
|
148
|
-
if [[ "$stderr" != *"
|
|
149
|
-
echo " stderr missing
|
|
150
|
-
return 1
|
|
151
|
-
fi
|
|
152
|
-
if [[ "$stderr" != *"reason=file-not-found-in-either-shape"* ]]; then
|
|
153
|
-
echo " stderr missing reason=file-not-found-in-either-shape: $stderr"
|
|
154
|
-
return 1
|
|
155
|
-
fi
|
|
156
|
-
return 0
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
# --- Case 4: both present (promotion race) → full wins + stale signal ---
|
|
160
|
-
case_both_present() {
|
|
161
|
-
local root="/tmp/maxy-logs-read-test-4-$$"
|
|
162
|
-
local script
|
|
163
|
-
script=$(setup_install_tree "$root")
|
|
164
|
-
local logdir="$root/data/accounts/acct-test/logs"
|
|
165
|
-
echo "full-content-sentinel-4" > "$logdir/$FULL_NAME"
|
|
166
|
-
echo "preflush-content-sentinel-4" > "$logdir/$PREFLUSH_NAME"
|
|
167
|
-
local server_log="$HOME/.$(basename "$root")/logs/server.log"
|
|
168
|
-
: > "$server_log"
|
|
169
|
-
|
|
170
|
-
local stdout stderr rc=0
|
|
171
|
-
stdout=$("$script" "$CONV_ID" system 2>/tmp/maxy-logs-read-stderr-4-$$) || rc=$?
|
|
172
|
-
stderr=$(cat /tmp/maxy-logs-read-stderr-4-$$)
|
|
173
|
-
rm -f /tmp/maxy-logs-read-stderr-4-$$
|
|
174
|
-
|
|
175
|
-
local server_log_contents
|
|
176
|
-
server_log_contents=$(cat "$server_log" 2>/dev/null || echo "")
|
|
177
|
-
|
|
178
|
-
cleanup_install_tree "$root"
|
|
179
|
-
|
|
180
|
-
if [[ $rc -ne 0 ]]; then
|
|
181
|
-
echo " expected exit 0, got $rc"
|
|
182
|
-
return 1
|
|
183
|
-
fi
|
|
184
|
-
if [[ "$stdout" != *"full-content-sentinel-4"* ]]; then
|
|
185
|
-
echo " stdout missing full sentinel (full must win): $stdout"
|
|
186
|
-
return 1
|
|
187
|
-
fi
|
|
188
|
-
if [[ "$stdout" == *"preflush-content-sentinel-4"* ]]; then
|
|
189
|
-
echo " stdout contained preflush sentinel — preflush must be ignored when full exists"
|
|
190
|
-
return 1
|
|
191
|
-
fi
|
|
192
|
-
if [[ "$stderr" != *"matched_shape=full"* ]]; then
|
|
193
|
-
echo " stderr missing matched_shape=full"
|
|
194
|
-
return 1
|
|
195
|
-
fi
|
|
196
|
-
if [[ "$server_log_contents" != *"stale-preflush-detected"* ]]; then
|
|
197
|
-
echo " server.log missing stale-preflush-detected signal: $server_log_contents"
|
|
198
|
-
return 1
|
|
199
|
-
fi
|
|
200
|
-
if [[ "$server_log_contents" != *"$PREFLUSH_NAME"* ]]; then
|
|
201
|
-
echo " server.log stale signal missing preflush path"
|
|
144
|
+
if [[ "$stderr" != *"reason=ambiguous-prefix"* ]]; then
|
|
145
|
+
echo " stderr missing ambiguous-prefix trailer: $stderr"
|
|
202
146
|
return 1
|
|
203
147
|
fi
|
|
204
148
|
return 0
|
|
205
149
|
}
|
|
206
150
|
|
|
207
|
-
run_case "
|
|
208
|
-
run_case "
|
|
209
|
-
run_case "
|
|
210
|
-
run_case "both present → full wins + stale signal" case_both_present
|
|
151
|
+
run_case "sessionKey file present → exit 0" case_file_present
|
|
152
|
+
run_case "no file → exit 1 + missing-on-resolve" case_missing
|
|
153
|
+
run_case "ambiguous prefix → exit 1, refuses to pick" case_ambiguous
|
|
211
154
|
|
|
212
155
|
echo ""
|
|
213
156
|
echo "================================================"
|
|
@@ -17,7 +17,7 @@ plugins:
|
|
|
17
17
|
|
|
18
18
|
# Real Agency
|
|
19
19
|
|
|
20
|
-
Premium plugin bundle for UK estate agency professionals. Purchasing this bundle grants access to all 11 sub-plugins, each independently activatable via `enabledPlugins`.
|
|
20
|
+
Premium plugin bundle for UK estate agency professionals. Purchasing this bundle grants access to all 11 sub-plugins, each independently activatable via `enabledPlugins`. Every admin boot reconciles `account.json` `enabledPlugins` against on-disk presence: any sub-plugin from the `plugins:` list above whose `platform/plugins/<sub>/PLUGIN.md` exists gets stamped via an idempotent set-union, so `mcp__loop__*` tools and the other sub-plugin surfaces are visible to the admin agent from the first turn after install — and on first boot post-deploy for accounts that already had the bundle on disk from a prior install. Disable individual sub-plugins with `plugin-toggle-enabled`. The bundle also delivers three specialist roles (negotiator, valuer, and compliance) that embed domain knowledge from the sub-plugins and operate autonomously with Loop CRM tools.
|
|
21
21
|
|
|
22
22
|
## Specialist Roles
|
|
23
23
|
|