@rubytech/create-maxy 1.0.876 → 1.0.878

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-trash/dist/index.js +1 -1
  3. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  4. package/payload/platform/lib/graph-trash/src/index.ts +1 -1
  5. package/payload/platform/neo4j/edge-annotations.json +11 -3
  6. package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-base64-guard.test.sh +204 -0
  7. package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +11 -5
  8. package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +96 -0
  9. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +5 -1
  10. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +88 -9
  11. package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +1 -1
  12. package/payload/platform/plugins/docs/references/admin-session.md +80 -0
  13. package/payload/platform/plugins/docs/references/platform.md +3 -1
  14. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -0
  15. package/payload/platform/plugins/memory/PLUGIN.md +4 -1
  16. package/payload/platform/plugins/memory/mcp/dist/index.js +127 -0
  17. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  18. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts +2 -0
  19. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts.map +1 -0
  20. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +97 -0
  21. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -0
  22. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.d.ts +2 -0
  23. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.d.ts.map +1 -0
  24. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js +184 -0
  25. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js.map +1 -0
  26. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +89 -0
  27. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -0
  28. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +542 -0
  29. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -0
  30. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.d.ts +41 -0
  31. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.d.ts.map +1 -0
  32. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.js +116 -0
  33. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.js.map +1 -0
  34. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +159 -0
  35. package/payload/platform/templates/agents/admin/IDENTITY.md +4 -0
  36. package/payload/platform/templates/specialists/agents/database-operator.md +3 -2
  37. package/payload/server/chunk-GOZP57CX.js +1373 -0
  38. package/payload/server/chunk-I4AQMEJA.js +11265 -0
  39. package/payload/server/chunk-INI2ED6U.js +2277 -0
  40. package/payload/server/chunk-JTZYXIUW.js +1373 -0
  41. package/payload/server/chunk-LQDUG4II.js +11336 -0
  42. package/payload/server/chunk-LU6TUP3E.js +2169 -0
  43. package/payload/server/chunk-RP25NRQY.js +660 -0
  44. package/payload/server/chunk-RRVBWC66.js +667 -0
  45. package/payload/server/client-pool-AIZ5QKFD.js +34 -0
  46. package/payload/server/client-pool-VYDOIFG7.js +34 -0
  47. package/payload/server/cloudflare-task-tracker-B6FXP3HI.js +20 -0
  48. package/payload/server/cloudflare-task-tracker-M7APAYEF.js +20 -0
  49. package/payload/server/maxy-edge.js +6 -5
  50. package/payload/server/public/assets/{Checkbox-BsqexMy3.js → Checkbox-CqsIsmEi.js} +1 -1
  51. package/payload/server/public/assets/admin-CZlNLb9T.js +352 -0
  52. package/payload/server/public/assets/data-CH-nQ7oX.js +1 -0
  53. package/payload/server/public/assets/graph-labels-D0qUVHtZ.js +1 -0
  54. package/payload/server/public/assets/graph-mpWDe4rf.js +1 -0
  55. package/payload/server/public/assets/{jsx-runtime-CGCRFPeX.css → jsx-runtime-Cy_HdZWV.css} +1 -1
  56. package/payload/server/public/assets/page-CnyySOZF.js +1 -0
  57. package/payload/server/public/assets/{page-qI0NJSs6.js → page-DcK36vDf.js} +2 -2
  58. package/payload/server/public/assets/public-SXA00FTv.js +5 -0
  59. package/payload/server/public/assets/{useVoiceRecorder-DVVSQc-9.js → useVoiceRecorder-DcByEBLy.js} +1 -1
  60. package/payload/server/public/data.html +5 -5
  61. package/payload/server/public/graph.html +6 -6
  62. package/payload/server/public/index.html +8 -8
  63. package/payload/server/public/public.html +5 -5
  64. package/payload/server/server.js +560 -448
  65. package/payload/server/public/assets/admin-pIeHRytz.js +0 -352
  66. package/payload/server/public/assets/data-rhAG7W2b.js +0 -1
  67. package/payload/server/public/assets/graph-DVAWZmkb.js +0 -1
  68. package/payload/server/public/assets/graph-labels-t_04n4zX.js +0 -1
  69. package/payload/server/public/assets/page-BM9O7QN8.js +0 -1
  70. package/payload/server/public/assets/public-oNo_2gt0.js +0 -5
  71. /package/payload/server/public/assets/{jsx-runtime-B8sGPXtT.js → jsx-runtime-BEjEWeaF.js} +0 -0
