@rubytech/create-maxy 1.0.495 → 1.0.497
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/config/brand.json +1 -1
- package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +3 -1
- package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +28 -0
- package/payload/platform/templates/agents/admin/IDENTITY.md +3 -1
- package/payload/server/public/brand-constants.json +1 -1
- package/payload/server/server.js +21 -0
package/package.json
CHANGED
|
@@ -33,13 +33,15 @@ Analyse Claude agent stream logs — the `claude-agent-stream-*.log` files gener
|
|
|
33
33
|
On the Pi, use the `logs-read` MCP tool to retrieve logs. From the dev machine (SSH), use the shell counterpart:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
# Retrieve session timeline (all log types)
|
|
36
|
+
# Retrieve session timeline (all log types) — sessionKey is the handle
|
|
37
37
|
sshpass -p 'password' ssh admin@maxy.local "~/maxy/platform/scripts/logs-read.sh <sessionKey>"
|
|
38
38
|
|
|
39
39
|
# Tail the most recent stream log
|
|
40
40
|
sshpass -p 'password' ssh admin@maxy.local "~/maxy/platform/scripts/logs-read.sh --tail system 200"
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
To go from a `conversationId` (visible in the admin UI) to a `sessionKey` (the log filter handle), see the **Conversation Identification** section in `references/analysis-patterns.md`.
|
|
44
|
+
|
|
43
45
|
## Boundaries
|
|
44
46
|
|
|
45
47
|
- This skill analyses logs. It does not fix the bugs it finds — that's a separate task.
|
package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md
CHANGED
|
@@ -50,6 +50,34 @@ Each session begins with a `[managed-spawn]` line and ends with either:
|
|
|
50
50
|
|
|
51
51
|
Extract `sessionKey` from `managed-spawn` and `session_id` from the `result` JSON.
|
|
52
52
|
|
|
53
|
+
## Conversation Identification
|
|
54
|
+
|
|
55
|
+
Three independent identifiers trace a conversation through the system:
|
|
56
|
+
|
|
57
|
+
| Identifier | Scope | Where it lives | Survives restart |
|
|
58
|
+
|------------|-------|-----------------|-----------------|
|
|
59
|
+
| `sessionKey` | Single agent process lifetime | Server memory, stream logs (`sessionKey=XXXXXXXX…`) | No |
|
|
60
|
+
| `conversationId` | Entire conversation (may span multiple sessionKeys) | Neo4j `Conversation` node, stream logs on resume/attribution | Yes |
|
|
61
|
+
| `visitorId` (public) / `userId` (admin) | Visitor or admin identity across conversations | `maxy_visitor` cookie (public), users.json (admin) | Yes |
|
|
62
|
+
|
|
63
|
+
### Finding the right session in logs
|
|
64
|
+
|
|
65
|
+
**From the admin UI**: The sessions modal and Claude info panel both display the first 8 characters of `conversationId`. Use `logs-read` with the corresponding `sessionKey` to pull the full timeline.
|
|
66
|
+
|
|
67
|
+
**From a conversationId**: The stream log lines that link `conversationId` to `sessionKey` are:
|
|
68
|
+
- `[session] conversation attributed: conversationId=XXXX… userId=… admin/…` (new sessions)
|
|
69
|
+
- `[session-resume] updated conversationId to XXXX… for session YYYY…` (resumed sessions)
|
|
70
|
+
- `[session] cold-resume visitor=XXXX… conversation=YYYY…` (public cold resume)
|
|
71
|
+
|
|
72
|
+
**From a visitorId**: Query Neo4j to find all conversations for a visitor, then trace the `sessionKey` into logs:
|
|
73
|
+
```cypher
|
|
74
|
+
MATCH (c:Conversation {visitorId: $visitorId, accountId: $accountId})
|
|
75
|
+
RETURN c.conversationId, c.sessionKey, c.createdAt
|
|
76
|
+
ORDER BY c.createdAt DESC
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Public agent sessions** use `[public-managed-spawn]` and `[public-managed-append]` tags instead of `[managed-spawn]` / `[managed-append]`. The `sessionKey` field is present in both.
|
|
80
|
+
|
|
53
81
|
## Error Classification
|
|
54
82
|
|
|
55
83
|
### Severity: ERROR
|
|
@@ -98,7 +98,9 @@ When the user asks about WhatsApp settings, config, policies, or operational lim
|
|
|
98
98
|
|
|
99
99
|
## Session Reset
|
|
100
100
|
|
|
101
|
-
When the user asks to start a new session, clear the conversation, or start fresh, call `session-reset`.
|
|
101
|
+
When the user asks to start a new session, clear the conversation, or start fresh, call `session-reset`. Do not ask for confirmation. After calling the tool, do not say anything further — the UI clears and returns to idle.
|
|
102
|
+
|
|
103
|
+
When you are about to suggest a reset — after a plugin activation, when context has drifted, or for any other reason — first persist every actionable finding from the current conversation to its durable store (graph nodes, tasks, profile updates). The compaction saves a session summary, but summaries are lossy: decisions, working state, and unfinished threads must be captured explicitly before the context window is cleared. Then tell the user what will carry into the new session (summary and open tasks via previous-context) and suggest the reset.
|
|
102
104
|
|
|
103
105
|
## Session Continuation
|
|
104
106
|
|
package/payload/server/server.js
CHANGED
|
@@ -5162,6 +5162,17 @@ function registerResumedSession(sessionKey, accountId, agentName, conversationId
|
|
|
5162
5162
|
messageHistory
|
|
5163
5163
|
});
|
|
5164
5164
|
}
|
|
5165
|
+
function seedSessionHistory(sessionKey, messages) {
|
|
5166
|
+
const session = sessionStore.get(sessionKey);
|
|
5167
|
+
if (!session) return 0;
|
|
5168
|
+
if (messages.length === 0) return 0;
|
|
5169
|
+
session.messageHistory = messages.map((m) => ({
|
|
5170
|
+
role: m.role,
|
|
5171
|
+
content: m.content,
|
|
5172
|
+
timestamp: m.createdAt ? new Date(m.createdAt).getTime() || Date.now() : Date.now()
|
|
5173
|
+
}));
|
|
5174
|
+
return session.messageHistory.length;
|
|
5175
|
+
}
|
|
5165
5176
|
function getSessionMessages(sessionKey) {
|
|
5166
5177
|
return sessionStore.get(sessionKey)?.messageHistory;
|
|
5167
5178
|
}
|
|
@@ -26332,8 +26343,18 @@ async function createAdminSession(accountId, thinkingView, userId, userName) {
|
|
|
26332
26343
|
} catch {
|
|
26333
26344
|
}
|
|
26334
26345
|
let conversationId = null;
|
|
26346
|
+
let loadedMessages = 0;
|
|
26347
|
+
let estimatedTokens = 0;
|
|
26335
26348
|
if (userId) {
|
|
26336
26349
|
conversationId = await findOrResumeAdminConversation(userId, accountId, sessionKey);
|
|
26350
|
+
if (conversationId) {
|
|
26351
|
+
const messages = await getRecentMessages(conversationId);
|
|
26352
|
+
if (messages.length > 0) {
|
|
26353
|
+
loadedMessages = seedSessionHistory(sessionKey, messages);
|
|
26354
|
+
estimatedTokens = messages.reduce((sum, m) => sum + Math.ceil(m.content.length / 4), 0);
|
|
26355
|
+
}
|
|
26356
|
+
console.log(`[managed-resume] ${(/* @__PURE__ */ new Date()).toISOString()} conversationId=${conversationId.slice(0, 8)}\u2026 loaded=${loadedMessages} messages (${estimatedTokens} estimated tokens)`);
|
|
26357
|
+
}
|
|
26337
26358
|
}
|
|
26338
26359
|
console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} admin session created: userId=${userId ?? "\u2013"} userName=${userName ?? "\u2013"} accountId=${accountId} conversationId=${conversationId?.slice(0, 8) ?? "\u2013"}`);
|
|
26339
26360
|
return Response.json({
|