@rubytech/create-maxy-code 0.1.570 → 0.1.571
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +38 -13
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +20 -7
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +38 -4
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/{AdminLoginScreens-5gI137xF.js → AdminLoginScreens-CKyVm5aW.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-CKyVm5aW.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-CKyVm5aW.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-Bfapavlp.js → AdminShell-slZzNEDR.js} +1 -1
- package/payload/server/public/assets/AdminShell-slZzNEDR.js.br +0 -0
- package/payload/server/public/assets/AdminShell-slZzNEDR.js.gz +0 -0
- package/payload/server/public/assets/{activity-DnbsmUgn.js → activity-6DhWjVwg.js} +1 -1
- package/payload/server/public/assets/activity-6DhWjVwg.js.br +0 -0
- package/payload/server/public/assets/activity-6DhWjVwg.js.gz +0 -0
- package/payload/server/public/assets/{admin-BXIv0_oj.js → admin-BB8DoIb_.js} +1 -1
- package/payload/server/public/assets/admin-BB8DoIb_.js.br +0 -0
- package/payload/server/public/assets/admin-BB8DoIb_.js.gz +0 -0
- package/payload/server/public/assets/{agents-Dl2wOcpj.js → agents-D-28pUk7.js} +1 -1
- package/payload/server/public/assets/agents-D-28pUk7.js.br +0 -0
- package/payload/server/public/assets/agents-D-28pUk7.js.gz +0 -0
- package/payload/server/public/assets/{browser-D-Uc9ewO.js → browser-BGJPx931.js} +1 -1
- package/payload/server/public/assets/browser-BGJPx931.js.br +0 -0
- package/payload/server/public/assets/browser-BGJPx931.js.gz +0 -0
- package/payload/server/public/assets/{calendar-Cu3O6Bay.js → calendar-CP7u15G9.js} +1 -1
- package/payload/server/public/assets/calendar-CP7u15G9.js.br +0 -0
- package/payload/server/public/assets/calendar-CP7u15G9.js.gz +0 -0
- package/payload/server/public/assets/chat-C0wgXTz3.js +1 -0
- package/payload/server/public/assets/chat-C0wgXTz3.js.br +0 -0
- package/payload/server/public/assets/chat-C0wgXTz3.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-CKe1u6eC.js +1 -0
- package/payload/server/public/assets/chevron-left-CKe1u6eC.js.br +0 -0
- package/payload/server/public/assets/clock-D8MegkDy.js +1 -0
- package/payload/server/public/assets/clock-D8MegkDy.js.br +0 -0
- package/payload/server/public/assets/{copy-DPBVV8KZ.js → copy-Cu819JFC.js} +1 -1
- package/payload/server/public/assets/copy-Cu819JFC.js.br +0 -0
- package/payload/server/public/assets/copy-Cu819JFC.js.gz +0 -0
- package/payload/server/public/assets/data-B7W5Ocvt.js +1 -0
- package/payload/server/public/assets/data-B7W5Ocvt.js.br +0 -0
- package/payload/server/public/assets/data-B7W5Ocvt.js.gz +0 -0
- package/payload/server/public/assets/{file-text-Dn82O6ke.js → file-text-BoiZDy84.js} +1 -1
- package/payload/server/public/assets/file-text-BoiZDy84.js.br +0 -0
- package/payload/server/public/assets/file-text-BoiZDy84.js.gz +0 -0
- package/payload/server/public/assets/{graph-D2J7a7Ll.js → graph-Dr6uIMgA.js} +1 -1
- package/payload/server/public/assets/graph-Dr6uIMgA.js.br +0 -0
- package/payload/server/public/assets/graph-Dr6uIMgA.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-D3gkY2IH.js → graph-labels-9y5-8Rc_.js} +1 -1
- package/payload/server/public/assets/graph-labels-9y5-8Rc_.js.br +0 -0
- package/payload/server/public/assets/graph-labels-9y5-8Rc_.js.gz +0 -0
- package/payload/server/public/assets/{operator-Bz_yj1im.js → operator-Cn5P5yqu.js} +1 -1
- package/payload/server/public/assets/operator-Cn5P5yqu.js.br +0 -0
- package/payload/server/public/assets/operator-Cn5P5yqu.js.gz +0 -0
- package/payload/server/public/assets/{page-D6u2xYh7.js → page-DqnWu9Aj.js} +1 -1
- package/payload/server/public/assets/page-DqnWu9Aj.js.br +0 -0
- package/payload/server/public/assets/page-DqnWu9Aj.js.gz +0 -0
- package/payload/server/public/assets/{page-mH4nyQ75.js → page-VTcDQ8qS.js} +1 -1
- package/payload/server/public/assets/page-VTcDQ8qS.js.br +0 -0
- package/payload/server/public/assets/page-VTcDQ8qS.js.gz +0 -0
- package/payload/server/public/assets/play-Dp6K3szP.js +1 -0
- package/payload/server/public/assets/play-Dp6K3szP.js.br +0 -0
- package/payload/server/public/assets/play-Dp6K3szP.js.gz +0 -0
- package/payload/server/public/assets/{public-CtoYVjPR.js → public-HlWIQCkl.js} +1 -1
- package/payload/server/public/assets/public-HlWIQCkl.js.br +0 -0
- package/payload/server/public/assets/public-HlWIQCkl.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-BXoIghE3.js → rotate-ccw-kpEqIj4T.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-kpEqIj4T.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-kpEqIj4T.js.gz +0 -0
- package/payload/server/public/assets/{routines-DXleYpDv.js → routines-CvDzjwtZ.js} +1 -1
- package/payload/server/public/assets/routines-CvDzjwtZ.js.br +0 -0
- package/payload/server/public/assets/routines-CvDzjwtZ.js.gz +0 -0
- package/payload/server/public/assets/{skills-CMl38MKH.js → skills-Bom76JQv.js} +1 -1
- package/payload/server/public/assets/skills-Bom76JQv.js.br +0 -0
- package/payload/server/public/assets/skills-Bom76JQv.js.gz +0 -0
- package/payload/server/public/assets/{tasks-Cshaf0Md.js → tasks-DCiTDQ-r.js} +1 -1
- package/payload/server/public/assets/tasks-DCiTDQ-r.js.br +0 -0
- package/payload/server/public/assets/tasks-DCiTDQ-r.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-CS-NXr_9.js → triangle-alert-DBSoNN4T.js} +1 -1
- package/payload/server/public/assets/triangle-alert-DBSoNN4T.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-DBSoNN4T.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-pKLfQJNG.js → useCopyFeedback-Do4uNxoZ.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-Do4uNxoZ.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-Do4uNxoZ.js.gz +0 -0
- package/payload/server/public/assets/{useMediaQuery-BHFn0-S9.css → useMediaQuery-BbG7Ar0P.css} +1 -1
- package/payload/server/public/assets/useMediaQuery-BbG7Ar0P.css.br +0 -0
- package/payload/server/public/assets/{useMediaQuery-BHFn0-S9.css.gz → useMediaQuery-BbG7Ar0P.css.gz} +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BzezRxgT.js +2 -0
- package/payload/server/public/assets/useVoiceRecorder-BzezRxgT.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BzezRxgT.js.gz +0 -0
- package/payload/server/public/assets/{wrench-czES9Rdy.js → wrench-BmLFQPJb.js} +1 -1
- package/payload/server/public/assets/wrench-BmLFQPJb.js.br +0 -0
- package/payload/server/public/assets/wrench-BmLFQPJb.js.gz +0 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +7 -7
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +13 -13
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +7 -7
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +739 -469
- package/payload/server/public/assets/AdminLoginScreens-5gI137xF.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-5gI137xF.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-Bfapavlp.js.br +0 -0
- package/payload/server/public/assets/AdminShell-Bfapavlp.js.gz +0 -0
- package/payload/server/public/assets/activity-DnbsmUgn.js.br +0 -0
- package/payload/server/public/assets/activity-DnbsmUgn.js.gz +0 -0
- package/payload/server/public/assets/admin-BXIv0_oj.js.br +0 -0
- package/payload/server/public/assets/admin-BXIv0_oj.js.gz +0 -0
- package/payload/server/public/assets/agents-Dl2wOcpj.js.br +0 -0
- package/payload/server/public/assets/agents-Dl2wOcpj.js.gz +0 -0
- package/payload/server/public/assets/browser-D-Uc9ewO.js.br +0 -0
- package/payload/server/public/assets/browser-D-Uc9ewO.js.gz +0 -0
- package/payload/server/public/assets/calendar-Cu3O6Bay.js.br +0 -0
- package/payload/server/public/assets/calendar-Cu3O6Bay.js.gz +0 -0
- package/payload/server/public/assets/chat-Bso94e-f.js +0 -1
- package/payload/server/public/assets/chat-Bso94e-f.js.br +0 -0
- package/payload/server/public/assets/chat-Bso94e-f.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-CDwfR9V-.js +0 -1
- package/payload/server/public/assets/chevron-left-CDwfR9V-.js.br +0 -0
- package/payload/server/public/assets/clock-DDVrNLt9.js +0 -1
- package/payload/server/public/assets/clock-DDVrNLt9.js.br +0 -0
- package/payload/server/public/assets/clock-DDVrNLt9.js.gz +0 -0
- package/payload/server/public/assets/copy-DPBVV8KZ.js.br +0 -0
- package/payload/server/public/assets/copy-DPBVV8KZ.js.gz +0 -0
- package/payload/server/public/assets/data-Dei8n2EX.js +0 -1
- package/payload/server/public/assets/data-Dei8n2EX.js.br +0 -0
- package/payload/server/public/assets/data-Dei8n2EX.js.gz +0 -0
- package/payload/server/public/assets/file-text-Dn82O6ke.js.br +0 -0
- package/payload/server/public/assets/file-text-Dn82O6ke.js.gz +0 -0
- package/payload/server/public/assets/graph-D2J7a7Ll.js.br +0 -0
- package/payload/server/public/assets/graph-D2J7a7Ll.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-D3gkY2IH.js.br +0 -0
- package/payload/server/public/assets/graph-labels-D3gkY2IH.js.gz +0 -0
- package/payload/server/public/assets/operator-Bz_yj1im.js.br +0 -0
- package/payload/server/public/assets/operator-Bz_yj1im.js.gz +0 -0
- package/payload/server/public/assets/page-D6u2xYh7.js.br +0 -0
- package/payload/server/public/assets/page-D6u2xYh7.js.gz +0 -0
- package/payload/server/public/assets/page-mH4nyQ75.js.br +0 -0
- package/payload/server/public/assets/page-mH4nyQ75.js.gz +0 -0
- package/payload/server/public/assets/play-ByuChQJJ.js +0 -1
- package/payload/server/public/assets/play-ByuChQJJ.js.br +0 -0
- package/payload/server/public/assets/play-ByuChQJJ.js.gz +0 -0
- package/payload/server/public/assets/public-CtoYVjPR.js.br +0 -0
- package/payload/server/public/assets/public-CtoYVjPR.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-BXoIghE3.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-BXoIghE3.js.gz +0 -0
- package/payload/server/public/assets/routines-DXleYpDv.js.br +0 -0
- package/payload/server/public/assets/routines-DXleYpDv.js.gz +0 -0
- package/payload/server/public/assets/skills-CMl38MKH.js.br +0 -0
- package/payload/server/public/assets/skills-CMl38MKH.js.gz +0 -0
- package/payload/server/public/assets/tasks-Cshaf0Md.js.br +0 -0
- package/payload/server/public/assets/tasks-Cshaf0Md.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-CS-NXr_9.js.br +0 -3
- package/payload/server/public/assets/triangle-alert-CS-NXr_9.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-pKLfQJNG.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-pKLfQJNG.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-BHFn0-S9.css.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-EgO1GmIg.js +0 -2
- package/payload/server/public/assets/useVoiceRecorder-EgO1GmIg.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-EgO1GmIg.js.gz +0 -0
- package/payload/server/public/assets/wrench-czES9Rdy.js.br +0 -0
- package/payload/server/public/assets/wrench-czES9Rdy.js.gz +0 -0
- /package/payload/server/public/assets/{useMediaQuery-oDCasnxD.js → useMediaQuery-6vKHR1CS.js} +0 -0
- /package/payload/server/public/assets/{useMediaQuery-oDCasnxD.js.br → useMediaQuery-6vKHR1CS.js.br} +0 -0
- /package/payload/server/public/assets/{useMediaQuery-oDCasnxD.js.gz → useMediaQuery-6vKHR1CS.js.gz} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -4367,7 +4367,7 @@ init_dist();
|
|
|
4367
4367
|
import { readFileSync as readFileSync51, existsSync as existsSync54, watchFile, readdirSync as readdirSync32, statSync as statSync30 } from "fs";
|
|
4368
4368
|
import { spawn as spawn3 } from "child_process";
|
|
4369
4369
|
import { createHash as createHash8 } from "crypto";
|
|
4370
|
-
import { resolve as resolve49, join as
|
|
4370
|
+
import { resolve as resolve49, join as join61, basename as basename17 } from "path";
|
|
4371
4371
|
import { homedir as homedir5 } from "os";
|
|
4372
4372
|
|
|
4373
4373
|
// server/lib/route-cache-watchers.ts
|
|
@@ -6788,6 +6788,9 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6788
6788
|
role: "admin",
|
|
6789
6789
|
personId: null,
|
|
6790
6790
|
text: prompt,
|
|
6791
|
+
// Task 2489 — a scheduled inject carries no inbound file by
|
|
6792
|
+
// construction: there is no message to have attached one.
|
|
6793
|
+
media: [],
|
|
6791
6794
|
source: "schedule",
|
|
6792
6795
|
scheduleProvenance,
|
|
6793
6796
|
reply
|
|
@@ -14961,7 +14964,7 @@ var webchat_greeting_default = app10;
|
|
|
14961
14964
|
init_dist();
|
|
14962
14965
|
init_claude_agent();
|
|
14963
14966
|
import { homedir as homedir3 } from "os";
|
|
14964
|
-
import { resolve as resolve21, join as
|
|
14967
|
+
import { resolve as resolve21, join as join33 } from "path";
|
|
14965
14968
|
import { existsSync as existsSync22, readFileSync as readFileSync27 } from "fs";
|
|
14966
14969
|
|
|
14967
14970
|
// app/lib/telegram/gateway/instance.ts
|
|
@@ -15002,6 +15005,20 @@ function checkTelegramAccess(params) {
|
|
|
15002
15005
|
}
|
|
15003
15006
|
|
|
15004
15007
|
// app/lib/telegram/route-inbound.ts
|
|
15008
|
+
var CONTENT_KEYS = [
|
|
15009
|
+
"photo",
|
|
15010
|
+
"video",
|
|
15011
|
+
"video_note",
|
|
15012
|
+
"voice",
|
|
15013
|
+
"audio",
|
|
15014
|
+
"document",
|
|
15015
|
+
"sticker",
|
|
15016
|
+
"venue",
|
|
15017
|
+
"location",
|
|
15018
|
+
"text",
|
|
15019
|
+
"caption"
|
|
15020
|
+
];
|
|
15021
|
+
var ENVELOPE_KEYS = /* @__PURE__ */ new Set(["message_id", "from", "chat", "date", "edit_date"]);
|
|
15005
15022
|
function telegramSenderDisplay(from) {
|
|
15006
15023
|
const first = from.first_name?.trim() ?? "";
|
|
15007
15024
|
if (first.length > 0) {
|
|
@@ -15012,13 +15029,97 @@ function telegramSenderDisplay(from) {
|
|
|
15012
15029
|
if (handle2.length > 0) return `@${handle2}`;
|
|
15013
15030
|
return String(from.id ?? "");
|
|
15014
15031
|
}
|
|
15032
|
+
function describeTelegramUpdate(update) {
|
|
15033
|
+
const isEdit = update.message == null && update.edited_message != null;
|
|
15034
|
+
const m = update.message ?? update.edited_message;
|
|
15035
|
+
const envelope = update.message != null ? "message" : update.edited_message != null ? "edited_message" : "other";
|
|
15036
|
+
if (!m) return { envelope, contentKeys: [], content: "none", primaryKind: "none", isEdit };
|
|
15037
|
+
let contentKeys = CONTENT_KEYS.filter((k) => m[k] != null);
|
|
15038
|
+
if (contentKeys.length === 0) {
|
|
15039
|
+
contentKeys = Object.keys(m).filter((k) => !ENVELOPE_KEYS.has(k)).sort();
|
|
15040
|
+
}
|
|
15041
|
+
return {
|
|
15042
|
+
envelope,
|
|
15043
|
+
contentKeys,
|
|
15044
|
+
content: contentKeys.length > 0 ? contentKeys.join(",") : "none",
|
|
15045
|
+
primaryKind: contentKeys[0] ?? "none",
|
|
15046
|
+
isEdit
|
|
15047
|
+
};
|
|
15048
|
+
}
|
|
15049
|
+
function fileIds(f) {
|
|
15050
|
+
if (!f || typeof f.file_id !== "string" || typeof f.file_unique_id !== "string") return null;
|
|
15051
|
+
return { fileId: f.file_id, fileUniqueId: f.file_unique_id };
|
|
15052
|
+
}
|
|
15053
|
+
function extractContent(m) {
|
|
15054
|
+
const media = [];
|
|
15055
|
+
let placeholder = null;
|
|
15056
|
+
const note = (s) => {
|
|
15057
|
+
if (placeholder === null) placeholder = s;
|
|
15058
|
+
};
|
|
15059
|
+
const photo = Array.isArray(m.photo) && m.photo.length > 0 ? m.photo[m.photo.length - 1] : void 0;
|
|
15060
|
+
const photoIds = fileIds(photo);
|
|
15061
|
+
if (photoIds) {
|
|
15062
|
+
media.push({ type: "image", ...photoIds, mimetype: "image/jpeg" });
|
|
15063
|
+
note("[photo]");
|
|
15064
|
+
}
|
|
15065
|
+
const videoIds = fileIds(m.video);
|
|
15066
|
+
if (videoIds) {
|
|
15067
|
+
media.push({ type: "video", ...videoIds, ...m.video?.mime_type ? { mimetype: m.video.mime_type } : {} });
|
|
15068
|
+
note("[video]");
|
|
15069
|
+
}
|
|
15070
|
+
const videoNoteIds = fileIds(m.video_note);
|
|
15071
|
+
if (videoNoteIds) {
|
|
15072
|
+
media.push({
|
|
15073
|
+
type: "video",
|
|
15074
|
+
...videoNoteIds,
|
|
15075
|
+
...m.video_note?.mime_type ? { mimetype: m.video_note.mime_type } : {}
|
|
15076
|
+
});
|
|
15077
|
+
note("[video]");
|
|
15078
|
+
}
|
|
15079
|
+
const voiceIds = fileIds(m.voice);
|
|
15080
|
+
if (voiceIds) {
|
|
15081
|
+
media.push({ type: "audio", ...voiceIds, ...m.voice?.mime_type ? { mimetype: m.voice.mime_type } : {} });
|
|
15082
|
+
note("[voice]");
|
|
15083
|
+
}
|
|
15084
|
+
const audioIds = fileIds(m.audio);
|
|
15085
|
+
if (audioIds) {
|
|
15086
|
+
media.push({ type: "audio", ...audioIds, ...m.audio?.mime_type ? { mimetype: m.audio.mime_type } : {} });
|
|
15087
|
+
note("[audio]");
|
|
15088
|
+
}
|
|
15089
|
+
const docIds = fileIds(m.document);
|
|
15090
|
+
if (docIds) {
|
|
15091
|
+
media.push({
|
|
15092
|
+
type: "document",
|
|
15093
|
+
...docIds,
|
|
15094
|
+
...m.document?.mime_type ? { mimetype: m.document.mime_type } : {},
|
|
15095
|
+
...m.document?.file_name ? { fileName: m.document.file_name } : {}
|
|
15096
|
+
});
|
|
15097
|
+
note(`[document: ${m.document?.file_name ?? "file"}]`);
|
|
15098
|
+
}
|
|
15099
|
+
if (m.sticker) note("[sticker]");
|
|
15100
|
+
if (m.venue) {
|
|
15101
|
+
const v = m.venue;
|
|
15102
|
+
const parts = [v.title, v.address, `${v.location?.latitude},${v.location?.longitude}`].filter(Boolean);
|
|
15103
|
+
note(`[location: ${parts.join(" \u2014 ")}]`);
|
|
15104
|
+
}
|
|
15105
|
+
if (m.location) {
|
|
15106
|
+
const coords = `${m.location.latitude},${m.location.longitude}`;
|
|
15107
|
+
note(m.location.live_period != null ? `[live location: ${coords}]` : `[location: ${coords}]`);
|
|
15108
|
+
}
|
|
15109
|
+
return { placeholder, media };
|
|
15110
|
+
}
|
|
15015
15111
|
function routeTelegramUpdate(input) {
|
|
15016
|
-
const
|
|
15112
|
+
const isEdit = input.update.message == null && input.update.edited_message != null;
|
|
15113
|
+
const m = input.update.message ?? input.update.edited_message;
|
|
15017
15114
|
if (!m || typeof m.from?.id !== "number" || typeof m.chat?.id !== "number") {
|
|
15018
15115
|
return { kind: "ignore", reason: "no-message" };
|
|
15019
15116
|
}
|
|
15020
|
-
|
|
15021
|
-
|
|
15117
|
+
const { placeholder, media } = extractContent(m);
|
|
15118
|
+
const typed = typeof m.text === "string" && m.text.length > 0 ? m.text : null;
|
|
15119
|
+
const captioned = typeof m.caption === "string" && m.caption.length > 0 ? m.caption : null;
|
|
15120
|
+
const text = typed ?? captioned ?? placeholder ?? "";
|
|
15121
|
+
if (text.length === 0 && media.length === 0) {
|
|
15122
|
+
return { kind: "ignore", reason: "unsupported-content" };
|
|
15022
15123
|
}
|
|
15023
15124
|
const access = checkTelegramAccess({ senderId: m.from.id, entry: input.entry });
|
|
15024
15125
|
if (!access.allowed) {
|
|
@@ -15028,25 +15129,211 @@ function routeTelegramUpdate(input) {
|
|
|
15028
15129
|
kind: "dispatch",
|
|
15029
15130
|
senderId: String(m.from.id),
|
|
15030
15131
|
chatId: m.chat.id,
|
|
15031
|
-
text
|
|
15132
|
+
text,
|
|
15032
15133
|
agentType: access.agentType,
|
|
15033
15134
|
reason: access.reason,
|
|
15034
15135
|
messageId: Number.isInteger(m.message_id) ? m.message_id : null,
|
|
15035
|
-
senderDisplay: telegramSenderDisplay(m.from)
|
|
15136
|
+
senderDisplay: telegramSenderDisplay(m.from),
|
|
15137
|
+
media,
|
|
15138
|
+
isEdit,
|
|
15139
|
+
editDate: Number.isInteger(m.edit_date) ? m.edit_date : null,
|
|
15140
|
+
textIsPlaceholder: typed === null && captioned === null && placeholder !== null
|
|
15036
15141
|
};
|
|
15037
15142
|
}
|
|
15038
15143
|
|
|
15144
|
+
// app/lib/telegram/inbound/media.ts
|
|
15145
|
+
import { mkdir as mkdir2, writeFile as writeFile4 } from "fs/promises";
|
|
15146
|
+
import { join as join31 } from "path";
|
|
15147
|
+
var TAG24 = "[telegram-inbound]";
|
|
15148
|
+
var TELEGRAM_MEDIA_DIR = "/tmp/maxy-media";
|
|
15149
|
+
var DOWNLOAD_TIMEOUT_MS = 45e3;
|
|
15150
|
+
function extensionFor(filePath, mimetype) {
|
|
15151
|
+
const fromPath = filePath.split("/").pop()?.split(".").slice(1).pop();
|
|
15152
|
+
if (fromPath && /^[a-z0-9]+$/i.test(fromPath)) return fromPath;
|
|
15153
|
+
const sub = mimetype?.split("/").pop()?.split(";")[0]?.trim();
|
|
15154
|
+
if (sub && /^[a-z0-9]+$/i.test(sub)) return sub;
|
|
15155
|
+
return "bin";
|
|
15156
|
+
}
|
|
15157
|
+
function pathSafe(s) {
|
|
15158
|
+
return s.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
15159
|
+
}
|
|
15160
|
+
function refusalReason(body, status) {
|
|
15161
|
+
const b = body;
|
|
15162
|
+
if (typeof b?.description === "string" && b.description.length > 0) return b.description;
|
|
15163
|
+
return `telegram returned ${status}`;
|
|
15164
|
+
}
|
|
15165
|
+
async function downloadTelegramMedia(input) {
|
|
15166
|
+
if (input.items.length === 0) return [];
|
|
15167
|
+
const doFetch = input.fetchImpl ?? fetch;
|
|
15168
|
+
const dir = input.dir ?? TELEGRAM_MEDIA_DIR;
|
|
15169
|
+
const timeoutMs = input.timeoutMs ?? DOWNLOAD_TIMEOUT_MS;
|
|
15170
|
+
const out = [];
|
|
15171
|
+
for (const item of input.items) {
|
|
15172
|
+
const base = {
|
|
15173
|
+
type: item.type,
|
|
15174
|
+
...item.mimetype ? { mimetype: item.mimetype } : {}
|
|
15175
|
+
};
|
|
15176
|
+
let result;
|
|
15177
|
+
let bytes = 0;
|
|
15178
|
+
try {
|
|
15179
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
15180
|
+
const metaRes = await doFetch(
|
|
15181
|
+
`https://api.telegram.org/bot${input.token}/getFile?file_id=${encodeURIComponent(item.fileId)}`,
|
|
15182
|
+
{ signal }
|
|
15183
|
+
);
|
|
15184
|
+
const meta = await metaRes.json();
|
|
15185
|
+
const filePath = meta?.result?.file_path;
|
|
15186
|
+
if (!metaRes.ok || meta?.ok !== true || typeof filePath !== "string" || filePath.length === 0) {
|
|
15187
|
+
result = { ...base, failure: refusalReason(meta, metaRes.status) };
|
|
15188
|
+
} else {
|
|
15189
|
+
const fileRes = await doFetch(`https://api.telegram.org/file/bot${input.token}/${filePath}`, { signal });
|
|
15190
|
+
if (!fileRes.ok) {
|
|
15191
|
+
result = { ...base, failure: `telegram returned ${fileRes.status}` };
|
|
15192
|
+
} else {
|
|
15193
|
+
const body = Buffer.from(await fileRes.arrayBuffer());
|
|
15194
|
+
await mkdir2(dir, { recursive: true });
|
|
15195
|
+
const path = join31(
|
|
15196
|
+
dir,
|
|
15197
|
+
`tg-${pathSafe(input.botId)}-${pathSafe(item.fileUniqueId)}.${extensionFor(filePath, item.mimetype)}`
|
|
15198
|
+
);
|
|
15199
|
+
await writeFile4(path, body);
|
|
15200
|
+
bytes = body.length;
|
|
15201
|
+
result = { ...base, path };
|
|
15202
|
+
}
|
|
15203
|
+
}
|
|
15204
|
+
} catch (err) {
|
|
15205
|
+
result = { ...base, failure: err instanceof Error ? err.message : String(err) };
|
|
15206
|
+
}
|
|
15207
|
+
console.error(
|
|
15208
|
+
`${TAG24} op=media-download botId=${input.botId} type=${item.type} ok=${result.path ? "yes" : "no"} bytes=${bytes} path=${result.path ?? "-"} reason=${result.failure ?? "-"}`
|
|
15209
|
+
);
|
|
15210
|
+
out.push(result);
|
|
15211
|
+
}
|
|
15212
|
+
return out;
|
|
15213
|
+
}
|
|
15214
|
+
|
|
15215
|
+
// app/lib/telegram/inbound/transcribe.ts
|
|
15216
|
+
init_stt();
|
|
15217
|
+
var TAG25 = "[telegram-inbound]";
|
|
15218
|
+
async function transcribeTelegramAudio(input) {
|
|
15219
|
+
const doTranscribe = input.transcribeImpl ?? transcribe;
|
|
15220
|
+
const out = [];
|
|
15221
|
+
const transcripts = [];
|
|
15222
|
+
for (const m of input.media) {
|
|
15223
|
+
if (m.type !== "audio") {
|
|
15224
|
+
out.push(m);
|
|
15225
|
+
continue;
|
|
15226
|
+
}
|
|
15227
|
+
if (!m.path) {
|
|
15228
|
+
console.error(
|
|
15229
|
+
`${TAG25} op=transcribe botId=${input.botId} ok=no chars=0 ms=0 reason=${m.failure ?? "no local file"}`
|
|
15230
|
+
);
|
|
15231
|
+
out.push(m);
|
|
15232
|
+
continue;
|
|
15233
|
+
}
|
|
15234
|
+
const startedMs = Date.now();
|
|
15235
|
+
let heard;
|
|
15236
|
+
let reason = "-";
|
|
15237
|
+
try {
|
|
15238
|
+
const r = await doTranscribe(m.path, m.mimetype ?? "");
|
|
15239
|
+
const t = r?.text.trim();
|
|
15240
|
+
heard = t ? t : void 0;
|
|
15241
|
+
if (!heard) reason = "no transcript returned";
|
|
15242
|
+
} catch (err) {
|
|
15243
|
+
reason = err instanceof Error ? err.message : String(err);
|
|
15244
|
+
}
|
|
15245
|
+
console.error(
|
|
15246
|
+
`${TAG25} op=transcribe botId=${input.botId} ok=${heard ? "yes" : "no"} chars=${heard?.length ?? 0} ms=${Date.now() - startedMs} reason=${reason}`
|
|
15247
|
+
);
|
|
15248
|
+
if (heard) {
|
|
15249
|
+
transcripts.push(heard);
|
|
15250
|
+
out.push({ ...m, transcribed: true });
|
|
15251
|
+
} else {
|
|
15252
|
+
out.push(m);
|
|
15253
|
+
}
|
|
15254
|
+
}
|
|
15255
|
+
if (transcripts.length === 0) return { text: input.text, media: out };
|
|
15256
|
+
const body = transcripts.join("\n\n");
|
|
15257
|
+
const caption = input.textIsPlaceholder ? "" : input.text.trim();
|
|
15258
|
+
return { text: caption ? `${caption}
|
|
15259
|
+
|
|
15260
|
+
${body}` : body, media: out };
|
|
15261
|
+
}
|
|
15262
|
+
|
|
15263
|
+
// app/lib/telegram/gateway/telegram-inbound-census.ts
|
|
15264
|
+
var ANSWER_THRESHOLD_MS = 3e4;
|
|
15265
|
+
var GAP_NAME_LIMIT = 10;
|
|
15266
|
+
var received = 0;
|
|
15267
|
+
var answered = 0;
|
|
15268
|
+
var outstanding = /* @__PURE__ */ new Map();
|
|
15269
|
+
var kindDispatched = 0;
|
|
15270
|
+
var kindIgnored = 0;
|
|
15271
|
+
var kindCounts = /* @__PURE__ */ new Map();
|
|
15272
|
+
function noteInboundKind(kind, dispatched) {
|
|
15273
|
+
if (dispatched) kindDispatched += 1;
|
|
15274
|
+
else kindIgnored += 1;
|
|
15275
|
+
kindCounts.set(kind, (kindCounts.get(kind) ?? 0) + 1);
|
|
15276
|
+
}
|
|
15277
|
+
function readTelegramKindCensus() {
|
|
15278
|
+
const kinds = [...kindCounts.entries()].map(([kind, count]) => ({ kind, count })).sort((a, b) => b.count - a.count || a.kind.localeCompare(b.kind));
|
|
15279
|
+
return { dispatched: kindDispatched, ignored: kindIgnored, kinds };
|
|
15280
|
+
}
|
|
15281
|
+
function buildTelegramKindCensusLine(c) {
|
|
15282
|
+
const kinds = c.kinds.length > 0 ? c.kinds.map((k) => `${k.kind}:${k.count}`).join(",") : "none";
|
|
15283
|
+
return `[telegram-native] op=inbound-kind-census dispatched=${c.dispatched} ignored=${c.ignored} kinds=${kinds}`;
|
|
15284
|
+
}
|
|
15285
|
+
function noteReceived(key2, botId, messageId, now) {
|
|
15286
|
+
received += 1;
|
|
15287
|
+
const list = outstanding.get(key2);
|
|
15288
|
+
if (list) list.push({ messageId, botId, receivedAt: now });
|
|
15289
|
+
else outstanding.set(key2, [{ messageId, botId, receivedAt: now }]);
|
|
15290
|
+
}
|
|
15291
|
+
function noteAnswered(key2) {
|
|
15292
|
+
const list = outstanding.get(key2);
|
|
15293
|
+
if (!list || list.length === 0) return;
|
|
15294
|
+
list.shift();
|
|
15295
|
+
if (list.length === 0) outstanding.delete(key2);
|
|
15296
|
+
answered += 1;
|
|
15297
|
+
}
|
|
15298
|
+
function readTelegramInboundCensus(now) {
|
|
15299
|
+
const gaps = [];
|
|
15300
|
+
for (const [key2, list] of outstanding) {
|
|
15301
|
+
for (const o of list) {
|
|
15302
|
+
const ageMs2 = now - o.receivedAt;
|
|
15303
|
+
if (ageMs2 > ANSWER_THRESHOLD_MS) gaps.push({ messageId: o.messageId, botId: o.botId, key: key2, ageMs: ageMs2 });
|
|
15304
|
+
}
|
|
15305
|
+
}
|
|
15306
|
+
gaps.sort((a, b) => b.ageMs - a.ageMs);
|
|
15307
|
+
return { received, answered, gaps };
|
|
15308
|
+
}
|
|
15309
|
+
function buildTelegramNotifyReconcileLines(input) {
|
|
15310
|
+
const named = input.gaps.slice(0, GAP_NAME_LIMIT);
|
|
15311
|
+
const lines = [
|
|
15312
|
+
`[telegram-native] op=telegram-notify-reconcile received=${input.received} answered=${input.answered} answerGap=${input.gaps.length} named=${named.length}`
|
|
15313
|
+
];
|
|
15314
|
+
for (const g of named) {
|
|
15315
|
+
lines.push(
|
|
15316
|
+
`[telegram-native] op=telegram-answer-gap messageId=${g.messageId} botId=${g.botId} key=${g.key} ageMs=${g.ageMs}`
|
|
15317
|
+
);
|
|
15318
|
+
}
|
|
15319
|
+
return lines;
|
|
15320
|
+
}
|
|
15321
|
+
function runTelegramNotifyReconcile(now) {
|
|
15322
|
+
for (const line of buildTelegramNotifyReconcileLines(readTelegramInboundCensus(now))) console.error(line);
|
|
15323
|
+
console.error(buildTelegramKindCensusLine(readTelegramKindCensus()));
|
|
15324
|
+
}
|
|
15325
|
+
|
|
15039
15326
|
// server/routes/telegram.ts
|
|
15040
15327
|
init_channel_key();
|
|
15041
15328
|
init_admin_session_id();
|
|
15042
15329
|
|
|
15043
15330
|
// server/channel-session-override.ts
|
|
15044
15331
|
import { readFileSync as readFileSync26, writeFileSync as writeFileSync11, renameSync as renameSync5 } from "fs";
|
|
15045
|
-
import { join as
|
|
15332
|
+
import { join as join32 } from "path";
|
|
15046
15333
|
var FILE2 = "channel-session-override.json";
|
|
15047
15334
|
var UUID3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
15048
15335
|
function channelOverridePath(accountDir) {
|
|
15049
|
-
return
|
|
15336
|
+
return join32(accountDir, FILE2);
|
|
15050
15337
|
}
|
|
15051
15338
|
function senderKey(channel, senderId) {
|
|
15052
15339
|
return `${channel}:${senderId}`;
|
|
@@ -15152,8 +15439,9 @@ function decideTelegramNotify(input) {
|
|
|
15152
15439
|
if (input.isDuplicate()) return { emit: false, reason: "duplicate" };
|
|
15153
15440
|
return { emit: true, senderType: input.agentType };
|
|
15154
15441
|
}
|
|
15155
|
-
function telegramNotifyId(botId, chatId, messageId) {
|
|
15156
|
-
|
|
15442
|
+
function telegramNotifyId(botId, chatId, messageId, editDate) {
|
|
15443
|
+
const suffix = editDate === void 0 ? "" : `:edit:${editDate}`;
|
|
15444
|
+
return `tg:${botId}:${chatId}:${messageId}${suffix}`;
|
|
15157
15445
|
}
|
|
15158
15446
|
|
|
15159
15447
|
// app/lib/telegram/inbound/notify-dedupe.ts
|
|
@@ -15182,21 +15470,21 @@ function isTelegramNotifyDuplicate(notifyId) {
|
|
|
15182
15470
|
|
|
15183
15471
|
// app/lib/telegram/gateway/telegram-notify-census.ts
|
|
15184
15472
|
var PUBLISH_THRESHOLD_MS = 3e4;
|
|
15185
|
-
var
|
|
15473
|
+
var GAP_NAME_LIMIT2 = 10;
|
|
15186
15474
|
var eligible = 0;
|
|
15187
15475
|
var published = 0;
|
|
15188
|
-
var
|
|
15476
|
+
var outstanding2 = /* @__PURE__ */ new Map();
|
|
15189
15477
|
function noteNotifyEligible(notifyId, botId, now) {
|
|
15190
15478
|
eligible += 1;
|
|
15191
|
-
|
|
15479
|
+
outstanding2.set(notifyId, { botId, at: now });
|
|
15192
15480
|
}
|
|
15193
15481
|
function noteNotifyPublished(notifyId) {
|
|
15194
|
-
if (!
|
|
15482
|
+
if (!outstanding2.delete(notifyId)) return;
|
|
15195
15483
|
published += 1;
|
|
15196
15484
|
}
|
|
15197
15485
|
function readTelegramNotifyCensus(now) {
|
|
15198
15486
|
const missing = [];
|
|
15199
|
-
for (const [notifyId, o] of
|
|
15487
|
+
for (const [notifyId, o] of outstanding2) {
|
|
15200
15488
|
const ageMs2 = now - o.at;
|
|
15201
15489
|
if (ageMs2 > PUBLISH_THRESHOLD_MS) missing.push({ notifyId, botId: o.botId, ageMs: ageMs2 });
|
|
15202
15490
|
}
|
|
@@ -15204,7 +15492,7 @@ function readTelegramNotifyCensus(now) {
|
|
|
15204
15492
|
return { eligible, published, missing };
|
|
15205
15493
|
}
|
|
15206
15494
|
function buildTelegramNotifyCensusLines(input) {
|
|
15207
|
-
const named = input.missing.slice(0,
|
|
15495
|
+
const named = input.missing.slice(0, GAP_NAME_LIMIT2);
|
|
15208
15496
|
const lines = [
|
|
15209
15497
|
`[telegram-native] op=notify-publish-census eligible=${input.eligible} published=${input.published} missing=${input.missing.length} named=${named.length}`
|
|
15210
15498
|
];
|
|
@@ -15224,10 +15512,10 @@ function runTelegramNotifyPublishCensus(now) {
|
|
|
15224
15512
|
// server/routes/telegram.ts
|
|
15225
15513
|
init_neo4j_store();
|
|
15226
15514
|
var telegramAdoptionSeen = /* @__PURE__ */ new Set();
|
|
15227
|
-
var
|
|
15515
|
+
var TAG26 = "[telegram-inbound]";
|
|
15228
15516
|
function configDirName2() {
|
|
15229
15517
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
|
|
15230
|
-
const brandPath =
|
|
15518
|
+
const brandPath = join33(platformRoot5, "config", "brand.json");
|
|
15231
15519
|
if (existsSync22(brandPath)) {
|
|
15232
15520
|
try {
|
|
15233
15521
|
return JSON.parse(readFileSync27(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -15246,61 +15534,67 @@ var app11 = new Hono();
|
|
|
15246
15534
|
app11.post("/", async (c) => {
|
|
15247
15535
|
const botId = c.req.query("bot");
|
|
15248
15536
|
if (!botId) {
|
|
15249
|
-
console.error(`${
|
|
15537
|
+
console.error(`${TAG26} op=reject reason=missing-bot-param`);
|
|
15250
15538
|
return c.json({ ok: false }, 400);
|
|
15251
15539
|
}
|
|
15252
|
-
console.error(`${
|
|
15540
|
+
console.error(`${TAG26} op=received botId=${botId} path=/api/telegram/`);
|
|
15253
15541
|
const resolved = resolveBotEntry(listValidAccounts(), botId);
|
|
15254
15542
|
if (resolved.kind === "none") {
|
|
15255
|
-
console.error(`${
|
|
15543
|
+
console.error(`${TAG26} op=reject reason=unknown-bot botId=${botId}`);
|
|
15256
15544
|
return c.json({ ok: false }, 401);
|
|
15257
15545
|
}
|
|
15258
15546
|
if (resolved.kind === "duplicate") {
|
|
15259
|
-
console.error(`${
|
|
15547
|
+
console.error(`${TAG26} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
|
|
15260
15548
|
return c.json({ ok: false }, 401);
|
|
15261
15549
|
}
|
|
15262
15550
|
const { accountId, accountDir, entry } = resolved;
|
|
15263
15551
|
const agentSlug = entry.role === "admin" ? "admin" : entry.agent;
|
|
15264
|
-
console.error(`${
|
|
15552
|
+
console.error(`${TAG26} op=entry botId=${botId} accountId=${accountId} role=${entry.role} agent=${agentSlug}`);
|
|
15265
15553
|
const sp = secretPath(botId);
|
|
15266
15554
|
if (!existsSync22(sp)) {
|
|
15267
|
-
console.error(`${
|
|
15555
|
+
console.error(`${TAG26} op=secret botId=${botId} result=missing-file`);
|
|
15268
15556
|
return c.json({ ok: false }, 401);
|
|
15269
15557
|
}
|
|
15270
15558
|
const expected = readFileSync27(sp, "utf-8").trim();
|
|
15271
15559
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
15272
15560
|
if (got !== expected) {
|
|
15273
|
-
console.error(`${
|
|
15561
|
+
console.error(`${TAG26} op=secret botId=${botId} result=mismatch`);
|
|
15274
15562
|
return c.json({ ok: false }, 401);
|
|
15275
15563
|
}
|
|
15276
|
-
console.error(`${
|
|
15564
|
+
console.error(`${TAG26} op=secret botId=${botId} result=ok`);
|
|
15277
15565
|
let update;
|
|
15278
15566
|
try {
|
|
15279
15567
|
update = await c.req.json();
|
|
15280
15568
|
} catch {
|
|
15281
15569
|
return c.json({ ok: true }, 200);
|
|
15282
15570
|
}
|
|
15571
|
+
const shape = describeTelegramUpdate(update);
|
|
15572
|
+
console.error(
|
|
15573
|
+
`${TAG26} op=inbound-kind botId=${botId} update=${shape.envelope} content=${shape.content} isEdit=${shape.isEdit ? "yes" : "no"}`
|
|
15574
|
+
);
|
|
15283
15575
|
const decision = routeTelegramUpdate({ update, entry });
|
|
15576
|
+
noteInboundKind(shape.primaryKind, decision.kind === "dispatch");
|
|
15284
15577
|
if (decision.kind === "ignore") {
|
|
15285
|
-
console.error(`${
|
|
15578
|
+
console.error(`${TAG26} op=ignore botId=${botId} reason=${decision.reason}`);
|
|
15286
15579
|
return c.json({ ok: true }, 200);
|
|
15287
15580
|
}
|
|
15288
15581
|
if (decision.kind === "denied") {
|
|
15289
|
-
console.error(`${
|
|
15582
|
+
console.error(`${TAG26} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
|
|
15290
15583
|
return c.json({ ok: true }, 200);
|
|
15291
15584
|
}
|
|
15292
15585
|
const { senderId, chatId, text } = decision;
|
|
15293
|
-
console.error(`${
|
|
15586
|
+
console.error(`${TAG26} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
|
|
15294
15587
|
const channelKey = telegramChannelKey(botId, senderId);
|
|
15295
15588
|
const scope = entry.role === "admin" ? "admin" : "public";
|
|
15296
15589
|
const adminUserId = entry.role === "admin" ? resolveTelegramAdminUserId({ accountId, chatId: senderId }) : null;
|
|
15297
15590
|
const sessionId = adminUserId ? adminSessionIdFor(accountId, senderId, adminUserId) : adminSessionIdFor(accountId, senderId, void 0, botId);
|
|
15298
15591
|
const inboundAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15592
|
+
const editSuffix = decision.isEdit ? `:edit:${decision.editDate}` : "";
|
|
15299
15593
|
appendMessage2(accountId, {
|
|
15300
15594
|
// Telegram's own per-chat message number, so a redelivered update dedupes.
|
|
15301
15595
|
// Task 2437 parses it once, in routeTelegramUpdate; reading the raw update
|
|
15302
15596
|
// again here would be a second authority for the same fact.
|
|
15303
|
-
messageId: `telegram:${accountId}:${channelKey}:in:${decision.messageId ?? inboundAt}`,
|
|
15597
|
+
messageId: `telegram:${accountId}:${channelKey}:in:${decision.messageId ?? inboundAt}${editSuffix}`,
|
|
15304
15598
|
sessionId,
|
|
15305
15599
|
dateSent: inboundAt,
|
|
15306
15600
|
body: text,
|
|
@@ -15319,14 +15613,26 @@ app11.post("/", async (c) => {
|
|
|
15319
15613
|
const gate = decideTelegramNotify({
|
|
15320
15614
|
messageId: decision.messageId,
|
|
15321
15615
|
agentType: decision.agentType,
|
|
15322
|
-
isDuplicate: () => decision.messageId === null ? false : isTelegramNotifyDuplicate(
|
|
15616
|
+
isDuplicate: () => decision.messageId === null ? false : isTelegramNotifyDuplicate(
|
|
15617
|
+
telegramNotifyId(
|
|
15618
|
+
botId,
|
|
15619
|
+
String(chatId),
|
|
15620
|
+
decision.messageId,
|
|
15621
|
+
decision.isEdit ? decision.editDate : void 0
|
|
15622
|
+
)
|
|
15623
|
+
)
|
|
15323
15624
|
});
|
|
15324
15625
|
if (!gate.emit) {
|
|
15325
15626
|
console.error(
|
|
15326
15627
|
`[channel-notify] op=skip channel=telegram botId=${botId} reason=${gate.reason}`
|
|
15327
15628
|
);
|
|
15328
15629
|
} else {
|
|
15329
|
-
const notifyId = telegramNotifyId(
|
|
15630
|
+
const notifyId = telegramNotifyId(
|
|
15631
|
+
botId,
|
|
15632
|
+
String(chatId),
|
|
15633
|
+
decision.messageId,
|
|
15634
|
+
decision.isEdit ? decision.editDate : void 0
|
|
15635
|
+
);
|
|
15330
15636
|
const { body, truncated } = formatNotifyBody(text);
|
|
15331
15637
|
noteNotifyEligible(notifyId, botId, Date.now());
|
|
15332
15638
|
console.error(
|
|
@@ -15357,14 +15663,14 @@ app11.post("/", async (c) => {
|
|
|
15357
15663
|
}
|
|
15358
15664
|
}
|
|
15359
15665
|
const active = entry.role === "admin" ? true : isActiveAgentSlug(accountDir, entry.agent);
|
|
15360
|
-
console.error(`${
|
|
15666
|
+
console.error(`${TAG26} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
|
|
15361
15667
|
if (!active) {
|
|
15362
|
-
console.error(`${
|
|
15668
|
+
console.error(`${TAG26} op=reject reason=agent-inactive botId=${botId} agent=${agentSlug}`);
|
|
15363
15669
|
return c.json({ ok: true }, 200);
|
|
15364
15670
|
}
|
|
15365
15671
|
const gateway = getTelegramGateway();
|
|
15366
15672
|
if (!gateway) {
|
|
15367
|
-
console.error(`${
|
|
15673
|
+
console.error(`${TAG26} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
|
|
15368
15674
|
return c.json({ ok: true }, 200);
|
|
15369
15675
|
}
|
|
15370
15676
|
const reply = async (replyText) => {
|
|
@@ -15385,8 +15691,8 @@ app11.post("/", async (c) => {
|
|
|
15385
15691
|
origin: "agent",
|
|
15386
15692
|
createdAt: at
|
|
15387
15693
|
});
|
|
15388
|
-
console.error(`${
|
|
15389
|
-
} else console.error(`${
|
|
15694
|
+
console.error(`${TAG26} op=reply-sent botId=${botId} ok=true`);
|
|
15695
|
+
} else console.error(`${TAG26} op=reply-dropped botId=${botId} reason=${sent.error}`);
|
|
15390
15696
|
};
|
|
15391
15697
|
if (adminUserId) {
|
|
15392
15698
|
const line = runAdminSessionAdoption({
|
|
@@ -15412,25 +15718,35 @@ app11.post("/", async (c) => {
|
|
|
15412
15718
|
});
|
|
15413
15719
|
if (line) console.error(line);
|
|
15414
15720
|
}
|
|
15415
|
-
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15432
|
-
|
|
15433
|
-
|
|
15721
|
+
const media = await downloadTelegramMedia({ token: entry.token, botId, items: decision.media });
|
|
15722
|
+
void (async () => {
|
|
15723
|
+
const heard = await transcribeTelegramAudio({
|
|
15724
|
+
botId,
|
|
15725
|
+
text,
|
|
15726
|
+
textIsPlaceholder: decision.textIsPlaceholder,
|
|
15727
|
+
media
|
|
15728
|
+
});
|
|
15729
|
+
void gateway.handleInbound({
|
|
15730
|
+
accountId,
|
|
15731
|
+
accountDir,
|
|
15732
|
+
botId,
|
|
15733
|
+
botToken: entry.token,
|
|
15734
|
+
agentSlug,
|
|
15735
|
+
senderId,
|
|
15736
|
+
role: entry.role,
|
|
15737
|
+
personId: null,
|
|
15738
|
+
// Task 2078 — the admin person this chat is bound to (the users.json
|
|
15739
|
+
// telegram binding). It is the SUBJECT of the session id, so one admin's
|
|
15740
|
+
// Telegram, WhatsApp and webchat resolve to one conversation. Resolved
|
|
15741
|
+
// above, alongside the store row's own session id, so the row and the spawn
|
|
15742
|
+
// can never name different sessions for one message.
|
|
15743
|
+
adminUserId,
|
|
15744
|
+
chatId: String(chatId),
|
|
15745
|
+
text: heard.text,
|
|
15746
|
+
media: heard.media,
|
|
15747
|
+
reply
|
|
15748
|
+
});
|
|
15749
|
+
})();
|
|
15434
15750
|
return c.json({ ok: true }, 200);
|
|
15435
15751
|
});
|
|
15436
15752
|
var telegram_default = app11;
|
|
@@ -15444,29 +15760,29 @@ function mountTelegramRoutes(app79, telegramRoutes) {
|
|
|
15444
15760
|
// server/routes/quickbooks.ts
|
|
15445
15761
|
init_dist();
|
|
15446
15762
|
init_claude_agent();
|
|
15447
|
-
import { join as
|
|
15763
|
+
import { join as join34 } from "path";
|
|
15448
15764
|
import { existsSync as existsSync23, readFileSync as readFileSync28, writeFileSync as writeFileSync12, mkdirSync as mkdirSync5, rmSync as rmSync4, renameSync as renameSync6 } from "fs";
|
|
15449
|
-
var
|
|
15765
|
+
var TAG27 = "[quickbooks]";
|
|
15450
15766
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
15451
15767
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
15452
15768
|
function pendingPath(accountDir, state) {
|
|
15453
|
-
return
|
|
15769
|
+
return join34(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
15454
15770
|
}
|
|
15455
15771
|
function storePath(accountDir) {
|
|
15456
|
-
return
|
|
15772
|
+
return join34(accountDir, "secrets", "quickbooks.json");
|
|
15457
15773
|
}
|
|
15458
15774
|
async function completeConsent(args) {
|
|
15459
15775
|
const { accountDir, code, realmId } = args;
|
|
15460
15776
|
const state = args.state;
|
|
15461
15777
|
if (!state || !STATE_RE.test(state) || !existsSync23(pendingPath(accountDir, state))) {
|
|
15462
|
-
console.error(`${
|
|
15778
|
+
console.error(`${TAG27} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
|
|
15463
15779
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
15464
15780
|
}
|
|
15465
15781
|
const claimFile = `${pendingPath(accountDir, state)}.claimed`;
|
|
15466
15782
|
try {
|
|
15467
15783
|
renameSync6(pendingPath(accountDir, state), claimFile);
|
|
15468
15784
|
} catch {
|
|
15469
|
-
console.error(`${
|
|
15785
|
+
console.error(`${TAG27} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
15470
15786
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
15471
15787
|
}
|
|
15472
15788
|
try {
|
|
@@ -15474,14 +15790,14 @@ async function completeConsent(args) {
|
|
|
15474
15790
|
try {
|
|
15475
15791
|
pending = JSON.parse(readFileSync28(claimFile, "utf-8"));
|
|
15476
15792
|
} catch {
|
|
15477
|
-
console.error(`${
|
|
15793
|
+
console.error(`${TAG27} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
15478
15794
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
15479
15795
|
}
|
|
15480
15796
|
if (Date.now() > pending.expiresAt) {
|
|
15481
|
-
console.error(`${
|
|
15797
|
+
console.error(`${TAG27} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
15482
15798
|
return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
|
|
15483
15799
|
}
|
|
15484
|
-
console.error(`${
|
|
15800
|
+
console.error(`${TAG27} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
|
|
15485
15801
|
if (!code || !realmId) {
|
|
15486
15802
|
return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
|
|
15487
15803
|
}
|
|
@@ -15505,12 +15821,12 @@ async function completeConsent(args) {
|
|
|
15505
15821
|
});
|
|
15506
15822
|
const text = await res.text();
|
|
15507
15823
|
if (!res.ok) {
|
|
15508
|
-
console.error(`${
|
|
15824
|
+
console.error(`${TAG27} op=token-exchange realmId=${realmId} persisted=false`);
|
|
15509
15825
|
return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
|
|
15510
15826
|
}
|
|
15511
15827
|
const body = JSON.parse(text);
|
|
15512
15828
|
if (!body.refresh_token) {
|
|
15513
|
-
console.error(`${
|
|
15829
|
+
console.error(`${TAG27} op=token-exchange realmId=${realmId} persisted=false`);
|
|
15514
15830
|
return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
|
|
15515
15831
|
}
|
|
15516
15832
|
const now = Date.now();
|
|
@@ -15520,10 +15836,10 @@ async function completeConsent(args) {
|
|
|
15520
15836
|
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
15521
15837
|
lastRefresh: now
|
|
15522
15838
|
};
|
|
15523
|
-
mkdirSync5(
|
|
15839
|
+
mkdirSync5(join34(accountDir, "secrets"), { recursive: true });
|
|
15524
15840
|
writeFileSync12(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
15525
15841
|
const persisted = JSON.parse(readFileSync28(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
15526
|
-
console.error(`${
|
|
15842
|
+
console.error(`${TAG27} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
15527
15843
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
15528
15844
|
} finally {
|
|
15529
15845
|
rmSync4(claimFile, { force: true });
|
|
@@ -15536,7 +15852,7 @@ var app12 = new Hono();
|
|
|
15536
15852
|
app12.get("/callback", async (c) => {
|
|
15537
15853
|
const account = resolveAccount();
|
|
15538
15854
|
if (!account) {
|
|
15539
|
-
console.error(`${
|
|
15855
|
+
console.error(`${TAG27} op=callback stateValid=false realmId= reason=no-account`);
|
|
15540
15856
|
return c.html(page("QuickBooks", "This install has no account configured."), 500);
|
|
15541
15857
|
}
|
|
15542
15858
|
const result = await completeConsent({
|
|
@@ -15566,7 +15882,7 @@ function claudeBin() {
|
|
|
15566
15882
|
}
|
|
15567
15883
|
|
|
15568
15884
|
// server/routes/onboarding.ts
|
|
15569
|
-
import { dirname as dirname13, join as
|
|
15885
|
+
import { dirname as dirname13, join as join36 } from "path";
|
|
15570
15886
|
|
|
15571
15887
|
// app/lib/claude-keychain.ts
|
|
15572
15888
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -15696,7 +16012,7 @@ function readHostCredsBlob(service) {
|
|
|
15696
16012
|
|
|
15697
16013
|
// ../lib/admins-write/src/index.ts
|
|
15698
16014
|
import { existsSync as existsSync24, readFileSync as readFileSync29, writeFileSync as writeFileSync13, renameSync as renameSync7, mkdirSync as mkdirSync6, readdirSync as readdirSync19, statSync as statSync18, appendFileSync as appendFileSync2 } from "fs";
|
|
15699
|
-
import { dirname as dirname12, join as
|
|
16015
|
+
import { dirname as dirname12, join as join35 } from "path";
|
|
15700
16016
|
function id8(value) {
|
|
15701
16017
|
return value.slice(0, 8);
|
|
15702
16018
|
}
|
|
@@ -15769,7 +16085,7 @@ function writeAdminEntry(input) {
|
|
|
15769
16085
|
return result;
|
|
15770
16086
|
}
|
|
15771
16087
|
try {
|
|
15772
|
-
const accountJsonPath =
|
|
16088
|
+
const accountJsonPath = join35(input.accountDir, "account.json");
|
|
15773
16089
|
if (!existsSync24(accountJsonPath)) {
|
|
15774
16090
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
15775
16091
|
}
|
|
@@ -15817,13 +16133,13 @@ function computeAdminStoreDivergence(input) {
|
|
|
15817
16133
|
}
|
|
15818
16134
|
for (const entry of entries2) {
|
|
15819
16135
|
if (entry.startsWith(".")) continue;
|
|
15820
|
-
const accountDir =
|
|
16136
|
+
const accountDir = join35(input.accountsDir, entry);
|
|
15821
16137
|
try {
|
|
15822
16138
|
if (!statSync18(accountDir).isDirectory()) continue;
|
|
15823
16139
|
} catch {
|
|
15824
16140
|
continue;
|
|
15825
16141
|
}
|
|
15826
|
-
const accountJsonPath =
|
|
16142
|
+
const accountJsonPath = join35(accountDir, "account.json");
|
|
15827
16143
|
if (!existsSync24(accountJsonPath)) continue;
|
|
15828
16144
|
let admins = [];
|
|
15829
16145
|
try {
|
|
@@ -16002,7 +16318,7 @@ app13.post("/claude-auth", async (c) => {
|
|
|
16002
16318
|
});
|
|
16003
16319
|
persistKeychainService(
|
|
16004
16320
|
writebackResult,
|
|
16005
|
-
(service) => writeFileSync14(
|
|
16321
|
+
(service) => writeFileSync14(join36(dirname13(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
|
|
16006
16322
|
(line) => console.log(line)
|
|
16007
16323
|
);
|
|
16008
16324
|
if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
|
|
@@ -16272,8 +16588,8 @@ init_paths();
|
|
|
16272
16588
|
init_remote_auth();
|
|
16273
16589
|
init_loop_registry();
|
|
16274
16590
|
import { appendFileSync as appendFileSync3, existsSync as existsSync26, renameSync as renameSync9, statSync as statSync19 } from "fs";
|
|
16275
|
-
import { join as
|
|
16276
|
-
var CLIENT_ERRORS_LOG =
|
|
16591
|
+
import { join as join37 } from "path";
|
|
16592
|
+
var CLIENT_ERRORS_LOG = join37(LOG_DIR, "client-errors.log");
|
|
16277
16593
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
16278
16594
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
16279
16595
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -16701,12 +17017,12 @@ import { resolve as resolve22, basename as basename11 } from "path";
|
|
|
16701
17017
|
|
|
16702
17018
|
// app/lib/logs-read-resolve.ts
|
|
16703
17019
|
import { existsSync as existsSync27 } from "fs";
|
|
16704
|
-
import { join as
|
|
17020
|
+
import { join as join38 } from "path";
|
|
16705
17021
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
16706
17022
|
const tried = [filename];
|
|
16707
17023
|
const hits = [];
|
|
16708
17024
|
for (const dir of logDirs) {
|
|
16709
|
-
const fullPath =
|
|
17025
|
+
const fullPath = join38(dir, filename);
|
|
16710
17026
|
if (existsSync27(fullPath)) {
|
|
16711
17027
|
hits.push({ path: fullPath, dir });
|
|
16712
17028
|
}
|
|
@@ -17036,7 +17352,7 @@ import { execFileSync as execFileSync6 } from "child_process";
|
|
|
17036
17352
|
// ../services/claude-session-manager/src/tool-surface.ts
|
|
17037
17353
|
import { readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync22, existsSync as existsSync31 } from "fs";
|
|
17038
17354
|
import { createHash as createHash5 } from "crypto";
|
|
17039
|
-
import { join as
|
|
17355
|
+
import { join as join39 } from "path";
|
|
17040
17356
|
|
|
17041
17357
|
// ../services/claude-session-manager/src/canonical-tool-names.ts
|
|
17042
17358
|
function canonicalToolName(plugin, tool) {
|
|
@@ -17289,13 +17605,13 @@ function loadToolSurface(pluginsRoots) {
|
|
|
17289
17605
|
const riskByTool = /* @__PURE__ */ new Map();
|
|
17290
17606
|
const manifestPaths = /* @__PURE__ */ new Map();
|
|
17291
17607
|
const loadOne = (pluginsRoot, plugin) => {
|
|
17292
|
-
const pluginDir =
|
|
17608
|
+
const pluginDir = join39(pluginsRoot, plugin);
|
|
17293
17609
|
try {
|
|
17294
17610
|
if (!statSync22(pluginDir).isDirectory()) return;
|
|
17295
17611
|
} catch {
|
|
17296
17612
|
return;
|
|
17297
17613
|
}
|
|
17298
|
-
const manifestPath =
|
|
17614
|
+
const manifestPath = join39(pluginDir, "PLUGIN.md");
|
|
17299
17615
|
if (!existsSync31(manifestPath)) return;
|
|
17300
17616
|
const raw = readFileSync32(manifestPath, "utf-8");
|
|
17301
17617
|
const frontmatter = extractFrontmatter(raw, plugin);
|
|
@@ -17341,9 +17657,9 @@ function loadToolSurface(pluginsRoots) {
|
|
|
17341
17657
|
for (const root of roots) {
|
|
17342
17658
|
const entries2 = readdirSync21(root).sort();
|
|
17343
17659
|
for (const plugin of entries2) {
|
|
17344
|
-
const pluginDir =
|
|
17660
|
+
const pluginDir = join39(root, plugin);
|
|
17345
17661
|
loadOne(root, plugin);
|
|
17346
|
-
const subRoot =
|
|
17662
|
+
const subRoot = join39(pluginDir, "plugins");
|
|
17347
17663
|
let subEntries;
|
|
17348
17664
|
try {
|
|
17349
17665
|
if (!statSync22(subRoot).isDirectory()) continue;
|
|
@@ -18804,7 +19120,7 @@ init_claude_agent();
|
|
|
18804
19120
|
init_account();
|
|
18805
19121
|
init_neo4j_store();
|
|
18806
19122
|
import { existsSync as existsSync34, readFileSync as readFileSync34, readdirSync as readdirSync23, statSync as statSync23 } from "fs";
|
|
18807
|
-
import { dirname as dirname14, resolve as resolve25, join as
|
|
19123
|
+
import { dirname as dirname14, resolve as resolve25, join as join40 } from "path";
|
|
18808
19124
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
18809
19125
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
18810
19126
|
try {
|
|
@@ -18845,8 +19161,8 @@ function frontmatterField(manifest, field2) {
|
|
|
18845
19161
|
function extractPluginToolDescriptions(pluginDir) {
|
|
18846
19162
|
const out = /* @__PURE__ */ new Map();
|
|
18847
19163
|
const candidates = [
|
|
18848
|
-
|
|
18849
|
-
|
|
19164
|
+
join40(pluginDir, "mcp/dist/index.js"),
|
|
19165
|
+
join40(pluginDir, "mcp/src/index.ts")
|
|
18850
19166
|
];
|
|
18851
19167
|
let raw = null;
|
|
18852
19168
|
for (const path of candidates) {
|
|
@@ -18904,7 +19220,7 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18904
19220
|
const platformPlugins = resolve25(PLATFORM_ROOT, "plugins");
|
|
18905
19221
|
if (existsSync34(platformPlugins)) {
|
|
18906
19222
|
for (const name of readdirSync23(platformPlugins)) {
|
|
18907
|
-
const dir =
|
|
19223
|
+
const dir = join40(platformPlugins, name);
|
|
18908
19224
|
try {
|
|
18909
19225
|
if (statSync23(dir).isDirectory()) out.set(name, dir);
|
|
18910
19226
|
} catch {
|
|
@@ -18914,11 +19230,11 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18914
19230
|
const premiumRoot = resolve25(dirname14(PLATFORM_ROOT), "premium-plugins");
|
|
18915
19231
|
if (existsSync34(premiumRoot)) {
|
|
18916
19232
|
for (const bundle of readdirSync23(premiumRoot)) {
|
|
18917
|
-
const bundlePlugins =
|
|
19233
|
+
const bundlePlugins = join40(premiumRoot, bundle, "plugins");
|
|
18918
19234
|
if (!existsSync34(bundlePlugins)) continue;
|
|
18919
19235
|
try {
|
|
18920
19236
|
for (const name of readdirSync23(bundlePlugins)) {
|
|
18921
|
-
const dir =
|
|
19237
|
+
const dir = join40(bundlePlugins, name);
|
|
18922
19238
|
try {
|
|
18923
19239
|
if (statSync23(dir).isDirectory()) out.set(name, dir);
|
|
18924
19240
|
} catch {
|
|
@@ -18932,7 +19248,7 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18932
19248
|
try {
|
|
18933
19249
|
for (const name of readdirSync23(accountPluginsDir)) {
|
|
18934
19250
|
if (out.has(name)) continue;
|
|
18935
|
-
const dir =
|
|
19251
|
+
const dir = join40(accountPluginsDir, name);
|
|
18936
19252
|
try {
|
|
18937
19253
|
if (statSync23(dir).isDirectory()) out.set(name, dir);
|
|
18938
19254
|
} catch {
|
|
@@ -18951,7 +19267,7 @@ function listAccountPluginNames(accountPluginsDir) {
|
|
|
18951
19267
|
try {
|
|
18952
19268
|
return readdirSync23(accountPluginsDir).filter((name) => {
|
|
18953
19269
|
try {
|
|
18954
|
-
return statSync23(
|
|
19270
|
+
return statSync23(join40(accountPluginsDir, name)).isDirectory();
|
|
18955
19271
|
} catch {
|
|
18956
19272
|
return false;
|
|
18957
19273
|
}
|
|
@@ -18994,7 +19310,7 @@ function computeActivePlugins(accountId) {
|
|
|
18994
19310
|
for (const name of emitNames) {
|
|
18995
19311
|
const dir = pluginDirs.get(name);
|
|
18996
19312
|
if (!dir) continue;
|
|
18997
|
-
const fm = readFrontmatter(
|
|
19313
|
+
const fm = readFrontmatter(join40(dir, "PLUGIN.md"));
|
|
18998
19314
|
if (!fm) continue;
|
|
18999
19315
|
const description = frontmatterField(`---
|
|
19000
19316
|
${fm}
|
|
@@ -19011,7 +19327,7 @@ ${fm}
|
|
|
19011
19327
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
19012
19328
|
);
|
|
19013
19329
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
19014
|
-
const hasSource = existsSync34(
|
|
19330
|
+
const hasSource = existsSync34(join40(dir, "mcp/dist/index.js")) || existsSync34(join40(dir, "mcp/src/index.ts"));
|
|
19015
19331
|
if (hasSource) {
|
|
19016
19332
|
console.warn(
|
|
19017
19333
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -19021,7 +19337,7 @@ ${fm}
|
|
|
19021
19337
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
19022
19338
|
const skills = [];
|
|
19023
19339
|
for (const relPath of skillPaths) {
|
|
19024
|
-
const skillPath =
|
|
19340
|
+
const skillPath = join40(dir, relPath);
|
|
19025
19341
|
const skillFm = readFrontmatter(skillPath);
|
|
19026
19342
|
if (!skillFm) continue;
|
|
19027
19343
|
const skillName = frontmatterField(`---
|
|
@@ -19065,7 +19381,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
19065
19381
|
const out = [];
|
|
19066
19382
|
for (const file of entries2.sort()) {
|
|
19067
19383
|
if (!file.endsWith(".md")) continue;
|
|
19068
|
-
const fm = readFrontmatter(
|
|
19384
|
+
const fm = readFrontmatter(join40(specialistsDir, file));
|
|
19069
19385
|
if (!fm) continue;
|
|
19070
19386
|
const wrapped = `---
|
|
19071
19387
|
${fm}
|
|
@@ -19159,7 +19475,7 @@ function resolveTunnelUrl() {
|
|
|
19159
19475
|
if (!state) return null;
|
|
19160
19476
|
return `https://${hostname2}.${state.domain}`;
|
|
19161
19477
|
}
|
|
19162
|
-
var
|
|
19478
|
+
var TAG28 = "[claude-session-manager:wrapper]";
|
|
19163
19479
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
19164
19480
|
const auth = await ensureAuth();
|
|
19165
19481
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -19177,12 +19493,12 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
19177
19493
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
19178
19494
|
const ownerMs = Date.now() - ownerStart;
|
|
19179
19495
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
19180
|
-
console.log(`${
|
|
19496
|
+
console.log(`${TAG28} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
19181
19497
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
19182
19498
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
19183
19499
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
19184
19500
|
const tunnelUrl = resolveTunnelUrl();
|
|
19185
|
-
console.log(`${
|
|
19501
|
+
console.log(`${TAG28} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
19186
19502
|
const upstreamPayload = JSON.stringify({
|
|
19187
19503
|
senderId: args.senderId,
|
|
19188
19504
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -19209,24 +19525,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
19209
19525
|
// unshapely values.
|
|
19210
19526
|
conversationNodeId: args.conversationNodeId
|
|
19211
19527
|
});
|
|
19212
|
-
console.log(`${
|
|
19528
|
+
console.log(`${TAG28} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
19213
19529
|
const forwardStart = Date.now();
|
|
19214
19530
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
19215
19531
|
method: "POST",
|
|
19216
19532
|
headers: { "content-type": "application/json" },
|
|
19217
19533
|
body: upstreamPayload
|
|
19218
19534
|
}).catch((err) => {
|
|
19219
|
-
console.error(`${
|
|
19535
|
+
console.error(`${TAG28} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
19220
19536
|
return null;
|
|
19221
19537
|
});
|
|
19222
19538
|
if (!upstream) return {
|
|
19223
19539
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
19224
19540
|
claudeSessionId: null
|
|
19225
19541
|
};
|
|
19226
|
-
console.log(`${
|
|
19542
|
+
console.log(`${TAG28} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
19227
19543
|
if (args.initialMessage) {
|
|
19228
19544
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
19229
|
-
console.log(`${
|
|
19545
|
+
console.log(`${TAG28} initial-message-inlined bytes=${inputBytes}`);
|
|
19230
19546
|
}
|
|
19231
19547
|
const bodyText = await upstream.text().catch(() => "");
|
|
19232
19548
|
let claudeSessionId = null;
|
|
@@ -19261,7 +19577,7 @@ app23.post("/", async (c) => {
|
|
|
19261
19577
|
if (refusal) return refusal;
|
|
19262
19578
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
19263
19579
|
if (!senderId) {
|
|
19264
|
-
console.error(`${
|
|
19580
|
+
console.error(`${TAG28} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
19265
19581
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
19266
19582
|
}
|
|
19267
19583
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -19270,7 +19586,7 @@ app23.post("/", async (c) => {
|
|
|
19270
19586
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
19271
19587
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
19272
19588
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
19273
|
-
console.log(`${
|
|
19589
|
+
console.log(`${TAG28} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
19274
19590
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
19275
19591
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
19276
19592
|
senderId,
|
|
@@ -19289,14 +19605,14 @@ app23.post("/", async (c) => {
|
|
|
19289
19605
|
claudeSessionId,
|
|
19290
19606
|
senderId
|
|
19291
19607
|
);
|
|
19292
|
-
console.log(`${
|
|
19608
|
+
console.log(`${TAG28} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
19293
19609
|
return response;
|
|
19294
19610
|
});
|
|
19295
19611
|
var claude_sessions_default = app23;
|
|
19296
19612
|
|
|
19297
19613
|
// server/routes/admin/log-ingest.ts
|
|
19298
19614
|
init_dist();
|
|
19299
|
-
var
|
|
19615
|
+
var TAG29 = "[log-ingest]";
|
|
19300
19616
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
19301
19617
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
19302
19618
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -19307,7 +19623,7 @@ function isLoopbackAddr2(addr) {
|
|
|
19307
19623
|
app24.post("/", async (c) => {
|
|
19308
19624
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
19309
19625
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
19310
|
-
console.error(`${
|
|
19626
|
+
console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
19311
19627
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
19312
19628
|
}
|
|
19313
19629
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -19316,7 +19632,7 @@ app24.post("/", async (c) => {
|
|
|
19316
19632
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
19317
19633
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
19318
19634
|
if (offender !== void 0) {
|
|
19319
|
-
console.error(`${
|
|
19635
|
+
console.error(`${TAG29} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
19320
19636
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
19321
19637
|
}
|
|
19322
19638
|
}
|
|
@@ -19354,9 +19670,9 @@ init_dist();
|
|
|
19354
19670
|
init_sidebar_sessions();
|
|
19355
19671
|
init_claude_agent();
|
|
19356
19672
|
init_account_scope();
|
|
19357
|
-
import { join as
|
|
19673
|
+
import { join as join41 } from "path";
|
|
19358
19674
|
init_channel_key();
|
|
19359
|
-
var
|
|
19675
|
+
var TAG30 = "[blocked-tool-notify]";
|
|
19360
19676
|
function isLoopbackAddr3(addr) {
|
|
19361
19677
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
19362
19678
|
}
|
|
@@ -19374,18 +19690,18 @@ Answer the permission card in the session's PTY or in Claude Desktop. Some check
|
|
|
19374
19690
|
async function sendWhatsApp(account, to, text) {
|
|
19375
19691
|
const res = resolveSocket(account.accountId);
|
|
19376
19692
|
if (!res.ok) {
|
|
19377
|
-
console.error(`${
|
|
19693
|
+
console.error(`${TAG30} op=socket-unavailable accountId=${account.accountId} reason=${res.reason}`);
|
|
19378
19694
|
return false;
|
|
19379
19695
|
}
|
|
19380
19696
|
const sent = await sendTextMessage(res.sock, to, text, { accountId: res.accountId });
|
|
19381
|
-
if (!sent.success) console.error(`${
|
|
19697
|
+
if (!sent.success) console.error(`${TAG30} op=send-failed to=${to} error=${sent.error ?? "unknown"}`);
|
|
19382
19698
|
return sent.success === true;
|
|
19383
19699
|
}
|
|
19384
19700
|
var app25 = new Hono();
|
|
19385
19701
|
app25.post("/", async (c) => {
|
|
19386
19702
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
19387
19703
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
19388
|
-
console.error(`${
|
|
19704
|
+
console.error(`${TAG30} op=reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
19389
19705
|
return c.json({ error: "session-blocked-loopback-only" }, 403);
|
|
19390
19706
|
}
|
|
19391
19707
|
let body = {};
|
|
@@ -19402,17 +19718,17 @@ app25.post("/", async (c) => {
|
|
|
19402
19718
|
if (!tool) return c.json({ error: "tool-required" }, 400);
|
|
19403
19719
|
const text = blockedNotificationText({ sessionId, agentId, tool, blockedForMs });
|
|
19404
19720
|
const projectDir = findSessionProjectDir(sessionId);
|
|
19405
|
-
const meta = projectDir ? readSidecarMeta(
|
|
19721
|
+
const meta = projectDir ? readSidecarMeta(join41(projectDir, `${sessionId}.meta.json`)) : { role: null, channel: null, senderId: null, accountId: null };
|
|
19406
19722
|
const account = validateAccountId2(meta.accountId ?? "");
|
|
19407
19723
|
if (!account) {
|
|
19408
19724
|
console.error(
|
|
19409
|
-
`${
|
|
19725
|
+
`${TAG30} op=account-unresolved sessionId=${sessionId.slice(0, 8)} sidecarAccountId=${meta.accountId ?? "none"}`
|
|
19410
19726
|
);
|
|
19411
19727
|
return c.json({ delivered: false, channel: "none" }, 200);
|
|
19412
19728
|
}
|
|
19413
19729
|
if (meta.role === "admin" && meta.channel === "whatsapp" && meta.senderId) {
|
|
19414
19730
|
const delivered2 = await sendWhatsApp(account, meta.senderId, text);
|
|
19415
|
-
console.error(`${
|
|
19731
|
+
console.error(`${TAG30} op=notify sessionId=${sessionId.slice(0, 8)} channel=whatsapp delivered=${delivered2}`);
|
|
19416
19732
|
return c.json({ delivered: delivered2, channel: "whatsapp" }, 200);
|
|
19417
19733
|
}
|
|
19418
19734
|
if (meta.role === "admin" && meta.channel === "telegram" && meta.senderId) {
|
|
@@ -19422,11 +19738,11 @@ app25.post("/", async (c) => {
|
|
|
19422
19738
|
const chatId = Number(parsed.senderId);
|
|
19423
19739
|
if (resolved.kind === "one" && Number.isFinite(chatId)) {
|
|
19424
19740
|
const res = await sendTelegramText(resolved.entry.token, chatId, text);
|
|
19425
|
-
console.error(`${
|
|
19741
|
+
console.error(`${TAG30} op=notify sessionId=${sessionId.slice(0, 8)} channel=telegram delivered=${res.ok}`);
|
|
19426
19742
|
return c.json({ delivered: res.ok, channel: "telegram" }, 200);
|
|
19427
19743
|
}
|
|
19428
19744
|
console.error(
|
|
19429
|
-
`${
|
|
19745
|
+
`${TAG30} op=telegram-unresolved sessionId=${sessionId.slice(0, 8)} botId=${parsed.botId} kind=${resolved.kind}`
|
|
19430
19746
|
);
|
|
19431
19747
|
}
|
|
19432
19748
|
}
|
|
@@ -19436,7 +19752,7 @@ app25.post("/", async (c) => {
|
|
|
19436
19752
|
if (await sendWhatsApp(account, phone, text)) delivered = true;
|
|
19437
19753
|
}
|
|
19438
19754
|
console.error(
|
|
19439
|
-
`${
|
|
19755
|
+
`${TAG30} op=notify sessionId=${sessionId.slice(0, 8)} channel=house-admin phones=${phones.length} delivered=${delivered}`
|
|
19440
19756
|
);
|
|
19441
19757
|
return c.json({ delivered, channel: "house-admin" }, 200);
|
|
19442
19758
|
});
|
|
@@ -19475,18 +19791,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
19475
19791
|
]);
|
|
19476
19792
|
var app26 = new Hono();
|
|
19477
19793
|
app26.post("/", async (c) => {
|
|
19478
|
-
const
|
|
19794
|
+
const TAG62 = "[admin:events]";
|
|
19479
19795
|
let body;
|
|
19480
19796
|
try {
|
|
19481
19797
|
body = await c.req.json();
|
|
19482
19798
|
} catch (err) {
|
|
19483
19799
|
const detail = err instanceof Error ? err.message : String(err);
|
|
19484
|
-
console.error(`${
|
|
19800
|
+
console.error(`${TAG62} reject reason=body-not-json detail=${detail}`);
|
|
19485
19801
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
19486
19802
|
}
|
|
19487
19803
|
const event = typeof body.event === "string" ? body.event : "";
|
|
19488
19804
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
19489
|
-
console.error(`${
|
|
19805
|
+
console.error(`${TAG62} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
19490
19806
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
19491
19807
|
}
|
|
19492
19808
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -19609,10 +19925,10 @@ init_claude_agent();
|
|
|
19609
19925
|
init_data_path();
|
|
19610
19926
|
init_sidebar_sessions();
|
|
19611
19927
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync36 } from "fs";
|
|
19612
|
-
import { readdir as readdir4, readFile as readFile9, stat as stat6, mkdir as
|
|
19928
|
+
import { readdir as readdir4, readFile as readFile9, stat as stat6, mkdir as mkdir3, unlink as unlink3, rename as rename3, rmdir } from "fs/promises";
|
|
19613
19929
|
import { realpathSync as realpathSync7 } from "fs";
|
|
19614
19930
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
19615
|
-
import { basename as basename13, dirname as dirname15, join as
|
|
19931
|
+
import { basename as basename13, dirname as dirname15, join as join43, relative as relative6, resolve as resolve28, sep as sep9 } from "path";
|
|
19616
19932
|
import { Readable as Readable2 } from "stream";
|
|
19617
19933
|
init_attachments();
|
|
19618
19934
|
|
|
@@ -19936,7 +20252,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
19936
20252
|
init_data_path();
|
|
19937
20253
|
init_neo4j_store();
|
|
19938
20254
|
import * as fsp from "fs/promises";
|
|
19939
|
-
import { resolve as resolve27, relative as relative5, join as
|
|
20255
|
+
import { resolve as resolve27, relative as relative5, join as join42, basename as basename12, extname, sep as sep8 } from "path";
|
|
19940
20256
|
import { tmpdir as tmpdir3 } from "os";
|
|
19941
20257
|
import { execFile } from "child_process";
|
|
19942
20258
|
import { promisify } from "util";
|
|
@@ -20018,7 +20334,7 @@ async function extractPdf(absolute) {
|
|
|
20018
20334
|
return stdout.trim();
|
|
20019
20335
|
}
|
|
20020
20336
|
async function ocrPdf(absolute) {
|
|
20021
|
-
const outPdf =
|
|
20337
|
+
const outPdf = join42(tmpdir3(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
20022
20338
|
try {
|
|
20023
20339
|
await execFileAsync(
|
|
20024
20340
|
"ocrmypdf",
|
|
@@ -20080,7 +20396,7 @@ async function readDisplayName(absolute) {
|
|
|
20080
20396
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
20081
20397
|
if (base === `${stem}.meta.json`) return null;
|
|
20082
20398
|
try {
|
|
20083
|
-
const raw = await fsp.readFile(
|
|
20399
|
+
const raw = await fsp.readFile(join42(dir, `${stem}.meta.json`), "utf-8");
|
|
20084
20400
|
const meta = JSON.parse(raw);
|
|
20085
20401
|
const dn = meta.displayName ?? meta.filename;
|
|
20086
20402
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -20101,7 +20417,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
20101
20417
|
for (const entry of entries2) {
|
|
20102
20418
|
if (entry.isSymbolicLink()) continue;
|
|
20103
20419
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
20104
|
-
const abs =
|
|
20420
|
+
const abs = join42(root, entry.name);
|
|
20105
20421
|
if (entry.isDirectory()) {
|
|
20106
20422
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
20107
20423
|
if (!sub.clean) clean = false;
|
|
@@ -20477,7 +20793,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
20477
20793
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
20478
20794
|
async function readMeta2(absDir, baseName) {
|
|
20479
20795
|
try {
|
|
20480
|
-
const raw = await readFile9(
|
|
20796
|
+
const raw = await readFile9(join43(absDir, `${baseName}.meta.json`), "utf8");
|
|
20481
20797
|
const parsed = JSON.parse(raw);
|
|
20482
20798
|
if (typeof parsed?.filename === "string") {
|
|
20483
20799
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -20532,7 +20848,7 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
20532
20848
|
}
|
|
20533
20849
|
async function enrich(absolute, entry, accountNames) {
|
|
20534
20850
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
20535
|
-
const dirAbs =
|
|
20851
|
+
const dirAbs = join43(absolute, entry.name);
|
|
20536
20852
|
const meta = await readMeta2(dirAbs, entry.name);
|
|
20537
20853
|
if (meta?.filename) {
|
|
20538
20854
|
const servable = await servableFilesIn(dirAbs, entry.name);
|
|
@@ -20541,7 +20857,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
20541
20857
|
let size = null;
|
|
20542
20858
|
let modifiedAt = entry.modifiedAt;
|
|
20543
20859
|
try {
|
|
20544
|
-
const st = await stat6(
|
|
20860
|
+
const st = await stat6(join43(dirAbs, innerName));
|
|
20545
20861
|
size = st.size;
|
|
20546
20862
|
modifiedAt = st.mtime.toISOString();
|
|
20547
20863
|
} catch {
|
|
@@ -20750,7 +21066,7 @@ app27.get("/", requireAdminSession, async (c) => {
|
|
|
20750
21066
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
20751
21067
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
20752
21068
|
try {
|
|
20753
|
-
const entryPath =
|
|
21069
|
+
const entryPath = join43(absolute, name);
|
|
20754
21070
|
const s = await stat6(entryPath);
|
|
20755
21071
|
entries2.push({
|
|
20756
21072
|
name,
|
|
@@ -20779,7 +21095,7 @@ app27.get("/", requireAdminSession, async (c) => {
|
|
|
20779
21095
|
const displayPath = buildDisplayPath(relPath, accountNames);
|
|
20780
21096
|
if (groupReq || isAccountRoot(relPath)) {
|
|
20781
21097
|
const acctId = relPath.split("/")[1] ?? accountId;
|
|
20782
|
-
const schemaMd = await readFile9(
|
|
21098
|
+
const schemaMd = await readFile9(join43(absolute, "SCHEMA.md"), "utf8").catch(() => null);
|
|
20783
21099
|
const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
|
|
20784
21100
|
console.error(
|
|
20785
21101
|
`[data-schema] op=classify account=${acctId} status=${groups.parsed ? "ok" : "parse-failed"} reason=${groups.reason} entries=${entries2.length} home=${groups.home.join(",") || "none"} system=${groups.system.length} unknown=${groups.unknown.join(",") || "none"}`
|
|
@@ -20817,7 +21133,7 @@ app27.get("/", requireAdminSession, async (c) => {
|
|
|
20817
21133
|
for (const name of homeDirs) {
|
|
20818
21134
|
const base = byName.get(name);
|
|
20819
21135
|
try {
|
|
20820
|
-
const dirents = await readdir4(
|
|
21136
|
+
const dirents = await readdir4(join43(absolute, name), { withFileTypes: true });
|
|
20821
21137
|
const visible = dirents.filter((d) => !d.name.startsWith("."));
|
|
20822
21138
|
visible.sort((a, b) => {
|
|
20823
21139
|
const ad = a.isDirectory() ? 0 : 1;
|
|
@@ -20882,7 +21198,7 @@ app27.get("/download", requireAdminSession, async (c) => {
|
|
|
20882
21198
|
console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
|
|
20883
21199
|
return c.json({ error: "Not found" }, 404);
|
|
20884
21200
|
}
|
|
20885
|
-
const meta = readSidecarMeta(
|
|
21201
|
+
const meta = readSidecarMeta(join43(projectDir, `${sessionId}.meta.json`));
|
|
20886
21202
|
if (!meta.accountId || meta.accountId !== accountId) {
|
|
20887
21203
|
console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
20888
21204
|
return c.json({ error: "Not found" }, 404);
|
|
@@ -20977,7 +21293,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
20977
21293
|
const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
|
|
20978
21294
|
for (const d of dirents) {
|
|
20979
21295
|
if (d.isSymbolicLink()) continue;
|
|
20980
|
-
const child =
|
|
21296
|
+
const child = join43(dirAbsolute, d.name);
|
|
20981
21297
|
if (d.isDirectory()) {
|
|
20982
21298
|
yield* walkRegularFiles(child);
|
|
20983
21299
|
continue;
|
|
@@ -21087,7 +21403,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
21087
21403
|
const base = resolveSharedOrOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
21088
21404
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
21089
21405
|
const relDir = relpath ? dirname15(relpath) : ".";
|
|
21090
|
-
const destRel = relDir === "." ? base.relative :
|
|
21406
|
+
const destRel = relDir === "." ? base.relative : join43(base.relative, relDir);
|
|
21091
21407
|
if ((0, import_dist.isSharedPath)(destRel)) {
|
|
21092
21408
|
const gate = gateSharedWrite(base.absolute, destRel, accountId, "POST /api/admin/files/upload");
|
|
21093
21409
|
if (!gate.ok) return { ok: false, status: gate.status, error: gate.error };
|
|
@@ -21104,7 +21420,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
21104
21420
|
const destDir = relDir === "." ? base.absolute : resolve28(base.absolute, relDir);
|
|
21105
21421
|
const destPath = resolve28(destDir, finalName);
|
|
21106
21422
|
if (relpath) {
|
|
21107
|
-
const firstCreated = await
|
|
21423
|
+
const firstCreated = await mkdir3(destDir, { recursive: true });
|
|
21108
21424
|
if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
|
|
21109
21425
|
} else {
|
|
21110
21426
|
const info = await stat6(destDir).catch(() => null);
|
|
@@ -21147,7 +21463,7 @@ app27.post("/upload", requireAdminSession, async (c) => {
|
|
|
21147
21463
|
console.error(`[data-upload] op=request uid=${uid} account=${accountId} dir="${destRel}" token=${token} rel="${relpath ?? ""}" declaredBytes=${declaredBytes}`);
|
|
21148
21464
|
const ceiling = dataUploadCeiling();
|
|
21149
21465
|
const tmpDir = resolve28(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
|
|
21150
|
-
await
|
|
21466
|
+
await mkdir3(tmpDir, { recursive: true });
|
|
21151
21467
|
const tmpPath = resolve28(tmpDir, `${uid}.part`);
|
|
21152
21468
|
const out = createWriteStream2(tmpPath);
|
|
21153
21469
|
const t0 = Date.now();
|
|
@@ -21296,7 +21612,7 @@ async function handleChunkUpload(c, accountId) {
|
|
|
21296
21612
|
const target = await resolveUploadTarget(c, accountId, uploadId);
|
|
21297
21613
|
if (!target.ok) return c.json({ error: target.error }, target.status);
|
|
21298
21614
|
const tmpDir = resolve28(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
|
|
21299
|
-
await
|
|
21615
|
+
await mkdir3(tmpDir, { recursive: true });
|
|
21300
21616
|
const tmpPath = resolve28(tmpDir, `${uploadId}.part`);
|
|
21301
21617
|
const out = createWriteStream2(tmpPath);
|
|
21302
21618
|
const state2 = {
|
|
@@ -21473,7 +21789,7 @@ app27.delete("/", requireAdminSession, async (c) => {
|
|
|
21473
21789
|
const dot = base.lastIndexOf(".");
|
|
21474
21790
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
21475
21791
|
const containerDir = dirname15(absolute);
|
|
21476
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
21792
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join43(containerDir, `${stem}.meta.json`) : null;
|
|
21477
21793
|
const isAttachmentContainer = UUID_RE3.test(stem) && basename13(containerDir) === stem;
|
|
21478
21794
|
await unlink3(absolute);
|
|
21479
21795
|
if (sidecarPath) {
|
|
@@ -21483,7 +21799,7 @@ app27.delete("/", requireAdminSession, async (c) => {
|
|
|
21483
21799
|
}
|
|
21484
21800
|
}
|
|
21485
21801
|
if (isAttachmentContainer) {
|
|
21486
|
-
await unlink3(
|
|
21802
|
+
await unlink3(join43(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
21487
21803
|
});
|
|
21488
21804
|
await rmdir(containerDir).catch(() => {
|
|
21489
21805
|
});
|
|
@@ -21542,7 +21858,7 @@ app27.post("/folder", requireAdminSession, async (c) => {
|
|
|
21542
21858
|
try {
|
|
21543
21859
|
const info = await stat6(parent.absolute);
|
|
21544
21860
|
if (!info.isDirectory()) return c.json({ error: "Parent is not a directory" }, 400);
|
|
21545
|
-
await
|
|
21861
|
+
await mkdir3(newAbs, { recursive: false });
|
|
21546
21862
|
} catch (err) {
|
|
21547
21863
|
const code = err.code;
|
|
21548
21864
|
if (code === "EEXIST") return c.json({ error: "A file or folder with that name already exists" }, 409);
|
|
@@ -22609,7 +22925,7 @@ function isHiddenByDefault(label) {
|
|
|
22609
22925
|
// server/lib/top-level-labels.ts
|
|
22610
22926
|
var import_dist6 = __toESM(require_dist5(), 1);
|
|
22611
22927
|
import { readdirSync as readdirSync24, readFileSync as readFileSync36 } from "fs";
|
|
22612
|
-
import { join as
|
|
22928
|
+
import { join as join44, resolve as resolve29 } from "path";
|
|
22613
22929
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
22614
22930
|
/* @__PURE__ */ new Set([
|
|
22615
22931
|
// Base-schema infra (schema-base.md has no top-level section).
|
|
@@ -22713,7 +23029,7 @@ function parseTopLevelLabels(content) {
|
|
|
22713
23029
|
}
|
|
22714
23030
|
function resolveReferencesDir() {
|
|
22715
23031
|
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
22716
|
-
return
|
|
23032
|
+
return join44(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
22717
23033
|
}
|
|
22718
23034
|
return resolve29(import.meta.dirname, "../../../plugins/memory/references");
|
|
22719
23035
|
}
|
|
@@ -22723,7 +23039,7 @@ function parseTableTopLevelLabels(referencesDir) {
|
|
|
22723
23039
|
try {
|
|
22724
23040
|
const fileNames = readdirSync24(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
|
|
22725
23041
|
for (const fileName of fileNames) {
|
|
22726
|
-
const content = readFileSync36(
|
|
23042
|
+
const content = readFileSync36(join44(referencesDir, fileName), "utf-8");
|
|
22727
23043
|
const parsed = parseTopLevelLabels(content);
|
|
22728
23044
|
if (parsed.length > 0) contributingFiles.push(fileName);
|
|
22729
23045
|
for (const label of parsed) labels.add(label);
|
|
@@ -24503,24 +24819,24 @@ init_session_store();
|
|
|
24503
24819
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
24504
24820
|
|
|
24505
24821
|
// server/wa-descriptor.ts
|
|
24506
|
-
import { resolve as resolve31, join as
|
|
24822
|
+
import { resolve as resolve31, join as join45 } from "path";
|
|
24507
24823
|
function waGatewayUrl() {
|
|
24508
24824
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
24509
24825
|
}
|
|
24510
24826
|
function waServerPath() {
|
|
24511
|
-
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
24827
|
+
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
|
|
24512
24828
|
}
|
|
24513
24829
|
function waChannelDescriptor(senderId) {
|
|
24514
24830
|
return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
|
|
24515
24831
|
}
|
|
24516
24832
|
|
|
24517
24833
|
// server/telegram-descriptor.ts
|
|
24518
|
-
import { resolve as resolve32, join as
|
|
24834
|
+
import { resolve as resolve32, join as join46 } from "path";
|
|
24519
24835
|
function telegramGatewayUrl() {
|
|
24520
24836
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
24521
24837
|
}
|
|
24522
24838
|
function telegramServerPath() {
|
|
24523
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ??
|
|
24839
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ?? join46(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
24524
24840
|
}
|
|
24525
24841
|
function telegramChannelDescriptor(senderId) {
|
|
24526
24842
|
return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
|
|
@@ -24817,10 +25133,10 @@ var system_stats_default = app42;
|
|
|
24817
25133
|
init_dist();
|
|
24818
25134
|
init_neo4j_store();
|
|
24819
25135
|
import { existsSync as existsSync38, readFileSync as readFileSync37 } from "fs";
|
|
24820
|
-
import { resolve as resolve33, join as
|
|
25136
|
+
import { resolve as resolve33, join as join47 } from "path";
|
|
24821
25137
|
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve33(process.cwd(), "..");
|
|
24822
25138
|
var brandHostname = "maxy";
|
|
24823
|
-
var brandJsonPath =
|
|
25139
|
+
var brandJsonPath = join47(PLATFORM_ROOT4, "config", "brand.json");
|
|
24824
25140
|
if (existsSync38(brandJsonPath)) {
|
|
24825
25141
|
try {
|
|
24826
25142
|
const brand = JSON.parse(readFileSync37(brandJsonPath, "utf-8"));
|
|
@@ -25082,7 +25398,7 @@ function managerLogFollowUrl(sessionId, opts) {
|
|
|
25082
25398
|
}
|
|
25083
25399
|
|
|
25084
25400
|
// server/routes/admin/linkedin-ingest.ts
|
|
25085
|
-
var
|
|
25401
|
+
var TAG31 = "[linkedin-ingest-route]";
|
|
25086
25402
|
var UUID4 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
25087
25403
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
25088
25404
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -25207,28 +25523,28 @@ app44.post("/", requireIngestToken, async (c) => {
|
|
|
25207
25523
|
try {
|
|
25208
25524
|
body = await c.req.json();
|
|
25209
25525
|
} catch {
|
|
25210
|
-
console.error(
|
|
25526
|
+
console.error(TAG31 + " rejected status=400 reason=schema:body-not-json");
|
|
25211
25527
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
25212
25528
|
}
|
|
25213
25529
|
const v = validate2(body);
|
|
25214
25530
|
if (!v.ok) {
|
|
25215
|
-
console.error(
|
|
25531
|
+
console.error(TAG31 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
25216
25532
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
25217
25533
|
}
|
|
25218
25534
|
const envelope = v.envelope;
|
|
25219
25535
|
const senderId = c.var.ingestAccountId ?? "";
|
|
25220
25536
|
if (!senderId) {
|
|
25221
|
-
console.error(
|
|
25537
|
+
console.error(TAG31 + " rejected status=500 reason=admin-account-not-resolved");
|
|
25222
25538
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
25223
25539
|
}
|
|
25224
25540
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
25225
25541
|
console.log(
|
|
25226
|
-
|
|
25542
|
+
TAG31 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
25227
25543
|
);
|
|
25228
25544
|
const initialMessage = buildInitialMessage(envelope);
|
|
25229
25545
|
const spawnStart = Date.now();
|
|
25230
25546
|
const sessionId = randomUUID9();
|
|
25231
|
-
console.log(
|
|
25547
|
+
console.log(TAG31 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
25232
25548
|
const spawned = await managerRcSpawn({
|
|
25233
25549
|
sessionId,
|
|
25234
25550
|
initialMessage,
|
|
@@ -25241,12 +25557,12 @@ app44.post("/", requireIngestToken, async (c) => {
|
|
|
25241
25557
|
});
|
|
25242
25558
|
if ("error" in spawned) {
|
|
25243
25559
|
console.error(
|
|
25244
|
-
|
|
25560
|
+
TAG31 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
25245
25561
|
);
|
|
25246
25562
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
25247
25563
|
}
|
|
25248
25564
|
console.log(
|
|
25249
|
-
|
|
25565
|
+
TAG31 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
25250
25566
|
);
|
|
25251
25567
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
25252
25568
|
});
|
|
@@ -25256,7 +25572,7 @@ var linkedin_ingest_default = app44;
|
|
|
25256
25572
|
init_dist();
|
|
25257
25573
|
init_neo4j_store();
|
|
25258
25574
|
import neo4j2 from "neo4j-driver";
|
|
25259
|
-
var
|
|
25575
|
+
var TAG32 = "[post-turn-context]";
|
|
25260
25576
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
25261
25577
|
"embedding",
|
|
25262
25578
|
"passwordHash",
|
|
@@ -25298,7 +25614,7 @@ var app45 = new Hono();
|
|
|
25298
25614
|
app45.get("/", async (c) => {
|
|
25299
25615
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
25300
25616
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
25301
|
-
console.error(`${
|
|
25617
|
+
console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
25302
25618
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
25303
25619
|
}
|
|
25304
25620
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -25307,7 +25623,7 @@ app45.get("/", async (c) => {
|
|
|
25307
25623
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
25308
25624
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
25309
25625
|
if (offender !== void 0) {
|
|
25310
|
-
console.error(`${
|
|
25626
|
+
console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
25311
25627
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
25312
25628
|
}
|
|
25313
25629
|
}
|
|
@@ -25339,7 +25655,7 @@ app45.get("/", async (c) => {
|
|
|
25339
25655
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
25340
25656
|
const total = Date.now() - started2;
|
|
25341
25657
|
console.log(
|
|
25342
|
-
`${
|
|
25658
|
+
`${TAG32} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
25343
25659
|
);
|
|
25344
25660
|
return c.json({
|
|
25345
25661
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -25348,7 +25664,7 @@ app45.get("/", async (c) => {
|
|
|
25348
25664
|
const elapsed = Date.now() - started2;
|
|
25349
25665
|
const message = err instanceof Error ? err.message : String(err);
|
|
25350
25666
|
console.error(
|
|
25351
|
-
`${
|
|
25667
|
+
`${TAG32} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
25352
25668
|
);
|
|
25353
25669
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
25354
25670
|
} finally {
|
|
@@ -25465,7 +25781,7 @@ function formatPreviousContext(writes) {
|
|
|
25465
25781
|
}
|
|
25466
25782
|
|
|
25467
25783
|
// server/routes/admin/public-session-context.ts
|
|
25468
|
-
var
|
|
25784
|
+
var TAG33 = "[public-session-context]";
|
|
25469
25785
|
function isLoopbackAddr5(addr) {
|
|
25470
25786
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
25471
25787
|
}
|
|
@@ -25473,7 +25789,7 @@ var app46 = new Hono();
|
|
|
25473
25789
|
app46.get("/", async (c) => {
|
|
25474
25790
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
25475
25791
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
25476
|
-
console.error(`${
|
|
25792
|
+
console.error(`${TAG33} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
25477
25793
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
25478
25794
|
}
|
|
25479
25795
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -25482,7 +25798,7 @@ app46.get("/", async (c) => {
|
|
|
25482
25798
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
25483
25799
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
25484
25800
|
if (offender !== void 0) {
|
|
25485
|
-
console.error(`${
|
|
25801
|
+
console.error(`${TAG33} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
25486
25802
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
25487
25803
|
}
|
|
25488
25804
|
}
|
|
@@ -25496,14 +25812,14 @@ app46.get("/", async (c) => {
|
|
|
25496
25812
|
const writes = await fetchSliceWrites(session, sliceToken, accountId);
|
|
25497
25813
|
const total = Date.now() - started2;
|
|
25498
25814
|
console.log(
|
|
25499
|
-
`${
|
|
25815
|
+
`${TAG33} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
25500
25816
|
);
|
|
25501
25817
|
return c.json({ writes });
|
|
25502
25818
|
} catch (err) {
|
|
25503
25819
|
const elapsed = Date.now() - started2;
|
|
25504
25820
|
const message = err instanceof Error ? err.message : String(err);
|
|
25505
25821
|
console.error(
|
|
25506
|
-
`${
|
|
25822
|
+
`${TAG33} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
25507
25823
|
);
|
|
25508
25824
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
25509
25825
|
} finally {
|
|
@@ -25525,7 +25841,7 @@ function getWebchatGateway() {
|
|
|
25525
25841
|
}
|
|
25526
25842
|
|
|
25527
25843
|
// server/routes/admin/public-session-exit.ts
|
|
25528
|
-
var
|
|
25844
|
+
var TAG34 = "[public-session-exit-route]";
|
|
25529
25845
|
function isLoopbackAddr6(addr) {
|
|
25530
25846
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
25531
25847
|
}
|
|
@@ -25533,7 +25849,7 @@ var app47 = new Hono();
|
|
|
25533
25849
|
app47.post("/", async (c) => {
|
|
25534
25850
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
25535
25851
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
25536
|
-
console.error(`${
|
|
25852
|
+
console.error(`${TAG34} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
25537
25853
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
25538
25854
|
}
|
|
25539
25855
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -25542,7 +25858,7 @@ app47.post("/", async (c) => {
|
|
|
25542
25858
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
25543
25859
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
25544
25860
|
if (offender !== void 0) {
|
|
25545
|
-
console.error(`${
|
|
25861
|
+
console.error(`${TAG34} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
25546
25862
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
25547
25863
|
}
|
|
25548
25864
|
}
|
|
@@ -25556,7 +25872,7 @@ app47.post("/", async (c) => {
|
|
|
25556
25872
|
if (!sessionId) return c.json({ error: "sessionId required" }, 400);
|
|
25557
25873
|
const gateway = getWebchatGateway();
|
|
25558
25874
|
if (!gateway) {
|
|
25559
|
-
console.error(`${
|
|
25875
|
+
console.error(`${TAG34} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
|
|
25560
25876
|
return c.json({ error: "webchat-gateway-unset" }, 503);
|
|
25561
25877
|
}
|
|
25562
25878
|
gateway.handlePublicSessionExit(sessionId);
|
|
@@ -25566,7 +25882,7 @@ var public_session_exit_default = app47;
|
|
|
25566
25882
|
|
|
25567
25883
|
// server/routes/admin/access-session-evict.ts
|
|
25568
25884
|
init_dist();
|
|
25569
|
-
var
|
|
25885
|
+
var TAG35 = "[access-session-evict]";
|
|
25570
25886
|
function isLoopbackAddr7(addr) {
|
|
25571
25887
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
25572
25888
|
}
|
|
@@ -25574,7 +25890,7 @@ var app48 = new Hono();
|
|
|
25574
25890
|
app48.post("/", async (c) => {
|
|
25575
25891
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
25576
25892
|
if (!isLoopbackAddr7(remoteAddr)) {
|
|
25577
|
-
console.error(`${
|
|
25893
|
+
console.error(`${TAG35} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
25578
25894
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
25579
25895
|
}
|
|
25580
25896
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -25583,7 +25899,7 @@ app48.post("/", async (c) => {
|
|
|
25583
25899
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
25584
25900
|
const offender = tokens.find((t) => !isLoopbackAddr7(t));
|
|
25585
25901
|
if (offender !== void 0) {
|
|
25586
|
-
console.error(`${
|
|
25902
|
+
console.error(`${TAG35} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
25587
25903
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
25588
25904
|
}
|
|
25589
25905
|
}
|
|
@@ -25596,7 +25912,7 @@ app48.post("/", async (c) => {
|
|
|
25596
25912
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
25597
25913
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
25598
25914
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
25599
|
-
console.log(`${
|
|
25915
|
+
console.log(`${TAG35} grantId=${grantId} dropped=${dropped}`);
|
|
25600
25916
|
return c.json({ ok: true, dropped });
|
|
25601
25917
|
});
|
|
25602
25918
|
var access_session_evict_default = app48;
|
|
@@ -25604,7 +25920,7 @@ var access_session_evict_default = app48;
|
|
|
25604
25920
|
// server/routes/admin/enrol-person.ts
|
|
25605
25921
|
init_dist();
|
|
25606
25922
|
init_normalize();
|
|
25607
|
-
var
|
|
25923
|
+
var TAG36 = "[enrol]";
|
|
25608
25924
|
function isLoopbackAddr8(addr) {
|
|
25609
25925
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
25610
25926
|
}
|
|
@@ -25613,7 +25929,7 @@ var app49 = new Hono();
|
|
|
25613
25929
|
app49.post("/", async (c) => {
|
|
25614
25930
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
25615
25931
|
if (!isLoopbackAddr8(remoteAddr)) {
|
|
25616
|
-
console.error(`${
|
|
25932
|
+
console.error(`${TAG36} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
25617
25933
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
25618
25934
|
}
|
|
25619
25935
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -25622,7 +25938,7 @@ app49.post("/", async (c) => {
|
|
|
25622
25938
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
25623
25939
|
const offender = tokens.find((t) => !isLoopbackAddr8(t));
|
|
25624
25940
|
if (offender !== void 0) {
|
|
25625
|
-
console.error(`${
|
|
25941
|
+
console.error(`${TAG36} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
25626
25942
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
25627
25943
|
}
|
|
25628
25944
|
}
|
|
@@ -25647,7 +25963,7 @@ app49.post("/", async (c) => {
|
|
|
25647
25963
|
}
|
|
25648
25964
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
25649
25965
|
if (!accountId) {
|
|
25650
|
-
console.error(`${
|
|
25966
|
+
console.error(`${TAG36} op=person result=no-account-id`);
|
|
25651
25967
|
return c.json({ error: "no-account-id" }, 500);
|
|
25652
25968
|
}
|
|
25653
25969
|
let personId;
|
|
@@ -25655,7 +25971,7 @@ app49.post("/", async (c) => {
|
|
|
25655
25971
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
25656
25972
|
} catch (err) {
|
|
25657
25973
|
console.error(
|
|
25658
|
-
`${
|
|
25974
|
+
`${TAG36} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
25659
25975
|
);
|
|
25660
25976
|
return c.json({ error: "enrol-failed" }, 500);
|
|
25661
25977
|
}
|
|
@@ -25665,11 +25981,11 @@ app49.post("/", async (c) => {
|
|
|
25665
25981
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
25666
25982
|
} catch (err) {
|
|
25667
25983
|
console.error(
|
|
25668
|
-
`${
|
|
25984
|
+
`${TAG36} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
25669
25985
|
);
|
|
25670
25986
|
}
|
|
25671
25987
|
console.log(
|
|
25672
|
-
`${
|
|
25988
|
+
`${TAG36} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
25673
25989
|
);
|
|
25674
25990
|
return c.json({ personId, grant }, 200);
|
|
25675
25991
|
});
|
|
@@ -25776,7 +26092,7 @@ init_account_scope();
|
|
|
25776
26092
|
init_neo4j_store();
|
|
25777
26093
|
import { existsSync as existsSync40 } from "fs";
|
|
25778
26094
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
25779
|
-
import { join as
|
|
26095
|
+
import { join as join49 } from "path";
|
|
25780
26096
|
|
|
25781
26097
|
// server/lib/calendar-ics.ts
|
|
25782
26098
|
var CRLF = "\r\n";
|
|
@@ -25877,7 +26193,7 @@ function countVEvents(ics) {
|
|
|
25877
26193
|
|
|
25878
26194
|
// server/lib/calendar-availability.ts
|
|
25879
26195
|
import { readFileSync as readFileSync39 } from "fs";
|
|
25880
|
-
import { join as
|
|
26196
|
+
import { join as join48 } from "path";
|
|
25881
26197
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
25882
26198
|
var REQUIRED_KEYS = [
|
|
25883
26199
|
"timezone",
|
|
@@ -25886,7 +26202,7 @@ var REQUIRED_KEYS = [
|
|
|
25886
26202
|
"weekly"
|
|
25887
26203
|
];
|
|
25888
26204
|
function readAvailabilityConfig(accountDir) {
|
|
25889
|
-
const path =
|
|
26205
|
+
const path = join48(accountDir, AVAILABILITY_FILENAME);
|
|
25890
26206
|
let raw;
|
|
25891
26207
|
try {
|
|
25892
26208
|
raw = readFileSync39(path, "utf-8");
|
|
@@ -26444,7 +26760,7 @@ app51.get("/booking-link", requireAdminSession, (c) => {
|
|
|
26444
26760
|
}
|
|
26445
26761
|
const id82 = account.accountId.slice(0, 8);
|
|
26446
26762
|
try {
|
|
26447
|
-
if (!existsSync40(
|
|
26763
|
+
if (!existsSync40(join49(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
26448
26764
|
console.log(`[calendar] op=booking-link accountId=${id82} bookingDomain=none source=availability-config`);
|
|
26449
26765
|
return c.json({ bookingDomain: null });
|
|
26450
26766
|
}
|
|
@@ -26467,7 +26783,7 @@ init_dist();
|
|
|
26467
26783
|
init_helpers();
|
|
26468
26784
|
init_account_scope();
|
|
26469
26785
|
import { existsSync as existsSync41, readFileSync as readFileSync40 } from "fs";
|
|
26470
|
-
import { join as
|
|
26786
|
+
import { join as join50 } from "path";
|
|
26471
26787
|
var app52 = new Hono();
|
|
26472
26788
|
var PORTAL_FILENAME = "data-portal.json";
|
|
26473
26789
|
app52.get("/portal-link", requireAdminSession, (c) => {
|
|
@@ -26478,7 +26794,7 @@ app52.get("/portal-link", requireAdminSession, (c) => {
|
|
|
26478
26794
|
}
|
|
26479
26795
|
const id82 = account.accountId.slice(0, 8);
|
|
26480
26796
|
try {
|
|
26481
|
-
const path =
|
|
26797
|
+
const path = join50(account.accountDir, PORTAL_FILENAME);
|
|
26482
26798
|
if (!existsSync41(path)) {
|
|
26483
26799
|
console.log(`[data-portal] op=portal-link accountId=${id82} portalDomain=none source=data-portal-config`);
|
|
26484
26800
|
return c.json({ portalDomain: null });
|
|
@@ -27608,7 +27924,7 @@ init_helpers();
|
|
|
27608
27924
|
init_claude_agent();
|
|
27609
27925
|
init_route_cache();
|
|
27610
27926
|
init_neo4j_store();
|
|
27611
|
-
import { basename as basename15, join as
|
|
27927
|
+
import { basename as basename15, join as join51 } from "path";
|
|
27612
27928
|
|
|
27613
27929
|
// app/lib/time-entry-format.ts
|
|
27614
27930
|
function secondsBetween(startIso, endIso) {
|
|
@@ -27629,7 +27945,7 @@ function toNum(v) {
|
|
|
27629
27945
|
|
|
27630
27946
|
// server/routes/admin/tasks-list.ts
|
|
27631
27947
|
init_sidebar_sessions();
|
|
27632
|
-
var
|
|
27948
|
+
var TAG37 = "[task-timer]";
|
|
27633
27949
|
var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
|
|
27634
27950
|
var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
27635
27951
|
var app55 = new Hono();
|
|
@@ -27637,12 +27953,12 @@ app55.get("/", requireAdminSession, async (c) => {
|
|
|
27637
27953
|
const cacheKey = c.var.cacheKey;
|
|
27638
27954
|
const accountId = getAccountIdForSession(cacheKey);
|
|
27639
27955
|
if (!accountId) {
|
|
27640
|
-
console.error(`${
|
|
27956
|
+
console.error(`${TAG37} op=list auth-rejected reason="no account for session"`);
|
|
27641
27957
|
return c.json({ error: "Account not found for session" }, 401);
|
|
27642
27958
|
}
|
|
27643
27959
|
const cacheStart = Date.now();
|
|
27644
27960
|
const cached3 = await getOrCompute("tasks-list", accountId, () => computeTaskList(accountId));
|
|
27645
|
-
console.log(`${
|
|
27961
|
+
console.log(`${TAG37} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
|
|
27646
27962
|
if (cached3.value === null) {
|
|
27647
27963
|
return c.json({ error: "tasks-list-failed" }, 500);
|
|
27648
27964
|
}
|
|
@@ -27743,13 +28059,13 @@ async function computeTaskList(accountId) {
|
|
|
27743
28059
|
orphans = orphanResult.records.length > 0 ? toNum(orphanResult.records[0].get("orphans")) : 0;
|
|
27744
28060
|
} catch (err) {
|
|
27745
28061
|
console.error(
|
|
27746
|
-
`${
|
|
28062
|
+
`${TAG37} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
27747
28063
|
);
|
|
27748
28064
|
orphans = -1;
|
|
27749
28065
|
}
|
|
27750
28066
|
if (orphans > 0) {
|
|
27751
28067
|
console.error(
|
|
27752
|
-
`${
|
|
28068
|
+
`${TAG37} op=session-orphans account=${accountId} orphans=${orphans} detail="task marked for a session spawn that never linked; the spawned session is unreachable from its row"`
|
|
27753
28069
|
);
|
|
27754
28070
|
}
|
|
27755
28071
|
let orphanEntries = 0;
|
|
@@ -27768,14 +28084,14 @@ async function computeTaskList(accountId) {
|
|
|
27768
28084
|
orphanAdjustments = orphanTime.records.length > 0 ? toNum(orphanTime.records[0].get("orphanAdjustments")) : 0;
|
|
27769
28085
|
} catch (err) {
|
|
27770
28086
|
console.error(
|
|
27771
|
-
`${
|
|
28087
|
+
`${TAG37} op=orphan-time-records-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
27772
28088
|
);
|
|
27773
28089
|
orphanEntries = -1;
|
|
27774
28090
|
orphanAdjustments = -1;
|
|
27775
28091
|
}
|
|
27776
28092
|
if (orphanEntries > 0 || orphanAdjustments > 0) {
|
|
27777
28093
|
console.error(
|
|
27778
|
-
`${
|
|
28094
|
+
`${TAG37} op=orphan-time-records account=${accountId} orphanEntries=${orphanEntries} orphanAdjustments=${orphanAdjustments} detail="time records whose task no longer exists; something removed the task without its records"`
|
|
27779
28095
|
);
|
|
27780
28096
|
}
|
|
27781
28097
|
const linkedIds = [...open3, ...completed].map((r) => r.sessionId).filter((s) => s !== null);
|
|
@@ -27785,10 +28101,10 @@ async function computeTaskList(accountId) {
|
|
|
27785
28101
|
dangling = 0;
|
|
27786
28102
|
} else if (cfg !== null) {
|
|
27787
28103
|
try {
|
|
27788
|
-
const walk = enumerateJsonlsWithSkips(
|
|
28104
|
+
const walk = enumerateJsonlsWithSkips(join51(cfg, "projects"));
|
|
27789
28105
|
if (walk.skipped > 0) {
|
|
27790
28106
|
console.error(
|
|
27791
|
-
`${
|
|
28107
|
+
`${TAG37} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
|
|
27792
28108
|
);
|
|
27793
28109
|
dangling = null;
|
|
27794
28110
|
} else {
|
|
@@ -27797,28 +28113,28 @@ async function computeTaskList(accountId) {
|
|
|
27797
28113
|
}
|
|
27798
28114
|
} catch (err) {
|
|
27799
28115
|
console.error(
|
|
27800
|
-
`${
|
|
28116
|
+
`${TAG37} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
27801
28117
|
);
|
|
27802
28118
|
dangling = null;
|
|
27803
28119
|
}
|
|
27804
28120
|
}
|
|
27805
28121
|
if (dangling !== null && dangling > 0) {
|
|
27806
28122
|
console.error(
|
|
27807
|
-
`${
|
|
28123
|
+
`${TAG37} op=session-dangling account=${accountId} dangling=${dangling} linked=${linkedIds.length} detail="a task links a session with no JSONL on disk; clicking it will not resume"`
|
|
27808
28124
|
);
|
|
27809
28125
|
}
|
|
27810
28126
|
const returned = result.records.length;
|
|
27811
28127
|
if (returned < graphTotal) {
|
|
27812
28128
|
console.error(
|
|
27813
|
-
`${
|
|
28129
|
+
`${TAG37} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
|
|
27814
28130
|
);
|
|
27815
28131
|
}
|
|
27816
28132
|
console.log(
|
|
27817
|
-
`${
|
|
28133
|
+
`${TAG37} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned} sessionLinked=${sessionLinked} sessionOrphans=${orphans < 0 ? "n/a" : orphans} sessionDangling=${dangling === null ? "n/a" : dangling}`
|
|
27818
28134
|
);
|
|
27819
28135
|
return { open: open3, completed };
|
|
27820
28136
|
} catch (err) {
|
|
27821
|
-
console.error(`${
|
|
28137
|
+
console.error(`${TAG37} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
27822
28138
|
return null;
|
|
27823
28139
|
} finally {
|
|
27824
28140
|
await session.close();
|
|
@@ -27833,7 +28149,7 @@ init_claude_agent();
|
|
|
27833
28149
|
init_route_cache();
|
|
27834
28150
|
init_neo4j_store();
|
|
27835
28151
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
27836
|
-
var
|
|
28152
|
+
var TAG38 = "[task-timer]";
|
|
27837
28153
|
var app56 = new Hono();
|
|
27838
28154
|
app56.post("/", requireAdminSession, async (c) => {
|
|
27839
28155
|
const cacheKey = c.var.cacheKey;
|
|
@@ -27848,7 +28164,7 @@ app56.post("/", requireAdminSession, async (c) => {
|
|
|
27848
28164
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
27849
28165
|
if (!taskId) {
|
|
27850
28166
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
27851
|
-
console.error(`${
|
|
28167
|
+
console.error(`${TAG38} op=timer-start rejected reason=${reason} account=${accountId}`);
|
|
27852
28168
|
return c.json({ error: "taskId required" }, 400);
|
|
27853
28169
|
}
|
|
27854
28170
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -27859,7 +28175,7 @@ app56.post("/", requireAdminSession, async (c) => {
|
|
|
27859
28175
|
{ taskId, accountId }
|
|
27860
28176
|
);
|
|
27861
28177
|
if (target.records.length === 0) {
|
|
27862
|
-
console.error(`${
|
|
28178
|
+
console.error(`${TAG38} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
27863
28179
|
return c.json({ error: "task-not-found" }, 404);
|
|
27864
28180
|
}
|
|
27865
28181
|
const open3 = await session.run(
|
|
@@ -27871,7 +28187,7 @@ app56.post("/", requireAdminSession, async (c) => {
|
|
|
27871
28187
|
const priorEntryId = open3.records[0]?.get("entryId");
|
|
27872
28188
|
const priorStartedAt = open3.records[0]?.get("startedAt");
|
|
27873
28189
|
if (priorEntryId) {
|
|
27874
|
-
console.log(`${
|
|
28190
|
+
console.log(`${TAG38} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
27875
28191
|
invalidate("tasks-list", accountId);
|
|
27876
28192
|
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
27877
28193
|
}
|
|
@@ -27882,11 +28198,11 @@ app56.post("/", requireAdminSession, async (c) => {
|
|
|
27882
28198
|
CREATE (te)-[:LOGGED_AGAINST]->(t)`,
|
|
27883
28199
|
{ taskId, accountId, entryId, now }
|
|
27884
28200
|
);
|
|
27885
|
-
console.log(`${
|
|
28201
|
+
console.log(`${TAG38} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
|
|
27886
28202
|
invalidate("tasks-list", accountId);
|
|
27887
28203
|
return c.json({ ok: true, running: true, entryId, startedAt: now });
|
|
27888
28204
|
} catch (err) {
|
|
27889
|
-
console.error(`${
|
|
28205
|
+
console.error(`${TAG38} op=start error="${err instanceof Error ? err.message : String(err)}"`);
|
|
27890
28206
|
return c.json({ error: "task-timer-start-failed" }, 500);
|
|
27891
28207
|
} finally {
|
|
27892
28208
|
await session.close();
|
|
@@ -27901,7 +28217,7 @@ init_claude_agent();
|
|
|
27901
28217
|
init_route_cache();
|
|
27902
28218
|
init_neo4j_store();
|
|
27903
28219
|
import neo4j4 from "neo4j-driver";
|
|
27904
|
-
var
|
|
28220
|
+
var TAG39 = "[task-timer]";
|
|
27905
28221
|
var app57 = new Hono();
|
|
27906
28222
|
app57.post("/", requireAdminSession, async (c) => {
|
|
27907
28223
|
const cacheKey = c.var.cacheKey;
|
|
@@ -27916,7 +28232,7 @@ app57.post("/", requireAdminSession, async (c) => {
|
|
|
27916
28232
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
27917
28233
|
if (!taskId) {
|
|
27918
28234
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
27919
|
-
console.error(`${
|
|
28235
|
+
console.error(`${TAG39} op=timer-stop rejected reason=${reason} account=${accountId}`);
|
|
27920
28236
|
return c.json({ error: "taskId required" }, 400);
|
|
27921
28237
|
}
|
|
27922
28238
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -27937,7 +28253,7 @@ app57.post("/", requireAdminSession, async (c) => {
|
|
|
27937
28253
|
{ taskId, accountId }
|
|
27938
28254
|
);
|
|
27939
28255
|
const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
|
|
27940
|
-
console.log(`${
|
|
28256
|
+
console.log(`${TAG39} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
|
|
27941
28257
|
invalidate("tasks-list", accountId);
|
|
27942
28258
|
return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
|
|
27943
28259
|
}
|
|
@@ -27961,12 +28277,12 @@ app57.post("/", requireAdminSession, async (c) => {
|
|
|
27961
28277
|
const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
|
|
27962
28278
|
const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
|
|
27963
28279
|
const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
|
|
27964
|
-
console.log(`${
|
|
27965
|
-
console.log(`${
|
|
28280
|
+
console.log(`${TAG39} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
|
|
28281
|
+
console.log(`${TAG39} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
|
|
27966
28282
|
invalidate("tasks-list", accountId);
|
|
27967
28283
|
return c.json({ ok: true, running: false, seconds, secondsLogged });
|
|
27968
28284
|
} catch (err) {
|
|
27969
|
-
console.error(`${
|
|
28285
|
+
console.error(`${TAG39} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
|
|
27970
28286
|
return c.json({ error: "task-timer-stop-failed" }, 500);
|
|
27971
28287
|
} finally {
|
|
27972
28288
|
await session.close();
|
|
@@ -27980,7 +28296,7 @@ init_helpers();
|
|
|
27980
28296
|
init_claude_agent();
|
|
27981
28297
|
init_route_cache();
|
|
27982
28298
|
init_neo4j_store();
|
|
27983
|
-
var
|
|
28299
|
+
var TAG40 = "[task-timer]";
|
|
27984
28300
|
var app58 = new Hono();
|
|
27985
28301
|
app58.post("/", requireAdminSession, async (c) => {
|
|
27986
28302
|
const cacheKey = c.var.cacheKey;
|
|
@@ -27995,7 +28311,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
27995
28311
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
27996
28312
|
if (!taskId) {
|
|
27997
28313
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
27998
|
-
console.error(`${
|
|
28314
|
+
console.error(`${TAG40} op=complete rejected reason=${reason} account=${accountId}`);
|
|
27999
28315
|
return c.json({ error: "taskId required" }, 400);
|
|
28000
28316
|
}
|
|
28001
28317
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -28011,11 +28327,11 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
28011
28327
|
return c.json({ error: "task-not-found" }, 404);
|
|
28012
28328
|
}
|
|
28013
28329
|
const secondsLogged = toNum(result.records[0].get("secondsLogged"));
|
|
28014
|
-
console.log(`${
|
|
28330
|
+
console.log(`${TAG40} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
|
|
28015
28331
|
invalidate("tasks-list", accountId);
|
|
28016
28332
|
return c.json({ ok: true, status: "completed", secondsLogged });
|
|
28017
28333
|
} catch (err) {
|
|
28018
|
-
console.error(`${
|
|
28334
|
+
console.error(`${TAG40} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
|
|
28019
28335
|
return c.json({ error: "task-complete-failed" }, 500);
|
|
28020
28336
|
} finally {
|
|
28021
28337
|
await session.close();
|
|
@@ -28031,7 +28347,7 @@ init_route_cache();
|
|
|
28031
28347
|
init_neo4j_store();
|
|
28032
28348
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
28033
28349
|
import neo4j5 from "neo4j-driver";
|
|
28034
|
-
var
|
|
28350
|
+
var TAG41 = "[task-time-adjust]";
|
|
28035
28351
|
var app59 = new Hono();
|
|
28036
28352
|
app59.post("/", requireAdminSession, async (c) => {
|
|
28037
28353
|
const cacheKey = c.var.cacheKey;
|
|
@@ -28041,23 +28357,23 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
28041
28357
|
try {
|
|
28042
28358
|
body = await c.req.json();
|
|
28043
28359
|
} catch {
|
|
28044
|
-
console.error(`${
|
|
28360
|
+
console.error(`${TAG41} op=reject reason=bad-json`);
|
|
28045
28361
|
return c.json({ error: "invalid-json" }, 400);
|
|
28046
28362
|
}
|
|
28047
28363
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
28048
28364
|
if (!taskId) {
|
|
28049
28365
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
28050
|
-
console.error(`${
|
|
28366
|
+
console.error(`${TAG41} op=time-adjust rejected reason=${reason} account=${accountId}`);
|
|
28051
28367
|
return c.json({ error: "taskId required" }, 400);
|
|
28052
28368
|
}
|
|
28053
28369
|
const newSeconds = body.newSeconds;
|
|
28054
28370
|
if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
|
|
28055
|
-
console.error(`${
|
|
28371
|
+
console.error(`${TAG41} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
|
|
28056
28372
|
return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
|
|
28057
28373
|
}
|
|
28058
28374
|
const adjustmentId = randomUUID12();
|
|
28059
28375
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28060
|
-
console.log(`${
|
|
28376
|
+
console.log(`${TAG41} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
|
|
28061
28377
|
const session = getSession();
|
|
28062
28378
|
try {
|
|
28063
28379
|
const guard = await session.run(
|
|
@@ -28067,12 +28383,12 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
28067
28383
|
{ taskId, accountId }
|
|
28068
28384
|
);
|
|
28069
28385
|
if (guard.records.length === 0) {
|
|
28070
|
-
console.error(`${
|
|
28386
|
+
console.error(`${TAG41} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
28071
28387
|
return c.json({ error: "task-not-found" }, 404);
|
|
28072
28388
|
}
|
|
28073
28389
|
const openCount = toNum(guard.records[0].get("openCount"));
|
|
28074
28390
|
if (openCount > 0) {
|
|
28075
|
-
console.error(`${
|
|
28391
|
+
console.error(`${TAG41} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
28076
28392
|
return c.json({ error: "task-timer-running" }, 409);
|
|
28077
28393
|
}
|
|
28078
28394
|
const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
|
|
@@ -28098,11 +28414,11 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
28098
28414
|
}
|
|
28099
28415
|
);
|
|
28100
28416
|
const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
|
|
28101
|
-
console.log(`${
|
|
28417
|
+
console.log(`${TAG41} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
|
|
28102
28418
|
invalidate("tasks-list", accountId);
|
|
28103
28419
|
return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
|
|
28104
28420
|
} catch (err) {
|
|
28105
|
-
console.error(`${
|
|
28421
|
+
console.error(`${TAG41} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
28106
28422
|
return c.json({ error: "task-time-adjust-failed" }, 500);
|
|
28107
28423
|
} finally {
|
|
28108
28424
|
await session.close();
|
|
@@ -28117,7 +28433,7 @@ init_claude_agent();
|
|
|
28117
28433
|
init_route_cache();
|
|
28118
28434
|
init_neo4j_store();
|
|
28119
28435
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
28120
|
-
var
|
|
28436
|
+
var TAG42 = "[task-delete]";
|
|
28121
28437
|
var app60 = new Hono();
|
|
28122
28438
|
app60.post("/", requireAdminSession, async (c) => {
|
|
28123
28439
|
const cacheKey = c.var.cacheKey;
|
|
@@ -28127,18 +28443,18 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
28127
28443
|
try {
|
|
28128
28444
|
body = await c.req.json();
|
|
28129
28445
|
} catch {
|
|
28130
|
-
console.error(`${
|
|
28446
|
+
console.error(`${TAG42} op=reject reason=bad-json`);
|
|
28131
28447
|
return c.json({ error: "invalid-json" }, 400);
|
|
28132
28448
|
}
|
|
28133
28449
|
const deletionId = randomUUID13();
|
|
28134
28450
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
28135
28451
|
if (!taskId) {
|
|
28136
28452
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
28137
|
-
console.error(`${
|
|
28453
|
+
console.error(`${TAG42} op=reject reason=${reason} deletionId=${deletionId} accountId=${accountId}`);
|
|
28138
28454
|
return c.json({ error: "taskId required" }, 400);
|
|
28139
28455
|
}
|
|
28140
28456
|
console.log(
|
|
28141
|
-
`${
|
|
28457
|
+
`${TAG42} op=request deletionId=${deletionId} taskId=${taskId} accountId=${accountId} confirmed=${body.confirmed === true}`
|
|
28142
28458
|
);
|
|
28143
28459
|
const session = getSession();
|
|
28144
28460
|
try {
|
|
@@ -28154,18 +28470,18 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
28154
28470
|
{ taskId, accountId }
|
|
28155
28471
|
);
|
|
28156
28472
|
if (guard.records.length === 0) {
|
|
28157
|
-
console.error(`${
|
|
28473
|
+
console.error(`${TAG42} op=reject reason=no-task deletionId=${deletionId} taskId=${taskId} accountId=${accountId}`);
|
|
28158
28474
|
return c.json({ error: "task-not-found" }, 404);
|
|
28159
28475
|
}
|
|
28160
28476
|
const timeEntries = toNum(guard.records[0].get("timeEntries"));
|
|
28161
28477
|
const openCount = toNum(guard.records[0].get("openCount"));
|
|
28162
28478
|
const adjustments = toNum(guard.records[0].get("adjustments"));
|
|
28163
28479
|
console.log(
|
|
28164
|
-
`${
|
|
28480
|
+
`${TAG42} op=guard deletionId=${deletionId} taskId=${taskId} openCount=${openCount} timeEntries=${timeEntries} adjustments=${adjustments}`
|
|
28165
28481
|
);
|
|
28166
28482
|
if (openCount > 0) {
|
|
28167
28483
|
console.error(
|
|
28168
|
-
`${
|
|
28484
|
+
`${TAG42} op=reject reason=running deletionId=${deletionId} taskId=${taskId} openCount=${openCount}`
|
|
28169
28485
|
);
|
|
28170
28486
|
return c.json({ error: "task-timer-running" }, 409);
|
|
28171
28487
|
}
|
|
@@ -28201,18 +28517,18 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
28201
28517
|
const adjustmentsLeft = toNum(after.records[0]?.get("adjustmentsLeft"));
|
|
28202
28518
|
const remaining = taskLeft + entriesLeft + adjustmentsLeft;
|
|
28203
28519
|
console.log(
|
|
28204
|
-
`${
|
|
28520
|
+
`${TAG42} op=persisted deletionId=${deletionId} taskId=${taskId} tasksDeleted=${tasksDeleted} timeEntriesDeleted=${timeEntriesDeleted} adjustmentsDeleted=${adjustmentsDeleted} remaining=${remaining}`
|
|
28205
28521
|
);
|
|
28206
28522
|
if (remaining > 0) {
|
|
28207
28523
|
console.error(
|
|
28208
|
-
`${
|
|
28524
|
+
`${TAG42} op=incomplete deletionId=${deletionId} taskId=${taskId} taskLeft=${taskLeft} entriesLeft=${entriesLeft} adjustmentsLeft=${adjustmentsLeft} detail="the delete returned but rows for this taskId survive"`
|
|
28209
28525
|
);
|
|
28210
28526
|
}
|
|
28211
28527
|
invalidate("tasks-list", accountId);
|
|
28212
28528
|
return c.json({ ok: true, tasksDeleted, timeEntriesDeleted, adjustmentsDeleted, remaining });
|
|
28213
28529
|
} catch (err) {
|
|
28214
28530
|
console.error(
|
|
28215
|
-
`${
|
|
28531
|
+
`${TAG42} op=error deletionId=${deletionId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
28216
28532
|
);
|
|
28217
28533
|
return c.json({ error: "task-delete-failed" }, 500);
|
|
28218
28534
|
} finally {
|
|
@@ -28315,7 +28631,7 @@ async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
|
|
|
28315
28631
|
}
|
|
28316
28632
|
|
|
28317
28633
|
// server/routes/admin/task-assign.ts
|
|
28318
|
-
var
|
|
28634
|
+
var TAG43 = "[task-assign]";
|
|
28319
28635
|
var app61 = new Hono();
|
|
28320
28636
|
app61.post("/", requireAdminSession, async (c) => {
|
|
28321
28637
|
const cacheKey = c.var.cacheKey;
|
|
@@ -28330,7 +28646,7 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
28330
28646
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
28331
28647
|
if (!taskId) {
|
|
28332
28648
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
28333
|
-
console.error(`${
|
|
28649
|
+
console.error(`${TAG43} op=assign rejected reason=${reason} account=${accountId}`);
|
|
28334
28650
|
return c.json({ error: "taskId required" }, 400);
|
|
28335
28651
|
}
|
|
28336
28652
|
const rawAssignee = body.assigneeUserId;
|
|
@@ -28342,7 +28658,7 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
28342
28658
|
const { ids } = await resolveAllowedAssigneeIds(accountId);
|
|
28343
28659
|
if (!ids.has(assigneeUserId)) {
|
|
28344
28660
|
console.error(
|
|
28345
|
-
`${
|
|
28661
|
+
`${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
|
|
28346
28662
|
);
|
|
28347
28663
|
return c.json({ error: "assignee-not-in-roster" }, 403);
|
|
28348
28664
|
}
|
|
@@ -28364,7 +28680,7 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
28364
28680
|
`MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
|
|
28365
28681
|
{ taskId, accountId, now }
|
|
28366
28682
|
);
|
|
28367
|
-
console.log(`${
|
|
28683
|
+
console.log(`${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
|
|
28368
28684
|
invalidate("tasks-list", accountId);
|
|
28369
28685
|
return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
|
|
28370
28686
|
}
|
|
@@ -28380,7 +28696,7 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
28380
28696
|
);
|
|
28381
28697
|
if (set.records.length === 0) {
|
|
28382
28698
|
console.error(
|
|
28383
|
-
`${
|
|
28699
|
+
`${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
|
|
28384
28700
|
);
|
|
28385
28701
|
return c.json({ error: "assignee-no-admin-node" }, 409);
|
|
28386
28702
|
}
|
|
@@ -28388,12 +28704,12 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
28388
28704
|
const family = set.records[0].get("familyName") ?? null;
|
|
28389
28705
|
const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
|
|
28390
28706
|
console.log(
|
|
28391
|
-
`${
|
|
28707
|
+
`${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
|
|
28392
28708
|
);
|
|
28393
28709
|
invalidate("tasks-list", accountId);
|
|
28394
28710
|
return c.json({ ok: true, assigneeUserId, assigneeName });
|
|
28395
28711
|
} catch (err) {
|
|
28396
|
-
console.error(`${
|
|
28712
|
+
console.error(`${TAG43} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
|
|
28397
28713
|
return c.json({ error: "task-assign-failed" }, 500);
|
|
28398
28714
|
} finally {
|
|
28399
28715
|
await session.close();
|
|
@@ -28406,13 +28722,13 @@ init_dist();
|
|
|
28406
28722
|
init_helpers();
|
|
28407
28723
|
init_claude_agent();
|
|
28408
28724
|
init_neo4j_store();
|
|
28409
|
-
var
|
|
28725
|
+
var TAG44 = "[task-session]";
|
|
28410
28726
|
var app62 = new Hono();
|
|
28411
28727
|
app62.post("/", requireAdminSession, async (c) => {
|
|
28412
28728
|
const cacheKey = c.var.cacheKey;
|
|
28413
28729
|
const accountId = getAccountIdForSession(cacheKey);
|
|
28414
28730
|
if (!accountId) {
|
|
28415
|
-
console.error(`${
|
|
28731
|
+
console.error(`${TAG44} op=request auth-rejected reason="no account for session"`);
|
|
28416
28732
|
return c.json({ error: "Account not found for session" }, 401);
|
|
28417
28733
|
}
|
|
28418
28734
|
let body;
|
|
@@ -28424,7 +28740,7 @@ app62.post("/", requireAdminSession, async (c) => {
|
|
|
28424
28740
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
28425
28741
|
if (!taskId) {
|
|
28426
28742
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
28427
|
-
console.error(`${
|
|
28743
|
+
console.error(`${TAG44} op=request rejected reason=${reason} account=${accountId}`);
|
|
28428
28744
|
return c.json({ error: "taskId required" }, 400);
|
|
28429
28745
|
}
|
|
28430
28746
|
const session = getSession();
|
|
@@ -28438,14 +28754,14 @@ app62.post("/", requireAdminSession, async (c) => {
|
|
|
28438
28754
|
{ taskId, accountId }
|
|
28439
28755
|
);
|
|
28440
28756
|
if (found.records.length === 0) {
|
|
28441
|
-
console.error(`${
|
|
28757
|
+
console.error(`${TAG44} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
28442
28758
|
return c.json({ error: "task-not-found" }, 404);
|
|
28443
28759
|
}
|
|
28444
28760
|
const title = found.records[0].get("name") ?? "";
|
|
28445
28761
|
const sessionId = found.records[0].get("sessionId") ?? null;
|
|
28446
28762
|
const description = found.records[0].get("description") ?? "";
|
|
28447
28763
|
const notes = found.records[0].get("notes") ?? "";
|
|
28448
|
-
console.log(`${
|
|
28764
|
+
console.log(`${TAG44} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
|
|
28449
28765
|
if (sessionId !== null) return c.json({ sessionId, title, description, notes });
|
|
28450
28766
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28451
28767
|
const stamped = await session.run(
|
|
@@ -28455,10 +28771,10 @@ app62.post("/", requireAdminSession, async (c) => {
|
|
|
28455
28771
|
{ taskId, accountId, now }
|
|
28456
28772
|
);
|
|
28457
28773
|
const at = stamped.records[0]?.get("at") ?? void 0;
|
|
28458
|
-
console.log(`${
|
|
28774
|
+
console.log(`${TAG44} op=marker taskId=${taskId} stamped=${at !== void 0}`);
|
|
28459
28775
|
return c.json({ sessionId: null, title, description, notes });
|
|
28460
28776
|
} catch (err) {
|
|
28461
|
-
console.error(`${
|
|
28777
|
+
console.error(`${TAG44} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
28462
28778
|
return c.json({ error: "task-session-open-failed" }, 500);
|
|
28463
28779
|
} finally {
|
|
28464
28780
|
await session.close();
|
|
@@ -28472,13 +28788,13 @@ init_helpers();
|
|
|
28472
28788
|
init_claude_agent();
|
|
28473
28789
|
init_neo4j_store();
|
|
28474
28790
|
init_route_cache();
|
|
28475
|
-
var
|
|
28791
|
+
var TAG45 = "[task-session]";
|
|
28476
28792
|
var app63 = new Hono();
|
|
28477
28793
|
app63.post("/", requireAdminSession, async (c) => {
|
|
28478
28794
|
const cacheKey = c.var.cacheKey;
|
|
28479
28795
|
const accountId = getAccountIdForSession(cacheKey);
|
|
28480
28796
|
if (!accountId) {
|
|
28481
|
-
console.error(`${
|
|
28797
|
+
console.error(`${TAG45} op=link auth-rejected reason="no account for session"`);
|
|
28482
28798
|
return c.json({ error: "Account not found for session" }, 401);
|
|
28483
28799
|
}
|
|
28484
28800
|
let body;
|
|
@@ -28490,12 +28806,12 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
28490
28806
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
28491
28807
|
if (!taskId) {
|
|
28492
28808
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
28493
|
-
console.error(`${
|
|
28809
|
+
console.error(`${TAG45} op=link rejected reason=${reason} account=${accountId}`);
|
|
28494
28810
|
return c.json({ error: "taskId required" }, 400);
|
|
28495
28811
|
}
|
|
28496
28812
|
const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : "";
|
|
28497
28813
|
if (!sessionId) {
|
|
28498
|
-
console.error(`${
|
|
28814
|
+
console.error(`${TAG45} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
|
|
28499
28815
|
return c.json({ error: "sessionId required" }, 400);
|
|
28500
28816
|
}
|
|
28501
28817
|
const session = getSession();
|
|
@@ -28509,13 +28825,13 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
28509
28825
|
{ taskId, accountId, sessionId }
|
|
28510
28826
|
);
|
|
28511
28827
|
if (state.records.length === 0) {
|
|
28512
|
-
console.error(`${
|
|
28828
|
+
console.error(`${TAG45} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
28513
28829
|
return c.json({ error: "task-not-found" }, 404);
|
|
28514
28830
|
}
|
|
28515
28831
|
const conversationExists = state.records[0].get("conversationExists") === true;
|
|
28516
28832
|
const priorSessionIds = (state.records[0].get("priorSessionIds") ?? []).filter((s) => typeof s === "string");
|
|
28517
28833
|
if (!conversationExists) {
|
|
28518
|
-
console.error(`${
|
|
28834
|
+
console.error(`${TAG45} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
|
|
28519
28835
|
return c.json({ linked: false, created: false, repointedFrom: null });
|
|
28520
28836
|
}
|
|
28521
28837
|
const stale = priorSessionIds.filter((s) => s !== sessionId);
|
|
@@ -28541,18 +28857,18 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
28541
28857
|
const repointedFrom = stale.length > 0 ? stale[0] : null;
|
|
28542
28858
|
if (!linked) {
|
|
28543
28859
|
console.error(
|
|
28544
|
-
`${
|
|
28860
|
+
`${TAG45} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
|
|
28545
28861
|
);
|
|
28546
28862
|
return c.json({ linked: false, created: false, repointedFrom });
|
|
28547
28863
|
}
|
|
28548
28864
|
console.log(
|
|
28549
|
-
`${
|
|
28865
|
+
`${TAG45} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
|
|
28550
28866
|
);
|
|
28551
28867
|
invalidate("tasks-list", accountId);
|
|
28552
28868
|
return c.json({ linked: true, created, repointedFrom });
|
|
28553
28869
|
} catch (err) {
|
|
28554
28870
|
console.error(
|
|
28555
|
-
`${
|
|
28871
|
+
`${TAG45} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
|
|
28556
28872
|
);
|
|
28557
28873
|
return c.json({ error: "task-session-link-failed" }, 500);
|
|
28558
28874
|
} finally {
|
|
@@ -28565,21 +28881,21 @@ var task_session_link_default = app63;
|
|
|
28565
28881
|
init_dist();
|
|
28566
28882
|
init_helpers();
|
|
28567
28883
|
init_claude_agent();
|
|
28568
|
-
var
|
|
28884
|
+
var TAG46 = "[admin-users]";
|
|
28569
28885
|
var app64 = new Hono();
|
|
28570
28886
|
app64.get("/", requireAdminSession, async (c) => {
|
|
28571
28887
|
const cacheKey = c.var.cacheKey;
|
|
28572
28888
|
const accountId = getAccountIdForSession(cacheKey);
|
|
28573
28889
|
if (!accountId) {
|
|
28574
|
-
console.error(`${
|
|
28890
|
+
console.error(`${TAG46} op=list auth-rejected reason="no account for session"`);
|
|
28575
28891
|
return c.json({ error: "Account not found for session" }, 401);
|
|
28576
28892
|
}
|
|
28577
28893
|
try {
|
|
28578
28894
|
const users = await resolveAssignableAdmins(accountId);
|
|
28579
|
-
console.log(`${
|
|
28895
|
+
console.log(`${TAG46} op=list account=${accountId} count=${users.length}`);
|
|
28580
28896
|
return c.json({ ok: true, users });
|
|
28581
28897
|
} catch (err) {
|
|
28582
|
-
console.error(`${
|
|
28898
|
+
console.error(`${TAG46} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
28583
28899
|
return c.json({ error: "admin-users-list-failed" }, 500);
|
|
28584
28900
|
}
|
|
28585
28901
|
});
|
|
@@ -28593,7 +28909,7 @@ init_account();
|
|
|
28593
28909
|
init_neo4j_store();
|
|
28594
28910
|
init_src2();
|
|
28595
28911
|
import { resolve as resolve38 } from "path";
|
|
28596
|
-
var
|
|
28912
|
+
var TAG47 = "[admin:routines]";
|
|
28597
28913
|
function scopeFor(d, houseDir, houseAccountId) {
|
|
28598
28914
|
if (d.channel !== "whatsapp") return null;
|
|
28599
28915
|
if (d.label === "Account manager") return boundSubAccountFor(houseDir, d.destination);
|
|
@@ -28611,7 +28927,7 @@ var app65 = new Hono();
|
|
|
28611
28927
|
app65.get("/", requireAdminSession, async (c) => {
|
|
28612
28928
|
const accountId = getAccountIdForSession(c.var.cacheKey);
|
|
28613
28929
|
if (!accountId) {
|
|
28614
|
-
console.error(`${
|
|
28930
|
+
console.error(`${TAG47} op=destinations auth-rejected reason="no account for session"`);
|
|
28615
28931
|
return c.json({ error: "Account not found for session" }, 401);
|
|
28616
28932
|
}
|
|
28617
28933
|
let houseAccountId = null;
|
|
@@ -28619,7 +28935,7 @@ app65.get("/", requireAdminSession, async (c) => {
|
|
|
28619
28935
|
houseAccountId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
28620
28936
|
} catch (err) {
|
|
28621
28937
|
const message = err instanceof Error ? err.message : String(err);
|
|
28622
|
-
console.error(`${
|
|
28938
|
+
console.error(`${TAG47} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
|
|
28623
28939
|
}
|
|
28624
28940
|
const destinations = listDispatchDestinations({ accountsDir: ACCOUNTS_DIR, houseAccountId, accountId });
|
|
28625
28941
|
const houseDir = houseAccountId === null ? null : resolve38(ACCOUNTS_DIR, houseAccountId);
|
|
@@ -28670,7 +28986,7 @@ app65.get("/", requireAdminSession, async (c) => {
|
|
|
28670
28986
|
const scopes = [...byScope.keys()];
|
|
28671
28987
|
const nameScope = scopes.length === 0 ? "none" : scopes.every((s) => s === houseAccountId) ? "house" : scopes.some((s) => s === houseAccountId) ? "mixed" : "account";
|
|
28672
28988
|
console.log(
|
|
28673
|
-
`${
|
|
28989
|
+
`${TAG47} op=destinations account=${accountId.slice(0, 8)} count=${destinations.length} named=${named} unnamed=${destinations.length - named} nameScope=${nameScope}` + (houseAccountId === null ? " outcome=house-unresolved" : "") + (namesUnresolved === null ? "" : ` outcome=names-unresolved reason="${namesUnresolved}"`)
|
|
28674
28990
|
);
|
|
28675
28991
|
return c.json({ destinations });
|
|
28676
28992
|
});
|
|
@@ -28685,7 +29001,7 @@ import { readdirSync as readdirSync28 } from "fs";
|
|
|
28685
29001
|
init_neo4j_store();
|
|
28686
29002
|
init_loop_registry();
|
|
28687
29003
|
var app66 = new Hono();
|
|
28688
|
-
var
|
|
29004
|
+
var TAG48 = "[activity]";
|
|
28689
29005
|
function resolveHouseAccountId2(accounts) {
|
|
28690
29006
|
const houses = accounts.filter((a) => a.config.role === "house");
|
|
28691
29007
|
if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
|
|
@@ -28714,19 +29030,19 @@ app66.get("/", requireAdminSession, async (c) => {
|
|
|
28714
29030
|
const house = resolveHouseAccountId2(valid);
|
|
28715
29031
|
const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
|
|
28716
29032
|
console.log(
|
|
28717
|
-
`${
|
|
29033
|
+
`${TAG48} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
|
|
28718
29034
|
);
|
|
28719
29035
|
if (!isHouse) {
|
|
28720
29036
|
const reason = house.accountId === null ? house.reason : "not-house";
|
|
28721
29037
|
console.error(
|
|
28722
|
-
`${
|
|
29038
|
+
`${TAG48} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
|
|
28723
29039
|
);
|
|
28724
29040
|
return c.json({ error: "house-only" }, 403);
|
|
28725
29041
|
}
|
|
28726
|
-
console.log(`${
|
|
29042
|
+
console.log(`${TAG48} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
|
|
28727
29043
|
const onDisk = countAccountDirsOnDisk();
|
|
28728
29044
|
console.log(
|
|
28729
|
-
`${
|
|
29045
|
+
`${TAG48} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
|
|
28730
29046
|
);
|
|
28731
29047
|
const start = Date.now();
|
|
28732
29048
|
let res;
|
|
@@ -28742,17 +29058,17 @@ app66.get("/", requireAdminSession, async (c) => {
|
|
|
28742
29058
|
});
|
|
28743
29059
|
} catch (err) {
|
|
28744
29060
|
console.error(
|
|
28745
|
-
`${
|
|
29061
|
+
`${TAG48} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
|
|
28746
29062
|
);
|
|
28747
29063
|
return c.json({ error: "manager-unreachable" }, 502);
|
|
28748
29064
|
}
|
|
28749
29065
|
if (res.status !== 200) {
|
|
28750
|
-
console.error(`${
|
|
29066
|
+
console.error(`${TAG48} op=manager-fail req=${req} reason=status status=${res.status}`);
|
|
28751
29067
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
28752
29068
|
}
|
|
28753
29069
|
const body = await res.json().catch(() => null);
|
|
28754
29070
|
if (!body || !Array.isArray(body.rows)) {
|
|
28755
|
-
console.error(`${
|
|
29071
|
+
console.error(`${TAG48} op=manager-fail req=${req} reason=bad-json`);
|
|
28756
29072
|
return c.json({ error: "manager-bad-json" }, 502);
|
|
28757
29073
|
}
|
|
28758
29074
|
const rows = body.rows;
|
|
@@ -28763,10 +29079,10 @@ app66.get("/", requireAdminSession, async (c) => {
|
|
|
28763
29079
|
const ageNull = rows.filter((r) => r.ageMs === null).length;
|
|
28764
29080
|
const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
|
|
28765
29081
|
console.log(
|
|
28766
|
-
`${
|
|
29082
|
+
`${TAG48} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
|
|
28767
29083
|
);
|
|
28768
29084
|
console.log(
|
|
28769
|
-
`${
|
|
29085
|
+
`${TAG48} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
|
|
28770
29086
|
);
|
|
28771
29087
|
const names = {};
|
|
28772
29088
|
await Promise.all(
|
|
@@ -28785,7 +29101,7 @@ app66.get("/", requireAdminSession, async (c) => {
|
|
|
28785
29101
|
return acc;
|
|
28786
29102
|
}, {});
|
|
28787
29103
|
console.log(
|
|
28788
|
-
`${
|
|
29104
|
+
`${TAG48} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
|
|
28789
29105
|
);
|
|
28790
29106
|
return c.json({
|
|
28791
29107
|
rows,
|
|
@@ -28879,7 +29195,7 @@ init_dist();
|
|
|
28879
29195
|
|
|
28880
29196
|
// server/routes/access/verify-token.ts
|
|
28881
29197
|
init_dist();
|
|
28882
|
-
var
|
|
29198
|
+
var TAG49 = "[access-verify]";
|
|
28883
29199
|
var MINT_TAG = "[access-session-mint]";
|
|
28884
29200
|
var COOKIE_NAME = "__access_session";
|
|
28885
29201
|
var app68 = new Hono();
|
|
@@ -28898,39 +29214,39 @@ app68.post("/", async (c) => {
|
|
|
28898
29214
|
}
|
|
28899
29215
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
28900
29216
|
if (rateMsg) {
|
|
28901
|
-
console.error(`${
|
|
29217
|
+
console.error(`${TAG49} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
28902
29218
|
return c.json({ error: rateMsg }, 429);
|
|
28903
29219
|
}
|
|
28904
29220
|
const grant = await findGrantByMagicToken(token);
|
|
28905
29221
|
if (!grant) {
|
|
28906
29222
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
28907
|
-
console.error(`${
|
|
29223
|
+
console.error(`${TAG49} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
28908
29224
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
28909
29225
|
}
|
|
28910
29226
|
if (grant.agentSlug !== agentSlug) {
|
|
28911
29227
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
28912
29228
|
console.error(
|
|
28913
|
-
`${
|
|
29229
|
+
`${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
28914
29230
|
);
|
|
28915
29231
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
28916
29232
|
}
|
|
28917
29233
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
28918
29234
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
28919
29235
|
console.error(
|
|
28920
|
-
`${
|
|
29236
|
+
`${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
28921
29237
|
);
|
|
28922
29238
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
28923
29239
|
}
|
|
28924
29240
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
28925
29241
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
28926
29242
|
console.error(
|
|
28927
|
-
`${
|
|
29243
|
+
`${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
28928
29244
|
);
|
|
28929
29245
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
28930
29246
|
}
|
|
28931
29247
|
if (!grant.sliceToken) {
|
|
28932
29248
|
console.error(
|
|
28933
|
-
`${
|
|
29249
|
+
`${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
28934
29250
|
);
|
|
28935
29251
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
28936
29252
|
}
|
|
@@ -28946,12 +29262,12 @@ app68.post("/", async (c) => {
|
|
|
28946
29262
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
28947
29263
|
} catch (err) {
|
|
28948
29264
|
console.error(
|
|
28949
|
-
`${
|
|
29265
|
+
`${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
28950
29266
|
);
|
|
28951
29267
|
return c.json({ error: "verification-failed" }, 500);
|
|
28952
29268
|
}
|
|
28953
29269
|
clearAccessRateLimit(ip, agentSlug);
|
|
28954
|
-
console.log(`${
|
|
29270
|
+
console.log(`${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
28955
29271
|
console.log(
|
|
28956
29272
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
28957
29273
|
);
|
|
@@ -29030,7 +29346,7 @@ async function sendMagicLinkEmail(payload) {
|
|
|
29030
29346
|
}
|
|
29031
29347
|
|
|
29032
29348
|
// server/routes/access/request-magic-link.ts
|
|
29033
|
-
var
|
|
29349
|
+
var TAG50 = "[access-request-link]";
|
|
29034
29350
|
var app69 = new Hono();
|
|
29035
29351
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
29036
29352
|
app69.post("/", async (c) => {
|
|
@@ -29047,18 +29363,18 @@ app69.post("/", async (c) => {
|
|
|
29047
29363
|
}
|
|
29048
29364
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
29049
29365
|
if (rateMsg) {
|
|
29050
|
-
console.error(`${
|
|
29366
|
+
console.error(`${TAG50} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
29051
29367
|
return c.json({ error: rateMsg }, 429);
|
|
29052
29368
|
}
|
|
29053
29369
|
recordRequestLinkAttempt(contactValue);
|
|
29054
29370
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
29055
29371
|
if (!accountId) {
|
|
29056
|
-
console.error(`${
|
|
29372
|
+
console.error(`${TAG50} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
29057
29373
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
29058
29374
|
}
|
|
29059
29375
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
29060
29376
|
if (!grant) {
|
|
29061
|
-
console.log(`${
|
|
29377
|
+
console.log(`${TAG50} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
29062
29378
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
29063
29379
|
}
|
|
29064
29380
|
let token;
|
|
@@ -29066,7 +29382,7 @@ app69.post("/", async (c) => {
|
|
|
29066
29382
|
token = await generateNewMagicToken(grant.grantId);
|
|
29067
29383
|
} catch (err) {
|
|
29068
29384
|
console.error(
|
|
29069
|
-
`${
|
|
29385
|
+
`${TAG50} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
29070
29386
|
);
|
|
29071
29387
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
29072
29388
|
}
|
|
@@ -29098,12 +29414,12 @@ app69.post("/", async (c) => {
|
|
|
29098
29414
|
});
|
|
29099
29415
|
if (!sendResult.ok) {
|
|
29100
29416
|
console.error(
|
|
29101
|
-
`${
|
|
29417
|
+
`${TAG50} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
29102
29418
|
);
|
|
29103
29419
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
29104
29420
|
}
|
|
29105
29421
|
console.log(
|
|
29106
|
-
`${
|
|
29422
|
+
`${TAG50} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
29107
29423
|
);
|
|
29108
29424
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
29109
29425
|
});
|
|
@@ -29344,7 +29660,7 @@ init_dist();
|
|
|
29344
29660
|
|
|
29345
29661
|
// app/lib/brand-config.ts
|
|
29346
29662
|
import { existsSync as existsSync45, readFileSync as readFileSync46 } from "fs";
|
|
29347
|
-
import { join as
|
|
29663
|
+
import { join as join52 } from "path";
|
|
29348
29664
|
var cached2 = null;
|
|
29349
29665
|
var cachedAttempted = false;
|
|
29350
29666
|
function readBrandConfig() {
|
|
@@ -29352,7 +29668,7 @@ function readBrandConfig() {
|
|
|
29352
29668
|
cachedAttempted = true;
|
|
29353
29669
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
29354
29670
|
if (!platformRoot5) return null;
|
|
29355
|
-
const brandPath =
|
|
29671
|
+
const brandPath = join52(platformRoot5, "config", "brand.json");
|
|
29356
29672
|
if (!existsSync45(brandPath)) return null;
|
|
29357
29673
|
try {
|
|
29358
29674
|
cached2 = JSON.parse(readFileSync46(brandPath, "utf-8"));
|
|
@@ -30133,12 +30449,12 @@ var calendar_public_default = app76;
|
|
|
30133
30449
|
init_dist();
|
|
30134
30450
|
import { createReadStream as createReadStream3 } from "fs";
|
|
30135
30451
|
import { stat as stat8, readFile as readFile11, realpath } from "fs/promises";
|
|
30136
|
-
import { join as
|
|
30452
|
+
import { join as join53, resolve as resolve42, sep as sep11 } from "path";
|
|
30137
30453
|
import { Readable as Readable3 } from "stream";
|
|
30138
30454
|
init_data_path();
|
|
30139
30455
|
init_attachments();
|
|
30140
30456
|
var app77 = new Hono();
|
|
30141
|
-
var
|
|
30457
|
+
var TAG51 = "[portal-fetch]";
|
|
30142
30458
|
async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
|
|
30143
30459
|
if (!secret || !signature) return false;
|
|
30144
30460
|
if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
|
|
@@ -30193,14 +30509,14 @@ async function readAccountSecret(accountId) {
|
|
|
30193
30509
|
try {
|
|
30194
30510
|
text = await readFile11(path, "utf8");
|
|
30195
30511
|
} catch {
|
|
30196
|
-
console.error(`${
|
|
30512
|
+
console.error(`${TAG51} op=no-secret account="${accountId}" path="${path}"`);
|
|
30197
30513
|
return "";
|
|
30198
30514
|
}
|
|
30199
30515
|
for (const line of text.split("\n")) {
|
|
30200
30516
|
const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
|
|
30201
30517
|
if (m) return m[1].trim();
|
|
30202
30518
|
}
|
|
30203
|
-
console.error(`${
|
|
30519
|
+
console.error(`${TAG51} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
|
|
30204
30520
|
return "";
|
|
30205
30521
|
}
|
|
30206
30522
|
function isValidAccountId2(value) {
|
|
@@ -30208,7 +30524,7 @@ function isValidAccountId2(value) {
|
|
|
30208
30524
|
}
|
|
30209
30525
|
async function readExposeFolders2(accountDir) {
|
|
30210
30526
|
try {
|
|
30211
|
-
const cfg = JSON.parse(await readFile11(
|
|
30527
|
+
const cfg = JSON.parse(await readFile11(join53(accountDir, "data-portal.json"), "utf8"));
|
|
30212
30528
|
return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
30213
30529
|
} catch {
|
|
30214
30530
|
return [];
|
|
@@ -30217,7 +30533,7 @@ async function readExposeFolders2(accountDir) {
|
|
|
30217
30533
|
async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
30218
30534
|
let schemaText = null;
|
|
30219
30535
|
try {
|
|
30220
|
-
schemaText = await readFile11(
|
|
30536
|
+
schemaText = await readFile11(join53(accountDir, "SCHEMA.md"), "utf8");
|
|
30221
30537
|
} catch {
|
|
30222
30538
|
schemaText = null;
|
|
30223
30539
|
}
|
|
@@ -30260,16 +30576,16 @@ async function handle(c, headOnly) {
|
|
|
30260
30576
|
const sig = c.req.query("sig") ?? "";
|
|
30261
30577
|
const owner = c.req.query("owner") ?? "";
|
|
30262
30578
|
console.log(
|
|
30263
|
-
`${
|
|
30579
|
+
`${TAG51} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
|
|
30264
30580
|
);
|
|
30265
30581
|
if (!isValidAccountId2(accountId)) {
|
|
30266
|
-
console.error(`${
|
|
30582
|
+
console.error(`${TAG51} op=denied account=${q(accountId)} reason=account-id`);
|
|
30267
30583
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
30268
30584
|
}
|
|
30269
30585
|
const secret = await readAccountSecret(accountId);
|
|
30270
30586
|
const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
|
|
30271
30587
|
if (!verified) {
|
|
30272
|
-
console.error(`${
|
|
30588
|
+
console.error(`${TAG51} op=denied account=${q(accountId)} reason=secret`);
|
|
30273
30589
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
30274
30590
|
}
|
|
30275
30591
|
const target = await resolveFetchTarget(
|
|
@@ -30279,14 +30595,14 @@ async function handle(c, headOnly) {
|
|
|
30279
30595
|
);
|
|
30280
30596
|
if (!target.ok) {
|
|
30281
30597
|
const op = target.reason === "enoent" ? "miss" : "denied";
|
|
30282
|
-
console.error(`${
|
|
30598
|
+
console.error(`${TAG51} op=${op} account=${accountId} reason=${target.reason}`);
|
|
30283
30599
|
return c.json({ ok: false, error: "not found" }, 404);
|
|
30284
30600
|
}
|
|
30285
30601
|
if (headOnly) {
|
|
30286
|
-
console.log(`${
|
|
30602
|
+
console.log(`${TAG51} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
|
|
30287
30603
|
return c.body(null, 200);
|
|
30288
30604
|
}
|
|
30289
|
-
console.log(`${
|
|
30605
|
+
console.log(`${TAG51} op=served account=${accountId} bytes=${target.sizeBytes}`);
|
|
30290
30606
|
return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
|
|
30291
30607
|
status: 200,
|
|
30292
30608
|
headers: {
|
|
@@ -30309,7 +30625,7 @@ init_remote_auth();
|
|
|
30309
30625
|
|
|
30310
30626
|
// app/lib/timeentry-census.ts
|
|
30311
30627
|
init_loop_registry();
|
|
30312
|
-
var
|
|
30628
|
+
var TAG52 = "[timeentry-census]";
|
|
30313
30629
|
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
30314
30630
|
const openEntries = rows.openEntries.length;
|
|
30315
30631
|
let oldestOpenAgeMs = 0;
|
|
@@ -30349,12 +30665,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
|
30349
30665
|
sumAdjustments: toNum(r.get("sumAdjustments"))
|
|
30350
30666
|
}));
|
|
30351
30667
|
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
30352
|
-
const line = `${
|
|
30668
|
+
const line = `${TAG52} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
30353
30669
|
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
30354
30670
|
else console.log(line);
|
|
30355
30671
|
return finding;
|
|
30356
30672
|
} catch (err) {
|
|
30357
|
-
console.error(`${
|
|
30673
|
+
console.error(`${TAG52} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
30358
30674
|
return null;
|
|
30359
30675
|
}
|
|
30360
30676
|
}
|
|
@@ -30368,13 +30684,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
30368
30684
|
try {
|
|
30369
30685
|
session = openSession();
|
|
30370
30686
|
} catch (err) {
|
|
30371
|
-
console.error(`${
|
|
30687
|
+
console.error(`${TAG52} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
30372
30688
|
return;
|
|
30373
30689
|
}
|
|
30374
30690
|
try {
|
|
30375
30691
|
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
30376
30692
|
} catch (err) {
|
|
30377
|
-
console.error(`${
|
|
30693
|
+
console.error(`${TAG52} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
30378
30694
|
} finally {
|
|
30379
30695
|
try {
|
|
30380
30696
|
await session.close();
|
|
@@ -30396,7 +30712,7 @@ init_neo4j_store();
|
|
|
30396
30712
|
// app/lib/ledger-census.ts
|
|
30397
30713
|
init_loop_registry();
|
|
30398
30714
|
import { readdirSync as readdirSync29, readFileSync as readFileSync47, statSync as statSync26 } from "fs";
|
|
30399
|
-
import { join as
|
|
30715
|
+
import { join as join54 } from "path";
|
|
30400
30716
|
|
|
30401
30717
|
// ../lib/ledger-core/dist/reconcile.js
|
|
30402
30718
|
var LEDGER_INDEX_NAMES = [
|
|
@@ -30439,7 +30755,7 @@ function formatCensusLine(f) {
|
|
|
30439
30755
|
}
|
|
30440
30756
|
|
|
30441
30757
|
// app/lib/ledger-census.ts
|
|
30442
|
-
var
|
|
30758
|
+
var TAG53 = "[ledger-census]";
|
|
30443
30759
|
var DAY_MS = 864e5;
|
|
30444
30760
|
function countWriteRejects24h(logDir, now) {
|
|
30445
30761
|
let entries2;
|
|
@@ -30450,7 +30766,7 @@ function countWriteRejects24h(logDir, now) {
|
|
|
30450
30766
|
}
|
|
30451
30767
|
let total = 0;
|
|
30452
30768
|
for (const name of entries2) {
|
|
30453
|
-
const path =
|
|
30769
|
+
const path = join54(logDir, name);
|
|
30454
30770
|
try {
|
|
30455
30771
|
if (now - statSync26(path).mtimeMs > DAY_MS) continue;
|
|
30456
30772
|
for (const line of readFileSync47(path, "utf8").split("\n")) {
|
|
@@ -30515,7 +30831,7 @@ async function runLedgerCensusOnce(session, now) {
|
|
|
30515
30831
|
else console.log(line);
|
|
30516
30832
|
return finding;
|
|
30517
30833
|
} catch (err) {
|
|
30518
|
-
console.error(`${
|
|
30834
|
+
console.error(`${TAG53} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
30519
30835
|
return null;
|
|
30520
30836
|
}
|
|
30521
30837
|
}
|
|
@@ -30528,7 +30844,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
30528
30844
|
session = openSession();
|
|
30529
30845
|
} catch (err) {
|
|
30530
30846
|
console.error(
|
|
30531
|
-
`${
|
|
30847
|
+
`${TAG53} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
30532
30848
|
);
|
|
30533
30849
|
return;
|
|
30534
30850
|
}
|
|
@@ -30536,7 +30852,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
30536
30852
|
await runLedgerCensusOnce(session, Date.now());
|
|
30537
30853
|
} catch (err) {
|
|
30538
30854
|
console.error(
|
|
30539
|
-
`${
|
|
30855
|
+
`${TAG53} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
30540
30856
|
);
|
|
30541
30857
|
} finally {
|
|
30542
30858
|
try {
|
|
@@ -30559,7 +30875,7 @@ init_neo4j_store();
|
|
|
30559
30875
|
|
|
30560
30876
|
// app/lib/conversation-audit.ts
|
|
30561
30877
|
init_neo4j_store();
|
|
30562
|
-
var
|
|
30878
|
+
var TAG54 = "[conversation-audit]";
|
|
30563
30879
|
async function runConversationAudit() {
|
|
30564
30880
|
const session = getSession();
|
|
30565
30881
|
try {
|
|
@@ -30596,12 +30912,12 @@ async function runConversationAudit() {
|
|
|
30596
30912
|
multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
|
|
30597
30913
|
};
|
|
30598
30914
|
console.error(
|
|
30599
|
-
`${
|
|
30915
|
+
`${TAG54} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
|
|
30600
30916
|
);
|
|
30601
30917
|
return result;
|
|
30602
30918
|
} catch (err) {
|
|
30603
30919
|
const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
|
|
30604
|
-
console.error(`${
|
|
30920
|
+
console.error(`${TAG54} op=failed reason=${reason}`);
|
|
30605
30921
|
return null;
|
|
30606
30922
|
} finally {
|
|
30607
30923
|
await session.close();
|
|
@@ -30736,8 +31052,8 @@ init_loop_registry();
|
|
|
30736
31052
|
init_data_path();
|
|
30737
31053
|
var import_dist9 = __toESM(require_dist(), 1);
|
|
30738
31054
|
import { existsSync as existsSync47, statSync as statSync27, readdirSync as readdirSync30 } from "fs";
|
|
30739
|
-
import { join as
|
|
30740
|
-
var
|
|
31055
|
+
import { join as join55 } from "path";
|
|
31056
|
+
var TAG55 = "[shared-census]";
|
|
30741
31057
|
var WIRED_SURFACES = 3;
|
|
30742
31058
|
function countFiles(dir) {
|
|
30743
31059
|
let n = 0;
|
|
@@ -30748,7 +31064,7 @@ function countFiles(dir) {
|
|
|
30748
31064
|
return 0;
|
|
30749
31065
|
}
|
|
30750
31066
|
for (const e of entries2) {
|
|
30751
|
-
if (e.isDirectory()) n += countFiles(
|
|
31067
|
+
if (e.isDirectory()) n += countFiles(join55(dir, e.name));
|
|
30752
31068
|
else if (e.isFile()) n++;
|
|
30753
31069
|
}
|
|
30754
31070
|
return n;
|
|
@@ -30765,8 +31081,8 @@ function runSharedFolderCensus(dataRoot = DATA_ROOT) {
|
|
|
30765
31081
|
}
|
|
30766
31082
|
}
|
|
30767
31083
|
const files = isDir ? countFiles(root) : 0;
|
|
30768
|
-
console.error(`${
|
|
30769
|
-
console.error(`${
|
|
31084
|
+
console.error(`${TAG55} op=root exists=${exists} isDir=${isDir} files=${files}`);
|
|
31085
|
+
console.error(`${TAG55} op=wiring surfaces=${WIRED_SURFACES}/3`);
|
|
30770
31086
|
return `shared root ${exists ? "present" : "ABSENT"}, ${files} file(s)`;
|
|
30771
31087
|
}
|
|
30772
31088
|
function startSharedFolderCensus() {
|
|
@@ -30886,7 +31202,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
30886
31202
|
init_data_path();
|
|
30887
31203
|
init_neo4j_store();
|
|
30888
31204
|
init_account();
|
|
30889
|
-
import { mkdir as
|
|
31205
|
+
import { mkdir as mkdir5, readdir as readdir6, rename as rename4, rm as rm3 } from "fs/promises";
|
|
30890
31206
|
import { dirname as dirname17, relative as relative8, resolve as resolve44 } from "path";
|
|
30891
31207
|
var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
30892
31208
|
async function walkFiles(dir) {
|
|
@@ -30919,7 +31235,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
30919
31235
|
for (const oldAbs of files) {
|
|
30920
31236
|
const suffix = relative8(srcDir, oldAbs);
|
|
30921
31237
|
const newAbs = resolve44(destDir, suffix);
|
|
30922
|
-
await
|
|
31238
|
+
await mkdir5(dirname17(newAbs), { recursive: true });
|
|
30923
31239
|
await rename4(oldAbs, newAbs);
|
|
30924
31240
|
moved++;
|
|
30925
31241
|
const oldRel = relative8(dataRoot, oldAbs);
|
|
@@ -31013,9 +31329,9 @@ init_paths();
|
|
|
31013
31329
|
init_pin_validator();
|
|
31014
31330
|
init_account();
|
|
31015
31331
|
init_neo4j_store();
|
|
31016
|
-
import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as
|
|
31332
|
+
import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile5, unlink as unlink4 } from "fs/promises";
|
|
31017
31333
|
import { existsSync as existsSync48 } from "fs";
|
|
31018
|
-
import { join as
|
|
31334
|
+
import { join as join56 } from "path";
|
|
31019
31335
|
var ADMIN_ROLE2 = "admin";
|
|
31020
31336
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
31021
31337
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -31040,7 +31356,7 @@ async function readRaw3(path) {
|
|
|
31040
31356
|
async function writeRaw(path, obj) {
|
|
31041
31357
|
const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
|
|
31042
31358
|
try {
|
|
31043
|
-
await
|
|
31359
|
+
await writeFile5(tmp, JSON.stringify(obj, null, 2), "utf8");
|
|
31044
31360
|
await rename5(tmp, path);
|
|
31045
31361
|
} catch (err) {
|
|
31046
31362
|
try {
|
|
@@ -31060,7 +31376,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
31060
31376
|
}
|
|
31061
31377
|
for (const slug of slugs) {
|
|
31062
31378
|
if (!slug.isDirectory()) continue;
|
|
31063
|
-
const slugDir =
|
|
31379
|
+
const slugDir = join56(projectsRoot, slug.name);
|
|
31064
31380
|
let entries2;
|
|
31065
31381
|
try {
|
|
31066
31382
|
entries2 = await readdir7(slugDir, { withFileTypes: true });
|
|
@@ -31069,9 +31385,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
31069
31385
|
}
|
|
31070
31386
|
for (const entry of entries2) {
|
|
31071
31387
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
31072
|
-
out.push(
|
|
31388
|
+
out.push(join56(slugDir, entry.name));
|
|
31073
31389
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
31074
|
-
const subDir =
|
|
31390
|
+
const subDir = join56(slugDir, entry.name);
|
|
31075
31391
|
let subs;
|
|
31076
31392
|
try {
|
|
31077
31393
|
subs = await readdir7(subDir, { withFileTypes: true });
|
|
@@ -31079,7 +31395,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
31079
31395
|
continue;
|
|
31080
31396
|
}
|
|
31081
31397
|
for (const s of subs) {
|
|
31082
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
31398
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join56(subDir, s.name));
|
|
31083
31399
|
}
|
|
31084
31400
|
}
|
|
31085
31401
|
}
|
|
@@ -31091,7 +31407,7 @@ function shortId(path) {
|
|
|
31091
31407
|
return base.slice(0, 8);
|
|
31092
31408
|
}
|
|
31093
31409
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
31094
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
31410
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join56(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
31095
31411
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
31096
31412
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
31097
31413
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -31167,9 +31483,9 @@ async function migrateAdminWebchatSidecars(opts = {}) {
|
|
|
31167
31483
|
|
|
31168
31484
|
// app/lib/migrate-sidecar-account-ids.ts
|
|
31169
31485
|
init_account();
|
|
31170
|
-
import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as
|
|
31486
|
+
import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile6, unlink as unlink5 } from "fs/promises";
|
|
31171
31487
|
import { existsSync as existsSync49 } from "fs";
|
|
31172
|
-
import { join as
|
|
31488
|
+
import { join as join57 } from "path";
|
|
31173
31489
|
var SESSION_META_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
31174
31490
|
function projectSlugForCwd(cwd) {
|
|
31175
31491
|
return cwd.replace(/\//g, "-");
|
|
@@ -31191,7 +31507,7 @@ async function readRaw4(path) {
|
|
|
31191
31507
|
async function writeRaw2(path, obj) {
|
|
31192
31508
|
const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
|
|
31193
31509
|
try {
|
|
31194
|
-
await
|
|
31510
|
+
await writeFile6(tmp, JSON.stringify(obj, null, 2), "utf8");
|
|
31195
31511
|
await rename6(tmp, path);
|
|
31196
31512
|
} catch (err) {
|
|
31197
31513
|
try {
|
|
@@ -31215,7 +31531,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
31215
31531
|
}
|
|
31216
31532
|
for (const slug of slugs) {
|
|
31217
31533
|
if (!slug.isDirectory()) continue;
|
|
31218
|
-
const slugDir =
|
|
31534
|
+
const slugDir = join57(projectsRoot, slug.name);
|
|
31219
31535
|
let entries2;
|
|
31220
31536
|
try {
|
|
31221
31537
|
entries2 = await readdir8(slugDir, { withFileTypes: true });
|
|
@@ -31224,9 +31540,9 @@ async function collectSidecars(projectsRoot) {
|
|
|
31224
31540
|
}
|
|
31225
31541
|
for (const entry of entries2) {
|
|
31226
31542
|
if (entry.isFile() && SESSION_META_RE2.test(entry.name)) {
|
|
31227
|
-
out.push({ path:
|
|
31543
|
+
out.push({ path: join57(slugDir, entry.name), slug: slug.name });
|
|
31228
31544
|
} else if (entry.isDirectory() && (entry.name === "subagents" || entry.name === "archive")) {
|
|
31229
|
-
const subDir =
|
|
31545
|
+
const subDir = join57(slugDir, entry.name);
|
|
31230
31546
|
let subs;
|
|
31231
31547
|
try {
|
|
31232
31548
|
subs = await readdir8(subDir, { withFileTypes: true });
|
|
@@ -31235,7 +31551,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
31235
31551
|
}
|
|
31236
31552
|
for (const s of subs) {
|
|
31237
31553
|
if (s.isFile() && SESSION_META_RE2.test(s.name)) {
|
|
31238
|
-
out.push({ path:
|
|
31554
|
+
out.push({ path: join57(subDir, s.name), slug: slug.name });
|
|
31239
31555
|
}
|
|
31240
31556
|
}
|
|
31241
31557
|
}
|
|
@@ -31244,7 +31560,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
31244
31560
|
return out;
|
|
31245
31561
|
}
|
|
31246
31562
|
async function migrateSidecarAccountIds(opts = {}) {
|
|
31247
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
31563
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join57(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
31248
31564
|
const accounts = opts.accounts ?? listValidAccounts();
|
|
31249
31565
|
const result = {
|
|
31250
31566
|
scanned: 0,
|
|
@@ -31459,15 +31775,15 @@ var InboundHub = class {
|
|
|
31459
31775
|
|
|
31460
31776
|
// app/lib/whatsapp/inbound/public-inbound-census.ts
|
|
31461
31777
|
var routed = 0;
|
|
31462
|
-
var
|
|
31778
|
+
var answered2 = 0;
|
|
31463
31779
|
function noteRouted() {
|
|
31464
31780
|
routed += 1;
|
|
31465
31781
|
}
|
|
31466
|
-
function
|
|
31467
|
-
|
|
31782
|
+
function noteAnswered2() {
|
|
31783
|
+
answered2 += 1;
|
|
31468
31784
|
}
|
|
31469
31785
|
function readPublicInboundCensus() {
|
|
31470
|
-
return { routed, answered, answerGap: Math.max(0, routed -
|
|
31786
|
+
return { routed, answered: answered2, answerGap: Math.max(0, routed - answered2) };
|
|
31471
31787
|
}
|
|
31472
31788
|
function runPublicNotifyReconcile() {
|
|
31473
31789
|
const c = readPublicInboundCensus();
|
|
@@ -32013,7 +32329,7 @@ var WaGateway = class {
|
|
|
32013
32329
|
* inbound; it is dropped and counted as expired, not reported as a race. */
|
|
32014
32330
|
noteReplyDispatch(senderId, atMs) {
|
|
32015
32331
|
const key2 = normalizeTarget(senderId) ?? senderId;
|
|
32016
|
-
if (this.awaitingPublicAnswer.delete(key2))
|
|
32332
|
+
if (this.awaitingPublicAnswer.delete(key2)) noteAnswered2();
|
|
32017
32333
|
const inFlight2 = this.pendingMediaStanza.get(key2);
|
|
32018
32334
|
if (inFlight2 === void 0) return;
|
|
32019
32335
|
this.expireStaleStanzas(key2, inFlight2, atMs);
|
|
@@ -32770,7 +33086,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
32770
33086
|
|
|
32771
33087
|
// app/lib/webchat/gateway/resolve-turn-answer.ts
|
|
32772
33088
|
import { existsSync as existsSync50, openSync as openSync9, readSync as readSync8, closeSync as closeSync9, readdirSync as readdirSync31 } from "fs";
|
|
32773
|
-
import { join as
|
|
33089
|
+
import { join as join58 } from "path";
|
|
32774
33090
|
function resolveTurnAnswer(p) {
|
|
32775
33091
|
if (!SESSION_ID_RE2.test(p.sessionId)) return "";
|
|
32776
33092
|
const path = findJsonl(p.projectsRoot, p.sessionId);
|
|
@@ -32806,7 +33122,7 @@ function findJsonl(projectsRoot, sessionId) {
|
|
|
32806
33122
|
return null;
|
|
32807
33123
|
}
|
|
32808
33124
|
for (const slug of slugs) {
|
|
32809
|
-
const live =
|
|
33125
|
+
const live = join58(projectsRoot, slug, `${sessionId}.jsonl`);
|
|
32810
33126
|
if (existsSync50(live)) return live;
|
|
32811
33127
|
}
|
|
32812
33128
|
return null;
|
|
@@ -33604,14 +33920,14 @@ function makeFileDelivery(opts) {
|
|
|
33604
33920
|
}
|
|
33605
33921
|
|
|
33606
33922
|
// app/lib/webchat/file-delivery.ts
|
|
33607
|
-
var
|
|
33923
|
+
var TAG56 = "[webchat-adaptor]";
|
|
33608
33924
|
function platformRoot2() {
|
|
33609
33925
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
33610
33926
|
}
|
|
33611
33927
|
function makeWebchatSendFile(entry) {
|
|
33612
33928
|
return async (filePath) => {
|
|
33613
33929
|
if (!entry.accountId) {
|
|
33614
|
-
console.error(`${
|
|
33930
|
+
console.error(`${TAG56} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
33615
33931
|
return { ok: false, error: "no-account" };
|
|
33616
33932
|
}
|
|
33617
33933
|
const accountDir = resolve45(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
@@ -33619,14 +33935,14 @@ function makeWebchatSendFile(entry) {
|
|
|
33619
33935
|
const resolved = realpathSync9(filePath);
|
|
33620
33936
|
const accountResolved = realpathSync9(accountDir);
|
|
33621
33937
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
33622
|
-
console.error(`${
|
|
33938
|
+
console.error(`${TAG56} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
33623
33939
|
return { ok: false, error: "outside-account" };
|
|
33624
33940
|
}
|
|
33625
33941
|
return { ok: true };
|
|
33626
33942
|
} catch (err) {
|
|
33627
33943
|
const code = err.code;
|
|
33628
33944
|
console.error(
|
|
33629
|
-
`${
|
|
33945
|
+
`${TAG56} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
33630
33946
|
);
|
|
33631
33947
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
33632
33948
|
}
|
|
@@ -33635,7 +33951,7 @@ function makeWebchatSendFile(entry) {
|
|
|
33635
33951
|
function makeWebchatFileDelivery(entry) {
|
|
33636
33952
|
return makeFileDelivery({
|
|
33637
33953
|
entry,
|
|
33638
|
-
tag:
|
|
33954
|
+
tag: TAG56,
|
|
33639
33955
|
channel: "webchat",
|
|
33640
33956
|
sendFile: makeWebchatSendFile(entry),
|
|
33641
33957
|
deferUntilVerdict: true
|
|
@@ -33699,7 +34015,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
33699
34015
|
}
|
|
33700
34016
|
|
|
33701
34017
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
33702
|
-
var
|
|
34018
|
+
var TAG57 = "[whatsapp-adaptor]";
|
|
33703
34019
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
33704
34020
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
33705
34021
|
function platformRoot3() {
|
|
@@ -33717,7 +34033,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
33717
34033
|
});
|
|
33718
34034
|
if (result.ok) return { ok: true };
|
|
33719
34035
|
console.error(
|
|
33720
|
-
`${
|
|
34036
|
+
`${TAG57} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
33721
34037
|
);
|
|
33722
34038
|
return { ok: false, error: result.error };
|
|
33723
34039
|
};
|
|
@@ -33725,7 +34041,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
33725
34041
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
33726
34042
|
const shared = makeFileDelivery({
|
|
33727
34043
|
entry,
|
|
33728
|
-
tag:
|
|
34044
|
+
tag: TAG57,
|
|
33729
34045
|
channel: "whatsapp",
|
|
33730
34046
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
33731
34047
|
});
|
|
@@ -33760,7 +34076,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
33760
34076
|
if (!delivered) {
|
|
33761
34077
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
33762
34078
|
console.error(
|
|
33763
|
-
`${
|
|
34079
|
+
`${TAG57} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
33764
34080
|
);
|
|
33765
34081
|
}
|
|
33766
34082
|
}
|
|
@@ -34065,52 +34381,6 @@ function createTelegramChannelRoutes(deps) {
|
|
|
34065
34381
|
init_admin_session_id();
|
|
34066
34382
|
init_channel_key();
|
|
34067
34383
|
|
|
34068
|
-
// app/lib/telegram/gateway/telegram-inbound-census.ts
|
|
34069
|
-
var ANSWER_THRESHOLD_MS = 3e4;
|
|
34070
|
-
var GAP_NAME_LIMIT2 = 10;
|
|
34071
|
-
var received = 0;
|
|
34072
|
-
var answered2 = 0;
|
|
34073
|
-
var outstanding2 = /* @__PURE__ */ new Map();
|
|
34074
|
-
function noteReceived(key2, botId, messageId, now) {
|
|
34075
|
-
received += 1;
|
|
34076
|
-
const list = outstanding2.get(key2);
|
|
34077
|
-
if (list) list.push({ messageId, botId, receivedAt: now });
|
|
34078
|
-
else outstanding2.set(key2, [{ messageId, botId, receivedAt: now }]);
|
|
34079
|
-
}
|
|
34080
|
-
function noteAnswered2(key2) {
|
|
34081
|
-
const list = outstanding2.get(key2);
|
|
34082
|
-
if (!list || list.length === 0) return;
|
|
34083
|
-
list.shift();
|
|
34084
|
-
if (list.length === 0) outstanding2.delete(key2);
|
|
34085
|
-
answered2 += 1;
|
|
34086
|
-
}
|
|
34087
|
-
function readTelegramInboundCensus(now) {
|
|
34088
|
-
const gaps = [];
|
|
34089
|
-
for (const [key2, list] of outstanding2) {
|
|
34090
|
-
for (const o of list) {
|
|
34091
|
-
const ageMs2 = now - o.receivedAt;
|
|
34092
|
-
if (ageMs2 > ANSWER_THRESHOLD_MS) gaps.push({ messageId: o.messageId, botId: o.botId, key: key2, ageMs: ageMs2 });
|
|
34093
|
-
}
|
|
34094
|
-
}
|
|
34095
|
-
gaps.sort((a, b) => b.ageMs - a.ageMs);
|
|
34096
|
-
return { received, answered: answered2, gaps };
|
|
34097
|
-
}
|
|
34098
|
-
function buildTelegramNotifyReconcileLines(input) {
|
|
34099
|
-
const named = input.gaps.slice(0, GAP_NAME_LIMIT2);
|
|
34100
|
-
const lines = [
|
|
34101
|
-
`[telegram-native] op=telegram-notify-reconcile received=${input.received} answered=${input.answered} answerGap=${input.gaps.length} named=${named.length}`
|
|
34102
|
-
];
|
|
34103
|
-
for (const g of named) {
|
|
34104
|
-
lines.push(
|
|
34105
|
-
`[telegram-native] op=telegram-answer-gap messageId=${g.messageId} botId=${g.botId} key=${g.key} ageMs=${g.ageMs}`
|
|
34106
|
-
);
|
|
34107
|
-
}
|
|
34108
|
-
return lines;
|
|
34109
|
-
}
|
|
34110
|
-
function runTelegramNotifyReconcile(now) {
|
|
34111
|
-
for (const line of buildTelegramNotifyReconcileLines(readTelegramInboundCensus(now))) console.error(line);
|
|
34112
|
-
}
|
|
34113
|
-
|
|
34114
34384
|
// app/lib/telegram/gateway/telegram-spawn-census.ts
|
|
34115
34385
|
var byBot = /* @__PURE__ */ new Map();
|
|
34116
34386
|
function bucket(botId) {
|
|
@@ -34282,7 +34552,7 @@ var TelegramGateway = class {
|
|
|
34282
34552
|
);
|
|
34283
34553
|
}
|
|
34284
34554
|
this.hub.deliver(
|
|
34285
|
-
{ key: key2, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
|
|
34555
|
+
{ key: key2, text: input.text, media: input.media, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
|
|
34286
34556
|
Date.now()
|
|
34287
34557
|
);
|
|
34288
34558
|
const resolvedSessionId = this.sessionIdFor(input);
|
|
@@ -34326,7 +34596,7 @@ var TelegramGateway = class {
|
|
|
34326
34596
|
const reply = this.replies.get(key2);
|
|
34327
34597
|
if (!reply) throw new Error(`telegram-gateway: no reply route for key ${key2}`);
|
|
34328
34598
|
await reply(text);
|
|
34329
|
-
|
|
34599
|
+
noteAnswered(key2);
|
|
34330
34600
|
}
|
|
34331
34601
|
};
|
|
34332
34602
|
|
|
@@ -34362,7 +34632,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
34362
34632
|
}
|
|
34363
34633
|
|
|
34364
34634
|
// server/telegram-ensure-session.ts
|
|
34365
|
-
var
|
|
34635
|
+
var TAG58 = "[telegram-inbound]";
|
|
34366
34636
|
function buildTelegramEnsureSession(deps) {
|
|
34367
34637
|
return async (input) => {
|
|
34368
34638
|
const req = buildTelegramSpawnRequest({
|
|
@@ -34396,10 +34666,10 @@ function buildTelegramEnsureSession(deps) {
|
|
|
34396
34666
|
return;
|
|
34397
34667
|
}
|
|
34398
34668
|
console.error(
|
|
34399
|
-
`${
|
|
34669
|
+
`${TAG58} op=telegram-spawn-door botId=${input.botId} role=public door=rc agent=${input.agentSlug}`
|
|
34400
34670
|
);
|
|
34401
34671
|
console.error(
|
|
34402
|
-
`${
|
|
34672
|
+
`${TAG58} op=spawn botId=${input.botId} sessionId=${result2.sessionId} targetAccountId=${input.accountId} role=public`
|
|
34403
34673
|
);
|
|
34404
34674
|
noteSpawnOk2(input.botId);
|
|
34405
34675
|
return;
|
|
@@ -34413,7 +34683,7 @@ function buildTelegramEnsureSession(deps) {
|
|
|
34413
34683
|
return;
|
|
34414
34684
|
}
|
|
34415
34685
|
console.error(
|
|
34416
|
-
`${
|
|
34686
|
+
`${TAG58} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=admin`
|
|
34417
34687
|
);
|
|
34418
34688
|
noteSpawnOk2(input.botId);
|
|
34419
34689
|
deps.followers.get(req.channelKey)?.abort();
|
|
@@ -34439,7 +34709,7 @@ init_attachments();
|
|
|
34439
34709
|
import { realpathSync as realpathSync10 } from "fs";
|
|
34440
34710
|
import { readFile as readFile14, stat as stat10 } from "fs/promises";
|
|
34441
34711
|
import { resolve as resolve46, basename as basename16 } from "path";
|
|
34442
|
-
var
|
|
34712
|
+
var TAG59 = "[telegram:outbound]";
|
|
34443
34713
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
34444
34714
|
async function sendTelegramDocument(input) {
|
|
34445
34715
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
@@ -34456,10 +34726,10 @@ async function sendTelegramDocument(input) {
|
|
|
34456
34726
|
} catch (err) {
|
|
34457
34727
|
const code = err.code;
|
|
34458
34728
|
if (code === "ENOENT") {
|
|
34459
|
-
console.error(`${
|
|
34729
|
+
console.error(`${TAG59} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
|
|
34460
34730
|
return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
|
|
34461
34731
|
}
|
|
34462
|
-
console.error(`${
|
|
34732
|
+
console.error(`${TAG59} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
34463
34733
|
return { ok: false, status: 500, error: String(err) };
|
|
34464
34734
|
}
|
|
34465
34735
|
let resolvedPath;
|
|
@@ -34468,14 +34738,14 @@ async function sendTelegramDocument(input) {
|
|
|
34468
34738
|
} catch (err) {
|
|
34469
34739
|
const code = err.code;
|
|
34470
34740
|
if (code === "ENOENT") {
|
|
34471
|
-
console.error(`${
|
|
34741
|
+
console.error(`${TAG59} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
|
|
34472
34742
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
34473
34743
|
}
|
|
34474
|
-
console.error(`${
|
|
34744
|
+
console.error(`${TAG59} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
34475
34745
|
return { ok: false, status: 500, error: String(err) };
|
|
34476
34746
|
}
|
|
34477
34747
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
34478
|
-
console.error(`${
|
|
34748
|
+
console.error(`${TAG59} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
34479
34749
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
34480
34750
|
}
|
|
34481
34751
|
const fileStat = await stat10(resolvedPath);
|
|
@@ -34508,24 +34778,24 @@ async function sendTelegramDocument(input) {
|
|
|
34508
34778
|
error = e instanceof Error ? e.message : String(e);
|
|
34509
34779
|
}
|
|
34510
34780
|
console.error(
|
|
34511
|
-
`${
|
|
34781
|
+
`${TAG59} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok2}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
34512
34782
|
);
|
|
34513
34783
|
return ok2 ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
34514
34784
|
}
|
|
34515
34785
|
|
|
34516
34786
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
34517
|
-
var
|
|
34787
|
+
var TAG60 = "[telegram:outbound]";
|
|
34518
34788
|
function platformRoot4() {
|
|
34519
34789
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
34520
34790
|
}
|
|
34521
34791
|
function makeTelegramSendFile(entry, botToken) {
|
|
34522
34792
|
return async (filePath, caption) => {
|
|
34523
34793
|
if (!botToken) {
|
|
34524
|
-
console.error(`${
|
|
34794
|
+
console.error(`${TAG60} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
34525
34795
|
return { ok: false, error: "no-bot-token" };
|
|
34526
34796
|
}
|
|
34527
34797
|
if (entry.replyTarget == null) {
|
|
34528
|
-
console.error(`${
|
|
34798
|
+
console.error(`${TAG60} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
34529
34799
|
return { ok: false, error: "no-reply-target" };
|
|
34530
34800
|
}
|
|
34531
34801
|
const result = await sendTelegramDocument({
|
|
@@ -34542,7 +34812,7 @@ function makeTelegramSendFile(entry, botToken) {
|
|
|
34542
34812
|
function makeTelegramFileDelivery(entry, botToken) {
|
|
34543
34813
|
return makeFileDelivery({
|
|
34544
34814
|
entry,
|
|
34545
|
-
tag:
|
|
34815
|
+
tag: TAG60,
|
|
34546
34816
|
channel: "telegram",
|
|
34547
34817
|
sendFile: makeTelegramSendFile(entry, botToken)
|
|
34548
34818
|
});
|
|
@@ -34631,7 +34901,7 @@ init_webchat();
|
|
|
34631
34901
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
34632
34902
|
init_src3();
|
|
34633
34903
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
34634
|
-
var
|
|
34904
|
+
var TAG61 = "[public-session-review]";
|
|
34635
34905
|
var CONSUMED_CAP = 500;
|
|
34636
34906
|
var consumed = /* @__PURE__ */ new Set();
|
|
34637
34907
|
function consumeOnce(sessionId) {
|
|
@@ -34658,7 +34928,7 @@ async function fetchJsonl(sessionId) {
|
|
|
34658
34928
|
return await res.text();
|
|
34659
34929
|
} catch (err) {
|
|
34660
34930
|
console.error(
|
|
34661
|
-
`${
|
|
34931
|
+
`${TAG61} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
34662
34932
|
);
|
|
34663
34933
|
return null;
|
|
34664
34934
|
}
|
|
@@ -34682,7 +34952,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
34682
34952
|
const res = await fetch(url);
|
|
34683
34953
|
if (!res.ok) {
|
|
34684
34954
|
console.error(
|
|
34685
|
-
`${
|
|
34955
|
+
`${TAG61} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
34686
34956
|
);
|
|
34687
34957
|
return [];
|
|
34688
34958
|
}
|
|
@@ -34690,7 +34960,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
34690
34960
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
34691
34961
|
} catch (err) {
|
|
34692
34962
|
console.error(
|
|
34693
|
-
`${
|
|
34963
|
+
`${TAG61} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
34694
34964
|
);
|
|
34695
34965
|
return [];
|
|
34696
34966
|
}
|
|
@@ -34719,7 +34989,7 @@ function composeInitialMessage(input) {
|
|
|
34719
34989
|
}
|
|
34720
34990
|
async function dispatchReviewer(input, initialMessage) {
|
|
34721
34991
|
const sessionId = randomUUID14();
|
|
34722
|
-
console.log(`${
|
|
34992
|
+
console.log(`${TAG61} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
34723
34993
|
const spawned = await managerRcSpawn({
|
|
34724
34994
|
sessionId,
|
|
34725
34995
|
initialMessage,
|
|
@@ -34743,21 +35013,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
34743
35013
|
const dispatchedAt = Date.now();
|
|
34744
35014
|
if (consumed.has(input.sessionId)) {
|
|
34745
35015
|
console.log(
|
|
34746
|
-
`${
|
|
35016
|
+
`${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
34747
35017
|
);
|
|
34748
35018
|
return;
|
|
34749
35019
|
}
|
|
34750
35020
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
34751
35021
|
if (!jsonl) {
|
|
34752
35022
|
console.log(
|
|
34753
|
-
`${
|
|
35023
|
+
`${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
34754
35024
|
);
|
|
34755
35025
|
return;
|
|
34756
35026
|
}
|
|
34757
35027
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
34758
35028
|
if (operatorTurns === 0) {
|
|
34759
35029
|
console.log(
|
|
34760
|
-
`${
|
|
35030
|
+
`${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
34761
35031
|
);
|
|
34762
35032
|
return;
|
|
34763
35033
|
}
|
|
@@ -34771,19 +35041,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
34771
35041
|
});
|
|
34772
35042
|
if (!consumeOnce(input.sessionId)) {
|
|
34773
35043
|
console.log(
|
|
34774
|
-
`${
|
|
35044
|
+
`${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
34775
35045
|
);
|
|
34776
35046
|
return;
|
|
34777
35047
|
}
|
|
34778
35048
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
34779
35049
|
if (!dispatched.ok) {
|
|
34780
35050
|
console.error(
|
|
34781
|
-
`${
|
|
35051
|
+
`${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
34782
35052
|
);
|
|
34783
35053
|
return;
|
|
34784
35054
|
}
|
|
34785
35055
|
console.log(
|
|
34786
|
-
`${
|
|
35056
|
+
`${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
34787
35057
|
);
|
|
34788
35058
|
}
|
|
34789
35059
|
|
|
@@ -34935,7 +35205,7 @@ init_account();
|
|
|
34935
35205
|
|
|
34936
35206
|
// server/telegram-audit.ts
|
|
34937
35207
|
import { statSync as statSync28 } from "fs";
|
|
34938
|
-
import { join as
|
|
35208
|
+
import { join as join59 } from "path";
|
|
34939
35209
|
init_channel_key();
|
|
34940
35210
|
init_sidebar_sessions();
|
|
34941
35211
|
function buildTelegramAuditLines(input) {
|
|
@@ -35001,7 +35271,7 @@ function countTelegramSessionsForAccount(accountId) {
|
|
|
35001
35271
|
function* walkTelegramSidecars() {
|
|
35002
35272
|
const cfg = claudeConfigDir();
|
|
35003
35273
|
if (!cfg) return;
|
|
35004
|
-
const projectsRoot =
|
|
35274
|
+
const projectsRoot = join59(cfg, "projects");
|
|
35005
35275
|
for (const { path } of enumerateSessionSidecars(projectsRoot)) {
|
|
35006
35276
|
const meta = readSidecarMeta(path);
|
|
35007
35277
|
if (meta.channel !== "telegram" || !meta.accountId) continue;
|
|
@@ -35028,11 +35298,11 @@ function* walkTelegramSidecars() {
|
|
|
35028
35298
|
|
|
35029
35299
|
// server/telegram-migrate.ts
|
|
35030
35300
|
import { readFileSync as readFileSync48, writeFileSync as writeFileSync19, existsSync as existsSync51, renameSync as renameSync11, mkdirSync as mkdirSync11 } from "fs";
|
|
35031
|
-
import { dirname as dirname18, join as
|
|
35301
|
+
import { dirname as dirname18, join as join60 } from "path";
|
|
35032
35302
|
function migrateTelegramTwoSlot(input) {
|
|
35033
35303
|
const out = [];
|
|
35034
35304
|
for (const account of input.accounts) {
|
|
35035
|
-
const configPath3 =
|
|
35305
|
+
const configPath3 = join60(account.accountDir, "account.json");
|
|
35036
35306
|
let config;
|
|
35037
35307
|
try {
|
|
35038
35308
|
config = JSON.parse(readFileSync48(configPath3, "utf-8"));
|
|
@@ -35429,7 +35699,7 @@ function clientFrom(c) {
|
|
|
35429
35699
|
}
|
|
35430
35700
|
installMediaDownloadGuard();
|
|
35431
35701
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
35432
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT6 ?
|
|
35702
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join61(PLATFORM_ROOT6, "config", "brand.json") : "";
|
|
35433
35703
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
35434
35704
|
if (BRAND_JSON_PATH && !existsSync54(BRAND_JSON_PATH)) {
|
|
35435
35705
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -35468,7 +35738,7 @@ var brandLoginOpts = {
|
|
|
35468
35738
|
appleTouchIconPath: brandAppIcon512Path,
|
|
35469
35739
|
themeColor: BRAND.defaultColors?.primary
|
|
35470
35740
|
};
|
|
35471
|
-
var ALIAS_DOMAINS_PATH =
|
|
35741
|
+
var ALIAS_DOMAINS_PATH = join61(homedir5(), BRAND.configDir, "alias-domains.json");
|
|
35472
35742
|
function loadAliasDomains() {
|
|
35473
35743
|
try {
|
|
35474
35744
|
if (!existsSync54(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -35573,7 +35843,7 @@ var waGateway = new WaGateway({
|
|
|
35573
35843
|
deps: adminFanDeps("whatsapp", accountId)
|
|
35574
35844
|
}),
|
|
35575
35845
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
35576
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve49(process.env.MAXY_PLATFORM_ROOT ??
|
|
35846
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve49(process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
35577
35847
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
35578
35848
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
35579
35849
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -35588,7 +35858,7 @@ var waGateway = new WaGateway({
|
|
|
35588
35858
|
caption,
|
|
35589
35859
|
accountId,
|
|
35590
35860
|
maxyAccountId,
|
|
35591
|
-
platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ??
|
|
35861
|
+
platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, ".."))
|
|
35592
35862
|
});
|
|
35593
35863
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
35594
35864
|
},
|
|
@@ -35755,7 +36025,7 @@ function runDuplicateSenderAudit() {
|
|
|
35755
36025
|
try {
|
|
35756
36026
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
35757
36027
|
if (!configDir) return;
|
|
35758
|
-
const projectsRoot =
|
|
36028
|
+
const projectsRoot = join61(configDir, "projects");
|
|
35759
36029
|
const records2 = [];
|
|
35760
36030
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
35761
36031
|
if (isSubagent || archived) continue;
|
|
@@ -35807,7 +36077,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
35807
36077
|
// rather than hanging the POST.
|
|
35808
36078
|
publicProjectsRoot: () => {
|
|
35809
36079
|
const cfg = claudeConfigDir();
|
|
35810
|
-
return cfg ?
|
|
36080
|
+
return cfg ? join61(cfg, "projects") : "";
|
|
35811
36081
|
},
|
|
35812
36082
|
gatewayUrl: webchatGatewayUrl(),
|
|
35813
36083
|
serverPath: webchatServerPath(),
|
|
@@ -36481,7 +36751,7 @@ var SW_SOURCE = (() => {
|
|
|
36481
36751
|
function readInstalledVersion() {
|
|
36482
36752
|
try {
|
|
36483
36753
|
if (!PLATFORM_ROOT6) return "unknown";
|
|
36484
|
-
const versionFile =
|
|
36754
|
+
const versionFile = join61(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
|
|
36485
36755
|
if (!existsSync54(versionFile)) return "unknown";
|
|
36486
36756
|
const content = readFileSync51(versionFile, "utf-8").trim();
|
|
36487
36757
|
return content || "unknown";
|
|
@@ -36511,12 +36781,12 @@ ${clientErrorReporterScript}
|
|
|
36511
36781
|
return html;
|
|
36512
36782
|
}
|
|
36513
36783
|
function loadBrandingCache(agentSlug) {
|
|
36514
|
-
const configDir =
|
|
36784
|
+
const configDir = join61(homedir5(), BRAND.configDir);
|
|
36515
36785
|
try {
|
|
36516
36786
|
const verdict = resolvePublicAddressFromDisk(agentSlug);
|
|
36517
36787
|
const accountId = verdict.kind === "served" ? verdict.owner.accountId : getDefaultAccountId();
|
|
36518
36788
|
if (!accountId) return null;
|
|
36519
|
-
const cachePath =
|
|
36789
|
+
const cachePath = join61(configDir, "branding-cache", accountId, `${agentSlug}.json`);
|
|
36520
36790
|
if (!existsSync54(cachePath)) return null;
|
|
36521
36791
|
return JSON.parse(readFileSync51(cachePath, "utf-8"));
|
|
36522
36792
|
} catch {
|
|
@@ -36766,7 +37036,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
36766
37036
|
var httpServer = serve({ fetch: app78.fetch, port, hostname });
|
|
36767
37037
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
36768
37038
|
{
|
|
36769
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37039
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
36770
37040
|
const reconcileScript = resolve49(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
36771
37041
|
const runReconcile = (ctx) => {
|
|
36772
37042
|
if (!existsSync54(reconcileScript)) return;
|
|
@@ -36789,7 +37059,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
36789
37059
|
detached: true,
|
|
36790
37060
|
run: runReconcile
|
|
36791
37061
|
});
|
|
36792
|
-
const reconcileStatePath =
|
|
37062
|
+
const reconcileStatePath = join61(MAXY_DIR, "booking-reconcile-state.json");
|
|
36793
37063
|
registerLoop({
|
|
36794
37064
|
name: "calendar-reconcile-liveness",
|
|
36795
37065
|
intervalMs: 6e5,
|
|
@@ -36807,7 +37077,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
36807
37077
|
}
|
|
36808
37078
|
{
|
|
36809
37079
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
36810
|
-
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37080
|
+
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
36811
37081
|
const dreamSweepScript = resolve49(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
36812
37082
|
registerLoop({
|
|
36813
37083
|
name: "dream-cycle-sweep",
|
|
@@ -36831,7 +37101,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
36831
37101
|
});
|
|
36832
37102
|
}
|
|
36833
37103
|
{
|
|
36834
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37104
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
36835
37105
|
const outlookScript = resolve49(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
36836
37106
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
36837
37107
|
const runOutlookComplete = (ctx) => {
|
|
@@ -36857,7 +37127,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
36857
37127
|
});
|
|
36858
37128
|
}
|
|
36859
37129
|
{
|
|
36860
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37130
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
36861
37131
|
const strandedAccountsDir = resolve49(auditRoot, "..", "data/accounts");
|
|
36862
37132
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
36863
37133
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
@@ -36887,7 +37157,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
36887
37157
|
});
|
|
36888
37158
|
}
|
|
36889
37159
|
{
|
|
36890
|
-
const googleRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37160
|
+
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
36891
37161
|
const googleAccountsDir = resolve49(googleRoot, "..", "data/accounts");
|
|
36892
37162
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
36893
37163
|
const runGooglePendingAuditSafe = () => {
|
|
@@ -36931,7 +37201,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
36931
37201
|
});
|
|
36932
37202
|
}
|
|
36933
37203
|
{
|
|
36934
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37204
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
36935
37205
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
36936
37206
|
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
36937
37207
|
console.error(`[storage-audit] error="${err.message}"`);
|
|
@@ -37133,7 +37403,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
37133
37403
|
});
|
|
37134
37404
|
}
|
|
37135
37405
|
{
|
|
37136
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37406
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
37137
37407
|
const publishScript = resolve49(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
37138
37408
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
37139
37409
|
const bookingAccounts = () => {
|
|
@@ -37210,7 +37480,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
37210
37480
|
startTimeEntryCensus(() => getSession());
|
|
37211
37481
|
startLedgerCensus(() => getSession());
|
|
37212
37482
|
{
|
|
37213
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
37483
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
|
|
37214
37484
|
const auditScript = resolve49(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
37215
37485
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
37216
37486
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -37422,8 +37692,8 @@ var runIngestAuditTick = () => {
|
|
|
37422
37692
|
},
|
|
37423
37693
|
agentExists: (accountId, slug) => {
|
|
37424
37694
|
if (!house) return false;
|
|
37425
|
-
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir :
|
|
37426
|
-
return existsSync54(
|
|
37695
|
+
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join61(ACCOUNTS_DIR, accountId);
|
|
37696
|
+
return existsSync54(join61(dir, "agents", slug, "config.json"));
|
|
37427
37697
|
}
|
|
37428
37698
|
});
|
|
37429
37699
|
} catch (err) {
|
|
@@ -37471,7 +37741,7 @@ registerLoop({
|
|
|
37471
37741
|
runPublicAddressCollisionAudit({
|
|
37472
37742
|
houseAccountId: () => resolveAccount()?.accountId ?? null,
|
|
37473
37743
|
activeSlugs: () => listValidAccounts().map((a) => {
|
|
37474
|
-
const agentsRoot =
|
|
37744
|
+
const agentsRoot = join61(a.accountDir, "agents");
|
|
37475
37745
|
if (!existsSync54(agentsRoot)) return { accountId: a.accountId, slugs: [] };
|
|
37476
37746
|
const slugs = readdirSync32(agentsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((slug) => isActiveAgentSlug(a.accountDir, slug));
|
|
37477
37747
|
return { accountId: a.accountId, slugs };
|
|
@@ -37655,7 +37925,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
37655
37925
|
}
|
|
37656
37926
|
init({
|
|
37657
37927
|
configDir: configDirForWhatsApp,
|
|
37658
|
-
platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ??
|
|
37928
|
+
platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..")),
|
|
37659
37929
|
accountConfig: bootAccountConfig,
|
|
37660
37930
|
// Task 2074 — enrich with the sub-account name and fan out to every open
|
|
37661
37931
|
// admin SSE stream. Fire-and-forget: the manager's persist path must not
|