@rubytech/create-maxy 1.0.736 → 1.0.738
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/oauth-llm/dist/index.d.ts +11 -1
- package/payload/platform/lib/oauth-llm/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/oauth-llm/dist/index.js.map +1 -1
- package/payload/platform/lib/oauth-llm/src/index.ts +11 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/docs/references/memory-guide.md +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +59 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +9 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +11 -0
- package/payload/platform/scripts/admin-conversation-recover.mjs +386 -0
- package/payload/server/chunk-VOD2IZ6J.js +2934 -0
- package/payload/server/chunk-VS7CRH4M.js +9439 -0
- package/payload/server/client-pool-67NUIL7H.js +28 -0
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/server.js +13 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-classifier.d.ts","sourceRoot":"","sources":["../../src/lib/llm-classifier.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"llm-classifier.d.ts","sourceRoot":"","sources":["../../src/lib/llm-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -171,13 +171,20 @@ export async function classifyDocument(params) {
|
|
|
171
171
|
"",
|
|
172
172
|
"Return the JSON object now.",
|
|
173
173
|
].join("\n");
|
|
174
|
-
|
|
174
|
+
// Task 781: 60s wrapper default tipped over for 15K-char inputs at 8K
|
|
175
|
+
// maxTokens (observed 56s p99 → fallback at 60s). 180s gives Haiku 4.5
|
|
176
|
+
// headroom for the 10K–20K band without affecting short admin classifiers,
|
|
177
|
+
// which keep the wrapper's 60s default.
|
|
178
|
+
process.stderr.write(`[memory-classify] [${accountId}] calling haiku (chars=${documentText.length}, labels=${ontologyLabels.size}, timeoutMs=180000)\n`);
|
|
179
|
+
const haikuStart = Date.now();
|
|
175
180
|
const llmResult = await callOauthLlm({
|
|
176
181
|
model: HAIKU_MODEL,
|
|
177
182
|
system: SYSTEM_PROMPT,
|
|
178
183
|
userMessage,
|
|
179
184
|
maxTokens: MAX_OUTPUT_TOKENS,
|
|
185
|
+
timeoutMs: 180_000,
|
|
180
186
|
});
|
|
187
|
+
const haikuMs = Date.now() - haikuStart;
|
|
181
188
|
if (llmResult.kind === "fallback") {
|
|
182
189
|
logFallback(accountId, `${llmResult.cause}: ${llmResult.reason}`);
|
|
183
190
|
return { kind: "fallback", reason: llmResult.reason };
|
|
@@ -327,7 +334,7 @@ export async function classifyDocument(params) {
|
|
|
327
334
|
});
|
|
328
335
|
}
|
|
329
336
|
}
|
|
330
|
-
process.stderr.write(`[memory-classify] [${accountId}] haiku ok (sections=${sections.length}, orphanCandidates=${orphanCandidates.length}, hallucinatedRelated=${hallucinatedRelated})\n`);
|
|
337
|
+
process.stderr.write(`[memory-classify] [${accountId}] haiku ok (sections=${sections.length}, orphanCandidates=${orphanCandidates.length}, hallucinatedRelated=${hallucinatedRelated}, elapsedMs=${haikuMs})\n`);
|
|
331
338
|
return {
|
|
332
339
|
kind: "ok",
|
|
333
340
|
output: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-classifier.js","sourceRoot":"","sources":["../../src/lib/llm-classifier.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"llm-classifier.js","sourceRoot":"","sources":["../../src/lib/llm-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -47,6 +47,17 @@ EXTRACT --> CLASSIFY --> INGEST
|
|
|
47
47
|
|
|
48
48
|
Pulls text from the file and caches it under the `attachmentId`. Inputs: `storagePath`, `filename`, `mimeType`, `attachmentId` (all from the attachment metadata block in your brief). Returns metadata + a 240-char preview. The full text lives in the in-process cache.
|
|
49
49
|
|
|
50
|
+
After extract returns, look at the document's char count and emit a one-line size→latency estimate in chat **before** calling `memory-classify`, so the operator knows whether to expect a 10s turnaround or a 90–180s wait. The `memory-classify` server enforces a 180s ceiling on the Haiku call (Task 781) — anything above the >20K band may push toward that ceiling and time out loudly.
|
|
51
|
+
|
|
52
|
+
| chars | estimate |
|
|
53
|
+
|---|---|
|
|
54
|
+
| <5K | ~10s |
|
|
55
|
+
| 5K–10K | ~20s |
|
|
56
|
+
| 10K–20K | ~45–90s |
|
|
57
|
+
| >20K | ~90–180s |
|
|
58
|
+
|
|
59
|
+
Form: "Classifying `<filename>` (`<N>` chars) — expect ~`<estimate>`."
|
|
60
|
+
|
|
50
61
|
### 2. `memory-classify`
|
|
51
62
|
|
|
52
63
|
Calls Haiku with the loaded ontology and the cached text. Inputs: `attachmentId` (same one), `anchorDescription` (a short sentence built from the confirmed anchor — e.g. `"subject = UserProfile (the account owner); edges from UserProfile."` or `"subject = LocalBusiness {name: 'Acme Roofing'} (the operator's business); edges from LocalBusiness."`). Returns:
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Task 782 — one-shot AdminConversation recovery from preflush stream logs.
|
|
3
|
+
//
|
|
4
|
+
// Background. Task 650 (2026-04-22) deferred admin Conversation persistence
|
|
5
|
+
// until a 2-user-turn threshold; the gate filtered out single-turn admin chats
|
|
6
|
+
// (the common case). Task 782 fixes the gate forward (any non-empty buffer
|
|
7
|
+
// flushes), but five days of admin sessions had already run without writing
|
|
8
|
+
// AdminConversation nodes. Their interaction transcripts survive only in the
|
|
9
|
+
// per-session preflush stream logs under
|
|
10
|
+
// <maxy_root>/data/accounts/<accountId>/logs/claude-agent-stream-preflush-{sk12}.log
|
|
11
|
+
// This script replays them into Neo4j as AdminConversation + Message nodes.
|
|
12
|
+
//
|
|
13
|
+
// Invocation. Run on the Maxy laptop (192.168.88.10), not in the dev worktree.
|
|
14
|
+
// node platform/scripts/admin-conversation-recover.mjs --dry-run # preview
|
|
15
|
+
// node platform/scripts/admin-conversation-recover.mjs --apply # commit
|
|
16
|
+
//
|
|
17
|
+
// Flags.
|
|
18
|
+
// --dry-run (default) print proposed writes; do nothing
|
|
19
|
+
// --apply actually write to Neo4j (mutually exclusive with --dry-run)
|
|
20
|
+
// --maxy-root <path> override autodetected ~/maxy
|
|
21
|
+
// --account-id <uuid> restrict to a single account (default: all accounts)
|
|
22
|
+
// --since <iso> log mtime cutoff (default: 2026-04-22T00:00:00Z)
|
|
23
|
+
// --user-id <id> override the AdminUser id (default: looked up from Neo4j)
|
|
24
|
+
//
|
|
25
|
+
// Source identifiers in the preflush log filename only carry the first 12 chars
|
|
26
|
+
// of the original sessionKey; the full key was RAM-only and is unrecoverable.
|
|
27
|
+
// Reconstructed Conversations carry sessionKey="recovered:<sk12>:<mtime-epoch>"
|
|
28
|
+
// so they remain unique without forging the original.
|
|
29
|
+
|
|
30
|
+
import { readFileSync, statSync, readdirSync, existsSync } from "node:fs";
|
|
31
|
+
import { join, basename } from "node:path";
|
|
32
|
+
import { homedir } from "node:os";
|
|
33
|
+
import { randomUUID } from "node:crypto";
|
|
34
|
+
import { createRequire } from "node:module";
|
|
35
|
+
|
|
36
|
+
const require = createRequire(import.meta.url);
|
|
37
|
+
|
|
38
|
+
function parseFlags(argv) {
|
|
39
|
+
const flags = {
|
|
40
|
+
dryRun: true,
|
|
41
|
+
apply: false,
|
|
42
|
+
maxyRoot: join(homedir(), "maxy"),
|
|
43
|
+
accountId: null,
|
|
44
|
+
since: "2026-04-22T00:00:00Z",
|
|
45
|
+
userId: null,
|
|
46
|
+
};
|
|
47
|
+
for (let i = 2; i < argv.length; i++) {
|
|
48
|
+
const a = argv[i];
|
|
49
|
+
if (a === "--dry-run") { flags.dryRun = true; flags.apply = false; }
|
|
50
|
+
else if (a === "--apply") { flags.apply = true; flags.dryRun = false; }
|
|
51
|
+
else if (a === "--maxy-root") flags.maxyRoot = argv[++i];
|
|
52
|
+
else if (a === "--account-id") flags.accountId = argv[++i];
|
|
53
|
+
else if (a === "--since") flags.since = argv[++i];
|
|
54
|
+
else if (a === "--user-id") flags.userId = argv[++i];
|
|
55
|
+
else if (a === "--help" || a === "-h") {
|
|
56
|
+
console.log(readFileSync(import.meta.url.replace("file://", ""), "utf8").split("\n").slice(1, 28).map(l => l.replace(/^\/\/ ?/, "")).join("\n"));
|
|
57
|
+
process.exit(0);
|
|
58
|
+
} else {
|
|
59
|
+
console.error(`unknown flag: ${a}`);
|
|
60
|
+
process.exit(2);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return flags;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function findPreflushLogs(maxyRoot, accountFilter, sinceIso) {
|
|
67
|
+
const accountsDir = join(maxyRoot, "data", "accounts");
|
|
68
|
+
if (!existsSync(accountsDir)) {
|
|
69
|
+
console.error(`accountsDir missing: ${accountsDir}`);
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const sinceMs = Date.parse(sinceIso);
|
|
73
|
+
if (Number.isNaN(sinceMs)) {
|
|
74
|
+
console.error(`invalid --since: ${sinceIso}`);
|
|
75
|
+
process.exit(2);
|
|
76
|
+
}
|
|
77
|
+
const out = [];
|
|
78
|
+
for (const accountId of readdirSync(accountsDir)) {
|
|
79
|
+
if (accountFilter && accountId !== accountFilter) continue;
|
|
80
|
+
const logsDir = join(accountsDir, accountId, "logs");
|
|
81
|
+
if (!existsSync(logsDir)) continue;
|
|
82
|
+
for (const name of readdirSync(logsDir)) {
|
|
83
|
+
if (!name.startsWith("claude-agent-stream-preflush-")) continue;
|
|
84
|
+
if (!name.endsWith(".log")) continue;
|
|
85
|
+
const path = join(logsDir, name);
|
|
86
|
+
const stat = statSync(path);
|
|
87
|
+
if (stat.mtimeMs < sinceMs) continue;
|
|
88
|
+
const sk12 = name.slice("claude-agent-stream-preflush-".length, -".log".length);
|
|
89
|
+
out.push({ path, accountId, sk12, mtimeMs: stat.mtimeMs, sizeBytes: stat.size });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
out.sort((a, b) => a.mtimeMs - b.mtimeMs);
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Parse one preflush log into ordered turns. Each turn carries role + content +
|
|
97
|
+
// timestamp; tool-only assistant turns produce empty content (still kept so the
|
|
98
|
+
// reconstruction reflects the real interaction shape).
|
|
99
|
+
function parseLog(path) {
|
|
100
|
+
const text = readFileSync(path, "utf8");
|
|
101
|
+
const turns = [];
|
|
102
|
+
for (const rawLine of text.split("\n")) {
|
|
103
|
+
if (!rawLine) continue;
|
|
104
|
+
if (!rawLine.startsWith("{")) continue;
|
|
105
|
+
let msg;
|
|
106
|
+
try { msg = JSON.parse(rawLine); } catch { continue; }
|
|
107
|
+
if (!msg || typeof msg !== "object") continue;
|
|
108
|
+
if (msg.type === "user" && msg.message?.content) {
|
|
109
|
+
const content = typeof msg.message.content === "string"
|
|
110
|
+
? msg.message.content
|
|
111
|
+
: Array.isArray(msg.message.content)
|
|
112
|
+
? msg.message.content.filter(c => c?.type === "text").map(c => c.text).join("\n")
|
|
113
|
+
: "";
|
|
114
|
+
if (content) turns.push({ role: "user", content, timestamp: msg.timestamp });
|
|
115
|
+
} else if (msg.type === "assistant" && Array.isArray(msg.message?.content)) {
|
|
116
|
+
const textParts = msg.message.content.filter(c => c?.type === "text").map(c => c.text);
|
|
117
|
+
if (textParts.length > 0) {
|
|
118
|
+
turns.push({ role: "assistant", content: textParts.join("\n"), timestamp: msg.timestamp });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return turns;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function loadDriver(maxyRoot) {
|
|
126
|
+
// The neo4j-driver dep lives under platform/ui — resolve from there so the
|
|
127
|
+
// script works whether invoked from worktree, deployed payload, or laptop.
|
|
128
|
+
const candidates = [
|
|
129
|
+
join(maxyRoot, "platform", "ui", "node_modules", "neo4j-driver"),
|
|
130
|
+
join(process.cwd(), "platform", "ui", "node_modules", "neo4j-driver"),
|
|
131
|
+
join(process.cwd(), "node_modules", "neo4j-driver"),
|
|
132
|
+
];
|
|
133
|
+
for (const c of candidates) {
|
|
134
|
+
if (existsSync(c)) {
|
|
135
|
+
const mod = require(c);
|
|
136
|
+
return mod.default || mod;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
console.error(`neo4j-driver not found in any of:\n ${candidates.join("\n ")}`);
|
|
140
|
+
process.exit(2);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function readNeo4jConfig() {
|
|
144
|
+
const uri = process.env.NEO4J_URI;
|
|
145
|
+
const username = process.env.NEO4J_USERNAME ?? "neo4j";
|
|
146
|
+
const password = process.env.NEO4J_PASSWORD;
|
|
147
|
+
if (!uri || !password) {
|
|
148
|
+
console.error("NEO4J_URI and NEO4J_PASSWORD must be set");
|
|
149
|
+
process.exit(2);
|
|
150
|
+
}
|
|
151
|
+
return { uri, username, password };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function resolveUserId(driver, accountId, override) {
|
|
155
|
+
if (override) return override;
|
|
156
|
+
const session = driver.session();
|
|
157
|
+
try {
|
|
158
|
+
const result = await session.run(
|
|
159
|
+
`MATCH (au:AdminUser {accountId: $accountId})
|
|
160
|
+
OPTIONAL MATCH (au)<-[:STARTED_BY]-(c:Conversation)
|
|
161
|
+
WITH au, count(c) AS conversationCount
|
|
162
|
+
RETURN au.userId AS userId
|
|
163
|
+
ORDER BY conversationCount DESC
|
|
164
|
+
LIMIT 1`,
|
|
165
|
+
{ accountId },
|
|
166
|
+
);
|
|
167
|
+
const userId = result.records[0]?.get("userId");
|
|
168
|
+
if (!userId) {
|
|
169
|
+
console.error(`no AdminUser found for accountId=${accountId} — pass --user-id explicitly`);
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
return userId;
|
|
173
|
+
} finally {
|
|
174
|
+
await session.close();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function reconstructOne(driver, file, userId, dryRun) {
|
|
179
|
+
const turns = parseLog(file.path);
|
|
180
|
+
if (turns.length === 0) {
|
|
181
|
+
return { ...file, status: "skipped", reason: "no-turns", turns: 0 };
|
|
182
|
+
}
|
|
183
|
+
const recoveredSessionKey = `recovered:${file.sk12}:${file.mtimeMs}`;
|
|
184
|
+
const conversationId = randomUUID();
|
|
185
|
+
if (dryRun) {
|
|
186
|
+
return {
|
|
187
|
+
...file,
|
|
188
|
+
status: "would-create",
|
|
189
|
+
conversationId,
|
|
190
|
+
recoveredSessionKey,
|
|
191
|
+
userId,
|
|
192
|
+
turns: turns.length,
|
|
193
|
+
sample: turns.slice(0, 1).map(t => `${t.role}:${t.content.slice(0, 60)}`)[0],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const session = driver.session();
|
|
197
|
+
try {
|
|
198
|
+
// Apply phase. Mirrors createNewAdminConversation's shape (Task 782
|
|
199
|
+
// sublabel + assertion enforced); persistMessage shape mirrored inline so
|
|
200
|
+
// we don't import the platform module from a script.
|
|
201
|
+
//
|
|
202
|
+
// Idempotency: MERGE on the synthetic recoveredSessionKey so a re-run
|
|
203
|
+
// against the same preflush log returns the existing node instead of
|
|
204
|
+
// creating a duplicate (or throwing under the conversation_id_unique
|
|
205
|
+
// constraint). When MERGE matches, ON MATCH leaves the existing
|
|
206
|
+
// conversationId — the local `conversationId` variable is then stale, but
|
|
207
|
+
// we look up the matched id from RETURN and switch to it before message
|
|
208
|
+
// replay.
|
|
209
|
+
const createdAtBase = new Date(file.mtimeMs).toISOString();
|
|
210
|
+
let effectiveConversationId = conversationId;
|
|
211
|
+
let alreadyExists = false;
|
|
212
|
+
await session.executeWrite(async tx => {
|
|
213
|
+
const result = await tx.run(
|
|
214
|
+
`MERGE (au:AdminUser {userId: $userId})
|
|
215
|
+
ON CREATE SET au.accountId = $accountId,
|
|
216
|
+
au.name = 'Admin',
|
|
217
|
+
au.createdAt = datetime(),
|
|
218
|
+
au.scope = 'admin'
|
|
219
|
+
WITH au
|
|
220
|
+
MERGE (c:Conversation {sessionKey: $sessionKey})
|
|
221
|
+
ON CREATE SET c:AdminConversation,
|
|
222
|
+
c.conversationId = $conversationId,
|
|
223
|
+
c.accountId = $accountId,
|
|
224
|
+
c.agentType = 'admin',
|
|
225
|
+
c.userId = $userId,
|
|
226
|
+
c.createdBySource = 'admin-conversation-recover',
|
|
227
|
+
c.recoveredFrom = $sourcePath,
|
|
228
|
+
c.createdAt = datetime($createdAtBase),
|
|
229
|
+
c.updatedAt = datetime($createdAtBase)
|
|
230
|
+
MERGE (c)-[:STARTED_BY]->(au)
|
|
231
|
+
WITH c, c.createdBySource = 'admin-conversation-recover' AND c.conversationId = $conversationId AS createdNow
|
|
232
|
+
RETURN c.conversationId AS conversationId, NOT createdNow AS alreadyExists`,
|
|
233
|
+
{
|
|
234
|
+
userId,
|
|
235
|
+
accountId: file.accountId,
|
|
236
|
+
conversationId,
|
|
237
|
+
sessionKey: recoveredSessionKey,
|
|
238
|
+
sourcePath: file.path,
|
|
239
|
+
createdAtBase,
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
effectiveConversationId = result.records[0]?.get("conversationId") ?? conversationId;
|
|
243
|
+
alreadyExists = result.records[0]?.get("alreadyExists") === true;
|
|
244
|
+
if (alreadyExists) return;
|
|
245
|
+
let prevId = null;
|
|
246
|
+
for (let i = 0; i < turns.length; i++) {
|
|
247
|
+
const t = turns[i];
|
|
248
|
+
const messageId = randomUUID();
|
|
249
|
+
const ts = t.timestamp ?? new Date(file.mtimeMs + i * 1000).toISOString();
|
|
250
|
+
await tx.run(
|
|
251
|
+
`MATCH (c:Conversation {conversationId: $conversationId})
|
|
252
|
+
CREATE (m:Message {
|
|
253
|
+
messageId: $messageId,
|
|
254
|
+
role: $role,
|
|
255
|
+
content: $content,
|
|
256
|
+
accountId: $accountId,
|
|
257
|
+
createdAt: datetime($ts),
|
|
258
|
+
createdBySource: 'admin-conversation-recover'
|
|
259
|
+
})
|
|
260
|
+
SET m:` + (t.role === "user" ? "UserMessage" : "AssistantMessage") + `
|
|
261
|
+
CREATE (m)-[:PART_OF]->(c)`,
|
|
262
|
+
{
|
|
263
|
+
conversationId,
|
|
264
|
+
messageId,
|
|
265
|
+
role: t.role,
|
|
266
|
+
content: t.content,
|
|
267
|
+
accountId: file.accountId,
|
|
268
|
+
ts,
|
|
269
|
+
},
|
|
270
|
+
);
|
|
271
|
+
if (prevId) {
|
|
272
|
+
await tx.run(
|
|
273
|
+
`MATCH (a:Message {messageId: $prevId})
|
|
274
|
+
MATCH (b:Message {messageId: $thisId})
|
|
275
|
+
CREATE (a)-[:NEXT]->(b)`,
|
|
276
|
+
{ prevId, thisId: messageId },
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
prevId = messageId;
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
return {
|
|
283
|
+
...file,
|
|
284
|
+
status: alreadyExists ? "already-recovered" : "created",
|
|
285
|
+
conversationId: effectiveConversationId,
|
|
286
|
+
recoveredSessionKey,
|
|
287
|
+
userId,
|
|
288
|
+
turns: turns.length,
|
|
289
|
+
};
|
|
290
|
+
} catch (err) {
|
|
291
|
+
return {
|
|
292
|
+
...file,
|
|
293
|
+
status: "failed",
|
|
294
|
+
error: err instanceof Error ? err.message : String(err),
|
|
295
|
+
turns: turns.length,
|
|
296
|
+
};
|
|
297
|
+
} finally {
|
|
298
|
+
await session.close();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function reconcileSublabels(driver, dryRun) {
|
|
303
|
+
if (dryRun) return { reconciled: 0, dryRun: true };
|
|
304
|
+
const session = driver.session();
|
|
305
|
+
try {
|
|
306
|
+
const result = await session.run(
|
|
307
|
+
`MATCH (c:Conversation)
|
|
308
|
+
WHERE c.agentType = 'admin' AND NOT c:AdminConversation
|
|
309
|
+
SET c:AdminConversation
|
|
310
|
+
RETURN count(c) AS reconciled`,
|
|
311
|
+
);
|
|
312
|
+
const reconciled = result.records[0]?.get("reconciled");
|
|
313
|
+
return {
|
|
314
|
+
reconciled: typeof reconciled?.toNumber === "function" ? reconciled.toNumber() : Number(reconciled ?? 0),
|
|
315
|
+
};
|
|
316
|
+
} finally {
|
|
317
|
+
await session.close();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function main() {
|
|
322
|
+
const flags = parseFlags(process.argv);
|
|
323
|
+
const mode = flags.apply ? "APPLY" : "DRY-RUN";
|
|
324
|
+
console.log(`[admin-recover] mode=${mode} maxyRoot=${flags.maxyRoot} since=${flags.since} accountFilter=${flags.accountId ?? "all"}`);
|
|
325
|
+
|
|
326
|
+
const files = findPreflushLogs(flags.maxyRoot, flags.accountId, flags.since);
|
|
327
|
+
console.log(`[admin-recover] found ${files.length} preflush log(s)`);
|
|
328
|
+
if (files.length === 0) {
|
|
329
|
+
console.log(`[admin-recover] nothing to do`);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const Neo4j = await loadDriver(flags.maxyRoot);
|
|
334
|
+
const cfg = readNeo4jConfig();
|
|
335
|
+
const driver = Neo4j.driver(cfg.uri, Neo4j.auth.basic(cfg.username, cfg.password));
|
|
336
|
+
|
|
337
|
+
// Verify connectivity before iterating.
|
|
338
|
+
try {
|
|
339
|
+
await driver.verifyConnectivity();
|
|
340
|
+
} catch (err) {
|
|
341
|
+
console.error(`[admin-recover] neo4j connect failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
342
|
+
await driver.close();
|
|
343
|
+
process.exit(2);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const userIdByAccount = new Map();
|
|
347
|
+
const results = [];
|
|
348
|
+
for (const file of files) {
|
|
349
|
+
let userId = userIdByAccount.get(file.accountId);
|
|
350
|
+
if (userId === undefined) {
|
|
351
|
+
userId = await resolveUserId(driver, file.accountId, flags.userId);
|
|
352
|
+
userIdByAccount.set(file.accountId, userId);
|
|
353
|
+
}
|
|
354
|
+
if (!userId) {
|
|
355
|
+
results.push({ ...file, status: "skipped", reason: "no-user-id", turns: 0 });
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const r = await reconstructOne(driver, file, userId, flags.dryRun);
|
|
359
|
+
results.push(r);
|
|
360
|
+
const tag = `[admin-recover:${r.status}]`;
|
|
361
|
+
const summary = r.status === "would-create"
|
|
362
|
+
? `${tag} ${basename(r.path)} accountId=${r.accountId.slice(0, 8)} sk12=${r.sk12} turns=${r.turns} sample=${JSON.stringify(r.sample ?? "")}`
|
|
363
|
+
: r.status === "created" || r.status === "already-recovered"
|
|
364
|
+
? `${tag} ${basename(r.path)} conversationId=${r.conversationId.slice(0, 8)} turns=${r.turns}`
|
|
365
|
+
: r.status === "failed"
|
|
366
|
+
? `${tag} ${basename(r.path)} error=${r.error}`
|
|
367
|
+
: `${tag} ${basename(r.path)} reason=${r.reason}`;
|
|
368
|
+
console.log(summary);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const reconcile = await reconcileSublabels(driver, flags.dryRun);
|
|
372
|
+
console.log(`[admin-recover] reconcile-sublabels reconciled=${reconcile.reconciled}${reconcile.dryRun ? " (dry-run)" : ""}`);
|
|
373
|
+
|
|
374
|
+
const counts = results.reduce((acc, r) => {
|
|
375
|
+
acc[r.status] = (acc[r.status] ?? 0) + 1;
|
|
376
|
+
return acc;
|
|
377
|
+
}, {});
|
|
378
|
+
console.log(`[admin-recover] summary mode=${mode} files=${results.length} ${Object.entries(counts).map(([k, v]) => `${k}=${v}`).join(" ")}`);
|
|
379
|
+
|
|
380
|
+
await driver.close();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
main().catch(err => {
|
|
384
|
+
console.error(`[admin-recover] fatal: ${err instanceof Error ? err.stack : String(err)}`);
|
|
385
|
+
process.exit(1);
|
|
386
|
+
});
|