@rubytech/create-maxy 1.0.877 → 1.0.878
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-trash/dist/index.js +1 -1
- package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-trash/src/index.ts +1 -1
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-base64-guard.test.sh +204 -0
- package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +96 -0
- package/payload/platform/plugins/docs/references/platform.md +3 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +4 -0
- package/payload/server/chunk-INI2ED6U.js +2277 -0
- package/payload/server/chunk-JTZYXIUW.js +1373 -0
- package/payload/server/chunk-LQDUG4II.js +11336 -0
- package/payload/server/chunk-RP25NRQY.js +660 -0
- package/payload/server/client-pool-AIZ5QKFD.js +34 -0
- package/payload/server/cloudflare-task-tracker-B6FXP3HI.js +20 -0
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/public/assets/{Checkbox-m3yLBLrp.js → Checkbox-CqsIsmEi.js} +1 -1
- package/payload/server/public/assets/admin-CZlNLb9T.js +352 -0
- package/payload/server/public/assets/data-CH-nQ7oX.js +1 -0
- package/payload/server/public/assets/graph-labels-D0qUVHtZ.js +1 -0
- package/payload/server/public/assets/graph-mpWDe4rf.js +1 -0
- package/payload/server/public/assets/{jsx-runtime-DJwgVAMg.css → jsx-runtime-Cy_HdZWV.css} +1 -1
- package/payload/server/public/assets/page-CnyySOZF.js +1 -0
- package/payload/server/public/assets/{page-BLRjaAoU.js → page-DcK36vDf.js} +2 -2
- package/payload/server/public/assets/public-SXA00FTv.js +5 -0
- package/payload/server/public/assets/{useVoiceRecorder-JwwBC5pd.js → useVoiceRecorder-DcByEBLy.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +520 -438
- package/payload/server/public/assets/admin-DEm0CCga.js +0 -352
- package/payload/server/public/assets/data-BkbjVYwP.js +0 -1
- package/payload/server/public/assets/graph-Cic-rDfg.js +0 -1
- package/payload/server/public/assets/graph-labels-C13OVh5P.js +0 -1
- package/payload/server/public/assets/page-p-Fj8Guk.js +0 -1
- package/payload/server/public/assets/public-4udeVi_T.js +0 -5
- /package/payload/server/public/assets/{jsx-runtime-Bd3TJ8Bg.js → jsx-runtime-BEjEWeaF.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
vncLog,
|
|
76
76
|
waitForExit,
|
|
77
77
|
writeChromiumWrapper
|
|
78
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-LQDUG4II.js";
|
|
79
79
|
import {
|
|
80
80
|
CDP_PORT,
|
|
81
81
|
COMMERCIAL_MODE,
|
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
getVisitorIdForSession,
|
|
103
103
|
interruptClient,
|
|
104
104
|
listAdminSessionsInProgress,
|
|
105
|
-
|
|
105
|
+
mintAdminSessionToken,
|
|
106
106
|
preConversationLogStream,
|
|
107
107
|
registerGrantSession,
|
|
108
108
|
registerResumedSession,
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
sigtermFlushStreamLogs,
|
|
115
115
|
unregisterSession,
|
|
116
116
|
validateSession
|
|
117
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-JTZYXIUW.js";
|
|
118
118
|
import {
|
|
119
119
|
CLOUDFLARE_TASK_DIAGNOSTICS,
|
|
120
120
|
appendCloudflareSteps,
|
|
@@ -122,10 +122,11 @@ import {
|
|
|
122
122
|
openCloudflareTask,
|
|
123
123
|
readTunnelState,
|
|
124
124
|
resolveUnitGoneVerdict
|
|
125
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-RP25NRQY.js";
|
|
126
126
|
import {
|
|
127
127
|
GREETING_DIRECTIVE,
|
|
128
128
|
HAIKU_MODEL,
|
|
129
|
+
backfillConversationChannelAddress,
|
|
129
130
|
backfillNullUserIdConversations,
|
|
130
131
|
bindVisitorToGroup,
|
|
131
132
|
checkGroupMembership,
|
|
@@ -154,8 +155,9 @@ import {
|
|
|
154
155
|
runAdminUserSelfHeal,
|
|
155
156
|
verifyAndGetConversationUpdatedAt,
|
|
156
157
|
verifyConversationOwnership,
|
|
157
|
-
writeAdminUserAndPerson
|
|
158
|
-
|
|
158
|
+
writeAdminUserAndPerson,
|
|
159
|
+
writeTurnFailure
|
|
160
|
+
} from "./chunk-INI2ED6U.js";
|
|
159
161
|
import {
|
|
160
162
|
__commonJS,
|
|
161
163
|
__toESM
|
|
@@ -180,7 +182,7 @@ var require_dist = __commonJS({
|
|
|
180
182
|
Event: ["eventId"],
|
|
181
183
|
KnowledgeDocument: ["attachmentId"],
|
|
182
184
|
DigitalDocument: ["attachmentId"],
|
|
183
|
-
Conversation: ["conversationId"
|
|
185
|
+
Conversation: ["conversationId"],
|
|
184
186
|
Message: ["messageId"],
|
|
185
187
|
OnboardingState: ["accountId"],
|
|
186
188
|
Workflow: ["workflowId"],
|
|
@@ -2087,22 +2089,22 @@ async function persistWhatsAppMessage(input) {
|
|
|
2087
2089
|
const messageId = `whatsapp-live:${input.accountId}:${input.remoteJid}:${input.msgKeyId}`;
|
|
2088
2090
|
const senderTelephone = input.fromMe && input.selfPhone ? input.selfPhone : input.senderPhone;
|
|
2089
2091
|
const dateSentIso = new Date(input.timestamp * 1e3).toISOString();
|
|
2090
|
-
const scope = deriveScope(input.
|
|
2092
|
+
const scope = deriveScope(input.cacheKey);
|
|
2091
2093
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2092
|
-
const prev = sessionWriteLocks.get(input.
|
|
2094
|
+
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2093
2095
|
let release;
|
|
2094
2096
|
const mine = new Promise((resolve22) => {
|
|
2095
2097
|
release = resolve22;
|
|
2096
2098
|
});
|
|
2097
2099
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2098
|
-
sessionWriteLocks.set(input.
|
|
2100
|
+
sessionWriteLocks.set(input.cacheKey, chained);
|
|
2099
2101
|
await prev;
|
|
2100
2102
|
const t0 = Date.now();
|
|
2101
2103
|
let session = null;
|
|
2102
2104
|
try {
|
|
2103
2105
|
session = getSession();
|
|
2104
2106
|
const cypher = `
|
|
2105
|
-
MATCH (c:Conversation {
|
|
2107
|
+
MATCH (c:Conversation {conversationId: $conversationId})
|
|
2106
2108
|
OPTIONAL MATCH (existingS:Person {telephone: $senderTelephone})
|
|
2107
2109
|
OPTIONAL MATCH (existingM:Message {messageId: $messageId})
|
|
2108
2110
|
WITH c,
|
|
@@ -2166,7 +2168,7 @@ async function persistWhatsAppMessage(input) {
|
|
|
2166
2168
|
senderReused AS senderReused
|
|
2167
2169
|
`;
|
|
2168
2170
|
const params = {
|
|
2169
|
-
|
|
2171
|
+
conversationId: input.conversationId,
|
|
2170
2172
|
messageId,
|
|
2171
2173
|
platformAccountId: input.platformAccountId,
|
|
2172
2174
|
senderTelephone,
|
|
@@ -2185,7 +2187,7 @@ async function persistWhatsAppMessage(input) {
|
|
|
2185
2187
|
const result = await session.run(cypher, params);
|
|
2186
2188
|
const ms = Date.now() - t0;
|
|
2187
2189
|
if (result.records.length === 0) {
|
|
2188
|
-
console.error(`${TAG7} skip reason=conversation-not-found accountId=${input.platformAccountId}
|
|
2190
|
+
console.error(`${TAG7} skip reason=conversation-not-found accountId=${input.platformAccountId} cacheKey=${input.cacheKey} messageId=${messageId}`);
|
|
2189
2191
|
return null;
|
|
2190
2192
|
}
|
|
2191
2193
|
const rec = result.records[0];
|
|
@@ -2206,7 +2208,7 @@ async function persistWhatsAppMessage(input) {
|
|
|
2206
2208
|
console.error(`${TAG7} next-skip reason=no-prior msgId=${messageId}`);
|
|
2207
2209
|
}
|
|
2208
2210
|
console.error(
|
|
2209
|
-
`${TAG7} write messageId=${messageId} accountId=${input.platformAccountId}
|
|
2211
|
+
`${TAG7} write messageId=${messageId} accountId=${input.platformAccountId} cacheKey=${input.cacheKey} fromMe=${input.fromMe} dateSent=${dateSentIso} bodyBytes=${Buffer.byteLength(input.body, "utf8")} ms=${ms}`
|
|
2210
2212
|
);
|
|
2211
2213
|
return { messageId, created: true, senderElementId };
|
|
2212
2214
|
} catch (err) {
|
|
@@ -2218,14 +2220,14 @@ async function persistWhatsAppMessage(input) {
|
|
|
2218
2220
|
return null;
|
|
2219
2221
|
} finally {
|
|
2220
2222
|
release();
|
|
2221
|
-
if (sessionWriteLocks.get(input.
|
|
2222
|
-
sessionWriteLocks.delete(input.
|
|
2223
|
+
if (sessionWriteLocks.get(input.cacheKey) === chained) {
|
|
2224
|
+
sessionWriteLocks.delete(input.cacheKey);
|
|
2223
2225
|
}
|
|
2224
2226
|
if (session) await session.close();
|
|
2225
2227
|
}
|
|
2226
2228
|
}
|
|
2227
|
-
function deriveScope(
|
|
2228
|
-
const segments =
|
|
2229
|
+
function deriveScope(cacheKey) {
|
|
2230
|
+
const segments = cacheKey.split(":");
|
|
2229
2231
|
return segments.length <= 2 ? "admin" : "public";
|
|
2230
2232
|
}
|
|
2231
2233
|
function splitName(pushName) {
|
|
@@ -2253,24 +2255,24 @@ async function ensureWhatsAppConversation(input) {
|
|
|
2253
2255
|
const result = await ensureConversation(
|
|
2254
2256
|
input.platformAccountId,
|
|
2255
2257
|
input.agentType,
|
|
2256
|
-
input.
|
|
2258
|
+
input.cacheKey
|
|
2257
2259
|
);
|
|
2258
2260
|
const ms = Date.now() - t0;
|
|
2259
2261
|
if (!result.conversationId) {
|
|
2260
2262
|
console.error(
|
|
2261
|
-
`${TAG8} conversation-merged FAIL
|
|
2263
|
+
`${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-conversationId ms=${ms}`
|
|
2262
2264
|
);
|
|
2263
2265
|
return null;
|
|
2264
2266
|
}
|
|
2265
2267
|
console.error(
|
|
2266
|
-
`${TAG8} conversation-merged
|
|
2268
|
+
`${TAG8} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp created=${result.created} ms=${ms}`
|
|
2267
2269
|
);
|
|
2268
2270
|
return { conversationId: result.conversationId, created: result.created };
|
|
2269
2271
|
} catch (err) {
|
|
2270
2272
|
const ms = Date.now() - t0;
|
|
2271
2273
|
const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
|
|
2272
2274
|
console.error(
|
|
2273
|
-
`${TAG8} conversation-merged FAIL
|
|
2275
|
+
`${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
|
|
2274
2276
|
);
|
|
2275
2277
|
return null;
|
|
2276
2278
|
}
|
|
@@ -2781,14 +2783,14 @@ function storeMessage(storeKey, entry) {
|
|
|
2781
2783
|
console.error(`${TAG13} message store trimmed for ${storeKey}: ${trimmed} oldest messages removed`);
|
|
2782
2784
|
}
|
|
2783
2785
|
}
|
|
2784
|
-
function
|
|
2786
|
+
function deriveCacheKey(input) {
|
|
2785
2787
|
if (input.isOwnerMirror || input.agentType === "admin") {
|
|
2786
2788
|
return `whatsapp:${input.accountId}`;
|
|
2787
2789
|
}
|
|
2788
2790
|
if (input.isGroup) {
|
|
2789
2791
|
if (!input.groupJid) {
|
|
2790
2792
|
throw new Error(
|
|
2791
|
-
`
|
|
2793
|
+
`deriveCacheKey: isGroup=true requires groupJid (accountId=${input.accountId}, senderPhone=${input.senderPhone})`
|
|
2792
2794
|
);
|
|
2793
2795
|
}
|
|
2794
2796
|
return `whatsapp:${input.accountId}:group:${input.groupJid}`;
|
|
@@ -3267,14 +3269,14 @@ function monitorInbound(conn) {
|
|
|
3267
3269
|
jid: remoteJid
|
|
3268
3270
|
});
|
|
3269
3271
|
const fromMe = Boolean(msg.key.fromMe);
|
|
3270
|
-
const
|
|
3272
|
+
const cacheKeyAgentType = isGroup ? "public" : fromMe ? "admin" : checkDmAccess({
|
|
3271
3273
|
senderPhone,
|
|
3272
3274
|
selfPhone: conn.selfPhone ?? "",
|
|
3273
3275
|
config: whatsAppConfig,
|
|
3274
3276
|
accountConfig: whatsAppConfig.accounts?.[conn.accountId]
|
|
3275
3277
|
}).agentType;
|
|
3276
|
-
const
|
|
3277
|
-
agentType:
|
|
3278
|
+
const cacheKey = deriveCacheKey({
|
|
3279
|
+
agentType: cacheKeyAgentType,
|
|
3278
3280
|
accountId: conn.accountId,
|
|
3279
3281
|
senderPhone,
|
|
3280
3282
|
isGroup,
|
|
@@ -3285,8 +3287,8 @@ function monitorInbound(conn) {
|
|
|
3285
3287
|
const merged = await ensureWhatsAppConversation({
|
|
3286
3288
|
accountId: conn.accountId,
|
|
3287
3289
|
platformAccountId: conn.platformAccountId,
|
|
3288
|
-
|
|
3289
|
-
agentType:
|
|
3290
|
+
cacheKey,
|
|
3291
|
+
agentType: cacheKeyAgentType,
|
|
3290
3292
|
groupJid: isGroup ? remoteJid : void 0
|
|
3291
3293
|
});
|
|
3292
3294
|
if (merged) {
|
|
@@ -3294,7 +3296,8 @@ function monitorInbound(conn) {
|
|
|
3294
3296
|
accountId: conn.accountId,
|
|
3295
3297
|
platformAccountId: conn.platformAccountId,
|
|
3296
3298
|
remoteJid,
|
|
3297
|
-
|
|
3299
|
+
cacheKey,
|
|
3300
|
+
conversationId: merged.conversationId,
|
|
3298
3301
|
msgKeyId: msg.key.id,
|
|
3299
3302
|
fromMe,
|
|
3300
3303
|
senderPhone,
|
|
@@ -3376,7 +3379,7 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3376
3379
|
isGroup: isGroup2,
|
|
3377
3380
|
groupJid: isGroup2 ? remoteJid : void 0,
|
|
3378
3381
|
reply: reply2,
|
|
3379
|
-
|
|
3382
|
+
cacheKey: deriveCacheKey({
|
|
3380
3383
|
agentType: "admin",
|
|
3381
3384
|
accountId: conn.accountId,
|
|
3382
3385
|
senderPhone: senderPhone2,
|
|
@@ -3470,7 +3473,7 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3470
3473
|
if (!currentSock) throw new Error("WhatsApp disconnected \u2014 cannot reply");
|
|
3471
3474
|
await sendTextMessage(currentSock, remoteJid, text, { accountId: conn.accountId });
|
|
3472
3475
|
};
|
|
3473
|
-
const
|
|
3476
|
+
const cacheKey = deriveCacheKey({
|
|
3474
3477
|
agentType: accessResult.agentType,
|
|
3475
3478
|
accountId: conn.accountId,
|
|
3476
3479
|
senderPhone,
|
|
@@ -3487,7 +3490,7 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3487
3490
|
groupJid: isGroup ? remoteJid : void 0,
|
|
3488
3491
|
groupSubject,
|
|
3489
3492
|
reply,
|
|
3490
|
-
|
|
3493
|
+
cacheKey,
|
|
3491
3494
|
mediaPath: mediaResult?.path,
|
|
3492
3495
|
mediaMimetype: mediaResult?.mimetype,
|
|
3493
3496
|
mediaType: extracted.mediaType,
|
|
@@ -3832,9 +3835,9 @@ app2.post("/", async (c) => {
|
|
|
3832
3835
|
...m.role === "user" ? { senderName: m.senderName } : {}
|
|
3833
3836
|
});
|
|
3834
3837
|
}
|
|
3835
|
-
const
|
|
3836
|
-
registerResumedSession(
|
|
3837
|
-
setGroupContextForSession(
|
|
3838
|
+
const cacheKey2 = crypto.randomUUID();
|
|
3839
|
+
registerResumedSession(cacheKey2, accountId, agentSlug, groupInfo.conversationId, agentMessages);
|
|
3840
|
+
setGroupContextForSession(cacheKey2, {
|
|
3838
3841
|
groupSlug,
|
|
3839
3842
|
groupName: groupInfo.groupName,
|
|
3840
3843
|
conversationId: groupInfo.conversationId,
|
|
@@ -3846,7 +3849,7 @@ app2.post("/", async (c) => {
|
|
|
3846
3849
|
console.log(`[session] cold-resume group=${groupSlug} visitor=${visitorId.slice(0, 8)}\u2026 messages=${uiMessages.length}`);
|
|
3847
3850
|
return withVisitorCookie(
|
|
3848
3851
|
Response.json({
|
|
3849
|
-
session_key:
|
|
3852
|
+
session_key: cacheKey2,
|
|
3850
3853
|
agent_id: agentSlug,
|
|
3851
3854
|
resumed,
|
|
3852
3855
|
...resumed ? { messages: uiMessages } : {},
|
|
@@ -3889,13 +3892,13 @@ app2.post("/", async (c) => {
|
|
|
3889
3892
|
content: m.content,
|
|
3890
3893
|
timestamp: new Date(m.createdAt).getTime() || Date.now()
|
|
3891
3894
|
}));
|
|
3892
|
-
const
|
|
3893
|
-
registerResumedSession(
|
|
3895
|
+
const cacheKey2 = crypto.randomUUID();
|
|
3896
|
+
registerResumedSession(cacheKey2, accountId, agentSlug, recent.conversationId, agentMessages);
|
|
3894
3897
|
const resumed = uiMessages.length > 0;
|
|
3895
3898
|
console.log(`[session] cold-resume visitor=${visitorId.slice(0, 8)}\u2026 conversation=${recent.conversationId.slice(0, 8)}\u2026 messages=${uiMessages.length}`);
|
|
3896
3899
|
return withVisitorCookie(
|
|
3897
3900
|
Response.json({
|
|
3898
|
-
session_key:
|
|
3901
|
+
session_key: cacheKey2,
|
|
3899
3902
|
agent_id: agentSlug,
|
|
3900
3903
|
resumed,
|
|
3901
3904
|
...resumed ? { messages: uiMessages } : {},
|
|
@@ -3907,13 +3910,13 @@ app2.post("/", async (c) => {
|
|
|
3907
3910
|
}
|
|
3908
3911
|
}
|
|
3909
3912
|
const newVisitorId = visitorId ?? crypto.randomUUID();
|
|
3910
|
-
const
|
|
3911
|
-
registerSession(
|
|
3913
|
+
const cacheKey = crypto.randomUUID();
|
|
3914
|
+
registerSession(cacheKey, "public", accountId, agentSlug);
|
|
3912
3915
|
const hasImage = agentConfig?.image ? "yes" : "no";
|
|
3913
|
-
console.log(`[session] new-session visitor=${newVisitorId.slice(0, 8)}\u2026 session=${
|
|
3916
|
+
console.log(`[session] new-session visitor=${newVisitorId.slice(0, 8)}\u2026 session=${cacheKey.slice(0, 8)}\u2026 agent=${agentSlug} image=${hasImage} showAgentName=${agentConfig?.showAgentName ?? false}`);
|
|
3914
3917
|
return withVisitorCookie(
|
|
3915
3918
|
Response.json({
|
|
3916
|
-
session_key:
|
|
3919
|
+
session_key: cacheKey,
|
|
3917
3920
|
agent_id: agentSlug,
|
|
3918
3921
|
...branding ? { branding } : {},
|
|
3919
3922
|
...agentIdentity
|
|
@@ -4506,9 +4509,9 @@ var chat_default = app3;
|
|
|
4506
4509
|
// server/routes/group.ts
|
|
4507
4510
|
var app4 = new Hono();
|
|
4508
4511
|
app4.get("/messages", async (c) => {
|
|
4509
|
-
const
|
|
4512
|
+
const cacheKey = c.req.query("session_key");
|
|
4510
4513
|
const since = c.req.query("since");
|
|
4511
|
-
if (!
|
|
4514
|
+
if (!cacheKey) {
|
|
4512
4515
|
return c.json({ error: "session_key required" }, 400);
|
|
4513
4516
|
}
|
|
4514
4517
|
if (!since) {
|
|
@@ -4518,18 +4521,18 @@ app4.get("/messages", async (c) => {
|
|
|
4518
4521
|
if (isNaN(sinceDate.getTime())) {
|
|
4519
4522
|
return c.json({ error: "Invalid since parameter \u2014 expected ISO 8601" }, 400);
|
|
4520
4523
|
}
|
|
4521
|
-
if (!validateSession(
|
|
4524
|
+
if (!validateSession(cacheKey, "public").ok) {
|
|
4522
4525
|
return c.json({ error: "Session expired" }, 401);
|
|
4523
4526
|
}
|
|
4524
|
-
const groupSlug = getGroupSlugForSession(
|
|
4527
|
+
const groupSlug = getGroupSlugForSession(cacheKey);
|
|
4525
4528
|
if (!groupSlug) {
|
|
4526
4529
|
return c.json({ error: "Not a group session" }, 400);
|
|
4527
4530
|
}
|
|
4528
|
-
const conversationId = getConversationIdForSession(
|
|
4531
|
+
const conversationId = getConversationIdForSession(cacheKey);
|
|
4529
4532
|
if (!conversationId) {
|
|
4530
4533
|
return c.json({ error: "No conversation bound" }, 400);
|
|
4531
4534
|
}
|
|
4532
|
-
const visitorId = getVisitorIdForSession(
|
|
4535
|
+
const visitorId = getVisitorIdForSession(cacheKey);
|
|
4533
4536
|
const POLL_LIMIT = 100;
|
|
4534
4537
|
try {
|
|
4535
4538
|
const messages = await getMessagesSince(conversationId, since, POLL_LIMIT);
|
|
@@ -5026,8 +5029,8 @@ app5.post("/verify-token", async (c) => {
|
|
|
5026
5029
|
}
|
|
5027
5030
|
await consumeMagicToken(result.grantId);
|
|
5028
5031
|
const accountId = result.accountId;
|
|
5029
|
-
const
|
|
5030
|
-
registerGrantSession(
|
|
5032
|
+
const cacheKey = crypto.randomUUID();
|
|
5033
|
+
registerGrantSession(cacheKey, accountId, agentSlug, {
|
|
5031
5034
|
grantId: result.grantId,
|
|
5032
5035
|
grantExpiresAt: result.expiresAt ?? void 0,
|
|
5033
5036
|
grantStatus: result.status,
|
|
@@ -5038,7 +5041,7 @@ app5.post("/verify-token", async (c) => {
|
|
|
5038
5041
|
clearAccessRateLimit(clientIp, agentSlug);
|
|
5039
5042
|
console.error(`[access-gate] verify-token ip=${clientIp} agent=${agentSlug} contact=${maskContact(result.contactValue)} result=success`);
|
|
5040
5043
|
return c.json({
|
|
5041
|
-
session_key:
|
|
5044
|
+
session_key: cacheKey,
|
|
5042
5045
|
grant: {
|
|
5043
5046
|
displayName: result.displayName,
|
|
5044
5047
|
contactValue: result.contactValue,
|
|
@@ -5106,8 +5109,8 @@ app5.post("/verify-otp", async (c) => {
|
|
|
5106
5109
|
}, remaining > 0 ? 401 : 429);
|
|
5107
5110
|
}
|
|
5108
5111
|
await consumeOtp(grant.grantId);
|
|
5109
|
-
const
|
|
5110
|
-
registerGrantSession(
|
|
5112
|
+
const cacheKey = crypto.randomUUID();
|
|
5113
|
+
registerGrantSession(cacheKey, account.accountId, agentSlug, {
|
|
5111
5114
|
grantId: grant.grantId,
|
|
5112
5115
|
grantExpiresAt: grant.expiresAt ?? void 0,
|
|
5113
5116
|
grantStatus: grant.status,
|
|
@@ -5118,7 +5121,7 @@ app5.post("/verify-otp", async (c) => {
|
|
|
5118
5121
|
clearAccessRateLimit(clientIp, agentSlug);
|
|
5119
5122
|
console.error(`[access-gate] verify-otp ip=${clientIp} agent=${agentSlug} phone=${maskContact(phone)} result=success`);
|
|
5120
5123
|
return c.json({
|
|
5121
|
-
session_key:
|
|
5124
|
+
session_key: cacheKey,
|
|
5122
5125
|
grant: {
|
|
5123
5126
|
displayName: grant.displayName,
|
|
5124
5127
|
contactValue: grant.contactValue,
|
|
@@ -5216,8 +5219,8 @@ app5.post("/login", async (c) => {
|
|
|
5216
5219
|
console.error(`[access-gate] login ip=${clientIp} agent=${agentSlug} contact=${maskContact(contact)} result=wrong_password`);
|
|
5217
5220
|
return c.json({ error: "Invalid credentials" }, 401);
|
|
5218
5221
|
}
|
|
5219
|
-
const
|
|
5220
|
-
registerGrantSession(
|
|
5222
|
+
const cacheKey = crypto.randomUUID();
|
|
5223
|
+
registerGrantSession(cacheKey, account.accountId, agentSlug, {
|
|
5221
5224
|
grantId: grant.grantId,
|
|
5222
5225
|
grantExpiresAt: grant.expiresAt ?? void 0,
|
|
5223
5226
|
grantStatus: grant.status,
|
|
@@ -5227,7 +5230,7 @@ app5.post("/login", async (c) => {
|
|
|
5227
5230
|
});
|
|
5228
5231
|
clearAccessRateLimit(clientIp, agentSlug);
|
|
5229
5232
|
console.error(`[access-gate] login ip=${clientIp} agent=${agentSlug} contact=${maskContact(contact)} result=success`);
|
|
5230
|
-
return c.json({ session_key:
|
|
5233
|
+
return c.json({ session_key: cacheKey, agent_id: agentSlug });
|
|
5231
5234
|
} catch (err) {
|
|
5232
5235
|
console.error(`[access-gate] login ip=${clientIp} agent=${agentSlug} error=${err instanceof Error ? err.message : String(err)}`);
|
|
5233
5236
|
return c.json({ error: "Internal server error" }, 500);
|
|
@@ -5386,11 +5389,11 @@ function verifyWebhookSecret(headerValue, storedSecret) {
|
|
|
5386
5389
|
}
|
|
5387
5390
|
async function handleInbound(params) {
|
|
5388
5391
|
const { chatId, senderId, text, botType, botToken, accountId, agentType } = params;
|
|
5389
|
-
const
|
|
5392
|
+
const cacheKey = `telegram:${chatId}`;
|
|
5390
5393
|
const gatewayChannel = agentType === "admin" ? "telegram-admin" : "telegram-dm";
|
|
5391
|
-
registerSession(
|
|
5394
|
+
registerSession(cacheKey, agentType, accountId);
|
|
5392
5395
|
console.error(
|
|
5393
|
-
`${TAG16} session registered:
|
|
5396
|
+
`${TAG16} session registered: cacheKey=${cacheKey} agentType=${agentType} botType=${botType} senderId=${senderId} accountId=${accountId.slice(0, 8)}\u2026`
|
|
5394
5397
|
);
|
|
5395
5398
|
const gatewayResult = await processInbound(text, gatewayChannel);
|
|
5396
5399
|
if (gatewayResult.screening.verdict === "discard") {
|
|
@@ -5404,7 +5407,7 @@ async function handleInbound(params) {
|
|
|
5404
5407
|
for await (const event of invokeAgent(
|
|
5405
5408
|
{ type: agentType },
|
|
5406
5409
|
gatewayResult.processedText,
|
|
5407
|
-
|
|
5410
|
+
cacheKey,
|
|
5408
5411
|
[],
|
|
5409
5412
|
void 0,
|
|
5410
5413
|
gatewayResult
|
|
@@ -6220,19 +6223,25 @@ app7.get("/messages", (c) => {
|
|
|
6220
6223
|
});
|
|
6221
6224
|
app7.get("/conversation-graph-state", async (c) => {
|
|
6222
6225
|
try {
|
|
6223
|
-
const
|
|
6226
|
+
const directCacheKey = c.req.query("cacheKey");
|
|
6224
6227
|
const jid = c.req.query("jid");
|
|
6225
6228
|
const accountIdQuery = c.req.query("accountId");
|
|
6226
|
-
let
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
+
let cacheKey;
|
|
6230
|
+
let accountId;
|
|
6231
|
+
if (directCacheKey) {
|
|
6232
|
+
cacheKey = directCacheKey;
|
|
6233
|
+
const m = directCacheKey.match(/^whatsapp:([^:]+)/);
|
|
6234
|
+
if (!m) {
|
|
6235
|
+
return c.json({ error: `cacheKey=${directCacheKey} not a recognised whatsapp cacheKey shape.` }, 400);
|
|
6236
|
+
}
|
|
6237
|
+
accountId = validateAccountId(m[1] ?? accountIdQuery ?? null);
|
|
6229
6238
|
} else {
|
|
6230
6239
|
if (!jid) {
|
|
6231
|
-
return c.json({ error: "Provide either
|
|
6240
|
+
return c.json({ error: "Provide either cacheKey or jid (with optional accountId)." }, 400);
|
|
6232
6241
|
}
|
|
6233
|
-
|
|
6242
|
+
accountId = validateAccountId(accountIdQuery ?? null);
|
|
6234
6243
|
if (isGroupJid(jid)) {
|
|
6235
|
-
|
|
6244
|
+
cacheKey = deriveCacheKey({
|
|
6236
6245
|
agentType: "public",
|
|
6237
6246
|
accountId,
|
|
6238
6247
|
senderPhone: "",
|
|
@@ -6242,9 +6251,9 @@ app7.get("/conversation-graph-state", async (c) => {
|
|
|
6242
6251
|
} else {
|
|
6243
6252
|
const e164 = jid.replace(/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i, "$1");
|
|
6244
6253
|
if (!/^\d+$/.test(e164)) {
|
|
6245
|
-
return c.json({ error: `Cannot derive
|
|
6254
|
+
return c.json({ error: `Cannot derive cacheKey from jid=${jid} \u2014 not a recognised user JID. Pass cacheKey explicitly.` }, 400);
|
|
6246
6255
|
}
|
|
6247
|
-
|
|
6256
|
+
cacheKey = deriveCacheKey({
|
|
6248
6257
|
agentType: "public",
|
|
6249
6258
|
accountId,
|
|
6250
6259
|
senderPhone: e164,
|
|
@@ -6252,8 +6261,9 @@ app7.get("/conversation-graph-state", async (c) => {
|
|
|
6252
6261
|
});
|
|
6253
6262
|
}
|
|
6254
6263
|
}
|
|
6264
|
+
const channelAddress = cacheKey.startsWith("whatsapp:") ? cacheKey.slice("whatsapp:".length) : cacheKey;
|
|
6255
6265
|
const cypher = `
|
|
6256
|
-
MATCH (c:Conversation {
|
|
6266
|
+
MATCH (c:Conversation {accountId: $accountId, channel: 'whatsapp', channelAddress: $channelAddress})
|
|
6257
6267
|
OPTIONAL MATCH (m:Message:WhatsAppMessage)-[:PART_OF]->(c)
|
|
6258
6268
|
RETURN
|
|
6259
6269
|
c.conversationId AS conversationId,
|
|
@@ -6270,7 +6280,7 @@ app7.get("/conversation-graph-state", async (c) => {
|
|
|
6270
6280
|
const rows = [];
|
|
6271
6281
|
try {
|
|
6272
6282
|
session = getSession();
|
|
6273
|
-
const result = await session.run(cypher, {
|
|
6283
|
+
const result = await session.run(cypher, { accountId, channelAddress });
|
|
6274
6284
|
for (const rec of result.records) {
|
|
6275
6285
|
if (conversationId === null) {
|
|
6276
6286
|
conversationId = rec.get("conversationId") ?? null;
|
|
@@ -6288,13 +6298,13 @@ app7.get("/conversation-graph-state", async (c) => {
|
|
|
6288
6298
|
}
|
|
6289
6299
|
} catch (err) {
|
|
6290
6300
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6291
|
-
console.error(`${TAG18} conversation-graph-state ERR
|
|
6292
|
-
return c.json({ error: `Graph query failed: ${msg}`,
|
|
6301
|
+
console.error(`${TAG18} conversation-graph-state ERR cacheKey=${cacheKey} reason=${msg}`);
|
|
6302
|
+
return c.json({ error: `Graph query failed: ${msg}`, cacheKey, cypher: cypher.trim() }, 500);
|
|
6293
6303
|
}
|
|
6294
6304
|
const ms = Date.now() - t0;
|
|
6295
|
-
console.error(`[mcp:whatsapp] tool=whatsapp-conversation-graph-state
|
|
6305
|
+
console.error(`[mcp:whatsapp] tool=whatsapp-conversation-graph-state cacheKey=${cacheKey} graphRows=${rows.length} conversationId=${conversationId ?? "null"} ms=${ms}`);
|
|
6296
6306
|
return c.json({
|
|
6297
|
-
|
|
6307
|
+
cacheKey,
|
|
6298
6308
|
conversationId,
|
|
6299
6309
|
graphRows: rows,
|
|
6300
6310
|
cypher: cypher.trim(),
|
|
@@ -7005,9 +7015,9 @@ async function resolveUserIdentity(accountId, userId) {
|
|
|
7005
7015
|
async function createAdminSession(accountId, thinkingView, userId, userName, role, avatar) {
|
|
7006
7016
|
const account = resolveAccount();
|
|
7007
7017
|
const effectiveThinkingView = thinkingView ?? account?.config.thinkingView ?? "default";
|
|
7008
|
-
const
|
|
7009
|
-
registerSession(
|
|
7010
|
-
if (userId) setWantsPriorConversation(
|
|
7018
|
+
const cacheKey = userId ? mintAdminSessionToken({ accountId, userId }) : crypto.randomUUID();
|
|
7019
|
+
registerSession(cacheKey, "admin", accountId, void 0, userId, userName, role);
|
|
7020
|
+
if (userId) setWantsPriorConversation(cacheKey);
|
|
7011
7021
|
let onboardingComplete = true;
|
|
7012
7022
|
try {
|
|
7013
7023
|
const step = await loadOnboardingStep(accountId);
|
|
@@ -7021,10 +7031,27 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
7021
7031
|
businessName = branding?.name || void 0;
|
|
7022
7032
|
} catch {
|
|
7023
7033
|
}
|
|
7024
|
-
|
|
7025
|
-
|
|
7034
|
+
let initialConversationId = null;
|
|
7035
|
+
try {
|
|
7036
|
+
const ensured = await ensureConversation(
|
|
7037
|
+
accountId,
|
|
7038
|
+
"admin",
|
|
7039
|
+
cacheKey,
|
|
7040
|
+
void 0,
|
|
7041
|
+
void 0,
|
|
7042
|
+
userId
|
|
7043
|
+
);
|
|
7044
|
+
if (ensured.conversationId) {
|
|
7045
|
+
initialConversationId = ensured.conversationId;
|
|
7046
|
+
setConversationIdForSession(cacheKey, ensured.conversationId);
|
|
7047
|
+
}
|
|
7048
|
+
} catch (err) {
|
|
7049
|
+
console.error(`[session] eager-ensureConversation FAILED at boot: ${err instanceof Error ? err.message : String(err)}`);
|
|
7050
|
+
}
|
|
7051
|
+
console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} admin session created: userId=${userId ?? "\u2013"} userName=${userName ?? "\u2013"} accountId=${accountId} conversationId=${initialConversationId ?? "unbound"} cacheKey=${cacheKey.slice(0, 8)}`);
|
|
7052
|
+
console.log(`[admin-session] role=${role ?? "null"} cacheKey=${cacheKey.slice(0, 8)} phase=create eager-ensured=${initialConversationId ? "true" : "false"}`);
|
|
7026
7053
|
return {
|
|
7027
|
-
session_key:
|
|
7054
|
+
session_key: cacheKey,
|
|
7028
7055
|
agent_id: "admin",
|
|
7029
7056
|
userId,
|
|
7030
7057
|
userName,
|
|
@@ -7033,16 +7060,16 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
7033
7060
|
thinkingView: effectiveThinkingView,
|
|
7034
7061
|
onboardingComplete,
|
|
7035
7062
|
businessName,
|
|
7036
|
-
conversationId:
|
|
7063
|
+
conversationId: initialConversationId
|
|
7037
7064
|
};
|
|
7038
7065
|
}
|
|
7039
7066
|
var app10 = new Hono();
|
|
7040
7067
|
app10.get("/", async (c) => {
|
|
7041
|
-
const
|
|
7042
|
-
if (!
|
|
7068
|
+
const cacheKey = c.req.query("session_key");
|
|
7069
|
+
if (!cacheKey || !validateSession(cacheKey, "admin").ok) {
|
|
7043
7070
|
return c.json({ error: "Invalid or expired admin session" }, 401);
|
|
7044
7071
|
}
|
|
7045
|
-
const accountId = getAccountIdForSession(
|
|
7072
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
7046
7073
|
if (!accountId) {
|
|
7047
7074
|
return c.json({ error: "Session has no account binding" }, 401);
|
|
7048
7075
|
}
|
|
@@ -7061,21 +7088,21 @@ app10.get("/", async (c) => {
|
|
|
7061
7088
|
businessName = branding?.name || void 0;
|
|
7062
7089
|
} catch {
|
|
7063
7090
|
}
|
|
7064
|
-
const role = getRoleForSession(
|
|
7065
|
-
console.log(`[admin-session] role=${role ?? "null"}
|
|
7066
|
-
const restoredUserId = getUserIdForSession(
|
|
7067
|
-
let restoredUserName = getUserNameForSession(
|
|
7091
|
+
const role = getRoleForSession(cacheKey);
|
|
7092
|
+
console.log(`[admin-session] role=${role ?? "null"} cacheKey=${cacheKey.slice(0, 8)} phase=restore`);
|
|
7093
|
+
const restoredUserId = getUserIdForSession(cacheKey);
|
|
7094
|
+
let restoredUserName = getUserNameForSession(cacheKey);
|
|
7068
7095
|
let restoredAvatar = null;
|
|
7069
7096
|
if (restoredUserId) {
|
|
7070
7097
|
const resolved = await resolveUserIdentity(accountId, restoredUserId);
|
|
7071
7098
|
restoredUserName = resolved.userName;
|
|
7072
7099
|
restoredAvatar = resolved.avatar;
|
|
7073
7100
|
if (resolved.userName !== void 0) {
|
|
7074
|
-
registerSession(
|
|
7101
|
+
registerSession(cacheKey, "admin", accountId, void 0, restoredUserId, resolved.userName, role ?? void 0);
|
|
7075
7102
|
}
|
|
7076
7103
|
}
|
|
7077
7104
|
return c.json({
|
|
7078
|
-
session_key:
|
|
7105
|
+
session_key: cacheKey,
|
|
7079
7106
|
agent_id: "admin",
|
|
7080
7107
|
userId: restoredUserId,
|
|
7081
7108
|
userName: restoredUserName,
|
|
@@ -7084,7 +7111,7 @@ app10.get("/", async (c) => {
|
|
|
7084
7111
|
thinkingView,
|
|
7085
7112
|
onboardingComplete,
|
|
7086
7113
|
businessName,
|
|
7087
|
-
conversationId: getConversationIdForSession(
|
|
7114
|
+
conversationId: getConversationIdForSession(cacheKey) ?? null
|
|
7088
7115
|
});
|
|
7089
7116
|
});
|
|
7090
7117
|
app10.post("/", async (c) => {
|
|
@@ -7435,7 +7462,7 @@ ${inner.content}`;
|
|
|
7435
7462
|
}
|
|
7436
7463
|
function chatReject(status, error, sk) {
|
|
7437
7464
|
const keyPrefix = sk ? sk.slice(0, 8) + "\u2026" : "none";
|
|
7438
|
-
console.log(`[session] chat-reject status=${status} reason="${error}"
|
|
7465
|
+
console.log(`[session] chat-reject status=${status} reason="${error}" cacheKey=${keyPrefix}`);
|
|
7439
7466
|
return new Response(JSON.stringify({ error }), {
|
|
7440
7467
|
status,
|
|
7441
7468
|
headers: { "Content-Type": "application/json" }
|
|
@@ -7443,9 +7470,9 @@ function chatReject(status, error, sk) {
|
|
|
7443
7470
|
}
|
|
7444
7471
|
var app11 = new Hono();
|
|
7445
7472
|
app11.post("/cancel", requireAdminSession, async (c) => {
|
|
7446
|
-
const session_key = c.var.
|
|
7473
|
+
const session_key = c.var.cacheKey;
|
|
7447
7474
|
try {
|
|
7448
|
-
const { interruptClient: interruptClient2 } = await import("./client-pool-
|
|
7475
|
+
const { interruptClient: interruptClient2 } = await import("./client-pool-AIZ5QKFD.js");
|
|
7449
7476
|
await interruptClient2(session_key);
|
|
7450
7477
|
return c.json({ ok: true });
|
|
7451
7478
|
} catch (err) {
|
|
@@ -7453,7 +7480,7 @@ app11.post("/cancel", requireAdminSession, async (c) => {
|
|
|
7453
7480
|
}
|
|
7454
7481
|
});
|
|
7455
7482
|
app11.post("/", requireAdminSession, async (c) => {
|
|
7456
|
-
const session_key = c.var.
|
|
7483
|
+
const session_key = c.var.cacheKey;
|
|
7457
7484
|
const contentType = c.req.header("content-type") ?? "";
|
|
7458
7485
|
let message;
|
|
7459
7486
|
let userTimestamp;
|
|
@@ -7534,7 +7561,7 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7534
7561
|
try {
|
|
7535
7562
|
const authResult = await ensureAuth();
|
|
7536
7563
|
if (authResult.status === "dead" || authResult.status === "missing") {
|
|
7537
|
-
console.log(`[session] chat-reject status=401 reason="auth_expired"
|
|
7564
|
+
console.log(`[session] chat-reject status=401 reason="auth_expired" cacheKey=${session_key.slice(0, 8)}\u2026 auth_status=${authResult.status}`);
|
|
7538
7565
|
return new Response(
|
|
7539
7566
|
JSON.stringify({ error: "auth_expired", auth_status: authResult.status }),
|
|
7540
7567
|
{ status: 401, headers: { "Content-Type": "application/json" } }
|
|
@@ -7622,10 +7649,10 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7622
7649
|
setAgentSessionId(session_key, prior.agentSessionId);
|
|
7623
7650
|
resumedAgentSessionId = prior.agentSessionId;
|
|
7624
7651
|
acquireReason = "pin-rebind";
|
|
7625
|
-
console.log(`[chat-route] resume-from-prior conversationId=${conversationId.slice(0, 8)}\u2026 priorAgentSessionId=${prior.agentSessionId.slice(0, 8)}\u2026
|
|
7652
|
+
console.log(`[chat-route] resume-from-prior conversationId=${conversationId.slice(0, 8)}\u2026 priorAgentSessionId=${prior.agentSessionId.slice(0, 8)}\u2026 cacheKey=${session_key.slice(0, 12)}\u2026`);
|
|
7626
7653
|
} else {
|
|
7627
7654
|
if (wantsPrior) {
|
|
7628
|
-
console.log(`[chat-route] prior-conversation-not-found accountId=${accountId.slice(0, 8)}\u2026 userId=${userId.slice(0, 8)}\u2026
|
|
7655
|
+
console.log(`[chat-route] prior-conversation-not-found accountId=${accountId.slice(0, 8)}\u2026 userId=${userId.slice(0, 8)}\u2026 cacheKey=${session_key.slice(0, 12)}\u2026 \u2014 cold-minting`);
|
|
7629
7656
|
}
|
|
7630
7657
|
const minted = randomUUID6();
|
|
7631
7658
|
const created = await createNewAdminConversation(userId, accountId, session_key, userName, minted);
|
|
@@ -7635,7 +7662,7 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7635
7662
|
conversationId = created;
|
|
7636
7663
|
setConversationIdForSession(session_key, conversationId);
|
|
7637
7664
|
acquireReason = "cold";
|
|
7638
|
-
console.log(`[chat-route] new conversation conversationId=${conversationId}
|
|
7665
|
+
console.log(`[chat-route] new conversation conversationId=${conversationId} cacheKey=${session_key.slice(0, 12)}\u2026`);
|
|
7639
7666
|
}
|
|
7640
7667
|
}
|
|
7641
7668
|
const encoder = new TextEncoder();
|
|
@@ -7643,12 +7670,12 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7643
7670
|
const sk = conversationId.slice(0, 8);
|
|
7644
7671
|
const teeStreamLogPath = resolve8(account.accountDir, "logs", `claude-agent-stream-${conversationId}.log`);
|
|
7645
7672
|
try {
|
|
7646
|
-
appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=task965-mint-at-entry]
|
|
7673
|
+
appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=task965-mint-at-entry] cacheKey=${session_key.slice(0, 12)}\u2026 conversationId=${conversationId}
|
|
7647
7674
|
`);
|
|
7648
7675
|
} catch {
|
|
7649
7676
|
}
|
|
7650
7677
|
try {
|
|
7651
|
-
appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [client-acquire]
|
|
7678
|
+
appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [client-acquire] cacheKey=${session_key.slice(0, 12)}\u2026 resume=${resumedAgentSessionId ? resumedAgentSessionId.slice(0, 8) + "\u2026" : "none"} reason=${acquireReason}
|
|
7652
7679
|
`);
|
|
7653
7680
|
} catch {
|
|
7654
7681
|
}
|
|
@@ -7657,12 +7684,12 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7657
7684
|
incoming.on("close", () => {
|
|
7658
7685
|
const tsClose = (/* @__PURE__ */ new Date()).toISOString();
|
|
7659
7686
|
try {
|
|
7660
|
-
appendFileSync3(teeStreamLogPath, `[${tsClose}] [incoming-close]
|
|
7687
|
+
appendFileSync3(teeStreamLogPath, `[${tsClose}] [incoming-close] cacheKey=${session_key.slice(0, 12)}\u2026 complete=${incoming.complete}
|
|
7661
7688
|
`);
|
|
7662
7689
|
} catch {
|
|
7663
7690
|
}
|
|
7664
7691
|
if (incoming.complete === false) {
|
|
7665
|
-
console.error(`[${tsClose}] [incoming-close] DISCONNECT
|
|
7692
|
+
console.error(`[${tsClose}] [incoming-close] DISCONNECT cacheKey=${session_key.slice(0, 12)}\u2026`);
|
|
7666
7693
|
interruptClient(session_key).catch((err) => {
|
|
7667
7694
|
try {
|
|
7668
7695
|
appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [incoming-close] interrupt-failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -7718,7 +7745,7 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7718
7745
|
const reasonStr = typeof reason === "string" ? reason : reason instanceof Error ? reason.message : "consumer-cancelled";
|
|
7719
7746
|
sseLog.write(`[${ts}] [${sk}] admin: CANCEL [stream-cancel] reason=${reasonStr}
|
|
7720
7747
|
`);
|
|
7721
|
-
console.error(`[${(/* @__PURE__ */ new Date()).toISOString()}] [stream-cancel-callback]
|
|
7748
|
+
console.error(`[${(/* @__PURE__ */ new Date()).toISOString()}] [stream-cancel-callback] cacheKey=${session_key.slice(0, 12)}\u2026 reason=${JSON.stringify(reasonStr)}`);
|
|
7722
7749
|
interruptClient(session_key).catch((err) => {
|
|
7723
7750
|
sseLog.write(`[${ts}] [${sk}] admin: ABORT [interrupt-failed] ${err instanceof Error ? err.message : String(err)}
|
|
7724
7751
|
`);
|
|
@@ -7726,7 +7753,7 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7726
7753
|
},
|
|
7727
7754
|
async start(controller) {
|
|
7728
7755
|
let controllerOpen = true;
|
|
7729
|
-
const sseEntry = { controller, conversationId,
|
|
7756
|
+
const sseEntry = { controller, conversationId, cacheKey: session_key };
|
|
7730
7757
|
try {
|
|
7731
7758
|
const reqSignal = c.req.raw?.signal;
|
|
7732
7759
|
if (reqSignal) {
|
|
@@ -7840,14 +7867,89 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7840
7867
|
});
|
|
7841
7868
|
var chat_default2 = app11;
|
|
7842
7869
|
|
|
7843
|
-
// server/routes/admin/
|
|
7870
|
+
// server/routes/admin/chat-failure.ts
|
|
7871
|
+
var MODE_VALUES = /* @__PURE__ */ new Set(["server-shutdown", "client-network-drop"]);
|
|
7872
|
+
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7873
|
+
var ISO_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
7874
|
+
function validate(body) {
|
|
7875
|
+
if (typeof body.mode !== "string" || !MODE_VALUES.has(body.mode)) {
|
|
7876
|
+
return { ok: false, reason: "mode" };
|
|
7877
|
+
}
|
|
7878
|
+
if (typeof body.at !== "string" || !ISO_RE.test(body.at)) {
|
|
7879
|
+
return { ok: false, reason: "at" };
|
|
7880
|
+
}
|
|
7881
|
+
if (body.conversationId !== null && (typeof body.conversationId !== "string" || !UUID_RE3.test(body.conversationId))) {
|
|
7882
|
+
return { ok: false, reason: "conversationId" };
|
|
7883
|
+
}
|
|
7884
|
+
if (typeof body.prior_event_count !== "number" || !Number.isInteger(body.prior_event_count) || body.prior_event_count < 0) {
|
|
7885
|
+
return { ok: false, reason: "prior_event_count" };
|
|
7886
|
+
}
|
|
7887
|
+
return {
|
|
7888
|
+
ok: true,
|
|
7889
|
+
value: {
|
|
7890
|
+
mode: body.mode,
|
|
7891
|
+
at: body.at,
|
|
7892
|
+
conversationId: body.conversationId,
|
|
7893
|
+
priorEventCount: body.prior_event_count
|
|
7894
|
+
}
|
|
7895
|
+
};
|
|
7896
|
+
}
|
|
7844
7897
|
var app12 = new Hono();
|
|
7845
7898
|
app12.post("/", requireAdminSession, async (c) => {
|
|
7846
|
-
|
|
7899
|
+
let body;
|
|
7900
|
+
try {
|
|
7901
|
+
body = await c.req.json();
|
|
7902
|
+
} catch {
|
|
7903
|
+
console.error(`[admin-chat-failure] persist kind=? conversationId=? writer=clientReport outcome=fail reason=body-not-json`);
|
|
7904
|
+
return c.json({ ok: false, reason: "body-not-json" }, 400);
|
|
7905
|
+
}
|
|
7906
|
+
const v = validate(body);
|
|
7907
|
+
if (!v.ok) {
|
|
7908
|
+
console.error(`[admin-chat-failure] persist kind=? conversationId=? writer=clientReport outcome=fail reason=schema:${v.reason}`);
|
|
7909
|
+
return c.json({ ok: false, reason: `schema:${v.reason}` }, 400);
|
|
7910
|
+
}
|
|
7911
|
+
const cacheKey = c.var.cacheKey;
|
|
7912
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
7913
|
+
if (!accountId) {
|
|
7914
|
+
console.error(`[admin-chat-failure] persist kind=${v.value.mode} conversationId=? writer=clientReport outcome=fail reason=no-account`);
|
|
7915
|
+
return c.json({ ok: false, reason: "no-account" }, 401);
|
|
7916
|
+
}
|
|
7917
|
+
const cid = v.value.conversationId;
|
|
7918
|
+
const cidTag = cid ? cid : "null";
|
|
7919
|
+
console.error(`[admin-chat] stream-drop kind=${v.value.mode} conversationId=${cidTag} at=${v.value.at}`);
|
|
7920
|
+
if (cid === null) {
|
|
7921
|
+
console.error(`[admin-chat-failure] persist kind=${v.value.mode} conversationId=null writer=clientReport outcome=skip reason=no-cid`);
|
|
7922
|
+
return c.body(null, 204);
|
|
7923
|
+
}
|
|
7924
|
+
const result = await writeTurnFailure({
|
|
7925
|
+
conversationId: cid,
|
|
7926
|
+
accountId,
|
|
7927
|
+
mode: v.value.mode,
|
|
7928
|
+
at: v.value.at,
|
|
7929
|
+
cacheKey,
|
|
7930
|
+
priorEventCount: v.value.priorEventCount
|
|
7931
|
+
});
|
|
7932
|
+
if (!result.ok) {
|
|
7933
|
+
if (result.reason === "cid-not-found") {
|
|
7934
|
+
console.error(`[admin-chat-failure] persist kind=${v.value.mode} conversationId=${cid} writer=clientReport outcome=skip reason=cid-not-found`);
|
|
7935
|
+
return c.body(null, 204);
|
|
7936
|
+
}
|
|
7937
|
+
console.error(`[admin-chat-failure] persist kind=${v.value.mode} conversationId=${cid} writer=clientReport outcome=fail reason=${result.reason}`);
|
|
7938
|
+
return c.json({ ok: false, reason: result.reason }, 500);
|
|
7939
|
+
}
|
|
7940
|
+
console.error(`[admin-chat-failure] persist kind=${v.value.mode} conversationId=${cid} writer=clientReport outcome=ok at=${result.at}`);
|
|
7941
|
+
return c.json({ ok: true, at: result.at });
|
|
7942
|
+
});
|
|
7943
|
+
var chat_failure_default = app12;
|
|
7944
|
+
|
|
7945
|
+
// server/routes/admin/compact.ts
|
|
7946
|
+
var app13 = new Hono();
|
|
7947
|
+
app13.post("/", requireAdminSession, async (c) => {
|
|
7948
|
+
const cacheKey = c.var.cacheKey;
|
|
7847
7949
|
const encoder = new TextEncoder();
|
|
7848
7950
|
const stream = new ReadableStream({
|
|
7849
7951
|
async start(controller) {
|
|
7850
|
-
const iter = compactSession(
|
|
7952
|
+
const iter = compactSession(cacheKey);
|
|
7851
7953
|
let step = await iter.next();
|
|
7852
7954
|
while (!step.done) {
|
|
7853
7955
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: "status", message: step.value })}
|
|
@@ -7869,18 +7971,18 @@ app12.post("/", requireAdminSession, async (c) => {
|
|
|
7869
7971
|
}
|
|
7870
7972
|
});
|
|
7871
7973
|
});
|
|
7872
|
-
var compact_default =
|
|
7974
|
+
var compact_default = app13;
|
|
7873
7975
|
|
|
7874
7976
|
// server/routes/admin/logs.ts
|
|
7875
7977
|
import { existsSync as existsSync12, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync6 } from "fs";
|
|
7876
7978
|
import { resolve as resolve9, basename as basename2 } from "path";
|
|
7877
7979
|
var TAIL_BYTES = 8192;
|
|
7878
|
-
var
|
|
7879
|
-
|
|
7980
|
+
var app14 = new Hono();
|
|
7981
|
+
app14.get("/", async (c) => {
|
|
7880
7982
|
const fileParam = c.req.query("file");
|
|
7881
7983
|
const typeParam = c.req.query("type");
|
|
7882
7984
|
const conversationIdParam = c.req.query("conversationId");
|
|
7883
|
-
const
|
|
7985
|
+
const cacheKeyParam = c.req.query("cacheKey");
|
|
7884
7986
|
const download = c.req.query("download") === "1";
|
|
7885
7987
|
const account = resolveAccount();
|
|
7886
7988
|
const accountLogDir = account ? resolve9(account.accountDir, "logs") : null;
|
|
@@ -7927,56 +8029,29 @@ app13.get("/", async (c) => {
|
|
|
7927
8029
|
400
|
|
7928
8030
|
);
|
|
7929
8031
|
}
|
|
7930
|
-
if (!conversationIdParam && !
|
|
8032
|
+
if (!conversationIdParam && !cacheKeyParam) {
|
|
7931
8033
|
console.warn(`[admin/logs] rejected type=${typeParam} reason=no-id`);
|
|
7932
8034
|
return c.json(
|
|
7933
|
-
{ error: `type=${typeParam} requires conversationId or
|
|
8035
|
+
{ error: `type=${typeParam} requires conversationId or cacheKey`, code: "ID_REQUIRED" },
|
|
7934
8036
|
400
|
|
7935
8037
|
);
|
|
7936
8038
|
}
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
if (!sessionKey && conversationId || sessionKey && !conversationId) {
|
|
7940
|
-
const neoSession = getSession();
|
|
7941
|
-
try {
|
|
7942
|
-
if (!sessionKey && conversationId) {
|
|
7943
|
-
const result = await neoSession.run(
|
|
7944
|
-
`MATCH (c:Conversation {conversationId: $conversationId})
|
|
7945
|
-
RETURN c.sessionKey AS sessionKey LIMIT 1`,
|
|
7946
|
-
{ conversationId }
|
|
7947
|
-
);
|
|
7948
|
-
const sk = result.records[0]?.get("sessionKey");
|
|
7949
|
-
if (typeof sk === "string" && sk.length > 0) sessionKey = sk;
|
|
7950
|
-
} else if (sessionKey && !conversationId) {
|
|
7951
|
-
const result = await neoSession.run(
|
|
7952
|
-
`MATCH (c:Conversation {sessionKey: $sessionKey})
|
|
7953
|
-
RETURN c.conversationId AS conversationId LIMIT 1`,
|
|
7954
|
-
{ sessionKey }
|
|
7955
|
-
);
|
|
7956
|
-
const cid = result.records[0]?.get("conversationId");
|
|
7957
|
-
if (typeof cid === "string" && cid.length > 0) conversationId = cid;
|
|
7958
|
-
}
|
|
7959
|
-
} catch (err) {
|
|
7960
|
-
const reason2 = err instanceof Error ? err.message : String(err);
|
|
7961
|
-
console.warn(`[admin/logs] id-lookup-neo4j-error sessionKey=${sessionKey ?? "none"} conversationId=${conversationId ?? "none"} reason=${reason2}`);
|
|
7962
|
-
} finally {
|
|
7963
|
-
await neoSession.close();
|
|
7964
|
-
}
|
|
7965
|
-
}
|
|
8039
|
+
const cacheKey = cacheKeyParam ?? null;
|
|
8040
|
+
const conversationId = conversationIdParam ?? null;
|
|
7966
8041
|
const MISSING_SENTINEL = ".task702-identifier-not-supplied.log";
|
|
7967
8042
|
const fullFilename = conversationId ? `${prefix}-${conversationId}.log` : MISSING_SENTINEL;
|
|
7968
|
-
const preflushFilename =
|
|
8043
|
+
const preflushFilename = cacheKey && typeParam === "public" ? `${prefix}-${preflushSliceOf(cacheKey)}.log` : MISSING_SENTINEL;
|
|
7969
8044
|
const { hits, stalePreflushPaths, tried } = resolveConversationLogPaths(
|
|
7970
8045
|
fullFilename,
|
|
7971
8046
|
preflushFilename,
|
|
7972
8047
|
logDirs
|
|
7973
8048
|
);
|
|
7974
8049
|
const stalePreflushCount = stalePreflushPaths.length;
|
|
7975
|
-
const
|
|
8050
|
+
const cacheKeySlice = cacheKey ? cacheKey.slice(0, 12) : "none";
|
|
7976
8051
|
const conversationIdSlice = conversationId ? conversationId.slice(0, 12) : "none";
|
|
7977
8052
|
if (hits.length > 0) {
|
|
7978
8053
|
const hit = hits[0];
|
|
7979
|
-
console.info(`[admin/logs] resolved
|
|
8054
|
+
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} conversationId=${conversationIdSlice} shape=${hit.shape} stalePreflushCount=${stalePreflushCount}`);
|
|
7980
8055
|
try {
|
|
7981
8056
|
const filename = basename2(hit.path);
|
|
7982
8057
|
if (stalePreflushCount > 0 && !download) {
|
|
@@ -8006,14 +8081,14 @@ app13.get("/", async (c) => {
|
|
|
8006
8081
|
);
|
|
8007
8082
|
}
|
|
8008
8083
|
}
|
|
8009
|
-
const reason = !conversationId ? "no preflush log on disk for
|
|
8010
|
-
console.warn(`[admin/logs] not-found tried=[${tried.join(",")}]
|
|
8084
|
+
const reason = !conversationId ? "no preflush log on disk for cacheKey and conversationId not derivable" : !cacheKey ? "no full log on disk and cacheKey not derivable" : "no preflush log, no full log";
|
|
8085
|
+
console.warn(`[admin/logs] not-found tried=[${tried.join(",")}] cacheKey=${cacheKeySlice} conversationId=${conversationIdSlice} reason=${JSON.stringify(reason)}`);
|
|
8011
8086
|
return c.json(
|
|
8012
8087
|
{
|
|
8013
8088
|
error: reason,
|
|
8014
8089
|
code: "NOT_FOUND",
|
|
8015
8090
|
reason,
|
|
8016
|
-
|
|
8091
|
+
cacheKey: cacheKey ?? null,
|
|
8017
8092
|
conversationId: conversationId ?? null
|
|
8018
8093
|
},
|
|
8019
8094
|
404
|
|
@@ -8046,12 +8121,12 @@ app13.get("/", async (c) => {
|
|
|
8046
8121
|
}
|
|
8047
8122
|
return c.json({ logs });
|
|
8048
8123
|
});
|
|
8049
|
-
var logs_default =
|
|
8124
|
+
var logs_default = app14;
|
|
8050
8125
|
|
|
8051
8126
|
// server/routes/admin/claude-info.ts
|
|
8052
8127
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
8053
|
-
var
|
|
8054
|
-
|
|
8128
|
+
var app15 = new Hono();
|
|
8129
|
+
app15.get("/", (c) => {
|
|
8055
8130
|
let version = "unknown";
|
|
8056
8131
|
try {
|
|
8057
8132
|
const raw = execFileSync2("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
|
|
@@ -8069,17 +8144,17 @@ app14.get("/", (c) => {
|
|
|
8069
8144
|
const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
|
|
8070
8145
|
return c.json({ version, account, model, thinkingView });
|
|
8071
8146
|
});
|
|
8072
|
-
var claude_info_default =
|
|
8147
|
+
var claude_info_default = app15;
|
|
8073
8148
|
|
|
8074
8149
|
// server/routes/admin/attachment.ts
|
|
8075
8150
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
8076
8151
|
import { existsSync as existsSync13 } from "fs";
|
|
8077
8152
|
import { resolve as resolve10 } from "path";
|
|
8078
|
-
var
|
|
8079
|
-
|
|
8153
|
+
var app16 = new Hono();
|
|
8154
|
+
app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
8080
8155
|
const attachmentId = c.req.param("attachmentId");
|
|
8081
|
-
const
|
|
8082
|
-
const accountId = getAccountIdForSession(
|
|
8156
|
+
const cacheKey = c.var.cacheKey;
|
|
8157
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8083
8158
|
if (!accountId) {
|
|
8084
8159
|
return new Response("Unauthorized", { status: 401 });
|
|
8085
8160
|
}
|
|
@@ -8115,13 +8190,13 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8115
8190
|
}
|
|
8116
8191
|
});
|
|
8117
8192
|
});
|
|
8118
|
-
var attachment_default =
|
|
8193
|
+
var attachment_default = app16;
|
|
8119
8194
|
|
|
8120
8195
|
// server/routes/admin/agents.ts
|
|
8121
8196
|
import { resolve as resolve11 } from "path";
|
|
8122
8197
|
import { readdirSync as readdirSync6, readFileSync as readFileSync12, existsSync as existsSync14, rmSync } from "fs";
|
|
8123
|
-
var
|
|
8124
|
-
|
|
8198
|
+
var app17 = new Hono();
|
|
8199
|
+
app17.get("/", (c) => {
|
|
8125
8200
|
const account = resolveAccount();
|
|
8126
8201
|
if (!account) return c.json({ agents: [] });
|
|
8127
8202
|
const agentsDir = resolve11(account.accountDir, "agents");
|
|
@@ -8151,7 +8226,7 @@ app16.get("/", (c) => {
|
|
|
8151
8226
|
}
|
|
8152
8227
|
return c.json({ agents });
|
|
8153
8228
|
});
|
|
8154
|
-
|
|
8229
|
+
app17.delete("/:slug", async (c) => {
|
|
8155
8230
|
const slug = c.req.param("slug");
|
|
8156
8231
|
const account = resolveAccount();
|
|
8157
8232
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -8181,7 +8256,7 @@ app16.delete("/:slug", async (c) => {
|
|
|
8181
8256
|
return c.json({ error: "Failed to delete agent" }, 500);
|
|
8182
8257
|
}
|
|
8183
8258
|
});
|
|
8184
|
-
|
|
8259
|
+
app17.post("/:slug/project", async (c) => {
|
|
8185
8260
|
const slug = c.req.param("slug");
|
|
8186
8261
|
const account = resolveAccount();
|
|
8187
8262
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -8203,7 +8278,7 @@ app16.post("/:slug/project", async (c) => {
|
|
|
8203
8278
|
return c.json({ error: `Projection failed: ${msg}` }, 500);
|
|
8204
8279
|
}
|
|
8205
8280
|
});
|
|
8206
|
-
var agents_default =
|
|
8281
|
+
var agents_default = app17;
|
|
8207
8282
|
|
|
8208
8283
|
// server/routes/admin/sessions.ts
|
|
8209
8284
|
import crypto2 from "crypto";
|
|
@@ -8471,19 +8546,19 @@ function formatAge(updatedAtStr) {
|
|
|
8471
8546
|
return "unknown";
|
|
8472
8547
|
}
|
|
8473
8548
|
}
|
|
8474
|
-
var
|
|
8475
|
-
|
|
8476
|
-
const
|
|
8477
|
-
const accountId = getAccountIdForSession(
|
|
8549
|
+
var app18 = new Hono();
|
|
8550
|
+
app18.get("/", requireAdminSession, async (c) => {
|
|
8551
|
+
const cacheKey = c.var.cacheKey;
|
|
8552
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8478
8553
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8479
|
-
const userId = getUserIdForSession(
|
|
8554
|
+
const userId = getUserIdForSession(cacheKey);
|
|
8480
8555
|
if (!userId) return c.json({ error: "User identity required \u2014 authenticate with users.json PIN" }, 401);
|
|
8481
8556
|
try {
|
|
8482
8557
|
const flushed = await listAdminSessions(accountId, userId, 20);
|
|
8483
8558
|
const inProgressRaw = listAdminSessionsInProgress(accountId, userId);
|
|
8484
8559
|
const flushedRows = flushed.map((r) => ({
|
|
8485
8560
|
conversationId: r.conversationId,
|
|
8486
|
-
|
|
8561
|
+
cacheKey: null,
|
|
8487
8562
|
name: r.name,
|
|
8488
8563
|
updatedAt: r.updatedAt,
|
|
8489
8564
|
phase: "flushed",
|
|
@@ -8491,7 +8566,7 @@ app17.get("/", requireAdminSession, async (c) => {
|
|
|
8491
8566
|
}));
|
|
8492
8567
|
const inProgressRows = inProgressRaw.map((r) => ({
|
|
8493
8568
|
conversationId: null,
|
|
8494
|
-
|
|
8569
|
+
cacheKey: r.cacheKey,
|
|
8495
8570
|
name: null,
|
|
8496
8571
|
updatedAt: new Date(r.createdAt).toISOString(),
|
|
8497
8572
|
phase: "pre-flush",
|
|
@@ -8512,52 +8587,52 @@ app17.get("/", requireAdminSession, async (c) => {
|
|
|
8512
8587
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
8513
8588
|
}
|
|
8514
8589
|
});
|
|
8515
|
-
|
|
8516
|
-
const
|
|
8517
|
-
const accountId = getAccountIdForSession(
|
|
8518
|
-
const userId = getUserIdForSession(
|
|
8590
|
+
app18.post("/new", requireAdminSession, async (c) => {
|
|
8591
|
+
const oldCacheKey = c.var.cacheKey;
|
|
8592
|
+
const accountId = getAccountIdForSession(oldCacheKey);
|
|
8593
|
+
const userId = getUserIdForSession(oldCacheKey);
|
|
8519
8594
|
if (!accountId || !userId) {
|
|
8520
8595
|
return c.json({ error: "Session missing account or user context" }, 400);
|
|
8521
8596
|
}
|
|
8522
|
-
const
|
|
8523
|
-
const userName = getUserNameForSession(
|
|
8524
|
-
registerSession(
|
|
8525
|
-
const previousConversationId = clearSessionHistory(
|
|
8526
|
-
unregisterSession(
|
|
8527
|
-
console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} session reset for new conversation:
|
|
8528
|
-
return c.json({ session_key:
|
|
8597
|
+
const newCacheKey = crypto2.randomUUID();
|
|
8598
|
+
const userName = getUserNameForSession(oldCacheKey);
|
|
8599
|
+
registerSession(newCacheKey, "admin", accountId, void 0, userId, userName);
|
|
8600
|
+
const previousConversationId = clearSessionHistory(oldCacheKey);
|
|
8601
|
+
unregisterSession(oldCacheKey);
|
|
8602
|
+
console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} session reset for new conversation: oldCacheKey=${oldCacheKey.slice(0, 8)}\u2026 newCacheKey=${newCacheKey.slice(0, 8)}\u2026 previousConversationId=${previousConversationId?.slice(0, 8) ?? "none"}\u2026 newConversationId=deferred`);
|
|
8603
|
+
return c.json({ session_key: newCacheKey, conversationId: null });
|
|
8529
8604
|
});
|
|
8530
|
-
|
|
8531
|
-
const
|
|
8532
|
-
const accountId = getAccountIdForSession(
|
|
8533
|
-
const userId = getUserIdForSession(
|
|
8605
|
+
app18.post("/switch", requireAdminSession, async (c) => {
|
|
8606
|
+
const cacheKey = c.var.cacheKey;
|
|
8607
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8608
|
+
const userId = getUserIdForSession(cacheKey);
|
|
8534
8609
|
if (!accountId || !userId) {
|
|
8535
8610
|
return c.json({ error: "Session missing account or user context" }, 400);
|
|
8536
8611
|
}
|
|
8537
8612
|
const body = await c.req.json().catch(() => ({}));
|
|
8538
|
-
const
|
|
8539
|
-
if (!
|
|
8613
|
+
const targetCacheKey = typeof body.target_session_key === "string" ? body.target_session_key : "";
|
|
8614
|
+
if (!targetCacheKey) {
|
|
8540
8615
|
return c.json({ error: "target_session_key required" }, 400);
|
|
8541
8616
|
}
|
|
8542
|
-
const targetCheck = validateSession(
|
|
8617
|
+
const targetCheck = validateSession(targetCacheKey, "admin");
|
|
8543
8618
|
if (!targetCheck.ok) {
|
|
8544
|
-
console.error(`[session-switch] reject reason=${targetCheck.reason} from=${
|
|
8619
|
+
console.error(`[session-switch] reject reason=${targetCheck.reason} from=${cacheKey.slice(0, 8)} target=${targetCacheKey.slice(0, 8)}`);
|
|
8545
8620
|
return c.json({ error: "Target session not registered or wrong agent type", code: targetCheck.reason }, 404);
|
|
8546
8621
|
}
|
|
8547
|
-
const targetAccountId = getAccountIdForSession(
|
|
8548
|
-
const targetUserId = getUserIdForSession(
|
|
8622
|
+
const targetAccountId = getAccountIdForSession(targetCacheKey);
|
|
8623
|
+
const targetUserId = getUserIdForSession(targetCacheKey);
|
|
8549
8624
|
if (targetAccountId !== accountId || targetUserId !== userId) {
|
|
8550
|
-
console.error(`[session-switch] reject reason=ownership-mismatch from=${
|
|
8625
|
+
console.error(`[session-switch] reject reason=ownership-mismatch from=${cacheKey.slice(0, 8)} target=${targetCacheKey.slice(0, 8)} accountMatch=${targetAccountId === accountId} userMatch=${targetUserId === userId}`);
|
|
8551
8626
|
return c.json({ error: "Target session not owned by current operator" }, 403);
|
|
8552
8627
|
}
|
|
8553
|
-
const targetConversationId = getConversationIdForSession(
|
|
8554
|
-
console.log(`[session-switch] from=${
|
|
8555
|
-
return c.json({ session_key:
|
|
8628
|
+
const targetConversationId = getConversationIdForSession(targetCacheKey) ?? null;
|
|
8629
|
+
console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetConversationId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
|
|
8630
|
+
return c.json({ session_key: targetCacheKey, conversationId: targetConversationId });
|
|
8556
8631
|
});
|
|
8557
|
-
|
|
8632
|
+
app18.delete("/:id", requireAdminSession, async (c) => {
|
|
8558
8633
|
const conversationId = c.req.param("id");
|
|
8559
|
-
const
|
|
8560
|
-
const accountId = getAccountIdForSession(
|
|
8634
|
+
const cacheKey = c.var.cacheKey;
|
|
8635
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8561
8636
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8562
8637
|
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
8563
8638
|
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
@@ -8569,42 +8644,42 @@ app17.delete("/:id", requireAdminSession, async (c) => {
|
|
|
8569
8644
|
return c.json({ error: "Failed to delete session" }, 500);
|
|
8570
8645
|
}
|
|
8571
8646
|
});
|
|
8572
|
-
|
|
8647
|
+
app18.post("/:id/resume", async (c) => {
|
|
8573
8648
|
const conversationId = c.req.param("id");
|
|
8574
|
-
const
|
|
8575
|
-
if (!
|
|
8649
|
+
const cacheKey = c.req.query("session_key") ?? "";
|
|
8650
|
+
if (!cacheKey) {
|
|
8576
8651
|
console.error(`[session] middleware-reject status=400 code=session-missing reason="session_key required" path=${c.req.path}`);
|
|
8577
8652
|
return c.json({ error: "session_key required", code: "session-missing" }, 400);
|
|
8578
8653
|
}
|
|
8579
8654
|
let bridged = false;
|
|
8580
|
-
let result = validateSession(
|
|
8655
|
+
let result = validateSession(cacheKey, "admin");
|
|
8581
8656
|
if (!result.ok) {
|
|
8582
8657
|
if (result.reason === "session-not-registered") {
|
|
8583
|
-
const bridge = await tryCookieBridgeForConversation(c,
|
|
8658
|
+
const bridge = await tryCookieBridgeForConversation(c, cacheKey, conversationId);
|
|
8584
8659
|
if (!bridge.ok) {
|
|
8585
8660
|
if (bridge.reason === "conversation-not-found") {
|
|
8586
8661
|
return c.json({ error: "Conversation not found" }, 404);
|
|
8587
8662
|
}
|
|
8588
|
-
const tail =
|
|
8589
|
-
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="cookie-bridge-rejected:${bridge.reason}" path=${c.req.path}
|
|
8663
|
+
const tail = cacheKey.slice(0, 8);
|
|
8664
|
+
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="cookie-bridge-rejected:${bridge.reason}" path=${c.req.path} cacheKey=${tail}\u2026`);
|
|
8590
8665
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
8591
8666
|
}
|
|
8592
8667
|
bridged = true;
|
|
8593
|
-
result = validateSession(
|
|
8668
|
+
result = validateSession(cacheKey, "admin");
|
|
8594
8669
|
if (!result.ok) {
|
|
8595
|
-
const tail =
|
|
8596
|
-
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="post-bridge re-validate failed" path=${c.req.path}
|
|
8670
|
+
const tail = cacheKey.slice(0, 8);
|
|
8671
|
+
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="post-bridge re-validate failed" path=${c.req.path} cacheKey=${tail}\u2026`);
|
|
8597
8672
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
8598
8673
|
}
|
|
8599
8674
|
} else {
|
|
8600
|
-
const tail =
|
|
8675
|
+
const tail = cacheKey.slice(0, 8);
|
|
8601
8676
|
const wireCode = result.reason === "agent-type-mismatch" ? "session-not-registered" : result.reason;
|
|
8602
|
-
console.error(`[session] middleware-reject status=401 code=${wireCode} reason="invalid or expired admin session" path=${c.req.path}
|
|
8677
|
+
console.error(`[session] middleware-reject status=401 code=${wireCode} reason="invalid or expired admin session" path=${c.req.path} cacheKey=${tail}\u2026`);
|
|
8603
8678
|
return c.json({ error: "Invalid or expired admin session", code: wireCode }, 401);
|
|
8604
8679
|
}
|
|
8605
8680
|
}
|
|
8606
|
-
const accountId = getAccountIdForSession(
|
|
8607
|
-
const userId = getUserIdForSession(
|
|
8681
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8682
|
+
const userId = getUserIdForSession(cacheKey);
|
|
8608
8683
|
if (!accountId) {
|
|
8609
8684
|
return c.json({ error: "Session missing account context" }, 400);
|
|
8610
8685
|
}
|
|
@@ -8614,9 +8689,9 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8614
8689
|
const updatedAt = await verifyAndGetConversationUpdatedAt(conversationId, accountId);
|
|
8615
8690
|
if (updatedAt === null) return c.json({ error: "Conversation not found" }, 404);
|
|
8616
8691
|
const persistedAgentSessionId = await getAgentSessionIdForConversation(conversationId);
|
|
8617
|
-
setConversationIdForSession(
|
|
8692
|
+
setConversationIdForSession(cacheKey, conversationId);
|
|
8618
8693
|
if (persistedAgentSessionId) {
|
|
8619
|
-
setAgentSessionId(
|
|
8694
|
+
setAgentSessionId(cacheKey, persistedAgentSessionId);
|
|
8620
8695
|
}
|
|
8621
8696
|
const streamLogPath = resolvePath(ACCOUNTS_DIR, accountId, "logs", `claude-agent-stream-${conversationId}.log`);
|
|
8622
8697
|
const tag = persistedAgentSessionId ? `agentSessionId=${persistedAgentSessionId.slice(0, 8)}\u2026` : "agentSessionId=missing";
|
|
@@ -8641,7 +8716,7 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8641
8716
|
jsonlMalformedLines = replay.malformedLines;
|
|
8642
8717
|
jsonlReplayMessages = replay.messages;
|
|
8643
8718
|
if (replay.jsonlMissing) {
|
|
8644
|
-
console.error(`[jsonl-resume-miss]
|
|
8719
|
+
console.error(`[jsonl-resume-miss] cacheKey=${cacheKey.slice(0, 8)}\u2026 conversationId=${conversationId.slice(0, 8)}\u2026 agentSessionId=${persistedAgentSessionId.slice(0, 8)}\u2026 expectedPath=${jsonlPath} configDir=${process.env.CLAUDE_CONFIG_DIR ?? "<unset>"}`);
|
|
8645
8720
|
}
|
|
8646
8721
|
} else {
|
|
8647
8722
|
jsonlMissing = true;
|
|
@@ -8804,7 +8879,7 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8804
8879
|
const reason = bridged ? "post-restart" : "page-refresh";
|
|
8805
8880
|
try {
|
|
8806
8881
|
const source = jsonlMissing ? persistedAgentSessionId ? "jsonl-missing" : "neo4j-only" : "jsonl";
|
|
8807
|
-
appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} source=${source}
|
|
8882
|
+
appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} source=${source} cacheKey=${cacheKey.slice(0, 8)} conversationId=${conversationId.slice(0, 8)} ${tag} loadedMessages=${messages.length} jsonlReplayMessages=${jsonlReplayMessages.length} neo4jMessages=${neo4jMessages.length} jsonlMalformed=${jsonlMalformedLines} componentCount=${totalComponents} userAttachmentCount=${totalAttachments} syntheticHidden=${syntheticHidden}
|
|
8808
8883
|
`);
|
|
8809
8884
|
if (totalComponents > 0) {
|
|
8810
8885
|
appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-rehydrate] conversationId=${conversationId.slice(0, 8)} count=${totalComponents} valid=${totalValid} invalid=${totalInvalid} textRuns=${textRuns}
|
|
@@ -8821,7 +8896,7 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8821
8896
|
} catch {
|
|
8822
8897
|
}
|
|
8823
8898
|
const age = formatAge(updatedAt);
|
|
8824
|
-
console.log(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} reason=${reason} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages ${tag} components=${totalComponents} attachments=${totalAttachments} syntheticHidden=${syntheticHidden} jsonlMissing=${jsonlMissing} healMissing=${jsonlHealMissing}
|
|
8899
|
+
console.log(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} reason=${reason} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages ${tag} components=${totalComponents} attachments=${totalAttachments} syntheticHidden=${syntheticHidden} jsonlMissing=${jsonlMissing} healMissing=${jsonlHealMissing} cacheKey=${cacheKey.slice(0, 8)}\u2026`);
|
|
8825
8900
|
return c.json({
|
|
8826
8901
|
conversationId,
|
|
8827
8902
|
messages: rehydrated,
|
|
@@ -8834,10 +8909,10 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8834
8909
|
}
|
|
8835
8910
|
});
|
|
8836
8911
|
});
|
|
8837
|
-
|
|
8912
|
+
app18.post("/:id/label", requireAdminSession, async (c) => {
|
|
8838
8913
|
const conversationId = c.req.param("id");
|
|
8839
|
-
const
|
|
8840
|
-
const accountId = getAccountIdForSession(
|
|
8914
|
+
const cacheKey = c.var.cacheKey;
|
|
8915
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8841
8916
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8842
8917
|
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
8843
8918
|
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
@@ -8861,16 +8936,16 @@ app17.post("/:id/label", requireAdminSession, async (c) => {
|
|
|
8861
8936
|
return c.json({ label: null });
|
|
8862
8937
|
}
|
|
8863
8938
|
});
|
|
8864
|
-
|
|
8939
|
+
app18.put("/:id/label", requireAdminSession, async (c) => {
|
|
8865
8940
|
const conversationId = c.req.param("id");
|
|
8866
|
-
const
|
|
8941
|
+
const cacheKey = c.var.cacheKey;
|
|
8867
8942
|
let body;
|
|
8868
8943
|
try {
|
|
8869
8944
|
body = await c.req.json();
|
|
8870
8945
|
} catch {
|
|
8871
8946
|
return c.json({ error: "Invalid JSON body" }, 400);
|
|
8872
8947
|
}
|
|
8873
|
-
const accountId = getAccountIdForSession(
|
|
8948
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8874
8949
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8875
8950
|
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
8876
8951
|
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
@@ -8887,11 +8962,11 @@ app17.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
8887
8962
|
return c.json({ error: "Failed to rename session" }, 500);
|
|
8888
8963
|
}
|
|
8889
8964
|
});
|
|
8890
|
-
var sessions_default =
|
|
8965
|
+
var sessions_default = app18;
|
|
8891
8966
|
|
|
8892
8967
|
// server/routes/admin/browser.ts
|
|
8893
|
-
var
|
|
8894
|
-
|
|
8968
|
+
var app19 = new Hono();
|
|
8969
|
+
app19.post("/launch", async (c) => {
|
|
8895
8970
|
try {
|
|
8896
8971
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
8897
8972
|
if (transport === "vnc") {
|
|
@@ -8913,7 +8988,7 @@ app18.post("/launch", async (c) => {
|
|
|
8913
8988
|
);
|
|
8914
8989
|
}
|
|
8915
8990
|
});
|
|
8916
|
-
var browser_default =
|
|
8991
|
+
var browser_default = app19;
|
|
8917
8992
|
|
|
8918
8993
|
// server/routes/admin/browser-iframe.ts
|
|
8919
8994
|
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
@@ -8930,8 +9005,8 @@ function asString(v, max = 500) {
|
|
|
8930
9005
|
function asNumber(v) {
|
|
8931
9006
|
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
8932
9007
|
}
|
|
8933
|
-
var
|
|
8934
|
-
|
|
9008
|
+
var app20 = new Hono();
|
|
9009
|
+
app20.post("/event", async (c) => {
|
|
8935
9010
|
let body = {};
|
|
8936
9011
|
try {
|
|
8937
9012
|
body = await c.req.json();
|
|
@@ -8952,7 +9027,7 @@ app19.post("/event", async (c) => {
|
|
|
8952
9027
|
});
|
|
8953
9028
|
return c.body(null, 204);
|
|
8954
9029
|
});
|
|
8955
|
-
var browser_iframe_default =
|
|
9030
|
+
var browser_iframe_default = app20;
|
|
8956
9031
|
|
|
8957
9032
|
// app/lib/cdp-client.ts
|
|
8958
9033
|
var CDP_HOST = "127.0.0.1";
|
|
@@ -8995,8 +9070,8 @@ async function cdpNavigateNewTab(url, opts = {}) {
|
|
|
8995
9070
|
}
|
|
8996
9071
|
|
|
8997
9072
|
// server/routes/admin/device-browser.ts
|
|
8998
|
-
var
|
|
8999
|
-
|
|
9073
|
+
var app21 = new Hono();
|
|
9074
|
+
app21.post("/navigate", async (c) => {
|
|
9000
9075
|
const TAG19 = "[device-url:click]";
|
|
9001
9076
|
let body;
|
|
9002
9077
|
try {
|
|
@@ -9083,7 +9158,7 @@ app20.post("/navigate", async (c) => {
|
|
|
9083
9158
|
targetId: outcome.targetId
|
|
9084
9159
|
});
|
|
9085
9160
|
});
|
|
9086
|
-
var device_browser_default =
|
|
9161
|
+
var device_browser_default = app21;
|
|
9087
9162
|
|
|
9088
9163
|
// server/routes/admin/events.ts
|
|
9089
9164
|
var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
|
|
@@ -9092,8 +9167,8 @@ var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
|
|
|
9092
9167
|
"device-url:vnc-surface-shown",
|
|
9093
9168
|
"device-url:malformed"
|
|
9094
9169
|
]);
|
|
9095
|
-
var
|
|
9096
|
-
|
|
9170
|
+
var app22 = new Hono();
|
|
9171
|
+
app22.post("/", async (c) => {
|
|
9097
9172
|
const TAG19 = "[admin:events]";
|
|
9098
9173
|
let body;
|
|
9099
9174
|
try {
|
|
@@ -9124,7 +9199,7 @@ app21.post("/", async (c) => {
|
|
|
9124
9199
|
console.error(`[${event}] ${formatted}`);
|
|
9125
9200
|
return c.json({ ok: true });
|
|
9126
9201
|
});
|
|
9127
|
-
var events_default =
|
|
9202
|
+
var events_default = app22;
|
|
9128
9203
|
|
|
9129
9204
|
// server/routes/admin/cloudflare.ts
|
|
9130
9205
|
import { homedir as homedir2 } from "os";
|
|
@@ -9242,7 +9317,7 @@ function validateBody(body) {
|
|
|
9242
9317
|
}
|
|
9243
9318
|
return null;
|
|
9244
9319
|
}
|
|
9245
|
-
var
|
|
9320
|
+
var app23 = new Hono();
|
|
9246
9321
|
function fieldFromReason(reason) {
|
|
9247
9322
|
switch (reason) {
|
|
9248
9323
|
case "not-signed-in":
|
|
@@ -9263,15 +9338,15 @@ function fieldFromReason(reason) {
|
|
|
9263
9338
|
return "script";
|
|
9264
9339
|
}
|
|
9265
9340
|
}
|
|
9266
|
-
|
|
9341
|
+
app23.get("/domains", requireAdminSession, async (c) => {
|
|
9267
9342
|
const started = Date.now();
|
|
9268
|
-
const
|
|
9343
|
+
const cacheKey = c.var.cacheKey;
|
|
9269
9344
|
let correlationId;
|
|
9270
|
-
let
|
|
9345
|
+
let cacheKeyTail;
|
|
9271
9346
|
let streamLogPath;
|
|
9272
9347
|
function tag() {
|
|
9273
9348
|
if (!correlationId) return "";
|
|
9274
|
-
return ` conversationId=${correlationId} session_key=${
|
|
9349
|
+
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9275
9350
|
}
|
|
9276
9351
|
function log(line) {
|
|
9277
9352
|
console.log(`[cloudflare-domains] ${line}${tag()}`);
|
|
@@ -9299,9 +9374,9 @@ app22.get("/domains", requireAdminSession, async (c) => {
|
|
|
9299
9374
|
};
|
|
9300
9375
|
return c.json(body, 200);
|
|
9301
9376
|
}
|
|
9302
|
-
const accountId = getAccountIdForSession(
|
|
9303
|
-
correlationId = getConversationIdForSession(
|
|
9304
|
-
|
|
9377
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9378
|
+
correlationId = getConversationIdForSession(cacheKey);
|
|
9379
|
+
cacheKeyTail = cacheKey.slice(-8);
|
|
9305
9380
|
if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
|
|
9306
9381
|
if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
|
|
9307
9382
|
streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
|
|
@@ -9358,15 +9433,15 @@ ${result.stderr}` : ""}`;
|
|
|
9358
9433
|
return c.json(success, 200);
|
|
9359
9434
|
});
|
|
9360
9435
|
var TUNNELS_TIMEOUT_MS = 30 * 1e3;
|
|
9361
|
-
|
|
9436
|
+
app23.get("/tunnels", requireAdminSession, async (c) => {
|
|
9362
9437
|
const started = Date.now();
|
|
9363
|
-
const
|
|
9438
|
+
const cacheKey = c.var.cacheKey;
|
|
9364
9439
|
let correlationId;
|
|
9365
|
-
let
|
|
9440
|
+
let cacheKeyTail;
|
|
9366
9441
|
let streamLogPath;
|
|
9367
9442
|
function tag() {
|
|
9368
9443
|
if (!correlationId) return "";
|
|
9369
|
-
return ` conversationId=${correlationId} session_key=${
|
|
9444
|
+
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9370
9445
|
}
|
|
9371
9446
|
function log(line) {
|
|
9372
9447
|
console.log(`[cloudflare-tunnels] ${line}${tag()}`);
|
|
@@ -9391,9 +9466,9 @@ app22.get("/tunnels", requireAdminSession, async (c) => {
|
|
|
9391
9466
|
const body = { ok: false, field, message, output, defaultName, correlationId, streamLogPath };
|
|
9392
9467
|
return c.json(body, 200);
|
|
9393
9468
|
}
|
|
9394
|
-
const accountId = getAccountIdForSession(
|
|
9395
|
-
correlationId = getConversationIdForSession(
|
|
9396
|
-
|
|
9469
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9470
|
+
correlationId = getConversationIdForSession(cacheKey);
|
|
9471
|
+
cacheKeyTail = cacheKey.slice(-8);
|
|
9397
9472
|
if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
|
|
9398
9473
|
if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
|
|
9399
9474
|
streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
|
|
@@ -9454,15 +9529,15 @@ ${result.stderr}` : ""}`;
|
|
|
9454
9529
|
const success = { ok: true, tunnels, defaultName, correlationId, streamLogPath };
|
|
9455
9530
|
return c.json(success, 200);
|
|
9456
9531
|
});
|
|
9457
|
-
|
|
9532
|
+
app23.post("/setup", requireAdminSession, async (c) => {
|
|
9458
9533
|
const started = Date.now();
|
|
9459
|
-
const
|
|
9534
|
+
const cacheKey = c.var.cacheKey;
|
|
9460
9535
|
let correlationId;
|
|
9461
|
-
let
|
|
9536
|
+
let cacheKeyTail;
|
|
9462
9537
|
let streamLogPath;
|
|
9463
9538
|
function tag() {
|
|
9464
9539
|
if (!correlationId) return "";
|
|
9465
|
-
return ` conversationId=${correlationId} session_key=${
|
|
9540
|
+
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9466
9541
|
}
|
|
9467
9542
|
function log(line) {
|
|
9468
9543
|
console.log(`[cloudflare-setup] ${line}${tag()}`);
|
|
@@ -9498,9 +9573,9 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9498
9573
|
} catch {
|
|
9499
9574
|
return err("request", "Invalid JSON body");
|
|
9500
9575
|
}
|
|
9501
|
-
const accountId = getAccountIdForSession(
|
|
9502
|
-
correlationId = getConversationIdForSession(
|
|
9503
|
-
|
|
9576
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9577
|
+
correlationId = getConversationIdForSession(cacheKey);
|
|
9578
|
+
cacheKeyTail = cacheKey.slice(-8);
|
|
9504
9579
|
if (!accountId) {
|
|
9505
9580
|
return err("request", "No account bound to session \u2014 refresh chat.");
|
|
9506
9581
|
}
|
|
@@ -9553,7 +9628,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9553
9628
|
try {
|
|
9554
9629
|
cloudflareTask = await openCloudflareTask({
|
|
9555
9630
|
accountId,
|
|
9556
|
-
|
|
9631
|
+
conversationId: correlationId,
|
|
9557
9632
|
inputsProvided: Object.keys(taskInputs),
|
|
9558
9633
|
inputs: taskInputs,
|
|
9559
9634
|
inputSchema: CLOUDFLARE_SETUP_FORM_SCHEMA,
|
|
@@ -9601,7 +9676,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9601
9676
|
taskId: cloudflareTask.taskId,
|
|
9602
9677
|
taskElementId: cloudflareTask.taskElementId,
|
|
9603
9678
|
accountId,
|
|
9604
|
-
|
|
9679
|
+
conversationId: correlationId,
|
|
9605
9680
|
status: "failed",
|
|
9606
9681
|
errorMessage: CLOUDFLARE_TASK_DIAGNOSTICS.endpointDiedPreReconcile
|
|
9607
9682
|
});
|
|
@@ -9618,7 +9693,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9618
9693
|
taskId: cloudflareTask.taskId,
|
|
9619
9694
|
taskElementId: cloudflareTask.taskElementId,
|
|
9620
9695
|
accountId,
|
|
9621
|
-
|
|
9696
|
+
conversationId: correlationId,
|
|
9622
9697
|
status: "failed",
|
|
9623
9698
|
errorMessage: `${CLOUDFLARE_TASK_DIAGNOSTICS.scriptExitedNonzero} exit=${status.execMainStatus}`
|
|
9624
9699
|
});
|
|
@@ -9660,7 +9735,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9660
9735
|
taskId: cloudflareTask.taskId,
|
|
9661
9736
|
taskElementId: cloudflareTask.taskElementId,
|
|
9662
9737
|
accountId,
|
|
9663
|
-
|
|
9738
|
+
conversationId: correlationId,
|
|
9664
9739
|
tunnelId: tunnelState?.tunnelId,
|
|
9665
9740
|
tunnelName: tunnelState?.tunnelName,
|
|
9666
9741
|
hostnames: tunnelState ? hostnameRecords : void 0,
|
|
@@ -9691,7 +9766,7 @@ actionId: ${actionId}`,
|
|
|
9691
9766
|
};
|
|
9692
9767
|
return ok(success);
|
|
9693
9768
|
});
|
|
9694
|
-
var cloudflare_default =
|
|
9769
|
+
var cloudflare_default = app23;
|
|
9695
9770
|
|
|
9696
9771
|
// server/routes/admin/files.ts
|
|
9697
9772
|
import { createReadStream as createReadStream3 } from "fs";
|
|
@@ -9751,7 +9826,7 @@ var UNIQUE_KEYS_BY_LABEL = {
|
|
|
9751
9826
|
Event: ["eventId"],
|
|
9752
9827
|
KnowledgeDocument: ["attachmentId"],
|
|
9753
9828
|
DigitalDocument: ["attachmentId"],
|
|
9754
|
-
Conversation: ["conversationId"
|
|
9829
|
+
Conversation: ["conversationId"],
|
|
9755
9830
|
Message: ["messageId"],
|
|
9756
9831
|
OnboardingState: ["accountId"],
|
|
9757
9832
|
Workflow: ["workflowId"],
|
|
@@ -9972,7 +10047,7 @@ async function restoreNode(params) {
|
|
|
9972
10047
|
}
|
|
9973
10048
|
|
|
9974
10049
|
// app/lib/file-delete-cascade.ts
|
|
9975
|
-
var
|
|
10050
|
+
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9976
10051
|
function parseAttachmentPath(relPath2) {
|
|
9977
10052
|
const segments = relPath2.split("/").filter(Boolean);
|
|
9978
10053
|
if (segments.length !== 4) return null;
|
|
@@ -9980,7 +10055,7 @@ function parseAttachmentPath(relPath2) {
|
|
|
9980
10055
|
const accountId = segments[1];
|
|
9981
10056
|
const attachmentId = segments[2];
|
|
9982
10057
|
const filename = segments[3];
|
|
9983
|
-
if (!
|
|
10058
|
+
if (!UUID_RE4.test(accountId) || !UUID_RE4.test(attachmentId)) return null;
|
|
9984
10059
|
const dot = filename.lastIndexOf(".");
|
|
9985
10060
|
if (dot === -1) return null;
|
|
9986
10061
|
const stem = filename.slice(0, dot);
|
|
@@ -10052,7 +10127,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
10052
10127
|
}
|
|
10053
10128
|
|
|
10054
10129
|
// server/routes/admin/files.ts
|
|
10055
|
-
var
|
|
10130
|
+
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
10056
10131
|
async function readMeta(absDir, baseName) {
|
|
10057
10132
|
try {
|
|
10058
10133
|
const raw = await readFile3(join9(absDir, `${baseName}.meta.json`), "utf8");
|
|
@@ -10074,7 +10149,7 @@ async function readAccountNames() {
|
|
|
10074
10149
|
return map;
|
|
10075
10150
|
}
|
|
10076
10151
|
for (const name of names) {
|
|
10077
|
-
if (!
|
|
10152
|
+
if (!UUID_RE5.test(name)) continue;
|
|
10078
10153
|
const configPath2 = resolve15(accountsDir, name, "account.json");
|
|
10079
10154
|
try {
|
|
10080
10155
|
const raw = await readFile3(configPath2, "utf8");
|
|
@@ -10092,7 +10167,7 @@ async function readAccountNames() {
|
|
|
10092
10167
|
return map;
|
|
10093
10168
|
}
|
|
10094
10169
|
async function enrich(absolute, entry, accountNames) {
|
|
10095
|
-
if (entry.kind === "directory" &&
|
|
10170
|
+
if (entry.kind === "directory" && UUID_RE5.test(entry.name)) {
|
|
10096
10171
|
const meta = await readMeta(join9(absolute, entry.name), entry.name);
|
|
10097
10172
|
if (meta?.filename) {
|
|
10098
10173
|
entry.displayName = meta.filename;
|
|
@@ -10108,7 +10183,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
10108
10183
|
if (entry.kind === "file") {
|
|
10109
10184
|
const dot = entry.name.lastIndexOf(".");
|
|
10110
10185
|
const base = dot === -1 ? entry.name : entry.name.slice(0, dot);
|
|
10111
|
-
if (
|
|
10186
|
+
if (UUID_RE5.test(base)) {
|
|
10112
10187
|
const meta = await readMeta(absolute, base);
|
|
10113
10188
|
if (meta?.filename) {
|
|
10114
10189
|
entry.displayName = meta.filename;
|
|
@@ -10120,14 +10195,14 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
10120
10195
|
function buildDisplayPath(relPath2, accountNames) {
|
|
10121
10196
|
if (relPath2 === "." || relPath2 === "") return [];
|
|
10122
10197
|
return relPath2.split("/").filter(Boolean).map((seg) => {
|
|
10123
|
-
const dn =
|
|
10198
|
+
const dn = UUID_RE5.test(seg) ? accountNames.get(seg) : void 0;
|
|
10124
10199
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
10125
10200
|
});
|
|
10126
10201
|
}
|
|
10127
|
-
var
|
|
10128
|
-
|
|
10129
|
-
const
|
|
10130
|
-
if (!getAccountIdForSession(
|
|
10202
|
+
var app24 = new Hono();
|
|
10203
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
10204
|
+
const cacheKey = c.var.cacheKey;
|
|
10205
|
+
if (!getAccountIdForSession(cacheKey)) {
|
|
10131
10206
|
console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
|
|
10132
10207
|
return c.json({ error: "Account not found for session" }, 401);
|
|
10133
10208
|
}
|
|
@@ -10148,7 +10223,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
10148
10223
|
const names = await readdir2(absolute);
|
|
10149
10224
|
const entries = [];
|
|
10150
10225
|
for (const name of names) {
|
|
10151
|
-
if (
|
|
10226
|
+
if (UUID_RE5.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
10152
10227
|
continue;
|
|
10153
10228
|
}
|
|
10154
10229
|
try {
|
|
@@ -10186,9 +10261,9 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
10186
10261
|
return c.json({ error: message }, 500);
|
|
10187
10262
|
}
|
|
10188
10263
|
});
|
|
10189
|
-
|
|
10190
|
-
const
|
|
10191
|
-
if (!getAccountIdForSession(
|
|
10264
|
+
app24.get("/download", requireAdminSession, async (c) => {
|
|
10265
|
+
const cacheKey = c.var.cacheKey;
|
|
10266
|
+
if (!getAccountIdForSession(cacheKey)) {
|
|
10192
10267
|
console.error(`[data] auth-rejected endpoint="/api/admin/files/download" reason="no account for session"`);
|
|
10193
10268
|
return c.json({ error: "Account not found for session" }, 401);
|
|
10194
10269
|
}
|
|
@@ -10234,9 +10309,9 @@ app23.get("/download", requireAdminSession, async (c) => {
|
|
|
10234
10309
|
return c.json({ error: message }, 500);
|
|
10235
10310
|
}
|
|
10236
10311
|
});
|
|
10237
|
-
|
|
10238
|
-
const
|
|
10239
|
-
const accountId = getAccountIdForSession(
|
|
10312
|
+
app24.post("/upload", requireAdminSession, async (c) => {
|
|
10313
|
+
const cacheKey = c.var.cacheKey;
|
|
10314
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
10240
10315
|
if (!accountId) {
|
|
10241
10316
|
console.error(`[data] auth-rejected endpoint="/api/admin/files/upload" reason="no account for session"`);
|
|
10242
10317
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10292,9 +10367,9 @@ app23.post("/upload", requireAdminSession, async (c) => {
|
|
|
10292
10367
|
mimeType: file.type
|
|
10293
10368
|
});
|
|
10294
10369
|
});
|
|
10295
|
-
|
|
10296
|
-
const
|
|
10297
|
-
const accountId = getAccountIdForSession(
|
|
10370
|
+
app24.delete("/", requireAdminSession, async (c) => {
|
|
10371
|
+
const cacheKey = c.var.cacheKey;
|
|
10372
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
10298
10373
|
if (!accountId) {
|
|
10299
10374
|
console.error(`[data] auth-rejected endpoint="DELETE /api/admin/files" reason="no account for session"`);
|
|
10300
10375
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10325,7 +10400,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
10325
10400
|
}
|
|
10326
10401
|
const dot = base.lastIndexOf(".");
|
|
10327
10402
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
10328
|
-
const sidecarPath =
|
|
10403
|
+
const sidecarPath = UUID_RE5.test(stem) && base !== `${stem}.meta.json` ? join9(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
10329
10404
|
await unlink2(absolute);
|
|
10330
10405
|
if (sidecarPath) {
|
|
10331
10406
|
try {
|
|
@@ -10359,7 +10434,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
10359
10434
|
return c.json({ error: message }, 500);
|
|
10360
10435
|
}
|
|
10361
10436
|
});
|
|
10362
|
-
var files_default =
|
|
10437
|
+
var files_default = app24;
|
|
10363
10438
|
|
|
10364
10439
|
// ../lib/graph-search/src/index.ts
|
|
10365
10440
|
var import_dist = __toESM(require_dist());
|
|
@@ -10739,14 +10814,14 @@ var MAX_LIMIT = 2e3;
|
|
|
10739
10814
|
var DEFAULT_VECTOR_THRESHOLD = 0.82;
|
|
10740
10815
|
var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
|
|
10741
10816
|
var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
|
|
10742
|
-
var
|
|
10743
|
-
|
|
10744
|
-
const
|
|
10817
|
+
var app25 = new Hono();
|
|
10818
|
+
app25.get("/", requireAdminSession, async (c) => {
|
|
10819
|
+
const cacheKey = c.var.cacheKey;
|
|
10745
10820
|
const q = (c.req.query("q") ?? "").trim();
|
|
10746
10821
|
const rawLimit = c.req.query("limit");
|
|
10747
10822
|
const rawLabels = c.req.query("labels");
|
|
10748
10823
|
const rawThreshold = c.req.query("threshold");
|
|
10749
|
-
const accountId = getAccountIdForSession(
|
|
10824
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
10750
10825
|
if (!accountId) {
|
|
10751
10826
|
console.error(`[graph-search] auth-rejected endpoint="/api/admin/graph-search" reason="no account for session"`);
|
|
10752
10827
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10871,7 +10946,7 @@ app24.get("/", requireAdminSession, async (c) => {
|
|
|
10871
10946
|
await session.close();
|
|
10872
10947
|
}
|
|
10873
10948
|
});
|
|
10874
|
-
var graph_search_default =
|
|
10949
|
+
var graph_search_default = app25;
|
|
10875
10950
|
|
|
10876
10951
|
// server/routes/admin/graph-subgraph.ts
|
|
10877
10952
|
import neo4j2 from "neo4j-driver";
|
|
@@ -11027,12 +11102,12 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
11027
11102
|
"passwordHash",
|
|
11028
11103
|
"magicToken",
|
|
11029
11104
|
"otpCode",
|
|
11030
|
-
"
|
|
11105
|
+
"cacheKey"
|
|
11031
11106
|
]);
|
|
11032
|
-
var
|
|
11033
|
-
|
|
11034
|
-
const
|
|
11035
|
-
const accountId = getAccountIdForSession(
|
|
11107
|
+
var app26 = new Hono();
|
|
11108
|
+
app26.get("/", requireAdminSession, async (c) => {
|
|
11109
|
+
const cacheKey = c.var.cacheKey;
|
|
11110
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11036
11111
|
if (!accountId) {
|
|
11037
11112
|
console.error('[graph-page] auth-rejected reason="no account for session"');
|
|
11038
11113
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11613,14 +11688,14 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
11613
11688
|
}
|
|
11614
11689
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
11615
11690
|
}
|
|
11616
|
-
var graph_subgraph_default =
|
|
11691
|
+
var graph_subgraph_default = app26;
|
|
11617
11692
|
|
|
11618
11693
|
// server/routes/admin/graph-delete.ts
|
|
11619
11694
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash"];
|
|
11620
|
-
var
|
|
11621
|
-
|
|
11622
|
-
const
|
|
11623
|
-
const accountId = getAccountIdForSession(
|
|
11695
|
+
var app27 = new Hono();
|
|
11696
|
+
app27.post("/", requireAdminSession, async (c) => {
|
|
11697
|
+
const cacheKey = c.var.cacheKey;
|
|
11698
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11624
11699
|
if (!accountId) {
|
|
11625
11700
|
console.error('[graph-page] delete auth-rejected reason="no account for session"');
|
|
11626
11701
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11689,13 +11764,13 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
11689
11764
|
}
|
|
11690
11765
|
}
|
|
11691
11766
|
});
|
|
11692
|
-
var graph_delete_default =
|
|
11767
|
+
var graph_delete_default = app27;
|
|
11693
11768
|
|
|
11694
11769
|
// server/routes/admin/graph-restore.ts
|
|
11695
|
-
var
|
|
11696
|
-
|
|
11697
|
-
const
|
|
11698
|
-
const accountId = getAccountIdForSession(
|
|
11770
|
+
var app28 = new Hono();
|
|
11771
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
11772
|
+
const cacheKey = c.var.cacheKey;
|
|
11773
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11699
11774
|
if (!accountId) {
|
|
11700
11775
|
console.error('[graph-page] restore auth-rejected reason="no account for session"');
|
|
11701
11776
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11757,13 +11832,13 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
11757
11832
|
}
|
|
11758
11833
|
}
|
|
11759
11834
|
});
|
|
11760
|
-
var graph_restore_default =
|
|
11835
|
+
var graph_restore_default = app28;
|
|
11761
11836
|
|
|
11762
11837
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
11763
|
-
var
|
|
11764
|
-
|
|
11765
|
-
const
|
|
11766
|
-
const accountId = getAccountIdForSession(
|
|
11838
|
+
var app29 = new Hono();
|
|
11839
|
+
app29.get("/", requireAdminSession, async (c) => {
|
|
11840
|
+
const cacheKey = c.var.cacheKey;
|
|
11841
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11767
11842
|
if (!accountId) {
|
|
11768
11843
|
console.error('[graph-page] labels-in-graph-rejected reason="no account for session"');
|
|
11769
11844
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11827,14 +11902,14 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
11827
11902
|
sum(halfEdges) AS relDegree
|
|
11828
11903
|
RETURN label, nodeCount, relDegree
|
|
11829
11904
|
`;
|
|
11830
|
-
var graph_labels_in_graph_default =
|
|
11905
|
+
var graph_labels_in_graph_default = app29;
|
|
11831
11906
|
|
|
11832
11907
|
// server/routes/admin/graph-default-view.ts
|
|
11833
|
-
var
|
|
11834
|
-
|
|
11835
|
-
const
|
|
11836
|
-
const accountId = getAccountIdForSession(
|
|
11837
|
-
const userId = getUserIdForSession(
|
|
11908
|
+
var app30 = new Hono();
|
|
11909
|
+
app30.get("/", requireAdminSession, async (c) => {
|
|
11910
|
+
const cacheKey = c.var.cacheKey;
|
|
11911
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11912
|
+
const userId = getUserIdForSession(cacheKey);
|
|
11838
11913
|
if (!accountId || !userId) {
|
|
11839
11914
|
console.error('[graph-page] default-view-rejected reason="missing account or user context"');
|
|
11840
11915
|
return c.json({ error: "Account and user context required for default view" }, 401);
|
|
@@ -11869,10 +11944,10 @@ app29.get("/", requireAdminSession, async (c) => {
|
|
|
11869
11944
|
}
|
|
11870
11945
|
}
|
|
11871
11946
|
});
|
|
11872
|
-
|
|
11873
|
-
const
|
|
11874
|
-
const accountId = getAccountIdForSession(
|
|
11875
|
-
const userId = getUserIdForSession(
|
|
11947
|
+
app30.put("/", requireAdminSession, async (c) => {
|
|
11948
|
+
const cacheKey = c.var.cacheKey;
|
|
11949
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11950
|
+
const userId = getUserIdForSession(cacheKey);
|
|
11876
11951
|
if (!accountId || !userId) {
|
|
11877
11952
|
console.error('[graph-page] default-view-rejected reason="missing account or user context"');
|
|
11878
11953
|
return c.json({ error: "Account and user context required for default view" }, 401);
|
|
@@ -11958,11 +12033,11 @@ var WRITE_CYPHER = `
|
|
|
11958
12033
|
p.updatedAt = $updatedAt
|
|
11959
12034
|
RETURN p.labels AS labels
|
|
11960
12035
|
`;
|
|
11961
|
-
var graph_default_view_default =
|
|
12036
|
+
var graph_default_view_default = app30;
|
|
11962
12037
|
|
|
11963
12038
|
// server/routes/admin/file-attach.ts
|
|
11964
|
-
var
|
|
11965
|
-
|
|
12039
|
+
var app31 = new Hono();
|
|
12040
|
+
app31.post("/", async (c) => {
|
|
11966
12041
|
try {
|
|
11967
12042
|
const body = await c.req.json();
|
|
11968
12043
|
const { filePath, accountId } = body;
|
|
@@ -11985,11 +12060,11 @@ app30.post("/", async (c) => {
|
|
|
11985
12060
|
return c.json({ error: message }, 500);
|
|
11986
12061
|
}
|
|
11987
12062
|
});
|
|
11988
|
-
var file_attach_default =
|
|
12063
|
+
var file_attach_default = app31;
|
|
11989
12064
|
|
|
11990
12065
|
// server/routes/admin/adherence.ts
|
|
11991
|
-
var
|
|
11992
|
-
|
|
12066
|
+
var app32 = new Hono();
|
|
12067
|
+
app32.get("/", requireAdminSession, async (c) => {
|
|
11993
12068
|
const agent = c.req.query("agent") ?? "admin";
|
|
11994
12069
|
const includeBlock = c.req.query("block") === "1";
|
|
11995
12070
|
const account = resolveAccount();
|
|
@@ -12010,7 +12085,7 @@ app31.get("/", requireAdminSession, async (c) => {
|
|
|
12010
12085
|
return c.json({ error: "Failed to read adherence ledger", agent }, 500);
|
|
12011
12086
|
}
|
|
12012
12087
|
});
|
|
12013
|
-
var adherence_default =
|
|
12088
|
+
var adherence_default = app32;
|
|
12014
12089
|
|
|
12015
12090
|
// server/routes/admin/sidebar-artefacts.ts
|
|
12016
12091
|
import neo4j3 from "neo4j-driver";
|
|
@@ -12020,10 +12095,10 @@ import { existsSync as existsSync18 } from "fs";
|
|
|
12020
12095
|
var LIMIT = 50;
|
|
12021
12096
|
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
12022
12097
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
12023
|
-
var
|
|
12024
|
-
|
|
12025
|
-
const
|
|
12026
|
-
const accountId = getAccountIdForSession(
|
|
12098
|
+
var app33 = new Hono();
|
|
12099
|
+
app33.get("/", requireAdminSession, async (c) => {
|
|
12100
|
+
const cacheKey = c.var.cacheKey;
|
|
12101
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
12027
12102
|
if (!accountId) {
|
|
12028
12103
|
return c.json({ error: "Account not found for session" }, 401);
|
|
12029
12104
|
}
|
|
@@ -12227,18 +12302,18 @@ function isWithin(target, root) {
|
|
|
12227
12302
|
const rel = relative2(root, target);
|
|
12228
12303
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
12229
12304
|
}
|
|
12230
|
-
var sidebar_artefacts_default =
|
|
12305
|
+
var sidebar_artefacts_default = app33;
|
|
12231
12306
|
|
|
12232
12307
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
12233
12308
|
import { mkdir as mkdir3, readdir as readdir4, stat as stat5, writeFile as writeFile4 } from "fs/promises";
|
|
12234
12309
|
import { resolve as resolve17 } from "path";
|
|
12235
12310
|
import { existsSync as existsSync19 } from "fs";
|
|
12236
12311
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
12237
|
-
var
|
|
12238
|
-
var
|
|
12239
|
-
|
|
12240
|
-
const
|
|
12241
|
-
const accountId = getAccountIdForSession(
|
|
12312
|
+
var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12313
|
+
var app34 = new Hono();
|
|
12314
|
+
app34.post("/", requireAdminSession, async (c) => {
|
|
12315
|
+
const cacheKey = c.var.cacheKey;
|
|
12316
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
12242
12317
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
12243
12318
|
const body = await safeJson(c);
|
|
12244
12319
|
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
@@ -12294,7 +12369,7 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12294
12369
|
}
|
|
12295
12370
|
return { kind: "admin-template", path: resolve17(parent, filename) };
|
|
12296
12371
|
}
|
|
12297
|
-
if (
|
|
12372
|
+
if (UUID_RE6.test(id)) {
|
|
12298
12373
|
const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
|
|
12299
12374
|
if (!existsSync19(dir)) {
|
|
12300
12375
|
return { kind: "reject", status: 400, reason: "not-found" };
|
|
@@ -12316,20 +12391,20 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12316
12391
|
function relPath(absPath, root) {
|
|
12317
12392
|
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
12318
12393
|
}
|
|
12319
|
-
var sidebar_artefact_save_default =
|
|
12394
|
+
var sidebar_artefact_save_default = app34;
|
|
12320
12395
|
|
|
12321
12396
|
// server/routes/admin/sidebar-artefact-content.ts
|
|
12322
12397
|
import { readFile as readFile5, readdir as readdir5 } from "fs/promises";
|
|
12323
12398
|
import { existsSync as existsSync20 } from "fs";
|
|
12324
12399
|
import { resolve as resolve18 } from "path";
|
|
12325
|
-
var
|
|
12326
|
-
var
|
|
12327
|
-
|
|
12328
|
-
const
|
|
12329
|
-
const accountId = getAccountIdForSession(
|
|
12400
|
+
var UUID_RE7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12401
|
+
var app35 = new Hono();
|
|
12402
|
+
app35.get("/", requireAdminSession, async (c) => {
|
|
12403
|
+
const cacheKey = c.var.cacheKey;
|
|
12404
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
12330
12405
|
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
|
12331
12406
|
const id = c.req.query("id") ?? "";
|
|
12332
|
-
if (!
|
|
12407
|
+
if (!UUID_RE7.test(id)) {
|
|
12333
12408
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12334
12409
|
return new Response("Not found", { status: 404 });
|
|
12335
12410
|
}
|
|
@@ -12365,7 +12440,7 @@ app34.get("/", requireAdminSession, async (c) => {
|
|
|
12365
12440
|
}
|
|
12366
12441
|
});
|
|
12367
12442
|
});
|
|
12368
|
-
var sidebar_artefact_content_default =
|
|
12443
|
+
var sidebar_artefact_content_default = app35;
|
|
12369
12444
|
|
|
12370
12445
|
// server/routes/admin/health.ts
|
|
12371
12446
|
import { existsSync as existsSync21, readFileSync as readFileSync16 } from "fs";
|
|
@@ -12410,8 +12485,8 @@ async function probeConversationDb() {
|
|
|
12410
12485
|
});
|
|
12411
12486
|
}
|
|
12412
12487
|
}
|
|
12413
|
-
var
|
|
12414
|
-
|
|
12488
|
+
var app36 = new Hono();
|
|
12489
|
+
app36.get("/", async (c) => {
|
|
12415
12490
|
const version = readVersion();
|
|
12416
12491
|
const probe = await probeConversationDb();
|
|
12417
12492
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -12433,37 +12508,38 @@ app35.get("/", async (c) => {
|
|
|
12433
12508
|
uptimeMs
|
|
12434
12509
|
});
|
|
12435
12510
|
});
|
|
12436
|
-
var health_default2 =
|
|
12511
|
+
var health_default2 = app36;
|
|
12437
12512
|
|
|
12438
12513
|
// server/routes/admin/index.ts
|
|
12439
|
-
var
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12514
|
+
var app37 = new Hono();
|
|
12515
|
+
app37.route("/session", session_default2);
|
|
12516
|
+
app37.route("/chat", chat_default2);
|
|
12517
|
+
app37.route("/chat-failure", chat_failure_default);
|
|
12518
|
+
app37.route("/compact", compact_default);
|
|
12519
|
+
app37.route("/logs", logs_default);
|
|
12520
|
+
app37.route("/claude-info", claude_info_default);
|
|
12521
|
+
app37.route("/attachment", attachment_default);
|
|
12522
|
+
app37.route("/agents", agents_default);
|
|
12523
|
+
app37.route("/sessions", sessions_default);
|
|
12524
|
+
app37.route("/browser", browser_default);
|
|
12525
|
+
app37.route("/browser-iframe", browser_iframe_default);
|
|
12526
|
+
app37.route("/device-browser", device_browser_default);
|
|
12527
|
+
app37.route("/events", events_default);
|
|
12528
|
+
app37.route("/cloudflare", cloudflare_default);
|
|
12529
|
+
app37.route("/files", files_default);
|
|
12530
|
+
app37.route("/graph-search", graph_search_default);
|
|
12531
|
+
app37.route("/graph-subgraph", graph_subgraph_default);
|
|
12532
|
+
app37.route("/graph-delete", graph_delete_default);
|
|
12533
|
+
app37.route("/graph-restore", graph_restore_default);
|
|
12534
|
+
app37.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12535
|
+
app37.route("/graph-default-view", graph_default_view_default);
|
|
12536
|
+
app37.route("/file-attach", file_attach_default);
|
|
12537
|
+
app37.route("/adherence", adherence_default);
|
|
12538
|
+
app37.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12539
|
+
app37.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
12540
|
+
app37.route("/sidebar-artefact-content", sidebar_artefact_content_default);
|
|
12541
|
+
app37.route("/health-brand", health_default2);
|
|
12542
|
+
var admin_default = app37;
|
|
12467
12543
|
|
|
12468
12544
|
// server/routes/sites.ts
|
|
12469
12545
|
import { existsSync as existsSync22, readFileSync as readFileSync17, realpathSync as realpathSync4, statSync as statSync7 } from "fs";
|
|
@@ -12498,8 +12574,8 @@ function getExt(p) {
|
|
|
12498
12574
|
if (idx < p.lastIndexOf("/")) return "";
|
|
12499
12575
|
return p.slice(idx).toLowerCase();
|
|
12500
12576
|
}
|
|
12501
|
-
var
|
|
12502
|
-
|
|
12577
|
+
var app38 = new Hono();
|
|
12578
|
+
app38.get("/:rel{.*}", (c) => {
|
|
12503
12579
|
const reqPath = c.req.path;
|
|
12504
12580
|
const rawRel = c.req.param("rel") ?? "";
|
|
12505
12581
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -12602,7 +12678,7 @@ app37.get("/:rel{.*}", (c) => {
|
|
|
12602
12678
|
"X-Content-Type-Options": "nosniff"
|
|
12603
12679
|
});
|
|
12604
12680
|
});
|
|
12605
|
-
var sites_default =
|
|
12681
|
+
var sites_default = app38;
|
|
12606
12682
|
|
|
12607
12683
|
// app/lib/graph-health.ts
|
|
12608
12684
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -12756,9 +12832,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
|
|
|
12756
12832
|
function isPublicHost(host) {
|
|
12757
12833
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
12758
12834
|
}
|
|
12759
|
-
var
|
|
12760
|
-
|
|
12761
|
-
|
|
12835
|
+
var app39 = new Hono();
|
|
12836
|
+
app39.use("*", clientIpMiddleware);
|
|
12837
|
+
app39.use("*", async (c, next) => {
|
|
12762
12838
|
await next();
|
|
12763
12839
|
c.header("X-Content-Type-Options", "nosniff");
|
|
12764
12840
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -12768,7 +12844,7 @@ app38.use("*", async (c, next) => {
|
|
|
12768
12844
|
);
|
|
12769
12845
|
});
|
|
12770
12846
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
12771
|
-
|
|
12847
|
+
app39.use("*", async (c, next) => {
|
|
12772
12848
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
12773
12849
|
await next();
|
|
12774
12850
|
return;
|
|
@@ -12801,7 +12877,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
12801
12877
|
"/sites/"
|
|
12802
12878
|
];
|
|
12803
12879
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
12804
|
-
|
|
12880
|
+
app39.use("*", async (c, next) => {
|
|
12805
12881
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12806
12882
|
if (!isPublicHost(host)) {
|
|
12807
12883
|
await next();
|
|
@@ -12841,7 +12917,7 @@ function resolveRemoteAuthOpts() {
|
|
|
12841
12917
|
return brandLoginOpts;
|
|
12842
12918
|
}
|
|
12843
12919
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
12844
|
-
|
|
12920
|
+
app39.post("/__remote-auth/login", async (c) => {
|
|
12845
12921
|
const client = clientFrom(c);
|
|
12846
12922
|
const clientIp = client.ip || "unknown";
|
|
12847
12923
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -12886,7 +12962,7 @@ app38.post("/__remote-auth/login", async (c) => {
|
|
|
12886
12962
|
}
|
|
12887
12963
|
});
|
|
12888
12964
|
});
|
|
12889
|
-
|
|
12965
|
+
app39.get("/__remote-auth/logout", (c) => {
|
|
12890
12966
|
const client = clientFrom(c);
|
|
12891
12967
|
const clientIp = client.ip || "unknown";
|
|
12892
12968
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -12899,7 +12975,7 @@ app38.get("/__remote-auth/logout", (c) => {
|
|
|
12899
12975
|
}
|
|
12900
12976
|
});
|
|
12901
12977
|
});
|
|
12902
|
-
|
|
12978
|
+
app39.post("/__remote-auth/change-password", async (c) => {
|
|
12903
12979
|
const client = clientFrom(c);
|
|
12904
12980
|
const clientIp = client.ip || "unknown";
|
|
12905
12981
|
const rateLimited = checkRateLimit(client);
|
|
@@ -12950,13 +13026,13 @@ app38.post("/__remote-auth/change-password", async (c) => {
|
|
|
12950
13026
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
12951
13027
|
}
|
|
12952
13028
|
});
|
|
12953
|
-
|
|
13029
|
+
app39.get("/__remote-auth/setup", (c) => {
|
|
12954
13030
|
if (isRemoteAuthConfigured()) {
|
|
12955
13031
|
return c.redirect("/");
|
|
12956
13032
|
}
|
|
12957
13033
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
12958
13034
|
});
|
|
12959
|
-
|
|
13035
|
+
app39.post("/__remote-auth/set-initial-password", async (c) => {
|
|
12960
13036
|
if (isRemoteAuthConfigured()) {
|
|
12961
13037
|
return c.redirect("/");
|
|
12962
13038
|
}
|
|
@@ -12994,10 +13070,10 @@ app38.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
12994
13070
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
12995
13071
|
}
|
|
12996
13072
|
});
|
|
12997
|
-
|
|
13073
|
+
app39.get("/api/remote-auth/status", (c) => {
|
|
12998
13074
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
12999
13075
|
});
|
|
13000
|
-
|
|
13076
|
+
app39.post("/api/remote-auth/set-password", async (c) => {
|
|
13001
13077
|
let body;
|
|
13002
13078
|
try {
|
|
13003
13079
|
body = await c.req.json();
|
|
@@ -13027,9 +13103,9 @@ app38.post("/api/remote-auth/set-password", async (c) => {
|
|
|
13027
13103
|
return c.json({ error: "Failed to save password" }, 500);
|
|
13028
13104
|
}
|
|
13029
13105
|
});
|
|
13030
|
-
|
|
13106
|
+
app39.route("/api/_client-error", client_error_default);
|
|
13031
13107
|
console.log("[client-error-route] mounted");
|
|
13032
|
-
|
|
13108
|
+
app39.use("*", async (c, next) => {
|
|
13033
13109
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13034
13110
|
const path2 = c.req.path;
|
|
13035
13111
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -13069,15 +13145,15 @@ app38.use("*", async (c, next) => {
|
|
|
13069
13145
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
13070
13146
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
13071
13147
|
});
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13148
|
+
app39.route("/api/health", health_default);
|
|
13149
|
+
app39.route("/api/session", session_default);
|
|
13150
|
+
app39.route("/api/chat", chat_default);
|
|
13151
|
+
app39.route("/api/group", group_default);
|
|
13152
|
+
app39.route("/api/access", access_default);
|
|
13153
|
+
app39.route("/api/telegram", telegram_default);
|
|
13154
|
+
app39.route("/api/whatsapp", whatsapp_default);
|
|
13155
|
+
app39.route("/api/onboarding", onboarding_default);
|
|
13156
|
+
app39.route("/api/admin", admin_default);
|
|
13081
13157
|
var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
|
|
13082
13158
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13083
13159
|
var IMAGE_MIME = {
|
|
@@ -13089,7 +13165,7 @@ var IMAGE_MIME = {
|
|
|
13089
13165
|
".svg": "image/svg+xml",
|
|
13090
13166
|
".ico": "image/x-icon"
|
|
13091
13167
|
};
|
|
13092
|
-
|
|
13168
|
+
app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
13093
13169
|
const slug = c.req.param("slug");
|
|
13094
13170
|
const filename = c.req.param("filename");
|
|
13095
13171
|
if (!SAFE_SLUG_RE.test(slug)) {
|
|
@@ -13124,7 +13200,7 @@ app38.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
13124
13200
|
"Cache-Control": "public, max-age=3600"
|
|
13125
13201
|
});
|
|
13126
13202
|
});
|
|
13127
|
-
|
|
13203
|
+
app39.get("/generated/:filename", (c) => {
|
|
13128
13204
|
const filename = c.req.param("filename");
|
|
13129
13205
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
13130
13206
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -13154,7 +13230,7 @@ app38.get("/generated/:filename", (c) => {
|
|
|
13154
13230
|
"Cache-Control": "public, max-age=86400"
|
|
13155
13231
|
});
|
|
13156
13232
|
});
|
|
13157
|
-
|
|
13233
|
+
app39.route("/sites", sites_default);
|
|
13158
13234
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
13159
13235
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
13160
13236
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -13291,7 +13367,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
13291
13367
|
function escapeHtml(s) {
|
|
13292
13368
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
13293
13369
|
}
|
|
13294
|
-
|
|
13370
|
+
app39.get("/", (c) => {
|
|
13295
13371
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13296
13372
|
if (isPublicHost(host)) {
|
|
13297
13373
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -13299,12 +13375,12 @@ app38.get("/", (c) => {
|
|
|
13299
13375
|
}
|
|
13300
13376
|
return c.html(cachedHtml("index.html"));
|
|
13301
13377
|
});
|
|
13302
|
-
|
|
13378
|
+
app39.get("/public", (c) => {
|
|
13303
13379
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13304
13380
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13305
13381
|
return c.html(cachedHtml("public.html"));
|
|
13306
13382
|
});
|
|
13307
|
-
|
|
13383
|
+
app39.get("/chat", (c) => {
|
|
13308
13384
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13309
13385
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13310
13386
|
return c.html(cachedHtml("public.html"));
|
|
@@ -13323,9 +13399,9 @@ async function logViewerFetch(c, next) {
|
|
|
13323
13399
|
duration_ms: Date.now() - start
|
|
13324
13400
|
});
|
|
13325
13401
|
}
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13402
|
+
app39.use("/vnc-viewer.html", logViewerFetch);
|
|
13403
|
+
app39.use("/vnc-popout.html", logViewerFetch);
|
|
13404
|
+
app39.get("/vnc-popout.html", (c) => {
|
|
13329
13405
|
let html = htmlCache.get("vnc-popout.html");
|
|
13330
13406
|
if (!html) {
|
|
13331
13407
|
html = readFileSync18(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -13338,7 +13414,7 @@ app38.get("/vnc-popout.html", (c) => {
|
|
|
13338
13414
|
}
|
|
13339
13415
|
return c.html(html);
|
|
13340
13416
|
});
|
|
13341
|
-
|
|
13417
|
+
app39.post("/api/vnc/client-event", async (c) => {
|
|
13342
13418
|
let body;
|
|
13343
13419
|
try {
|
|
13344
13420
|
body = await c.req.json();
|
|
@@ -13359,20 +13435,20 @@ app38.post("/api/vnc/client-event", async (c) => {
|
|
|
13359
13435
|
});
|
|
13360
13436
|
return c.json({ ok: true });
|
|
13361
13437
|
});
|
|
13362
|
-
|
|
13438
|
+
app39.get("/g/:slug", (c) => {
|
|
13363
13439
|
return c.html(brandedPublicHtml());
|
|
13364
13440
|
});
|
|
13365
|
-
|
|
13441
|
+
app39.get("/graph", (c) => {
|
|
13366
13442
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13367
13443
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13368
13444
|
return c.html(cachedHtml("graph.html"));
|
|
13369
13445
|
});
|
|
13370
|
-
|
|
13446
|
+
app39.get("/data", (c) => {
|
|
13371
13447
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13372
13448
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13373
13449
|
return c.html(cachedHtml("data.html"));
|
|
13374
13450
|
});
|
|
13375
|
-
|
|
13451
|
+
app39.get("/:slug", async (c, next) => {
|
|
13376
13452
|
const slug = c.req.param("slug");
|
|
13377
13453
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
13378
13454
|
const branding = loadBrandingCache(slug);
|
|
@@ -13382,15 +13458,15 @@ app38.get("/:slug", async (c, next) => {
|
|
|
13382
13458
|
await next();
|
|
13383
13459
|
});
|
|
13384
13460
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
13385
|
-
|
|
13461
|
+
app39.get("/favicon.ico", (c) => {
|
|
13386
13462
|
c.header("Cache-Control", "public, max-age=300");
|
|
13387
13463
|
return c.redirect(brandFaviconPath, 302);
|
|
13388
13464
|
});
|
|
13389
13465
|
}
|
|
13390
|
-
|
|
13466
|
+
app39.use("/*", serveStatic({ root: "./public" }));
|
|
13391
13467
|
var port = parseInt(process.env.MAXY_UI_INTERNAL_PORT ?? process.env.PORT ?? "19199", 10);
|
|
13392
13468
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
13393
|
-
var httpServer = serve({ fetch:
|
|
13469
|
+
var httpServer = serve({ fetch: app39.fetch, port, hostname });
|
|
13394
13470
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
13395
13471
|
console.log("[boot] auth-mode summary: oauth=8 api-key=1 (api-key consumer: invokePublicAgent only)");
|
|
13396
13472
|
var SUBAPP_MANIFEST = [
|
|
@@ -13411,7 +13487,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
13411
13487
|
}
|
|
13412
13488
|
try {
|
|
13413
13489
|
const registered = [];
|
|
13414
|
-
for (const r of
|
|
13490
|
+
for (const r of app39.routes ?? []) {
|
|
13415
13491
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
13416
13492
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
13417
13493
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -13443,6 +13519,13 @@ try {
|
|
|
13443
13519
|
console.error(`[session] backfill startup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13444
13520
|
}
|
|
13445
13521
|
})();
|
|
13522
|
+
(async () => {
|
|
13523
|
+
try {
|
|
13524
|
+
await backfillConversationChannelAddress();
|
|
13525
|
+
} catch (err) {
|
|
13526
|
+
console.error(`[session-985] channelAddress backfill startup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13527
|
+
}
|
|
13528
|
+
})();
|
|
13446
13529
|
(async () => {
|
|
13447
13530
|
try {
|
|
13448
13531
|
if (!existsSync23(USERS_FILE)) return;
|
|
@@ -13497,15 +13580,14 @@ autoDeliverPremiumPlugins(bootEntitlement?.purchasedPlugins ?? void 0);
|
|
|
13497
13580
|
(async () => {
|
|
13498
13581
|
if (!bootAccount) return;
|
|
13499
13582
|
try {
|
|
13500
|
-
const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-
|
|
13583
|
+
const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-B6FXP3HI.js");
|
|
13501
13584
|
const result = await recoverRunningCloudflareTasks(
|
|
13502
13585
|
bootAccount.accountId,
|
|
13503
13586
|
configDirForWhatsApp,
|
|
13504
|
-
//
|
|
13505
|
-
//
|
|
13506
|
-
//
|
|
13507
|
-
// and let the
|
|
13508
|
-
// existing edge.
|
|
13587
|
+
// Task 985 — no conversationId at boot. The reconciler operates on
|
|
13588
|
+
// Tasks whose Conversation is already linked via RAISED_DURING; the
|
|
13589
|
+
// tracker resolves the conversationId off that edge when present.
|
|
13590
|
+
// Pass null and let the recovery path pick it up.
|
|
13509
13591
|
null
|
|
13510
13592
|
);
|
|
13511
13593
|
if (result.scanned > 0) {
|
|
@@ -13587,10 +13669,10 @@ init({
|
|
|
13587
13669
|
agentName = resolved.slug;
|
|
13588
13670
|
}
|
|
13589
13671
|
let enrichedText = msg.text || msg.mediaPath || msg.mediaType || msg.replyContext ? buildEnrichedText2(msg.text ?? "") : "";
|
|
13590
|
-
if (msg.
|
|
13672
|
+
if (msg.cacheKey) {
|
|
13591
13673
|
const platformAccountId = bootAccount?.accountId ?? msg.accountId;
|
|
13592
|
-
registerSession(msg.
|
|
13593
|
-
console.error(`[session] channel session registered:
|
|
13674
|
+
registerSession(msg.cacheKey, msg.agentType, platformAccountId, agentName);
|
|
13675
|
+
console.error(`[session] channel session registered: cacheKey=${msg.cacheKey.slice(0, 12)}\u2026 channel=whatsapp accountId=${platformAccountId.slice(0, 8)}\u2026`);
|
|
13594
13676
|
}
|
|
13595
13677
|
let gatewayResult;
|
|
13596
13678
|
if (msg.text) {
|
|
@@ -13614,7 +13696,7 @@ init({
|
|
|
13614
13696
|
for await (const event of invokeAgent(
|
|
13615
13697
|
{ type: msg.agentType, agentName },
|
|
13616
13698
|
enrichedText,
|
|
13617
|
-
msg.
|
|
13699
|
+
msg.cacheKey,
|
|
13618
13700
|
[],
|
|
13619
13701
|
void 0,
|
|
13620
13702
|
gatewayResult
|
|
@@ -13632,7 +13714,7 @@ init({
|
|
|
13632
13714
|
for await (const event of invokeAgent(
|
|
13633
13715
|
{ type: msg.agentType, agentName },
|
|
13634
13716
|
enrichedText,
|
|
13635
|
-
msg.
|
|
13717
|
+
msg.cacheKey,
|
|
13636
13718
|
[],
|
|
13637
13719
|
void 0,
|
|
13638
13720
|
gatewayResult
|