@rubytech/create-maxy-code 0.1.536 → 0.1.537
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/hooks/__tests__/mailbox-inject.test.sh +11 -5
- package/payload/platform/plugins/admin/hooks/mailbox-inject.sh +12 -7
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +47 -4
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +5 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +46 -3
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +6 -6
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +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 +67 -4
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +23 -2
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +7 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +8 -2
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +32 -27
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.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-BpHVvUsH.js → AdminLoginScreens-CYFf2awh.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-CYFf2awh.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-CYFf2awh.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-7l3ubYFZ.js +2 -0
- package/payload/server/public/assets/AdminShell-7l3ubYFZ.js.br +0 -0
- package/payload/server/public/assets/AdminShell-7l3ubYFZ.js.gz +0 -0
- package/payload/server/public/assets/{activity-B3WEyiTh.js → activity-BH65sm9Q.js} +1 -1
- package/payload/server/public/assets/activity-BH65sm9Q.js.br +0 -0
- package/payload/server/public/assets/activity-BH65sm9Q.js.gz +0 -0
- package/payload/server/public/assets/admin-CQtEjRGU.js +1 -0
- package/payload/server/public/assets/admin-CQtEjRGU.js.br +0 -0
- package/payload/server/public/assets/admin-CQtEjRGU.js.gz +0 -0
- package/payload/server/public/assets/{agents-CmYDQbdM.js → agents-CjhOWwl5.js} +1 -1
- package/payload/server/public/assets/agents-CjhOWwl5.js.br +0 -0
- package/payload/server/public/assets/agents-CjhOWwl5.js.gz +0 -0
- package/payload/server/public/assets/{browser-CP8TnIUm.js → browser-DGXpfL99.js} +1 -1
- package/payload/server/public/assets/browser-DGXpfL99.js.br +0 -0
- package/payload/server/public/assets/browser-DGXpfL99.js.gz +0 -0
- package/payload/server/public/assets/calendar-Cu4yjEuX.js +1 -0
- package/payload/server/public/assets/calendar-Cu4yjEuX.js.br +0 -0
- package/payload/server/public/assets/calendar-Cu4yjEuX.js.gz +0 -0
- package/payload/server/public/assets/chat-0na4XVZC.js +1 -0
- package/payload/server/public/assets/chat-0na4XVZC.js.br +0 -0
- package/payload/server/public/assets/chat-0na4XVZC.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-DHzJobWp.js +1 -0
- package/payload/server/public/assets/chevron-left-DHzJobWp.js.br +0 -0
- package/payload/server/public/assets/chevron-right-yg4DMfLT.js +1 -0
- package/payload/server/public/assets/chevron-right-yg4DMfLT.js.br +0 -0
- package/payload/server/public/assets/clock-BIDzihvp.js +1 -0
- package/payload/server/public/assets/clock-BIDzihvp.js.br +0 -0
- package/payload/server/public/assets/clock-BIDzihvp.js.gz +0 -0
- package/payload/server/public/assets/data-Ql9qG3YO.js +1 -0
- package/payload/server/public/assets/data-Ql9qG3YO.js.br +0 -0
- package/payload/server/public/assets/data-Ql9qG3YO.js.gz +0 -0
- package/payload/server/public/assets/{file-text-lsHlk4lR.js → file-text-CbQoZfJD.js} +1 -1
- package/payload/server/public/assets/file-text-CbQoZfJD.js.br +0 -0
- package/payload/server/public/assets/file-text-CbQoZfJD.js.gz +0 -0
- package/payload/server/public/assets/{graph-B0awsgVj.js → graph-7414Kjn9.js} +3 -3
- package/payload/server/public/assets/graph-7414Kjn9.js.br +0 -0
- package/payload/server/public/assets/graph-7414Kjn9.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-Ci5Jz1oY.js → graph-labels-D695CsC9.js} +1 -1
- package/payload/server/public/assets/graph-labels-D695CsC9.js.br +0 -0
- package/payload/server/public/assets/graph-labels-D695CsC9.js.gz +0 -0
- package/payload/server/public/assets/{maximize-2-DRndYysc.js → maximize-2-CD0gTjW_.js} +1 -1
- package/payload/server/public/assets/maximize-2-CD0gTjW_.js.br +0 -0
- package/payload/server/public/assets/maximize-2-CD0gTjW_.js.gz +0 -0
- package/payload/server/public/assets/operator-CLw4PZs5.js +1 -0
- package/payload/server/public/assets/operator-CLw4PZs5.js.br +0 -0
- package/payload/server/public/assets/operator-CLw4PZs5.js.gz +0 -0
- package/payload/server/public/assets/{page-RkwjxAgF.js → page-BNRFmFc-.js} +5 -5
- package/payload/server/public/assets/page-BNRFmFc-.js.br +0 -0
- package/payload/server/public/assets/page-BNRFmFc-.js.gz +0 -0
- package/payload/server/public/assets/page-BRr295G2.js +1 -0
- package/payload/server/public/assets/page-BRr295G2.js.br +0 -0
- package/payload/server/public/assets/page-BRr295G2.js.gz +0 -0
- package/payload/server/public/assets/play-CbRU6q0T.js +1 -0
- package/payload/server/public/assets/play-CbRU6q0T.js.br +0 -0
- package/payload/server/public/assets/play-CbRU6q0T.js.gz +0 -0
- package/payload/server/public/assets/{public-BNAVdC2B.js → public-CqbKJ-Q3.js} +1 -1
- package/payload/server/public/assets/public-CqbKJ-Q3.js.br +0 -0
- package/payload/server/public/assets/public-CqbKJ-Q3.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-D6DZb7tR.js → rotate-ccw-CjliWBou.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-CjliWBou.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-CjliWBou.js.gz +0 -0
- package/payload/server/public/assets/routines-yJuRuBfn.js +2 -0
- package/payload/server/public/assets/routines-yJuRuBfn.js.br +0 -0
- package/payload/server/public/assets/routines-yJuRuBfn.js.gz +0 -0
- package/payload/server/public/assets/{skills-9S_nNIpO.js → skills-ipK9BJFb.js} +1 -1
- package/payload/server/public/assets/skills-ipK9BJFb.js.br +0 -0
- package/payload/server/public/assets/skills-ipK9BJFb.js.gz +0 -0
- package/payload/server/public/assets/tasks-CGcJHQ3X.js +3 -0
- package/payload/server/public/assets/tasks-CGcJHQ3X.js.br +0 -0
- package/payload/server/public/assets/tasks-CGcJHQ3X.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-BcpCZDHe.js → triangle-alert-CjsLPsBD.js} +1 -1
- package/payload/server/public/assets/triangle-alert-CjsLPsBD.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-CjsLPsBD.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-DqTnYnz5.js → useCopyFeedback-umIgCxI_.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-umIgCxI_.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-umIgCxI_.js.gz +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-CYEDydoq.css → useSubAccountSwitcher-D8jXV7R5.css} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-D8jXV7R5.css.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-CYEDydoq.css.gz → useSubAccountSwitcher-D8jXV7R5.css.gz} +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-UMg53kKF.js +14 -0
- package/payload/server/public/assets/useSubAccountSwitcher-UMg53kKF.js.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-UMg53kKF.js.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-tzfqfXni.js +2 -0
- package/payload/server/public/assets/useVoiceRecorder-tzfqfXni.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-tzfqfXni.js.gz +0 -0
- package/payload/server/public/assets/{wrench-DvUj2R3p.js → wrench-DtfKfR4s.js} +1 -1
- package/payload/server/public/assets/wrench-DtfKfR4s.js.br +0 -0
- package/payload/server/public/assets/wrench-DtfKfR4s.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 +14 -14
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +6 -6
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +692 -439
- package/payload/server/public/assets/AdminLoginScreens-BpHVvUsH.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BpHVvUsH.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-BT7VQIu7.js +0 -2
- package/payload/server/public/assets/AdminShell-BT7VQIu7.js.br +0 -0
- package/payload/server/public/assets/AdminShell-BT7VQIu7.js.gz +0 -0
- package/payload/server/public/assets/activity-B3WEyiTh.js.br +0 -0
- package/payload/server/public/assets/activity-B3WEyiTh.js.gz +0 -0
- package/payload/server/public/assets/admin-BEKL9Bq_.js +0 -1
- package/payload/server/public/assets/admin-BEKL9Bq_.js.br +0 -0
- package/payload/server/public/assets/admin-BEKL9Bq_.js.gz +0 -0
- package/payload/server/public/assets/agents-CmYDQbdM.js.br +0 -0
- package/payload/server/public/assets/agents-CmYDQbdM.js.gz +0 -0
- package/payload/server/public/assets/browser-CP8TnIUm.js.br +0 -0
- package/payload/server/public/assets/browser-CP8TnIUm.js.gz +0 -0
- package/payload/server/public/assets/calendar-DM6Bl8Ra.js +0 -1
- package/payload/server/public/assets/calendar-DM6Bl8Ra.js.br +0 -0
- package/payload/server/public/assets/calendar-DM6Bl8Ra.js.gz +0 -0
- package/payload/server/public/assets/chat-BJWdNwCN.js +0 -1
- package/payload/server/public/assets/chat-BJWdNwCN.js.br +0 -2
- package/payload/server/public/assets/chat-BJWdNwCN.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-DU8Es8Xq.js +0 -1
- package/payload/server/public/assets/chevron-right-D8HTOkyy.js +0 -1
- package/payload/server/public/assets/chevron-right-D8HTOkyy.js.br +0 -0
- package/payload/server/public/assets/clock-BdNuUyUU.js +0 -1
- package/payload/server/public/assets/clock-BdNuUyUU.js.br +0 -0
- package/payload/server/public/assets/clock-BdNuUyUU.js.gz +0 -0
- package/payload/server/public/assets/data-EjLIuy-W.js +0 -1
- package/payload/server/public/assets/data-EjLIuy-W.js.br +0 -0
- package/payload/server/public/assets/data-EjLIuy-W.js.gz +0 -0
- package/payload/server/public/assets/file-text-lsHlk4lR.js.br +0 -0
- package/payload/server/public/assets/file-text-lsHlk4lR.js.gz +0 -0
- package/payload/server/public/assets/graph-B0awsgVj.js.br +0 -0
- package/payload/server/public/assets/graph-B0awsgVj.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-Ci5Jz1oY.js.br +0 -0
- package/payload/server/public/assets/graph-labels-Ci5Jz1oY.js.gz +0 -0
- package/payload/server/public/assets/maximize-2-DRndYysc.js.br +0 -0
- package/payload/server/public/assets/maximize-2-DRndYysc.js.gz +0 -0
- package/payload/server/public/assets/operator-tiI-kz6v.js +0 -1
- package/payload/server/public/assets/operator-tiI-kz6v.js.br +0 -0
- package/payload/server/public/assets/operator-tiI-kz6v.js.gz +0 -0
- package/payload/server/public/assets/page-RkwjxAgF.js.br +0 -0
- package/payload/server/public/assets/page-RkwjxAgF.js.gz +0 -0
- package/payload/server/public/assets/page-ZG7SXMO0.js +0 -1
- package/payload/server/public/assets/page-ZG7SXMO0.js.br +0 -0
- package/payload/server/public/assets/page-ZG7SXMO0.js.gz +0 -0
- package/payload/server/public/assets/public-BNAVdC2B.js.br +0 -0
- package/payload/server/public/assets/public-BNAVdC2B.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-D6DZb7tR.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-D6DZb7tR.js.gz +0 -0
- package/payload/server/public/assets/routines-BVcPovu-.js +0 -2
- package/payload/server/public/assets/routines-BVcPovu-.js.br +0 -0
- package/payload/server/public/assets/routines-BVcPovu-.js.gz +0 -0
- package/payload/server/public/assets/skills-9S_nNIpO.js.br +0 -0
- package/payload/server/public/assets/skills-9S_nNIpO.js.gz +0 -0
- package/payload/server/public/assets/tasks-D-D2efaL.js +0 -3
- package/payload/server/public/assets/tasks-D-D2efaL.js.br +0 -0
- package/payload/server/public/assets/tasks-D-D2efaL.js.gz +0 -0
- package/payload/server/public/assets/time-entry-format-CKpHcWWs.js +0 -1
- package/payload/server/public/assets/time-entry-format-CKpHcWWs.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-CKpHcWWs.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-BcpCZDHe.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-BcpCZDHe.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-DqTnYnz5.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-DqTnYnz5.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-CYEDydoq.css.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-ny9tP8am.js +0 -14
- package/payload/server/public/assets/useSubAccountSwitcher-ny9tP8am.js.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-ny9tP8am.js.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DcgtZl-4.js +0 -2
- package/payload/server/public/assets/useVoiceRecorder-DcgtZl-4.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DcgtZl-4.js.gz +0 -0
- package/payload/server/public/assets/wrench-DvUj2R3p.js.br +0 -2
- package/payload/server/public/assets/wrench-DvUj2R3p.js.gz +0 -0
package/payload/server/server.js
CHANGED
|
@@ -2385,11 +2385,11 @@ function staticCacheHeaders(root) {
|
|
|
2385
2385
|
}
|
|
2386
2386
|
|
|
2387
2387
|
// server/lib/static-mounts.ts
|
|
2388
|
-
function mountStaticFiles(
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2388
|
+
function mountStaticFiles(app77, root) {
|
|
2389
|
+
app77.use("/*", staticCacheHeaders(root));
|
|
2390
|
+
app77.use("/assets/*", assetsVary);
|
|
2391
|
+
app77.use("/assets/*", serveStatic({ root, precompressed: true }));
|
|
2392
|
+
app77.use("/*", serveStatic({ root }));
|
|
2393
2393
|
}
|
|
2394
2394
|
var assetsVary = async (c, next) => {
|
|
2395
2395
|
await next();
|
|
@@ -3589,8 +3589,8 @@ function webchatTurnTimeoutMs() {
|
|
|
3589
3589
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
3590
3590
|
}
|
|
3591
3591
|
function createChatRoutes(deps) {
|
|
3592
|
-
const
|
|
3593
|
-
|
|
3592
|
+
const app77 = new Hono();
|
|
3593
|
+
app77.post("/", async (c) => {
|
|
3594
3594
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
3595
3595
|
const contentType = c.req.header("content-type") ?? "";
|
|
3596
3596
|
const account = resolveAccount();
|
|
@@ -3862,7 +3862,7 @@ ${result.result.text}` : result.result.text;
|
|
|
3862
3862
|
}
|
|
3863
3863
|
});
|
|
3864
3864
|
});
|
|
3865
|
-
return
|
|
3865
|
+
return app77;
|
|
3866
3866
|
}
|
|
3867
3867
|
|
|
3868
3868
|
// server/routes/channel/schedule-inject.ts
|
|
@@ -4806,8 +4806,8 @@ function transcriptBoundary(sessionKey) {
|
|
|
4806
4806
|
}
|
|
4807
4807
|
}
|
|
4808
4808
|
function createScheduleInjectRoutes(deps) {
|
|
4809
|
-
const
|
|
4810
|
-
|
|
4809
|
+
const app77 = new Hono();
|
|
4810
|
+
app77.post("/", async (c) => {
|
|
4811
4811
|
const env = c.env;
|
|
4812
4812
|
const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
|
|
4813
4813
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
@@ -4918,7 +4918,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
4918
4918
|
console.error(`${TAG5} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
|
|
4919
4919
|
return c.json({ ok: true, sessionKey: sessionId, ...transcriptBoundary(sessionId) }, 200);
|
|
4920
4920
|
});
|
|
4921
|
-
return
|
|
4921
|
+
return app77;
|
|
4922
4922
|
}
|
|
4923
4923
|
|
|
4924
4924
|
// server/index.ts
|
|
@@ -5844,7 +5844,7 @@ function setDispatchInbound(accountDir, accountId, value, ctx) {
|
|
|
5844
5844
|
const id = accountId.trim();
|
|
5845
5845
|
if (!id) return { ok: false, reason: "missing-account-id", error: "Missing account id." };
|
|
5846
5846
|
const verdict = resolveKey(id, ctx);
|
|
5847
|
-
const failure = policyKeyFailure(verdict, id,
|
|
5847
|
+
const failure = policyKeyFailure(verdict, id, null);
|
|
5848
5848
|
if (failure) {
|
|
5849
5849
|
console.error(`${TAG10} op=set-dispatch-inbound account=${id} ok=false reason=${failure.reason}`);
|
|
5850
5850
|
return failure;
|
|
@@ -5880,16 +5880,9 @@ function setDispatchInbound(accountDir, accountId, value, ctx) {
|
|
|
5880
5880
|
return { ok: false, reason: "write-failed", error: msg };
|
|
5881
5881
|
}
|
|
5882
5882
|
}
|
|
5883
|
-
function policyKeyFailure(verdict, accountId,
|
|
5883
|
+
function policyKeyFailure(verdict, accountId, houseFailure) {
|
|
5884
5884
|
if (verdict.kind === "self") return null;
|
|
5885
|
-
if (verdict.kind === "house")
|
|
5886
|
-
if (!opts.refuseHouse) return null;
|
|
5887
|
-
return {
|
|
5888
|
-
ok: false,
|
|
5889
|
-
reason: "house-policy-is-top-level",
|
|
5890
|
-
error: `Account "${accountId}" is the house. Its dmPolicy, adminPhones and allowFrom are the TOP-LEVEL WhatsApp config, not a per-account override \u2014 set them with the "update-config" action (adminPhones also has add-admin-phone / remove-admin-phone). Writing a per-account slice for the house would create a second home for the same three fields.`
|
|
5891
|
-
};
|
|
5892
|
-
}
|
|
5885
|
+
if (verdict.kind === "house") return houseFailure;
|
|
5893
5886
|
if (verdict.kind === "ambiguous") {
|
|
5894
5887
|
return {
|
|
5895
5888
|
ok: false,
|
|
@@ -5903,6 +5896,13 @@ function policyKeyFailure(verdict, accountId, opts) {
|
|
|
5903
5896
|
error: `Account "${accountId}" has no WhatsApp credential directory, so it has no config slice the inbound gate would read. Pair the account first.`
|
|
5904
5897
|
};
|
|
5905
5898
|
}
|
|
5899
|
+
function policyHouseFailure(accountId) {
|
|
5900
|
+
return {
|
|
5901
|
+
ok: false,
|
|
5902
|
+
reason: "house-policy-is-top-level",
|
|
5903
|
+
error: `Account "${accountId}" is the house. Its dmPolicy, adminPhones and allowFrom are the TOP-LEVEL WhatsApp config, not a per-account override \u2014 set them with the "update-config" action (adminPhones also has add-admin-phone / remove-admin-phone). Writing a per-account slice for the house would create a second home for the same three fields.`
|
|
5904
|
+
};
|
|
5905
|
+
}
|
|
5906
5906
|
function resolveKey(accountId, ctx) {
|
|
5907
5907
|
return resolveAccountConfigKey({
|
|
5908
5908
|
targetAccountId: accountId,
|
|
@@ -5925,7 +5925,7 @@ function setAccountPolicy(accountDir, accountId, policy, ctx) {
|
|
|
5925
5925
|
};
|
|
5926
5926
|
}
|
|
5927
5927
|
const verdict = resolveKey(id, ctx);
|
|
5928
|
-
const failure = policyKeyFailure(verdict, id,
|
|
5928
|
+
const failure = policyKeyFailure(verdict, id, policyHouseFailure(id));
|
|
5929
5929
|
if (failure) {
|
|
5930
5930
|
console.error(`${TAG10} op=set-account-policy account=${id} ok=false reason=${failure.reason}`);
|
|
5931
5931
|
return failure;
|
|
@@ -5963,7 +5963,7 @@ function readAccountPolicy(accountDir, accountId, ctx) {
|
|
|
5963
5963
|
const id = accountId.trim();
|
|
5964
5964
|
if (!id) return { ok: false, reason: "missing-account-id", error: "Missing account id." };
|
|
5965
5965
|
const verdict = resolveKey(id, ctx);
|
|
5966
|
-
const failure = policyKeyFailure(verdict, id,
|
|
5966
|
+
const failure = policyKeyFailure(verdict, id, null);
|
|
5967
5967
|
if (failure) return failure;
|
|
5968
5968
|
const key = verdict.key;
|
|
5969
5969
|
try {
|
|
@@ -6035,14 +6035,43 @@ function readAccountManagers(accountDir) {
|
|
|
6035
6035
|
return {};
|
|
6036
6036
|
}
|
|
6037
6037
|
}
|
|
6038
|
-
function
|
|
6038
|
+
function publicAgentHouseFailure(accountId) {
|
|
6039
|
+
return {
|
|
6040
|
+
ok: false,
|
|
6041
|
+
reason: "house-public-agent-is-top-level",
|
|
6042
|
+
error: `Account "${accountId}" is the house. Its publicAgent and publicAgentEnabled are the TOP-LEVEL WhatsApp config \u2014 set them by calling this action without an accountId. Writing a per-account slice for the house would create a second home for the same field.`
|
|
6043
|
+
};
|
|
6044
|
+
}
|
|
6045
|
+
function publicAgentKey(target) {
|
|
6046
|
+
if (target.scope === "top-level") return { key: null };
|
|
6047
|
+
const id = target.accountId.trim();
|
|
6048
|
+
if (!id) return { ok: false, reason: "missing-account-id", error: "Missing account id." };
|
|
6049
|
+
const verdict = resolveKey(id, target.ctx);
|
|
6050
|
+
const failure = policyKeyFailure(verdict, id, publicAgentHouseFailure(id));
|
|
6051
|
+
if (failure) return failure;
|
|
6052
|
+
return { key: verdict.key };
|
|
6053
|
+
}
|
|
6054
|
+
function publicAgentScopeLabel(target) {
|
|
6055
|
+
return target.scope === "top-level" ? "the top-level default" : `account ${target.accountId}`;
|
|
6056
|
+
}
|
|
6057
|
+
function setPublicAgent(accountDir, slug, target) {
|
|
6039
6058
|
const trimmed = slug.trim();
|
|
6040
6059
|
if (!trimmed) {
|
|
6041
|
-
return { ok: false, error: "Agent slug cannot be empty." };
|
|
6060
|
+
return { ok: false, reason: "missing-slug", error: "Agent slug cannot be empty." };
|
|
6042
6061
|
}
|
|
6043
|
-
const
|
|
6062
|
+
const resolvedKey = publicAgentKey(target);
|
|
6063
|
+
if ("ok" in resolvedKey) {
|
|
6064
|
+
console.error(`${TAG10} op=set-public-agent accountId=${publicAgentScopeLabel(target)} ok=false reason=${resolvedKey.reason}`);
|
|
6065
|
+
return resolvedKey;
|
|
6066
|
+
}
|
|
6067
|
+
const key = resolvedKey.key;
|
|
6068
|
+
const agentConfigPath = join12(target.agentsDir, "agents", trimmed, "config.json");
|
|
6044
6069
|
if (!existsSync6(agentConfigPath)) {
|
|
6045
|
-
return {
|
|
6070
|
+
return {
|
|
6071
|
+
ok: false,
|
|
6072
|
+
reason: "agent-not-found",
|
|
6073
|
+
error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.`
|
|
6074
|
+
};
|
|
6046
6075
|
}
|
|
6047
6076
|
try {
|
|
6048
6077
|
const config = readConfig(accountDir);
|
|
@@ -6050,46 +6079,58 @@ function setPublicAgent(accountDir, slug) {
|
|
|
6050
6079
|
config.whatsapp = {};
|
|
6051
6080
|
}
|
|
6052
6081
|
const wa = config.whatsapp;
|
|
6053
|
-
|
|
6082
|
+
if (key) {
|
|
6083
|
+
if (!wa.accounts || typeof wa.accounts !== "object") wa.accounts = {};
|
|
6084
|
+
const accounts = wa.accounts;
|
|
6085
|
+
if (!accounts[key] || typeof accounts[key] !== "object") accounts[key] = {};
|
|
6086
|
+
accounts[key].publicAgent = trimmed;
|
|
6087
|
+
} else {
|
|
6088
|
+
wa.publicAgent = trimmed;
|
|
6089
|
+
}
|
|
6054
6090
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
6055
6091
|
if (!parsed.success) {
|
|
6056
6092
|
const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
6057
|
-
return { ok: false, error: `Validation failed: ${msg}` };
|
|
6093
|
+
return { ok: false, reason: "validation-failed", error: `Validation failed: ${msg}` };
|
|
6058
6094
|
}
|
|
6059
6095
|
config.whatsapp = parsed.data;
|
|
6060
6096
|
writeConfig(accountDir, config);
|
|
6061
|
-
console.error(
|
|
6097
|
+
console.error(
|
|
6098
|
+
`${TAG10} op=set-public-agent accountId=${target.scope === "top-level" ? "top-level" : target.accountId} key=${key ?? "top-level"} slug=${trimmed} ok=true`
|
|
6099
|
+
);
|
|
6062
6100
|
reloadManagerConfig(accountDir);
|
|
6063
|
-
return {
|
|
6101
|
+
return {
|
|
6102
|
+
ok: true,
|
|
6103
|
+
key,
|
|
6104
|
+
message: `Public agent for ${publicAgentScopeLabel(target)} set to "${trimmed}". WhatsApp messages from non-admin phones will be handled by this agent.`
|
|
6105
|
+
};
|
|
6064
6106
|
} catch (err) {
|
|
6065
6107
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6066
|
-
console.error(`${TAG10}
|
|
6067
|
-
return { ok: false, error: msg };
|
|
6108
|
+
console.error(`${TAG10} op=set-public-agent ok=false reason=write-failed detail=${msg}`);
|
|
6109
|
+
return { ok: false, reason: "write-failed", error: msg };
|
|
6068
6110
|
}
|
|
6069
6111
|
}
|
|
6070
|
-
function setPublicAgentEnabled(accountDir, enabled,
|
|
6071
|
-
const
|
|
6072
|
-
const
|
|
6112
|
+
function setPublicAgentEnabled(accountDir, enabled, target) {
|
|
6113
|
+
const scope = publicAgentScopeLabel(target);
|
|
6114
|
+
const resolvedKey = publicAgentKey(target);
|
|
6115
|
+
if ("ok" in resolvedKey) {
|
|
6116
|
+
console.error(`${TAG10} op=set-public-agent-enabled accountId=${scope} ok=false reason=${resolvedKey.reason}`);
|
|
6117
|
+
return resolvedKey;
|
|
6118
|
+
}
|
|
6119
|
+
const key = resolvedKey.key;
|
|
6073
6120
|
if (enabled) {
|
|
6074
|
-
const resolved =
|
|
6075
|
-
try {
|
|
6076
|
-
const wa = readConfig(accountDir).whatsapp;
|
|
6077
|
-
const top = wa?.publicAgent;
|
|
6078
|
-
return typeof top === "string" && top.trim() ? { slug: top.trim(), source: "top-level" } : null;
|
|
6079
|
-
} catch {
|
|
6080
|
-
return null;
|
|
6081
|
-
}
|
|
6082
|
-
})();
|
|
6121
|
+
const resolved = key ? resolvePublicAgent(accountDir, { accountId: key, isHouse: false }) : resolvePublicAgent(accountDir, { accountId: "", isHouse: true });
|
|
6083
6122
|
if (!resolved) {
|
|
6084
6123
|
return {
|
|
6085
6124
|
ok: false,
|
|
6125
|
+
reason: "no-public-agent",
|
|
6086
6126
|
error: `Cannot enable public answering for ${scope}: no public agent is configured. Set one with set-public-agent first.`
|
|
6087
6127
|
};
|
|
6088
6128
|
}
|
|
6089
|
-
const agentConfigPath = join12(
|
|
6129
|
+
const agentConfigPath = join12(target.agentsDir, "agents", resolved.slug, "config.json");
|
|
6090
6130
|
if (!existsSync6(agentConfigPath)) {
|
|
6091
6131
|
return {
|
|
6092
6132
|
ok: false,
|
|
6133
|
+
reason: "agent-not-found",
|
|
6093
6134
|
error: `Cannot enable public answering for ${scope}: the configured agent "${resolved.slug}" has no config.json at ${agentConfigPath}. Point publicAgent at an existing agent first.`
|
|
6094
6135
|
};
|
|
6095
6136
|
}
|
|
@@ -6100,33 +6141,34 @@ function setPublicAgentEnabled(accountDir, enabled, opts) {
|
|
|
6100
6141
|
config.whatsapp = {};
|
|
6101
6142
|
}
|
|
6102
6143
|
const wa = config.whatsapp;
|
|
6103
|
-
if (
|
|
6144
|
+
if (key) {
|
|
6104
6145
|
if (!wa.accounts || typeof wa.accounts !== "object") wa.accounts = {};
|
|
6105
6146
|
const accounts = wa.accounts;
|
|
6106
|
-
if (!accounts[
|
|
6107
|
-
|
|
6108
|
-
}
|
|
6109
|
-
accounts[accountId].publicAgentEnabled = enabled;
|
|
6147
|
+
if (!accounts[key] || typeof accounts[key] !== "object") accounts[key] = {};
|
|
6148
|
+
accounts[key].publicAgentEnabled = enabled;
|
|
6110
6149
|
} else {
|
|
6111
6150
|
wa.publicAgentEnabled = enabled;
|
|
6112
6151
|
}
|
|
6113
6152
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
6114
6153
|
if (!parsed.success) {
|
|
6115
6154
|
const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
6116
|
-
return { ok: false, error: `Validation failed: ${msg}` };
|
|
6155
|
+
return { ok: false, reason: "validation-failed", error: `Validation failed: ${msg}` };
|
|
6117
6156
|
}
|
|
6118
6157
|
config.whatsapp = parsed.data;
|
|
6119
6158
|
writeConfig(accountDir, config);
|
|
6120
|
-
console.error(
|
|
6159
|
+
console.error(
|
|
6160
|
+
`${TAG10} op=set-public-agent-enabled accountId=${target.scope === "top-level" ? "top-level" : target.accountId} key=${key ?? "top-level"} enabled=${enabled} ok=true`
|
|
6161
|
+
);
|
|
6121
6162
|
reloadManagerConfig(accountDir);
|
|
6122
6163
|
return {
|
|
6123
6164
|
ok: true,
|
|
6165
|
+
key,
|
|
6124
6166
|
message: enabled ? `Public answering enabled for ${scope}. Non-admin WhatsApp senders will be answered by the configured public agent.` : `Public answering disabled for ${scope}. Non-admin WhatsApp senders receive no reply; account managers are still notified.`
|
|
6125
6167
|
};
|
|
6126
6168
|
} catch (err) {
|
|
6127
6169
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6128
|
-
console.error(`${TAG10}
|
|
6129
|
-
return { ok: false, error: msg };
|
|
6170
|
+
console.error(`${TAG10} op=set-public-agent-enabled ok=false reason=write-failed detail=${msg}`);
|
|
6171
|
+
return { ok: false, reason: "write-failed", error: msg };
|
|
6130
6172
|
}
|
|
6131
6173
|
}
|
|
6132
6174
|
function resolvePublicAgent(accountDir, opts) {
|
|
@@ -6140,6 +6182,7 @@ function resolvePublicAgent(accountDir, opts) {
|
|
|
6140
6182
|
if (typeof accountSlug === "string" && accountSlug.trim()) {
|
|
6141
6183
|
return { slug: accountSlug.trim(), source: "account" };
|
|
6142
6184
|
}
|
|
6185
|
+
if (!opts.isHouse) return null;
|
|
6143
6186
|
const topSlug = wa.publicAgent;
|
|
6144
6187
|
if (typeof topSlug === "string" && topSlug.trim()) {
|
|
6145
6188
|
return { slug: topSlug.trim(), source: "top-level" };
|
|
@@ -6159,6 +6202,7 @@ function resolvePublicAgentEnabled(accountDir, opts) {
|
|
|
6159
6202
|
if (typeof account?.publicAgentEnabled === "boolean") {
|
|
6160
6203
|
return { enabled: account.publicAgentEnabled, source: "account" };
|
|
6161
6204
|
}
|
|
6205
|
+
if (!opts.isHouse) return { enabled: false, source: "default" };
|
|
6162
6206
|
if (typeof wa.publicAgentEnabled === "boolean") {
|
|
6163
6207
|
return { enabled: wa.publicAgentEnabled, source: "top-level" };
|
|
6164
6208
|
}
|
|
@@ -7440,6 +7484,65 @@ app3.post("/config", async (c) => {
|
|
|
7440
7484
|
console.error(`${TAG15} config action=set-account-policy account=${target} ok=${result.ok}${result.ok ? "" : ` reason=${result.reason}`}`);
|
|
7441
7485
|
return c.json(result, result.ok ? 200 : 400);
|
|
7442
7486
|
}
|
|
7487
|
+
if (action === "set-public-agent" || action === "get-public-agent" || action === "set-public-agent-enabled" || action === "list-public-agents") {
|
|
7488
|
+
const acct = resolveAccount();
|
|
7489
|
+
if (!acct) return c.json({ ok: false, error: "No account configured." }, 500);
|
|
7490
|
+
const resolved = resolveLifecycleAccountId(c, accountId);
|
|
7491
|
+
const topLevel = resolved.targetSource === "house-default";
|
|
7492
|
+
if (topLevel) {
|
|
7493
|
+
const denial2 = houseSocketScopeDenial(c, `config action=${action}`);
|
|
7494
|
+
if (denial2) return denial2;
|
|
7495
|
+
} else {
|
|
7496
|
+
const denial2 = selfOrHouseScopeDenial(c, resolved.accountId, `config action=${action}`, resolved.targetSource);
|
|
7497
|
+
if (denial2) return denial2;
|
|
7498
|
+
}
|
|
7499
|
+
const targetDir = topLevel ? acct.accountDir : listValidAccounts().find((a) => a.accountId === resolved.accountId)?.accountDir;
|
|
7500
|
+
if (!targetDir) {
|
|
7501
|
+
return c.json({ ok: false, error: `Account "${resolved.accountId}" is not provisioned on this install.` }, 400);
|
|
7502
|
+
}
|
|
7503
|
+
const writeTarget = topLevel ? { scope: "top-level", agentsDir: targetDir } : { scope: "account", accountId: resolved.accountId, agentsDir: targetDir, ctx: accountPolicyContext() };
|
|
7504
|
+
if (action === "set-public-agent") {
|
|
7505
|
+
if (!slug || typeof slug !== "string") {
|
|
7506
|
+
return c.json({ ok: false, error: 'Missing required field "slug" (the agent directory name, e.g. "my-agent").' }, 400);
|
|
7507
|
+
}
|
|
7508
|
+
const result = setPublicAgent(acct.accountDir, slug, writeTarget);
|
|
7509
|
+
return c.json(result, result.ok ? 200 : 400);
|
|
7510
|
+
}
|
|
7511
|
+
if (action === "set-public-agent-enabled") {
|
|
7512
|
+
if (typeof enabled !== "boolean") {
|
|
7513
|
+
return c.json({ ok: false, error: 'Missing required field "enabled" (true or false).' }, 400);
|
|
7514
|
+
}
|
|
7515
|
+
const result = setPublicAgentEnabled(acct.accountDir, enabled, writeTarget);
|
|
7516
|
+
return c.json(result, result.ok ? 200 : 400);
|
|
7517
|
+
}
|
|
7518
|
+
if (action === "get-public-agent") {
|
|
7519
|
+
const readKey2 = topLevel ? "default" : resolved.accountId;
|
|
7520
|
+
const resolvedAgent = resolvePublicAgent(acct.accountDir, { accountId: readKey2, isHouse: topLevel });
|
|
7521
|
+
console.error(`${TAG15} config action=get-public-agent accountId=${topLevel ? "top-level" : resolved.accountId} slug=${resolvedAgent?.slug ?? "none"} source=${resolvedAgent?.source ?? "none"}`);
|
|
7522
|
+
return c.json({ ok: true, slug: resolvedAgent?.slug ?? null, source: resolvedAgent?.source ?? null });
|
|
7523
|
+
}
|
|
7524
|
+
const agentsDir = resolve7(targetDir, "agents");
|
|
7525
|
+
const agents = [];
|
|
7526
|
+
if (existsSync8(agentsDir)) {
|
|
7527
|
+
try {
|
|
7528
|
+
for (const entry of readdirSync7(agentsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7529
|
+
if (!entry.isDirectory() || entry.name === "admin") continue;
|
|
7530
|
+
const configPath3 = resolve7(agentsDir, entry.name, "config.json");
|
|
7531
|
+
if (!existsSync8(configPath3)) continue;
|
|
7532
|
+
try {
|
|
7533
|
+
const parsed = JSON.parse(readFileSync10(configPath3, "utf-8"));
|
|
7534
|
+
agents.push({ slug: entry.name, displayName: parsed.displayName ?? entry.name });
|
|
7535
|
+
} catch {
|
|
7536
|
+
console.error(`${TAG15} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
|
|
7537
|
+
}
|
|
7538
|
+
}
|
|
7539
|
+
} catch (err) {
|
|
7540
|
+
console.error(`${TAG15} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
|
|
7541
|
+
}
|
|
7542
|
+
}
|
|
7543
|
+
console.error(`${TAG15} config action=list-public-agents accountId=${topLevel ? "top-level" : resolved.accountId} count=${agents.length}`);
|
|
7544
|
+
return c.json({ ok: true, agents });
|
|
7545
|
+
}
|
|
7443
7546
|
if (action === "add-account-manager" || action === "remove-account-manager" || action === "list-account-managers") {
|
|
7444
7547
|
const acct = resolveAccount();
|
|
7445
7548
|
if (!acct) return c.json({ ok: false, error: "No account configured." }, 500);
|
|
@@ -7551,57 +7654,10 @@ app3.post("/config", async (c) => {
|
|
|
7551
7654
|
// Task 2233 — `add-account-manager`, `remove-account-manager` and
|
|
7552
7655
|
// `list-account-managers` are handled above this switch, on the
|
|
7553
7656
|
// per-binding gate. They remain valid actions; only their gate moved.
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
const result = setPublicAgent(account.accountDir, slug);
|
|
7559
|
-
console.error(`${TAG15} config action=set-public-agent slug=${slug} ok=${result.ok}`);
|
|
7560
|
-
return c.json(result, result.ok ? 200 : 400);
|
|
7561
|
-
}
|
|
7562
|
-
case "get-public-agent": {
|
|
7563
|
-
const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
|
|
7564
|
-
const resolved = resolvePublicAgent(account.accountDir, { accountId: targetAccount });
|
|
7565
|
-
console.error(`${TAG15} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
|
|
7566
|
-
return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
|
|
7567
|
-
}
|
|
7568
|
-
// Task 2262 — the switch that turns public answering on and off. No
|
|
7569
|
-
// matching getter: `get-config` already returns the whole WhatsApp config,
|
|
7570
|
-
// so the field is readable the moment it exists. An absent/blank accountId
|
|
7571
|
-
// writes the install-wide default; a present one writes that account only.
|
|
7572
|
-
case "set-public-agent-enabled": {
|
|
7573
|
-
if (typeof enabled !== "boolean") {
|
|
7574
|
-
return c.json({ ok: false, error: 'Missing required field "enabled" (true or false).' }, 400);
|
|
7575
|
-
}
|
|
7576
|
-
const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : void 0;
|
|
7577
|
-
const result = setPublicAgentEnabled(account.accountDir, enabled, targetAccount ? { accountId: targetAccount } : void 0);
|
|
7578
|
-
console.error(`${TAG15} config action=set-public-agent-enabled accountId=${targetAccount ?? "top-level"} enabled=${enabled} ok=${result.ok}`);
|
|
7579
|
-
return c.json(result, result.ok ? 200 : 400);
|
|
7580
|
-
}
|
|
7581
|
-
case "list-public-agents": {
|
|
7582
|
-
const agentsDir = resolve7(account.accountDir, "agents");
|
|
7583
|
-
const agents = [];
|
|
7584
|
-
if (existsSync8(agentsDir)) {
|
|
7585
|
-
try {
|
|
7586
|
-
const entries2 = readdirSync7(agentsDir, { withFileTypes: true });
|
|
7587
|
-
for (const entry of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7588
|
-
if (!entry.isDirectory() || entry.name === "admin") continue;
|
|
7589
|
-
const configPath3 = resolve7(agentsDir, entry.name, "config.json");
|
|
7590
|
-
if (!existsSync8(configPath3)) continue;
|
|
7591
|
-
try {
|
|
7592
|
-
const config = JSON.parse(readFileSync10(configPath3, "utf-8"));
|
|
7593
|
-
agents.push({ slug: entry.name, displayName: config.displayName ?? entry.name });
|
|
7594
|
-
} catch {
|
|
7595
|
-
console.error(`${TAG15} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
|
|
7596
|
-
}
|
|
7597
|
-
}
|
|
7598
|
-
} catch (err) {
|
|
7599
|
-
console.error(`${TAG15} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
|
|
7600
|
-
}
|
|
7601
|
-
}
|
|
7602
|
-
console.error(`${TAG15} config action=list-public-agents count=${agents.length}`);
|
|
7603
|
-
return c.json({ ok: true, agents });
|
|
7604
|
-
}
|
|
7657
|
+
// Task 2271 — `set-public-agent`, `get-public-agent`,
|
|
7658
|
+
// `set-public-agent-enabled` and `list-public-agents` are handled above
|
|
7659
|
+
// this switch, on the per-account scope gate. They remain valid actions;
|
|
7660
|
+
// only their gate and their target moved.
|
|
7605
7661
|
case "schema": {
|
|
7606
7662
|
const text = serializeWhatsAppSchema();
|
|
7607
7663
|
console.error(`${TAG15} config action=schema`);
|
|
@@ -12342,8 +12398,8 @@ async function reapplyLeversViaManager() {
|
|
|
12342
12398
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
12343
12399
|
var sendSeq = 0;
|
|
12344
12400
|
function createWebchatRoutes(deps) {
|
|
12345
|
-
const
|
|
12346
|
-
|
|
12401
|
+
const app77 = new Hono();
|
|
12402
|
+
app77.post("/send", requireAdminSession, async (c) => {
|
|
12347
12403
|
let accountId;
|
|
12348
12404
|
try {
|
|
12349
12405
|
accountId = resolvePlatformAccountId();
|
|
@@ -12541,7 +12597,7 @@ ${note}` : note;
|
|
|
12541
12597
|
if (turnTimer.unref) turnTimer.unref();
|
|
12542
12598
|
return c.json({ ok: true });
|
|
12543
12599
|
});
|
|
12544
|
-
|
|
12600
|
+
app77.post("/interrupt", requireAdminSession, async (c) => {
|
|
12545
12601
|
const cacheKey = c.get("cacheKey");
|
|
12546
12602
|
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
12547
12603
|
const primaryUserId = resolvePrimaryAdminUserId();
|
|
@@ -12569,7 +12625,7 @@ ${note}` : note;
|
|
|
12569
12625
|
}
|
|
12570
12626
|
return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
|
|
12571
12627
|
});
|
|
12572
|
-
|
|
12628
|
+
app77.post("/settings", requireAdminSession, async (c) => {
|
|
12573
12629
|
const body = await c.req.json().catch(() => null);
|
|
12574
12630
|
const op = body?.op;
|
|
12575
12631
|
const value = body?.value;
|
|
@@ -12605,7 +12661,7 @@ ${note}` : note;
|
|
|
12605
12661
|
console.log(`[webchat:settings] op=${op} outcome=accepted accountId=${account.accountId.slice(0, 8)} value=${value} settingsApplied=${settingsApplied}`);
|
|
12606
12662
|
return c.json({ ok: true, settingsApplied });
|
|
12607
12663
|
});
|
|
12608
|
-
|
|
12664
|
+
app77.get("/session", requireAdminSession, async (c) => {
|
|
12609
12665
|
let accountId;
|
|
12610
12666
|
try {
|
|
12611
12667
|
accountId = resolvePlatformAccountId();
|
|
@@ -12678,7 +12734,7 @@ ${note}` : note;
|
|
|
12678
12734
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
12679
12735
|
return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
12680
12736
|
});
|
|
12681
|
-
|
|
12737
|
+
app77.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
12682
12738
|
const body = await c.req.json().catch(() => null);
|
|
12683
12739
|
const sessionId = body?.sessionId;
|
|
12684
12740
|
const requestId = body?.request_id;
|
|
@@ -12695,7 +12751,7 @@ ${note}` : note;
|
|
|
12695
12751
|
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
12696
12752
|
return c.json({ ok });
|
|
12697
12753
|
});
|
|
12698
|
-
return
|
|
12754
|
+
return app77;
|
|
12699
12755
|
}
|
|
12700
12756
|
|
|
12701
12757
|
// server/routes/webchat-greeting.ts
|
|
@@ -16826,18 +16882,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
16826
16882
|
]);
|
|
16827
16883
|
var app24 = new Hono();
|
|
16828
16884
|
app24.post("/", async (c) => {
|
|
16829
|
-
const
|
|
16885
|
+
const TAG52 = "[admin:events]";
|
|
16830
16886
|
let body;
|
|
16831
16887
|
try {
|
|
16832
16888
|
body = await c.req.json();
|
|
16833
16889
|
} catch (err) {
|
|
16834
16890
|
const detail = err instanceof Error ? err.message : String(err);
|
|
16835
|
-
console.error(`${
|
|
16891
|
+
console.error(`${TAG52} reject reason=body-not-json detail=${detail}`);
|
|
16836
16892
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
16837
16893
|
}
|
|
16838
16894
|
const event = typeof body.event === "string" ? body.event : "";
|
|
16839
16895
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
16840
|
-
console.error(`${
|
|
16896
|
+
console.error(`${TAG52} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
16841
16897
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
16842
16898
|
}
|
|
16843
16899
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -22283,7 +22339,8 @@ async function managerSpawn(opts) {
|
|
|
22283
22339
|
previousContext: opts.previousContext,
|
|
22284
22340
|
initialMessage: opts.initialMessage,
|
|
22285
22341
|
passive: opts.passive,
|
|
22286
|
-
targetAccountId: opts.targetAccountId
|
|
22342
|
+
targetAccountId: opts.targetAccountId,
|
|
22343
|
+
agentAccountId: opts.agentAccountId
|
|
22287
22344
|
})
|
|
22288
22345
|
}).catch((err) => ({ __throw: err instanceof Error ? err.message : String(err) }));
|
|
22289
22346
|
if ("__throw" in res) {
|
|
@@ -24788,6 +24845,32 @@ async function computeTaskList(accountId) {
|
|
|
24788
24845
|
`${TAG29} 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"`
|
|
24789
24846
|
);
|
|
24790
24847
|
}
|
|
24848
|
+
let orphanEntries = 0;
|
|
24849
|
+
let orphanAdjustments = 0;
|
|
24850
|
+
try {
|
|
24851
|
+
const orphanTime = await session.run(
|
|
24852
|
+
`OPTIONAL MATCH (te:TimeEntry {accountId: $accountId})
|
|
24853
|
+
WHERE NOT EXISTS { MATCH (:Task {taskId: te.taskId, accountId: $accountId}) }
|
|
24854
|
+
WITH count(te) AS orphanEntries
|
|
24855
|
+
OPTIONAL MATCH (ta:TimeAdjustment {accountId: $accountId})
|
|
24856
|
+
WHERE NOT EXISTS { MATCH (:Task {taskId: ta.taskId, accountId: $accountId}) }
|
|
24857
|
+
RETURN orphanEntries, count(ta) AS orphanAdjustments`,
|
|
24858
|
+
{ accountId }
|
|
24859
|
+
);
|
|
24860
|
+
orphanEntries = orphanTime.records.length > 0 ? toNum(orphanTime.records[0].get("orphanEntries")) : 0;
|
|
24861
|
+
orphanAdjustments = orphanTime.records.length > 0 ? toNum(orphanTime.records[0].get("orphanAdjustments")) : 0;
|
|
24862
|
+
} catch (err) {
|
|
24863
|
+
console.error(
|
|
24864
|
+
`${TAG29} op=orphan-time-records-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
24865
|
+
);
|
|
24866
|
+
orphanEntries = -1;
|
|
24867
|
+
orphanAdjustments = -1;
|
|
24868
|
+
}
|
|
24869
|
+
if (orphanEntries > 0 || orphanAdjustments > 0) {
|
|
24870
|
+
console.error(
|
|
24871
|
+
`${TAG29} 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"`
|
|
24872
|
+
);
|
|
24873
|
+
}
|
|
24791
24874
|
const linkedIds = [...open3, ...completed].map((r) => r.sessionId).filter((s) => s !== null);
|
|
24792
24875
|
let dangling = null;
|
|
24793
24876
|
const cfg = claudeConfigDir();
|
|
@@ -25100,6 +25183,112 @@ app57.post("/", requireAdminSession, async (c) => {
|
|
|
25100
25183
|
});
|
|
25101
25184
|
var task_time_adjust_default = app57;
|
|
25102
25185
|
|
|
25186
|
+
// server/routes/admin/task-delete.ts
|
|
25187
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
25188
|
+
var TAG34 = "[task-delete]";
|
|
25189
|
+
var app58 = new Hono();
|
|
25190
|
+
app58.post("/", requireAdminSession, async (c) => {
|
|
25191
|
+
const cacheKey = c.var.cacheKey;
|
|
25192
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
25193
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
25194
|
+
let body;
|
|
25195
|
+
try {
|
|
25196
|
+
body = await c.req.json();
|
|
25197
|
+
} catch {
|
|
25198
|
+
console.error(`${TAG34} op=reject reason=bad-json`);
|
|
25199
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
25200
|
+
}
|
|
25201
|
+
const deletionId = randomUUID13();
|
|
25202
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
25203
|
+
if (!taskId) {
|
|
25204
|
+
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
25205
|
+
console.error(`${TAG34} op=reject reason=${reason} deletionId=${deletionId} accountId=${accountId}`);
|
|
25206
|
+
return c.json({ error: "taskId required" }, 400);
|
|
25207
|
+
}
|
|
25208
|
+
console.log(
|
|
25209
|
+
`${TAG34} op=request deletionId=${deletionId} taskId=${taskId} accountId=${accountId} confirmed=${body.confirmed === true}`
|
|
25210
|
+
);
|
|
25211
|
+
const session = getSession();
|
|
25212
|
+
try {
|
|
25213
|
+
const guard = await session.run(
|
|
25214
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
25215
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId})
|
|
25216
|
+
OPTIONAL MATCH (open:TimeEntry {taskId: $taskId, accountId: $accountId})
|
|
25217
|
+
WHERE open.endedAt IS NULL
|
|
25218
|
+
OPTIONAL MATCH (ta:TimeAdjustment {taskId: $taskId, accountId: $accountId})
|
|
25219
|
+
RETURN count(DISTINCT te) AS timeEntries,
|
|
25220
|
+
count(DISTINCT open) AS openCount,
|
|
25221
|
+
count(DISTINCT ta) AS adjustments`,
|
|
25222
|
+
{ taskId, accountId }
|
|
25223
|
+
);
|
|
25224
|
+
if (guard.records.length === 0) {
|
|
25225
|
+
console.error(`${TAG34} op=reject reason=no-task deletionId=${deletionId} taskId=${taskId} accountId=${accountId}`);
|
|
25226
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
25227
|
+
}
|
|
25228
|
+
const timeEntries = toNum(guard.records[0].get("timeEntries"));
|
|
25229
|
+
const openCount = toNum(guard.records[0].get("openCount"));
|
|
25230
|
+
const adjustments = toNum(guard.records[0].get("adjustments"));
|
|
25231
|
+
console.log(
|
|
25232
|
+
`${TAG34} op=guard deletionId=${deletionId} taskId=${taskId} openCount=${openCount} timeEntries=${timeEntries} adjustments=${adjustments}`
|
|
25233
|
+
);
|
|
25234
|
+
if (openCount > 0) {
|
|
25235
|
+
console.error(
|
|
25236
|
+
`${TAG34} op=reject reason=running deletionId=${deletionId} taskId=${taskId} openCount=${openCount}`
|
|
25237
|
+
);
|
|
25238
|
+
return c.json({ error: "task-timer-running" }, 409);
|
|
25239
|
+
}
|
|
25240
|
+
const write = await session.run(
|
|
25241
|
+
`OPTIONAL MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId})
|
|
25242
|
+
WITH collect(te) AS entries
|
|
25243
|
+
OPTIONAL MATCH (ta:TimeAdjustment {taskId: $taskId, accountId: $accountId})
|
|
25244
|
+
WITH entries, collect(ta) AS adjustments
|
|
25245
|
+
OPTIONAL MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
25246
|
+
WITH entries, adjustments, collect(t) AS tasks
|
|
25247
|
+
FOREACH (n IN entries | DETACH DELETE n)
|
|
25248
|
+
FOREACH (n IN adjustments | DETACH DELETE n)
|
|
25249
|
+
FOREACH (n IN tasks | DETACH DELETE n)
|
|
25250
|
+
RETURN size(tasks) AS tasksDeleted,
|
|
25251
|
+
size(entries) AS timeEntriesDeleted,
|
|
25252
|
+
size(adjustments) AS adjustmentsDeleted`,
|
|
25253
|
+
{ taskId, accountId }
|
|
25254
|
+
);
|
|
25255
|
+
const tasksDeleted = toNum(write.records[0]?.get("tasksDeleted"));
|
|
25256
|
+
const timeEntriesDeleted = toNum(write.records[0]?.get("timeEntriesDeleted"));
|
|
25257
|
+
const adjustmentsDeleted = toNum(write.records[0]?.get("adjustmentsDeleted"));
|
|
25258
|
+
const after = await session.run(
|
|
25259
|
+
`OPTIONAL MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
25260
|
+
WITH count(t) AS taskLeft
|
|
25261
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId})
|
|
25262
|
+
WITH taskLeft, count(te) AS entriesLeft
|
|
25263
|
+
OPTIONAL MATCH (ta:TimeAdjustment {taskId: $taskId, accountId: $accountId})
|
|
25264
|
+
RETURN taskLeft, entriesLeft, count(ta) AS adjustmentsLeft`,
|
|
25265
|
+
{ taskId, accountId }
|
|
25266
|
+
);
|
|
25267
|
+
const taskLeft = toNum(after.records[0]?.get("taskLeft"));
|
|
25268
|
+
const entriesLeft = toNum(after.records[0]?.get("entriesLeft"));
|
|
25269
|
+
const adjustmentsLeft = toNum(after.records[0]?.get("adjustmentsLeft"));
|
|
25270
|
+
const remaining = taskLeft + entriesLeft + adjustmentsLeft;
|
|
25271
|
+
console.log(
|
|
25272
|
+
`${TAG34} op=persisted deletionId=${deletionId} taskId=${taskId} tasksDeleted=${tasksDeleted} timeEntriesDeleted=${timeEntriesDeleted} adjustmentsDeleted=${adjustmentsDeleted} remaining=${remaining}`
|
|
25273
|
+
);
|
|
25274
|
+
if (remaining > 0) {
|
|
25275
|
+
console.error(
|
|
25276
|
+
`${TAG34} op=incomplete deletionId=${deletionId} taskId=${taskId} taskLeft=${taskLeft} entriesLeft=${entriesLeft} adjustmentsLeft=${adjustmentsLeft} detail="the delete returned but rows for this taskId survive"`
|
|
25277
|
+
);
|
|
25278
|
+
}
|
|
25279
|
+
invalidate("tasks-list", accountId);
|
|
25280
|
+
return c.json({ ok: true, tasksDeleted, timeEntriesDeleted, adjustmentsDeleted, remaining });
|
|
25281
|
+
} catch (err) {
|
|
25282
|
+
console.error(
|
|
25283
|
+
`${TAG34} op=error deletionId=${deletionId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
25284
|
+
);
|
|
25285
|
+
return c.json({ error: "task-delete-failed" }, 500);
|
|
25286
|
+
} finally {
|
|
25287
|
+
await session.close();
|
|
25288
|
+
}
|
|
25289
|
+
});
|
|
25290
|
+
var task_delete_default = app58;
|
|
25291
|
+
|
|
25103
25292
|
// app/lib/admin-roster.ts
|
|
25104
25293
|
import { existsSync as existsSync42, readdirSync as readdirSync26, readFileSync as readFileSync40 } from "fs";
|
|
25105
25294
|
import { resolve as resolve33 } from "path";
|
|
@@ -25185,9 +25374,9 @@ async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
|
|
|
25185
25374
|
}
|
|
25186
25375
|
|
|
25187
25376
|
// server/routes/admin/task-assign.ts
|
|
25188
|
-
var
|
|
25189
|
-
var
|
|
25190
|
-
|
|
25377
|
+
var TAG35 = "[task-assign]";
|
|
25378
|
+
var app59 = new Hono();
|
|
25379
|
+
app59.post("/", requireAdminSession, async (c) => {
|
|
25191
25380
|
const cacheKey = c.var.cacheKey;
|
|
25192
25381
|
const accountId = getAccountIdForSession(cacheKey);
|
|
25193
25382
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -25200,7 +25389,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
25200
25389
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
25201
25390
|
if (!taskId) {
|
|
25202
25391
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
25203
|
-
console.error(`${
|
|
25392
|
+
console.error(`${TAG35} op=assign rejected reason=${reason} account=${accountId}`);
|
|
25204
25393
|
return c.json({ error: "taskId required" }, 400);
|
|
25205
25394
|
}
|
|
25206
25395
|
const rawAssignee = body.assigneeUserId;
|
|
@@ -25212,7 +25401,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
25212
25401
|
const { ids } = await resolveAllowedAssigneeIds(accountId);
|
|
25213
25402
|
if (!ids.has(assigneeUserId)) {
|
|
25214
25403
|
console.error(
|
|
25215
|
-
`${
|
|
25404
|
+
`${TAG35} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
|
|
25216
25405
|
);
|
|
25217
25406
|
return c.json({ error: "assignee-not-in-roster" }, 403);
|
|
25218
25407
|
}
|
|
@@ -25234,7 +25423,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
25234
25423
|
`MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
|
|
25235
25424
|
{ taskId, accountId, now }
|
|
25236
25425
|
);
|
|
25237
|
-
console.log(`${
|
|
25426
|
+
console.log(`${TAG35} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
|
|
25238
25427
|
invalidate("tasks-list", accountId);
|
|
25239
25428
|
return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
|
|
25240
25429
|
}
|
|
@@ -25250,7 +25439,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
25250
25439
|
);
|
|
25251
25440
|
if (set.records.length === 0) {
|
|
25252
25441
|
console.error(
|
|
25253
|
-
`${
|
|
25442
|
+
`${TAG35} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
|
|
25254
25443
|
);
|
|
25255
25444
|
return c.json({ error: "assignee-no-admin-node" }, 409);
|
|
25256
25445
|
}
|
|
@@ -25258,27 +25447,27 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
25258
25447
|
const family = set.records[0].get("familyName") ?? null;
|
|
25259
25448
|
const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
|
|
25260
25449
|
console.log(
|
|
25261
|
-
`${
|
|
25450
|
+
`${TAG35} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
|
|
25262
25451
|
);
|
|
25263
25452
|
invalidate("tasks-list", accountId);
|
|
25264
25453
|
return c.json({ ok: true, assigneeUserId, assigneeName });
|
|
25265
25454
|
} catch (err) {
|
|
25266
|
-
console.error(`${
|
|
25455
|
+
console.error(`${TAG35} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
|
|
25267
25456
|
return c.json({ error: "task-assign-failed" }, 500);
|
|
25268
25457
|
} finally {
|
|
25269
25458
|
await session.close();
|
|
25270
25459
|
}
|
|
25271
25460
|
});
|
|
25272
|
-
var task_assign_default =
|
|
25461
|
+
var task_assign_default = app59;
|
|
25273
25462
|
|
|
25274
25463
|
// server/routes/admin/task-session-open.ts
|
|
25275
|
-
var
|
|
25276
|
-
var
|
|
25277
|
-
|
|
25464
|
+
var TAG36 = "[task-session]";
|
|
25465
|
+
var app60 = new Hono();
|
|
25466
|
+
app60.post("/", requireAdminSession, async (c) => {
|
|
25278
25467
|
const cacheKey = c.var.cacheKey;
|
|
25279
25468
|
const accountId = getAccountIdForSession(cacheKey);
|
|
25280
25469
|
if (!accountId) {
|
|
25281
|
-
console.error(`${
|
|
25470
|
+
console.error(`${TAG36} op=request auth-rejected reason="no account for session"`);
|
|
25282
25471
|
return c.json({ error: "Account not found for session" }, 401);
|
|
25283
25472
|
}
|
|
25284
25473
|
let body;
|
|
@@ -25290,7 +25479,7 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
25290
25479
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
25291
25480
|
if (!taskId) {
|
|
25292
25481
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
25293
|
-
console.error(`${
|
|
25482
|
+
console.error(`${TAG36} op=request rejected reason=${reason} account=${accountId}`);
|
|
25294
25483
|
return c.json({ error: "taskId required" }, 400);
|
|
25295
25484
|
}
|
|
25296
25485
|
const session = getSession();
|
|
@@ -25304,14 +25493,14 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
25304
25493
|
{ taskId, accountId }
|
|
25305
25494
|
);
|
|
25306
25495
|
if (found.records.length === 0) {
|
|
25307
|
-
console.error(`${
|
|
25496
|
+
console.error(`${TAG36} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
25308
25497
|
return c.json({ error: "task-not-found" }, 404);
|
|
25309
25498
|
}
|
|
25310
25499
|
const title = found.records[0].get("name") ?? "";
|
|
25311
25500
|
const sessionId = found.records[0].get("sessionId") ?? null;
|
|
25312
25501
|
const description = found.records[0].get("description") ?? "";
|
|
25313
25502
|
const notes = found.records[0].get("notes") ?? "";
|
|
25314
|
-
console.log(`${
|
|
25503
|
+
console.log(`${TAG36} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
|
|
25315
25504
|
if (sessionId !== null) return c.json({ sessionId, title, description, notes });
|
|
25316
25505
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25317
25506
|
const stamped = await session.run(
|
|
@@ -25321,25 +25510,25 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
25321
25510
|
{ taskId, accountId, now }
|
|
25322
25511
|
);
|
|
25323
25512
|
const at = stamped.records[0]?.get("at") ?? void 0;
|
|
25324
|
-
console.log(`${
|
|
25513
|
+
console.log(`${TAG36} op=marker taskId=${taskId} stamped=${at !== void 0}`);
|
|
25325
25514
|
return c.json({ sessionId: null, title, description, notes });
|
|
25326
25515
|
} catch (err) {
|
|
25327
|
-
console.error(`${
|
|
25516
|
+
console.error(`${TAG36} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
25328
25517
|
return c.json({ error: "task-session-open-failed" }, 500);
|
|
25329
25518
|
} finally {
|
|
25330
25519
|
await session.close();
|
|
25331
25520
|
}
|
|
25332
25521
|
});
|
|
25333
|
-
var task_session_open_default =
|
|
25522
|
+
var task_session_open_default = app60;
|
|
25334
25523
|
|
|
25335
25524
|
// server/routes/admin/task-session-link.ts
|
|
25336
|
-
var
|
|
25337
|
-
var
|
|
25338
|
-
|
|
25525
|
+
var TAG37 = "[task-session]";
|
|
25526
|
+
var app61 = new Hono();
|
|
25527
|
+
app61.post("/", requireAdminSession, async (c) => {
|
|
25339
25528
|
const cacheKey = c.var.cacheKey;
|
|
25340
25529
|
const accountId = getAccountIdForSession(cacheKey);
|
|
25341
25530
|
if (!accountId) {
|
|
25342
|
-
console.error(`${
|
|
25531
|
+
console.error(`${TAG37} op=link auth-rejected reason="no account for session"`);
|
|
25343
25532
|
return c.json({ error: "Account not found for session" }, 401);
|
|
25344
25533
|
}
|
|
25345
25534
|
let body;
|
|
@@ -25351,12 +25540,12 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
25351
25540
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
25352
25541
|
if (!taskId) {
|
|
25353
25542
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
25354
|
-
console.error(`${
|
|
25543
|
+
console.error(`${TAG37} op=link rejected reason=${reason} account=${accountId}`);
|
|
25355
25544
|
return c.json({ error: "taskId required" }, 400);
|
|
25356
25545
|
}
|
|
25357
25546
|
const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : "";
|
|
25358
25547
|
if (!sessionId) {
|
|
25359
|
-
console.error(`${
|
|
25548
|
+
console.error(`${TAG37} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
|
|
25360
25549
|
return c.json({ error: "sessionId required" }, 400);
|
|
25361
25550
|
}
|
|
25362
25551
|
const session = getSession();
|
|
@@ -25370,13 +25559,13 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
25370
25559
|
{ taskId, accountId, sessionId }
|
|
25371
25560
|
);
|
|
25372
25561
|
if (state.records.length === 0) {
|
|
25373
|
-
console.error(`${
|
|
25562
|
+
console.error(`${TAG37} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
25374
25563
|
return c.json({ error: "task-not-found" }, 404);
|
|
25375
25564
|
}
|
|
25376
25565
|
const conversationExists = state.records[0].get("conversationExists") === true;
|
|
25377
25566
|
const priorSessionIds = (state.records[0].get("priorSessionIds") ?? []).filter((s) => typeof s === "string");
|
|
25378
25567
|
if (!conversationExists) {
|
|
25379
|
-
console.error(`${
|
|
25568
|
+
console.error(`${TAG37} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
|
|
25380
25569
|
return c.json({ linked: false, created: false, repointedFrom: null });
|
|
25381
25570
|
}
|
|
25382
25571
|
const stale = priorSessionIds.filter((s) => s !== sessionId);
|
|
@@ -25402,50 +25591,50 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
25402
25591
|
const repointedFrom = stale.length > 0 ? stale[0] : null;
|
|
25403
25592
|
if (!linked) {
|
|
25404
25593
|
console.error(
|
|
25405
|
-
`${
|
|
25594
|
+
`${TAG37} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
|
|
25406
25595
|
);
|
|
25407
25596
|
return c.json({ linked: false, created: false, repointedFrom });
|
|
25408
25597
|
}
|
|
25409
25598
|
console.log(
|
|
25410
|
-
`${
|
|
25599
|
+
`${TAG37} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
|
|
25411
25600
|
);
|
|
25412
25601
|
invalidate("tasks-list", accountId);
|
|
25413
25602
|
return c.json({ linked: true, created, repointedFrom });
|
|
25414
25603
|
} catch (err) {
|
|
25415
25604
|
console.error(
|
|
25416
|
-
`${
|
|
25605
|
+
`${TAG37} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
|
|
25417
25606
|
);
|
|
25418
25607
|
return c.json({ error: "task-session-link-failed" }, 500);
|
|
25419
25608
|
} finally {
|
|
25420
25609
|
await session.close();
|
|
25421
25610
|
}
|
|
25422
25611
|
});
|
|
25423
|
-
var task_session_link_default =
|
|
25612
|
+
var task_session_link_default = app61;
|
|
25424
25613
|
|
|
25425
25614
|
// server/routes/admin/admin-users-list.ts
|
|
25426
|
-
var
|
|
25427
|
-
var
|
|
25428
|
-
|
|
25615
|
+
var TAG38 = "[admin-users]";
|
|
25616
|
+
var app62 = new Hono();
|
|
25617
|
+
app62.get("/", requireAdminSession, async (c) => {
|
|
25429
25618
|
const cacheKey = c.var.cacheKey;
|
|
25430
25619
|
const accountId = getAccountIdForSession(cacheKey);
|
|
25431
25620
|
if (!accountId) {
|
|
25432
|
-
console.error(`${
|
|
25621
|
+
console.error(`${TAG38} op=list auth-rejected reason="no account for session"`);
|
|
25433
25622
|
return c.json({ error: "Account not found for session" }, 401);
|
|
25434
25623
|
}
|
|
25435
25624
|
try {
|
|
25436
25625
|
const users = await resolveAssignableAdmins(accountId);
|
|
25437
|
-
console.log(`${
|
|
25626
|
+
console.log(`${TAG38} op=list account=${accountId} count=${users.length}`);
|
|
25438
25627
|
return c.json({ ok: true, users });
|
|
25439
25628
|
} catch (err) {
|
|
25440
|
-
console.error(`${
|
|
25629
|
+
console.error(`${TAG38} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
25441
25630
|
return c.json({ error: "admin-users-list-failed" }, 500);
|
|
25442
25631
|
}
|
|
25443
25632
|
});
|
|
25444
|
-
var admin_users_list_default =
|
|
25633
|
+
var admin_users_list_default = app62;
|
|
25445
25634
|
|
|
25446
25635
|
// server/routes/admin/dispatch-destinations.ts
|
|
25447
25636
|
import { resolve as resolve34 } from "path";
|
|
25448
|
-
var
|
|
25637
|
+
var TAG39 = "[admin:routines]";
|
|
25449
25638
|
function scopeFor(d, houseDir, houseAccountId) {
|
|
25450
25639
|
if (d.channel !== "whatsapp") return null;
|
|
25451
25640
|
if (d.label === "Account manager") return boundSubAccountFor(houseDir, d.destination);
|
|
@@ -25459,11 +25648,11 @@ function telephoneVariants(destination) {
|
|
|
25459
25648
|
function scrubDigitRuns(message) {
|
|
25460
25649
|
return message.replace(/\d{7,}/g, "<redacted>");
|
|
25461
25650
|
}
|
|
25462
|
-
var
|
|
25463
|
-
|
|
25651
|
+
var app63 = new Hono();
|
|
25652
|
+
app63.get("/", requireAdminSession, async (c) => {
|
|
25464
25653
|
const accountId = getAccountIdForSession(c.var.cacheKey);
|
|
25465
25654
|
if (!accountId) {
|
|
25466
|
-
console.error(`${
|
|
25655
|
+
console.error(`${TAG39} op=destinations auth-rejected reason="no account for session"`);
|
|
25467
25656
|
return c.json({ error: "Account not found for session" }, 401);
|
|
25468
25657
|
}
|
|
25469
25658
|
let houseAccountId = null;
|
|
@@ -25471,7 +25660,7 @@ app62.get("/", requireAdminSession, async (c) => {
|
|
|
25471
25660
|
houseAccountId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
25472
25661
|
} catch (err) {
|
|
25473
25662
|
const message = err instanceof Error ? err.message : String(err);
|
|
25474
|
-
console.error(`${
|
|
25663
|
+
console.error(`${TAG39} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
|
|
25475
25664
|
}
|
|
25476
25665
|
const destinations = listDispatchDestinations({ accountsDir: ACCOUNTS_DIR, houseAccountId, accountId });
|
|
25477
25666
|
const houseDir = houseAccountId === null ? null : resolve34(ACCOUNTS_DIR, houseAccountId);
|
|
@@ -25522,16 +25711,16 @@ app62.get("/", requireAdminSession, async (c) => {
|
|
|
25522
25711
|
const scopes = [...byScope.keys()];
|
|
25523
25712
|
const nameScope = scopes.length === 0 ? "none" : scopes.every((s) => s === houseAccountId) ? "house" : scopes.some((s) => s === houseAccountId) ? "mixed" : "account";
|
|
25524
25713
|
console.log(
|
|
25525
|
-
`${
|
|
25714
|
+
`${TAG39} 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}"`)
|
|
25526
25715
|
);
|
|
25527
25716
|
return c.json({ destinations });
|
|
25528
25717
|
});
|
|
25529
|
-
var dispatch_destinations_default =
|
|
25718
|
+
var dispatch_destinations_default = app63;
|
|
25530
25719
|
|
|
25531
25720
|
// server/routes/admin/activity.ts
|
|
25532
25721
|
import { readdirSync as readdirSync27 } from "fs";
|
|
25533
|
-
var
|
|
25534
|
-
var
|
|
25722
|
+
var app64 = new Hono();
|
|
25723
|
+
var TAG40 = "[activity]";
|
|
25535
25724
|
function resolveHouseAccountId2(accounts) {
|
|
25536
25725
|
const houses = accounts.filter((a) => a.config.role === "house");
|
|
25537
25726
|
if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
|
|
@@ -25552,7 +25741,7 @@ function countAccountDirsOnDisk() {
|
|
|
25552
25741
|
return null;
|
|
25553
25742
|
}
|
|
25554
25743
|
}
|
|
25555
|
-
|
|
25744
|
+
app64.get("/", requireAdminSession, async (c) => {
|
|
25556
25745
|
const req = requestToken();
|
|
25557
25746
|
const cacheKey = c.var.cacheKey;
|
|
25558
25747
|
const caller2 = getAccountIdForSession(cacheKey) ?? null;
|
|
@@ -25560,19 +25749,19 @@ app63.get("/", requireAdminSession, async (c) => {
|
|
|
25560
25749
|
const house = resolveHouseAccountId2(valid);
|
|
25561
25750
|
const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
|
|
25562
25751
|
console.log(
|
|
25563
|
-
`${
|
|
25752
|
+
`${TAG40} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
|
|
25564
25753
|
);
|
|
25565
25754
|
if (!isHouse) {
|
|
25566
25755
|
const reason = house.accountId === null ? house.reason : "not-house";
|
|
25567
25756
|
console.error(
|
|
25568
|
-
`${
|
|
25757
|
+
`${TAG40} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
|
|
25569
25758
|
);
|
|
25570
25759
|
return c.json({ error: "house-only" }, 403);
|
|
25571
25760
|
}
|
|
25572
|
-
console.log(`${
|
|
25761
|
+
console.log(`${TAG40} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
|
|
25573
25762
|
const onDisk = countAccountDirsOnDisk();
|
|
25574
25763
|
console.log(
|
|
25575
|
-
`${
|
|
25764
|
+
`${TAG40} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
|
|
25576
25765
|
);
|
|
25577
25766
|
const start = Date.now();
|
|
25578
25767
|
let res;
|
|
@@ -25588,17 +25777,17 @@ app63.get("/", requireAdminSession, async (c) => {
|
|
|
25588
25777
|
});
|
|
25589
25778
|
} catch (err) {
|
|
25590
25779
|
console.error(
|
|
25591
|
-
`${
|
|
25780
|
+
`${TAG40} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
|
|
25592
25781
|
);
|
|
25593
25782
|
return c.json({ error: "manager-unreachable" }, 502);
|
|
25594
25783
|
}
|
|
25595
25784
|
if (res.status !== 200) {
|
|
25596
|
-
console.error(`${
|
|
25785
|
+
console.error(`${TAG40} op=manager-fail req=${req} reason=status status=${res.status}`);
|
|
25597
25786
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
25598
25787
|
}
|
|
25599
25788
|
const body = await res.json().catch(() => null);
|
|
25600
25789
|
if (!body || !Array.isArray(body.rows)) {
|
|
25601
|
-
console.error(`${
|
|
25790
|
+
console.error(`${TAG40} op=manager-fail req=${req} reason=bad-json`);
|
|
25602
25791
|
return c.json({ error: "manager-bad-json" }, 502);
|
|
25603
25792
|
}
|
|
25604
25793
|
const rows = body.rows;
|
|
@@ -25609,10 +25798,10 @@ app63.get("/", requireAdminSession, async (c) => {
|
|
|
25609
25798
|
const ageNull = rows.filter((r) => r.ageMs === null).length;
|
|
25610
25799
|
const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
|
|
25611
25800
|
console.log(
|
|
25612
|
-
`${
|
|
25801
|
+
`${TAG40} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
|
|
25613
25802
|
);
|
|
25614
25803
|
console.log(
|
|
25615
|
-
`${
|
|
25804
|
+
`${TAG40} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
|
|
25616
25805
|
);
|
|
25617
25806
|
const names = {};
|
|
25618
25807
|
await Promise.all(
|
|
@@ -25631,7 +25820,7 @@ app63.get("/", requireAdminSession, async (c) => {
|
|
|
25631
25820
|
return acc;
|
|
25632
25821
|
}, {});
|
|
25633
25822
|
console.log(
|
|
25634
|
-
`${
|
|
25823
|
+
`${TAG40} 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(" ")
|
|
25635
25824
|
);
|
|
25636
25825
|
return c.json({
|
|
25637
25826
|
rows,
|
|
@@ -25661,69 +25850,70 @@ app63.get("/", requireAdminSession, async (c) => {
|
|
|
25661
25850
|
}
|
|
25662
25851
|
});
|
|
25663
25852
|
});
|
|
25664
|
-
var activity_default =
|
|
25853
|
+
var activity_default = app64;
|
|
25665
25854
|
|
|
25666
25855
|
// server/routes/admin/index.ts
|
|
25667
|
-
var
|
|
25668
|
-
|
|
25669
|
-
|
|
25670
|
-
|
|
25671
|
-
|
|
25672
|
-
|
|
25673
|
-
|
|
25674
|
-
|
|
25675
|
-
|
|
25676
|
-
|
|
25677
|
-
|
|
25678
|
-
|
|
25679
|
-
|
|
25680
|
-
|
|
25681
|
-
|
|
25682
|
-
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
|
|
25688
|
-
|
|
25689
|
-
|
|
25690
|
-
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
|
|
25705
|
-
|
|
25706
|
-
|
|
25707
|
-
|
|
25708
|
-
|
|
25709
|
-
|
|
25710
|
-
|
|
25711
|
-
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
|
|
25716
|
-
|
|
25717
|
-
|
|
25718
|
-
|
|
25719
|
-
|
|
25856
|
+
var app65 = new Hono();
|
|
25857
|
+
app65.route("/session", session_default);
|
|
25858
|
+
app65.route("/accounts", accounts_default);
|
|
25859
|
+
app65.route("/logs", logs_default);
|
|
25860
|
+
app65.route("/claude-info", claude_info_default);
|
|
25861
|
+
app65.route("/attachment", attachment_default);
|
|
25862
|
+
app65.route("/session-upload", session_upload_default);
|
|
25863
|
+
app65.route("/agents", agents_default);
|
|
25864
|
+
app65.route("/sessions", sessions_default);
|
|
25865
|
+
app65.route("/claude-sessions", claude_sessions_default);
|
|
25866
|
+
app65.route("/log-ingest", log_ingest_default);
|
|
25867
|
+
app65.route("/events", events_default);
|
|
25868
|
+
app65.route("/files", files_default);
|
|
25869
|
+
app65.route("/graph-search", graph_search_default);
|
|
25870
|
+
app65.route("/graph-subgraph", graph_subgraph_default);
|
|
25871
|
+
app65.route("/graph-delete", graph_delete_default);
|
|
25872
|
+
app65.route("/graph-restore", graph_restore_default);
|
|
25873
|
+
app65.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
25874
|
+
app65.route("/graph-default-view", graph_default_view_default);
|
|
25875
|
+
app65.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
25876
|
+
app65.route("/sidebar-sessions", sidebar_sessions_default);
|
|
25877
|
+
app65.route("/session-delete", session_delete_default);
|
|
25878
|
+
app65.route("/session-stop", session_stop_default);
|
|
25879
|
+
app65.route("/session-archive", session_archive_default);
|
|
25880
|
+
app65.route("/session-rename", session_rename_default);
|
|
25881
|
+
app65.route("/session-usage", session_usage_default);
|
|
25882
|
+
app65.route("/browser", browser_default);
|
|
25883
|
+
app65.route("/session-rc-spawn", session_rc_spawn_default);
|
|
25884
|
+
app65.route("/session-reseat", session_reseat_default);
|
|
25885
|
+
app65.route("/system-stats", system_stats_default);
|
|
25886
|
+
app65.route("/health-brand", health_default2);
|
|
25887
|
+
app65.route("/linkedin-ingest", linkedin_ingest_default);
|
|
25888
|
+
app65.route("/post-turn-context", post_turn_context_default);
|
|
25889
|
+
app65.route("/public-session-context", public_session_context_default);
|
|
25890
|
+
app65.route("/public-session-exit", public_session_exit_default);
|
|
25891
|
+
app65.route("/access-session-evict", access_session_evict_default);
|
|
25892
|
+
app65.route("/enrol-person", enrol_person_default);
|
|
25893
|
+
app65.route("/calendar", calendar_default);
|
|
25894
|
+
app65.route("/data-portal", data_portal_default);
|
|
25895
|
+
app65.route("/routines", routines_default);
|
|
25896
|
+
app65.route("/skills", skills_default);
|
|
25897
|
+
app65.route("/tasks-list", tasks_list_default);
|
|
25898
|
+
app65.route("/task-timer-start", task_timer_start_default);
|
|
25899
|
+
app65.route("/task-timer-stop", task_timer_stop_default);
|
|
25900
|
+
app65.route("/task-complete", task_complete_default);
|
|
25901
|
+
app65.route("/task-time-adjust", task_time_adjust_default);
|
|
25902
|
+
app65.route("/task-delete", task_delete_default);
|
|
25903
|
+
app65.route("/task-assign", task_assign_default);
|
|
25904
|
+
app65.route("/task-session-open", task_session_open_default);
|
|
25905
|
+
app65.route("/task-session-link", task_session_link_default);
|
|
25906
|
+
app65.route("/admin-users-list", admin_users_list_default);
|
|
25907
|
+
app65.route("/dispatch-destinations", dispatch_destinations_default);
|
|
25908
|
+
app65.route("/activity", activity_default);
|
|
25909
|
+
var admin_default = app65;
|
|
25720
25910
|
|
|
25721
25911
|
// server/routes/access/verify-token.ts
|
|
25722
|
-
var
|
|
25912
|
+
var TAG41 = "[access-verify]";
|
|
25723
25913
|
var MINT_TAG = "[access-session-mint]";
|
|
25724
25914
|
var COOKIE_NAME = "__access_session";
|
|
25725
|
-
var
|
|
25726
|
-
|
|
25915
|
+
var app66 = new Hono();
|
|
25916
|
+
app66.post("/", async (c) => {
|
|
25727
25917
|
const ip = c.var.clientIp || "unknown";
|
|
25728
25918
|
let body;
|
|
25729
25919
|
try {
|
|
@@ -25738,39 +25928,39 @@ app65.post("/", async (c) => {
|
|
|
25738
25928
|
}
|
|
25739
25929
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
25740
25930
|
if (rateMsg) {
|
|
25741
|
-
console.error(`${
|
|
25931
|
+
console.error(`${TAG41} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
25742
25932
|
return c.json({ error: rateMsg }, 429);
|
|
25743
25933
|
}
|
|
25744
25934
|
const grant = await findGrantByMagicToken(token);
|
|
25745
25935
|
if (!grant) {
|
|
25746
25936
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
25747
|
-
console.error(`${
|
|
25937
|
+
console.error(`${TAG41} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
25748
25938
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
25749
25939
|
}
|
|
25750
25940
|
if (grant.agentSlug !== agentSlug) {
|
|
25751
25941
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
25752
25942
|
console.error(
|
|
25753
|
-
`${
|
|
25943
|
+
`${TAG41} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
25754
25944
|
);
|
|
25755
25945
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
25756
25946
|
}
|
|
25757
25947
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
25758
25948
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
25759
25949
|
console.error(
|
|
25760
|
-
`${
|
|
25950
|
+
`${TAG41} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
25761
25951
|
);
|
|
25762
25952
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
25763
25953
|
}
|
|
25764
25954
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
25765
25955
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
25766
25956
|
console.error(
|
|
25767
|
-
`${
|
|
25957
|
+
`${TAG41} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
25768
25958
|
);
|
|
25769
25959
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
25770
25960
|
}
|
|
25771
25961
|
if (!grant.sliceToken) {
|
|
25772
25962
|
console.error(
|
|
25773
|
-
`${
|
|
25963
|
+
`${TAG41} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
25774
25964
|
);
|
|
25775
25965
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
25776
25966
|
}
|
|
@@ -25786,12 +25976,12 @@ app65.post("/", async (c) => {
|
|
|
25786
25976
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
25787
25977
|
} catch (err) {
|
|
25788
25978
|
console.error(
|
|
25789
|
-
`${
|
|
25979
|
+
`${TAG41} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
25790
25980
|
);
|
|
25791
25981
|
return c.json({ error: "verification-failed" }, 500);
|
|
25792
25982
|
}
|
|
25793
25983
|
clearAccessRateLimit(ip, agentSlug);
|
|
25794
|
-
console.log(`${
|
|
25984
|
+
console.log(`${TAG41} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
25795
25985
|
console.log(
|
|
25796
25986
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
25797
25987
|
);
|
|
@@ -25805,7 +25995,7 @@ app65.post("/", async (c) => {
|
|
|
25805
25995
|
displayName: grant.displayName
|
|
25806
25996
|
});
|
|
25807
25997
|
});
|
|
25808
|
-
var verify_token_default =
|
|
25998
|
+
var verify_token_default = app66;
|
|
25809
25999
|
|
|
25810
26000
|
// app/lib/access-email.ts
|
|
25811
26001
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -25867,10 +26057,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
25867
26057
|
}
|
|
25868
26058
|
|
|
25869
26059
|
// server/routes/access/request-magic-link.ts
|
|
25870
|
-
var
|
|
25871
|
-
var
|
|
26060
|
+
var TAG42 = "[access-request-link]";
|
|
26061
|
+
var app67 = new Hono();
|
|
25872
26062
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
25873
|
-
|
|
26063
|
+
app67.post("/", async (c) => {
|
|
25874
26064
|
let body;
|
|
25875
26065
|
try {
|
|
25876
26066
|
body = await c.req.json();
|
|
@@ -25884,18 +26074,18 @@ app66.post("/", async (c) => {
|
|
|
25884
26074
|
}
|
|
25885
26075
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
25886
26076
|
if (rateMsg) {
|
|
25887
|
-
console.error(`${
|
|
26077
|
+
console.error(`${TAG42} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
25888
26078
|
return c.json({ error: rateMsg }, 429);
|
|
25889
26079
|
}
|
|
25890
26080
|
recordRequestLinkAttempt(contactValue);
|
|
25891
26081
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
25892
26082
|
if (!accountId) {
|
|
25893
|
-
console.error(`${
|
|
26083
|
+
console.error(`${TAG42} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
25894
26084
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
25895
26085
|
}
|
|
25896
26086
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
25897
26087
|
if (!grant) {
|
|
25898
|
-
console.log(`${
|
|
26088
|
+
console.log(`${TAG42} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
25899
26089
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
25900
26090
|
}
|
|
25901
26091
|
let token;
|
|
@@ -25903,7 +26093,7 @@ app66.post("/", async (c) => {
|
|
|
25903
26093
|
token = await generateNewMagicToken(grant.grantId);
|
|
25904
26094
|
} catch (err) {
|
|
25905
26095
|
console.error(
|
|
25906
|
-
`${
|
|
26096
|
+
`${TAG42} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
25907
26097
|
);
|
|
25908
26098
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
25909
26099
|
}
|
|
@@ -25935,22 +26125,22 @@ app66.post("/", async (c) => {
|
|
|
25935
26125
|
});
|
|
25936
26126
|
if (!sendResult.ok) {
|
|
25937
26127
|
console.error(
|
|
25938
|
-
`${
|
|
26128
|
+
`${TAG42} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
25939
26129
|
);
|
|
25940
26130
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
25941
26131
|
}
|
|
25942
26132
|
console.log(
|
|
25943
|
-
`${
|
|
26133
|
+
`${TAG42} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
25944
26134
|
);
|
|
25945
26135
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
25946
26136
|
});
|
|
25947
|
-
var request_magic_link_default =
|
|
26137
|
+
var request_magic_link_default = app67;
|
|
25948
26138
|
|
|
25949
26139
|
// server/routes/access/index.ts
|
|
25950
|
-
var
|
|
25951
|
-
|
|
25952
|
-
|
|
25953
|
-
var access_default =
|
|
26140
|
+
var app68 = new Hono();
|
|
26141
|
+
app68.route("/verify-token", verify_token_default);
|
|
26142
|
+
app68.route("/request-magic-link", request_magic_link_default);
|
|
26143
|
+
var access_default = app68;
|
|
25954
26144
|
|
|
25955
26145
|
// server/routes/sites.ts
|
|
25956
26146
|
import { existsSync as existsSync43, readFileSync as readFileSync41, realpathSync as realpathSync8, statSync as statSync22 } from "fs";
|
|
@@ -25985,8 +26175,8 @@ function getExt(p) {
|
|
|
25985
26175
|
if (idx < p.lastIndexOf("/")) return "";
|
|
25986
26176
|
return p.slice(idx).toLowerCase();
|
|
25987
26177
|
}
|
|
25988
|
-
var
|
|
25989
|
-
|
|
26178
|
+
var app69 = new Hono();
|
|
26179
|
+
app69.get("/:rel{.*}", (c) => {
|
|
25990
26180
|
const reqPath = c.req.path;
|
|
25991
26181
|
const rawRel = c.req.param("rel") ?? "";
|
|
25992
26182
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -26089,7 +26279,7 @@ app68.get("/:rel{.*}", (c) => {
|
|
|
26089
26279
|
"X-Content-Type-Options": "nosniff"
|
|
26090
26280
|
});
|
|
26091
26281
|
});
|
|
26092
|
-
var sites_default =
|
|
26282
|
+
var sites_default = app69;
|
|
26093
26283
|
|
|
26094
26284
|
// app/lib/visitor-token.ts
|
|
26095
26285
|
import { createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
@@ -26189,7 +26379,7 @@ function readBrandConfig() {
|
|
|
26189
26379
|
}
|
|
26190
26380
|
|
|
26191
26381
|
// server/routes/visitor-consent.ts
|
|
26192
|
-
var
|
|
26382
|
+
var app70 = new Hono();
|
|
26193
26383
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
26194
26384
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
26195
26385
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -26234,17 +26424,17 @@ function siteSlugFromReferer(referer) {
|
|
|
26234
26424
|
return "";
|
|
26235
26425
|
}
|
|
26236
26426
|
}
|
|
26237
|
-
|
|
26427
|
+
app70.options("/consent", (c) => {
|
|
26238
26428
|
const origin = getOrigin(c);
|
|
26239
26429
|
setCorsHeaders(c, origin);
|
|
26240
26430
|
return c.body(null, 204);
|
|
26241
26431
|
});
|
|
26242
|
-
|
|
26432
|
+
app70.options("/brand-config", (c) => {
|
|
26243
26433
|
const origin = getOrigin(c);
|
|
26244
26434
|
setCorsHeaders(c, origin);
|
|
26245
26435
|
return c.body(null, 204);
|
|
26246
26436
|
});
|
|
26247
|
-
|
|
26437
|
+
app70.post("/consent", async (c) => {
|
|
26248
26438
|
const origin = getOrigin(c);
|
|
26249
26439
|
setCorsHeaders(c, origin);
|
|
26250
26440
|
let raw;
|
|
@@ -26284,7 +26474,7 @@ app69.post("/consent", async (c) => {
|
|
|
26284
26474
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
26285
26475
|
return c.body(null, 204);
|
|
26286
26476
|
});
|
|
26287
|
-
|
|
26477
|
+
app70.get("/brand-config", (c) => {
|
|
26288
26478
|
const origin = getOrigin(c);
|
|
26289
26479
|
setCorsHeaders(c, origin);
|
|
26290
26480
|
const brand = readBrandConfig();
|
|
@@ -26294,7 +26484,7 @@ app69.get("/brand-config", (c) => {
|
|
|
26294
26484
|
c.header("Cache-Control", "public, max-age=300");
|
|
26295
26485
|
return c.json({ consent: { copy, palette } });
|
|
26296
26486
|
});
|
|
26297
|
-
var visitor_consent_default =
|
|
26487
|
+
var visitor_consent_default = app70;
|
|
26298
26488
|
|
|
26299
26489
|
// server/routes/listings.ts
|
|
26300
26490
|
function getCookie(headerValue, name) {
|
|
@@ -26321,8 +26511,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
26321
26511
|
}
|
|
26322
26512
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
26323
26513
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
26324
|
-
var
|
|
26325
|
-
|
|
26514
|
+
var app71 = new Hono();
|
|
26515
|
+
app71.get("/:slug/click", async (c) => {
|
|
26326
26516
|
const slug = c.req.param("slug") ?? "";
|
|
26327
26517
|
const rawSession = c.req.query("session") ?? "";
|
|
26328
26518
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -26386,10 +26576,10 @@ app70.get("/:slug/click", async (c) => {
|
|
|
26386
26576
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
26387
26577
|
return c.redirect(redirectUrl, 302);
|
|
26388
26578
|
});
|
|
26389
|
-
var listings_default =
|
|
26579
|
+
var listings_default = app71;
|
|
26390
26580
|
|
|
26391
26581
|
// server/routes/visitor-event.ts
|
|
26392
|
-
var
|
|
26582
|
+
var app72 = new Hono();
|
|
26393
26583
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
26394
26584
|
var buckets = /* @__PURE__ */ new Map();
|
|
26395
26585
|
var RATE_LIMIT = 60;
|
|
@@ -26465,12 +26655,12 @@ function originAllowed(origin, allowlist) {
|
|
|
26465
26655
|
return false;
|
|
26466
26656
|
}
|
|
26467
26657
|
}
|
|
26468
|
-
|
|
26658
|
+
app72.options("/event", (c) => {
|
|
26469
26659
|
const origin = getOrigin2(c);
|
|
26470
26660
|
setCorsHeaders2(c, origin);
|
|
26471
26661
|
return c.body(null, 204);
|
|
26472
26662
|
});
|
|
26473
|
-
|
|
26663
|
+
app72.post("/event", async (c) => {
|
|
26474
26664
|
const origin = getOrigin2(c);
|
|
26475
26665
|
setCorsHeaders2(c, origin);
|
|
26476
26666
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -26675,7 +26865,7 @@ async function writeEvent(opts) {
|
|
|
26675
26865
|
);
|
|
26676
26866
|
}
|
|
26677
26867
|
}
|
|
26678
|
-
var visitor_event_default =
|
|
26868
|
+
var visitor_event_default = app72;
|
|
26679
26869
|
|
|
26680
26870
|
// server/routes/session.ts
|
|
26681
26871
|
import { resolve as resolve37 } from "path";
|
|
@@ -26721,8 +26911,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
26721
26911
|
headers
|
|
26722
26912
|
});
|
|
26723
26913
|
}
|
|
26724
|
-
var
|
|
26725
|
-
|
|
26914
|
+
var app73 = new Hono();
|
|
26915
|
+
app73.post("/", async (c) => {
|
|
26726
26916
|
let body;
|
|
26727
26917
|
try {
|
|
26728
26918
|
body = await c.req.json();
|
|
@@ -26869,20 +27059,20 @@ app72.post("/", async (c) => {
|
|
|
26869
27059
|
newVisitorId
|
|
26870
27060
|
);
|
|
26871
27061
|
});
|
|
26872
|
-
var session_default2 =
|
|
27062
|
+
var session_default2 = app73;
|
|
26873
27063
|
|
|
26874
27064
|
// server/routes/calendar-public.ts
|
|
26875
|
-
var
|
|
27065
|
+
var app74 = new Hono();
|
|
26876
27066
|
function setCors(c) {
|
|
26877
27067
|
c.header("Access-Control-Allow-Origin", "*");
|
|
26878
27068
|
c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
26879
27069
|
c.header("Access-Control-Allow-Headers", "content-type");
|
|
26880
27070
|
}
|
|
26881
|
-
|
|
27071
|
+
app74.options("/free-busy", (c) => {
|
|
26882
27072
|
setCors(c);
|
|
26883
27073
|
return c.body(null, 204);
|
|
26884
27074
|
});
|
|
26885
|
-
|
|
27075
|
+
app74.get("/free-busy", async (c) => {
|
|
26886
27076
|
setCors(c);
|
|
26887
27077
|
const from = c.req.query("from");
|
|
26888
27078
|
const to = c.req.query("to");
|
|
@@ -26938,15 +27128,15 @@ app73.get("/free-busy", async (c) => {
|
|
|
26938
27128
|
await session.close();
|
|
26939
27129
|
}
|
|
26940
27130
|
});
|
|
26941
|
-
var calendar_public_default =
|
|
27131
|
+
var calendar_public_default = app74;
|
|
26942
27132
|
|
|
26943
27133
|
// server/routes/portal-fetch.ts
|
|
26944
27134
|
import { createReadStream as createReadStream3 } from "fs";
|
|
26945
27135
|
import { stat as stat8, readFile as readFile11, realpath } from "fs/promises";
|
|
26946
27136
|
import { join as join49, resolve as resolve38, sep as sep11 } from "path";
|
|
26947
27137
|
import { Readable as Readable3 } from "stream";
|
|
26948
|
-
var
|
|
26949
|
-
var
|
|
27138
|
+
var app75 = new Hono();
|
|
27139
|
+
var TAG43 = "[portal-fetch]";
|
|
26950
27140
|
async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
|
|
26951
27141
|
if (!secret || !signature) return false;
|
|
26952
27142
|
if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
|
|
@@ -27001,14 +27191,14 @@ async function readAccountSecret(accountId) {
|
|
|
27001
27191
|
try {
|
|
27002
27192
|
text = await readFile11(path, "utf8");
|
|
27003
27193
|
} catch {
|
|
27004
|
-
console.error(`${
|
|
27194
|
+
console.error(`${TAG43} op=no-secret account="${accountId}" path="${path}"`);
|
|
27005
27195
|
return "";
|
|
27006
27196
|
}
|
|
27007
27197
|
for (const line of text.split("\n")) {
|
|
27008
27198
|
const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
|
|
27009
27199
|
if (m) return m[1].trim();
|
|
27010
27200
|
}
|
|
27011
|
-
console.error(`${
|
|
27201
|
+
console.error(`${TAG43} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
|
|
27012
27202
|
return "";
|
|
27013
27203
|
}
|
|
27014
27204
|
function isValidAccountId2(value) {
|
|
@@ -27068,16 +27258,16 @@ async function handle(c, headOnly) {
|
|
|
27068
27258
|
const sig = c.req.query("sig") ?? "";
|
|
27069
27259
|
const owner = c.req.query("owner") ?? "";
|
|
27070
27260
|
console.log(
|
|
27071
|
-
`${
|
|
27261
|
+
`${TAG43} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
|
|
27072
27262
|
);
|
|
27073
27263
|
if (!isValidAccountId2(accountId)) {
|
|
27074
|
-
console.error(`${
|
|
27264
|
+
console.error(`${TAG43} op=denied account=${q(accountId)} reason=account-id`);
|
|
27075
27265
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
27076
27266
|
}
|
|
27077
27267
|
const secret = await readAccountSecret(accountId);
|
|
27078
27268
|
const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
|
|
27079
27269
|
if (!verified) {
|
|
27080
|
-
console.error(`${
|
|
27270
|
+
console.error(`${TAG43} op=denied account=${q(accountId)} reason=secret`);
|
|
27081
27271
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
27082
27272
|
}
|
|
27083
27273
|
const target = await resolveFetchTarget(
|
|
@@ -27087,14 +27277,14 @@ async function handle(c, headOnly) {
|
|
|
27087
27277
|
);
|
|
27088
27278
|
if (!target.ok) {
|
|
27089
27279
|
const op = target.reason === "enoent" ? "miss" : "denied";
|
|
27090
|
-
console.error(`${
|
|
27280
|
+
console.error(`${TAG43} op=${op} account=${accountId} reason=${target.reason}`);
|
|
27091
27281
|
return c.json({ ok: false, error: "not found" }, 404);
|
|
27092
27282
|
}
|
|
27093
27283
|
if (headOnly) {
|
|
27094
|
-
console.log(`${
|
|
27284
|
+
console.log(`${TAG43} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
|
|
27095
27285
|
return c.body(null, 200);
|
|
27096
27286
|
}
|
|
27097
|
-
console.log(`${
|
|
27287
|
+
console.log(`${TAG43} op=served account=${accountId} bytes=${target.sizeBytes}`);
|
|
27098
27288
|
return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
|
|
27099
27289
|
status: 200,
|
|
27100
27290
|
headers: {
|
|
@@ -27108,12 +27298,12 @@ async function handle(c, headOnly) {
|
|
|
27108
27298
|
}
|
|
27109
27299
|
});
|
|
27110
27300
|
}
|
|
27111
|
-
|
|
27112
|
-
|
|
27113
|
-
var portal_fetch_default =
|
|
27301
|
+
app75.get("/fetch", (c) => handle(c, false));
|
|
27302
|
+
app75.on("HEAD", "/fetch", (c) => handle(c, true));
|
|
27303
|
+
var portal_fetch_default = app75;
|
|
27114
27304
|
|
|
27115
27305
|
// app/lib/timeentry-census.ts
|
|
27116
|
-
var
|
|
27306
|
+
var TAG44 = "[timeentry-census]";
|
|
27117
27307
|
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
27118
27308
|
const openEntries = rows.openEntries.length;
|
|
27119
27309
|
let oldestOpenAgeMs = 0;
|
|
@@ -27153,12 +27343,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
|
27153
27343
|
sumAdjustments: toNum(r.get("sumAdjustments"))
|
|
27154
27344
|
}));
|
|
27155
27345
|
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
27156
|
-
const line = `${
|
|
27346
|
+
const line = `${TAG44} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
27157
27347
|
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
27158
27348
|
else console.log(line);
|
|
27159
27349
|
return finding;
|
|
27160
27350
|
} catch (err) {
|
|
27161
|
-
console.error(`${
|
|
27351
|
+
console.error(`${TAG44} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
27162
27352
|
return null;
|
|
27163
27353
|
}
|
|
27164
27354
|
}
|
|
@@ -27172,13 +27362,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
27172
27362
|
try {
|
|
27173
27363
|
session = openSession();
|
|
27174
27364
|
} catch (err) {
|
|
27175
|
-
console.error(`${
|
|
27365
|
+
console.error(`${TAG44} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
27176
27366
|
return;
|
|
27177
27367
|
}
|
|
27178
27368
|
try {
|
|
27179
27369
|
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
27180
27370
|
} catch (err) {
|
|
27181
|
-
console.error(`${
|
|
27371
|
+
console.error(`${TAG44} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
27182
27372
|
} finally {
|
|
27183
27373
|
try {
|
|
27184
27374
|
await session.close();
|
|
@@ -27239,7 +27429,7 @@ function formatCensusLine(f) {
|
|
|
27239
27429
|
}
|
|
27240
27430
|
|
|
27241
27431
|
// app/lib/ledger-census.ts
|
|
27242
|
-
var
|
|
27432
|
+
var TAG45 = "[ledger-census]";
|
|
27243
27433
|
var DAY_MS = 864e5;
|
|
27244
27434
|
function countWriteRejects24h(logDir, now) {
|
|
27245
27435
|
let entries2;
|
|
@@ -27315,7 +27505,7 @@ async function runLedgerCensusOnce(session, now) {
|
|
|
27315
27505
|
else console.log(line);
|
|
27316
27506
|
return finding;
|
|
27317
27507
|
} catch (err) {
|
|
27318
|
-
console.error(`${
|
|
27508
|
+
console.error(`${TAG45} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
27319
27509
|
return null;
|
|
27320
27510
|
}
|
|
27321
27511
|
}
|
|
@@ -27328,7 +27518,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
27328
27518
|
session = openSession();
|
|
27329
27519
|
} catch (err) {
|
|
27330
27520
|
console.error(
|
|
27331
|
-
`${
|
|
27521
|
+
`${TAG45} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
27332
27522
|
);
|
|
27333
27523
|
return;
|
|
27334
27524
|
}
|
|
@@ -27336,7 +27526,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
27336
27526
|
await runLedgerCensusOnce(session, Date.now());
|
|
27337
27527
|
} catch (err) {
|
|
27338
27528
|
console.error(
|
|
27339
|
-
`${
|
|
27529
|
+
`${TAG45} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
27340
27530
|
);
|
|
27341
27531
|
} finally {
|
|
27342
27532
|
try {
|
|
@@ -27354,7 +27544,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
27354
27544
|
}
|
|
27355
27545
|
|
|
27356
27546
|
// app/lib/conversation-audit.ts
|
|
27357
|
-
var
|
|
27547
|
+
var TAG46 = "[conversation-audit]";
|
|
27358
27548
|
async function runConversationAudit() {
|
|
27359
27549
|
const session = getSession();
|
|
27360
27550
|
try {
|
|
@@ -27391,12 +27581,12 @@ async function runConversationAudit() {
|
|
|
27391
27581
|
multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
|
|
27392
27582
|
};
|
|
27393
27583
|
console.error(
|
|
27394
|
-
`${
|
|
27584
|
+
`${TAG46} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
|
|
27395
27585
|
);
|
|
27396
27586
|
return result;
|
|
27397
27587
|
} catch (err) {
|
|
27398
27588
|
const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
|
|
27399
|
-
console.error(`${
|
|
27589
|
+
console.error(`${TAG46} op=failed reason=${reason}`);
|
|
27400
27590
|
return null;
|
|
27401
27591
|
} finally {
|
|
27402
27592
|
await session.close();
|
|
@@ -28290,8 +28480,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
28290
28480
|
|
|
28291
28481
|
// app/lib/whatsapp/gateway/routes.ts
|
|
28292
28482
|
function createWaChannelRoutes(deps) {
|
|
28293
|
-
const
|
|
28294
|
-
|
|
28483
|
+
const app77 = new Hono();
|
|
28484
|
+
app77.get("/wa-channel/inbound", (c) => {
|
|
28295
28485
|
const senderId = c.req.query("senderId");
|
|
28296
28486
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
28297
28487
|
return streamSSE(c, async (stream2) => {
|
|
@@ -28309,7 +28499,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28309
28499
|
}
|
|
28310
28500
|
});
|
|
28311
28501
|
});
|
|
28312
|
-
|
|
28502
|
+
app77.post("/wa-channel/reply", async (c) => {
|
|
28313
28503
|
const body = await c.req.json().catch(() => null);
|
|
28314
28504
|
const senderId = body?.senderId;
|
|
28315
28505
|
const text = body?.text;
|
|
@@ -28331,7 +28521,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28331
28521
|
deps.onReplyDispatch?.(senderId, Date.now());
|
|
28332
28522
|
return c.json({ ok: true });
|
|
28333
28523
|
});
|
|
28334
|
-
|
|
28524
|
+
app77.post("/wa-channel/reply-document", async (c) => {
|
|
28335
28525
|
const body = await c.req.json().catch(() => null);
|
|
28336
28526
|
const senderId = body?.senderId;
|
|
28337
28527
|
const files = body?.files;
|
|
@@ -28370,7 +28560,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28370
28560
|
}
|
|
28371
28561
|
return c.json({ ok: true, results });
|
|
28372
28562
|
});
|
|
28373
|
-
|
|
28563
|
+
app77.post("/wa-channel/ready", async (c) => {
|
|
28374
28564
|
const body = await c.req.json().catch(() => null);
|
|
28375
28565
|
const senderId = body?.senderId;
|
|
28376
28566
|
if (typeof senderId !== "string") {
|
|
@@ -28379,7 +28569,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28379
28569
|
deps.onReady?.(senderId);
|
|
28380
28570
|
return c.json({ ok: true });
|
|
28381
28571
|
});
|
|
28382
|
-
|
|
28572
|
+
app77.post("/wa-channel/received", async (c) => {
|
|
28383
28573
|
const body = await c.req.json().catch(() => null);
|
|
28384
28574
|
const senderId = body?.senderId;
|
|
28385
28575
|
const waMessageId = body?.waMessageId;
|
|
@@ -28389,7 +28579,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28389
28579
|
deps.onReceived?.(senderId, waMessageId);
|
|
28390
28580
|
return c.json({ ok: true });
|
|
28391
28581
|
});
|
|
28392
|
-
|
|
28582
|
+
app77.post("/wa-channel/turn-end", async (c) => {
|
|
28393
28583
|
const body = await c.req.json().catch(() => null);
|
|
28394
28584
|
const senderId = body?.senderId;
|
|
28395
28585
|
const sessionId = body?.sessionId;
|
|
@@ -28435,7 +28625,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28435
28625
|
console.error(`[whatsapp-native] op=turn-end ${decision} delivered=none`);
|
|
28436
28626
|
return c.json({ ok: true, delivered: "none" });
|
|
28437
28627
|
});
|
|
28438
|
-
return
|
|
28628
|
+
return app77;
|
|
28439
28629
|
}
|
|
28440
28630
|
|
|
28441
28631
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -28858,7 +29048,7 @@ function formatPublicAgentRouteLine(p) {
|
|
|
28858
29048
|
// app/lib/whatsapp/inbound/public-agent-registry-audit.ts
|
|
28859
29049
|
function auditPublicAgentRegistry(deps) {
|
|
28860
29050
|
const accounts = deps.enabledAccounts();
|
|
28861
|
-
const unresolvable = accounts.filter((a) => a.slug === null || !deps.agentExists(a.slug));
|
|
29051
|
+
const unresolvable = accounts.filter((a) => a.slug === null || !deps.agentExists(a.accountId, a.slug));
|
|
28862
29052
|
return { checked: accounts.length, unresolvable };
|
|
28863
29053
|
}
|
|
28864
29054
|
function runPublicAgentRegistryAudit(deps) {
|
|
@@ -28873,6 +29063,22 @@ function runPublicAgentRegistryAudit(deps) {
|
|
|
28873
29063
|
);
|
|
28874
29064
|
}
|
|
28875
29065
|
|
|
29066
|
+
// app/lib/whatsapp/inbound/public-agent-slice-audit.ts
|
|
29067
|
+
function auditPublicAgentSlices(deps) {
|
|
29068
|
+
const accounts = deps.enabledAccounts();
|
|
29069
|
+
const unconfigured = accounts.filter((a) => !a.house && a.ownSlug === null).map((a) => ({ accountId: a.accountId }));
|
|
29070
|
+
return { checked: accounts.length, unconfigured };
|
|
29071
|
+
}
|
|
29072
|
+
function runPublicAgentSliceAudit(deps) {
|
|
29073
|
+
const result = auditPublicAgentSlices(deps);
|
|
29074
|
+
for (const row of result.unconfigured) {
|
|
29075
|
+
console.error(`[whatsapp:public-agent] op=slice-unconfigured account=${row.accountId}`);
|
|
29076
|
+
}
|
|
29077
|
+
console.error(
|
|
29078
|
+
`[whatsapp:public-agent] op=slice-audit checked=${result.checked} unconfigured=${result.unconfigured.length}`
|
|
29079
|
+
);
|
|
29080
|
+
}
|
|
29081
|
+
|
|
28876
29082
|
// app/lib/webchat/gateway/inbound-hub.ts
|
|
28877
29083
|
var InboundHub2 = class {
|
|
28878
29084
|
keys = /* @__PURE__ */ new Map();
|
|
@@ -29047,8 +29253,8 @@ var InboundHub2 = class {
|
|
|
29047
29253
|
|
|
29048
29254
|
// app/lib/webchat/gateway/routes.ts
|
|
29049
29255
|
function createWebchatChannelRoutes(deps) {
|
|
29050
|
-
const
|
|
29051
|
-
|
|
29256
|
+
const app77 = new Hono();
|
|
29257
|
+
app77.get("/webchat-channel/inbound", (c) => {
|
|
29052
29258
|
const key = c.req.query("key");
|
|
29053
29259
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
29054
29260
|
const role = c.req.query("role");
|
|
@@ -29073,7 +29279,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29073
29279
|
}
|
|
29074
29280
|
});
|
|
29075
29281
|
});
|
|
29076
|
-
|
|
29282
|
+
app77.post("/webchat-channel/reply", async (c) => {
|
|
29077
29283
|
const body = await c.req.json().catch(() => null);
|
|
29078
29284
|
const key = body?.key;
|
|
29079
29285
|
const text = body?.text;
|
|
@@ -29083,7 +29289,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29083
29289
|
deps.onReply?.(key, text);
|
|
29084
29290
|
return c.json({ ok: true });
|
|
29085
29291
|
});
|
|
29086
|
-
|
|
29292
|
+
app77.post("/webchat-channel/connector-auth", async (c) => {
|
|
29087
29293
|
const body = await c.req.json().catch(() => null);
|
|
29088
29294
|
const key = body?.key;
|
|
29089
29295
|
const sessionId = body?.sessionId;
|
|
@@ -29096,7 +29302,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29096
29302
|
const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
|
|
29097
29303
|
return c.json(result);
|
|
29098
29304
|
});
|
|
29099
|
-
|
|
29305
|
+
app77.post("/webchat-channel/ready", async (c) => {
|
|
29100
29306
|
const body = await c.req.json().catch(() => null);
|
|
29101
29307
|
const key = body?.key;
|
|
29102
29308
|
if (typeof key !== "string") {
|
|
@@ -29105,7 +29311,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29105
29311
|
deps.onReady?.(key);
|
|
29106
29312
|
return c.json({ ok: true });
|
|
29107
29313
|
});
|
|
29108
|
-
|
|
29314
|
+
app77.post("/webchat-channel/permission-request", async (c) => {
|
|
29109
29315
|
const body = await c.req.json().catch(() => null);
|
|
29110
29316
|
const key = body?.key;
|
|
29111
29317
|
const requestId = body?.request_id;
|
|
@@ -29119,7 +29325,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29119
29325
|
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
29120
29326
|
return c.json(verdict);
|
|
29121
29327
|
});
|
|
29122
|
-
|
|
29328
|
+
app77.post("/webchat-channel/received", async (c) => {
|
|
29123
29329
|
const body = await c.req.json().catch(() => null);
|
|
29124
29330
|
const key = body?.key;
|
|
29125
29331
|
const messageId = body?.messageId;
|
|
@@ -29129,7 +29335,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29129
29335
|
deps.onReceived?.(key, messageId);
|
|
29130
29336
|
return c.json({ ok: true });
|
|
29131
29337
|
});
|
|
29132
|
-
|
|
29338
|
+
app77.post("/webchat-channel/turn-end", async (c) => {
|
|
29133
29339
|
const body = await c.req.json().catch(() => null);
|
|
29134
29340
|
const key = body?.key;
|
|
29135
29341
|
const sessionId = body?.sessionId;
|
|
@@ -29149,7 +29355,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29149
29355
|
deps.onTurnEnd?.(key, role);
|
|
29150
29356
|
return c.json({ ok: true });
|
|
29151
29357
|
});
|
|
29152
|
-
return
|
|
29358
|
+
return app77;
|
|
29153
29359
|
}
|
|
29154
29360
|
|
|
29155
29361
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -29908,14 +30114,14 @@ function makeFileDelivery(opts) {
|
|
|
29908
30114
|
}
|
|
29909
30115
|
|
|
29910
30116
|
// app/lib/webchat/file-delivery.ts
|
|
29911
|
-
var
|
|
30117
|
+
var TAG47 = "[webchat-adaptor]";
|
|
29912
30118
|
function platformRoot2() {
|
|
29913
30119
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
29914
30120
|
}
|
|
29915
30121
|
function makeWebchatSendFile(entry) {
|
|
29916
30122
|
return async (filePath) => {
|
|
29917
30123
|
if (!entry.accountId) {
|
|
29918
|
-
console.error(`${
|
|
30124
|
+
console.error(`${TAG47} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
29919
30125
|
return { ok: false, error: "no-account" };
|
|
29920
30126
|
}
|
|
29921
30127
|
const accountDir = resolve41(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
@@ -29923,14 +30129,14 @@ function makeWebchatSendFile(entry) {
|
|
|
29923
30129
|
const resolved = realpathSync9(filePath);
|
|
29924
30130
|
const accountResolved = realpathSync9(accountDir);
|
|
29925
30131
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
29926
|
-
console.error(`${
|
|
30132
|
+
console.error(`${TAG47} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
29927
30133
|
return { ok: false, error: "outside-account" };
|
|
29928
30134
|
}
|
|
29929
30135
|
return { ok: true };
|
|
29930
30136
|
} catch (err) {
|
|
29931
30137
|
const code = err.code;
|
|
29932
30138
|
console.error(
|
|
29933
|
-
`${
|
|
30139
|
+
`${TAG47} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
29934
30140
|
);
|
|
29935
30141
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
29936
30142
|
}
|
|
@@ -29939,7 +30145,7 @@ function makeWebchatSendFile(entry) {
|
|
|
29939
30145
|
function makeWebchatFileDelivery(entry) {
|
|
29940
30146
|
return makeFileDelivery({
|
|
29941
30147
|
entry,
|
|
29942
|
-
tag:
|
|
30148
|
+
tag: TAG47,
|
|
29943
30149
|
channel: "webchat",
|
|
29944
30150
|
sendFile: makeWebchatSendFile(entry),
|
|
29945
30151
|
deferUntilVerdict: true
|
|
@@ -30001,7 +30207,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
30001
30207
|
}
|
|
30002
30208
|
|
|
30003
30209
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
30004
|
-
var
|
|
30210
|
+
var TAG48 = "[whatsapp-adaptor]";
|
|
30005
30211
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
30006
30212
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
30007
30213
|
function platformRoot3() {
|
|
@@ -30019,7 +30225,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
30019
30225
|
});
|
|
30020
30226
|
if (result.ok) return { ok: true };
|
|
30021
30227
|
console.error(
|
|
30022
|
-
`${
|
|
30228
|
+
`${TAG48} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
30023
30229
|
);
|
|
30024
30230
|
return { ok: false, error: result.error };
|
|
30025
30231
|
};
|
|
@@ -30027,7 +30233,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
30027
30233
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
30028
30234
|
const shared = makeFileDelivery({
|
|
30029
30235
|
entry,
|
|
30030
|
-
tag:
|
|
30236
|
+
tag: TAG48,
|
|
30031
30237
|
channel: "whatsapp",
|
|
30032
30238
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
30033
30239
|
});
|
|
@@ -30062,7 +30268,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
30062
30268
|
if (!delivered) {
|
|
30063
30269
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
30064
30270
|
console.error(
|
|
30065
|
-
`${
|
|
30271
|
+
`${TAG48} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
30066
30272
|
);
|
|
30067
30273
|
}
|
|
30068
30274
|
}
|
|
@@ -30245,8 +30451,8 @@ var InboundHub3 = class {
|
|
|
30245
30451
|
|
|
30246
30452
|
// app/lib/telegram/gateway/routes.ts
|
|
30247
30453
|
function createTelegramChannelRoutes(deps) {
|
|
30248
|
-
const
|
|
30249
|
-
|
|
30454
|
+
const app77 = new Hono();
|
|
30455
|
+
app77.get("/tg-channel/inbound", (c) => {
|
|
30250
30456
|
const key = c.req.query("key");
|
|
30251
30457
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
30252
30458
|
return streamSSE(c, async (stream2) => {
|
|
@@ -30264,7 +30470,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
30264
30470
|
}
|
|
30265
30471
|
});
|
|
30266
30472
|
});
|
|
30267
|
-
|
|
30473
|
+
app77.post("/tg-channel/reply", async (c) => {
|
|
30268
30474
|
const body = await c.req.json().catch(() => null);
|
|
30269
30475
|
const key = body?.key;
|
|
30270
30476
|
const text = body?.text;
|
|
@@ -30280,7 +30486,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
30280
30486
|
console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
30281
30487
|
return c.json({ ok: true });
|
|
30282
30488
|
});
|
|
30283
|
-
|
|
30489
|
+
app77.post("/tg-channel/ready", async (c) => {
|
|
30284
30490
|
const body = await c.req.json().catch(() => null);
|
|
30285
30491
|
const key = body?.key;
|
|
30286
30492
|
if (typeof key !== "string") {
|
|
@@ -30289,7 +30495,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
30289
30495
|
deps.onReady?.(key);
|
|
30290
30496
|
return c.json({ ok: true });
|
|
30291
30497
|
});
|
|
30292
|
-
|
|
30498
|
+
app77.post("/tg-channel/received", async (c) => {
|
|
30293
30499
|
const body = await c.req.json().catch(() => null);
|
|
30294
30500
|
const key = body?.key;
|
|
30295
30501
|
const messageId = body?.messageId;
|
|
@@ -30299,7 +30505,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
30299
30505
|
deps.onReceived?.(key, messageId);
|
|
30300
30506
|
return c.json({ ok: true });
|
|
30301
30507
|
});
|
|
30302
|
-
|
|
30508
|
+
app77.post("/tg-channel/turn-end", async (c) => {
|
|
30303
30509
|
const body = await c.req.json().catch(() => null);
|
|
30304
30510
|
const key = body?.key;
|
|
30305
30511
|
const sessionId = body?.sessionId;
|
|
@@ -30332,7 +30538,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
30332
30538
|
console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
|
|
30333
30539
|
return c.json({ ok: true, delivered: "none" });
|
|
30334
30540
|
});
|
|
30335
|
-
return
|
|
30541
|
+
return app77;
|
|
30336
30542
|
}
|
|
30337
30543
|
|
|
30338
30544
|
// app/lib/telegram/gateway/telegram-gateway.ts
|
|
@@ -30483,7 +30689,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
30483
30689
|
import { realpathSync as realpathSync10 } from "fs";
|
|
30484
30690
|
import { readFile as readFile14, stat as stat10 } from "fs/promises";
|
|
30485
30691
|
import { resolve as resolve42, basename as basename16 } from "path";
|
|
30486
|
-
var
|
|
30692
|
+
var TAG49 = "[telegram:outbound]";
|
|
30487
30693
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
30488
30694
|
async function sendTelegramDocument(input) {
|
|
30489
30695
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
@@ -30500,10 +30706,10 @@ async function sendTelegramDocument(input) {
|
|
|
30500
30706
|
} catch (err) {
|
|
30501
30707
|
const code = err.code;
|
|
30502
30708
|
if (code === "ENOENT") {
|
|
30503
|
-
console.error(`${
|
|
30709
|
+
console.error(`${TAG49} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
|
|
30504
30710
|
return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
|
|
30505
30711
|
}
|
|
30506
|
-
console.error(`${
|
|
30712
|
+
console.error(`${TAG49} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
30507
30713
|
return { ok: false, status: 500, error: String(err) };
|
|
30508
30714
|
}
|
|
30509
30715
|
let resolvedPath;
|
|
@@ -30512,14 +30718,14 @@ async function sendTelegramDocument(input) {
|
|
|
30512
30718
|
} catch (err) {
|
|
30513
30719
|
const code = err.code;
|
|
30514
30720
|
if (code === "ENOENT") {
|
|
30515
|
-
console.error(`${
|
|
30721
|
+
console.error(`${TAG49} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
|
|
30516
30722
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
30517
30723
|
}
|
|
30518
|
-
console.error(`${
|
|
30724
|
+
console.error(`${TAG49} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
30519
30725
|
return { ok: false, status: 500, error: String(err) };
|
|
30520
30726
|
}
|
|
30521
30727
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
30522
|
-
console.error(`${
|
|
30728
|
+
console.error(`${TAG49} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
30523
30729
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
30524
30730
|
}
|
|
30525
30731
|
const fileStat = await stat10(resolvedPath);
|
|
@@ -30552,13 +30758,13 @@ async function sendTelegramDocument(input) {
|
|
|
30552
30758
|
error = e instanceof Error ? e.message : String(e);
|
|
30553
30759
|
}
|
|
30554
30760
|
console.error(
|
|
30555
|
-
`${
|
|
30761
|
+
`${TAG49} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
30556
30762
|
);
|
|
30557
30763
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
30558
30764
|
}
|
|
30559
30765
|
|
|
30560
30766
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
30561
|
-
var
|
|
30767
|
+
var TAG50 = "[telegram:outbound]";
|
|
30562
30768
|
function platformRoot4() {
|
|
30563
30769
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
30564
30770
|
}
|
|
@@ -30570,11 +30776,11 @@ function makeTelegramSendFile(entry) {
|
|
|
30570
30776
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
30571
30777
|
}
|
|
30572
30778
|
if (!botToken) {
|
|
30573
|
-
console.error(`${
|
|
30779
|
+
console.error(`${TAG50} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
30574
30780
|
return { ok: false, error: "no-bot-token" };
|
|
30575
30781
|
}
|
|
30576
30782
|
if (entry.replyTarget == null) {
|
|
30577
|
-
console.error(`${
|
|
30783
|
+
console.error(`${TAG50} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
30578
30784
|
return { ok: false, error: "no-reply-target" };
|
|
30579
30785
|
}
|
|
30580
30786
|
const result = await sendTelegramDocument({
|
|
@@ -30591,7 +30797,7 @@ function makeTelegramSendFile(entry) {
|
|
|
30591
30797
|
function makeTelegramFileDelivery(entry) {
|
|
30592
30798
|
return makeFileDelivery({
|
|
30593
30799
|
entry,
|
|
30594
|
-
tag:
|
|
30800
|
+
tag: TAG50,
|
|
30595
30801
|
channel: "telegram",
|
|
30596
30802
|
sendFile: makeTelegramSendFile(entry)
|
|
30597
30803
|
});
|
|
@@ -30631,8 +30837,8 @@ function startTelegramNativeFileFollower(input) {
|
|
|
30631
30837
|
}
|
|
30632
30838
|
|
|
30633
30839
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
30634
|
-
import { randomUUID as
|
|
30635
|
-
var
|
|
30840
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
30841
|
+
var TAG51 = "[public-session-review]";
|
|
30636
30842
|
var CONSUMED_CAP = 500;
|
|
30637
30843
|
var consumed = /* @__PURE__ */ new Set();
|
|
30638
30844
|
function consumeOnce(sessionId) {
|
|
@@ -30659,7 +30865,7 @@ async function fetchJsonl(sessionId) {
|
|
|
30659
30865
|
return await res.text();
|
|
30660
30866
|
} catch (err) {
|
|
30661
30867
|
console.error(
|
|
30662
|
-
`${
|
|
30868
|
+
`${TAG51} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
30663
30869
|
);
|
|
30664
30870
|
return null;
|
|
30665
30871
|
}
|
|
@@ -30683,7 +30889,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
30683
30889
|
const res = await fetch(url);
|
|
30684
30890
|
if (!res.ok) {
|
|
30685
30891
|
console.error(
|
|
30686
|
-
`${
|
|
30892
|
+
`${TAG51} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
30687
30893
|
);
|
|
30688
30894
|
return [];
|
|
30689
30895
|
}
|
|
@@ -30691,7 +30897,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
30691
30897
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
30692
30898
|
} catch (err) {
|
|
30693
30899
|
console.error(
|
|
30694
|
-
`${
|
|
30900
|
+
`${TAG51} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
30695
30901
|
);
|
|
30696
30902
|
return [];
|
|
30697
30903
|
}
|
|
@@ -30719,8 +30925,8 @@ function composeInitialMessage(input) {
|
|
|
30719
30925
|
].join("\n");
|
|
30720
30926
|
}
|
|
30721
30927
|
async function dispatchReviewer(input, initialMessage) {
|
|
30722
|
-
const sessionId =
|
|
30723
|
-
console.log(`${
|
|
30928
|
+
const sessionId = randomUUID14();
|
|
30929
|
+
console.log(`${TAG51} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
30724
30930
|
const spawned = await managerRcSpawn({
|
|
30725
30931
|
sessionId,
|
|
30726
30932
|
initialMessage,
|
|
@@ -30740,21 +30946,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
30740
30946
|
const dispatchedAt = Date.now();
|
|
30741
30947
|
if (consumed.has(input.sessionId)) {
|
|
30742
30948
|
console.log(
|
|
30743
|
-
`${
|
|
30949
|
+
`${TAG51} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
30744
30950
|
);
|
|
30745
30951
|
return;
|
|
30746
30952
|
}
|
|
30747
30953
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
30748
30954
|
if (!jsonl) {
|
|
30749
30955
|
console.log(
|
|
30750
|
-
`${
|
|
30956
|
+
`${TAG51} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
30751
30957
|
);
|
|
30752
30958
|
return;
|
|
30753
30959
|
}
|
|
30754
30960
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
30755
30961
|
if (operatorTurns === 0) {
|
|
30756
30962
|
console.log(
|
|
30757
|
-
`${
|
|
30963
|
+
`${TAG51} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
30758
30964
|
);
|
|
30759
30965
|
return;
|
|
30760
30966
|
}
|
|
@@ -30768,19 +30974,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
30768
30974
|
});
|
|
30769
30975
|
if (!consumeOnce(input.sessionId)) {
|
|
30770
30976
|
console.log(
|
|
30771
|
-
`${
|
|
30977
|
+
`${TAG51} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
30772
30978
|
);
|
|
30773
30979
|
return;
|
|
30774
30980
|
}
|
|
30775
30981
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
30776
30982
|
if (!dispatched.ok) {
|
|
30777
30983
|
console.error(
|
|
30778
|
-
`${
|
|
30984
|
+
`${TAG51} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
30779
30985
|
);
|
|
30780
30986
|
return;
|
|
30781
30987
|
}
|
|
30782
30988
|
console.log(
|
|
30783
|
-
`${
|
|
30989
|
+
`${TAG51} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
30784
30990
|
);
|
|
30785
30991
|
}
|
|
30786
30992
|
|
|
@@ -31237,7 +31443,7 @@ startManagerEventsSubscriber();
|
|
|
31237
31443
|
function isPublicHost(host) {
|
|
31238
31444
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
31239
31445
|
}
|
|
31240
|
-
var
|
|
31446
|
+
var app76 = new Hono();
|
|
31241
31447
|
function resolveChannelOverride(accountId, channel, senderId) {
|
|
31242
31448
|
try {
|
|
31243
31449
|
const dir = listValidAccounts().find((a) => a.accountId === accountId)?.accountDir;
|
|
@@ -31373,6 +31579,11 @@ var waGateway = new WaGateway({
|
|
|
31373
31579
|
channel: "whatsapp",
|
|
31374
31580
|
accountId: effectiveAccountId,
|
|
31375
31581
|
targetAccountId: effectiveAccountId,
|
|
31582
|
+
// Task 2271 — this slug came from THIS account's own slice
|
|
31583
|
+
// (`resolvePublicAgent` with `isHouse` false), so the spawn must read
|
|
31584
|
+
// that account's own agents directory, run in its directory and file its
|
|
31585
|
+
// session under it.
|
|
31586
|
+
agentAccountId: effectiveAccountId,
|
|
31376
31587
|
agentSlug: publicAgentSlug,
|
|
31377
31588
|
sessionId: publicSessionId,
|
|
31378
31589
|
personId: personId ?? void 0,
|
|
@@ -31441,7 +31652,7 @@ var waGateway = new WaGateway({
|
|
|
31441
31652
|
nativeFileFollowers.set(senderId, ac);
|
|
31442
31653
|
}
|
|
31443
31654
|
});
|
|
31444
|
-
|
|
31655
|
+
app76.route("/", waGateway.routes());
|
|
31445
31656
|
waGateway.startSweeper();
|
|
31446
31657
|
registerLoop({
|
|
31447
31658
|
name: "whatsapp-link-census",
|
|
@@ -31578,7 +31789,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
31578
31789
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
31579
31790
|
});
|
|
31580
31791
|
setWebchatGateway(webchatGateway);
|
|
31581
|
-
|
|
31792
|
+
app76.route("/", webchatGateway.routes());
|
|
31582
31793
|
webchatGateway.startSweeper();
|
|
31583
31794
|
webchatGateway.startPublicReaper();
|
|
31584
31795
|
var telegramFileFollowers = /* @__PURE__ */ new Map();
|
|
@@ -31622,7 +31833,7 @@ var telegramGateway = new TelegramGateway({
|
|
|
31622
31833
|
}
|
|
31623
31834
|
});
|
|
31624
31835
|
setTelegramGateway(telegramGateway);
|
|
31625
|
-
|
|
31836
|
+
app76.route("/", telegramGateway.routes());
|
|
31626
31837
|
telegramGateway.startSweeper();
|
|
31627
31838
|
var chatRoutes = createChatRoutes({
|
|
31628
31839
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
@@ -31661,19 +31872,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
31661
31872
|
// and why the real dependencies are bound there rather than assembled here.
|
|
31662
31873
|
effectiveAccountFor: resolveScheduledEffectiveAccountForInstall
|
|
31663
31874
|
});
|
|
31664
|
-
|
|
31665
|
-
|
|
31875
|
+
app76.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
31876
|
+
app76.use("*", clientIpMiddleware);
|
|
31666
31877
|
function allowsSameOriginFraming(path) {
|
|
31667
31878
|
return path === "/vnc-viewer.html" || path.startsWith("/api/admin/attachment/") || path.startsWith("/api/public-reader/attachment/") || path === "/api/admin/files/download" || path === "/api/admin/session-upload";
|
|
31668
31879
|
}
|
|
31669
|
-
|
|
31880
|
+
app76.use("*", async (c, next) => {
|
|
31670
31881
|
await next();
|
|
31671
31882
|
c.header("X-Content-Type-Options", "nosniff");
|
|
31672
31883
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
31673
31884
|
c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
|
|
31674
31885
|
});
|
|
31675
31886
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
31676
|
-
|
|
31887
|
+
app76.use("*", async (c, next) => {
|
|
31677
31888
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
31678
31889
|
await next();
|
|
31679
31890
|
return;
|
|
@@ -31691,7 +31902,7 @@ app75.use("*", async (c, next) => {
|
|
|
31691
31902
|
});
|
|
31692
31903
|
}
|
|
31693
31904
|
});
|
|
31694
|
-
|
|
31905
|
+
app76.use("*", async (c, next) => {
|
|
31695
31906
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31696
31907
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
31697
31908
|
await next();
|
|
@@ -31729,7 +31940,7 @@ function resolveRemoteAuthOpts(c) {
|
|
|
31729
31940
|
return { ...brandLoginOpts, origin };
|
|
31730
31941
|
}
|
|
31731
31942
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
31732
|
-
|
|
31943
|
+
app76.post("/__remote-auth/login", async (c) => {
|
|
31733
31944
|
const client = clientFrom(c);
|
|
31734
31945
|
const clientIp = client.ip || "unknown";
|
|
31735
31946
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -31774,7 +31985,7 @@ app75.post("/__remote-auth/login", async (c) => {
|
|
|
31774
31985
|
}
|
|
31775
31986
|
});
|
|
31776
31987
|
});
|
|
31777
|
-
|
|
31988
|
+
app76.get("/__remote-auth/logout", (c) => {
|
|
31778
31989
|
const client = clientFrom(c);
|
|
31779
31990
|
const clientIp = client.ip || "unknown";
|
|
31780
31991
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -31787,7 +31998,7 @@ app75.get("/__remote-auth/logout", (c) => {
|
|
|
31787
31998
|
}
|
|
31788
31999
|
});
|
|
31789
32000
|
});
|
|
31790
|
-
|
|
32001
|
+
app76.post("/__remote-auth/change-password", async (c) => {
|
|
31791
32002
|
const client = clientFrom(c);
|
|
31792
32003
|
const clientIp = client.ip || "unknown";
|
|
31793
32004
|
const rateLimited = checkRateLimit(client);
|
|
@@ -31846,13 +32057,13 @@ app75.post("/__remote-auth/change-password", async (c) => {
|
|
|
31846
32057
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
31847
32058
|
}
|
|
31848
32059
|
});
|
|
31849
|
-
|
|
32060
|
+
app76.get("/__remote-auth/setup", (c) => {
|
|
31850
32061
|
if (isRemoteAuthConfigured()) {
|
|
31851
32062
|
return c.redirect("/");
|
|
31852
32063
|
}
|
|
31853
32064
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
|
|
31854
32065
|
});
|
|
31855
|
-
|
|
32066
|
+
app76.post("/__remote-auth/set-initial-password", async (c) => {
|
|
31856
32067
|
if (isRemoteAuthConfigured()) {
|
|
31857
32068
|
return c.redirect("/");
|
|
31858
32069
|
}
|
|
@@ -31890,10 +32101,10 @@ app75.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
31890
32101
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
31891
32102
|
}
|
|
31892
32103
|
});
|
|
31893
|
-
|
|
32104
|
+
app76.get("/api/remote-auth/status", (c) => {
|
|
31894
32105
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
31895
32106
|
});
|
|
31896
|
-
|
|
32107
|
+
app76.post("/api/remote-auth/set-password", async (c) => {
|
|
31897
32108
|
let body;
|
|
31898
32109
|
try {
|
|
31899
32110
|
body = await c.req.json();
|
|
@@ -31932,10 +32143,10 @@ app75.post("/api/remote-auth/set-password", async (c) => {
|
|
|
31932
32143
|
return c.json({ error: "Failed to save password" }, 500);
|
|
31933
32144
|
}
|
|
31934
32145
|
});
|
|
31935
|
-
|
|
32146
|
+
app76.route("/api/_client-error", client_error_default);
|
|
31936
32147
|
console.log("[client-error-route] mounted");
|
|
31937
32148
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
31938
|
-
|
|
32149
|
+
app76.use("*", async (c, next) => {
|
|
31939
32150
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31940
32151
|
const path = c.req.path;
|
|
31941
32152
|
if (path === "/favicon.ico" || path.startsWith("/assets/") || path.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
|
|
@@ -31979,30 +32190,30 @@ app75.use("*", async (c, next) => {
|
|
|
31979
32190
|
}
|
|
31980
32191
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path }), 200);
|
|
31981
32192
|
});
|
|
31982
|
-
|
|
31983
|
-
|
|
31984
|
-
|
|
31985
|
-
|
|
31986
|
-
|
|
31987
|
-
|
|
31988
|
-
|
|
31989
|
-
|
|
31990
|
-
|
|
32193
|
+
app76.route("/api/health", health_default);
|
|
32194
|
+
app76.route("/api/chat", chatRoutes);
|
|
32195
|
+
app76.route("/api/whatsapp", whatsapp_default);
|
|
32196
|
+
app76.route("/api/storage", storage_broker_default);
|
|
32197
|
+
app76.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
32198
|
+
app76.route("/api/session-reader", session_reader_default);
|
|
32199
|
+
app76.route("/api/operator-conversations", operator_conversations_default);
|
|
32200
|
+
app76.route("/api/public-reader", public_reader_default);
|
|
32201
|
+
app76.route("/api/webchat", createWebchatRoutes({
|
|
31991
32202
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
31992
32203
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
31993
32204
|
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
31994
32205
|
deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
|
|
31995
32206
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
31996
32207
|
}));
|
|
31997
|
-
|
|
31998
|
-
|
|
31999
|
-
|
|
32000
|
-
|
|
32001
|
-
|
|
32002
|
-
|
|
32003
|
-
|
|
32004
|
-
|
|
32005
|
-
|
|
32208
|
+
app76.route("/api/webchat/greeting", webchat_greeting_default);
|
|
32209
|
+
app76.route("/api/telegram", telegram_default);
|
|
32210
|
+
app76.route("/api/quickbooks", quickbooks_default);
|
|
32211
|
+
app76.route("/api/onboarding", onboarding_default);
|
|
32212
|
+
app76.route("/api/admin", admin_default);
|
|
32213
|
+
app76.route("/api/access", access_default);
|
|
32214
|
+
app76.route("/api/session", session_default2);
|
|
32215
|
+
app76.route("/api/calendar", calendar_public_default);
|
|
32216
|
+
app76.route("/api/portal", portal_fetch_default);
|
|
32006
32217
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
32007
32218
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
32008
32219
|
var IMAGE_MIME = {
|
|
@@ -32014,7 +32225,7 @@ var IMAGE_MIME = {
|
|
|
32014
32225
|
".svg": "image/svg+xml",
|
|
32015
32226
|
".ico": "image/x-icon"
|
|
32016
32227
|
};
|
|
32017
|
-
|
|
32228
|
+
app76.get("/agent-assets/:slug/:filename", (c) => {
|
|
32018
32229
|
const slug = c.req.param("slug");
|
|
32019
32230
|
const filename = c.req.param("filename");
|
|
32020
32231
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -32049,7 +32260,7 @@ app75.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
32049
32260
|
"Cache-Control": "public, max-age=3600"
|
|
32050
32261
|
});
|
|
32051
32262
|
});
|
|
32052
|
-
|
|
32263
|
+
app76.get("/generated/:filename", (c) => {
|
|
32053
32264
|
const filename = c.req.param("filename");
|
|
32054
32265
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
32055
32266
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -32079,10 +32290,10 @@ app75.get("/generated/:filename", (c) => {
|
|
|
32079
32290
|
"Cache-Control": "public, max-age=86400"
|
|
32080
32291
|
});
|
|
32081
32292
|
});
|
|
32082
|
-
|
|
32083
|
-
|
|
32084
|
-
|
|
32085
|
-
|
|
32293
|
+
app76.route("/sites", sites_default);
|
|
32294
|
+
app76.route("/listings", listings_default);
|
|
32295
|
+
app76.route("/v", visitor_event_default);
|
|
32296
|
+
app76.route("/v", visitor_consent_default);
|
|
32086
32297
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
32087
32298
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
32088
32299
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -32207,7 +32418,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
32207
32418
|
function agentUnavailableHtml() {
|
|
32208
32419
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
32209
32420
|
}
|
|
32210
|
-
|
|
32421
|
+
app76.get("/", (c) => {
|
|
32211
32422
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32212
32423
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
32213
32424
|
if (klass === "operator") {
|
|
@@ -32229,12 +32440,12 @@ app75.get("/", (c) => {
|
|
|
32229
32440
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
32230
32441
|
return c.html(cachedHtml("index.html"));
|
|
32231
32442
|
});
|
|
32232
|
-
|
|
32443
|
+
app76.get("/public", (c) => {
|
|
32233
32444
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32234
32445
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32235
32446
|
return c.html(cachedHtml("public.html"));
|
|
32236
32447
|
});
|
|
32237
|
-
|
|
32448
|
+
app76.get("/public-chat", (c) => {
|
|
32238
32449
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32239
32450
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32240
32451
|
return c.html(cachedHtml("public.html"));
|
|
@@ -32253,9 +32464,9 @@ async function logViewerFetch(c, next) {
|
|
|
32253
32464
|
duration_ms: Date.now() - start
|
|
32254
32465
|
});
|
|
32255
32466
|
}
|
|
32256
|
-
|
|
32257
|
-
|
|
32258
|
-
|
|
32467
|
+
app76.use("/vnc-viewer.html", logViewerFetch);
|
|
32468
|
+
app76.use("/vnc-popout.html", logViewerFetch);
|
|
32469
|
+
app76.get("/vnc-popout.html", (c) => {
|
|
32259
32470
|
let html = htmlCache.get("vnc-popout.html");
|
|
32260
32471
|
if (!html) {
|
|
32261
32472
|
html = readFileSync47(resolve45(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -32268,7 +32479,7 @@ app75.get("/vnc-popout.html", (c) => {
|
|
|
32268
32479
|
}
|
|
32269
32480
|
return c.html(html);
|
|
32270
32481
|
});
|
|
32271
|
-
|
|
32482
|
+
app76.post("/api/vnc/client-event", async (c) => {
|
|
32272
32483
|
let body;
|
|
32273
32484
|
try {
|
|
32274
32485
|
body = await c.req.json();
|
|
@@ -32289,11 +32500,11 @@ app75.post("/api/vnc/client-event", async (c) => {
|
|
|
32289
32500
|
});
|
|
32290
32501
|
return c.json({ ok: true });
|
|
32291
32502
|
});
|
|
32292
|
-
|
|
32503
|
+
app76.get("/g/:slug", (c) => {
|
|
32293
32504
|
return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
|
|
32294
32505
|
});
|
|
32295
32506
|
for (const pwa of PWA_SURFACES) {
|
|
32296
|
-
|
|
32507
|
+
app76.get(pwa.manifestPath, (c) => {
|
|
32297
32508
|
const manifest = buildManifest(pwa, {
|
|
32298
32509
|
productName: BRAND.productName,
|
|
32299
32510
|
appIcon192: brandAppIcon192Path,
|
|
@@ -32309,7 +32520,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
32309
32520
|
return c.body(JSON.stringify(manifest));
|
|
32310
32521
|
});
|
|
32311
32522
|
}
|
|
32312
|
-
|
|
32523
|
+
app76.get("/sw.js", (c) => {
|
|
32313
32524
|
if (SW_SOURCE == null) {
|
|
32314
32525
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
32315
32526
|
return c.text("Service worker unavailable", 500);
|
|
@@ -32318,12 +32529,12 @@ app75.get("/sw.js", (c) => {
|
|
|
32318
32529
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
32319
32530
|
return c.body(SW_SOURCE);
|
|
32320
32531
|
});
|
|
32321
|
-
|
|
32532
|
+
app76.get("/graph", (c) => {
|
|
32322
32533
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32323
32534
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
32324
32535
|
return c.html(cachedHtml("graph.html"));
|
|
32325
32536
|
});
|
|
32326
|
-
|
|
32537
|
+
app76.get("/chat", (c) => {
|
|
32327
32538
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32328
32539
|
if (isOperatorHost(host, getOperatorDomains())) {
|
|
32329
32540
|
console.log(`[host-class] host=${host} class=operator served=operator.html`);
|
|
@@ -32332,47 +32543,47 @@ app75.get("/chat", (c) => {
|
|
|
32332
32543
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32333
32544
|
return c.html(cachedHtml("chat.html"));
|
|
32334
32545
|
});
|
|
32335
|
-
|
|
32546
|
+
app76.get("/data", (c) => {
|
|
32336
32547
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32337
32548
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32338
32549
|
return c.html(cachedHtml("data.html"));
|
|
32339
32550
|
});
|
|
32340
|
-
|
|
32551
|
+
app76.get("/tasks", (c) => {
|
|
32341
32552
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32342
32553
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32343
32554
|
return c.html(cachedHtml("tasks.html"));
|
|
32344
32555
|
});
|
|
32345
|
-
|
|
32556
|
+
app76.get("/activity", (c) => {
|
|
32346
32557
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32347
32558
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32348
32559
|
return c.html(cachedHtml("activity.html"));
|
|
32349
32560
|
});
|
|
32350
|
-
|
|
32561
|
+
app76.get("/calendar", (c) => {
|
|
32351
32562
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32352
32563
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32353
32564
|
return c.html(cachedHtml("calendar.html"));
|
|
32354
32565
|
});
|
|
32355
|
-
|
|
32566
|
+
app76.get("/routines", (c) => {
|
|
32356
32567
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32357
32568
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32358
32569
|
return c.html(cachedHtml("routines.html"));
|
|
32359
32570
|
});
|
|
32360
|
-
|
|
32571
|
+
app76.get("/skills", (c) => {
|
|
32361
32572
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32362
32573
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32363
32574
|
return c.html(cachedHtml("skills.html"));
|
|
32364
32575
|
});
|
|
32365
|
-
|
|
32576
|
+
app76.get("/agents", (c) => {
|
|
32366
32577
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32367
32578
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
32368
32579
|
return c.html(cachedHtml("agents.html"));
|
|
32369
32580
|
});
|
|
32370
|
-
|
|
32581
|
+
app76.get("/browser", (c) => {
|
|
32371
32582
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32372
32583
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
32373
32584
|
return c.html(cachedHtml("browser.html"));
|
|
32374
32585
|
});
|
|
32375
|
-
|
|
32586
|
+
app76.get("/:slug", async (c, next) => {
|
|
32376
32587
|
const slug = c.req.param("slug");
|
|
32377
32588
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
32378
32589
|
const account = resolveAccount();
|
|
@@ -32387,13 +32598,13 @@ app75.get("/:slug", async (c, next) => {
|
|
|
32387
32598
|
await next();
|
|
32388
32599
|
});
|
|
32389
32600
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
32390
|
-
|
|
32601
|
+
app76.get("/favicon.ico", (c) => {
|
|
32391
32602
|
c.header("Cache-Control", "public, max-age=300");
|
|
32392
32603
|
return c.redirect(brandFaviconPath, 302);
|
|
32393
32604
|
});
|
|
32394
32605
|
}
|
|
32395
|
-
mountStaticFiles(
|
|
32396
|
-
|
|
32606
|
+
mountStaticFiles(app76, "./public");
|
|
32607
|
+
app76.all("*", (c) => {
|
|
32397
32608
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32398
32609
|
const path = c.req.path;
|
|
32399
32610
|
if (isPublicHost(host)) {
|
|
@@ -32407,7 +32618,7 @@ app75.all("*", (c) => {
|
|
|
32407
32618
|
});
|
|
32408
32619
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
32409
32620
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
32410
|
-
var httpServer = serve({ fetch:
|
|
32621
|
+
var httpServer = serve({ fetch: app76.fetch, port, hostname });
|
|
32411
32622
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
32412
32623
|
{
|
|
32413
32624
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join53(__dirname, "..");
|
|
@@ -32804,7 +33015,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
32804
33015
|
}
|
|
32805
33016
|
try {
|
|
32806
33017
|
const registered = [];
|
|
32807
|
-
for (const r of
|
|
33018
|
+
for (const r of app76.routes ?? []) {
|
|
32808
33019
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
32809
33020
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
32810
33021
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -32880,6 +33091,7 @@ registerLoop({
|
|
|
32880
33091
|
run: () => runAdminUserReconcileTick()
|
|
32881
33092
|
});
|
|
32882
33093
|
var INGEST_AUDIT_INTERVAL_MS = 15 * 60 * 1e3;
|
|
33094
|
+
var isHouseAccountKey = (houseAccountId, accountId) => accountId === houseAccountId || !isProvisionedAccount(ACCOUNTS_DIR, accountId);
|
|
32883
33095
|
var runIngestAuditTick = () => {
|
|
32884
33096
|
try {
|
|
32885
33097
|
runIngestAudit();
|
|
@@ -32905,17 +33117,57 @@ var runIngestAuditTick = () => {
|
|
|
32905
33117
|
const ids = /* @__PURE__ */ new Set([house.accountId]);
|
|
32906
33118
|
const accounts = wa?.accounts;
|
|
32907
33119
|
for (const id of Object.keys(accounts ?? {})) ids.add(id);
|
|
32908
|
-
|
|
32909
|
-
accountId,
|
|
32910
|
-
|
|
32911
|
-
|
|
32912
|
-
|
|
33120
|
+
const rows = Array.from(ids).map((accountId) => {
|
|
33121
|
+
const isHouse = isHouseAccountKey(house.accountId, accountId);
|
|
33122
|
+
return {
|
|
33123
|
+
accountId,
|
|
33124
|
+
isHouse,
|
|
33125
|
+
enabled: resolvePublicAgentEnabled(house.accountDir, { accountId, isHouse }).enabled,
|
|
33126
|
+
slug: resolvePublicAgent(house.accountDir, { accountId, isHouse })?.slug ?? null
|
|
33127
|
+
};
|
|
33128
|
+
});
|
|
33129
|
+
const seenHouse = { taken: false };
|
|
33130
|
+
return rows.filter((row) => row.enabled).filter((row) => {
|
|
33131
|
+
if (!row.isHouse) return true;
|
|
33132
|
+
if (seenHouse.taken) return false;
|
|
33133
|
+
seenHouse.taken = true;
|
|
33134
|
+
return true;
|
|
33135
|
+
}).map(({ accountId, slug }) => ({ accountId, slug }));
|
|
32913
33136
|
},
|
|
32914
|
-
agentExists: (
|
|
33137
|
+
agentExists: (accountId, slug) => {
|
|
33138
|
+
if (!house) return false;
|
|
33139
|
+
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join53(ACCOUNTS_DIR, accountId);
|
|
33140
|
+
return existsSync50(join53(dir, "agents", slug, "config.json"));
|
|
33141
|
+
}
|
|
32915
33142
|
});
|
|
32916
33143
|
} catch (err) {
|
|
32917
33144
|
console.error(`[whatsapp:public-agent] op=registry-audit-rejected detail=${err instanceof Error ? err.message : String(err)}`);
|
|
32918
33145
|
}
|
|
33146
|
+
try {
|
|
33147
|
+
const house = resolveAccount();
|
|
33148
|
+
runPublicAgentSliceAudit({
|
|
33149
|
+
enabledAccounts: () => {
|
|
33150
|
+
if (!house) return [];
|
|
33151
|
+
const wa = getConfig(house.accountDir);
|
|
33152
|
+
const accounts = wa?.accounts;
|
|
33153
|
+
const ids = /* @__PURE__ */ new Set([house.accountId]);
|
|
33154
|
+
for (const id of Object.keys(accounts ?? {})) ids.add(id);
|
|
33155
|
+
return Array.from(ids).map((accountId) => {
|
|
33156
|
+
const isHouse = isHouseAccountKey(house.accountId, accountId);
|
|
33157
|
+
const slice = accounts?.[accountId] ?? {};
|
|
33158
|
+
const ownSlug = typeof slice.publicAgent === "string" && slice.publicAgent.trim() ? slice.publicAgent.trim() : null;
|
|
33159
|
+
return {
|
|
33160
|
+
accountId,
|
|
33161
|
+
house: isHouse,
|
|
33162
|
+
ownSlug,
|
|
33163
|
+
enabled: resolvePublicAgentEnabled(house.accountDir, { accountId, isHouse }).enabled
|
|
33164
|
+
};
|
|
33165
|
+
}).filter((row) => row.enabled).map(({ accountId, house: isHouse, ownSlug }) => ({ accountId, house: isHouse, ownSlug }));
|
|
33166
|
+
}
|
|
33167
|
+
});
|
|
33168
|
+
} catch (err) {
|
|
33169
|
+
console.error(`[whatsapp:public-agent] op=slice-audit-rejected detail=${err instanceof Error ? err.message : String(err)}`);
|
|
33170
|
+
}
|
|
32919
33171
|
};
|
|
32920
33172
|
registerLoop({
|
|
32921
33173
|
name: "wa-ingest-audit",
|
|
@@ -33001,7 +33253,7 @@ if (bootAccount) {
|
|
|
33001
33253
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
33002
33254
|
}
|
|
33003
33255
|
var bootAccountConfig = bootAccount?.config;
|
|
33004
|
-
var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
|
|
33256
|
+
var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId, isHouse: true })?.slug ?? null : null;
|
|
33005
33257
|
var bootEntitlement = bootAccountConfig ? resolveEntitlement(
|
|
33006
33258
|
{ configDir: MAXY_DIR, platformRoot: PLATFORM_ROOT, commercialMode: COMMERCIAL_MODE },
|
|
33007
33259
|
{
|
|
@@ -33143,9 +33395,10 @@ init({
|
|
|
33143
33395
|
}
|
|
33144
33396
|
const houseForRoute = resolveAccount();
|
|
33145
33397
|
const routeAccountId = msg.effectiveAccountId;
|
|
33398
|
+
const routeIsHouse = houseForRoute ? routeAccountId === houseForRoute.accountId : false;
|
|
33146
33399
|
const route = decidePublicAgentRoute({
|
|
33147
|
-
resolveEnabled: () => houseForRoute ? resolvePublicAgentEnabled(houseForRoute.accountDir, { accountId: routeAccountId }) : { enabled: false, source: "default" },
|
|
33148
|
-
resolveSlug: () => houseForRoute ? resolvePublicAgent(houseForRoute.accountDir, { accountId: routeAccountId }) : null
|
|
33400
|
+
resolveEnabled: () => houseForRoute ? resolvePublicAgentEnabled(houseForRoute.accountDir, { accountId: routeAccountId, isHouse: routeIsHouse }) : { enabled: false, source: "default" },
|
|
33401
|
+
resolveSlug: () => houseForRoute ? resolvePublicAgent(houseForRoute.accountDir, { accountId: routeAccountId, isHouse: routeIsHouse }) : null
|
|
33149
33402
|
});
|
|
33150
33403
|
console.error(
|
|
33151
33404
|
formatPublicAgentRouteLine({
|