@@ -1,19 +1,11 @@
1
1
  import {
2
2
  ACCOUNTS_DIR,
3
3
  ATTACHMENTS_ROOT,
4
- CDP_PORT,
5
- COMMERCIAL_MODE,
6
4
  Hono,
7
- LOG_DIR,
8
- MAXY_DIR,
9
5
  MAX_FILES_PER_MESSAGE,
10
6
  MAX_FILE_SIZE_BYTES,
11
7
  PLATFORM_ROOT,
12
8
  SUPPORTED_MIME_TYPES,
13
- TELEGRAM_ADMIN_WEBHOOK_SECRET_FILE,
14
- TELEGRAM_WEBHOOK_SECRET_FILE,
15
- USERS_FILE,
16
- WEBSOCKIFY_PORT,
17
9
  assertSupportedMime,
18
10
  autoDeliverPremiumPlugins,
19
11
  browserViewerLog,
@@ -83,12 +75,22 @@ import {
83
75
  vncLog,
84
76
  waitForExit,
85
77
  writeChromiumWrapper
86
- } from "./chunk-5U36PKG4.js";
78
+ } from "./chunk-LQDUG4II.js";
87
79
  import {
80
+ CDP_PORT,
81
+ COMMERCIAL_MODE,
82
+ LOG_DIR,
83
+ MAXY_DIR,
84
+ TELEGRAM_ADMIN_WEBHOOK_SECRET_FILE,
85
+ TELEGRAM_WEBHOOK_SECRET_FILE,
86
+ USERS_FILE,
87
+ WEBSOCKIFY_PORT,
88
88
  agentLogStream,
89
89
  clearSessionHistory,
90
90
  completeGrantSetup,
91
+ consumeWantsPriorConversation,
91
92
  getAccountIdForSession,
93
+ getActiveClient,
92
94
  getAgentNameForSession,
93
95
  getConversationIdForSession,
94
96
  getGrantForSession,
@@ -100,6 +102,7 @@ import {
100
102
  getVisitorIdForSession,
101
103
  interruptClient,
102
104
  listAdminSessionsInProgress,
105
+ mintAdminSessionToken,
103
106
  preConversationLogStream,
104
107
  registerGrantSession,
105
108
  registerResumedSession,
@@ -107,10 +110,11 @@ import {
107
110
  setAgentSessionId,
108
111
  setConversationIdForSession,
109
112
  setGroupContextForSession,
113
+ setWantsPriorConversation,
110
114
  sigtermFlushStreamLogs,
111
115
  unregisterSession,
112
116
  validateSession
113
- } from "./chunk-NDEQBCVI.js";
117
+ } from "./chunk-JTZYXIUW.js";
114
118
  import {
115
119
  CLOUDFLARE_TASK_DIAGNOSTICS,
116
120
  appendCloudflareSteps,
@@ -118,10 +122,11 @@ import {
118
122
  openCloudflareTask,
119
123
  readTunnelState,
120
124
  resolveUnitGoneVerdict
121
- } from "./chunk-UXLZ5Z3Y.js";
125
+ } from "./chunk-RP25NRQY.js";
122
126
  import {
123
127
  GREETING_DIRECTIVE,
124
128
  HAIKU_MODEL,
129
+ backfillConversationChannelAddress,
125
130
  backfillNullUserIdConversations,
126
131
  bindVisitorToGroup,
127
132
  checkGroupMembership,
@@ -137,6 +142,7 @@ import {
137
142
  getAgentSessionIdForConversation,
138
143
  getGroupParticipants,
139
144
  getMessagesSince,
145
+ getMostRecentAdminConversationForUser,
140
146
  getRecentMessages,
141
147
  getSession,
142
148
  getUserTimezone,
@@ -149,8 +155,9 @@ import {
149
155
  runAdminUserSelfHeal,
150
156
  verifyAndGetConversationUpdatedAt,
151
157
  verifyConversationOwnership,
152
- writeAdminUserAndPerson
153
- } from "./chunk-FHNFKJZN.js";
158
+ writeAdminUserAndPerson,
159
+ writeTurnFailure
160
+ } from "./chunk-INI2ED6U.js";
154
161
  import {
155
162
  __commonJS,
156
163
  __toESM
@@ -175,7 +182,7 @@ var require_dist = __commonJS({
175
182
  Event: ["eventId"],
176
183
  KnowledgeDocument: ["attachmentId"],
177
184
  DigitalDocument: ["attachmentId"],
178
- Conversation: ["conversationId", "sessionKey"],
185
+ Conversation: ["conversationId"],
179
186
  Message: ["messageId"],
180
187
  OnboardingState: ["accountId"],
181
188
  Workflow: ["workflowId"],
@@ -2082,22 +2089,22 @@ async function persistWhatsAppMessage(input) {
2082
2089
  const messageId = `whatsapp-live:${input.accountId}:${input.remoteJid}:${input.msgKeyId}`;
2083
2090
  const senderTelephone = input.fromMe && input.selfPhone ? input.selfPhone : input.senderPhone;
2084
2091
  const dateSentIso = new Date(input.timestamp * 1e3).toISOString();
2085
- const scope = deriveScope(input.sessionKey);
2092
+ const scope = deriveScope(input.cacheKey);
2086
2093
  const { givenName, familyName } = splitName(input.pushName);
2087
- const prev = sessionWriteLocks.get(input.sessionKey);
2094
+ const prev = sessionWriteLocks.get(input.cacheKey);
2088
2095
  let release;
2089
2096
  const mine = new Promise((resolve22) => {
2090
2097
  release = resolve22;
2091
2098
  });
2092
2099
  const chained = (prev ?? Promise.resolve()).then(() => mine);
2093
- sessionWriteLocks.set(input.sessionKey, chained);
2100
+ sessionWriteLocks.set(input.cacheKey, chained);
2094
2101
  await prev;
2095
2102
  const t0 = Date.now();
2096
2103
  let session = null;
2097
2104
  try {
2098
2105
  session = getSession();
2099
2106
  const cypher = `
2100
- MATCH (c:Conversation {sessionKey: $sessionKey})
2107
+ MATCH (c:Conversation {conversationId: $conversationId})
2101
2108
  OPTIONAL MATCH (existingS:Person {telephone: $senderTelephone})
2102
2109
  OPTIONAL MATCH (existingM:Message {messageId: $messageId})
2103
2110
  WITH c,
@@ -2161,7 +2168,7 @@ async function persistWhatsAppMessage(input) {
2161
2168
  senderReused AS senderReused
2162
2169
  `;
2163
2170
  const params = {
2164
- sessionKey: input.sessionKey,
2171
+ conversationId: input.conversationId,
2165
2172
  messageId,
2166
2173
  platformAccountId: input.platformAccountId,
2167
2174
  senderTelephone,
@@ -2180,7 +2187,7 @@ async function persistWhatsAppMessage(input) {
2180
2187
  const result = await session.run(cypher, params);
2181
2188
  const ms = Date.now() - t0;
2182
2189
  if (result.records.length === 0) {
2183
- console.error(`${TAG7} skip reason=conversation-not-found accountId=${input.platformAccountId} sessionKey=${input.sessionKey} messageId=${messageId}`);
2190
+ console.error(`${TAG7} skip reason=conversation-not-found accountId=${input.platformAccountId} cacheKey=${input.cacheKey} messageId=${messageId}`);
2184
2191
  return null;
2185
2192
  }
2186
2193
  const rec = result.records[0];
@@ -2201,7 +2208,7 @@ async function persistWhatsAppMessage(input) {
2201
2208
  console.error(`${TAG7} next-skip reason=no-prior msgId=${messageId}`);
2202
2209
  }
2203
2210
  console.error(
2204
- `${TAG7} write messageId=${messageId} accountId=${input.platformAccountId} sessionKey=${input.sessionKey} fromMe=${input.fromMe} dateSent=${dateSentIso} bodyBytes=${Buffer.byteLength(input.body, "utf8")} ms=${ms}`
2211
+ `${TAG7} write messageId=${messageId} accountId=${input.platformAccountId} cacheKey=${input.cacheKey} fromMe=${input.fromMe} dateSent=${dateSentIso} bodyBytes=${Buffer.byteLength(input.body, "utf8")} ms=${ms}`
2205
2212
  );
2206
2213
  return { messageId, created: true, senderElementId };
2207
2214
  } catch (err) {
@@ -2213,14 +2220,14 @@ async function persistWhatsAppMessage(input) {
2213
2220
  return null;
2214
2221
  } finally {
2215
2222
  release();
2216
- if (sessionWriteLocks.get(input.sessionKey) === chained) {
2217
- sessionWriteLocks.delete(input.sessionKey);
2223
+ if (sessionWriteLocks.get(input.cacheKey) === chained) {
2224
+ sessionWriteLocks.delete(input.cacheKey);
2218
2225
  }
2219
2226
  if (session) await session.close();
2220
2227
  }
2221
2228
  }
2222
- function deriveScope(sessionKey) {
2223
- const segments = sessionKey.split(":");
2229
+ function deriveScope(cacheKey) {
2230
+ const segments = cacheKey.split(":");
2224
2231
  return segments.length <= 2 ? "admin" : "public";
2225
2232
  }
2226
2233
  function splitName(pushName) {
@@ -2248,24 +2255,24 @@ async function ensureWhatsAppConversation(input) {
2248
2255
  const result = await ensureConversation(
2249
2256
  input.platformAccountId,
2250
2257
  input.agentType,
2251
- input.sessionKey
2258
+ input.cacheKey
2252
2259
  );
2253
2260
  const ms = Date.now() - t0;
2254
2261
  if (!result.conversationId) {
2255
2262
  console.error(
2256
- `${TAG8} conversation-merged FAIL sessionKey=${input.sessionKey} reason=null-conversationId ms=${ms}`
2263
+ `${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-conversationId ms=${ms}`
2257
2264
  );
2258
2265
  return null;
2259
2266
  }
2260
2267
  console.error(
2261
- `${TAG8} conversation-merged sessionKey=${input.sessionKey} agentType=${input.agentType} channel=whatsapp created=${result.created} ms=${ms}`
2268
+ `${TAG8} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp created=${result.created} ms=${ms}`
2262
2269
  );
2263
2270
  return { conversationId: result.conversationId, created: result.created };
2264
2271
  } catch (err) {
2265
2272
  const ms = Date.now() - t0;
2266
2273
  const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
2267
2274
  console.error(
2268
- `${TAG8} conversation-merged FAIL sessionKey=${input.sessionKey} reason=${reason} ms=${ms}`
2275
+ `${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
2269
2276
  );
2270
2277
  return null;
2271
2278
  }
@@ -2776,14 +2783,14 @@ function storeMessage(storeKey, entry) {
2776
2783
  console.error(`${TAG13} message store trimmed for ${storeKey}: ${trimmed} oldest messages removed`);
2777
2784
  }
2778
2785
  }
2779
- function deriveSessionKey(input) {
2786
+ function deriveCacheKey(input) {
2780
2787
  if (input.isOwnerMirror || input.agentType === "admin") {
2781
2788
  return `whatsapp:${input.accountId}`;
2782
2789
  }
2783
2790
  if (input.isGroup) {
2784
2791
  if (!input.groupJid) {
2785
2792
  throw new Error(
2786
- `deriveSessionKey: isGroup=true requires groupJid (accountId=${input.accountId}, senderPhone=${input.senderPhone})`
2793
+ `deriveCacheKey: isGroup=true requires groupJid (accountId=${input.accountId}, senderPhone=${input.senderPhone})`
2787
2794
  );
2788
2795
  }
2789
2796
  return `whatsapp:${input.accountId}:group:${input.groupJid}`;
@@ -3262,14 +3269,14 @@ function monitorInbound(conn) {
3262
3269
  jid: remoteJid
3263
3270
  });
3264
3271
  const fromMe = Boolean(msg.key.fromMe);
3265
- const sessionKeyAgentType = isGroup ? "public" : fromMe ? "admin" : checkDmAccess({
3272
+ const cacheKeyAgentType = isGroup ? "public" : fromMe ? "admin" : checkDmAccess({
3266
3273
  senderPhone,
3267
3274
  selfPhone: conn.selfPhone ?? "",
3268
3275
  config: whatsAppConfig,
3269
3276
  accountConfig: whatsAppConfig.accounts?.[conn.accountId]
3270
3277
  }).agentType;
3271
- const sessionKey = deriveSessionKey({
3272
- agentType: sessionKeyAgentType,
3278
+ const cacheKey = deriveCacheKey({
3279
+ agentType: cacheKeyAgentType,
3273
3280
  accountId: conn.accountId,
3274
3281
  senderPhone,
3275
3282
  isGroup,
@@ -3280,8 +3287,8 @@ function monitorInbound(conn) {
3280
3287
  const merged = await ensureWhatsAppConversation({
3281
3288
  accountId: conn.accountId,
3282
3289
  platformAccountId: conn.platformAccountId,
3283
- sessionKey,
3284
- agentType: sessionKeyAgentType,
3290
+ cacheKey,
3291
+ agentType: cacheKeyAgentType,
3285
3292
  groupJid: isGroup ? remoteJid : void 0
3286
3293
  });
3287
3294
  if (merged) {
@@ -3289,7 +3296,8 @@ function monitorInbound(conn) {
3289
3296
  accountId: conn.accountId,
3290
3297
  platformAccountId: conn.platformAccountId,
3291
3298
  remoteJid,
3292
- sessionKey,
3299
+ cacheKey,
3300
+ conversationId: merged.conversationId,
3293
3301
  msgKeyId: msg.key.id,
3294
3302
  fromMe,
3295
3303
  senderPhone,
@@ -3371,7 +3379,7 @@ async function handleInboundMessage(conn, msg) {
3371
3379
  isGroup: isGroup2,
3372
3380
  groupJid: isGroup2 ? remoteJid : void 0,
3373
3381
  reply: reply2,
3374
- sessionKey: deriveSessionKey({
3382
+ cacheKey: deriveCacheKey({
3375
3383
  agentType: "admin",
3376
3384
  accountId: conn.accountId,
3377
3385
  senderPhone: senderPhone2,
@@ -3465,7 +3473,7 @@ async function handleInboundMessage(conn, msg) {
3465
3473
  if (!currentSock) throw new Error("WhatsApp disconnected \u2014 cannot reply");
3466
3474
  await sendTextMessage(currentSock, remoteJid, text, { accountId: conn.accountId });
3467
3475
  };
3468
- const sessionKey = deriveSessionKey({
3476
+ const cacheKey = deriveCacheKey({
3469
3477
  agentType: accessResult.agentType,
3470
3478
  accountId: conn.accountId,
3471
3479
  senderPhone,
@@ -3482,7 +3490,7 @@ async function handleInboundMessage(conn, msg) {
3482
3490
  groupJid: isGroup ? remoteJid : void 0,
3483
3491
  groupSubject,
3484
3492
  reply,
3485
- sessionKey,
3493
+ cacheKey,
3486
3494
  mediaPath: mediaResult?.path,
3487
3495
  mediaMimetype: mediaResult?.mimetype,
3488
3496
  mediaType: extracted.mediaType,
@@ -3827,9 +3835,9 @@ app2.post("/", async (c) => {
3827
3835
  ...m.role === "user" ? { senderName: m.senderName } : {}
3828
3836
  });
3829
3837
  }
3830
- const sessionKey2 = crypto.randomUUID();
3831
- registerResumedSession(sessionKey2, accountId, agentSlug, groupInfo.conversationId, agentMessages);
3832
- setGroupContextForSession(sessionKey2, {
3838
+ const cacheKey2 = crypto.randomUUID();
3839
+ registerResumedSession(cacheKey2, accountId, agentSlug, groupInfo.conversationId, agentMessages);
3840
+ setGroupContextForSession(cacheKey2, {
3833
3841
  groupSlug,
3834
3842
  groupName: groupInfo.groupName,
3835
3843
  conversationId: groupInfo.conversationId,
@@ -3841,7 +3849,7 @@ app2.post("/", async (c) => {
3841
3849
  console.log(`[session] cold-resume group=${groupSlug} visitor=${visitorId.slice(0, 8)}\u2026 messages=${uiMessages.length}`);
3842
3850
  return withVisitorCookie(
3843
3851
  Response.json({
3844
- session_key: sessionKey2,
3852
+ session_key: cacheKey2,
3845
3853
  agent_id: agentSlug,
3846
3854
  resumed,
3847
3855
  ...resumed ? { messages: uiMessages } : {},
@@ -3884,13 +3892,13 @@ app2.post("/", async (c) => {
3884
3892
  content: m.content,
3885
3893
  timestamp: new Date(m.createdAt).getTime() || Date.now()
3886
3894
  }));
3887
- const sessionKey2 = crypto.randomUUID();
3888
- registerResumedSession(sessionKey2, accountId, agentSlug, recent.conversationId, agentMessages);
3895
+ const cacheKey2 = crypto.randomUUID();
3896
+ registerResumedSession(cacheKey2, accountId, agentSlug, recent.conversationId, agentMessages);
3889
3897
  const resumed = uiMessages.length > 0;
3890
3898
  console.log(`[session] cold-resume visitor=${visitorId.slice(0, 8)}\u2026 conversation=${recent.conversationId.slice(0, 8)}\u2026 messages=${uiMessages.length}`);
3891
3899
  return withVisitorCookie(
3892
3900
  Response.json({
3893
- session_key: sessionKey2,
3901
+ session_key: cacheKey2,
3894
3902
  agent_id: agentSlug,
3895
3903
  resumed,
3896
3904
  ...resumed ? { messages: uiMessages } : {},
@@ -3902,13 +3910,13 @@ app2.post("/", async (c) => {
3902
3910
  }
3903
3911
  }
3904
3912
  const newVisitorId = visitorId ?? crypto.randomUUID();
3905
- const sessionKey = crypto.randomUUID();
3906
- registerSession(sessionKey, "public", accountId, agentSlug);
3913
+ const cacheKey = crypto.randomUUID();
3914
+ registerSession(cacheKey, "public", accountId, agentSlug);
3907
3915
  const hasImage = agentConfig?.image ? "yes" : "no";
3908
- console.log(`[session] new-session visitor=${newVisitorId.slice(0, 8)}\u2026 session=${sessionKey.slice(0, 8)}\u2026 agent=${agentSlug} image=${hasImage} showAgentName=${agentConfig?.showAgentName ?? false}`);
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}`);
3909
3917
  return withVisitorCookie(
3910
3918
  Response.json({
3911
- session_key: sessionKey,
3919
+ session_key: cacheKey,
3912
3920
  agent_id: agentSlug,
3913
3921
  ...branding ? { branding } : {},
3914
3922
  ...agentIdentity
@@ -4501,9 +4509,9 @@ var chat_default = app3;
4501
4509
  // server/routes/group.ts
4502
4510
  var app4 = new Hono();
4503
4511
  app4.get("/messages", async (c) => {
4504
- const sessionKey = c.req.query("session_key");
4512
+ const cacheKey = c.req.query("session_key");
4505
4513
  const since = c.req.query("since");
4506
- if (!sessionKey) {
4514
+ if (!cacheKey) {
4507
4515
  return c.json({ error: "session_key required" }, 400);
4508
4516
  }
4509
4517
  if (!since) {
@@ -4513,18 +4521,18 @@ app4.get("/messages", async (c) => {
4513
4521
  if (isNaN(sinceDate.getTime())) {
4514
4522
  return c.json({ error: "Invalid since parameter \u2014 expected ISO 8601" }, 400);
4515
4523
  }
4516
- if (!validateSession(sessionKey, "public").ok) {
4524
+ if (!validateSession(cacheKey, "public").ok) {
4517
4525
  return c.json({ error: "Session expired" }, 401);
4518
4526
  }
4519
- const groupSlug = getGroupSlugForSession(sessionKey);
4527
+ const groupSlug = getGroupSlugForSession(cacheKey);
4520
4528
  if (!groupSlug) {
4521
4529
  return c.json({ error: "Not a group session" }, 400);
4522
4530
  }
4523
- const conversationId = getConversationIdForSession(sessionKey);
4531
+ const conversationId = getConversationIdForSession(cacheKey);
4524
4532
  if (!conversationId) {
4525
4533
  return c.json({ error: "No conversation bound" }, 400);
4526
4534
  }
4527
- const visitorId = getVisitorIdForSession(sessionKey);
4535
+ const visitorId = getVisitorIdForSession(cacheKey);
4528
4536
  const POLL_LIMIT = 100;
4529
4537
  try {
4530
4538
  const messages = await getMessagesSince(conversationId, since, POLL_LIMIT);
@@ -5021,8 +5029,8 @@ app5.post("/verify-token", async (c) => {
5021
5029
  }
5022
5030
  await consumeMagicToken(result.grantId);
5023
5031
  const accountId = result.accountId;
5024
- const sessionKey = crypto.randomUUID();
5025
- registerGrantSession(sessionKey, accountId, agentSlug, {
5032
+ const cacheKey = crypto.randomUUID();
5033
+ registerGrantSession(cacheKey, accountId, agentSlug, {
5026
5034
  grantId: result.grantId,
5027
5035
  grantExpiresAt: result.expiresAt ?? void 0,
5028
5036
  grantStatus: result.status,
@@ -5033,7 +5041,7 @@ app5.post("/verify-token", async (c) => {
5033
5041
  clearAccessRateLimit(clientIp, agentSlug);
5034
5042
  console.error(`[access-gate] verify-token ip=${clientIp} agent=${agentSlug} contact=${maskContact(result.contactValue)} result=success`);
5035
5043
  return c.json({
5036
- session_key: sessionKey,
5044
+ session_key: cacheKey,
5037
5045
  grant: {
5038
5046
  displayName: result.displayName,
5039
5047
  contactValue: result.contactValue,
@@ -5101,8 +5109,8 @@ app5.post("/verify-otp", async (c) => {
5101
5109
  }, remaining > 0 ? 401 : 429);
5102
5110
  }
5103
5111
  await consumeOtp(grant.grantId);
5104
- const sessionKey = crypto.randomUUID();
5105
- registerGrantSession(sessionKey, account.accountId, agentSlug, {
5112
+ const cacheKey = crypto.randomUUID();
5113
+ registerGrantSession(cacheKey, account.accountId, agentSlug, {
5106
5114
  grantId: grant.grantId,
5107
5115
  grantExpiresAt: grant.expiresAt ?? void 0,
5108
5116
  grantStatus: grant.status,
@@ -5113,7 +5121,7 @@ app5.post("/verify-otp", async (c) => {
5113
5121
  clearAccessRateLimit(clientIp, agentSlug);
5114
5122
  console.error(`[access-gate] verify-otp ip=${clientIp} agent=${agentSlug} phone=${maskContact(phone)} result=success`);
5115
5123
  return c.json({
5116
- session_key: sessionKey,
5124
+ session_key: cacheKey,
5117
5125
  grant: {
5118
5126
  displayName: grant.displayName,
5119
5127
  contactValue: grant.contactValue,
@@ -5211,8 +5219,8 @@ app5.post("/login", async (c) => {
5211
5219
  console.error(`[access-gate] login ip=${clientIp} agent=${agentSlug} contact=${maskContact(contact)} result=wrong_password`);
5212
5220
  return c.json({ error: "Invalid credentials" }, 401);
5213
5221
  }
5214
- const sessionKey = crypto.randomUUID();
5215
- registerGrantSession(sessionKey, account.accountId, agentSlug, {
5222
+ const cacheKey = crypto.randomUUID();
5223
+ registerGrantSession(cacheKey, account.accountId, agentSlug, {
5216
5224
  grantId: grant.grantId,
5217
5225
  grantExpiresAt: grant.expiresAt ?? void 0,
5218
5226
  grantStatus: grant.status,
@@ -5222,7 +5230,7 @@ app5.post("/login", async (c) => {
5222
5230
  });
5223
5231
  clearAccessRateLimit(clientIp, agentSlug);
5224
5232
  console.error(`[access-gate] login ip=${clientIp} agent=${agentSlug} contact=${maskContact(contact)} result=success`);
5225
- return c.json({ session_key: sessionKey, agent_id: agentSlug });
5233
+ return c.json({ session_key: cacheKey, agent_id: agentSlug });
5226
5234
  } catch (err) {
5227
5235
  console.error(`[access-gate] login ip=${clientIp} agent=${agentSlug} error=${err instanceof Error ? err.message : String(err)}`);
5228
5236
  return c.json({ error: "Internal server error" }, 500);
@@ -5381,11 +5389,11 @@ function verifyWebhookSecret(headerValue, storedSecret) {
5381
5389
  }
5382
5390
  async function handleInbound(params) {
5383
5391
  const { chatId, senderId, text, botType, botToken, accountId, agentType } = params;
5384
- const sessionKey = `telegram:${chatId}`;
5392
+ const cacheKey = `telegram:${chatId}`;
5385
5393
  const gatewayChannel = agentType === "admin" ? "telegram-admin" : "telegram-dm";
5386
- registerSession(sessionKey, agentType, accountId);
5394
+ registerSession(cacheKey, agentType, accountId);
5387
5395
  console.error(
5388
- `${TAG16} session registered: sessionKey=${sessionKey} agentType=${agentType} botType=${botType} senderId=${senderId} accountId=${accountId.slice(0, 8)}\u2026`
5396
+ `${TAG16} session registered: cacheKey=${cacheKey} agentType=${agentType} botType=${botType} senderId=${senderId} accountId=${accountId.slice(0, 8)}\u2026`
5389
5397
  );
5390
5398
  const gatewayResult = await processInbound(text, gatewayChannel);
5391
5399
  if (gatewayResult.screening.verdict === "discard") {
@@ -5399,7 +5407,7 @@ async function handleInbound(params) {
5399
5407
  for await (const event of invokeAgent(
5400
5408
  { type: agentType },
5401
5409
  gatewayResult.processedText,
5402
- sessionKey,
5410
+ cacheKey,
5403
5411
  [],
5404
5412
  void 0,
5405
5413
  gatewayResult
@@ -6215,19 +6223,25 @@ app7.get("/messages", (c) => {
6215
6223
  });
6216
6224
  app7.get("/conversation-graph-state", async (c) => {
6217
6225
  try {
6218
- const directSessionKey = c.req.query("sessionKey");
6226
+ const directCacheKey = c.req.query("cacheKey");
6219
6227
  const jid = c.req.query("jid");
6220
6228
  const accountIdQuery = c.req.query("accountId");
6221
- let sessionKey;
6222
- if (directSessionKey) {
6223
- sessionKey = directSessionKey;
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);
6224
6238
  } else {
6225
6239
  if (!jid) {
6226
- return c.json({ error: "Provide either sessionKey or jid (with optional accountId)." }, 400);
6240
+ return c.json({ error: "Provide either cacheKey or jid (with optional accountId)." }, 400);
6227
6241
  }
6228
- const accountId = validateAccountId(accountIdQuery ?? null);
6242
+ accountId = validateAccountId(accountIdQuery ?? null);
6229
6243
  if (isGroupJid(jid)) {
6230
- sessionKey = deriveSessionKey({
6244
+ cacheKey = deriveCacheKey({
6231
6245
  agentType: "public",
6232
6246
  accountId,
6233
6247
  senderPhone: "",
@@ -6237,9 +6251,9 @@ app7.get("/conversation-graph-state", async (c) => {
6237
6251
  } else {
6238
6252
  const e164 = jid.replace(/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i, "$1");
6239
6253
  if (!/^\d+$/.test(e164)) {
6240
- return c.json({ error: `Cannot derive sessionKey from jid=${jid} \u2014 not a recognised user JID. Pass sessionKey explicitly.` }, 400);
6254
+ return c.json({ error: `Cannot derive cacheKey from jid=${jid} \u2014 not a recognised user JID. Pass cacheKey explicitly.` }, 400);
6241
6255
  }
6242
- sessionKey = deriveSessionKey({
6256
+ cacheKey = deriveCacheKey({
6243
6257
  agentType: "public",
6244
6258
  accountId,
6245
6259
  senderPhone: e164,
@@ -6247,8 +6261,9 @@ app7.get("/conversation-graph-state", async (c) => {
6247
6261
  });
6248
6262
  }
6249
6263
  }
6264
+ const channelAddress = cacheKey.startsWith("whatsapp:") ? cacheKey.slice("whatsapp:".length) : cacheKey;
6250
6265
  const cypher = `
6251
- MATCH (c:Conversation {sessionKey: $sessionKey})
6266
+ MATCH (c:Conversation {accountId: $accountId, channel: 'whatsapp', channelAddress: $channelAddress})
6252
6267
  OPTIONAL MATCH (m:Message:WhatsAppMessage)-[:PART_OF]->(c)
6253
6268
  RETURN
6254
6269
  c.conversationId AS conversationId,
@@ -6265,7 +6280,7 @@ app7.get("/conversation-graph-state", async (c) => {
6265
6280
  const rows = [];
6266
6281
  try {
6267
6282
  session = getSession();
6268
- const result = await session.run(cypher, { sessionKey });
6283
+ const result = await session.run(cypher, { accountId, channelAddress });
6269
6284
  for (const rec of result.records) {
6270
6285
  if (conversationId === null) {
6271
6286
  conversationId = rec.get("conversationId") ?? null;
@@ -6283,13 +6298,13 @@ app7.get("/conversation-graph-state", async (c) => {
6283
6298
  }
6284
6299
  } catch (err) {
6285
6300
  const msg = err instanceof Error ? err.message : String(err);
6286
- console.error(`${TAG18} conversation-graph-state ERR sessionKey=${sessionKey} reason=${msg}`);
6287
- return c.json({ error: `Graph query failed: ${msg}`, sessionKey, cypher: cypher.trim() }, 500);
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);
6288
6303
  }
6289
6304
  const ms = Date.now() - t0;
6290
- console.error(`[mcp:whatsapp] tool=whatsapp-conversation-graph-state sessionKey=${sessionKey} graphRows=${rows.length} conversationId=${conversationId ?? "null"} ms=${ms}`);
6305
+ console.error(`[mcp:whatsapp] tool=whatsapp-conversation-graph-state cacheKey=${cacheKey} graphRows=${rows.length} conversationId=${conversationId ?? "null"} ms=${ms}`);
6291
6306
  return c.json({
6292
- sessionKey,
6307
+ cacheKey,
6293
6308
  conversationId,
6294
6309
  graphRows: rows,
6295
6310
  cypher: cypher.trim(),
@@ -7000,8 +7015,9 @@ async function resolveUserIdentity(accountId, userId) {
7000
7015
  async function createAdminSession(accountId, thinkingView, userId, userName, role, avatar) {
7001
7016
  const account = resolveAccount();
7002
7017
  const effectiveThinkingView = thinkingView ?? account?.config.thinkingView ?? "default";
7003
- const sessionKey = crypto.randomUUID();
7004
- registerSession(sessionKey, "admin", accountId, void 0, userId, userName, role);
7018
+ const cacheKey = userId ? mintAdminSessionToken({ accountId, userId }) : crypto.randomUUID();
7019
+ registerSession(cacheKey, "admin", accountId, void 0, userId, userName, role);
7020
+ if (userId) setWantsPriorConversation(cacheKey);
7005
7021
  let onboardingComplete = true;
7006
7022
  try {
7007
7023
  const step = await loadOnboardingStep(accountId);
@@ -7015,10 +7031,27 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
7015
7031
  businessName = branding?.name || void 0;
7016
7032
  } catch {
7017
7033
  }
7018
- console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} admin session created: userId=${userId ?? "\u2013"} userName=${userName ?? "\u2013"} accountId=${accountId} conversationId=deferred sessionKey=${sessionKey.slice(0, 8)}`);
7019
- console.log(`[admin-session] role=${role ?? "null"} sessionKey=${sessionKey.slice(0, 8)} phase=create`);
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"}`);
7020
7053
  return {
7021
- session_key: sessionKey,
7054
+ session_key: cacheKey,
7022
7055
  agent_id: "admin",
7023
7056
  userId,
7024
7057
  userName,
@@ -7027,16 +7060,16 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
7027
7060
  thinkingView: effectiveThinkingView,
7028
7061
  onboardingComplete,
7029
7062
  businessName,
7030
- conversationId: null
7063
+ conversationId: initialConversationId
7031
7064
  };
7032
7065
  }
7033
7066
  var app10 = new Hono();
7034
7067
  app10.get("/", async (c) => {
7035
- const sessionKey = c.req.query("session_key");
7036
- if (!sessionKey || !validateSession(sessionKey, "admin").ok) {
7068
+ const cacheKey = c.req.query("session_key");
7069
+ if (!cacheKey || !validateSession(cacheKey, "admin").ok) {
7037
7070
  return c.json({ error: "Invalid or expired admin session" }, 401);
7038
7071
  }
7039
- const accountId = getAccountIdForSession(sessionKey);
7072
+ const accountId = getAccountIdForSession(cacheKey);
7040
7073
  if (!accountId) {
7041
7074
  return c.json({ error: "Session has no account binding" }, 401);
7042
7075
  }
@@ -7055,21 +7088,21 @@ app10.get("/", async (c) => {
7055
7088
  businessName = branding?.name || void 0;
7056
7089
  } catch {
7057
7090
  }
7058
- const role = getRoleForSession(sessionKey);
7059
- console.log(`[admin-session] role=${role ?? "null"} sessionKey=${sessionKey.slice(0, 8)} phase=restore`);
7060
- const restoredUserId = getUserIdForSession(sessionKey);
7061
- let restoredUserName = getUserNameForSession(sessionKey);
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);
7062
7095
  let restoredAvatar = null;
7063
7096
  if (restoredUserId) {
7064
7097
  const resolved = await resolveUserIdentity(accountId, restoredUserId);
7065
7098
  restoredUserName = resolved.userName;
7066
7099
  restoredAvatar = resolved.avatar;
7067
7100
  if (resolved.userName !== void 0) {
7068
- registerSession(sessionKey, "admin", accountId, void 0, restoredUserId, resolved.userName, role ?? void 0);
7101
+ registerSession(cacheKey, "admin", accountId, void 0, restoredUserId, resolved.userName, role ?? void 0);
7069
7102
  }
7070
7103
  }
7071
7104
  return c.json({
7072
- session_key: sessionKey,
7105
+ session_key: cacheKey,
7073
7106
  agent_id: "admin",
7074
7107
  userId: restoredUserId,
7075
7108
  userName: restoredUserName,
@@ -7078,7 +7111,7 @@ app10.get("/", async (c) => {
7078
7111
  thinkingView,
7079
7112
  onboardingComplete,
7080
7113
  businessName,
7081
- conversationId: getConversationIdForSession(sessionKey) ?? null
7114
+ conversationId: getConversationIdForSession(cacheKey) ?? null
7082
7115
  });
7083
7116
  });
7084
7117
  app10.post("/", async (c) => {
@@ -7429,7 +7462,7 @@ ${inner.content}`;
7429
7462
  }
7430
7463
  function chatReject(status, error, sk) {
7431
7464
  const keyPrefix = sk ? sk.slice(0, 8) + "\u2026" : "none";
7432
- console.log(`[session] chat-reject status=${status} reason="${error}" sessionKey=${keyPrefix}`);
7465
+ console.log(`[session] chat-reject status=${status} reason="${error}" cacheKey=${keyPrefix}`);
7433
7466
  return new Response(JSON.stringify({ error }), {
7434
7467
  status,
7435
7468
  headers: { "Content-Type": "application/json" }
@@ -7437,9 +7470,9 @@ function chatReject(status, error, sk) {
7437
7470
  }
7438
7471
  var app11 = new Hono();
7439
7472
  app11.post("/cancel", requireAdminSession, async (c) => {
7440
- const session_key = c.var.sessionKey;
7473
+ const session_key = c.var.cacheKey;
7441
7474
  try {
7442
- const { interruptClient: interruptClient2 } = await import("./client-pool-XAEDMS5D.js");
7475
+ const { interruptClient: interruptClient2 } = await import("./client-pool-AIZ5QKFD.js");
7443
7476
  await interruptClient2(session_key);
7444
7477
  return c.json({ ok: true });
7445
7478
  } catch (err) {
@@ -7447,7 +7480,7 @@ app11.post("/cancel", requireAdminSession, async (c) => {
7447
7480
  }
7448
7481
  });
7449
7482
  app11.post("/", requireAdminSession, async (c) => {
7450
- const session_key = c.var.sessionKey;
7483
+ const session_key = c.var.cacheKey;
7451
7484
  const contentType = c.req.header("content-type") ?? "";
7452
7485
  let message;
7453
7486
  let userTimestamp;
@@ -7528,7 +7561,7 @@ app11.post("/", requireAdminSession, async (c) => {
7528
7561
  try {
7529
7562
  const authResult = await ensureAuth();
7530
7563
  if (authResult.status === "dead" || authResult.status === "missing") {
7531
- console.log(`[session] chat-reject status=401 reason="auth_expired" sessionKey=${session_key.slice(0, 8)}\u2026 auth_status=${authResult.status}`);
7564
+ console.log(`[session] chat-reject status=401 reason="auth_expired" cacheKey=${session_key.slice(0, 8)}\u2026 auth_status=${authResult.status}`);
7532
7565
  return new Response(
7533
7566
  JSON.stringify({ error: "auth_expired", auth_status: authResult.status }),
7534
7567
  { status: 401, headers: { "Content-Type": "application/json" } }
@@ -7596,29 +7629,53 @@ app11.post("/", requireAdminSession, async (c) => {
7596
7629
  if (!isSystemMessage) {
7597
7630
  gatewayResult = await processInbound(message, "web-admin");
7598
7631
  }
7632
+ let acquireReason = "cold";
7633
+ let resumedAgentSessionId = null;
7599
7634
  let conversationId = getConversationIdForSession(session_key);
7600
- if (!conversationId) {
7635
+ if (conversationId) {
7636
+ acquireReason = getActiveClient(session_key) ? "warm" : "cold";
7637
+ } else {
7601
7638
  const userId = getUserIdForSession(session_key);
7602
7639
  const userName = getUserNameForSession(session_key);
7603
7640
  const accountId = getAccountIdForSession(session_key);
7604
7641
  if (!userId || !accountId) {
7605
7642
  return chatReject(401, "Invalid or expired admin session", session_key);
7606
7643
  }
7607
- const minted = randomUUID6();
7608
- const created = await createNewAdminConversation(userId, accountId, session_key, userName, minted);
7609
- if (!created) {
7610
- return chatReject(500, "Failed to create conversation", session_key);
7644
+ const wantsPrior = consumeWantsPriorConversation(session_key);
7645
+ const prior = wantsPrior ? await getMostRecentAdminConversationForUser(accountId, userId) : null;
7646
+ if (prior) {
7647
+ conversationId = prior.conversationId;
7648
+ setConversationIdForSession(session_key, conversationId);
7649
+ setAgentSessionId(session_key, prior.agentSessionId);
7650
+ resumedAgentSessionId = prior.agentSessionId;
7651
+ acquireReason = "pin-rebind";
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`);
7653
+ } else {
7654
+ if (wantsPrior) {
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`);
7656
+ }
7657
+ const minted = randomUUID6();
7658
+ const created = await createNewAdminConversation(userId, accountId, session_key, userName, minted);
7659
+ if (!created) {
7660
+ return chatReject(500, "Failed to create conversation", session_key);
7661
+ }
7662
+ conversationId = created;
7663
+ setConversationIdForSession(session_key, conversationId);
7664
+ acquireReason = "cold";
7665
+ console.log(`[chat-route] new conversation conversationId=${conversationId} cacheKey=${session_key.slice(0, 12)}\u2026`);
7611
7666
  }
7612
- conversationId = created;
7613
- setConversationIdForSession(session_key, conversationId);
7614
- console.log(`[chat-route] new conversation conversationId=${conversationId} sessionKey=${session_key.slice(0, 12)}\u2026`);
7615
7667
  }
7616
7668
  const encoder = new TextEncoder();
7617
7669
  const sseLogStream = agentLogStream("sse-events", account.accountDir, conversationId);
7618
7670
  const sk = conversationId.slice(0, 8);
7619
7671
  const teeStreamLogPath = resolve8(account.accountDir, "logs", `claude-agent-stream-${conversationId}.log`);
7620
7672
  try {
7621
- appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=task965-mint-at-entry] sessionKey=${session_key.slice(0, 12)}\u2026 conversationId=${conversationId}
7673
+ appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=task965-mint-at-entry] cacheKey=${session_key.slice(0, 12)}\u2026 conversationId=${conversationId}
7674
+ `);
7675
+ } catch {
7676
+ }
7677
+ try {
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}
7622
7679
  `);
7623
7680
  } catch {
7624
7681
  }
@@ -7627,12 +7684,12 @@ app11.post("/", requireAdminSession, async (c) => {
7627
7684
  incoming.on("close", () => {
7628
7685
  const tsClose = (/* @__PURE__ */ new Date()).toISOString();
7629
7686
  try {
7630
- appendFileSync3(teeStreamLogPath, `[${tsClose}] [incoming-close] sessionKey=${session_key.slice(0, 12)}\u2026 complete=${incoming.complete}
7687
+ appendFileSync3(teeStreamLogPath, `[${tsClose}] [incoming-close] cacheKey=${session_key.slice(0, 12)}\u2026 complete=${incoming.complete}
7631
7688
  `);
7632
7689
  } catch {
7633
7690
  }
7634
7691
  if (incoming.complete === false) {
7635
- console.error(`[${tsClose}] [incoming-close] DISCONNECT sessionKey=${session_key.slice(0, 12)}\u2026`);
7692
+ console.error(`[${tsClose}] [incoming-close] DISCONNECT cacheKey=${session_key.slice(0, 12)}\u2026`);
7636
7693
  interruptClient(session_key).catch((err) => {
7637
7694
  try {
7638
7695
  appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [incoming-close] interrupt-failed: ${err instanceof Error ? err.message : String(err)}
@@ -7688,7 +7745,7 @@ app11.post("/", requireAdminSession, async (c) => {
7688
7745
  const reasonStr = typeof reason === "string" ? reason : reason instanceof Error ? reason.message : "consumer-cancelled";
7689
7746
  sseLog.write(`[${ts}] [${sk}] admin: CANCEL [stream-cancel] reason=${reasonStr}
7690
7747
  `);
7691
- console.error(`[${(/* @__PURE__ */ new Date()).toISOString()}] [stream-cancel-callback] sessionKey=${session_key.slice(0, 12)}\u2026 reason=${JSON.stringify(reasonStr)}`);
7748
+ console.error(`[${(/* @__PURE__ */ new Date()).toISOString()}] [stream-cancel-callback] cacheKey=${session_key.slice(0, 12)}\u2026 reason=${JSON.stringify(reasonStr)}`);
7692
7749
  interruptClient(session_key).catch((err) => {
7693
7750
  sseLog.write(`[${ts}] [${sk}] admin: ABORT [interrupt-failed] ${err instanceof Error ? err.message : String(err)}
7694
7751
  `);
@@ -7696,7 +7753,7 @@ app11.post("/", requireAdminSession, async (c) => {
7696
7753
  },
7697
7754
  async start(controller) {
7698
7755
  let controllerOpen = true;
7699
- const sseEntry = { controller, conversationId, sessionKey: session_key };
7756
+ const sseEntry = { controller, conversationId, cacheKey: session_key };
7700
7757
  try {
7701
7758
  const reqSignal = c.req.raw?.signal;
7702
7759
  if (reqSignal) {
@@ -7810,14 +7867,89 @@ app11.post("/", requireAdminSession, async (c) => {
7810
7867
  });
7811
7868
  var chat_default2 = app11;
7812
7869
 
7813
- // server/routes/admin/compact.ts
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
+ }
7814
7897
  var app12 = new Hono();
7815
7898
  app12.post("/", requireAdminSession, async (c) => {
7816
- const sessionKey = c.var.sessionKey;
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;
7817
7949
  const encoder = new TextEncoder();
7818
7950
  const stream = new ReadableStream({
7819
7951
  async start(controller) {
7820
- const iter = compactSession(sessionKey);
7952
+ const iter = compactSession(cacheKey);
7821
7953
  let step = await iter.next();
7822
7954
  while (!step.done) {
7823
7955
  controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: "status", message: step.value })}
@@ -7839,18 +7971,18 @@ app12.post("/", requireAdminSession, async (c) => {
7839
7971
  }
7840
7972
  });
7841
7973
  });
7842
- var compact_default = app12;
7974
+ var compact_default = app13;
7843
7975
 
7844
7976
  // server/routes/admin/logs.ts
7845
7977
  import { existsSync as existsSync12, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync6 } from "fs";
7846
7978
  import { resolve as resolve9, basename as basename2 } from "path";
7847
7979
  var TAIL_BYTES = 8192;
7848
- var app13 = new Hono();
7849
- app13.get("/", async (c) => {
7980
+ var app14 = new Hono();
7981
+ app14.get("/", async (c) => {
7850
7982
  const fileParam = c.req.query("file");
7851
7983
  const typeParam = c.req.query("type");
7852
7984
  const conversationIdParam = c.req.query("conversationId");
7853
- const sessionKeyParam = c.req.query("sessionKey");
7985
+ const cacheKeyParam = c.req.query("cacheKey");
7854
7986
  const download = c.req.query("download") === "1";
7855
7987
  const account = resolveAccount();
7856
7988
  const accountLogDir = account ? resolve9(account.accountDir, "logs") : null;
@@ -7897,56 +8029,29 @@ app13.get("/", async (c) => {
7897
8029
  400
7898
8030
  );
7899
8031
  }
7900
- if (!conversationIdParam && !sessionKeyParam) {
8032
+ if (!conversationIdParam && !cacheKeyParam) {
7901
8033
  console.warn(`[admin/logs] rejected type=${typeParam} reason=no-id`);
7902
8034
  return c.json(
7903
- { error: `type=${typeParam} requires conversationId or sessionKey`, code: "ID_REQUIRED" },
8035
+ { error: `type=${typeParam} requires conversationId or cacheKey`, code: "ID_REQUIRED" },
7904
8036
  400
7905
8037
  );
7906
8038
  }
7907
- let sessionKey = sessionKeyParam ?? null;
7908
- let conversationId = conversationIdParam ?? null;
7909
- if (!sessionKey && conversationId || sessionKey && !conversationId) {
7910
- const neoSession = getSession();
7911
- try {
7912
- if (!sessionKey && conversationId) {
7913
- const result = await neoSession.run(
7914
- `MATCH (c:Conversation {conversationId: $conversationId})
7915
- RETURN c.sessionKey AS sessionKey LIMIT 1`,
7916
- { conversationId }
7917
- );
7918
- const sk = result.records[0]?.get("sessionKey");
7919
- if (typeof sk === "string" && sk.length > 0) sessionKey = sk;
7920
- } else if (sessionKey && !conversationId) {
7921
- const result = await neoSession.run(
7922
- `MATCH (c:Conversation {sessionKey: $sessionKey})
7923
- RETURN c.conversationId AS conversationId LIMIT 1`,
7924
- { sessionKey }
7925
- );
7926
- const cid = result.records[0]?.get("conversationId");
7927
- if (typeof cid === "string" && cid.length > 0) conversationId = cid;
7928
- }
7929
- } catch (err) {
7930
- const reason2 = err instanceof Error ? err.message : String(err);
7931
- console.warn(`[admin/logs] id-lookup-neo4j-error sessionKey=${sessionKey ?? "none"} conversationId=${conversationId ?? "none"} reason=${reason2}`);
7932
- } finally {
7933
- await neoSession.close();
7934
- }
7935
- }
8039
+ const cacheKey = cacheKeyParam ?? null;
8040
+ const conversationId = conversationIdParam ?? null;
7936
8041
  const MISSING_SENTINEL = ".task702-identifier-not-supplied.log";
7937
8042
  const fullFilename = conversationId ? `${prefix}-${conversationId}.log` : MISSING_SENTINEL;
7938
- const preflushFilename = sessionKey && typeParam === "public" ? `${prefix}-${preflushSliceOf(sessionKey)}.log` : MISSING_SENTINEL;
8043
+ const preflushFilename = cacheKey && typeParam === "public" ? `${prefix}-${preflushSliceOf(cacheKey)}.log` : MISSING_SENTINEL;
7939
8044
  const { hits, stalePreflushPaths, tried } = resolveConversationLogPaths(
7940
8045
  fullFilename,
7941
8046
  preflushFilename,
7942
8047
  logDirs
7943
8048
  );
7944
8049
  const stalePreflushCount = stalePreflushPaths.length;
7945
- const sessionKeySlice = sessionKey ? sessionKey.slice(0, 12) : "none";
8050
+ const cacheKeySlice = cacheKey ? cacheKey.slice(0, 12) : "none";
7946
8051
  const conversationIdSlice = conversationId ? conversationId.slice(0, 12) : "none";
7947
8052
  if (hits.length > 0) {
7948
8053
  const hit = hits[0];
7949
- console.info(`[admin/logs] resolved sessionKey=${sessionKeySlice} conversationId=${conversationIdSlice} shape=${hit.shape} stalePreflushCount=${stalePreflushCount}`);
8054
+ console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} conversationId=${conversationIdSlice} shape=${hit.shape} stalePreflushCount=${stalePreflushCount}`);
7950
8055
  try {
7951
8056
  const filename = basename2(hit.path);
7952
8057
  if (stalePreflushCount > 0 && !download) {
@@ -7976,14 +8081,14 @@ app13.get("/", async (c) => {
7976
8081
  );
7977
8082
  }
7978
8083
  }
7979
- const reason = !conversationId ? "no preflush log on disk for sessionKey and conversationId not derivable" : !sessionKey ? "no full log on disk and sessionKey not derivable" : "no preflush log, no full log";
7980
- console.warn(`[admin/logs] not-found tried=[${tried.join(",")}] sessionKey=${sessionKeySlice} conversationId=${conversationIdSlice} reason=${JSON.stringify(reason)}`);
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)}`);
7981
8086
  return c.json(
7982
8087
  {
7983
8088
  error: reason,
7984
8089
  code: "NOT_FOUND",
7985
8090
  reason,
7986
- sessionKey: sessionKey ?? null,
8091
+ cacheKey: cacheKey ?? null,
7987
8092
  conversationId: conversationId ?? null
7988
8093
  },
7989
8094
  404
@@ -8016,12 +8121,12 @@ app13.get("/", async (c) => {
8016
8121
  }
8017
8122
  return c.json({ logs });
8018
8123
  });
8019
- var logs_default = app13;
8124
+ var logs_default = app14;
8020
8125
 
8021
8126
  // server/routes/admin/claude-info.ts
8022
8127
  import { execFileSync as execFileSync2 } from "child_process";
8023
- var app14 = new Hono();
8024
- app14.get("/", (c) => {
8128
+ var app15 = new Hono();
8129
+ app15.get("/", (c) => {
8025
8130
  let version = "unknown";
8026
8131
  try {
8027
8132
  const raw = execFileSync2("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
@@ -8039,17 +8144,17 @@ app14.get("/", (c) => {
8039
8144
  const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
8040
8145
  return c.json({ version, account, model, thinkingView });
8041
8146
  });
8042
- var claude_info_default = app14;
8147
+ var claude_info_default = app15;
8043
8148
 
8044
8149
  // server/routes/admin/attachment.ts
8045
8150
  import { readFile as readFile2, readdir } from "fs/promises";
8046
8151
  import { existsSync as existsSync13 } from "fs";
8047
8152
  import { resolve as resolve10 } from "path";
8048
- var app15 = new Hono();
8049
- app15.get("/:attachmentId", requireAdminSession, async (c) => {
8153
+ var app16 = new Hono();
8154
+ app16.get("/:attachmentId", requireAdminSession, async (c) => {
8050
8155
  const attachmentId = c.req.param("attachmentId");
8051
- const sessionKey = c.var.sessionKey;
8052
- const accountId = getAccountIdForSession(sessionKey);
8156
+ const cacheKey = c.var.cacheKey;
8157
+ const accountId = getAccountIdForSession(cacheKey);
8053
8158
  if (!accountId) {
8054
8159
  return new Response("Unauthorized", { status: 401 });
8055
8160
  }
@@ -8085,13 +8190,13 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
8085
8190
  }
8086
8191
  });
8087
8192
  });
8088
- var attachment_default = app15;
8193
+ var attachment_default = app16;
8089
8194
 
8090
8195
  // server/routes/admin/agents.ts
8091
8196
  import { resolve as resolve11 } from "path";
8092
8197
  import { readdirSync as readdirSync6, readFileSync as readFileSync12, existsSync as existsSync14, rmSync } from "fs";
8093
- var app16 = new Hono();
8094
- app16.get("/", (c) => {
8198
+ var app17 = new Hono();
8199
+ app17.get("/", (c) => {
8095
8200
  const account = resolveAccount();
8096
8201
  if (!account) return c.json({ agents: [] });
8097
8202
  const agentsDir = resolve11(account.accountDir, "agents");
@@ -8121,7 +8226,7 @@ app16.get("/", (c) => {
8121
8226
  }
8122
8227
  return c.json({ agents });
8123
8228
  });
8124
- app16.delete("/:slug", async (c) => {
8229
+ app17.delete("/:slug", async (c) => {
8125
8230
  const slug = c.req.param("slug");
8126
8231
  const account = resolveAccount();
8127
8232
  if (!account) return c.json({ error: "No account resolved" }, 400);
@@ -8151,7 +8256,7 @@ app16.delete("/:slug", async (c) => {
8151
8256
  return c.json({ error: "Failed to delete agent" }, 500);
8152
8257
  }
8153
8258
  });
8154
- app16.post("/:slug/project", async (c) => {
8259
+ app17.post("/:slug/project", async (c) => {
8155
8260
  const slug = c.req.param("slug");
8156
8261
  const account = resolveAccount();
8157
8262
  if (!account) return c.json({ error: "No account resolved" }, 400);
@@ -8173,7 +8278,7 @@ app16.post("/:slug/project", async (c) => {
8173
8278
  return c.json({ error: `Projection failed: ${msg}` }, 500);
8174
8279
  }
8175
8280
  });
8176
- var agents_default = app16;
8281
+ var agents_default = app17;
8177
8282
 
8178
8283
  // server/routes/admin/sessions.ts
8179
8284
  import crypto2 from "crypto";
@@ -8441,19 +8546,19 @@ function formatAge(updatedAtStr) {
8441
8546
  return "unknown";
8442
8547
  }
8443
8548
  }
8444
- var app17 = new Hono();
8445
- app17.get("/", requireAdminSession, async (c) => {
8446
- const sessionKey = c.var.sessionKey;
8447
- const accountId = getAccountIdForSession(sessionKey);
8549
+ var app18 = new Hono();
8550
+ app18.get("/", requireAdminSession, async (c) => {
8551
+ const cacheKey = c.var.cacheKey;
8552
+ const accountId = getAccountIdForSession(cacheKey);
8448
8553
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
8449
- const userId = getUserIdForSession(sessionKey);
8554
+ const userId = getUserIdForSession(cacheKey);
8450
8555
  if (!userId) return c.json({ error: "User identity required \u2014 authenticate with users.json PIN" }, 401);
8451
8556
  try {
8452
8557
  const flushed = await listAdminSessions(accountId, userId, 20);
8453
8558
  const inProgressRaw = listAdminSessionsInProgress(accountId, userId);
8454
8559
  const flushedRows = flushed.map((r) => ({
8455
8560
  conversationId: r.conversationId,
8456
- sessionKey: null,
8561
+ cacheKey: null,
8457
8562
  name: r.name,
8458
8563
  updatedAt: r.updatedAt,
8459
8564
  phase: "flushed",
@@ -8461,7 +8566,7 @@ app17.get("/", requireAdminSession, async (c) => {
8461
8566
  }));
8462
8567
  const inProgressRows = inProgressRaw.map((r) => ({
8463
8568
  conversationId: null,
8464
- sessionKey: r.sessionKey,
8569
+ cacheKey: r.cacheKey,
8465
8570
  name: null,
8466
8571
  updatedAt: new Date(r.createdAt).toISOString(),
8467
8572
  phase: "pre-flush",
@@ -8482,52 +8587,52 @@ app17.get("/", requireAdminSession, async (c) => {
8482
8587
  return c.json({ error: "Failed to fetch sessions" }, 500);
8483
8588
  }
8484
8589
  });
8485
- app17.post("/new", requireAdminSession, async (c) => {
8486
- const oldSessionKey = c.var.sessionKey;
8487
- const accountId = getAccountIdForSession(oldSessionKey);
8488
- const userId = getUserIdForSession(oldSessionKey);
8590
+ app18.post("/new", requireAdminSession, async (c) => {
8591
+ const oldCacheKey = c.var.cacheKey;
8592
+ const accountId = getAccountIdForSession(oldCacheKey);
8593
+ const userId = getUserIdForSession(oldCacheKey);
8489
8594
  if (!accountId || !userId) {
8490
8595
  return c.json({ error: "Session missing account or user context" }, 400);
8491
8596
  }
8492
- const newSessionKey = crypto2.randomUUID();
8493
- const userName = getUserNameForSession(oldSessionKey);
8494
- registerSession(newSessionKey, "admin", accountId, void 0, userId, userName);
8495
- const previousConversationId = clearSessionHistory(oldSessionKey);
8496
- unregisterSession(oldSessionKey);
8497
- console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} session reset for new conversation: oldSessionKey=${oldSessionKey.slice(0, 8)}\u2026 newSessionKey=${newSessionKey.slice(0, 8)}\u2026 previousConversationId=${previousConversationId?.slice(0, 8) ?? "none"}\u2026 newConversationId=deferred`);
8498
- return c.json({ session_key: newSessionKey, conversationId: null });
8597
+ const newCacheKey = crypto2.randomUUID();
8598
+ const userName = getUserNameForSession(oldCacheKey);
8599
+ registerSession(newCacheKey, "admin", accountId, void 0, userId, userName);
8600
+ const previousConversationId = clearSessionHistory(oldCacheKey);
8601
+ unregisterSession(oldCacheKey);
8602
+ console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} session reset for new conversation: oldCacheKey=${oldCacheKey.slice(0, 8)}\u2026 newCacheKey=${newCacheKey.slice(0, 8)}\u2026 previousConversationId=${previousConversationId?.slice(0, 8) ?? "none"}\u2026 newConversationId=deferred`);
8603
+ return c.json({ session_key: newCacheKey, conversationId: null });
8499
8604
  });
8500
- app17.post("/switch", requireAdminSession, async (c) => {
8501
- const sessionKey = c.var.sessionKey;
8502
- const accountId = getAccountIdForSession(sessionKey);
8503
- const userId = getUserIdForSession(sessionKey);
8605
+ app18.post("/switch", requireAdminSession, async (c) => {
8606
+ const cacheKey = c.var.cacheKey;
8607
+ const accountId = getAccountIdForSession(cacheKey);
8608
+ const userId = getUserIdForSession(cacheKey);
8504
8609
  if (!accountId || !userId) {
8505
8610
  return c.json({ error: "Session missing account or user context" }, 400);
8506
8611
  }
8507
8612
  const body = await c.req.json().catch(() => ({}));
8508
- const targetSessionKey = typeof body.target_session_key === "string" ? body.target_session_key : "";
8509
- if (!targetSessionKey) {
8613
+ const targetCacheKey = typeof body.target_session_key === "string" ? body.target_session_key : "";
8614
+ if (!targetCacheKey) {
8510
8615
  return c.json({ error: "target_session_key required" }, 400);
8511
8616
  }
8512
- const targetCheck = validateSession(targetSessionKey, "admin");
8617
+ const targetCheck = validateSession(targetCacheKey, "admin");
8513
8618
  if (!targetCheck.ok) {
8514
- console.error(`[session-switch] reject reason=${targetCheck.reason} from=${sessionKey.slice(0, 8)} target=${targetSessionKey.slice(0, 8)}`);
8619
+ console.error(`[session-switch] reject reason=${targetCheck.reason} from=${cacheKey.slice(0, 8)} target=${targetCacheKey.slice(0, 8)}`);
8515
8620
  return c.json({ error: "Target session not registered or wrong agent type", code: targetCheck.reason }, 404);
8516
8621
  }
8517
- const targetAccountId = getAccountIdForSession(targetSessionKey);
8518
- const targetUserId = getUserIdForSession(targetSessionKey);
8622
+ const targetAccountId = getAccountIdForSession(targetCacheKey);
8623
+ const targetUserId = getUserIdForSession(targetCacheKey);
8519
8624
  if (targetAccountId !== accountId || targetUserId !== userId) {
8520
- console.error(`[session-switch] reject reason=ownership-mismatch from=${sessionKey.slice(0, 8)} target=${targetSessionKey.slice(0, 8)} accountMatch=${targetAccountId === accountId} userMatch=${targetUserId === userId}`);
8625
+ console.error(`[session-switch] reject reason=ownership-mismatch from=${cacheKey.slice(0, 8)} target=${targetCacheKey.slice(0, 8)} accountMatch=${targetAccountId === accountId} userMatch=${targetUserId === userId}`);
8521
8626
  return c.json({ error: "Target session not owned by current operator" }, 403);
8522
8627
  }
8523
- const targetConversationId = getConversationIdForSession(targetSessionKey) ?? null;
8524
- console.log(`[session-switch] from=${sessionKey.slice(0, 8)} to=${targetSessionKey.slice(0, 8)} targetConvId=${targetConversationId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
8525
- return c.json({ session_key: targetSessionKey, conversationId: targetConversationId });
8628
+ const targetConversationId = getConversationIdForSession(targetCacheKey) ?? null;
8629
+ console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetConversationId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
8630
+ return c.json({ session_key: targetCacheKey, conversationId: targetConversationId });
8526
8631
  });
8527
- app17.delete("/:id", requireAdminSession, async (c) => {
8632
+ app18.delete("/:id", requireAdminSession, async (c) => {
8528
8633
  const conversationId = c.req.param("id");
8529
- const sessionKey = c.var.sessionKey;
8530
- const accountId = getAccountIdForSession(sessionKey);
8634
+ const cacheKey = c.var.cacheKey;
8635
+ const accountId = getAccountIdForSession(cacheKey);
8531
8636
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
8532
8637
  const owned = await verifyConversationOwnership(conversationId, accountId);
8533
8638
  if (!owned) return c.json({ error: "Conversation not found" }, 404);
@@ -8539,42 +8644,42 @@ app17.delete("/:id", requireAdminSession, async (c) => {
8539
8644
  return c.json({ error: "Failed to delete session" }, 500);
8540
8645
  }
8541
8646
  });
8542
- app17.post("/:id/resume", async (c) => {
8647
+ app18.post("/:id/resume", async (c) => {
8543
8648
  const conversationId = c.req.param("id");
8544
- const sessionKey = c.req.query("session_key") ?? "";
8545
- if (!sessionKey) {
8649
+ const cacheKey = c.req.query("session_key") ?? "";
8650
+ if (!cacheKey) {
8546
8651
  console.error(`[session] middleware-reject status=400 code=session-missing reason="session_key required" path=${c.req.path}`);
8547
8652
  return c.json({ error: "session_key required", code: "session-missing" }, 400);
8548
8653
  }
8549
8654
  let bridged = false;
8550
- let result = validateSession(sessionKey, "admin");
8655
+ let result = validateSession(cacheKey, "admin");
8551
8656
  if (!result.ok) {
8552
8657
  if (result.reason === "session-not-registered") {
8553
- const bridge = await tryCookieBridgeForConversation(c, sessionKey, conversationId);
8658
+ const bridge = await tryCookieBridgeForConversation(c, cacheKey, conversationId);
8554
8659
  if (!bridge.ok) {
8555
8660
  if (bridge.reason === "conversation-not-found") {
8556
8661
  return c.json({ error: "Conversation not found" }, 404);
8557
8662
  }
8558
- const tail = sessionKey.slice(0, 8);
8559
- console.error(`[session] middleware-reject status=401 code=session-not-registered reason="cookie-bridge-rejected:${bridge.reason}" path=${c.req.path} sessionKey=${tail}\u2026`);
8663
+ const tail = cacheKey.slice(0, 8);
8664
+ console.error(`[session] middleware-reject status=401 code=session-not-registered reason="cookie-bridge-rejected:${bridge.reason}" path=${c.req.path} cacheKey=${tail}\u2026`);
8560
8665
  return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
8561
8666
  }
8562
8667
  bridged = true;
8563
- result = validateSession(sessionKey, "admin");
8668
+ result = validateSession(cacheKey, "admin");
8564
8669
  if (!result.ok) {
8565
- const tail = sessionKey.slice(0, 8);
8566
- console.error(`[session] middleware-reject status=401 code=session-not-registered reason="post-bridge re-validate failed" path=${c.req.path} sessionKey=${tail}\u2026`);
8670
+ const tail = cacheKey.slice(0, 8);
8671
+ console.error(`[session] middleware-reject status=401 code=session-not-registered reason="post-bridge re-validate failed" path=${c.req.path} cacheKey=${tail}\u2026`);
8567
8672
  return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
8568
8673
  }
8569
8674
  } else {
8570
- const tail = sessionKey.slice(0, 8);
8675
+ const tail = cacheKey.slice(0, 8);
8571
8676
  const wireCode = result.reason === "agent-type-mismatch" ? "session-not-registered" : result.reason;
8572
- console.error(`[session] middleware-reject status=401 code=${wireCode} reason="invalid or expired admin session" path=${c.req.path} sessionKey=${tail}\u2026`);
8677
+ console.error(`[session] middleware-reject status=401 code=${wireCode} reason="invalid or expired admin session" path=${c.req.path} cacheKey=${tail}\u2026`);
8573
8678
  return c.json({ error: "Invalid or expired admin session", code: wireCode }, 401);
8574
8679
  }
8575
8680
  }
8576
- const accountId = getAccountIdForSession(sessionKey);
8577
- const userId = getUserIdForSession(sessionKey);
8681
+ const accountId = getAccountIdForSession(cacheKey);
8682
+ const userId = getUserIdForSession(cacheKey);
8578
8683
  if (!accountId) {
8579
8684
  return c.json({ error: "Session missing account context" }, 400);
8580
8685
  }
@@ -8584,9 +8689,9 @@ app17.post("/:id/resume", async (c) => {
8584
8689
  const updatedAt = await verifyAndGetConversationUpdatedAt(conversationId, accountId);
8585
8690
  if (updatedAt === null) return c.json({ error: "Conversation not found" }, 404);
8586
8691
  const persistedAgentSessionId = await getAgentSessionIdForConversation(conversationId);
8587
- setConversationIdForSession(sessionKey, conversationId);
8692
+ setConversationIdForSession(cacheKey, conversationId);
8588
8693
  if (persistedAgentSessionId) {
8589
- setAgentSessionId(sessionKey, persistedAgentSessionId);
8694
+ setAgentSessionId(cacheKey, persistedAgentSessionId);
8590
8695
  }
8591
8696
  const streamLogPath = resolvePath(ACCOUNTS_DIR, accountId, "logs", `claude-agent-stream-${conversationId}.log`);
8592
8697
  const tag = persistedAgentSessionId ? `agentSessionId=${persistedAgentSessionId.slice(0, 8)}\u2026` : "agentSessionId=missing";
@@ -8611,7 +8716,7 @@ app17.post("/:id/resume", async (c) => {
8611
8716
  jsonlMalformedLines = replay.malformedLines;
8612
8717
  jsonlReplayMessages = replay.messages;
8613
8718
  if (replay.jsonlMissing) {
8614
- console.error(`[jsonl-resume-miss] sessionKey=${sessionKey.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>"}`);
8719
+ console.error(`[jsonl-resume-miss] cacheKey=${cacheKey.slice(0, 8)}\u2026 conversationId=${conversationId.slice(0, 8)}\u2026 agentSessionId=${persistedAgentSessionId.slice(0, 8)}\u2026 expectedPath=${jsonlPath} configDir=${process.env.CLAUDE_CONFIG_DIR ?? "<unset>"}`);
8615
8720
  }
8616
8721
  } else {
8617
8722
  jsonlMissing = true;
@@ -8774,7 +8879,7 @@ app17.post("/:id/resume", async (c) => {
8774
8879
  const reason = bridged ? "post-restart" : "page-refresh";
8775
8880
  try {
8776
8881
  const source = jsonlMissing ? persistedAgentSessionId ? "jsonl-missing" : "neo4j-only" : "jsonl";
8777
- appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} source=${source} sessionKey=${sessionKey.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}
8882
+ appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} source=${source} cacheKey=${cacheKey.slice(0, 8)} conversationId=${conversationId.slice(0, 8)} ${tag} loadedMessages=${messages.length} jsonlReplayMessages=${jsonlReplayMessages.length} neo4jMessages=${neo4jMessages.length} jsonlMalformed=${jsonlMalformedLines} componentCount=${totalComponents} userAttachmentCount=${totalAttachments} syntheticHidden=${syntheticHidden}
8778
8883
  `);
8779
8884
  if (totalComponents > 0) {
8780
8885
  appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-rehydrate] conversationId=${conversationId.slice(0, 8)} count=${totalComponents} valid=${totalValid} invalid=${totalInvalid} textRuns=${textRuns}
@@ -8791,7 +8896,7 @@ app17.post("/:id/resume", async (c) => {
8791
8896
  } catch {
8792
8897
  }
8793
8898
  const age = formatAge(updatedAt);
8794
- 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} sessionKey=${sessionKey.slice(0, 8)}\u2026`);
8899
+ console.log(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} reason=${reason} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages ${tag} components=${totalComponents} attachments=${totalAttachments} syntheticHidden=${syntheticHidden} jsonlMissing=${jsonlMissing} healMissing=${jsonlHealMissing} cacheKey=${cacheKey.slice(0, 8)}\u2026`);
8795
8900
  return c.json({
8796
8901
  conversationId,
8797
8902
  messages: rehydrated,
@@ -8804,10 +8909,10 @@ app17.post("/:id/resume", async (c) => {
8804
8909
  }
8805
8910
  });
8806
8911
  });
8807
- app17.post("/:id/label", requireAdminSession, async (c) => {
8912
+ app18.post("/:id/label", requireAdminSession, async (c) => {
8808
8913
  const conversationId = c.req.param("id");
8809
- const sessionKey = c.var.sessionKey;
8810
- const accountId = getAccountIdForSession(sessionKey);
8914
+ const cacheKey = c.var.cacheKey;
8915
+ const accountId = getAccountIdForSession(cacheKey);
8811
8916
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
8812
8917
  const owned = await verifyConversationOwnership(conversationId, accountId);
8813
8918
  if (!owned) return c.json({ error: "Conversation not found" }, 404);
@@ -8831,16 +8936,16 @@ app17.post("/:id/label", requireAdminSession, async (c) => {
8831
8936
  return c.json({ label: null });
8832
8937
  }
8833
8938
  });
8834
- app17.put("/:id/label", requireAdminSession, async (c) => {
8939
+ app18.put("/:id/label", requireAdminSession, async (c) => {
8835
8940
  const conversationId = c.req.param("id");
8836
- const sessionKey = c.var.sessionKey;
8941
+ const cacheKey = c.var.cacheKey;
8837
8942
  let body;
8838
8943
  try {
8839
8944
  body = await c.req.json();
8840
8945
  } catch {
8841
8946
  return c.json({ error: "Invalid JSON body" }, 400);
8842
8947
  }
8843
- const accountId = getAccountIdForSession(sessionKey);
8948
+ const accountId = getAccountIdForSession(cacheKey);
8844
8949
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
8845
8950
  const owned = await verifyConversationOwnership(conversationId, accountId);
8846
8951
  if (!owned) return c.json({ error: "Conversation not found" }, 404);
@@ -8857,11 +8962,11 @@ app17.put("/:id/label", requireAdminSession, async (c) => {
8857
8962
  return c.json({ error: "Failed to rename session" }, 500);
8858
8963
  }
8859
8964
  });
8860
- var sessions_default = app17;
8965
+ var sessions_default = app18;
8861
8966
 
8862
8967
  // server/routes/admin/browser.ts
8863
- var app18 = new Hono();
8864
- app18.post("/launch", async (c) => {
8968
+ var app19 = new Hono();
8969
+ app19.post("/launch", async (c) => {
8865
8970
  try {
8866
8971
  const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
8867
8972
  if (transport === "vnc") {
@@ -8883,7 +8988,7 @@ app18.post("/launch", async (c) => {
8883
8988
  );
8884
8989
  }
8885
8990
  });
8886
- var browser_default = app18;
8991
+ var browser_default = app19;
8887
8992
 
8888
8993
  // server/routes/admin/browser-iframe.ts
8889
8994
  var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
@@ -8900,8 +9005,8 @@ function asString(v, max = 500) {
8900
9005
  function asNumber(v) {
8901
9006
  return typeof v === "number" && Number.isFinite(v) ? v : void 0;
8902
9007
  }
8903
- var app19 = new Hono();
8904
- app19.post("/event", async (c) => {
9008
+ var app20 = new Hono();
9009
+ app20.post("/event", async (c) => {
8905
9010
  let body = {};
8906
9011
  try {
8907
9012
  body = await c.req.json();
@@ -8922,7 +9027,7 @@ app19.post("/event", async (c) => {
8922
9027
  });
8923
9028
  return c.body(null, 204);
8924
9029
  });
8925
- var browser_iframe_default = app19;
9030
+ var browser_iframe_default = app20;
8926
9031
 
8927
9032
  // app/lib/cdp-client.ts
8928
9033
  var CDP_HOST = "127.0.0.1";
@@ -8965,8 +9070,8 @@ async function cdpNavigateNewTab(url, opts = {}) {
8965
9070
  }
8966
9071
 
8967
9072
  // server/routes/admin/device-browser.ts
8968
- var app20 = new Hono();
8969
- app20.post("/navigate", async (c) => {
9073
+ var app21 = new Hono();
9074
+ app21.post("/navigate", async (c) => {
8970
9075
  const TAG19 = "[device-url:click]";
8971
9076
  let body;
8972
9077
  try {
@@ -9053,7 +9158,7 @@ app20.post("/navigate", async (c) => {
9053
9158
  targetId: outcome.targetId
9054
9159
  });
9055
9160
  });
9056
- var device_browser_default = app20;
9161
+ var device_browser_default = app21;
9057
9162
 
9058
9163
  // server/routes/admin/events.ts
9059
9164
  var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
@@ -9062,8 +9167,8 @@ var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
9062
9167
  "device-url:vnc-surface-shown",
9063
9168
  "device-url:malformed"
9064
9169
  ]);
9065
- var app21 = new Hono();
9066
- app21.post("/", async (c) => {
9170
+ var app22 = new Hono();
9171
+ app22.post("/", async (c) => {
9067
9172
  const TAG19 = "[admin:events]";
9068
9173
  let body;
9069
9174
  try {
@@ -9094,7 +9199,7 @@ app21.post("/", async (c) => {
9094
9199
  console.error(`[${event}] ${formatted}`);
9095
9200
  return c.json({ ok: true });
9096
9201
  });
9097
- var events_default = app21;
9202
+ var events_default = app22;
9098
9203
 
9099
9204
  // server/routes/admin/cloudflare.ts
9100
9205
  import { homedir as homedir2 } from "os";
@@ -9212,7 +9317,7 @@ function validateBody(body) {
9212
9317
  }
9213
9318
  return null;
9214
9319
  }
9215
- var app22 = new Hono();
9320
+ var app23 = new Hono();
9216
9321
  function fieldFromReason(reason) {
9217
9322
  switch (reason) {
9218
9323
  case "not-signed-in":
@@ -9233,15 +9338,15 @@ function fieldFromReason(reason) {
9233
9338
  return "script";
9234
9339
  }
9235
9340
  }
9236
- app22.get("/domains", requireAdminSession, async (c) => {
9341
+ app23.get("/domains", requireAdminSession, async (c) => {
9237
9342
  const started = Date.now();
9238
- const sessionKey = c.var.sessionKey;
9343
+ const cacheKey = c.var.cacheKey;
9239
9344
  let correlationId;
9240
- let sessionKeyTail;
9345
+ let cacheKeyTail;
9241
9346
  let streamLogPath;
9242
9347
  function tag() {
9243
9348
  if (!correlationId) return "";
9244
- return ` conversationId=${correlationId} session_key=${sessionKeyTail ?? "unknown"}`;
9349
+ return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
9245
9350
  }
9246
9351
  function log(line) {
9247
9352
  console.log(`[cloudflare-domains] ${line}${tag()}`);
@@ -9269,9 +9374,9 @@ app22.get("/domains", requireAdminSession, async (c) => {
9269
9374
  };
9270
9375
  return c.json(body, 200);
9271
9376
  }
9272
- const accountId = getAccountIdForSession(sessionKey);
9273
- correlationId = getConversationIdForSession(sessionKey);
9274
- sessionKeyTail = sessionKey.slice(-8);
9377
+ const accountId = getAccountIdForSession(cacheKey);
9378
+ correlationId = getConversationIdForSession(cacheKey);
9379
+ cacheKeyTail = cacheKey.slice(-8);
9275
9380
  if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
9276
9381
  if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
9277
9382
  streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
@@ -9328,15 +9433,15 @@ ${result.stderr}` : ""}`;
9328
9433
  return c.json(success, 200);
9329
9434
  });
9330
9435
  var TUNNELS_TIMEOUT_MS = 30 * 1e3;
9331
- app22.get("/tunnels", requireAdminSession, async (c) => {
9436
+ app23.get("/tunnels", requireAdminSession, async (c) => {
9332
9437
  const started = Date.now();
9333
- const sessionKey = c.var.sessionKey;
9438
+ const cacheKey = c.var.cacheKey;
9334
9439
  let correlationId;
9335
- let sessionKeyTail;
9440
+ let cacheKeyTail;
9336
9441
  let streamLogPath;
9337
9442
  function tag() {
9338
9443
  if (!correlationId) return "";
9339
- return ` conversationId=${correlationId} session_key=${sessionKeyTail ?? "unknown"}`;
9444
+ return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
9340
9445
  }
9341
9446
  function log(line) {
9342
9447
  console.log(`[cloudflare-tunnels] ${line}${tag()}`);
@@ -9361,9 +9466,9 @@ app22.get("/tunnels", requireAdminSession, async (c) => {
9361
9466
  const body = { ok: false, field, message, output, defaultName, correlationId, streamLogPath };
9362
9467
  return c.json(body, 200);
9363
9468
  }
9364
- const accountId = getAccountIdForSession(sessionKey);
9365
- correlationId = getConversationIdForSession(sessionKey);
9366
- sessionKeyTail = sessionKey.slice(-8);
9469
+ const accountId = getAccountIdForSession(cacheKey);
9470
+ correlationId = getConversationIdForSession(cacheKey);
9471
+ cacheKeyTail = cacheKey.slice(-8);
9367
9472
  if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
9368
9473
  if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
9369
9474
  streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
@@ -9424,15 +9529,15 @@ ${result.stderr}` : ""}`;
9424
9529
  const success = { ok: true, tunnels, defaultName, correlationId, streamLogPath };
9425
9530
  return c.json(success, 200);
9426
9531
  });
9427
- app22.post("/setup", requireAdminSession, async (c) => {
9532
+ app23.post("/setup", requireAdminSession, async (c) => {
9428
9533
  const started = Date.now();
9429
- const sessionKey = c.var.sessionKey;
9534
+ const cacheKey = c.var.cacheKey;
9430
9535
  let correlationId;
9431
- let sessionKeyTail;
9536
+ let cacheKeyTail;
9432
9537
  let streamLogPath;
9433
9538
  function tag() {
9434
9539
  if (!correlationId) return "";
9435
- return ` conversationId=${correlationId} session_key=${sessionKeyTail ?? "unknown"}`;
9540
+ return ` conversationId=${correlationId} session_key=${cacheKeyTail ?? "unknown"}`;
9436
9541
  }
9437
9542
  function log(line) {
9438
9543
  console.log(`[cloudflare-setup] ${line}${tag()}`);
@@ -9468,9 +9573,9 @@ app22.post("/setup", requireAdminSession, async (c) => {
9468
9573
  } catch {
9469
9574
  return err("request", "Invalid JSON body");
9470
9575
  }
9471
- const accountId = getAccountIdForSession(sessionKey);
9472
- correlationId = getConversationIdForSession(sessionKey);
9473
- sessionKeyTail = sessionKey.slice(-8);
9576
+ const accountId = getAccountIdForSession(cacheKey);
9577
+ correlationId = getConversationIdForSession(cacheKey);
9578
+ cacheKeyTail = cacheKey.slice(-8);
9474
9579
  if (!accountId) {
9475
9580
  return err("request", "No account bound to session \u2014 refresh chat.");
9476
9581
  }
@@ -9523,7 +9628,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
9523
9628
  try {
9524
9629
  cloudflareTask = await openCloudflareTask({
9525
9630
  accountId,
9526
- conversationKey: sessionKey,
9631
+ conversationId: correlationId,
9527
9632
  inputsProvided: Object.keys(taskInputs),
9528
9633
  inputs: taskInputs,
9529
9634
  inputSchema: CLOUDFLARE_SETUP_FORM_SCHEMA,
@@ -9571,7 +9676,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
9571
9676
  taskId: cloudflareTask.taskId,
9572
9677
  taskElementId: cloudflareTask.taskElementId,
9573
9678
  accountId,
9574
- conversationKey: sessionKey,
9679
+ conversationId: correlationId,
9575
9680
  status: "failed",
9576
9681
  errorMessage: CLOUDFLARE_TASK_DIAGNOSTICS.endpointDiedPreReconcile
9577
9682
  });
@@ -9588,7 +9693,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
9588
9693
  taskId: cloudflareTask.taskId,
9589
9694
  taskElementId: cloudflareTask.taskElementId,
9590
9695
  accountId,
9591
- conversationKey: sessionKey,
9696
+ conversationId: correlationId,
9592
9697
  status: "failed",
9593
9698
  errorMessage: `${CLOUDFLARE_TASK_DIAGNOSTICS.scriptExitedNonzero} exit=${status.execMainStatus}`
9594
9699
  });
@@ -9630,7 +9735,7 @@ app22.post("/setup", requireAdminSession, async (c) => {
9630
9735
  taskId: cloudflareTask.taskId,
9631
9736
  taskElementId: cloudflareTask.taskElementId,
9632
9737
  accountId,
9633
- conversationKey: sessionKey,
9738
+ conversationId: correlationId,
9634
9739
  tunnelId: tunnelState?.tunnelId,
9635
9740
  tunnelName: tunnelState?.tunnelName,
9636
9741
  hostnames: tunnelState ? hostnameRecords : void 0,
@@ -9661,7 +9766,7 @@ actionId: ${actionId}`,
9661
9766
  };
9662
9767
  return ok(success);
9663
9768
  });
9664
- var cloudflare_default = app22;
9769
+ var cloudflare_default = app23;
9665
9770
 
9666
9771
  // server/routes/admin/files.ts
9667
9772
  import { createReadStream as createReadStream3 } from "fs";
@@ -9721,7 +9826,7 @@ var UNIQUE_KEYS_BY_LABEL = {
9721
9826
  Event: ["eventId"],
9722
9827
  KnowledgeDocument: ["attachmentId"],
9723
9828
  DigitalDocument: ["attachmentId"],
9724
- Conversation: ["conversationId", "sessionKey"],
9829
+ Conversation: ["conversationId"],
9725
9830
  Message: ["messageId"],
9726
9831
  OnboardingState: ["accountId"],
9727
9832
  Workflow: ["workflowId"],
@@ -9942,7 +10047,7 @@ async function restoreNode(params) {
9942
10047
  }
9943
10048
 
9944
10049
  // app/lib/file-delete-cascade.ts
9945
- var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
10050
+ var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9946
10051
  function parseAttachmentPath(relPath2) {
9947
10052
  const segments = relPath2.split("/").filter(Boolean);
9948
10053
  if (segments.length !== 4) return null;
@@ -9950,7 +10055,7 @@ function parseAttachmentPath(relPath2) {
9950
10055
  const accountId = segments[1];
9951
10056
  const attachmentId = segments[2];
9952
10057
  const filename = segments[3];
9953
- if (!UUID_RE3.test(accountId) || !UUID_RE3.test(attachmentId)) return null;
10058
+ if (!UUID_RE4.test(accountId) || !UUID_RE4.test(attachmentId)) return null;
9954
10059
  const dot = filename.lastIndexOf(".");
9955
10060
  if (dot === -1) return null;
9956
10061
  const stem = filename.slice(0, dot);
@@ -10022,7 +10127,7 @@ async function cascadeDeleteDocument(params) {
10022
10127
  }
10023
10128
 
10024
10129
  // server/routes/admin/files.ts
10025
- var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
10130
+ var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
10026
10131
  async function readMeta(absDir, baseName) {
10027
10132
  try {
10028
10133
  const raw = await readFile3(join9(absDir, `${baseName}.meta.json`), "utf8");
@@ -10044,7 +10149,7 @@ async function readAccountNames() {
10044
10149
  return map;
10045
10150
  }
10046
10151
  for (const name of names) {
10047
- if (!UUID_RE4.test(name)) continue;
10152
+ if (!UUID_RE5.test(name)) continue;
10048
10153
  const configPath2 = resolve15(accountsDir, name, "account.json");
10049
10154
  try {
10050
10155
  const raw = await readFile3(configPath2, "utf8");
@@ -10062,7 +10167,7 @@ async function readAccountNames() {
10062
10167
  return map;
10063
10168
  }
10064
10169
  async function enrich(absolute, entry, accountNames) {
10065
- if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
10170
+ if (entry.kind === "directory" && UUID_RE5.test(entry.name)) {
10066
10171
  const meta = await readMeta(join9(absolute, entry.name), entry.name);
10067
10172
  if (meta?.filename) {
10068
10173
  entry.displayName = meta.filename;
@@ -10078,7 +10183,7 @@ async function enrich(absolute, entry, accountNames) {
10078
10183
  if (entry.kind === "file") {
10079
10184
  const dot = entry.name.lastIndexOf(".");
10080
10185
  const base = dot === -1 ? entry.name : entry.name.slice(0, dot);
10081
- if (UUID_RE4.test(base)) {
10186
+ if (UUID_RE5.test(base)) {
10082
10187
  const meta = await readMeta(absolute, base);
10083
10188
  if (meta?.filename) {
10084
10189
  entry.displayName = meta.filename;
@@ -10090,14 +10195,14 @@ async function enrich(absolute, entry, accountNames) {
10090
10195
  function buildDisplayPath(relPath2, accountNames) {
10091
10196
  if (relPath2 === "." || relPath2 === "") return [];
10092
10197
  return relPath2.split("/").filter(Boolean).map((seg) => {
10093
- const dn = UUID_RE4.test(seg) ? accountNames.get(seg) : void 0;
10198
+ const dn = UUID_RE5.test(seg) ? accountNames.get(seg) : void 0;
10094
10199
  return dn ? { name: seg, displayName: dn } : { name: seg };
10095
10200
  });
10096
10201
  }
10097
- var app23 = new Hono();
10098
- app23.get("/", requireAdminSession, async (c) => {
10099
- const sessionKey = c.var.sessionKey;
10100
- if (!getAccountIdForSession(sessionKey)) {
10202
+ var app24 = new Hono();
10203
+ app24.get("/", requireAdminSession, async (c) => {
10204
+ const cacheKey = c.var.cacheKey;
10205
+ if (!getAccountIdForSession(cacheKey)) {
10101
10206
  console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
10102
10207
  return c.json({ error: "Account not found for session" }, 401);
10103
10208
  }
@@ -10118,7 +10223,7 @@ app23.get("/", requireAdminSession, async (c) => {
10118
10223
  const names = await readdir2(absolute);
10119
10224
  const entries = [];
10120
10225
  for (const name of names) {
10121
- if (UUID_RE4.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
10226
+ if (UUID_RE5.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
10122
10227
  continue;
10123
10228
  }
10124
10229
  try {
@@ -10156,9 +10261,9 @@ app23.get("/", requireAdminSession, async (c) => {
10156
10261
  return c.json({ error: message }, 500);
10157
10262
  }
10158
10263
  });
10159
- app23.get("/download", requireAdminSession, async (c) => {
10160
- const sessionKey = c.var.sessionKey;
10161
- if (!getAccountIdForSession(sessionKey)) {
10264
+ app24.get("/download", requireAdminSession, async (c) => {
10265
+ const cacheKey = c.var.cacheKey;
10266
+ if (!getAccountIdForSession(cacheKey)) {
10162
10267
  console.error(`[data] auth-rejected endpoint="/api/admin/files/download" reason="no account for session"`);
10163
10268
  return c.json({ error: "Account not found for session" }, 401);
10164
10269
  }
@@ -10204,9 +10309,9 @@ app23.get("/download", requireAdminSession, async (c) => {
10204
10309
  return c.json({ error: message }, 500);
10205
10310
  }
10206
10311
  });
10207
- app23.post("/upload", requireAdminSession, async (c) => {
10208
- const sessionKey = c.var.sessionKey;
10209
- const accountId = getAccountIdForSession(sessionKey);
10312
+ app24.post("/upload", requireAdminSession, async (c) => {
10313
+ const cacheKey = c.var.cacheKey;
10314
+ const accountId = getAccountIdForSession(cacheKey);
10210
10315
  if (!accountId) {
10211
10316
  console.error(`[data] auth-rejected endpoint="/api/admin/files/upload" reason="no account for session"`);
10212
10317
  return c.json({ error: "Account not found for session" }, 401);
@@ -10262,9 +10367,9 @@ app23.post("/upload", requireAdminSession, async (c) => {
10262
10367
  mimeType: file.type
10263
10368
  });
10264
10369
  });
10265
- app23.delete("/", requireAdminSession, async (c) => {
10266
- const sessionKey = c.var.sessionKey;
10267
- const accountId = getAccountIdForSession(sessionKey);
10370
+ app24.delete("/", requireAdminSession, async (c) => {
10371
+ const cacheKey = c.var.cacheKey;
10372
+ const accountId = getAccountIdForSession(cacheKey);
10268
10373
  if (!accountId) {
10269
10374
  console.error(`[data] auth-rejected endpoint="DELETE /api/admin/files" reason="no account for session"`);
10270
10375
  return c.json({ error: "Account not found for session" }, 401);
@@ -10295,7 +10400,7 @@ app23.delete("/", requireAdminSession, async (c) => {
10295
10400
  }
10296
10401
  const dot = base.lastIndexOf(".");
10297
10402
  const stem = dot === -1 ? base : base.slice(0, dot);
10298
- const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join9(dirname6(absolute), `${stem}.meta.json`) : null;
10403
+ const sidecarPath = UUID_RE5.test(stem) && base !== `${stem}.meta.json` ? join9(dirname6(absolute), `${stem}.meta.json`) : null;
10299
10404
  await unlink2(absolute);
10300
10405
  if (sidecarPath) {
10301
10406
  try {
@@ -10329,7 +10434,7 @@ app23.delete("/", requireAdminSession, async (c) => {
10329
10434
  return c.json({ error: message }, 500);
10330
10435
  }
10331
10436
  });
10332
- var files_default = app23;
10437
+ var files_default = app24;
10333
10438
 
10334
10439
  // ../lib/graph-search/src/index.ts
10335
10440
  var import_dist = __toESM(require_dist());
@@ -10709,14 +10814,14 @@ var MAX_LIMIT = 2e3;
10709
10814
  var DEFAULT_VECTOR_THRESHOLD = 0.82;
10710
10815
  var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
10711
10816
  var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
10712
- var app24 = new Hono();
10713
- app24.get("/", requireAdminSession, async (c) => {
10714
- const sessionKey = c.var.sessionKey;
10817
+ var app25 = new Hono();
10818
+ app25.get("/", requireAdminSession, async (c) => {
10819
+ const cacheKey = c.var.cacheKey;
10715
10820
  const q = (c.req.query("q") ?? "").trim();
10716
10821
  const rawLimit = c.req.query("limit");
10717
10822
  const rawLabels = c.req.query("labels");
10718
10823
  const rawThreshold = c.req.query("threshold");
10719
- const accountId = getAccountIdForSession(sessionKey);
10824
+ const accountId = getAccountIdForSession(cacheKey);
10720
10825
  if (!accountId) {
10721
10826
  console.error(`[graph-search] auth-rejected endpoint="/api/admin/graph-search" reason="no account for session"`);
10722
10827
  return c.json({ error: "Account not found for session" }, 401);
@@ -10841,7 +10946,7 @@ app24.get("/", requireAdminSession, async (c) => {
10841
10946
  await session.close();
10842
10947
  }
10843
10948
  });
10844
- var graph_search_default = app24;
10949
+ var graph_search_default = app25;
10845
10950
 
10846
10951
  // server/routes/admin/graph-subgraph.ts
10847
10952
  import neo4j2 from "neo4j-driver";
@@ -10997,12 +11102,12 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
10997
11102
  "passwordHash",
10998
11103
  "magicToken",
10999
11104
  "otpCode",
11000
- "sessionKey"
11105
+ "cacheKey"
11001
11106
  ]);
11002
- var app25 = new Hono();
11003
- app25.get("/", requireAdminSession, async (c) => {
11004
- const sessionKey = c.var.sessionKey;
11005
- const accountId = getAccountIdForSession(sessionKey);
11107
+ var app26 = new Hono();
11108
+ app26.get("/", requireAdminSession, async (c) => {
11109
+ const cacheKey = c.var.cacheKey;
11110
+ const accountId = getAccountIdForSession(cacheKey);
11006
11111
  if (!accountId) {
11007
11112
  console.error('[graph-page] auth-rejected reason="no account for session"');
11008
11113
  return c.json({ error: "Account not found for session" }, 401);
@@ -11583,14 +11688,14 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
11583
11688
  }
11584
11689
  return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
11585
11690
  }
11586
- var graph_subgraph_default = app25;
11691
+ var graph_subgraph_default = app26;
11587
11692
 
11588
11693
  // server/routes/admin/graph-delete.ts
11589
11694
  var ALLOWED_BY = ["graph-page", "graph-drag-trash"];
11590
- var app26 = new Hono();
11591
- app26.post("/", requireAdminSession, async (c) => {
11592
- const sessionKey = c.var.sessionKey;
11593
- const accountId = getAccountIdForSession(sessionKey);
11695
+ var app27 = new Hono();
11696
+ app27.post("/", requireAdminSession, async (c) => {
11697
+ const cacheKey = c.var.cacheKey;
11698
+ const accountId = getAccountIdForSession(cacheKey);
11594
11699
  if (!accountId) {
11595
11700
  console.error('[graph-page] delete auth-rejected reason="no account for session"');
11596
11701
  return c.json({ error: "Account not found for session" }, 401);
@@ -11659,13 +11764,13 @@ app26.post("/", requireAdminSession, async (c) => {
11659
11764
  }
11660
11765
  }
11661
11766
  });
11662
- var graph_delete_default = app26;
11767
+ var graph_delete_default = app27;
11663
11768
 
11664
11769
  // server/routes/admin/graph-restore.ts
11665
- var app27 = new Hono();
11666
- app27.post("/", requireAdminSession, async (c) => {
11667
- const sessionKey = c.var.sessionKey;
11668
- const accountId = getAccountIdForSession(sessionKey);
11770
+ var app28 = new Hono();
11771
+ app28.post("/", requireAdminSession, async (c) => {
11772
+ const cacheKey = c.var.cacheKey;
11773
+ const accountId = getAccountIdForSession(cacheKey);
11669
11774
  if (!accountId) {
11670
11775
  console.error('[graph-page] restore auth-rejected reason="no account for session"');
11671
11776
  return c.json({ error: "Account not found for session" }, 401);
@@ -11727,13 +11832,13 @@ app27.post("/", requireAdminSession, async (c) => {
11727
11832
  }
11728
11833
  }
11729
11834
  });
11730
- var graph_restore_default = app27;
11835
+ var graph_restore_default = app28;
11731
11836
 
11732
11837
  // server/routes/admin/graph-labels-in-graph.ts
11733
- var app28 = new Hono();
11734
- app28.get("/", requireAdminSession, async (c) => {
11735
- const sessionKey = c.var.sessionKey;
11736
- const accountId = getAccountIdForSession(sessionKey);
11838
+ var app29 = new Hono();
11839
+ app29.get("/", requireAdminSession, async (c) => {
11840
+ const cacheKey = c.var.cacheKey;
11841
+ const accountId = getAccountIdForSession(cacheKey);
11737
11842
  if (!accountId) {
11738
11843
  console.error('[graph-page] labels-in-graph-rejected reason="no account for session"');
11739
11844
  return c.json({ error: "Account not found for session" }, 401);
@@ -11797,14 +11902,14 @@ var LABELS_IN_GRAPH_CYPHER = `
11797
11902
  sum(halfEdges) AS relDegree
11798
11903
  RETURN label, nodeCount, relDegree
11799
11904
  `;
11800
- var graph_labels_in_graph_default = app28;
11905
+ var graph_labels_in_graph_default = app29;
11801
11906
 
11802
11907
  // server/routes/admin/graph-default-view.ts
11803
- var app29 = new Hono();
11804
- app29.get("/", requireAdminSession, async (c) => {
11805
- const sessionKey = c.var.sessionKey;
11806
- const accountId = getAccountIdForSession(sessionKey);
11807
- const userId = getUserIdForSession(sessionKey);
11908
+ var app30 = new Hono();
11909
+ app30.get("/", requireAdminSession, async (c) => {
11910
+ const cacheKey = c.var.cacheKey;
11911
+ const accountId = getAccountIdForSession(cacheKey);
11912
+ const userId = getUserIdForSession(cacheKey);
11808
11913
  if (!accountId || !userId) {
11809
11914
  console.error('[graph-page] default-view-rejected reason="missing account or user context"');
11810
11915
  return c.json({ error: "Account and user context required for default view" }, 401);
@@ -11839,10 +11944,10 @@ app29.get("/", requireAdminSession, async (c) => {
11839
11944
  }
11840
11945
  }
11841
11946
  });
11842
- app29.put("/", requireAdminSession, async (c) => {
11843
- const sessionKey = c.var.sessionKey;
11844
- const accountId = getAccountIdForSession(sessionKey);
11845
- const userId = getUserIdForSession(sessionKey);
11947
+ app30.put("/", requireAdminSession, async (c) => {
11948
+ const cacheKey = c.var.cacheKey;
11949
+ const accountId = getAccountIdForSession(cacheKey);
11950
+ const userId = getUserIdForSession(cacheKey);
11846
11951
  if (!accountId || !userId) {
11847
11952
  console.error('[graph-page] default-view-rejected reason="missing account or user context"');
11848
11953
  return c.json({ error: "Account and user context required for default view" }, 401);
@@ -11928,11 +12033,11 @@ var WRITE_CYPHER = `
11928
12033
  p.updatedAt = $updatedAt
11929
12034
  RETURN p.labels AS labels
11930
12035
  `;
11931
- var graph_default_view_default = app29;
12036
+ var graph_default_view_default = app30;
11932
12037
 
11933
12038
  // server/routes/admin/file-attach.ts
11934
- var app30 = new Hono();
11935
- app30.post("/", async (c) => {
12039
+ var app31 = new Hono();
12040
+ app31.post("/", async (c) => {
11936
12041
  try {
11937
12042
  const body = await c.req.json();
11938
12043
  const { filePath, accountId } = body;
@@ -11955,11 +12060,11 @@ app30.post("/", async (c) => {
11955
12060
  return c.json({ error: message }, 500);
11956
12061
  }
11957
12062
  });
11958
- var file_attach_default = app30;
12063
+ var file_attach_default = app31;
11959
12064
 
11960
12065
  // server/routes/admin/adherence.ts
11961
- var app31 = new Hono();
11962
- app31.get("/", requireAdminSession, async (c) => {
12066
+ var app32 = new Hono();
12067
+ app32.get("/", requireAdminSession, async (c) => {
11963
12068
  const agent = c.req.query("agent") ?? "admin";
11964
12069
  const includeBlock = c.req.query("block") === "1";
11965
12070
  const account = resolveAccount();
@@ -11980,7 +12085,7 @@ app31.get("/", requireAdminSession, async (c) => {
11980
12085
  return c.json({ error: "Failed to read adherence ledger", agent }, 500);
11981
12086
  }
11982
12087
  });
11983
- var adherence_default = app31;
12088
+ var adherence_default = app32;
11984
12089
 
11985
12090
  // server/routes/admin/sidebar-artefacts.ts
11986
12091
  import neo4j3 from "neo4j-driver";
@@ -11990,10 +12095,10 @@ import { existsSync as existsSync18 } from "fs";
11990
12095
  var LIMIT = 50;
11991
12096
  var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
11992
12097
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
11993
- var app32 = new Hono();
11994
- app32.get("/", requireAdminSession, async (c) => {
11995
- const sessionKey = c.var.sessionKey;
11996
- const accountId = getAccountIdForSession(sessionKey);
12098
+ var app33 = new Hono();
12099
+ app33.get("/", requireAdminSession, async (c) => {
12100
+ const cacheKey = c.var.cacheKey;
12101
+ const accountId = getAccountIdForSession(cacheKey);
11997
12102
  if (!accountId) {
11998
12103
  return c.json({ error: "Account not found for session" }, 401);
11999
12104
  }
@@ -12197,18 +12302,18 @@ function isWithin(target, root) {
12197
12302
  const rel = relative2(root, target);
12198
12303
  return !rel.startsWith("..") && !isAbsolute(rel);
12199
12304
  }
12200
- var sidebar_artefacts_default = app32;
12305
+ var sidebar_artefacts_default = app33;
12201
12306
 
12202
12307
  // server/routes/admin/sidebar-artefact-save.ts
12203
12308
  import { mkdir as mkdir3, readdir as readdir4, stat as stat5, writeFile as writeFile4 } from "fs/promises";
12204
12309
  import { resolve as resolve17 } from "path";
12205
12310
  import { existsSync as existsSync19 } from "fs";
12206
12311
  var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
12207
- var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12208
- var app33 = new Hono();
12209
- app33.post("/", requireAdminSession, async (c) => {
12210
- const sessionKey = c.var.sessionKey;
12211
- const accountId = getAccountIdForSession(sessionKey);
12312
+ var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12313
+ var app34 = new Hono();
12314
+ app34.post("/", requireAdminSession, async (c) => {
12315
+ const cacheKey = c.var.cacheKey;
12316
+ const accountId = getAccountIdForSession(cacheKey);
12212
12317
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
12213
12318
  const body = await safeJson(c);
12214
12319
  if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
@@ -12264,7 +12369,7 @@ async function resolveSavePath(id, accountId, accountDir) {
12264
12369
  }
12265
12370
  return { kind: "admin-template", path: resolve17(parent, filename) };
12266
12371
  }
12267
- if (UUID_RE5.test(id)) {
12372
+ if (UUID_RE6.test(id)) {
12268
12373
  const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
12269
12374
  if (!existsSync19(dir)) {
12270
12375
  return { kind: "reject", status: 400, reason: "not-found" };
@@ -12286,20 +12391,20 @@ async function resolveSavePath(id, accountId, accountDir) {
12286
12391
  function relPath(absPath, root) {
12287
12392
  return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
12288
12393
  }
12289
- var sidebar_artefact_save_default = app33;
12394
+ var sidebar_artefact_save_default = app34;
12290
12395
 
12291
12396
  // server/routes/admin/sidebar-artefact-content.ts
12292
12397
  import { readFile as readFile5, readdir as readdir5 } from "fs/promises";
12293
12398
  import { existsSync as existsSync20 } from "fs";
12294
12399
  import { resolve as resolve18 } from "path";
12295
- var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12296
- var app34 = new Hono();
12297
- app34.get("/", requireAdminSession, async (c) => {
12298
- const sessionKey = c.var.sessionKey;
12299
- const accountId = getAccountIdForSession(sessionKey);
12400
+ var UUID_RE7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12401
+ var app35 = new Hono();
12402
+ app35.get("/", requireAdminSession, async (c) => {
12403
+ const cacheKey = c.var.cacheKey;
12404
+ const accountId = getAccountIdForSession(cacheKey);
12300
12405
  if (!accountId) return new Response("Unauthorized", { status: 401 });
12301
12406
  const id = c.req.query("id") ?? "";
12302
- if (!UUID_RE6.test(id)) {
12407
+ if (!UUID_RE7.test(id)) {
12303
12408
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12304
12409
  return new Response("Not found", { status: 404 });
12305
12410
  }
@@ -12335,7 +12440,7 @@ app34.get("/", requireAdminSession, async (c) => {
12335
12440
  }
12336
12441
  });
12337
12442
  });
12338
- var sidebar_artefact_content_default = app34;
12443
+ var sidebar_artefact_content_default = app35;
12339
12444
 
12340
12445
  // server/routes/admin/health.ts
12341
12446
  import { existsSync as existsSync21, readFileSync as readFileSync16 } from "fs";
@@ -12380,8 +12485,8 @@ async function probeConversationDb() {
12380
12485
  });
12381
12486
  }
12382
12487
  }
12383
- var app35 = new Hono();
12384
- app35.get("/", async (c) => {
12488
+ var app36 = new Hono();
12489
+ app36.get("/", async (c) => {
12385
12490
  const version = readVersion();
12386
12491
  const probe = await probeConversationDb();
12387
12492
  const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
@@ -12403,37 +12508,38 @@ app35.get("/", async (c) => {
12403
12508
  uptimeMs
12404
12509
  });
12405
12510
  });
12406
- var health_default2 = app35;
12511
+ var health_default2 = app36;
12407
12512
 
12408
12513
  // server/routes/admin/index.ts
12409
- var app36 = new Hono();
12410
- app36.route("/session", session_default2);
12411
- app36.route("/chat", chat_default2);
12412
- app36.route("/compact", compact_default);
12413
- app36.route("/logs", logs_default);
12414
- app36.route("/claude-info", claude_info_default);
12415
- app36.route("/attachment", attachment_default);
12416
- app36.route("/agents", agents_default);
12417
- app36.route("/sessions", sessions_default);
12418
- app36.route("/browser", browser_default);
12419
- app36.route("/browser-iframe", browser_iframe_default);
12420
- app36.route("/device-browser", device_browser_default);
12421
- app36.route("/events", events_default);
12422
- app36.route("/cloudflare", cloudflare_default);
12423
- app36.route("/files", files_default);
12424
- app36.route("/graph-search", graph_search_default);
12425
- app36.route("/graph-subgraph", graph_subgraph_default);
12426
- app36.route("/graph-delete", graph_delete_default);
12427
- app36.route("/graph-restore", graph_restore_default);
12428
- app36.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12429
- app36.route("/graph-default-view", graph_default_view_default);
12430
- app36.route("/file-attach", file_attach_default);
12431
- app36.route("/adherence", adherence_default);
12432
- app36.route("/sidebar-artefacts", sidebar_artefacts_default);
12433
- app36.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12434
- app36.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12435
- app36.route("/health-brand", health_default2);
12436
- var admin_default = app36;
12514
+ var app37 = new Hono();
12515
+ app37.route("/session", session_default2);
12516
+ app37.route("/chat", chat_default2);
12517
+ app37.route("/chat-failure", chat_failure_default);
12518
+ app37.route("/compact", compact_default);
12519
+ app37.route("/logs", logs_default);
12520
+ app37.route("/claude-info", claude_info_default);
12521
+ app37.route("/attachment", attachment_default);
12522
+ app37.route("/agents", agents_default);
12523
+ app37.route("/sessions", sessions_default);
12524
+ app37.route("/browser", browser_default);
12525
+ app37.route("/browser-iframe", browser_iframe_default);
12526
+ app37.route("/device-browser", device_browser_default);
12527
+ app37.route("/events", events_default);
12528
+ app37.route("/cloudflare", cloudflare_default);
12529
+ app37.route("/files", files_default);
12530
+ app37.route("/graph-search", graph_search_default);
12531
+ app37.route("/graph-subgraph", graph_subgraph_default);
12532
+ app37.route("/graph-delete", graph_delete_default);
12533
+ app37.route("/graph-restore", graph_restore_default);
12534
+ app37.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12535
+ app37.route("/graph-default-view", graph_default_view_default);
12536
+ app37.route("/file-attach", file_attach_default);
12537
+ app37.route("/adherence", adherence_default);
12538
+ app37.route("/sidebar-artefacts", sidebar_artefacts_default);
12539
+ app37.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12540
+ app37.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12541
+ app37.route("/health-brand", health_default2);
12542
+ var admin_default = app37;
12437
12543
 
12438
12544
  // server/routes/sites.ts
12439
12545
  import { existsSync as existsSync22, readFileSync as readFileSync17, realpathSync as realpathSync4, statSync as statSync7 } from "fs";
@@ -12468,8 +12574,8 @@ function getExt(p) {
12468
12574
  if (idx < p.lastIndexOf("/")) return "";
12469
12575
  return p.slice(idx).toLowerCase();
12470
12576
  }
12471
- var app37 = new Hono();
12472
- app37.get("/:rel{.*}", (c) => {
12577
+ var app38 = new Hono();
12578
+ app38.get("/:rel{.*}", (c) => {
12473
12579
  const reqPath = c.req.path;
12474
12580
  const rawRel = c.req.param("rel") ?? "";
12475
12581
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -12572,7 +12678,7 @@ app37.get("/:rel{.*}", (c) => {
12572
12678
  "X-Content-Type-Options": "nosniff"
12573
12679
  });
12574
12680
  });
12575
- var sites_default = app37;
12681
+ var sites_default = app38;
12576
12682
 
12577
12683
  // app/lib/graph-health.ts
12578
12684
  var HOUR_MS = 60 * 60 * 1e3;
@@ -12726,9 +12832,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
12726
12832
  function isPublicHost(host) {
12727
12833
  return host.startsWith("public.") || aliasDomains.has(host);
12728
12834
  }
12729
- var app38 = new Hono();
12730
- app38.use("*", clientIpMiddleware);
12731
- app38.use("*", async (c, next) => {
12835
+ var app39 = new Hono();
12836
+ app39.use("*", clientIpMiddleware);
12837
+ app39.use("*", async (c, next) => {
12732
12838
  await next();
12733
12839
  c.header("X-Content-Type-Options", "nosniff");
12734
12840
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -12738,7 +12844,7 @@ app38.use("*", async (c, next) => {
12738
12844
  );
12739
12845
  });
12740
12846
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
12741
- app38.use("*", async (c, next) => {
12847
+ app39.use("*", async (c, next) => {
12742
12848
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
12743
12849
  await next();
12744
12850
  return;
@@ -12771,7 +12877,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
12771
12877
  "/sites/"
12772
12878
  ];
12773
12879
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
12774
- app38.use("*", async (c, next) => {
12880
+ app39.use("*", async (c, next) => {
12775
12881
  const host = (c.req.header("host") ?? "").split(":")[0];
12776
12882
  if (!isPublicHost(host)) {
12777
12883
  await next();
@@ -12811,7 +12917,7 @@ function resolveRemoteAuthOpts() {
12811
12917
  return brandLoginOpts;
12812
12918
  }
12813
12919
  var MAX_LOGIN_BODY = 8 * 1024;
12814
- app38.post("/__remote-auth/login", async (c) => {
12920
+ app39.post("/__remote-auth/login", async (c) => {
12815
12921
  const client = clientFrom(c);
12816
12922
  const clientIp = client.ip || "unknown";
12817
12923
  if (!requestIsTlsTerminated(c)) {
@@ -12856,7 +12962,7 @@ app38.post("/__remote-auth/login", async (c) => {
12856
12962
  }
12857
12963
  });
12858
12964
  });
12859
- app38.get("/__remote-auth/logout", (c) => {
12965
+ app39.get("/__remote-auth/logout", (c) => {
12860
12966
  const client = clientFrom(c);
12861
12967
  const clientIp = client.ip || "unknown";
12862
12968
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -12869,7 +12975,7 @@ app38.get("/__remote-auth/logout", (c) => {
12869
12975
  }
12870
12976
  });
12871
12977
  });
12872
- app38.post("/__remote-auth/change-password", async (c) => {
12978
+ app39.post("/__remote-auth/change-password", async (c) => {
12873
12979
  const client = clientFrom(c);
12874
12980
  const clientIp = client.ip || "unknown";
12875
12981
  const rateLimited = checkRateLimit(client);
@@ -12920,13 +13026,13 @@ app38.post("/__remote-auth/change-password", async (c) => {
12920
13026
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
12921
13027
  }
12922
13028
  });
12923
- app38.get("/__remote-auth/setup", (c) => {
13029
+ app39.get("/__remote-auth/setup", (c) => {
12924
13030
  if (isRemoteAuthConfigured()) {
12925
13031
  return c.redirect("/");
12926
13032
  }
12927
13033
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
12928
13034
  });
12929
- app38.post("/__remote-auth/set-initial-password", async (c) => {
13035
+ app39.post("/__remote-auth/set-initial-password", async (c) => {
12930
13036
  if (isRemoteAuthConfigured()) {
12931
13037
  return c.redirect("/");
12932
13038
  }
@@ -12964,10 +13070,10 @@ app38.post("/__remote-auth/set-initial-password", async (c) => {
12964
13070
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
12965
13071
  }
12966
13072
  });
12967
- app38.get("/api/remote-auth/status", (c) => {
13073
+ app39.get("/api/remote-auth/status", (c) => {
12968
13074
  return c.json({ configured: isRemoteAuthConfigured() });
12969
13075
  });
12970
- app38.post("/api/remote-auth/set-password", async (c) => {
13076
+ app39.post("/api/remote-auth/set-password", async (c) => {
12971
13077
  let body;
12972
13078
  try {
12973
13079
  body = await c.req.json();
@@ -12997,9 +13103,9 @@ app38.post("/api/remote-auth/set-password", async (c) => {
12997
13103
  return c.json({ error: "Failed to save password" }, 500);
12998
13104
  }
12999
13105
  });
13000
- app38.route("/api/_client-error", client_error_default);
13106
+ app39.route("/api/_client-error", client_error_default);
13001
13107
  console.log("[client-error-route] mounted");
13002
- app38.use("*", async (c, next) => {
13108
+ app39.use("*", async (c, next) => {
13003
13109
  const host = (c.req.header("host") ?? "").split(":")[0];
13004
13110
  const path2 = c.req.path;
13005
13111
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -13039,15 +13145,15 @@ app38.use("*", async (c, next) => {
13039
13145
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
13040
13146
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
13041
13147
  });
13042
- app38.route("/api/health", health_default);
13043
- app38.route("/api/session", session_default);
13044
- app38.route("/api/chat", chat_default);
13045
- app38.route("/api/group", group_default);
13046
- app38.route("/api/access", access_default);
13047
- app38.route("/api/telegram", telegram_default);
13048
- app38.route("/api/whatsapp", whatsapp_default);
13049
- app38.route("/api/onboarding", onboarding_default);
13050
- app38.route("/api/admin", admin_default);
13148
+ app39.route("/api/health", health_default);
13149
+ app39.route("/api/session", session_default);
13150
+ app39.route("/api/chat", chat_default);
13151
+ app39.route("/api/group", group_default);
13152
+ app39.route("/api/access", access_default);
13153
+ app39.route("/api/telegram", telegram_default);
13154
+ app39.route("/api/whatsapp", whatsapp_default);
13155
+ app39.route("/api/onboarding", onboarding_default);
13156
+ app39.route("/api/admin", admin_default);
13051
13157
  var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
13052
13158
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
13053
13159
  var IMAGE_MIME = {
@@ -13059,7 +13165,7 @@ var IMAGE_MIME = {
13059
13165
  ".svg": "image/svg+xml",
13060
13166
  ".ico": "image/x-icon"
13061
13167
  };
13062
- app38.get("/agent-assets/:slug/:filename", (c) => {
13168
+ app39.get("/agent-assets/:slug/:filename", (c) => {
13063
13169
  const slug = c.req.param("slug");
13064
13170
  const filename = c.req.param("filename");
13065
13171
  if (!SAFE_SLUG_RE.test(slug)) {
@@ -13094,7 +13200,7 @@ app38.get("/agent-assets/:slug/:filename", (c) => {
13094
13200
  "Cache-Control": "public, max-age=3600"
13095
13201
  });
13096
13202
  });
13097
- app38.get("/generated/:filename", (c) => {
13203
+ app39.get("/generated/:filename", (c) => {
13098
13204
  const filename = c.req.param("filename");
13099
13205
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
13100
13206
  console.error(`[generated] serve file=${filename} status=403`);
@@ -13124,7 +13230,7 @@ app38.get("/generated/:filename", (c) => {
13124
13230
  "Cache-Control": "public, max-age=86400"
13125
13231
  });
13126
13232
  });
13127
- app38.route("/sites", sites_default);
13233
+ app39.route("/sites", sites_default);
13128
13234
  var htmlCache = /* @__PURE__ */ new Map();
13129
13235
  var brandLogoPath = "/brand/maxy-monochrome.png";
13130
13236
  var brandIconPath = "/brand/maxy-monochrome.png";
@@ -13261,7 +13367,7 @@ function brandedPublicHtml(agentSlug) {
13261
13367
  function escapeHtml(s) {
13262
13368
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
13263
13369
  }
13264
- app38.get("/", (c) => {
13370
+ app39.get("/", (c) => {
13265
13371
  const host = (c.req.header("host") ?? "").split(":")[0];
13266
13372
  if (isPublicHost(host)) {
13267
13373
  const defaultSlug = resolveDefaultSlug();
@@ -13269,12 +13375,12 @@ app38.get("/", (c) => {
13269
13375
  }
13270
13376
  return c.html(cachedHtml("index.html"));
13271
13377
  });
13272
- app38.get("/public", (c) => {
13378
+ app39.get("/public", (c) => {
13273
13379
  const host = (c.req.header("host") ?? "").split(":")[0];
13274
13380
  if (isPublicHost(host)) return c.text("Not found", 404);
13275
13381
  return c.html(cachedHtml("public.html"));
13276
13382
  });
13277
- app38.get("/chat", (c) => {
13383
+ app39.get("/chat", (c) => {
13278
13384
  const host = (c.req.header("host") ?? "").split(":")[0];
13279
13385
  if (isPublicHost(host)) return c.text("Not found", 404);
13280
13386
  return c.html(cachedHtml("public.html"));
@@ -13293,9 +13399,9 @@ async function logViewerFetch(c, next) {
13293
13399
  duration_ms: Date.now() - start
13294
13400
  });
13295
13401
  }
13296
- app38.use("/vnc-viewer.html", logViewerFetch);
13297
- app38.use("/vnc-popout.html", logViewerFetch);
13298
- app38.get("/vnc-popout.html", (c) => {
13402
+ app39.use("/vnc-viewer.html", logViewerFetch);
13403
+ app39.use("/vnc-popout.html", logViewerFetch);
13404
+ app39.get("/vnc-popout.html", (c) => {
13299
13405
  let html = htmlCache.get("vnc-popout.html");
13300
13406
  if (!html) {
13301
13407
  html = readFileSync18(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
@@ -13308,7 +13414,7 @@ app38.get("/vnc-popout.html", (c) => {
13308
13414
  }
13309
13415
  return c.html(html);
13310
13416
  });
13311
- app38.post("/api/vnc/client-event", async (c) => {
13417
+ app39.post("/api/vnc/client-event", async (c) => {
13312
13418
  let body;
13313
13419
  try {
13314
13420
  body = await c.req.json();
@@ -13329,20 +13435,20 @@ app38.post("/api/vnc/client-event", async (c) => {
13329
13435
  });
13330
13436
  return c.json({ ok: true });
13331
13437
  });
13332
- app38.get("/g/:slug", (c) => {
13438
+ app39.get("/g/:slug", (c) => {
13333
13439
  return c.html(brandedPublicHtml());
13334
13440
  });
13335
- app38.get("/graph", (c) => {
13441
+ app39.get("/graph", (c) => {
13336
13442
  const host = (c.req.header("host") ?? "").split(":")[0];
13337
13443
  if (isPublicHost(host)) return c.text("Not found", 404);
13338
13444
  return c.html(cachedHtml("graph.html"));
13339
13445
  });
13340
- app38.get("/data", (c) => {
13446
+ app39.get("/data", (c) => {
13341
13447
  const host = (c.req.header("host") ?? "").split(":")[0];
13342
13448
  if (isPublicHost(host)) return c.text("Not found", 404);
13343
13449
  return c.html(cachedHtml("data.html"));
13344
13450
  });
13345
- app38.get("/:slug", async (c, next) => {
13451
+ app39.get("/:slug", async (c, next) => {
13346
13452
  const slug = c.req.param("slug");
13347
13453
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
13348
13454
  const branding = loadBrandingCache(slug);
@@ -13352,15 +13458,15 @@ app38.get("/:slug", async (c, next) => {
13352
13458
  await next();
13353
13459
  });
13354
13460
  if (brandFaviconPath !== "/favicon.ico") {
13355
- app38.get("/favicon.ico", (c) => {
13461
+ app39.get("/favicon.ico", (c) => {
13356
13462
  c.header("Cache-Control", "public, max-age=300");
13357
13463
  return c.redirect(brandFaviconPath, 302);
13358
13464
  });
13359
13465
  }
13360
- app38.use("/*", serveStatic({ root: "./public" }));
13466
+ app39.use("/*", serveStatic({ root: "./public" }));
13361
13467
  var port = parseInt(process.env.MAXY_UI_INTERNAL_PORT ?? process.env.PORT ?? "19199", 10);
13362
13468
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
13363
- var httpServer = serve({ fetch: app38.fetch, port, hostname });
13469
+ var httpServer = serve({ fetch: app39.fetch, port, hostname });
13364
13470
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
13365
13471
  console.log("[boot] auth-mode summary: oauth=8 api-key=1 (api-key consumer: invokePublicAgent only)");
13366
13472
  var SUBAPP_MANIFEST = [
@@ -13381,7 +13487,7 @@ for (const m of SUBAPP_MANIFEST) {
13381
13487
  }
13382
13488
  try {
13383
13489
  const registered = [];
13384
- for (const r of app38.routes ?? []) {
13490
+ for (const r of app39.routes ?? []) {
13385
13491
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
13386
13492
  if (AGENT_SLUG_PATTERN.test(r.path)) {
13387
13493
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -13413,6 +13519,13 @@ try {
13413
13519
  console.error(`[session] backfill startup failed: ${err instanceof Error ? err.message : String(err)}`);
13414
13520
  }
13415
13521
  })();
13522
+ (async () => {
13523
+ try {
13524
+ await backfillConversationChannelAddress();
13525
+ } catch (err) {
13526
+ console.error(`[session-985] channelAddress backfill startup failed: ${err instanceof Error ? err.message : String(err)}`);
13527
+ }
13528
+ })();
13416
13529
  (async () => {
13417
13530
  try {
13418
13531
  if (!existsSync23(USERS_FILE)) return;
@@ -13467,15 +13580,14 @@ autoDeliverPremiumPlugins(bootEntitlement?.purchasedPlugins ?? void 0);
13467
13580
  (async () => {
13468
13581
  if (!bootAccount) return;
13469
13582
  try {
13470
- const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-OCFIVXEJ.js");
13583
+ const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-B6FXP3HI.js");
13471
13584
  const result = await recoverRunningCloudflareTasks(
13472
13585
  bootAccount.accountId,
13473
13586
  configDirForWhatsApp,
13474
- // No conversationKey at boot the tracker's writeNodeWithEdges path
13475
- // requires it for the Conversation join, but the recovery path is
13476
- // operating on Tasks whose Conversation is already linked. Pass null
13477
- // and let the tracker pick up the linked Conversation via the Task's
13478
- // existing edge.
13587
+ // Task 985 — no conversationId at boot. The reconciler operates on
13588
+ // Tasks whose Conversation is already linked via RAISED_DURING; the
13589
+ // tracker resolves the conversationId off that edge when present.
13590
+ // Pass null and let the recovery path pick it up.
13479
13591
  null
13480
13592
  );
13481
13593
  if (result.scanned > 0) {
@@ -13557,10 +13669,10 @@ init({
13557
13669
  agentName = resolved.slug;
13558
13670
  }
13559
13671
  let enrichedText = msg.text || msg.mediaPath || msg.mediaType || msg.replyContext ? buildEnrichedText2(msg.text ?? "") : "";
13560
- if (msg.sessionKey) {
13672
+ if (msg.cacheKey) {
13561
13673
  const platformAccountId = bootAccount?.accountId ?? msg.accountId;
13562
- registerSession(msg.sessionKey, msg.agentType, platformAccountId, agentName);
13563
- console.error(`[session] channel session registered: sessionKey=${msg.sessionKey.slice(0, 12)}\u2026 channel=whatsapp accountId=${platformAccountId.slice(0, 8)}\u2026`);
13674
+ registerSession(msg.cacheKey, msg.agentType, platformAccountId, agentName);
13675
+ console.error(`[session] channel session registered: cacheKey=${msg.cacheKey.slice(0, 12)}\u2026 channel=whatsapp accountId=${platformAccountId.slice(0, 8)}\u2026`);
13564
13676
  }
13565
13677
  let gatewayResult;
13566
13678
  if (msg.text) {
@@ -13584,7 +13696,7 @@ init({
13584
13696
  for await (const event of invokeAgent(
13585
13697
  { type: msg.agentType, agentName },
13586
13698
  enrichedText,
13587
- msg.sessionKey,
13699
+ msg.cacheKey,
13588
13700
  [],
13589
13701
  void 0,
13590
13702
  gatewayResult
@@ -13602,7 +13714,7 @@ init({
13602
13714
  for await (const event of invokeAgent(
13603
13715
  { type: msg.agentType, agentName },
13604
13716
  enrichedText,
13605
- msg.sessionKey,
13717
+ msg.cacheKey,
13606
13718
  [],
13607
13719
  void 0,
13608
13720
  gatewayResult