@rubytech/create-maxy 1.0.877 → 1.0.879
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/cloudflare/PLUGIN.md +9 -0
- package/payload/platform/plugins/docs/references/platform.md +8 -2
- package/payload/platform/templates/agents/admin/IDENTITY.md +6 -0
- package/payload/server/chunk-2INJCOYG.js +1373 -0
- package/payload/server/chunk-DOIAYD3J.js +2282 -0
- package/payload/server/chunk-ICY65BIH.js +11364 -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-Q5J4NI6Q.js +660 -0
- package/payload/server/chunk-RP25NRQY.js +660 -0
- package/payload/server/client-pool-AIZ5QKFD.js +34 -0
- package/payload/server/client-pool-JAM3QHGW.js +34 -0
- package/payload/server/cloudflare-task-tracker-B6FXP3HI.js +20 -0
- package/payload/server/cloudflare-task-tracker-HUTXJQXO.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-uVxIhs_u.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 +569 -443
- 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-ICY65BIH.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-2INJCOYG.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-Q5J4NI6Q.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-DOIAYD3J.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(),
|
|
@@ -6884,7 +6894,7 @@ app9.post("/", async (c) => {
|
|
|
6884
6894
|
const safe = typeof v === "string" ? truncate(v, 200) : typeof v === "number" || typeof v === "boolean" ? String(v) : JSON.stringify(v).slice(0, 200);
|
|
6885
6895
|
return `${k}=${safe}`;
|
|
6886
6896
|
}).join(" ");
|
|
6887
|
-
const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set([]);
|
|
6897
|
+
const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set(["stream-log-click"]);
|
|
6888
6898
|
if (TAGGED_PREFIX_SOURCES.has(source)) {
|
|
6889
6899
|
console.log(
|
|
6890
6900
|
`[${source}] ts=${ts} ip=${ip} version=${version || "unknown"}${extra ? " " + extra : ""}`
|
|
@@ -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-JAM3QHGW.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";
|
|
@@ -8443,7 +8518,12 @@ function reconstructAssistantEvents(content, components, conversationId, message
|
|
|
8443
8518
|
}
|
|
8444
8519
|
valid += 1;
|
|
8445
8520
|
const eventIndex = events.length;
|
|
8446
|
-
events.push({
|
|
8521
|
+
events.push({
|
|
8522
|
+
type: "component",
|
|
8523
|
+
name: c.name,
|
|
8524
|
+
data: parsedData,
|
|
8525
|
+
...c.attachmentId ? { attachmentId: c.attachmentId } : {}
|
|
8526
|
+
});
|
|
8447
8527
|
if (c.submitted === true) {
|
|
8448
8528
|
submittedEventIndices.push(eventIndex);
|
|
8449
8529
|
}
|
|
@@ -8471,19 +8551,19 @@ function formatAge(updatedAtStr) {
|
|
|
8471
8551
|
return "unknown";
|
|
8472
8552
|
}
|
|
8473
8553
|
}
|
|
8474
|
-
var
|
|
8475
|
-
|
|
8476
|
-
const
|
|
8477
|
-
const accountId = getAccountIdForSession(
|
|
8554
|
+
var app18 = new Hono();
|
|
8555
|
+
app18.get("/", requireAdminSession, async (c) => {
|
|
8556
|
+
const cacheKey = c.var.cacheKey;
|
|
8557
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8478
8558
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8479
|
-
const userId = getUserIdForSession(
|
|
8559
|
+
const userId = getUserIdForSession(cacheKey);
|
|
8480
8560
|
if (!userId) return c.json({ error: "User identity required \u2014 authenticate with users.json PIN" }, 401);
|
|
8481
8561
|
try {
|
|
8482
8562
|
const flushed = await listAdminSessions(accountId, userId, 20);
|
|
8483
8563
|
const inProgressRaw = listAdminSessionsInProgress(accountId, userId);
|
|
8484
8564
|
const flushedRows = flushed.map((r) => ({
|
|
8485
8565
|
conversationId: r.conversationId,
|
|
8486
|
-
|
|
8566
|
+
cacheKey: null,
|
|
8487
8567
|
name: r.name,
|
|
8488
8568
|
updatedAt: r.updatedAt,
|
|
8489
8569
|
phase: "flushed",
|
|
@@ -8491,7 +8571,7 @@ app17.get("/", requireAdminSession, async (c) => {
|
|
|
8491
8571
|
}));
|
|
8492
8572
|
const inProgressRows = inProgressRaw.map((r) => ({
|
|
8493
8573
|
conversationId: null,
|
|
8494
|
-
|
|
8574
|
+
cacheKey: r.cacheKey,
|
|
8495
8575
|
name: null,
|
|
8496
8576
|
updatedAt: new Date(r.createdAt).toISOString(),
|
|
8497
8577
|
phase: "pre-flush",
|
|
@@ -8512,52 +8592,52 @@ app17.get("/", requireAdminSession, async (c) => {
|
|
|
8512
8592
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
8513
8593
|
}
|
|
8514
8594
|
});
|
|
8515
|
-
|
|
8516
|
-
const
|
|
8517
|
-
const accountId = getAccountIdForSession(
|
|
8518
|
-
const userId = getUserIdForSession(
|
|
8595
|
+
app18.post("/new", requireAdminSession, async (c) => {
|
|
8596
|
+
const oldCacheKey = c.var.cacheKey;
|
|
8597
|
+
const accountId = getAccountIdForSession(oldCacheKey);
|
|
8598
|
+
const userId = getUserIdForSession(oldCacheKey);
|
|
8519
8599
|
if (!accountId || !userId) {
|
|
8520
8600
|
return c.json({ error: "Session missing account or user context" }, 400);
|
|
8521
8601
|
}
|
|
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:
|
|
8602
|
+
const newCacheKey = crypto2.randomUUID();
|
|
8603
|
+
const userName = getUserNameForSession(oldCacheKey);
|
|
8604
|
+
registerSession(newCacheKey, "admin", accountId, void 0, userId, userName);
|
|
8605
|
+
const previousConversationId = clearSessionHistory(oldCacheKey);
|
|
8606
|
+
unregisterSession(oldCacheKey);
|
|
8607
|
+
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`);
|
|
8608
|
+
return c.json({ session_key: newCacheKey, conversationId: null });
|
|
8529
8609
|
});
|
|
8530
|
-
|
|
8531
|
-
const
|
|
8532
|
-
const accountId = getAccountIdForSession(
|
|
8533
|
-
const userId = getUserIdForSession(
|
|
8610
|
+
app18.post("/switch", requireAdminSession, async (c) => {
|
|
8611
|
+
const cacheKey = c.var.cacheKey;
|
|
8612
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8613
|
+
const userId = getUserIdForSession(cacheKey);
|
|
8534
8614
|
if (!accountId || !userId) {
|
|
8535
8615
|
return c.json({ error: "Session missing account or user context" }, 400);
|
|
8536
8616
|
}
|
|
8537
8617
|
const body = await c.req.json().catch(() => ({}));
|
|
8538
|
-
const
|
|
8539
|
-
if (!
|
|
8618
|
+
const targetCacheKey = typeof body.target_session_key === "string" ? body.target_session_key : "";
|
|
8619
|
+
if (!targetCacheKey) {
|
|
8540
8620
|
return c.json({ error: "target_session_key required" }, 400);
|
|
8541
8621
|
}
|
|
8542
|
-
const targetCheck = validateSession(
|
|
8622
|
+
const targetCheck = validateSession(targetCacheKey, "admin");
|
|
8543
8623
|
if (!targetCheck.ok) {
|
|
8544
|
-
console.error(`[session-switch] reject reason=${targetCheck.reason} from=${
|
|
8624
|
+
console.error(`[session-switch] reject reason=${targetCheck.reason} from=${cacheKey.slice(0, 8)} target=${targetCacheKey.slice(0, 8)}`);
|
|
8545
8625
|
return c.json({ error: "Target session not registered or wrong agent type", code: targetCheck.reason }, 404);
|
|
8546
8626
|
}
|
|
8547
|
-
const targetAccountId = getAccountIdForSession(
|
|
8548
|
-
const targetUserId = getUserIdForSession(
|
|
8627
|
+
const targetAccountId = getAccountIdForSession(targetCacheKey);
|
|
8628
|
+
const targetUserId = getUserIdForSession(targetCacheKey);
|
|
8549
8629
|
if (targetAccountId !== accountId || targetUserId !== userId) {
|
|
8550
|
-
console.error(`[session-switch] reject reason=ownership-mismatch from=${
|
|
8630
|
+
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
8631
|
return c.json({ error: "Target session not owned by current operator" }, 403);
|
|
8552
8632
|
}
|
|
8553
|
-
const targetConversationId = getConversationIdForSession(
|
|
8554
|
-
console.log(`[session-switch] from=${
|
|
8555
|
-
return c.json({ session_key:
|
|
8633
|
+
const targetConversationId = getConversationIdForSession(targetCacheKey) ?? null;
|
|
8634
|
+
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)}`);
|
|
8635
|
+
return c.json({ session_key: targetCacheKey, conversationId: targetConversationId });
|
|
8556
8636
|
});
|
|
8557
|
-
|
|
8637
|
+
app18.delete("/:id", requireAdminSession, async (c) => {
|
|
8558
8638
|
const conversationId = c.req.param("id");
|
|
8559
|
-
const
|
|
8560
|
-
const accountId = getAccountIdForSession(
|
|
8639
|
+
const cacheKey = c.var.cacheKey;
|
|
8640
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8561
8641
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8562
8642
|
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
8563
8643
|
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
@@ -8569,42 +8649,42 @@ app17.delete("/:id", requireAdminSession, async (c) => {
|
|
|
8569
8649
|
return c.json({ error: "Failed to delete session" }, 500);
|
|
8570
8650
|
}
|
|
8571
8651
|
});
|
|
8572
|
-
|
|
8652
|
+
app18.post("/:id/resume", async (c) => {
|
|
8573
8653
|
const conversationId = c.req.param("id");
|
|
8574
|
-
const
|
|
8575
|
-
if (!
|
|
8654
|
+
const cacheKey = c.req.query("session_key") ?? "";
|
|
8655
|
+
if (!cacheKey) {
|
|
8576
8656
|
console.error(`[session] middleware-reject status=400 code=session-missing reason="session_key required" path=${c.req.path}`);
|
|
8577
8657
|
return c.json({ error: "session_key required", code: "session-missing" }, 400);
|
|
8578
8658
|
}
|
|
8579
8659
|
let bridged = false;
|
|
8580
|
-
let result = validateSession(
|
|
8660
|
+
let result = validateSession(cacheKey, "admin");
|
|
8581
8661
|
if (!result.ok) {
|
|
8582
8662
|
if (result.reason === "session-not-registered") {
|
|
8583
|
-
const bridge = await tryCookieBridgeForConversation(c,
|
|
8663
|
+
const bridge = await tryCookieBridgeForConversation(c, cacheKey, conversationId);
|
|
8584
8664
|
if (!bridge.ok) {
|
|
8585
8665
|
if (bridge.reason === "conversation-not-found") {
|
|
8586
8666
|
return c.json({ error: "Conversation not found" }, 404);
|
|
8587
8667
|
}
|
|
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}
|
|
8668
|
+
const tail = cacheKey.slice(0, 8);
|
|
8669
|
+
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
8670
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
8591
8671
|
}
|
|
8592
8672
|
bridged = true;
|
|
8593
|
-
result = validateSession(
|
|
8673
|
+
result = validateSession(cacheKey, "admin");
|
|
8594
8674
|
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}
|
|
8675
|
+
const tail = cacheKey.slice(0, 8);
|
|
8676
|
+
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
8677
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
8598
8678
|
}
|
|
8599
8679
|
} else {
|
|
8600
|
-
const tail =
|
|
8680
|
+
const tail = cacheKey.slice(0, 8);
|
|
8601
8681
|
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}
|
|
8682
|
+
console.error(`[session] middleware-reject status=401 code=${wireCode} reason="invalid or expired admin session" path=${c.req.path} cacheKey=${tail}\u2026`);
|
|
8603
8683
|
return c.json({ error: "Invalid or expired admin session", code: wireCode }, 401);
|
|
8604
8684
|
}
|
|
8605
8685
|
}
|
|
8606
|
-
const accountId = getAccountIdForSession(
|
|
8607
|
-
const userId = getUserIdForSession(
|
|
8686
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8687
|
+
const userId = getUserIdForSession(cacheKey);
|
|
8608
8688
|
if (!accountId) {
|
|
8609
8689
|
return c.json({ error: "Session missing account context" }, 400);
|
|
8610
8690
|
}
|
|
@@ -8614,9 +8694,9 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8614
8694
|
const updatedAt = await verifyAndGetConversationUpdatedAt(conversationId, accountId);
|
|
8615
8695
|
if (updatedAt === null) return c.json({ error: "Conversation not found" }, 404);
|
|
8616
8696
|
const persistedAgentSessionId = await getAgentSessionIdForConversation(conversationId);
|
|
8617
|
-
setConversationIdForSession(
|
|
8697
|
+
setConversationIdForSession(cacheKey, conversationId);
|
|
8618
8698
|
if (persistedAgentSessionId) {
|
|
8619
|
-
setAgentSessionId(
|
|
8699
|
+
setAgentSessionId(cacheKey, persistedAgentSessionId);
|
|
8620
8700
|
}
|
|
8621
8701
|
const streamLogPath = resolvePath(ACCOUNTS_DIR, accountId, "logs", `claude-agent-stream-${conversationId}.log`);
|
|
8622
8702
|
const tag = persistedAgentSessionId ? `agentSessionId=${persistedAgentSessionId.slice(0, 8)}\u2026` : "agentSessionId=missing";
|
|
@@ -8641,7 +8721,7 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8641
8721
|
jsonlMalformedLines = replay.malformedLines;
|
|
8642
8722
|
jsonlReplayMessages = replay.messages;
|
|
8643
8723
|
if (replay.jsonlMissing) {
|
|
8644
|
-
console.error(`[jsonl-resume-miss]
|
|
8724
|
+
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
8725
|
}
|
|
8646
8726
|
} else {
|
|
8647
8727
|
jsonlMissing = true;
|
|
@@ -8656,13 +8736,15 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8656
8736
|
if (match) {
|
|
8657
8737
|
const mergedComponents = j.components.map((c2, i) => {
|
|
8658
8738
|
const neoComp = match.components?.[i];
|
|
8739
|
+
const attachmentId = neoComp?.attachmentId ?? c2.artefactAttachmentId;
|
|
8659
8740
|
return {
|
|
8660
8741
|
componentId: neoComp?.componentId ?? c2.componentId,
|
|
8661
8742
|
name: c2.name,
|
|
8662
8743
|
data: c2.data,
|
|
8663
8744
|
ordinal: c2.ordinal,
|
|
8664
8745
|
textOffset: c2.textOffset,
|
|
8665
|
-
submitted: neoComp?.submitted ?? false
|
|
8746
|
+
submitted: neoComp?.submitted ?? false,
|
|
8747
|
+
...attachmentId ? { attachmentId } : {}
|
|
8666
8748
|
};
|
|
8667
8749
|
});
|
|
8668
8750
|
return {
|
|
@@ -8686,7 +8768,9 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8686
8768
|
data: c2.data,
|
|
8687
8769
|
ordinal: c2.ordinal,
|
|
8688
8770
|
textOffset: c2.textOffset,
|
|
8689
|
-
submitted: false
|
|
8771
|
+
submitted: false,
|
|
8772
|
+
// Task 989 — JSONL has artefactAttachmentId for persistent components.
|
|
8773
|
+
...c2.artefactAttachmentId ? { attachmentId: c2.artefactAttachmentId } : {}
|
|
8690
8774
|
})),
|
|
8691
8775
|
attachments: []
|
|
8692
8776
|
};
|
|
@@ -8804,7 +8888,7 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8804
8888
|
const reason = bridged ? "post-restart" : "page-refresh";
|
|
8805
8889
|
try {
|
|
8806
8890
|
const source = jsonlMissing ? persistedAgentSessionId ? "jsonl-missing" : "neo4j-only" : "jsonl";
|
|
8807
|
-
appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} source=${source}
|
|
8891
|
+
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
8892
|
`);
|
|
8809
8893
|
if (totalComponents > 0) {
|
|
8810
8894
|
appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-rehydrate] conversationId=${conversationId.slice(0, 8)} count=${totalComponents} valid=${totalValid} invalid=${totalInvalid} textRuns=${textRuns}
|
|
@@ -8821,7 +8905,7 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8821
8905
|
} catch {
|
|
8822
8906
|
}
|
|
8823
8907
|
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}
|
|
8908
|
+
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
8909
|
return c.json({
|
|
8826
8910
|
conversationId,
|
|
8827
8911
|
messages: rehydrated,
|
|
@@ -8834,10 +8918,10 @@ app17.post("/:id/resume", async (c) => {
|
|
|
8834
8918
|
}
|
|
8835
8919
|
});
|
|
8836
8920
|
});
|
|
8837
|
-
|
|
8921
|
+
app18.post("/:id/label", requireAdminSession, async (c) => {
|
|
8838
8922
|
const conversationId = c.req.param("id");
|
|
8839
|
-
const
|
|
8840
|
-
const accountId = getAccountIdForSession(
|
|
8923
|
+
const cacheKey = c.var.cacheKey;
|
|
8924
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8841
8925
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8842
8926
|
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
8843
8927
|
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
@@ -8861,16 +8945,16 @@ app17.post("/:id/label", requireAdminSession, async (c) => {
|
|
|
8861
8945
|
return c.json({ label: null });
|
|
8862
8946
|
}
|
|
8863
8947
|
});
|
|
8864
|
-
|
|
8948
|
+
app18.put("/:id/label", requireAdminSession, async (c) => {
|
|
8865
8949
|
const conversationId = c.req.param("id");
|
|
8866
|
-
const
|
|
8950
|
+
const cacheKey = c.var.cacheKey;
|
|
8867
8951
|
let body;
|
|
8868
8952
|
try {
|
|
8869
8953
|
body = await c.req.json();
|
|
8870
8954
|
} catch {
|
|
8871
8955
|
return c.json({ error: "Invalid JSON body" }, 400);
|
|
8872
8956
|
}
|
|
8873
|
-
const accountId = getAccountIdForSession(
|
|
8957
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
8874
8958
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
8875
8959
|
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
8876
8960
|
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
@@ -8887,11 +8971,11 @@ app17.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
8887
8971
|
return c.json({ error: "Failed to rename session" }, 500);
|
|
8888
8972
|
}
|
|
8889
8973
|
});
|
|
8890
|
-
var sessions_default =
|
|
8974
|
+
var sessions_default = app18;
|
|
8891
8975
|
|
|
8892
8976
|
// server/routes/admin/browser.ts
|
|
8893
|
-
var
|
|
8894
|
-
|
|
8977
|
+
var app19 = new Hono();
|
|
8978
|
+
app19.post("/launch", async (c) => {
|
|
8895
8979
|
try {
|
|
8896
8980
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
8897
8981
|
if (transport === "vnc") {
|
|
@@ -8913,7 +8997,7 @@ app18.post("/launch", async (c) => {
|
|
|
8913
8997
|
);
|
|
8914
8998
|
}
|
|
8915
8999
|
});
|
|
8916
|
-
var browser_default =
|
|
9000
|
+
var browser_default = app19;
|
|
8917
9001
|
|
|
8918
9002
|
// server/routes/admin/browser-iframe.ts
|
|
8919
9003
|
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
@@ -8930,8 +9014,8 @@ function asString(v, max = 500) {
|
|
|
8930
9014
|
function asNumber(v) {
|
|
8931
9015
|
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
8932
9016
|
}
|
|
8933
|
-
var
|
|
8934
|
-
|
|
9017
|
+
var app20 = new Hono();
|
|
9018
|
+
app20.post("/event", async (c) => {
|
|
8935
9019
|
let body = {};
|
|
8936
9020
|
try {
|
|
8937
9021
|
body = await c.req.json();
|
|
@@ -8952,7 +9036,7 @@ app19.post("/event", async (c) => {
|
|
|
8952
9036
|
});
|
|
8953
9037
|
return c.body(null, 204);
|
|
8954
9038
|
});
|
|
8955
|
-
var browser_iframe_default =
|
|
9039
|
+
var browser_iframe_default = app20;
|
|
8956
9040
|
|
|
8957
9041
|
// app/lib/cdp-client.ts
|
|
8958
9042
|
var CDP_HOST = "127.0.0.1";
|
|
@@ -8995,8 +9079,8 @@ async function cdpNavigateNewTab(url, opts = {}) {
|
|
|
8995
9079
|
}
|
|
8996
9080
|
|
|
8997
9081
|
// server/routes/admin/device-browser.ts
|
|
8998
|
-
var
|
|
8999
|
-
|
|
9082
|
+
var app21 = new Hono();
|
|
9083
|
+
app21.post("/navigate", async (c) => {
|
|
9000
9084
|
const TAG19 = "[device-url:click]";
|
|
9001
9085
|
let body;
|
|
9002
9086
|
try {
|
|
@@ -9083,7 +9167,7 @@ app20.post("/navigate", async (c) => {
|
|
|
9083
9167
|
targetId: outcome.targetId
|
|
9084
9168
|
});
|
|
9085
9169
|
});
|
|
9086
|
-
var device_browser_default =
|
|
9170
|
+
var device_browser_default = app21;
|
|
9087
9171
|
|
|
9088
9172
|
// server/routes/admin/events.ts
|
|
9089
9173
|
var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
|
|
@@ -9092,8 +9176,8 @@ var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
|
|
|
9092
9176
|
"device-url:vnc-surface-shown",
|
|
9093
9177
|
"device-url:malformed"
|
|
9094
9178
|
]);
|
|
9095
|
-
var
|
|
9096
|
-
|
|
9179
|
+
var app22 = new Hono();
|
|
9180
|
+
app22.post("/", async (c) => {
|
|
9097
9181
|
const TAG19 = "[admin:events]";
|
|
9098
9182
|
let body;
|
|
9099
9183
|
try {
|
|
@@ -9124,7 +9208,7 @@ app21.post("/", async (c) => {
|
|
|
9124
9208
|
console.error(`[${event}] ${formatted}`);
|
|
9125
9209
|
return c.json({ ok: true });
|
|
9126
9210
|
});
|
|
9127
|
-
var events_default =
|
|
9211
|
+
var events_default = app22;
|
|
9128
9212
|
|
|
9129
9213
|
// server/routes/admin/cloudflare.ts
|
|
9130
9214
|
import { homedir as homedir2 } from "os";
|
|
@@ -9175,6 +9259,31 @@ var CLOUDFLARE_SETUP_FORM_SCHEMA = {
|
|
|
9175
9259
|
// server/routes/admin/cloudflare.ts
|
|
9176
9260
|
var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
9177
9261
|
var DOMAINS_TIMEOUT_MS = 40 * 1e3;
|
|
9262
|
+
var discoveryCache = /* @__PURE__ */ new Map();
|
|
9263
|
+
function getDiscoveryEntry(accountId) {
|
|
9264
|
+
let entry = discoveryCache.get(accountId);
|
|
9265
|
+
if (!entry) {
|
|
9266
|
+
entry = { tunnels: [], domains: [] };
|
|
9267
|
+
discoveryCache.set(accountId, entry);
|
|
9268
|
+
}
|
|
9269
|
+
return entry;
|
|
9270
|
+
}
|
|
9271
|
+
function rememberDomains(accountId, domains) {
|
|
9272
|
+
const entry = getDiscoveryEntry(accountId);
|
|
9273
|
+
entry.domains = domains;
|
|
9274
|
+
entry.domainsUpdatedAt = Date.now();
|
|
9275
|
+
}
|
|
9276
|
+
function rememberTunnels(accountId, tunnels) {
|
|
9277
|
+
const entry = getDiscoveryEntry(accountId);
|
|
9278
|
+
entry.tunnels = tunnels;
|
|
9279
|
+
entry.tunnelsUpdatedAt = Date.now();
|
|
9280
|
+
}
|
|
9281
|
+
function readDiscoveryResults(accountId) {
|
|
9282
|
+
if (!accountId) return { tunnels: [], domains: [] };
|
|
9283
|
+
const entry = discoveryCache.get(accountId);
|
|
9284
|
+
if (!entry) return { tunnels: [], domains: [] };
|
|
9285
|
+
return { tunnels: entry.tunnels, domains: entry.domains };
|
|
9286
|
+
}
|
|
9178
9287
|
function loadBrandInfo() {
|
|
9179
9288
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve13(process.cwd(), "..");
|
|
9180
9289
|
const brandPath = resolve13(platformRoot2, "config", "brand.json");
|
|
@@ -9242,7 +9351,7 @@ function validateBody(body) {
|
|
|
9242
9351
|
}
|
|
9243
9352
|
return null;
|
|
9244
9353
|
}
|
|
9245
|
-
var
|
|
9354
|
+
var app23 = new Hono();
|
|
9246
9355
|
function fieldFromReason(reason) {
|
|
9247
9356
|
switch (reason) {
|
|
9248
9357
|
case "not-signed-in":
|
|
@@ -9263,15 +9372,15 @@ function fieldFromReason(reason) {
|
|
|
9263
9372
|
return "script";
|
|
9264
9373
|
}
|
|
9265
9374
|
}
|
|
9266
|
-
|
|
9375
|
+
app23.get("/domains", requireAdminSession, async (c) => {
|
|
9267
9376
|
const started = Date.now();
|
|
9268
|
-
const
|
|
9377
|
+
const cacheKey = c.var.cacheKey;
|
|
9269
9378
|
let correlationId;
|
|
9270
|
-
let
|
|
9379
|
+
let cacheKeyTail;
|
|
9271
9380
|
let streamLogPath;
|
|
9272
9381
|
function tag() {
|
|
9273
9382
|
if (!correlationId) return "";
|
|
9274
|
-
return ` conversationId=${correlationId} session_key=${
|
|
9383
|
+
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9275
9384
|
}
|
|
9276
9385
|
function log(line) {
|
|
9277
9386
|
console.log(`[cloudflare-domains] ${line}${tag()}`);
|
|
@@ -9299,9 +9408,9 @@ app22.get("/domains", requireAdminSession, async (c) => {
|
|
|
9299
9408
|
};
|
|
9300
9409
|
return c.json(body, 200);
|
|
9301
9410
|
}
|
|
9302
|
-
const accountId = getAccountIdForSession(
|
|
9303
|
-
correlationId = getConversationIdForSession(
|
|
9304
|
-
|
|
9411
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9412
|
+
correlationId = getConversationIdForSession(cacheKey);
|
|
9413
|
+
cacheKeyTail = cacheKey.slice(-8);
|
|
9305
9414
|
if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
|
|
9306
9415
|
if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
|
|
9307
9416
|
streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
|
|
@@ -9348,6 +9457,7 @@ ${result.stderr}` : ""}`;
|
|
|
9348
9457
|
correlationId,
|
|
9349
9458
|
streamLogPath
|
|
9350
9459
|
};
|
|
9460
|
+
rememberDomains(accountId, domains);
|
|
9351
9461
|
const total = Date.now() - started;
|
|
9352
9462
|
log(`phase=response-sent total_ms=${total} count=${domains.length}`);
|
|
9353
9463
|
writeRouteMilestone(
|
|
@@ -9358,15 +9468,15 @@ ${result.stderr}` : ""}`;
|
|
|
9358
9468
|
return c.json(success, 200);
|
|
9359
9469
|
});
|
|
9360
9470
|
var TUNNELS_TIMEOUT_MS = 30 * 1e3;
|
|
9361
|
-
|
|
9471
|
+
app23.get("/tunnels", requireAdminSession, async (c) => {
|
|
9362
9472
|
const started = Date.now();
|
|
9363
|
-
const
|
|
9473
|
+
const cacheKey = c.var.cacheKey;
|
|
9364
9474
|
let correlationId;
|
|
9365
|
-
let
|
|
9475
|
+
let cacheKeyTail;
|
|
9366
9476
|
let streamLogPath;
|
|
9367
9477
|
function tag() {
|
|
9368
9478
|
if (!correlationId) return "";
|
|
9369
|
-
return ` conversationId=${correlationId} session_key=${
|
|
9479
|
+
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9370
9480
|
}
|
|
9371
9481
|
function log(line) {
|
|
9372
9482
|
console.log(`[cloudflare-tunnels] ${line}${tag()}`);
|
|
@@ -9391,9 +9501,9 @@ app22.get("/tunnels", requireAdminSession, async (c) => {
|
|
|
9391
9501
|
const body = { ok: false, field, message, output, defaultName, correlationId, streamLogPath };
|
|
9392
9502
|
return c.json(body, 200);
|
|
9393
9503
|
}
|
|
9394
|
-
const accountId = getAccountIdForSession(
|
|
9395
|
-
correlationId = getConversationIdForSession(
|
|
9396
|
-
|
|
9504
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9505
|
+
correlationId = getConversationIdForSession(cacheKey);
|
|
9506
|
+
cacheKeyTail = cacheKey.slice(-8);
|
|
9397
9507
|
if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
|
|
9398
9508
|
if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
|
|
9399
9509
|
streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
|
|
@@ -9451,18 +9561,21 @@ ${result.stderr}` : ""}`;
|
|
|
9451
9561
|
"cloudflare-tunnels",
|
|
9452
9562
|
`phase=response-sent total_ms=${total} count=${tunnels.length} source=cloudflared${nullTag}`
|
|
9453
9563
|
);
|
|
9564
|
+
rememberTunnels(accountId, tunnels);
|
|
9454
9565
|
const success = { ok: true, tunnels, defaultName, correlationId, streamLogPath };
|
|
9455
9566
|
return c.json(success, 200);
|
|
9456
9567
|
});
|
|
9457
|
-
|
|
9568
|
+
app23.post("/setup", requireAdminSession, async (c) => {
|
|
9458
9569
|
const started = Date.now();
|
|
9459
|
-
const
|
|
9570
|
+
const cacheKey = c.var.cacheKey;
|
|
9460
9571
|
let correlationId;
|
|
9461
|
-
let
|
|
9572
|
+
let cacheKeyTail;
|
|
9462
9573
|
let streamLogPath;
|
|
9574
|
+
let resolvedAccountId;
|
|
9575
|
+
const heldInputs = {};
|
|
9463
9576
|
function tag() {
|
|
9464
9577
|
if (!correlationId) return "";
|
|
9465
|
-
return ` conversationId=${correlationId} session_key=${
|
|
9578
|
+
return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
|
|
9466
9579
|
}
|
|
9467
9580
|
function log(line) {
|
|
9468
9581
|
console.log(`[cloudflare-setup] ${line}${tag()}`);
|
|
@@ -9485,7 +9598,9 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9485
9598
|
message,
|
|
9486
9599
|
output,
|
|
9487
9600
|
correlationId,
|
|
9488
|
-
streamLogPath
|
|
9601
|
+
streamLogPath,
|
|
9602
|
+
inputsAlreadyHeld: { ...heldInputs },
|
|
9603
|
+
discoveryResults: readDiscoveryResults(resolvedAccountId)
|
|
9489
9604
|
};
|
|
9490
9605
|
return c.json(body2, 200);
|
|
9491
9606
|
}
|
|
@@ -9498,12 +9613,13 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9498
9613
|
} catch {
|
|
9499
9614
|
return err("request", "Invalid JSON body");
|
|
9500
9615
|
}
|
|
9501
|
-
const accountId = getAccountIdForSession(
|
|
9502
|
-
correlationId = getConversationIdForSession(
|
|
9503
|
-
|
|
9616
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9617
|
+
correlationId = getConversationIdForSession(cacheKey);
|
|
9618
|
+
cacheKeyTail = cacheKey.slice(-8);
|
|
9504
9619
|
if (!accountId) {
|
|
9505
9620
|
return err("request", "No account bound to session \u2014 refresh chat.");
|
|
9506
9621
|
}
|
|
9622
|
+
resolvedAccountId = accountId;
|
|
9507
9623
|
if (!correlationId) {
|
|
9508
9624
|
return err("request", "No active conversation for session \u2014 refresh chat.");
|
|
9509
9625
|
}
|
|
@@ -9512,6 +9628,9 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9512
9628
|
const adminFqdn = `${body.adminLabel}.${body.adminDomain}`;
|
|
9513
9629
|
const publicFqdn = body.publicLabel ? `${body.publicLabel}.${body.publicDomain}` : void 0;
|
|
9514
9630
|
const apex = body.apex && body.apex.length > 0 ? body.apex : void 0;
|
|
9631
|
+
heldInputs.admin = adminFqdn;
|
|
9632
|
+
if (publicFqdn) heldInputs.public = publicFqdn;
|
|
9633
|
+
if (apex) heldInputs.apex = apex;
|
|
9515
9634
|
log(`phase=submit-received admin=${adminFqdn} public=${publicFqdn ?? "absent"} apex=${apex ?? "absent"}`);
|
|
9516
9635
|
const account = resolveAccount();
|
|
9517
9636
|
if (!account) {
|
|
@@ -9553,7 +9672,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9553
9672
|
try {
|
|
9554
9673
|
cloudflareTask = await openCloudflareTask({
|
|
9555
9674
|
accountId,
|
|
9556
|
-
|
|
9675
|
+
conversationId: correlationId,
|
|
9557
9676
|
inputsProvided: Object.keys(taskInputs),
|
|
9558
9677
|
inputs: taskInputs,
|
|
9559
9678
|
inputSchema: CLOUDFLARE_SETUP_FORM_SCHEMA,
|
|
@@ -9601,7 +9720,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9601
9720
|
taskId: cloudflareTask.taskId,
|
|
9602
9721
|
taskElementId: cloudflareTask.taskElementId,
|
|
9603
9722
|
accountId,
|
|
9604
|
-
|
|
9723
|
+
conversationId: correlationId,
|
|
9605
9724
|
status: "failed",
|
|
9606
9725
|
errorMessage: CLOUDFLARE_TASK_DIAGNOSTICS.endpointDiedPreReconcile
|
|
9607
9726
|
});
|
|
@@ -9618,7 +9737,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9618
9737
|
taskId: cloudflareTask.taskId,
|
|
9619
9738
|
taskElementId: cloudflareTask.taskElementId,
|
|
9620
9739
|
accountId,
|
|
9621
|
-
|
|
9740
|
+
conversationId: correlationId,
|
|
9622
9741
|
status: "failed",
|
|
9623
9742
|
errorMessage: `${CLOUDFLARE_TASK_DIAGNOSTICS.scriptExitedNonzero} exit=${status.execMainStatus}`
|
|
9624
9743
|
});
|
|
@@ -9660,7 +9779,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
|
|
|
9660
9779
|
taskId: cloudflareTask.taskId,
|
|
9661
9780
|
taskElementId: cloudflareTask.taskElementId,
|
|
9662
9781
|
accountId,
|
|
9663
|
-
|
|
9782
|
+
conversationId: correlationId,
|
|
9664
9783
|
tunnelId: tunnelState?.tunnelId,
|
|
9665
9784
|
tunnelName: tunnelState?.tunnelName,
|
|
9666
9785
|
hostnames: tunnelState ? hostnameRecords : void 0,
|
|
@@ -9691,7 +9810,7 @@ actionId: ${actionId}`,
|
|
|
9691
9810
|
};
|
|
9692
9811
|
return ok(success);
|
|
9693
9812
|
});
|
|
9694
|
-
var cloudflare_default =
|
|
9813
|
+
var cloudflare_default = app23;
|
|
9695
9814
|
|
|
9696
9815
|
// server/routes/admin/files.ts
|
|
9697
9816
|
import { createReadStream as createReadStream3 } from "fs";
|
|
@@ -9751,7 +9870,7 @@ var UNIQUE_KEYS_BY_LABEL = {
|
|
|
9751
9870
|
Event: ["eventId"],
|
|
9752
9871
|
KnowledgeDocument: ["attachmentId"],
|
|
9753
9872
|
DigitalDocument: ["attachmentId"],
|
|
9754
|
-
Conversation: ["conversationId"
|
|
9873
|
+
Conversation: ["conversationId"],
|
|
9755
9874
|
Message: ["messageId"],
|
|
9756
9875
|
OnboardingState: ["accountId"],
|
|
9757
9876
|
Workflow: ["workflowId"],
|
|
@@ -9972,7 +10091,7 @@ async function restoreNode(params) {
|
|
|
9972
10091
|
}
|
|
9973
10092
|
|
|
9974
10093
|
// app/lib/file-delete-cascade.ts
|
|
9975
|
-
var
|
|
10094
|
+
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
10095
|
function parseAttachmentPath(relPath2) {
|
|
9977
10096
|
const segments = relPath2.split("/").filter(Boolean);
|
|
9978
10097
|
if (segments.length !== 4) return null;
|
|
@@ -9980,7 +10099,7 @@ function parseAttachmentPath(relPath2) {
|
|
|
9980
10099
|
const accountId = segments[1];
|
|
9981
10100
|
const attachmentId = segments[2];
|
|
9982
10101
|
const filename = segments[3];
|
|
9983
|
-
if (!
|
|
10102
|
+
if (!UUID_RE4.test(accountId) || !UUID_RE4.test(attachmentId)) return null;
|
|
9984
10103
|
const dot = filename.lastIndexOf(".");
|
|
9985
10104
|
if (dot === -1) return null;
|
|
9986
10105
|
const stem = filename.slice(0, dot);
|
|
@@ -10052,7 +10171,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
10052
10171
|
}
|
|
10053
10172
|
|
|
10054
10173
|
// server/routes/admin/files.ts
|
|
10055
|
-
var
|
|
10174
|
+
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
10175
|
async function readMeta(absDir, baseName) {
|
|
10057
10176
|
try {
|
|
10058
10177
|
const raw = await readFile3(join9(absDir, `${baseName}.meta.json`), "utf8");
|
|
@@ -10074,7 +10193,7 @@ async function readAccountNames() {
|
|
|
10074
10193
|
return map;
|
|
10075
10194
|
}
|
|
10076
10195
|
for (const name of names) {
|
|
10077
|
-
if (!
|
|
10196
|
+
if (!UUID_RE5.test(name)) continue;
|
|
10078
10197
|
const configPath2 = resolve15(accountsDir, name, "account.json");
|
|
10079
10198
|
try {
|
|
10080
10199
|
const raw = await readFile3(configPath2, "utf8");
|
|
@@ -10092,7 +10211,7 @@ async function readAccountNames() {
|
|
|
10092
10211
|
return map;
|
|
10093
10212
|
}
|
|
10094
10213
|
async function enrich(absolute, entry, accountNames) {
|
|
10095
|
-
if (entry.kind === "directory" &&
|
|
10214
|
+
if (entry.kind === "directory" && UUID_RE5.test(entry.name)) {
|
|
10096
10215
|
const meta = await readMeta(join9(absolute, entry.name), entry.name);
|
|
10097
10216
|
if (meta?.filename) {
|
|
10098
10217
|
entry.displayName = meta.filename;
|
|
@@ -10108,7 +10227,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
10108
10227
|
if (entry.kind === "file") {
|
|
10109
10228
|
const dot = entry.name.lastIndexOf(".");
|
|
10110
10229
|
const base = dot === -1 ? entry.name : entry.name.slice(0, dot);
|
|
10111
|
-
if (
|
|
10230
|
+
if (UUID_RE5.test(base)) {
|
|
10112
10231
|
const meta = await readMeta(absolute, base);
|
|
10113
10232
|
if (meta?.filename) {
|
|
10114
10233
|
entry.displayName = meta.filename;
|
|
@@ -10120,14 +10239,14 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
10120
10239
|
function buildDisplayPath(relPath2, accountNames) {
|
|
10121
10240
|
if (relPath2 === "." || relPath2 === "") return [];
|
|
10122
10241
|
return relPath2.split("/").filter(Boolean).map((seg) => {
|
|
10123
|
-
const dn =
|
|
10242
|
+
const dn = UUID_RE5.test(seg) ? accountNames.get(seg) : void 0;
|
|
10124
10243
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
10125
10244
|
});
|
|
10126
10245
|
}
|
|
10127
|
-
var
|
|
10128
|
-
|
|
10129
|
-
const
|
|
10130
|
-
if (!getAccountIdForSession(
|
|
10246
|
+
var app24 = new Hono();
|
|
10247
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
10248
|
+
const cacheKey = c.var.cacheKey;
|
|
10249
|
+
if (!getAccountIdForSession(cacheKey)) {
|
|
10131
10250
|
console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
|
|
10132
10251
|
return c.json({ error: "Account not found for session" }, 401);
|
|
10133
10252
|
}
|
|
@@ -10148,7 +10267,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
10148
10267
|
const names = await readdir2(absolute);
|
|
10149
10268
|
const entries = [];
|
|
10150
10269
|
for (const name of names) {
|
|
10151
|
-
if (
|
|
10270
|
+
if (UUID_RE5.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
10152
10271
|
continue;
|
|
10153
10272
|
}
|
|
10154
10273
|
try {
|
|
@@ -10186,9 +10305,9 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
10186
10305
|
return c.json({ error: message }, 500);
|
|
10187
10306
|
}
|
|
10188
10307
|
});
|
|
10189
|
-
|
|
10190
|
-
const
|
|
10191
|
-
if (!getAccountIdForSession(
|
|
10308
|
+
app24.get("/download", requireAdminSession, async (c) => {
|
|
10309
|
+
const cacheKey = c.var.cacheKey;
|
|
10310
|
+
if (!getAccountIdForSession(cacheKey)) {
|
|
10192
10311
|
console.error(`[data] auth-rejected endpoint="/api/admin/files/download" reason="no account for session"`);
|
|
10193
10312
|
return c.json({ error: "Account not found for session" }, 401);
|
|
10194
10313
|
}
|
|
@@ -10234,9 +10353,9 @@ app23.get("/download", requireAdminSession, async (c) => {
|
|
|
10234
10353
|
return c.json({ error: message }, 500);
|
|
10235
10354
|
}
|
|
10236
10355
|
});
|
|
10237
|
-
|
|
10238
|
-
const
|
|
10239
|
-
const accountId = getAccountIdForSession(
|
|
10356
|
+
app24.post("/upload", requireAdminSession, async (c) => {
|
|
10357
|
+
const cacheKey = c.var.cacheKey;
|
|
10358
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
10240
10359
|
if (!accountId) {
|
|
10241
10360
|
console.error(`[data] auth-rejected endpoint="/api/admin/files/upload" reason="no account for session"`);
|
|
10242
10361
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10292,9 +10411,9 @@ app23.post("/upload", requireAdminSession, async (c) => {
|
|
|
10292
10411
|
mimeType: file.type
|
|
10293
10412
|
});
|
|
10294
10413
|
});
|
|
10295
|
-
|
|
10296
|
-
const
|
|
10297
|
-
const accountId = getAccountIdForSession(
|
|
10414
|
+
app24.delete("/", requireAdminSession, async (c) => {
|
|
10415
|
+
const cacheKey = c.var.cacheKey;
|
|
10416
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
10298
10417
|
if (!accountId) {
|
|
10299
10418
|
console.error(`[data] auth-rejected endpoint="DELETE /api/admin/files" reason="no account for session"`);
|
|
10300
10419
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10325,7 +10444,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
10325
10444
|
}
|
|
10326
10445
|
const dot = base.lastIndexOf(".");
|
|
10327
10446
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
10328
|
-
const sidecarPath =
|
|
10447
|
+
const sidecarPath = UUID_RE5.test(stem) && base !== `${stem}.meta.json` ? join9(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
10329
10448
|
await unlink2(absolute);
|
|
10330
10449
|
if (sidecarPath) {
|
|
10331
10450
|
try {
|
|
@@ -10359,7 +10478,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
10359
10478
|
return c.json({ error: message }, 500);
|
|
10360
10479
|
}
|
|
10361
10480
|
});
|
|
10362
|
-
var files_default =
|
|
10481
|
+
var files_default = app24;
|
|
10363
10482
|
|
|
10364
10483
|
// ../lib/graph-search/src/index.ts
|
|
10365
10484
|
var import_dist = __toESM(require_dist());
|
|
@@ -10739,14 +10858,14 @@ var MAX_LIMIT = 2e3;
|
|
|
10739
10858
|
var DEFAULT_VECTOR_THRESHOLD = 0.82;
|
|
10740
10859
|
var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
|
|
10741
10860
|
var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
|
|
10742
|
-
var
|
|
10743
|
-
|
|
10744
|
-
const
|
|
10861
|
+
var app25 = new Hono();
|
|
10862
|
+
app25.get("/", requireAdminSession, async (c) => {
|
|
10863
|
+
const cacheKey = c.var.cacheKey;
|
|
10745
10864
|
const q = (c.req.query("q") ?? "").trim();
|
|
10746
10865
|
const rawLimit = c.req.query("limit");
|
|
10747
10866
|
const rawLabels = c.req.query("labels");
|
|
10748
10867
|
const rawThreshold = c.req.query("threshold");
|
|
10749
|
-
const accountId = getAccountIdForSession(
|
|
10868
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
10750
10869
|
if (!accountId) {
|
|
10751
10870
|
console.error(`[graph-search] auth-rejected endpoint="/api/admin/graph-search" reason="no account for session"`);
|
|
10752
10871
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10871,7 +10990,7 @@ app24.get("/", requireAdminSession, async (c) => {
|
|
|
10871
10990
|
await session.close();
|
|
10872
10991
|
}
|
|
10873
10992
|
});
|
|
10874
|
-
var graph_search_default =
|
|
10993
|
+
var graph_search_default = app25;
|
|
10875
10994
|
|
|
10876
10995
|
// server/routes/admin/graph-subgraph.ts
|
|
10877
10996
|
import neo4j2 from "neo4j-driver";
|
|
@@ -11027,12 +11146,12 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
11027
11146
|
"passwordHash",
|
|
11028
11147
|
"magicToken",
|
|
11029
11148
|
"otpCode",
|
|
11030
|
-
"
|
|
11149
|
+
"cacheKey"
|
|
11031
11150
|
]);
|
|
11032
|
-
var
|
|
11033
|
-
|
|
11034
|
-
const
|
|
11035
|
-
const accountId = getAccountIdForSession(
|
|
11151
|
+
var app26 = new Hono();
|
|
11152
|
+
app26.get("/", requireAdminSession, async (c) => {
|
|
11153
|
+
const cacheKey = c.var.cacheKey;
|
|
11154
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11036
11155
|
if (!accountId) {
|
|
11037
11156
|
console.error('[graph-page] auth-rejected reason="no account for session"');
|
|
11038
11157
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11613,14 +11732,14 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
11613
11732
|
}
|
|
11614
11733
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
11615
11734
|
}
|
|
11616
|
-
var graph_subgraph_default =
|
|
11735
|
+
var graph_subgraph_default = app26;
|
|
11617
11736
|
|
|
11618
11737
|
// server/routes/admin/graph-delete.ts
|
|
11619
11738
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash"];
|
|
11620
|
-
var
|
|
11621
|
-
|
|
11622
|
-
const
|
|
11623
|
-
const accountId = getAccountIdForSession(
|
|
11739
|
+
var app27 = new Hono();
|
|
11740
|
+
app27.post("/", requireAdminSession, async (c) => {
|
|
11741
|
+
const cacheKey = c.var.cacheKey;
|
|
11742
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11624
11743
|
if (!accountId) {
|
|
11625
11744
|
console.error('[graph-page] delete auth-rejected reason="no account for session"');
|
|
11626
11745
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11689,13 +11808,13 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
11689
11808
|
}
|
|
11690
11809
|
}
|
|
11691
11810
|
});
|
|
11692
|
-
var graph_delete_default =
|
|
11811
|
+
var graph_delete_default = app27;
|
|
11693
11812
|
|
|
11694
11813
|
// server/routes/admin/graph-restore.ts
|
|
11695
|
-
var
|
|
11696
|
-
|
|
11697
|
-
const
|
|
11698
|
-
const accountId = getAccountIdForSession(
|
|
11814
|
+
var app28 = new Hono();
|
|
11815
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
11816
|
+
const cacheKey = c.var.cacheKey;
|
|
11817
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11699
11818
|
if (!accountId) {
|
|
11700
11819
|
console.error('[graph-page] restore auth-rejected reason="no account for session"');
|
|
11701
11820
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11757,13 +11876,13 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
11757
11876
|
}
|
|
11758
11877
|
}
|
|
11759
11878
|
});
|
|
11760
|
-
var graph_restore_default =
|
|
11879
|
+
var graph_restore_default = app28;
|
|
11761
11880
|
|
|
11762
11881
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
11763
|
-
var
|
|
11764
|
-
|
|
11765
|
-
const
|
|
11766
|
-
const accountId = getAccountIdForSession(
|
|
11882
|
+
var app29 = new Hono();
|
|
11883
|
+
app29.get("/", requireAdminSession, async (c) => {
|
|
11884
|
+
const cacheKey = c.var.cacheKey;
|
|
11885
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11767
11886
|
if (!accountId) {
|
|
11768
11887
|
console.error('[graph-page] labels-in-graph-rejected reason="no account for session"');
|
|
11769
11888
|
return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11827,14 +11946,14 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
11827
11946
|
sum(halfEdges) AS relDegree
|
|
11828
11947
|
RETURN label, nodeCount, relDegree
|
|
11829
11948
|
`;
|
|
11830
|
-
var graph_labels_in_graph_default =
|
|
11949
|
+
var graph_labels_in_graph_default = app29;
|
|
11831
11950
|
|
|
11832
11951
|
// server/routes/admin/graph-default-view.ts
|
|
11833
|
-
var
|
|
11834
|
-
|
|
11835
|
-
const
|
|
11836
|
-
const accountId = getAccountIdForSession(
|
|
11837
|
-
const userId = getUserIdForSession(
|
|
11952
|
+
var app30 = new Hono();
|
|
11953
|
+
app30.get("/", requireAdminSession, async (c) => {
|
|
11954
|
+
const cacheKey = c.var.cacheKey;
|
|
11955
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11956
|
+
const userId = getUserIdForSession(cacheKey);
|
|
11838
11957
|
if (!accountId || !userId) {
|
|
11839
11958
|
console.error('[graph-page] default-view-rejected reason="missing account or user context"');
|
|
11840
11959
|
return c.json({ error: "Account and user context required for default view" }, 401);
|
|
@@ -11869,10 +11988,10 @@ app29.get("/", requireAdminSession, async (c) => {
|
|
|
11869
11988
|
}
|
|
11870
11989
|
}
|
|
11871
11990
|
});
|
|
11872
|
-
|
|
11873
|
-
const
|
|
11874
|
-
const accountId = getAccountIdForSession(
|
|
11875
|
-
const userId = getUserIdForSession(
|
|
11991
|
+
app30.put("/", requireAdminSession, async (c) => {
|
|
11992
|
+
const cacheKey = c.var.cacheKey;
|
|
11993
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11994
|
+
const userId = getUserIdForSession(cacheKey);
|
|
11876
11995
|
if (!accountId || !userId) {
|
|
11877
11996
|
console.error('[graph-page] default-view-rejected reason="missing account or user context"');
|
|
11878
11997
|
return c.json({ error: "Account and user context required for default view" }, 401);
|
|
@@ -11958,11 +12077,11 @@ var WRITE_CYPHER = `
|
|
|
11958
12077
|
p.updatedAt = $updatedAt
|
|
11959
12078
|
RETURN p.labels AS labels
|
|
11960
12079
|
`;
|
|
11961
|
-
var graph_default_view_default =
|
|
12080
|
+
var graph_default_view_default = app30;
|
|
11962
12081
|
|
|
11963
12082
|
// server/routes/admin/file-attach.ts
|
|
11964
|
-
var
|
|
11965
|
-
|
|
12083
|
+
var app31 = new Hono();
|
|
12084
|
+
app31.post("/", async (c) => {
|
|
11966
12085
|
try {
|
|
11967
12086
|
const body = await c.req.json();
|
|
11968
12087
|
const { filePath, accountId } = body;
|
|
@@ -11985,11 +12104,11 @@ app30.post("/", async (c) => {
|
|
|
11985
12104
|
return c.json({ error: message }, 500);
|
|
11986
12105
|
}
|
|
11987
12106
|
});
|
|
11988
|
-
var file_attach_default =
|
|
12107
|
+
var file_attach_default = app31;
|
|
11989
12108
|
|
|
11990
12109
|
// server/routes/admin/adherence.ts
|
|
11991
|
-
var
|
|
11992
|
-
|
|
12110
|
+
var app32 = new Hono();
|
|
12111
|
+
app32.get("/", requireAdminSession, async (c) => {
|
|
11993
12112
|
const agent = c.req.query("agent") ?? "admin";
|
|
11994
12113
|
const includeBlock = c.req.query("block") === "1";
|
|
11995
12114
|
const account = resolveAccount();
|
|
@@ -12010,7 +12129,7 @@ app31.get("/", requireAdminSession, async (c) => {
|
|
|
12010
12129
|
return c.json({ error: "Failed to read adherence ledger", agent }, 500);
|
|
12011
12130
|
}
|
|
12012
12131
|
});
|
|
12013
|
-
var adherence_default =
|
|
12132
|
+
var adherence_default = app32;
|
|
12014
12133
|
|
|
12015
12134
|
// server/routes/admin/sidebar-artefacts.ts
|
|
12016
12135
|
import neo4j3 from "neo4j-driver";
|
|
@@ -12020,10 +12139,10 @@ import { existsSync as existsSync18 } from "fs";
|
|
|
12020
12139
|
var LIMIT = 50;
|
|
12021
12140
|
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
12022
12141
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
12023
|
-
var
|
|
12024
|
-
|
|
12025
|
-
const
|
|
12026
|
-
const accountId = getAccountIdForSession(
|
|
12142
|
+
var app33 = new Hono();
|
|
12143
|
+
app33.get("/", requireAdminSession, async (c) => {
|
|
12144
|
+
const cacheKey = c.var.cacheKey;
|
|
12145
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
12027
12146
|
if (!accountId) {
|
|
12028
12147
|
return c.json({ error: "Account not found for session" }, 401);
|
|
12029
12148
|
}
|
|
@@ -12227,18 +12346,18 @@ function isWithin(target, root) {
|
|
|
12227
12346
|
const rel = relative2(root, target);
|
|
12228
12347
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
12229
12348
|
}
|
|
12230
|
-
var sidebar_artefacts_default =
|
|
12349
|
+
var sidebar_artefacts_default = app33;
|
|
12231
12350
|
|
|
12232
12351
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
12233
12352
|
import { mkdir as mkdir3, readdir as readdir4, stat as stat5, writeFile as writeFile4 } from "fs/promises";
|
|
12234
12353
|
import { resolve as resolve17 } from "path";
|
|
12235
12354
|
import { existsSync as existsSync19 } from "fs";
|
|
12236
12355
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
12237
|
-
var
|
|
12238
|
-
var
|
|
12239
|
-
|
|
12240
|
-
const
|
|
12241
|
-
const accountId = getAccountIdForSession(
|
|
12356
|
+
var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12357
|
+
var app34 = new Hono();
|
|
12358
|
+
app34.post("/", requireAdminSession, async (c) => {
|
|
12359
|
+
const cacheKey = c.var.cacheKey;
|
|
12360
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
12242
12361
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
12243
12362
|
const body = await safeJson(c);
|
|
12244
12363
|
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
@@ -12294,7 +12413,7 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12294
12413
|
}
|
|
12295
12414
|
return { kind: "admin-template", path: resolve17(parent, filename) };
|
|
12296
12415
|
}
|
|
12297
|
-
if (
|
|
12416
|
+
if (UUID_RE6.test(id)) {
|
|
12298
12417
|
const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
|
|
12299
12418
|
if (!existsSync19(dir)) {
|
|
12300
12419
|
return { kind: "reject", status: 400, reason: "not-found" };
|
|
@@ -12316,20 +12435,20 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12316
12435
|
function relPath(absPath, root) {
|
|
12317
12436
|
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
12318
12437
|
}
|
|
12319
|
-
var sidebar_artefact_save_default =
|
|
12438
|
+
var sidebar_artefact_save_default = app34;
|
|
12320
12439
|
|
|
12321
12440
|
// server/routes/admin/sidebar-artefact-content.ts
|
|
12322
12441
|
import { readFile as readFile5, readdir as readdir5 } from "fs/promises";
|
|
12323
12442
|
import { existsSync as existsSync20 } from "fs";
|
|
12324
12443
|
import { resolve as resolve18 } from "path";
|
|
12325
|
-
var
|
|
12326
|
-
var
|
|
12327
|
-
|
|
12328
|
-
const
|
|
12329
|
-
const accountId = getAccountIdForSession(
|
|
12444
|
+
var UUID_RE7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12445
|
+
var app35 = new Hono();
|
|
12446
|
+
app35.get("/", requireAdminSession, async (c) => {
|
|
12447
|
+
const cacheKey = c.var.cacheKey;
|
|
12448
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
12330
12449
|
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
|
12331
12450
|
const id = c.req.query("id") ?? "";
|
|
12332
|
-
if (!
|
|
12451
|
+
if (!UUID_RE7.test(id)) {
|
|
12333
12452
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12334
12453
|
return new Response("Not found", { status: 404 });
|
|
12335
12454
|
}
|
|
@@ -12365,7 +12484,7 @@ app34.get("/", requireAdminSession, async (c) => {
|
|
|
12365
12484
|
}
|
|
12366
12485
|
});
|
|
12367
12486
|
});
|
|
12368
|
-
var sidebar_artefact_content_default =
|
|
12487
|
+
var sidebar_artefact_content_default = app35;
|
|
12369
12488
|
|
|
12370
12489
|
// server/routes/admin/health.ts
|
|
12371
12490
|
import { existsSync as existsSync21, readFileSync as readFileSync16 } from "fs";
|
|
@@ -12410,8 +12529,8 @@ async function probeConversationDb() {
|
|
|
12410
12529
|
});
|
|
12411
12530
|
}
|
|
12412
12531
|
}
|
|
12413
|
-
var
|
|
12414
|
-
|
|
12532
|
+
var app36 = new Hono();
|
|
12533
|
+
app36.get("/", async (c) => {
|
|
12415
12534
|
const version = readVersion();
|
|
12416
12535
|
const probe = await probeConversationDb();
|
|
12417
12536
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -12433,37 +12552,38 @@ app35.get("/", async (c) => {
|
|
|
12433
12552
|
uptimeMs
|
|
12434
12553
|
});
|
|
12435
12554
|
});
|
|
12436
|
-
var health_default2 =
|
|
12555
|
+
var health_default2 = app36;
|
|
12437
12556
|
|
|
12438
12557
|
// 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
|
-
|
|
12558
|
+
var app37 = new Hono();
|
|
12559
|
+
app37.route("/session", session_default2);
|
|
12560
|
+
app37.route("/chat", chat_default2);
|
|
12561
|
+
app37.route("/chat-failure", chat_failure_default);
|
|
12562
|
+
app37.route("/compact", compact_default);
|
|
12563
|
+
app37.route("/logs", logs_default);
|
|
12564
|
+
app37.route("/claude-info", claude_info_default);
|
|
12565
|
+
app37.route("/attachment", attachment_default);
|
|
12566
|
+
app37.route("/agents", agents_default);
|
|
12567
|
+
app37.route("/sessions", sessions_default);
|
|
12568
|
+
app37.route("/browser", browser_default);
|
|
12569
|
+
app37.route("/browser-iframe", browser_iframe_default);
|
|
12570
|
+
app37.route("/device-browser", device_browser_default);
|
|
12571
|
+
app37.route("/events", events_default);
|
|
12572
|
+
app37.route("/cloudflare", cloudflare_default);
|
|
12573
|
+
app37.route("/files", files_default);
|
|
12574
|
+
app37.route("/graph-search", graph_search_default);
|
|
12575
|
+
app37.route("/graph-subgraph", graph_subgraph_default);
|
|
12576
|
+
app37.route("/graph-delete", graph_delete_default);
|
|
12577
|
+
app37.route("/graph-restore", graph_restore_default);
|
|
12578
|
+
app37.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12579
|
+
app37.route("/graph-default-view", graph_default_view_default);
|
|
12580
|
+
app37.route("/file-attach", file_attach_default);
|
|
12581
|
+
app37.route("/adherence", adherence_default);
|
|
12582
|
+
app37.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12583
|
+
app37.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
12584
|
+
app37.route("/sidebar-artefact-content", sidebar_artefact_content_default);
|
|
12585
|
+
app37.route("/health-brand", health_default2);
|
|
12586
|
+
var admin_default = app37;
|
|
12467
12587
|
|
|
12468
12588
|
// server/routes/sites.ts
|
|
12469
12589
|
import { existsSync as existsSync22, readFileSync as readFileSync17, realpathSync as realpathSync4, statSync as statSync7 } from "fs";
|
|
@@ -12498,8 +12618,8 @@ function getExt(p) {
|
|
|
12498
12618
|
if (idx < p.lastIndexOf("/")) return "";
|
|
12499
12619
|
return p.slice(idx).toLowerCase();
|
|
12500
12620
|
}
|
|
12501
|
-
var
|
|
12502
|
-
|
|
12621
|
+
var app38 = new Hono();
|
|
12622
|
+
app38.get("/:rel{.*}", (c) => {
|
|
12503
12623
|
const reqPath = c.req.path;
|
|
12504
12624
|
const rawRel = c.req.param("rel") ?? "";
|
|
12505
12625
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -12602,7 +12722,7 @@ app37.get("/:rel{.*}", (c) => {
|
|
|
12602
12722
|
"X-Content-Type-Options": "nosniff"
|
|
12603
12723
|
});
|
|
12604
12724
|
});
|
|
12605
|
-
var sites_default =
|
|
12725
|
+
var sites_default = app38;
|
|
12606
12726
|
|
|
12607
12727
|
// app/lib/graph-health.ts
|
|
12608
12728
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -12756,9 +12876,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
|
|
|
12756
12876
|
function isPublicHost(host) {
|
|
12757
12877
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
12758
12878
|
}
|
|
12759
|
-
var
|
|
12760
|
-
|
|
12761
|
-
|
|
12879
|
+
var app39 = new Hono();
|
|
12880
|
+
app39.use("*", clientIpMiddleware);
|
|
12881
|
+
app39.use("*", async (c, next) => {
|
|
12762
12882
|
await next();
|
|
12763
12883
|
c.header("X-Content-Type-Options", "nosniff");
|
|
12764
12884
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -12768,7 +12888,7 @@ app38.use("*", async (c, next) => {
|
|
|
12768
12888
|
);
|
|
12769
12889
|
});
|
|
12770
12890
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
12771
|
-
|
|
12891
|
+
app39.use("*", async (c, next) => {
|
|
12772
12892
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
12773
12893
|
await next();
|
|
12774
12894
|
return;
|
|
@@ -12801,7 +12921,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
12801
12921
|
"/sites/"
|
|
12802
12922
|
];
|
|
12803
12923
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
12804
|
-
|
|
12924
|
+
app39.use("*", async (c, next) => {
|
|
12805
12925
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12806
12926
|
if (!isPublicHost(host)) {
|
|
12807
12927
|
await next();
|
|
@@ -12841,7 +12961,7 @@ function resolveRemoteAuthOpts() {
|
|
|
12841
12961
|
return brandLoginOpts;
|
|
12842
12962
|
}
|
|
12843
12963
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
12844
|
-
|
|
12964
|
+
app39.post("/__remote-auth/login", async (c) => {
|
|
12845
12965
|
const client = clientFrom(c);
|
|
12846
12966
|
const clientIp = client.ip || "unknown";
|
|
12847
12967
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -12886,7 +13006,7 @@ app38.post("/__remote-auth/login", async (c) => {
|
|
|
12886
13006
|
}
|
|
12887
13007
|
});
|
|
12888
13008
|
});
|
|
12889
|
-
|
|
13009
|
+
app39.get("/__remote-auth/logout", (c) => {
|
|
12890
13010
|
const client = clientFrom(c);
|
|
12891
13011
|
const clientIp = client.ip || "unknown";
|
|
12892
13012
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -12899,7 +13019,7 @@ app38.get("/__remote-auth/logout", (c) => {
|
|
|
12899
13019
|
}
|
|
12900
13020
|
});
|
|
12901
13021
|
});
|
|
12902
|
-
|
|
13022
|
+
app39.post("/__remote-auth/change-password", async (c) => {
|
|
12903
13023
|
const client = clientFrom(c);
|
|
12904
13024
|
const clientIp = client.ip || "unknown";
|
|
12905
13025
|
const rateLimited = checkRateLimit(client);
|
|
@@ -12950,13 +13070,13 @@ app38.post("/__remote-auth/change-password", async (c) => {
|
|
|
12950
13070
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
12951
13071
|
}
|
|
12952
13072
|
});
|
|
12953
|
-
|
|
13073
|
+
app39.get("/__remote-auth/setup", (c) => {
|
|
12954
13074
|
if (isRemoteAuthConfigured()) {
|
|
12955
13075
|
return c.redirect("/");
|
|
12956
13076
|
}
|
|
12957
13077
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
12958
13078
|
});
|
|
12959
|
-
|
|
13079
|
+
app39.post("/__remote-auth/set-initial-password", async (c) => {
|
|
12960
13080
|
if (isRemoteAuthConfigured()) {
|
|
12961
13081
|
return c.redirect("/");
|
|
12962
13082
|
}
|
|
@@ -12994,10 +13114,10 @@ app38.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
12994
13114
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
12995
13115
|
}
|
|
12996
13116
|
});
|
|
12997
|
-
|
|
13117
|
+
app39.get("/api/remote-auth/status", (c) => {
|
|
12998
13118
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
12999
13119
|
});
|
|
13000
|
-
|
|
13120
|
+
app39.post("/api/remote-auth/set-password", async (c) => {
|
|
13001
13121
|
let body;
|
|
13002
13122
|
try {
|
|
13003
13123
|
body = await c.req.json();
|
|
@@ -13027,9 +13147,9 @@ app38.post("/api/remote-auth/set-password", async (c) => {
|
|
|
13027
13147
|
return c.json({ error: "Failed to save password" }, 500);
|
|
13028
13148
|
}
|
|
13029
13149
|
});
|
|
13030
|
-
|
|
13150
|
+
app39.route("/api/_client-error", client_error_default);
|
|
13031
13151
|
console.log("[client-error-route] mounted");
|
|
13032
|
-
|
|
13152
|
+
app39.use("*", async (c, next) => {
|
|
13033
13153
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13034
13154
|
const path2 = c.req.path;
|
|
13035
13155
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -13069,15 +13189,15 @@ app38.use("*", async (c, next) => {
|
|
|
13069
13189
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
13070
13190
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
13071
13191
|
});
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13192
|
+
app39.route("/api/health", health_default);
|
|
13193
|
+
app39.route("/api/session", session_default);
|
|
13194
|
+
app39.route("/api/chat", chat_default);
|
|
13195
|
+
app39.route("/api/group", group_default);
|
|
13196
|
+
app39.route("/api/access", access_default);
|
|
13197
|
+
app39.route("/api/telegram", telegram_default);
|
|
13198
|
+
app39.route("/api/whatsapp", whatsapp_default);
|
|
13199
|
+
app39.route("/api/onboarding", onboarding_default);
|
|
13200
|
+
app39.route("/api/admin", admin_default);
|
|
13081
13201
|
var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
|
|
13082
13202
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13083
13203
|
var IMAGE_MIME = {
|
|
@@ -13089,7 +13209,7 @@ var IMAGE_MIME = {
|
|
|
13089
13209
|
".svg": "image/svg+xml",
|
|
13090
13210
|
".ico": "image/x-icon"
|
|
13091
13211
|
};
|
|
13092
|
-
|
|
13212
|
+
app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
13093
13213
|
const slug = c.req.param("slug");
|
|
13094
13214
|
const filename = c.req.param("filename");
|
|
13095
13215
|
if (!SAFE_SLUG_RE.test(slug)) {
|
|
@@ -13124,7 +13244,7 @@ app38.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
13124
13244
|
"Cache-Control": "public, max-age=3600"
|
|
13125
13245
|
});
|
|
13126
13246
|
});
|
|
13127
|
-
|
|
13247
|
+
app39.get("/generated/:filename", (c) => {
|
|
13128
13248
|
const filename = c.req.param("filename");
|
|
13129
13249
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
13130
13250
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -13154,7 +13274,7 @@ app38.get("/generated/:filename", (c) => {
|
|
|
13154
13274
|
"Cache-Control": "public, max-age=86400"
|
|
13155
13275
|
});
|
|
13156
13276
|
});
|
|
13157
|
-
|
|
13277
|
+
app39.route("/sites", sites_default);
|
|
13158
13278
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
13159
13279
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
13160
13280
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -13291,7 +13411,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
13291
13411
|
function escapeHtml(s) {
|
|
13292
13412
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
13293
13413
|
}
|
|
13294
|
-
|
|
13414
|
+
app39.get("/", (c) => {
|
|
13295
13415
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13296
13416
|
if (isPublicHost(host)) {
|
|
13297
13417
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -13299,12 +13419,12 @@ app38.get("/", (c) => {
|
|
|
13299
13419
|
}
|
|
13300
13420
|
return c.html(cachedHtml("index.html"));
|
|
13301
13421
|
});
|
|
13302
|
-
|
|
13422
|
+
app39.get("/public", (c) => {
|
|
13303
13423
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13304
13424
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13305
13425
|
return c.html(cachedHtml("public.html"));
|
|
13306
13426
|
});
|
|
13307
|
-
|
|
13427
|
+
app39.get("/chat", (c) => {
|
|
13308
13428
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13309
13429
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13310
13430
|
return c.html(cachedHtml("public.html"));
|
|
@@ -13323,9 +13443,9 @@ async function logViewerFetch(c, next) {
|
|
|
13323
13443
|
duration_ms: Date.now() - start
|
|
13324
13444
|
});
|
|
13325
13445
|
}
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13446
|
+
app39.use("/vnc-viewer.html", logViewerFetch);
|
|
13447
|
+
app39.use("/vnc-popout.html", logViewerFetch);
|
|
13448
|
+
app39.get("/vnc-popout.html", (c) => {
|
|
13329
13449
|
let html = htmlCache.get("vnc-popout.html");
|
|
13330
13450
|
if (!html) {
|
|
13331
13451
|
html = readFileSync18(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -13338,7 +13458,7 @@ app38.get("/vnc-popout.html", (c) => {
|
|
|
13338
13458
|
}
|
|
13339
13459
|
return c.html(html);
|
|
13340
13460
|
});
|
|
13341
|
-
|
|
13461
|
+
app39.post("/api/vnc/client-event", async (c) => {
|
|
13342
13462
|
let body;
|
|
13343
13463
|
try {
|
|
13344
13464
|
body = await c.req.json();
|
|
@@ -13359,20 +13479,20 @@ app38.post("/api/vnc/client-event", async (c) => {
|
|
|
13359
13479
|
});
|
|
13360
13480
|
return c.json({ ok: true });
|
|
13361
13481
|
});
|
|
13362
|
-
|
|
13482
|
+
app39.get("/g/:slug", (c) => {
|
|
13363
13483
|
return c.html(brandedPublicHtml());
|
|
13364
13484
|
});
|
|
13365
|
-
|
|
13485
|
+
app39.get("/graph", (c) => {
|
|
13366
13486
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13367
13487
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13368
13488
|
return c.html(cachedHtml("graph.html"));
|
|
13369
13489
|
});
|
|
13370
|
-
|
|
13490
|
+
app39.get("/data", (c) => {
|
|
13371
13491
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13372
13492
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
13373
13493
|
return c.html(cachedHtml("data.html"));
|
|
13374
13494
|
});
|
|
13375
|
-
|
|
13495
|
+
app39.get("/:slug", async (c, next) => {
|
|
13376
13496
|
const slug = c.req.param("slug");
|
|
13377
13497
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
13378
13498
|
const branding = loadBrandingCache(slug);
|
|
@@ -13382,15 +13502,15 @@ app38.get("/:slug", async (c, next) => {
|
|
|
13382
13502
|
await next();
|
|
13383
13503
|
});
|
|
13384
13504
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
13385
|
-
|
|
13505
|
+
app39.get("/favicon.ico", (c) => {
|
|
13386
13506
|
c.header("Cache-Control", "public, max-age=300");
|
|
13387
13507
|
return c.redirect(brandFaviconPath, 302);
|
|
13388
13508
|
});
|
|
13389
13509
|
}
|
|
13390
|
-
|
|
13510
|
+
app39.use("/*", serveStatic({ root: "./public" }));
|
|
13391
13511
|
var port = parseInt(process.env.MAXY_UI_INTERNAL_PORT ?? process.env.PORT ?? "19199", 10);
|
|
13392
13512
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
13393
|
-
var httpServer = serve({ fetch:
|
|
13513
|
+
var httpServer = serve({ fetch: app39.fetch, port, hostname });
|
|
13394
13514
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
13395
13515
|
console.log("[boot] auth-mode summary: oauth=8 api-key=1 (api-key consumer: invokePublicAgent only)");
|
|
13396
13516
|
var SUBAPP_MANIFEST = [
|
|
@@ -13411,7 +13531,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
13411
13531
|
}
|
|
13412
13532
|
try {
|
|
13413
13533
|
const registered = [];
|
|
13414
|
-
for (const r of
|
|
13534
|
+
for (const r of app39.routes ?? []) {
|
|
13415
13535
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
13416
13536
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
13417
13537
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -13443,6 +13563,13 @@ try {
|
|
|
13443
13563
|
console.error(`[session] backfill startup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13444
13564
|
}
|
|
13445
13565
|
})();
|
|
13566
|
+
(async () => {
|
|
13567
|
+
try {
|
|
13568
|
+
await backfillConversationChannelAddress();
|
|
13569
|
+
} catch (err) {
|
|
13570
|
+
console.error(`[session-985] channelAddress backfill startup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13571
|
+
}
|
|
13572
|
+
})();
|
|
13446
13573
|
(async () => {
|
|
13447
13574
|
try {
|
|
13448
13575
|
if (!existsSync23(USERS_FILE)) return;
|
|
@@ -13497,15 +13624,14 @@ autoDeliverPremiumPlugins(bootEntitlement?.purchasedPlugins ?? void 0);
|
|
|
13497
13624
|
(async () => {
|
|
13498
13625
|
if (!bootAccount) return;
|
|
13499
13626
|
try {
|
|
13500
|
-
const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-
|
|
13627
|
+
const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-HUTXJQXO.js");
|
|
13501
13628
|
const result = await recoverRunningCloudflareTasks(
|
|
13502
13629
|
bootAccount.accountId,
|
|
13503
13630
|
configDirForWhatsApp,
|
|
13504
|
-
//
|
|
13505
|
-
//
|
|
13506
|
-
//
|
|
13507
|
-
// and let the
|
|
13508
|
-
// existing edge.
|
|
13631
|
+
// Task 985 — no conversationId at boot. The reconciler operates on
|
|
13632
|
+
// Tasks whose Conversation is already linked via RAISED_DURING; the
|
|
13633
|
+
// tracker resolves the conversationId off that edge when present.
|
|
13634
|
+
// Pass null and let the recovery path pick it up.
|
|
13509
13635
|
null
|
|
13510
13636
|
);
|
|
13511
13637
|
if (result.scanned > 0) {
|
|
@@ -13587,10 +13713,10 @@ init({
|
|
|
13587
13713
|
agentName = resolved.slug;
|
|
13588
13714
|
}
|
|
13589
13715
|
let enrichedText = msg.text || msg.mediaPath || msg.mediaType || msg.replyContext ? buildEnrichedText2(msg.text ?? "") : "";
|
|
13590
|
-
if (msg.
|
|
13716
|
+
if (msg.cacheKey) {
|
|
13591
13717
|
const platformAccountId = bootAccount?.accountId ?? msg.accountId;
|
|
13592
|
-
registerSession(msg.
|
|
13593
|
-
console.error(`[session] channel session registered:
|
|
13718
|
+
registerSession(msg.cacheKey, msg.agentType, platformAccountId, agentName);
|
|
13719
|
+
console.error(`[session] channel session registered: cacheKey=${msg.cacheKey.slice(0, 12)}\u2026 channel=whatsapp accountId=${platformAccountId.slice(0, 8)}\u2026`);
|
|
13594
13720
|
}
|
|
13595
13721
|
let gatewayResult;
|
|
13596
13722
|
if (msg.text) {
|
|
@@ -13614,7 +13740,7 @@ init({
|
|
|
13614
13740
|
for await (const event of invokeAgent(
|
|
13615
13741
|
{ type: msg.agentType, agentName },
|
|
13616
13742
|
enrichedText,
|
|
13617
|
-
msg.
|
|
13743
|
+
msg.cacheKey,
|
|
13618
13744
|
[],
|
|
13619
13745
|
void 0,
|
|
13620
13746
|
gatewayResult
|
|
@@ -13632,7 +13758,7 @@ init({
|
|
|
13632
13758
|
for await (const event of invokeAgent(
|
|
13633
13759
|
{ type: msg.agentType, agentName },
|
|
13634
13760
|
enrichedText,
|
|
13635
|
-
msg.
|
|
13761
|
+
msg.cacheKey,
|
|
13636
13762
|
[],
|
|
13637
13763
|
void 0,
|
|
13638
13764
|
gatewayResult
|