@rubytech/create-maxy 1.0.884 → 1.0.886
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/neo4j/schema.cypher +7 -0
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +21 -50
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/scripts/__tests__/logs-read-prefix.sh +85 -240
- package/payload/platform/scripts/check-no-conversation-id-leaks.mjs +165 -0
- package/payload/platform/scripts/conversation-id-allowlist.txt +151 -0
- 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/platform/scripts/seed-neo4j.sh +46 -0
- package/payload/premium-plugins/real-agency/BUNDLE.md +1 -1
- package/payload/server/chunk-IFMZ5I3E.js +1460 -0
- package/payload/server/chunk-MOAY7KG2.js +11667 -0
- package/payload/server/chunk-NPKQWE3S.js +1431 -0
- package/payload/server/chunk-ZVO5ASQA.js +11660 -0
- package/payload/server/client-pool-M6NS5G2U.js +34 -0
- package/payload/server/client-pool-QUMX7OUT.js +34 -0
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/server.js +181 -137
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
.docs/agents.md
|
|
2
|
+
.docs/conversation-archive.md
|
|
3
|
+
.docs/deployment.md
|
|
4
|
+
.docs/mcp-servers.md
|
|
5
|
+
.docs/neo4j.md
|
|
6
|
+
.docs/observability.md
|
|
7
|
+
.docs/platform.md
|
|
8
|
+
.docs/web-chat.md
|
|
9
|
+
.docs/whatsapp.md
|
|
10
|
+
platform/lib/graph-mcp/src/index.ts
|
|
11
|
+
platform/lib/graph-trash/src/index.ts
|
|
12
|
+
platform/lib/graph-write/src/__tests__/audit.test.ts
|
|
13
|
+
platform/lib/graph-write/src/audit.ts
|
|
14
|
+
platform/neo4j/schema.cypher
|
|
15
|
+
platform/plugins/admin/PLUGIN.md
|
|
16
|
+
platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh
|
|
17
|
+
platform/plugins/admin/mcp/src/index.ts
|
|
18
|
+
platform/plugins/admin/skills/onboarding/SKILL.md
|
|
19
|
+
platform/plugins/admin/skills/stream-log-review/SKILL.md
|
|
20
|
+
platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md
|
|
21
|
+
platform/plugins/business-assistant/references/profiling.md
|
|
22
|
+
platform/plugins/contacts/mcp/src/index.ts
|
|
23
|
+
platform/plugins/contacts/mcp/src/tools/contact-erase.ts
|
|
24
|
+
platform/plugins/contacts/mcp/src/tools/contact-export.ts
|
|
25
|
+
platform/plugins/contacts/mcp/src/tools/group-create.ts
|
|
26
|
+
platform/plugins/contacts/mcp/src/tools/group-manage.ts
|
|
27
|
+
platform/plugins/docs/references/admin-session.md
|
|
28
|
+
platform/plugins/docs/references/contacts-guide.md
|
|
29
|
+
platform/plugins/docs/references/internals.md
|
|
30
|
+
platform/plugins/docs/references/platform.md
|
|
31
|
+
platform/plugins/docs/references/plugins-guide.md
|
|
32
|
+
platform/plugins/docs/references/troubleshooting.md
|
|
33
|
+
platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md
|
|
34
|
+
platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md
|
|
35
|
+
platform/plugins/memory/bin/conversation-archive-ingest.mjs
|
|
36
|
+
platform/plugins/memory/bin/conversation-archive-ingest.sh
|
|
37
|
+
platform/plugins/memory/mcp/scripts/boot-smoke.sh
|
|
38
|
+
platform/plugins/memory/mcp/scripts/graph/fixture.cypher
|
|
39
|
+
platform/plugins/memory/mcp/src/index.ts
|
|
40
|
+
platform/plugins/memory/mcp/src/lib/graph-prune.ts
|
|
41
|
+
platform/plugins/memory/mcp/src/tools/conversation-archive-derive-insights.ts
|
|
42
|
+
platform/plugins/memory/mcp/src/tools/conversation-archive-enrich-rejection.ts
|
|
43
|
+
platform/plugins/memory/mcp/src/tools/conversation-memory-expunge.ts
|
|
44
|
+
platform/plugins/memory/mcp/src/tools/memory-archive-write.ts
|
|
45
|
+
platform/plugins/memory/mcp/src/tools/memory-find-candidates.ts
|
|
46
|
+
platform/plugins/memory/mcp/src/tools/memory-ingest.ts
|
|
47
|
+
platform/plugins/memory/mcp/src/tools/profile-update.ts
|
|
48
|
+
platform/plugins/memory/references/graph-primitives.md
|
|
49
|
+
platform/plugins/memory/references/schema-base.md
|
|
50
|
+
platform/plugins/memory/skills/conversation-archive/SKILL.md
|
|
51
|
+
platform/plugins/memory/skills/conversational-memory/SKILL.md
|
|
52
|
+
platform/plugins/memory/skills/document-ingest/SKILL.md
|
|
53
|
+
platform/plugins/scheduling/mcp/src/index.ts
|
|
54
|
+
platform/plugins/tasks/.mcp.json
|
|
55
|
+
platform/plugins/tasks/mcp/src/index.ts
|
|
56
|
+
platform/plugins/tasks/mcp/src/tools/project-create.ts
|
|
57
|
+
platform/plugins/tasks/mcp/src/tools/session-list.ts
|
|
58
|
+
platform/plugins/waitlist/mcp/src/index.ts
|
|
59
|
+
platform/plugins/waitlist/mcp/src/tools/__tests__/waitlist-persist.test.ts
|
|
60
|
+
platform/plugins/waitlist/mcp/src/tools/waitlist-heal.ts
|
|
61
|
+
platform/plugins/waitlist/mcp/src/tools/waitlist-list.ts
|
|
62
|
+
platform/plugins/waitlist/mcp/src/tools/waitlist-persist.ts
|
|
63
|
+
platform/plugins/waitlist/mcp/src/tools/waitlist-scan.ts
|
|
64
|
+
platform/plugins/waitlist/mcp/src/tools/waitlist-setup.ts
|
|
65
|
+
platform/plugins/whatsapp/PLUGIN.md
|
|
66
|
+
platform/plugins/whatsapp/mcp/src/index.ts
|
|
67
|
+
platform/plugins/workflows/mcp/src/index.ts
|
|
68
|
+
platform/scripts/__tests__/admin-persist-audit.test.ts
|
|
69
|
+
platform/scripts/admin-conversation-recover.mjs
|
|
70
|
+
platform/scripts/admin-persist-audit.ts
|
|
71
|
+
platform/scripts/check-no-conversation-id-leaks.mjs
|
|
72
|
+
platform/scripts/check-sdk-oauth.mjs
|
|
73
|
+
platform/scripts/component-knowledgedoc-backfill.ts
|
|
74
|
+
platform/scripts/seed-neo4j.sh
|
|
75
|
+
platform/templates/agents/admin/IDENTITY.md
|
|
76
|
+
platform/templates/specialists/agents/database-operator.md
|
|
77
|
+
platform/ui/__tests__/form-spawn-tailer.test.ts
|
|
78
|
+
platform/ui/app/AdminModals.tsx
|
|
79
|
+
platform/ui/app/ChatActionsMenu.tsx
|
|
80
|
+
platform/ui/app/ChatFooter.tsx
|
|
81
|
+
platform/ui/app/ConversationRowActions.tsx
|
|
82
|
+
platform/ui/app/Sidebar.tsx
|
|
83
|
+
platform/ui/app/__tests__/buildSessionLogsUrl.test.ts
|
|
84
|
+
platform/ui/app/admin/components/CloudflareSetupForm.tsx
|
|
85
|
+
platform/ui/app/graph/__tests__/display-helpers.test.ts
|
|
86
|
+
platform/ui/app/graph/__tests__/zoom-tier-colour-stability.test.ts
|
|
87
|
+
platform/ui/app/graph/display-helpers.ts
|
|
88
|
+
platform/ui/app/lib/__tests__/admin-conversation-create.test.ts
|
|
89
|
+
platform/ui/app/lib/__tests__/admin-persist-observability.test.ts
|
|
90
|
+
platform/ui/app/lib/__tests__/claude-agent-loop-stop.test.ts
|
|
91
|
+
platform/ui/app/lib/__tests__/conversation-deferred-persistence.test.ts
|
|
92
|
+
platform/ui/app/lib/__tests__/ensure-conversation-handled-by.test.ts
|
|
93
|
+
platform/ui/app/lib/__tests__/graph-trash-conversation-cascade.test.ts
|
|
94
|
+
platform/ui/app/lib/__tests__/jsonl-replay.test.ts
|
|
95
|
+
platform/ui/app/lib/__tests__/load-user-profile-sparse.test.ts
|
|
96
|
+
platform/ui/app/lib/__tests__/neo4j-store-autolabel.test.ts
|
|
97
|
+
platform/ui/app/lib/__tests__/neo4j-store-persist-message.test.ts
|
|
98
|
+
platform/ui/app/lib/admin-sse-registry.ts
|
|
99
|
+
platform/ui/app/lib/attachments.ts
|
|
100
|
+
platform/ui/app/lib/claude-agent/admin-agent.ts
|
|
101
|
+
platform/ui/app/lib/claude-agent/compaction.ts
|
|
102
|
+
platform/ui/app/lib/claude-agent/dispatcher.ts
|
|
103
|
+
platform/ui/app/lib/claude-agent/jsonl-replay.ts
|
|
104
|
+
platform/ui/app/lib/claude-agent/logging.ts
|
|
105
|
+
platform/ui/app/lib/claude-agent/memory-context.ts
|
|
106
|
+
platform/ui/app/lib/claude-agent/public-agent.ts
|
|
107
|
+
platform/ui/app/lib/claude-agent/session-store.ts
|
|
108
|
+
platform/ui/app/lib/claude-agent/spawn-env.ts
|
|
109
|
+
platform/ui/app/lib/claude-agent/stream-parser.ts
|
|
110
|
+
platform/ui/app/lib/client-event.ts
|
|
111
|
+
platform/ui/app/lib/cloudflare-setup-types.ts
|
|
112
|
+
platform/ui/app/lib/cloudflare-task-tracker.ts
|
|
113
|
+
platform/ui/app/lib/logs-read-resolve.ts
|
|
114
|
+
platform/ui/app/lib/neo4j-store.ts
|
|
115
|
+
platform/ui/app/lib/paths.ts
|
|
116
|
+
platform/ui/app/lib/useConversationRename.ts
|
|
117
|
+
platform/ui/app/lib/useLogsPopover.ts
|
|
118
|
+
platform/ui/app/lib/vnc.ts
|
|
119
|
+
platform/ui/app/lib/whatsapp/__tests__/ensure-conversation.test.ts
|
|
120
|
+
platform/ui/app/lib/whatsapp/__tests__/persist-message.test.ts
|
|
121
|
+
platform/ui/app/lib/whatsapp/ensure-conversation.ts
|
|
122
|
+
platform/ui/app/lib/whatsapp/manager.ts
|
|
123
|
+
platform/ui/app/lib/whatsapp/persist-message.ts
|
|
124
|
+
platform/ui/app/page.tsx
|
|
125
|
+
platform/ui/app/public/MessageList.tsx
|
|
126
|
+
platform/ui/app/public/page.tsx
|
|
127
|
+
platform/ui/app/public/types.ts
|
|
128
|
+
platform/ui/app/public/useSession.ts
|
|
129
|
+
platform/ui/app/useAdminAuth.ts
|
|
130
|
+
platform/ui/app/useAdminChat.ts
|
|
131
|
+
platform/ui/server/index.ts
|
|
132
|
+
platform/ui/server/routes/__tests__/whatsapp-conversation-graph-state.test.ts
|
|
133
|
+
platform/ui/server/routes/_helpers.ts
|
|
134
|
+
platform/ui/server/routes/admin/__tests__/browser-iframe-route.test.ts
|
|
135
|
+
platform/ui/server/routes/admin/__tests__/chat-stream-log-path.test.ts
|
|
136
|
+
platform/ui/server/routes/admin/__tests__/cloudflare-tunnels-zero.test.ts
|
|
137
|
+
platform/ui/server/routes/admin/__tests__/graph-search.test.ts
|
|
138
|
+
platform/ui/server/routes/admin/__tests__/graph-subgraph.test.ts
|
|
139
|
+
platform/ui/server/routes/admin/__tests__/logs.test.ts
|
|
140
|
+
platform/ui/server/routes/admin/__tests__/sessions.test.ts
|
|
141
|
+
platform/ui/server/routes/admin/browser-iframe.ts
|
|
142
|
+
platform/ui/server/routes/admin/chat-failure.ts
|
|
143
|
+
platform/ui/server/routes/admin/chat.ts
|
|
144
|
+
platform/ui/server/routes/admin/cloudflare.ts
|
|
145
|
+
platform/ui/server/routes/admin/graph-subgraph.ts
|
|
146
|
+
platform/ui/server/routes/admin/logs.ts
|
|
147
|
+
platform/ui/server/routes/admin/session.ts
|
|
148
|
+
platform/ui/server/routes/admin/sessions.ts
|
|
149
|
+
platform/ui/server/routes/group.ts
|
|
150
|
+
platform/ui/server/routes/session.ts
|
|
151
|
+
platform/ui/server/routes/whatsapp.ts
|
|
@@ -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
|
|
@@ -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) ---
|